From patchwork Mon Sep 4 13:53:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mykola Kostenok X-Patchwork-Id: 131159 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 9BCCE424F0; Mon, 4 Sep 2023 15:55:20 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 469E840DCF; Mon, 4 Sep 2023 15:54:09 +0200 (CEST) Received: from egress-ip44b.ess.de.barracuda.com (egress-ip44b.ess.de.barracuda.com [18.185.115.248]) by mails.dpdk.org (Postfix) with ESMTP id BB08C40DCF for ; Mon, 4 Sep 2023 15:54:07 +0200 (CEST) Received: from EUR04-HE1-obe.outbound.protection.outlook.com (mail-he1eur04lp2054.outbound.protection.outlook.com [104.47.13.54]) by mx-outbound42-61.eu-central-1c.ess.aws.cudaops.com (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Mon, 04 Sep 2023 13:54:05 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Dsxw7TttK8vCmHn9qbPO6CCcTYcSCPLOxoHXbn04El9zVQFRYBYFA0AemDX2b/QQv6K4xB1PSO5rj3NJLobGQbAK+1XcMj+mj0HpfYLYxfceCc9DhqyabzHQINGqI8BhXLizfrGHm2HjYXP6aCY/wTiOIageapne6QCmiITD/48OPTRt3cj1E2TMBAlbeO2xawcHxZsehwiGd45nbHFZUmt+kvxa4uRgBLI1vpuNZ5GfewDuUKYsOv7wkE1HLuwOm6+El7pDhwEGBJkbLsVmOdvUMiZyBtUxblS0zS8xjpXw9A85cQNkuUMiZYw5o/Nb36iItKwqty2UM5jCv8pl7g== 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=xlstFB1B5lq9vG7xGkc2Li7SlQT5JfVdq/0HC3xWp+I=; b=H5kwMsa2UebCz0Z3yuL22qyo9BEPaRELWplXnp1UryfWKf7tDRHrQ70L/G0Axa1Tb2wrGfBIIQ5th9cUGDSwd1POmV6g1xVhnudRrnIHffLilwZi6XnJg9I9zcYz9AgSw+HAO3XCFOCOlSlFj30wrAF66dBavm2nzlYke+V09+QUlizHP8oawhTcqQGhisGDgEjS3WYF/JpCzgnrnYhutmnEXOODiJDZjccDS3y+WOVQtz0/JZG92uBsrOatIjfT9DZlHT3YsWCqmg29ZLeY99386jjfE3+aoghh0GGSoWNrU//c/BbkhsHtXOeQA6nsk3mYlBpf5nmJHpKgL5g4JA== 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=xlstFB1B5lq9vG7xGkc2Li7SlQT5JfVdq/0HC3xWp+I=; b=IOiY2R/1Dxv1YOUZn7xvXDSWBcb809A4oY7Wuds8qEQue4qoJeNJX80b4hbdktLzm9nTsa5m2r2WE+y9c3LdUdW5yg1HBAXUOsb/Bx0CNGntEClcNAK25HU6PJ4hg967WHgiyfXomJtqjKmW7EtqW48i1K4GevylDgPzbeZkj04= Received: from AS4PR09CA0020.eurprd09.prod.outlook.com (2603:10a6:20b:5d4::7) by DB9P190MB1643.EURP190.PROD.OUTLOOK.COM (2603:10a6:10:24d::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6745.32; Mon, 4 Sep 2023 13:53:36 +0000 Received: from AM4PEPF00025F98.EURPRD83.prod.outlook.com (2603:10a6:20b:5d4:cafe::2a) by AS4PR09CA0020.outlook.office365.com (2603:10a6:20b:5d4::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6745.32 via Frontend Transport; Mon, 4 Sep 2023 13:53:36 +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 AM4PEPF00025F98.mail.protection.outlook.com (10.167.16.7) with Microsoft SMTP Server id 15.20.6792.1 via Frontend Transport; Mon, 4 Sep 2023 13:53:35 +0000 From: Mykola Kostenok To: dev@dpdk.org Cc: mko-plv@napatech.com, thomas@monjalon.net, ckm@napatech.com, andrew.rybchenko@oktetlabs.ru, ferruh.yigit@amd.com Subject: [PATCH v14 5/8] net/ntnic: adds FPGA abstraction layer Date: Mon, 4 Sep 2023 15:53:58 +0200 Message-Id: <20230904135401.3176309-5-mko-plv@napatech.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20230904135401.3176309-1-mko-plv@napatech.com> References: <20230816132552.2483752-1-mko-plv@napatech.com> <20230904135401.3176309-1-mko-plv@napatech.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AM4PEPF00025F98:EE_|DB9P190MB1643:EE_ X-MS-Office365-Filtering-Correlation-Id: c6150a18-4ac8-4992-f6b8-08dbad4e55c3 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: RPNGchMC7irdJ86APO2dWSiaQ2hTCiDPUu2RgQeSqyjAFXdG9Ni3An8dvmueP/Fscf6ceACc2BVKKju16Vzr+rfC7PwSvQGMKnQjVVf2FqXRz5g3K2QwMeaibOZ0JYieuOlNRHGJxb6ouhZiv7dEj+T8qa2PUzokZA48DbpqZRQJvD79srUD9ahnNgXANeohEapoZefqb/3nqCYBxBn86t3ddJXU60Dd63P0CqbPaLSiLinvfQgPaIosnJLkJCrgI4brYrcE1YpGhTY/ebwpFQlreetMSJe2NB9L7/w6U+6jQzfWX70IRr5C6ZQohB/MM4PZzBzKnGf6O4qLpN8ikpRMVqyQxQ3BLdksegW+HzeejwNfqMiO5RtuTW1PW+PTYQ4ilmZtB6v6rL9T2EgEULernJ84PUZAyCp5DBenAPEk0SeDsUJNDXN8e3Yl0HH+kz0+SQ93XtkWZDUimf8oi9WGbBhWNHnRUVNgV9DiCe5y5Bj/6ecGok/lspcwl6WEo/dFImyvvzs2pc2aC7Co2Eut0R0CNg0cKkomwBwW1rV5+q5Q2R10q4zXyX67jRRR0LQcOy4uOBjTsa0gBXUXfXzdavxHAZ2ha78fiayVNguzARrwc3d0xAr6JVXfXVudBGiTDySi2bZPLG71M5+mx7TaBKkBFxE57C+sqSPQGgT/mF79I/9+2WpQ+UwkyZUfDkMWpqylC545+dgVQeNUnHNtdLOHXurHh6wHWvjltjMu3yMLIxXdk2maHTyCt/vIZGeeNBjclmWBBRwNSDY3foEEeFjvtxGtZwbteJRNQek= 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)(39840400004)(346002)(376002)(396003)(136003)(451199024)(1800799009)(186009)(82310400011)(46966006)(36840700001)(30864003)(41300700001)(8936002)(83380400001)(40480700001)(478600001)(6666004)(2906002)(70586007)(5660300002)(8676002)(316002)(36736006)(6916009)(4326008)(70206006)(6512007)(2616005)(956004)(1076003)(26005)(6506007)(6486002)(36860700001)(336012)(81166007)(9316004)(86362001)(36756003)(356005)(47076005)(21314003)(36900700001)(559001)(579004)(309714004); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-ExternalHop-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-ExternalHop-MessageData-0: 1gVD4iBnccNHUS9HHxB+vQJ9xtKbR6QfQwid7N9HE3E5eQFF9b1bMydzHCZto4ufvmRhfKlXnc0gfpK4xdfXy11EdAKxnTperA11q5g30fOTgSd7QAJ0h46l85IceQ+aoTcpZjqunclBH1EYYaxh/iMZchYXIO05WPlpf3IfXLlOEkl2memZYRVAQJ6svsSBT1ufZ94fFaFHeCwopM28+3XP8N2r9AyH/9R6D1cPDwEIPkNwSUZn6MAFJRmVtc8iE464xSJbre4rZGFVmsUTEWtJwllHWy3df1qjWo8nUyMamyDxZuVNvtiHDRCj7AMK49g6ExxS0dar1zl7llS241Uy/NTh56QMvi8vhM4KrEZFEg6lnJp8KiHkxJpulYsA02F7jbuCLosphkzeWTZh0aTkFn6RoR/kHz2IuIUESCCXUbHrz/7sFHGa2+wa1fugujxqvCH577Ke7N+kWpjw1jbpu83VBHqgFTl47t3sC0xkomt3yAvdG0suo1xcZ1Kzl8J0bS+JB/YA3GaGswuOrXL3Y6Qzxh0JCF+yiyC+hfJwTQ+yX9if5sHPdK3JlaoKREARq3tk2yUrSjytW6WmCiQ/Wjenp1HavyxZTorzp5HXr/goEQkLeAA3KcQr/bMEmHozpV+X0qDaCGMsM8N5dnHj5rB4GIYB+xqNuYba2+YUlObSvDHakWxyixEgk/wui/WkHOQoW/yjNjsabOl2QNVXZ/H5edvGLs6klfHiJc4nuttIeC1VQ5c6cI/UKRsvcpsyv14rYTeIfXfp4xjTC+iTUipdkaXUYdZbOlKI6fQ= X-OriginatorOrg: napatech.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Sep 2023 13:53:35.9611 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: c6150a18-4ac8-4992-f6b8-08dbad4e55c3 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: AM4PEPF00025F98.EURPRD83.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9P190MB1643 X-BESS-ID: 1693835635-310813-12367-18355-2 X-BESS-VER: 2019.1_20230901.1930 X-BESS-Apparent-Source-IP: 104.47.13.54 X-BESS-Parts: H4sIAAAAAAACA4uuVkqtKFGyUioBkjpK+cVKViYG5pbGRkB2BlDYLMncKC3R3N zEONnMwsLYJCnFzNAkKdEwMdUwycIk2USpNhYA4685TUMAAAA= X-BESS-Outbound-Spam-Score: 0.00 X-BESS-Outbound-Spam-Report: Code version 3.2, rules version 3.2.2.250601 [from cloudscan23-147.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 The FPGA abstraction layer limits the need to rewrite flow logic when new FPGA modules are created. Signed-off-by: Christian Koue Muf Reviewed-by: Mykola Kostenok --- drivers/net/ntnic/meson.build | 21 + .../ntnic/nthw/flow_api/flow_api_actions.c | 205 ++ .../ntnic/nthw/flow_api/flow_api_actions.h | 284 +++ .../ntnic/nthw/flow_api/flow_api_backend.c | 182 ++ .../ntnic/nthw/flow_api/flow_api_backend.h | 1818 +++++++++++++++++ .../net/ntnic/nthw/flow_api/flow_api_engine.h | 475 +++++ .../ntnic/nthw/flow_api/flow_api_nic_setup.h | 32 + .../nthw/flow_api/flow_engine/flow_group.c | 125 ++ .../nthw/flow_api/flow_engine/flow_hasher.c | 213 ++ .../nthw/flow_api/flow_engine/flow_hasher.h | 20 + .../nthw/flow_api/flow_engine/flow_kcc.c | 434 ++++ .../ntnic/nthw/flow_api/flow_engine/flow_km.c | 1434 +++++++++++++ .../nthw/flow_api/flow_engine/flow_tunnel.c | 787 +++++++ .../ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c | 1789 ++++++++++++++++ .../nthw/flow_api/hw_mod/hw_mod_cat_v18.h | 138 ++ .../nthw/flow_api/hw_mod/hw_mod_cat_v21.h | 88 + .../nthw/flow_api/hw_mod/hw_mod_cat_v22.h | 83 + .../ntnic/nthw/flow_api/hw_mod/hw_mod_flm.c | 1099 ++++++++++ .../nthw/flow_api/hw_mod/hw_mod_flm_v17.h | 265 +++ .../nthw/flow_api/hw_mod/hw_mod_flm_v20.h | 102 + .../ntnic/nthw/flow_api/hw_mod/hw_mod_hsh.c | 195 ++ .../nthw/flow_api/hw_mod/hw_mod_hsh_v5.h | 36 + .../ntnic/nthw/flow_api/hw_mod/hw_mod_hst.c | 178 ++ .../nthw/flow_api/hw_mod/hw_mod_hst_v2.h | 32 + .../ntnic/nthw/flow_api/hw_mod/hw_mod_ioa.c | 271 +++ .../nthw/flow_api/hw_mod/hw_mod_ioa_v4.h | 36 + .../ntnic/nthw/flow_api/hw_mod/hw_mod_km.c | 629 ++++++ .../ntnic/nthw/flow_api/hw_mod/hw_mod_km_v7.h | 93 + .../ntnic/nthw/flow_api/hw_mod/hw_mod_pdb.c | 219 ++ .../nthw/flow_api/hw_mod/hw_mod_pdb_v9.h | 39 + .../ntnic/nthw/flow_api/hw_mod/hw_mod_qsl.c | 348 ++++ .../nthw/flow_api/hw_mod/hw_mod_qsl_v7.h | 45 + .../ntnic/nthw/flow_api/hw_mod/hw_mod_rmc.c | 112 + .../nthw/flow_api/hw_mod/hw_mod_rmc_v1_3.h | 20 + .../ntnic/nthw/flow_api/hw_mod/hw_mod_roa.c | 358 ++++ .../nthw/flow_api/hw_mod/hw_mod_roa_v6.h | 49 + .../ntnic/nthw/flow_api/hw_mod/hw_mod_slc.c | 132 ++ .../nthw/flow_api/hw_mod/hw_mod_slc_lr.c | 132 ++ .../nthw/flow_api/hw_mod/hw_mod_slc_lr_v2.h | 19 + .../nthw/flow_api/hw_mod/hw_mod_slc_v1.h | 19 + .../ntnic/nthw/flow_api/hw_mod/hw_mod_tpe.c | 983 +++++++++ .../nthw/flow_api/hw_mod/hw_mod_tpe_v1.h | 103 + .../nthw/flow_api/hw_mod/hw_mod_tpe_v2.h | 37 + .../nthw/flow_api/stream_binary_flow_api.h | 697 +++++++ 44 files changed, 14376 insertions(+) create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_api_actions.c create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_api_actions.h create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_api_backend.c create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_api_backend.h create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_api_engine.h create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_api_nic_setup.h create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_engine/flow_group.c create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_engine/flow_hasher.c create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_engine/flow_hasher.h create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_engine/flow_kcc.c create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_engine/flow_km.c create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_engine/flow_tunnel.c create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat_v18.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat_v21.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat_v22.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm.c create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm_v17.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm_v20.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hsh.c create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hsh_v5.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hst.c create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hst_v2.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_ioa.c create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_ioa_v4.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_km.c create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_km_v7.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_pdb.c create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_pdb_v9.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_qsl.c create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_qsl_v7.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_rmc.c create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_rmc_v1_3.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_roa.c create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_roa_v6.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc.c create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_lr.c create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_lr_v2.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_v1.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe.c create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe_v1.h create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe_v2.h create mode 100644 drivers/net/ntnic/nthw/flow_api/stream_binary_flow_api.h diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build index 8c065ee9a3..8a5a3d5deb 100644 --- a/drivers/net/ntnic/meson.build +++ b/drivers/net/ntnic/meson.build @@ -18,6 +18,7 @@ includes = [ include_directories('nthw'), include_directories('nthw/core'), include_directories('nthw/supported'), + include_directories('nthw/flow_api'), include_directories('nthw/flow_filter'), include_directories('sensors'), include_directories('sensors/avr_sensors'), @@ -60,6 +61,26 @@ sources = files( 'nthw/core/nthw_spim.c', 'nthw/core/nthw_spis.c', 'nthw/core/nthw_tsm.c', + 'nthw/flow_api/flow_api_actions.c', + 'nthw/flow_api/flow_api_backend.c', + 'nthw/flow_api/flow_engine/flow_group.c', + 'nthw/flow_api/flow_engine/flow_hasher.c', + 'nthw/flow_api/flow_engine/flow_kcc.c', + 'nthw/flow_api/flow_engine/flow_km.c', + 'nthw/flow_api/flow_engine/flow_tunnel.c', + 'nthw/flow_api/hw_mod/hw_mod_cat.c', + 'nthw/flow_api/hw_mod/hw_mod_flm.c', + 'nthw/flow_api/hw_mod/hw_mod_hsh.c', + 'nthw/flow_api/hw_mod/hw_mod_hst.c', + 'nthw/flow_api/hw_mod/hw_mod_ioa.c', + 'nthw/flow_api/hw_mod/hw_mod_km.c', + 'nthw/flow_api/hw_mod/hw_mod_pdb.c', + 'nthw/flow_api/hw_mod/hw_mod_qsl.c', + 'nthw/flow_api/hw_mod/hw_mod_rmc.c', + 'nthw/flow_api/hw_mod/hw_mod_roa.c', + 'nthw/flow_api/hw_mod/hw_mod_slc.c', + 'nthw/flow_api/hw_mod/hw_mod_slc_lr.c', + 'nthw/flow_api/hw_mod/hw_mod_tpe.c', 'nthw/flow_filter/flow_nthw_cat.c', 'nthw/flow_filter/flow_nthw_csu.c', 'nthw/flow_filter/flow_nthw_flm.c', diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api_actions.c b/drivers/net/ntnic/nthw/flow_api/flow_api_actions.c new file mode 100644 index 0000000000..945ab7d743 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/flow_api_actions.c @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include +#include +#include /* htons, htonl, ntohs */ + +#include "ntlog.h" + +#include "stream_binary_flow_api.h" +#include "flow_api_actions.h" +#include "flow_api_backend.h" +#include "flow_api_engine.h" + +int flow_actions_create_roa_tunhdr(struct flow_api_backend_s *be, int index, + struct tunnel_header_s *tun) +{ + int err = 0; + int num_writes = (tun->ip_version == 4) ? 4 : 8; + + /* + * Write 4 * 4 words = 64 bytes (IPv4) or 8 * 4 words = 128 bytes (IPv6) + */ + for (int i = 0; (i < num_writes) && !err; i++) { + for (int ii = 0; (ii < 4) && !err; ii++) { + /* must write each 4 words backwards! */ + err |= hw_mod_roa_tunhdr_set(be, HW_ROA_TUNHDR, + index, i * 4 + ii, + ntohl(tun->d.hdr32[(i + 1) * 4 - ii - 1])); + } + } + + return err; +} + +int flow_actions_create_roa_tuncfg(struct flow_api_backend_s *be, int index, + uint64_t color_actions) +{ + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_PRESET_ALL, index, 0); + /* + * If tunnel header specified + */ + int tun_len = get_roa_tunhdr_len(color_actions); + + if (tun_len) { + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_TUN_LEN, index, + tun_len); + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_TUN_TYPE, index, + roa_get_tun_type(color_actions)); + + /* set the total tunnel IP header length */ + if (get_roa_tun_ip_type(color_actions) == 1) { + /* IPv6 */ + if ((size_t)tun_len > (sizeof(struct flow_elem_eth) + + sizeof(struct flow_elem_ipv6))) { + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_IPTL_UPD, index, 1); + /* tunnel header length excludes the IPv6 header itself */ + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_IPTL_PRECALC, index, + (uint32_t)(tun_len - + (sizeof(struct flow_elem_eth) + + sizeof(struct flow_elem_ipv6)))); + } + } else { + /* IPv4 */ + if ((size_t)tun_len > sizeof(struct flow_elem_eth)) { + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_IPTL_UPD, + index, 1); + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_IPTL_PRECALC, index, + (uint32_t)(tun_len - + sizeof(struct flow_elem_eth))); + } + } + + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_IP_TYPE, index, + get_roa_tun_ip_type(color_actions)); + + if (get_roa_tun_ip_type(color_actions) == 1) { + /* IPv6 - Do not update the IP checksum in the tunnel header */ + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_IPCS_UPD, index, + 0); + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_IPCS_PRECALC, + index, 0); + } else { + /* IPv4 */ + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_IPCS_UPD, + index, 1); + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_IPCS_PRECALC, + index, + get_roa_tun_ip_csum(color_actions)); + } + + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_VXLAN_UDP_LEN_UPD, + index, 1); + + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_PUSH_TUNNEL, index, 1); + } + + /* bypass must be > 0 or recirculate_port >= 0 - bypass wins */ + uint8_t recirculate_bypass = roa_get_recirc_bypass_port(color_actions); + + if (recirculate_bypass) { + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_RECIRC_BYPASS, index, + recirculate_bypass); + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_RECIRCULATE, index, 1); + + } else { + int32_t recirculate_port = roa_get_recirc_port(color_actions); + + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_RECIRC_BYPASS, index, + 255); + + if (recirculate_port >= 0) { + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_RECIRC_PORT, + index, recirculate_port); + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_RECIRCULATE, + index, 1); + } + } + + uint8_t tx = roa_get_tx(color_actions); + + if (tx) { + if (tx == DESTINATION_TX_PHY0) { + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_TX_LAG_IX, + index, ROA_TX_PHY0); + } else if (tx == DESTINATION_TX_PHY1) { + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_TX_LAG_IX, + index, ROA_TX_PHY1); + } else if (tx == (DESTINATION_TX_PHY0 | DESTINATION_TX_PHY1)) { + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_TX_LAG_IX, + index, ROA_TX_PHY0); + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_RECIRC_BYPASS, + index, 0x81); /* port 1 - only port left */ + hw_mod_roa_tuncfg_set(be, HW_ROA_TUNCFG_RECIRCULATE, + index, 1); + + } else { + return -1; /* ERR */ + } + } + + /* + * Special IOA memory that contains ROA information - bad FPGA design + */ + if (tx || tun_len) { + if (be->ioa.ver > 3 && tun_len && + get_roa_tun_ip_type(color_actions) == 1) { + /* IPv6 VxLAN tunnel. Select EPP recipe 2 */ + hw_mod_ioa_roa_epp_set(be, HW_IOA_ROA_EPP_PUSH_TUNNEL, + index, 2); + } else { + /* IPv4 VxLAN tunnel or no tunnel (select recipe 1 or 0) */ + hw_mod_ioa_roa_epp_set(be, HW_IOA_ROA_EPP_PUSH_TUNNEL, + index, !!tun_len); + } + hw_mod_ioa_roa_epp_set(be, HW_IOA_ROA_EPP_TX_PORT, index, tx); + } + + return 0; +} + +int flow_actions_create_ioa_config(struct flow_api_backend_s *be, int index, + uint64_t color_actions) +{ + if (color_actions & ioa_set_vxlan_pop(0)) { + hw_mod_ioa_rcp_set(be, HW_IOA_RCP_TUNNEL_POP, index, 1); + NT_LOG(DBG, FILTER, "Pop outer Tunnel (Vxlan)\n"); + } + + if (color_actions & ioa_set_vlan_pop(0)) { + hw_mod_ioa_rcp_set(be, HW_IOA_RCP_VLAN_POP, index, 1); + NT_LOG(DBG, FILTER, "Pop outer Vlan\n"); + } + + int tpid_sel = ioa_get_tpid_sel(color_actions); + + if (color_actions & ioa_set_vlan_push(0, 0)) { + uint16_t tci = ioa_get_vlan_tci(color_actions); + + NT_LOG(DBG, FILTER, "Push Vlan with TPID/TCI %04x/%04x\n", + tpid_sel ? 0x88a8 : 0x8100, tci); + hw_mod_ioa_rcp_set(be, HW_IOA_RCP_VLAN_VID, index, + tci & 0x0FFF); + hw_mod_ioa_rcp_set(be, HW_IOA_RCP_VLAN_DEI, index, + (tci >> 12) & 0x1); + hw_mod_ioa_rcp_set(be, HW_IOA_RCP_VLAN_PCP, index, + (tci >> 13) & 0x7); + hw_mod_ioa_rcp_set(be, HW_IOA_RCP_VLAN_PUSH, index, 1); + } + + int queue = ioa_get_queue(color_actions); + + if (queue >= 0) { + hw_mod_ioa_rcp_set(be, HW_IOA_RCP_QUEUE_OVERRIDE_EN, index, 1); + hw_mod_ioa_rcp_set(be, HW_IOA_RCP_QUEUE_ID, index, queue); + } + + hw_mod_ioa_rcp_set(be, HW_IOA_RCP_VLAN_TPID_SEL, index, tpid_sel); + + return 0; +} diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api_actions.h b/drivers/net/ntnic/nthw/flow_api/flow_api_actions.h new file mode 100644 index 0000000000..400066e817 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/flow_api_actions.h @@ -0,0 +1,284 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _FLOW_ACTIONS_H_ +#define _FLOW_ACTIONS_H_ + +struct flow_api_backend_s; +struct tunnel_header_s; + +#define MAX_COLOR_FLOW_STATS 0x400 + +#define ROA_RECIRC_BYPASS_PHY_OFFSET 0x80 +#define MAX_REPLICATION_PORTS 2 + +enum { + DESTINATION_TX_NONE = 0, + DESTINATION_TX_PHY0 = 1, + DESTINATION_TX_PHY1 = 2 +}; + +enum { TUN_IPV4 = 0, TUN_IPV6 }; + +enum { + VLAN_TPID_802_1Q = 0, + VLAN_TPID_802_1AD, + VLAN_TPID_CUSTOM_0, + VLAN_TPID_CUSTOM_1 +}; + +enum { ROA_TX_NO_RETRANSMIT = 0, ROA_TX_PHY0, ROA_TX_PHY1, ROA_TX_RESERVED }; + +/* + * before version 6 of QSL + */ +#if (MAX_COLOR_FLOW_STATS == 0x4000) +#define MAX_HW_FLOW_STATS_OLD 0x3fff + +#else +#if (MAX_COLOR_FLOW_STATS == 0x400) +#define MAX_HW_FLOW_STATS_OLD 0x03ff +#else +#error *** Unsupported number of color statistics counter *** +#endif +#endif + +/* + * OLD behavior substituted from 4.1+ + * + * 13:0 Mark (color) 16384 flow stats + * 21:14 IOA index 256 entries + * 29:22 ROA index 256 entries + * 31:30 1 to indicate this layout + * or + * 9:0 Mark (color) 1024 flow stats + * 19:10 IOA index 1024 entries + * 29:20 ROA index 1024 entries + * 31:30 0 to indicate this layout + */ +static inline uint32_t set_color_action_old(uint32_t color, uint32_t ioa_rcp, + uint32_t roa_rcp) +{ +#if (MAX_COLOR_FLOW_STATS == 0x400) + uint32_t color_action = (color & MAX_HW_FLOW_STATS_OLD) | + ((ioa_rcp & 0x3ff) << 10) | + ((roa_rcp & 0x3ff) << 20) | (0 << 30); +#else + uint32_t color_action = (color & MAX_HW_FLOW_STATS_OLD) | + ((ioa_rcp & 0xff) << 14) | + ((roa_rcp & 0xff) << 22) | (1 << 30); +#endif + return color_action; +} + +#define BITMASK(a, b) ((1U << ((a) - (b) + 1)) - 1) + +/* + * 9:0 Mark (color) 1024 flow stats + * 17:10 IOA index 256 entries + * 25:18 ROA index 256 entries + * 30:26 QSL and HSH 32 recipes indexable + * 31:31 CAO implicitly when color_action is set + */ +#define FLOW_MARK_MASK BITMASK(9, 0) +#define IOA_RCP_MASK BITMASK(17, 10) +#define ROA_RCP_MASK BITMASK(25, 18) +#define QSL_HSH_MASK BITMASK(30, 26) + +static inline uint32_t set_color_action(uint32_t mark, uint32_t ioa_rcp, + uint32_t roa_rcp, uint32_t qsl_hsh) +{ + uint32_t color_action = (mark & FLOW_MARK_MASK) | + ((ioa_rcp & IOA_RCP_MASK) << 10) | + ((roa_rcp & ROA_RCP_MASK) << 18) | + ((qsl_hsh & QSL_HSH_MASK) << 26) | (1 << 31); + return color_action; +} + +/* + * This is a bitmask representation in SW for + * roa config settings. It is mostly done for + * effective cache matching + * + * ROA config bit offs bits + * ---------------------------- + * recirc port 7:0 8 -> uses hbx > 0 + * recirc bypass 15:8 8 -> uses hbx > 0 if set, will override + * tunnel type 19:16 4 + * tx port 23:20 4 -> txport + 1 + * tun_ip_type 24:24 1 + * recirculate 25:25 1 -> recirculate port set + * tunhdr_len 33:26 8 -> tunnel header length - 0 if none + * ip_csum_prec 49:34 16 -> tunnel ip header checksum pre-calculated + * new_recirc_port 50:50 1 -> indication of a new port for recirculate has been allocated. + * Needs default queue + */ + +static inline uint64_t set_roa_new_recirc_port(uint64_t actions) +{ + actions |= 1ULL << 50; + return actions; +} + +static inline uint8_t get_roa_new_recirc_port(uint64_t actions) +{ + return (uint8_t)((actions >> 50) & 1); +} + +static inline uint64_t set_roa_tun_ip_type(uint64_t actions, uint8_t ip_type) +{ + actions |= (uint64_t)(ip_type & 1) << 24; + return actions; +} + +static inline uint8_t get_roa_tun_ip_type(uint64_t actions) +{ + return (uint8_t)((actions >> 24) & 1); +} + +static inline uint64_t set_roa_tun_ip_csum(uint64_t actions, uint16_t csum) +{ + actions |= (uint64_t)csum << 34; + return actions; +} + +static inline uint16_t get_roa_tun_ip_csum(uint64_t actions) +{ + return (uint16_t)((actions >> 34) & 0xffff); +} + +static inline uint64_t set_roa_tunhdr_len(uint64_t actions, uint8_t length) +{ + actions |= (uint64_t)length << 26; + return actions; +} + +static inline uint8_t get_roa_tunhdr_len(uint64_t actions) +{ + return (uint8_t)((actions >> 26) & 0xff); +} + +static inline uint64_t set_roa_tx(uint64_t actions, uint8_t txport) +{ + actions |= ((txport + ROA_TX_PHY0) & 0x0f) << 20; + return actions; +} + +static inline uint8_t roa_get_tx(uint64_t actions) +{ + return (actions >> 20) & 0x0f; +} + +static inline uint64_t set_roa_tun_type(uint64_t actions, uint8_t type) +{ + actions |= (type & 0x0f) << 16; + return actions; +} + +static inline uint8_t roa_get_tun_type(uint64_t actions) +{ + return (actions >> 16) & 0x0f; +} + +static inline uint64_t set_roa_recirculate(uint64_t actions, uint8_t port) +{ + actions |= (1ULL << 25) | port; + return actions; +} + +static inline int32_t roa_get_recirc_port(uint64_t actions) +{ + if (!((1ULL << 25) & actions)) + return -1; + return (actions & 0xff); +} + +static inline uint64_t set_roa_recirc_bypass(uint64_t actions, uint8_t port) +{ + actions |= ((uint64_t)port & 0xff) << 8; + return actions; +} + +static inline uint8_t roa_get_recirc_bypass_port(uint64_t actions) +{ + return ((actions >> 8) & 0xff); +} + +/* + * This is a bitmask representation in SW for + * ioa action settings. It is mostly done for + * effective cache matching + * + * IOA action bit offs bits + * -------------------------------- + * tci 15:0 16 + * queue 23:16 8 uses hbx + * tpid select 27:24 4 + * pop vxlan 28 1 + * pop vlan 29 1 + * push vlan 30 1 + * queue override 31 1 + */ + +static inline uint64_t ioa_set_queue(uint64_t actions, uint8_t hb) +{ + actions |= (1 << 31) | ((uint64_t)hb << 16); + return actions; +} + +static inline int ioa_get_queue(uint64_t actions) +{ + if (!(actions & (1 << 31))) + return -1; + return ((actions >> 16) & 0xff); +} + +static inline uint64_t ioa_set_vxlan_pop(uint64_t actions) +{ + actions |= 1 << 28; + return actions; +} + +static inline uint64_t ioa_set_vlan_pop(uint64_t actions) +{ + actions |= 1 << 29; + return actions; +} + +static inline uint64_t ioa_set_vlan_push_qinq(uint64_t actions) +{ + actions |= (VLAN_TPID_802_1AD & 0x0f) << 24; + return actions; +} + +static inline uint8_t ioa_get_tpid_sel(uint64_t actions) +{ + return (uint8_t)((actions >> 24) & 0x0f); +} + +static inline uint64_t ioa_set_vlan_push(uint64_t actions, uint16_t tci) +{ + actions |= (1 << 30) | tci; + return actions; +} + +static inline uint64_t ioa_set_vlan_pcp(uint64_t actions, uint8_t pcp) +{ + actions |= (1 << 30) | ((uint16_t)(pcp & 7) << 13); + return actions; +} + +static inline uint16_t ioa_get_vlan_tci(uint64_t actions) +{ + return (uint16_t)(actions & 0xffff); +} + +int flow_actions_create_roa_tunhdr(struct flow_api_backend_s *be, int index, + struct tunnel_header_s *tun); +int flow_actions_create_roa_tuncfg(struct flow_api_backend_s *be, int index, + uint64_t color_actions); +int flow_actions_create_ioa_config(struct flow_api_backend_s *be, int index, + uint64_t color_actions); + +#endif /* _FLOW_ACTIONS_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_api_backend.c new file mode 100644 index 0000000000..f4d71acb51 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/flow_api_backend.c @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include +#include +#include + +#include "flow_api_backend.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +static const struct { + const char *name; + int (*allocate)(struct flow_api_backend_s *be); + void (*free)(struct flow_api_backend_s *be); + int (*reset)(struct flow_api_backend_s *be); + bool (*present)(struct flow_api_backend_s *be); +} module[] = { + { "CAT", hw_mod_cat_alloc, hw_mod_cat_free, hw_mod_cat_reset, + hw_mod_cat_present + }, + { "KM", hw_mod_km_alloc, hw_mod_km_free, hw_mod_km_reset, + hw_mod_km_present + }, + { "FLM", hw_mod_flm_alloc, hw_mod_flm_free, hw_mod_flm_reset, + hw_mod_flm_present + }, + { "HSH", hw_mod_hsh_alloc, hw_mod_hsh_free, hw_mod_hsh_reset, + hw_mod_hsh_present + }, + { "HST", hw_mod_hst_alloc, hw_mod_hst_free, hw_mod_hst_reset, + hw_mod_hst_present + }, + { "QSL", hw_mod_qsl_alloc, hw_mod_qsl_free, hw_mod_qsl_reset, + hw_mod_qsl_present + }, + { "SLC", hw_mod_slc_alloc, hw_mod_slc_free, hw_mod_slc_reset, + hw_mod_slc_present + }, + { "SLC LR", hw_mod_slc_lr_alloc, hw_mod_slc_lr_free, + hw_mod_slc_lr_reset, hw_mod_slc_lr_present + }, + { "PDB", hw_mod_pdb_alloc, hw_mod_pdb_free, hw_mod_pdb_reset, + hw_mod_pdb_present + }, + { "IOA", hw_mod_ioa_alloc, hw_mod_ioa_free, hw_mod_ioa_reset, + hw_mod_ioa_present + }, + { "ROA", hw_mod_roa_alloc, hw_mod_roa_free, hw_mod_roa_reset, + hw_mod_roa_present + }, + { "RMC", hw_mod_rmc_alloc, hw_mod_rmc_free, hw_mod_rmc_reset, + hw_mod_rmc_present + }, + { "TPE", hw_mod_tpe_alloc, hw_mod_tpe_free, hw_mod_tpe_reset, + hw_mod_tpe_present + }, +}; + +#define MOD_COUNT (ARRAY_SIZE(module)) + +void *callocate_mod(struct common_func_s *mod, int sets, ...) +{ +#define MAX_SETS 38 + void *base = NULL; + void **plist[MAX_SETS]; + int len[MAX_SETS]; + int offs[MAX_SETS]; + unsigned int total_bytes = 0; + int cnt, elem_size; + + assert(sets <= MAX_SETS); + assert(sets > 0); + + va_list args; + + va_start(args, sets); + + for (int i = 0; i < sets; i++) { + plist[i] = va_arg(args, void *); + cnt = va_arg(args, int); + elem_size = va_arg(args, int); + offs[i] = EXTRA_INDEXES * elem_size; + len[i] = offs[i] + cnt * elem_size; + total_bytes += len[i]; + } + base = calloc(1, total_bytes); + if (base) { + char *p_b = (char *)base; + + for (int i = 0; i < sets; i++) { + (*plist[i]) = (void *)((char *)p_b + offs[i]); + p_b += len[i]; + } + } else { + NT_LOG(ERR, FILTER, "ERROR: module memory allocation failed\n"); + } + + va_end(args); + + mod->base = base; + mod->allocated_size = total_bytes; + + return base; +} + +void zero_module_cache(struct common_func_s *mod) +{ + memset(mod->base, 0, mod->allocated_size); +} + +int flow_api_backend_init(struct flow_api_backend_s *dev, + const struct flow_api_backend_ops *iface, + void *be_dev) +{ + assert(dev); + dev->iface = iface; + dev->be_dev = be_dev; + dev->num_phy_ports = iface->get_nb_phy_port(be_dev); + dev->num_rx_ports = iface->get_nb_rx_port(be_dev); + dev->max_categories = iface->get_nb_categories(be_dev); + dev->max_queues = iface->get_nb_queues(be_dev); + + NT_LOG(DBG, FILTER, + "*************** FLOW REGISTER MODULES AND INITIALIZE - SET ALL TO DEFAULT *****************\n"); + /* + * Create Cache and SW, version independent, NIC module representation + */ + for (unsigned int mod = 0; mod < MOD_COUNT; mod++) { + if (!module[mod].present(dev)) + continue; + if (module[mod].allocate(dev) == 0 && + module[mod].reset(dev) == 0) { + /* OK */ + continue; + } else { + NT_LOG(ERR, FILTER, + "ERROR: Initialization of NIC module failed : [ %s ]\n", + module[mod].name); + flow_api_backend_done(dev); + NT_LOG(ERR, FILTER, + "*************** Failed to create Binary Flow API *******************\n"); + NT_LOG(ERR, FILTER, + "******** ERROR ERROR: Binary Flow API will not be available ********\n"); + NT_LOG(ERR, FILTER, + "********************************************************************\n"); + return -1; + } + } + + return 0; +} + +int flow_api_backend_reset(struct flow_api_backend_s *dev) +{ + assert(dev); + + for (unsigned int mod = 0; mod < MOD_COUNT; mod++) { + if (module[mod].reset(dev) == 0) { + /* OK */ + continue; + } else { + NT_LOG(ERR, FILTER, + "ERROR: Resetting NIC module failed : [ %s ]\n", + module[mod].name); + return -1; + } + } + + return 0; +} + +int flow_api_backend_done(struct flow_api_backend_s *dev) +{ + for (unsigned int mod = 0; mod < MOD_COUNT; mod++) + module[mod].free(dev); + return 0; +} diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api_backend.h b/drivers/net/ntnic/nthw/flow_api/flow_api_backend.h new file mode 100644 index 0000000000..c3386adea9 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/flow_api_backend.h @@ -0,0 +1,1818 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __FLOW_API_BACKEND_H__ +#define __FLOW_API_BACKEND_H__ + +/* + * Flow API + * Direct access to NIC HW module memory and register fields in a + * module version independent representation + */ + +#include +#include +#include + +#include "ntlog.h" + +/* supported module versions */ +#include "../flow_api/hw_mod/hw_mod_km_v7.h" +#include "flow_api/hw_mod/hw_mod_cat_v18.h" +#include "flow_api/hw_mod/hw_mod_cat_v21.h" +#include "flow_api/hw_mod/hw_mod_cat_v22.h" +#include "flow_api/hw_mod/hw_mod_flm_v17.h" +#include "flow_api/hw_mod/hw_mod_flm_v20.h" +#include "flow_api/hw_mod/hw_mod_hst_v2.h" +#include "flow_api/hw_mod/hw_mod_km_v7.h" +#include "flow_api/hw_mod/hw_mod_qsl_v7.h" +#include "flow_api/hw_mod/hw_mod_pdb_v9.h" +#include "flow_api/hw_mod/hw_mod_slc_v1.h" +#include "flow_api/hw_mod/hw_mod_slc_lr_v2.h" +#include "flow_api/hw_mod/hw_mod_roa_v6.h" +#include "flow_api/hw_mod/hw_mod_hsh_v5.h" +#include "flow_api/hw_mod/hw_mod_ioa_v4.h" +#include "flow_api/hw_mod/hw_mod_rmc_v1_3.h" +#include "flow_api/hw_mod/hw_mod_tpe_v1.h" +#include "flow_api/hw_mod/hw_mod_tpe_v2.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_PHYS_ADAPTERS 8 + +#define VER_MAJOR(ver) (((ver) >> 16) & 0xffff) +#define VER_MINOR(ver) ((ver) & 0xffff) + +struct flow_api_backend_s; +struct common_func_s; + +#define CAST_COMMON(mod) ((struct common_func_s *)(mod)) + +void *callocate_mod(struct common_func_s *mod, int sets, ...); +void zero_module_cache(struct common_func_s *mod); + +#define ZERO_MOD_CACHE(mod) (zero_module_cache(CAST_COMMON(mod))) + +#define ALL_ENTRIES -1000 +#define ALL_BANK_ENTRIES -1001 + +static inline int error_index_too_large(const char *func) +{ + NT_LOG(INF, FILTER, "ERROR:%s: Index too large\n", func); + return -2; +} + +static inline int error_word_off_too_large(const char *func) +{ + NT_LOG(INF, FILTER, "ERROR:%s: Word offset too large\n", func); + return -3; +} + +static inline int error_unsup_ver(const char *func, const char *mod, int ver) +{ + NT_LOG(INF, FILTER, "ERROR:%s: Unsupported NIC module: %s ver %i.%i\n", + func, mod, VER_MAJOR(ver), VER_MINOR(ver)); + return -4; +} + +static inline int error_unsup_field(const char *func) +{ + NT_LOG(INF, FILTER, "ERROR:%s: Unsupported field in NIC module\n", + func); + return -5; +} + +static inline int error_resource_count(const char *func, const char *resource, + const char *mod, int ver) +{ + NT_LOG(INF, FILTER, + "ERROR:%s: Insufficient resource [ %s ] : NIC module:" + "%s ver %i.%i\n", + func, resource, mod, VER_MAJOR(ver), VER_MINOR(ver)); + return -4; +} + +#define NOT_FOUND 0xffffffff + +enum { EXTRA_INDEXES }; +#define COPY_INDEX (EXTRA_INDEX_COPY - EXTRA_INDEXES) + +static inline void get_set(uint32_t *cached_val, uint32_t *val, int get) +{ + if (get) + *val = *cached_val; + else + *cached_val = *val; +} + +static inline void get_set_signed(int32_t *cached_val, uint32_t *val, int get) +{ + if (get) + *val = (uint32_t)*cached_val; + else + *cached_val = (int32_t)*val; +} + +static inline int find_equal_index(void *be_module_reg, + unsigned int type_size, unsigned int idx, unsigned int start, + unsigned int nb_elements, uint32_t *value, int get, const char *func) +{ + unsigned int i; + if (!get) + return error_unsup_field(func); + *value = NOT_FOUND; + if (start >= nb_elements) + return error_index_too_large(func); + for (i = start; i < nb_elements; i++) { + if (idx == i) + continue; + if (memcmp((uint8_t *)be_module_reg + idx * type_size, + (uint8_t *)be_module_reg + i * type_size, + type_size) == 0) { + *value = i; + break; + } + } + return 0; +} + +static inline int do_compare_indexes(void *be_module_reg, + unsigned int type_size, unsigned int idx, unsigned int cmp_idx, + unsigned int nb_elements, int get, const char *func) +{ + if (!get) + return error_unsup_field(func); + if (cmp_idx >= nb_elements) + return error_index_too_large(func); + if (idx != cmp_idx && + (memcmp((uint8_t *)be_module_reg + idx * type_size, + (uint8_t *)be_module_reg + cmp_idx * type_size, + type_size) == 0)) + return 1; + return 0; +} + +static inline int is_non_zero(const void *addr, size_t n) +{ + size_t i = 0; + const uint8_t *p = (const uint8_t *)addr; + + for (i = 0; i < n; i++) { + if (p[i] != 0) + return 1; + } + return 0; +} + +static inline int is_all_bits_set(const void *addr, size_t n) +{ + size_t i = 0; + const uint8_t *p = (const uint8_t *)addr; + + for (i = 0; i < n; i++) { + if (p[i] != 0xff) + return 0; + } + return 1; +} + +enum cte_index_e { + CT_COL = 0, + CT_COR = 1, + CT_HSH = 2, + CT_QSL = 3, + CT_IPF = 4, + CT_SLC = 5, + CT_PDB = 6, + CT_MSK = 7, + CT_HST = 8, + CT_EPP = 9, + CT_TPE = 10, + CT_RRB = 11, + CT_CNT +}; + +/* Sideband info bit indicator */ +#define SWX_INFO (1 << 6) + +enum frame_offs_e { + DYN_SOF = 0, + DYN_L2 = 1, + DYN_FIRST_VLAN = 2, + DYN_MPLS = 3, + DYN_L3 = 4, + DYN_ID_IPV4_6 = 5, + DYN_FINAL_IP_DST = 6, + DYN_L4 = 7, + DYN_L4_PAYLOAD = 8, + DYN_TUN_PAYLOAD = 9, + DYN_TUN_L2 = 10, + DYN_TUN_VLAN = 11, + DYN_TUN_MPLS = 12, + DYN_TUN_L3 = 13, + DYN_TUN_ID_IPV4_6 = 14, + DYN_TUN_FINAL_IP_DST = 15, + DYN_TUN_L4 = 16, + DYN_TUN_L4_PAYLOAD = 17, + DYN_EOF = 18, + DYN_L3_PAYLOAD_END = 19, + DYN_TUN_L3_PAYLOAD_END = 20, + SB_VNI = SWX_INFO | 1, + SB_MAC_PORT = SWX_INFO | 2, + SB_KCC_ID = SWX_INFO | 3 +}; + +enum km_flm_if_select_e { KM_FLM_IF_FIRST = 0, KM_FLM_IF_SECOND = 1 }; + +enum { + QW0_SEL_EXCLUDE = 0, + QW0_SEL_FIRST32 = 1, + QW0_SEL_SECOND32 = 2, + QW0_SEL_FIRST64 = 3, + QW0_SEL_ALL128 = 4, +}; + +enum { + QW4_SEL_EXCLUDE = 0, + QW4_SEL_FIRST32 = 1, + QW4_SEL_FIRST64 = 2, + QW4_SEL_ALL128 = 3, +}; + +enum { + SW8_SEL_EXCLUDE = 0, + SW8_SEL_FIRST16 = 1, + SW8_SEL_SECOND16 = 2, + SW8_SEL_ALL32 = 3, +}; + +enum { + DW8_SEL_EXCLUDE = 0, + DW8_SEL_FIRST16 = 1, + DW8_SEL_SECOND16 = 2, + DW8_SEL_FIRST32 = 3, + DW8_SEL_FIRST32_SWAP16 = 4, + DW8_SEL_ALL64 = 5, +}; + +enum { + SW9_SEL_EXCLUDE = 0, + SW9_SEL_FIRST16 = 1, + SW9_SEL_ALL32 = 2, +}; + +enum { + DW10_SEL_EXCLUDE = 0, + DW10_SEL_FIRST16 = 1, + DW10_SEL_FIRST32 = 2, + DW10_SEL_ALL64 = 3, +}; + +enum { + SWX_SEL_EXCLUDE = 0, + SWX_SEL_ALL32 = 1, +}; + +enum { + PROT_OTHER = 0, + PROT_L2_ETH2 = 1, + PROT_L2_SNAP = 2, + PROT_L2_LLC = 3, + PROT_L2_RAW = 4, + PROT_L2_PPPOE_D = 5, + PROT_L2_PPOE_S = 6 +}; + +enum { PROT_L3_IPV4 = 1, PROT_L3_IPV6 = 2 }; + +enum { PROT_L4_TCP = 1, PROT_L4_UDP = 2, PROT_L4_SCTP = 3, PROT_L4_ICMP = 4 }; + +enum { + PROT_TUN_IP_IN_IP = 1, + PROT_TUN_ETHER_IP = 2, + PROT_TUN_GREV0 = 3, + PROT_TUN_GREV1 = 4, + PROT_TUN_GTPV0U = 5, + PROT_TUN_GTPV1U = 6, + PROT_TUN_GTPV1C = 7, + PROT_TUN_GTPV2C = 8, + PROT_TUN_VXLAN = 9, + PROT_TUN_PSEUDO_WIRE = 10 +}; + +enum { PROT_TUN_L2_OTHER = 0, PROT_TUN_L2_ETH2 = 1 }; + +enum { PROT_TUN_L3_OTHER = 0, PROT_TUN_L3_IPV4 = 1, PROT_TUN_L3_IPV6 = 2 }; + +enum { + PROT_TUN_L4_OTHER = 0, + PROT_TUN_L4_TCP = 1, + PROT_TUN_L4_UDP = 2, + PROT_TUN_L4_SCTP = 3, + PROT_TUN_L4_ICMP = 4 +}; + +enum { + IP_FRAG_NOT_A_FRAG = 0, + IP_FRAG_FIRST = 1, + IP_FRAG_MIDDLE = 2, + IP_FRAG_LAST = 3 +}; + +enum { + HASH_HASH_NONE = 0, + HASH_USER_DEFINED = 1, + HASH_LAST_MPLS_LABEL = 2, + HASH_ALL_MPLS_LABELS = 3, + HASH_2TUPLE = 4, + HASH_2TUPLESORTED = 5, + HASH_LAST_VLAN_ID = 6, + HASH_ALL_VLAN_IDS = 7, + HASH_5TUPLE = 8, + HASH_5TUPLESORTED = 9, + HASH_3TUPLE_GRE_V0 = 10, + HASH_3TUPLE_GRE_V0_SORTED = 11, + HASH_5TUPLE_SCTP = 12, + HASH_5TUPLE_SCTP_SORTED = 13, + HASH_3TUPLE_GTP_V0 = 14, + HASH_3TUPLE_GTP_V0_SORTED = 15, + HASH_3TUPLE_GTP_V1V2 = 16, + HASH_3TUPLE_GTP_V1V2_SORTED = 17, + HASH_HASHINNER_2TUPLE = 18, + HASH_HASHINNER_2TUPLESORTED = 19, + HASH_HASHINNER_5TUPLE = 20, + HASH_HASHINNER_5TUPLESORTED = 21, + HASH_KM = 30, + HASH_ROUND_ROBIN = 31, + HASH_OUTER_DST_IP = 32, + HASH_INNER_SRC_IP = 33, +}; + +enum { + CPY_SELECT_DSCP_IPV4 = 0, + CPY_SELECT_DSCP_IPV6 = 1, + CPY_SELECT_RQI_QFI = 2, + CPY_SELECT_IPV4 = 3, + CPY_SELECT_PORT = 4, + CPY_SELECT_TEID = 5, +}; + +#define RCK_CML(_comp_) (1 << ((_comp_) * 4)) +#define RCK_CMU(_comp_) (1 << ((_comp_) * 4 + 1)) +#define RCK_SEL(_comp_) (1 << ((_comp_) * 4 + 2)) +#define RCK_SEU(_comp_) (1 << ((_comp_) * 4 + 3)) + +#define RCK_EXT(x) (((uint32_t)(x) << 6)) + +#define FIELD_START_INDEX 100 + +#define COMMON_FUNC_INFO_S \ + int ver; \ + void *base; \ + unsigned int allocated_size; \ + int debug + +struct common_func_s { + COMMON_FUNC_INFO_S; +}; + +struct cat_func_s { + COMMON_FUNC_INFO_S; + uint32_t nb_cat_funcs; + uint32_t nb_flow_types; + uint32_t nb_pm_ext; + uint32_t nb_len; + uint32_t kcc_size; + uint32_t cts_num; + uint32_t kcc_banks; + uint32_t kcc_id_bit_size; + uint32_t kcc_records; + uint32_t km_if_count; + int32_t km_if_m0; + int32_t km_if_m1; + + union { + struct hw_mod_cat_v18_s v18; + struct hw_mod_cat_v21_s v21; + struct hw_mod_cat_v22_s v22; + }; +}; + +enum hw_cat_e { + /* + * functions initial CAT v18 + */ + /* 00 */ HW_CAT_CFN_SET_ALL_DEFAULTS = 0, + /* 01 */ HW_CAT_CFN_PRESET_ALL, + /* 02 */ HW_CAT_CFN_COMPARE, + /* 03 */ HW_CAT_CFN_FIND, + /* 04 */ HW_CAT_CFN_COPY_FROM, + /* 05 */ HW_CAT_COT_PRESET_ALL, + /* 06 */ HW_CAT_COT_COMPARE, + /* 07 */ HW_CAT_COT_FIND, + /* fields */ + /* 00 */ HW_CAT_CFN_ENABLE = FIELD_START_INDEX, + /* 01 */ HW_CAT_CFN_INV, + /* 02 */ HW_CAT_CFN_PTC_INV, + /* 03 */ HW_CAT_CFN_PTC_ISL, + /* 04 */ HW_CAT_CFN_PTC_CFP, + /* 05 */ HW_CAT_CFN_PTC_MAC, + /* 06 */ HW_CAT_CFN_PTC_L2, + /* 07 */ HW_CAT_CFN_PTC_VNTAG, + /* 08 */ HW_CAT_CFN_PTC_VLAN, + /* 09 */ HW_CAT_CFN_PTC_MPLS, + /* 10 */ HW_CAT_CFN_PTC_L3, + /* 11 */ HW_CAT_CFN_PTC_FRAG, + /* 12 */ HW_CAT_CFN_PTC_IP_PROT, + /* 13 */ HW_CAT_CFN_PTC_L4, + /* 14 */ HW_CAT_CFN_PTC_TUNNEL, + /* 15 */ HW_CAT_CFN_PTC_TNL_L2, + /* 16 */ HW_CAT_CFN_PTC_TNL_VLAN, + /* 17 */ HW_CAT_CFN_PTC_TNL_MPLS, + /* 18 */ HW_CAT_CFN_PTC_TNL_L3, + /* 19 */ HW_CAT_CFN_PTC_TNL_FRAG, + /* 20 */ HW_CAT_CFN_PTC_TNL_IP_PROT, + /* 21 */ HW_CAT_CFN_PTC_TNL_L4, + /* 22 */ HW_CAT_CFN_ERR_INV, + /* 23 */ HW_CAT_CFN_ERR_CV, + /* 24 */ HW_CAT_CFN_ERR_FCS, + /* 25 */ HW_CAT_CFN_ERR_TRUNC, + /* 26 */ HW_CAT_CFN_ERR_L3_CS, + /* 27 */ HW_CAT_CFN_ERR_L4_CS, + /* 28 */ HW_CAT_CFN_MAC_PORT, + /* 29 */ HW_CAT_CFN_PM_CMP, + /* 30 */ HW_CAT_CFN_PM_DCT, + /* 31 */ HW_CAT_CFN_PM_EXT_INV, + /* 32 */ HW_CAT_CFN_PM_CMB, + /* 33 */ HW_CAT_CFN_PM_AND_INV, + /* 34 */ HW_CAT_CFN_PM_OR_INV, + /* 35 */ HW_CAT_CFN_PM_INV, + /* 36 */ HW_CAT_CFN_LC, + /* 37 */ HW_CAT_CFN_LC_INV, + /* 38 */ HW_CAT_CFN_KM0_OR, + /* 39 */ HW_CAT_CFN_KM1_OR, + /* 40 */ HW_CAT_KCE_ENABLE_BM, + /* 41 */ HW_CAT_KCS_CATEGORY, + /* 42 */ HW_CAT_FTE_ENABLE_BM, + /* 43 */ HW_CAT_CTE_ENABLE_BM, + /* 44 */ HW_CAT_CTS_CAT_A, + /* 45 */ HW_CAT_CTS_CAT_B, + /* 46 */ HW_CAT_COT_COLOR, + /* 47 */ HW_CAT_COT_KM, + /* 48 */ HW_CAT_CCT_COLOR, + /* 49 */ HW_CAT_CCT_KM, + /* 50 */ HW_CAT_KCC_KEY, + /* 51 */ HW_CAT_KCC_CATEGORY, + /* 52 */ HW_CAT_KCC_ID, + /* 53 */ HW_CAT_EXO_DYN, + /* 54 */ HW_CAT_EXO_OFS, + /* 55 */ HW_CAT_RCK_DATA, + /* 56 */ HW_CAT_LEN_LOWER, + /* 57 */ HW_CAT_LEN_UPPER, + /* 58 */ HW_CAT_LEN_DYN1, + /* 59 */ HW_CAT_LEN_DYN2, + /* 60 */ HW_CAT_LEN_INV, + /* 61 */ HW_CAT_CFN_ERR_TNL_L3_CS, + /* 62 */ HW_CAT_CFN_ERR_TNL_L4_CS, + /* 63 */ HW_CAT_CFN_ERR_TTL_EXP, + /* 64 */ HW_CAT_CFN_ERR_TNL_TTL_EXP, + + /* 65 */ HW_CAT_CCE_IMM, + /* 66 */ HW_CAT_CCE_IND, + /* 67 */ HW_CAT_CCS_COR_EN, + /* 68 */ HW_CAT_CCS_COR, + /* 69 */ HW_CAT_CCS_HSH_EN, + /* 70 */ HW_CAT_CCS_HSH, + /* 71 */ HW_CAT_CCS_QSL_EN, + /* 72 */ HW_CAT_CCS_QSL, + /* 73 */ HW_CAT_CCS_IPF_EN, + /* 74 */ HW_CAT_CCS_IPF, + /* 75 */ HW_CAT_CCS_SLC_EN, + /* 76 */ HW_CAT_CCS_SLC, + /* 77 */ HW_CAT_CCS_PDB_EN, + /* 78 */ HW_CAT_CCS_PDB, + /* 79 */ HW_CAT_CCS_MSK_EN, + /* 80 */ HW_CAT_CCS_MSK, + /* 81 */ HW_CAT_CCS_HST_EN, + /* 82 */ HW_CAT_CCS_HST, + /* 83 */ HW_CAT_CCS_EPP_EN, + /* 84 */ HW_CAT_CCS_EPP, + /* 85 */ HW_CAT_CCS_TPE_EN, + /* 86 */ HW_CAT_CCS_TPE, + /* 87 */ HW_CAT_CCS_RRB_EN, + /* 88 */ HW_CAT_CCS_RRB, + /* 89 */ HW_CAT_CCS_SB0_TYPE, + /* 90 */ HW_CAT_CCS_SB0_DATA, + /* 91 */ HW_CAT_CCS_SB1_TYPE, + /* 92 */ HW_CAT_CCS_SB1_DATA, + /* 93 */ HW_CAT_CCS_SB2_TYPE, + /* 94 */ HW_CAT_CCS_SB2_DATA, + +}; + +bool hw_mod_cat_present(struct flow_api_backend_s *be); +int hw_mod_cat_alloc(struct flow_api_backend_s *be); +void hw_mod_cat_free(struct flow_api_backend_s *be); +int hw_mod_cat_reset(struct flow_api_backend_s *be); +int hw_mod_cat_cfn_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_cat_cfn_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, int word_off, uint32_t value); +int hw_mod_cat_cfn_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, int word_off, uint32_t *value); +/* KCE/KCS/FTE KM */ +int hw_mod_cat_kce_km_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int start_idx, + int count); +int hw_mod_cat_kce_km_set(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t value); +int hw_mod_cat_kce_km_get(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t *value); +int hw_mod_cat_kcs_km_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int start_idx, + int count); +int hw_mod_cat_kcs_km_set(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t value); +int hw_mod_cat_kcs_km_get(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t *value); +int hw_mod_cat_fte_km_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int start_idx, + int count); +int hw_mod_cat_fte_km_set(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t value); +int hw_mod_cat_fte_km_get(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t *value); +/* KCE/KCS/FTE FLM */ +int hw_mod_cat_kce_flm_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int start_idx, + int count); +int hw_mod_cat_kce_flm_set(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t value); +int hw_mod_cat_kce_flm_get(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t *value); +int hw_mod_cat_kcs_flm_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int start_idx, + int count); +int hw_mod_cat_kcs_flm_set(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t value); +int hw_mod_cat_kcs_flm_get(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t *value); +int hw_mod_cat_fte_flm_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int start_idx, + int count); +int hw_mod_cat_fte_flm_set(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t value); +int hw_mod_cat_fte_flm_get(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t *value); + +int hw_mod_cat_cte_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_cat_cte_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value); +int hw_mod_cat_cte_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value); +int hw_mod_cat_cts_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_cat_cts_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value); +int hw_mod_cat_cts_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value); +int hw_mod_cat_cot_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_cat_cot_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value); +int hw_mod_cat_cot_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value); +int hw_mod_cat_cct_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_cat_cct_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value); +int hw_mod_cat_cct_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value); +int hw_mod_cat_kcc_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_cat_kcc_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, int word_off, uint32_t value); +int hw_mod_cat_kcc_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, int word_off, uint32_t *value); + +int hw_mod_cat_exo_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_cat_exo_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value); +int hw_mod_cat_exo_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value); +int hw_mod_cat_rck_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_cat_rck_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value); +int hw_mod_cat_rck_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value); +int hw_mod_cat_len_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_cat_len_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value); +int hw_mod_cat_len_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value); +/* added in v22 */ +int hw_mod_cat_cce_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_cat_cce_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value); +int hw_mod_cat_cce_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value); +int hw_mod_cat_ccs_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_cat_ccs_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value); +int hw_mod_cat_ccs_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value); + +struct km_func_s { + COMMON_FUNC_INFO_S; + uint32_t nb_categories; + uint32_t nb_cam_banks; + uint32_t nb_cam_record_words; + uint32_t nb_cam_records; + uint32_t nb_tcam_banks; + uint32_t nb_tcam_bank_width; + /* not read from backend, but rather set using version */ + uint32_t nb_km_rcp_mask_a_word_size; + uint32_t nb_km_rcp_mask_b_word_size; + union { + struct hw_mod_km_v7_s v7; + }; +}; + +enum hw_km_e { + /* functions */ + HW_KM_RCP_PRESET_ALL = 0, + HW_KM_CAM_PRESET_ALL, + /* to sync and reset hw with cache - force write all entries in a bank */ + HW_KM_TCAM_BANK_RESET, + /* fields */ + HW_KM_RCP_QW0_DYN = FIELD_START_INDEX, + HW_KM_RCP_QW0_OFS, + HW_KM_RCP_QW0_SEL_A, + HW_KM_RCP_QW0_SEL_B, + HW_KM_RCP_QW4_DYN, + HW_KM_RCP_QW4_OFS, + HW_KM_RCP_QW4_SEL_A, + HW_KM_RCP_QW4_SEL_B, + HW_KM_RCP_DW8_DYN, + HW_KM_RCP_DW8_OFS, + HW_KM_RCP_DW8_SEL_A, + HW_KM_RCP_DW8_SEL_B, + HW_KM_RCP_DW10_DYN, + HW_KM_RCP_DW10_OFS, + HW_KM_RCP_DW10_SEL_A, + HW_KM_RCP_DW10_SEL_B, + HW_KM_RCP_SWX_CCH, + HW_KM_RCP_SWX_SEL_A, + HW_KM_RCP_SWX_SEL_B, + HW_KM_RCP_MASK_A, + HW_KM_RCP_MASK_B, + HW_KM_RCP_DUAL, + HW_KM_RCP_PAIRED, + HW_KM_RCP_EL_A, + HW_KM_RCP_EL_B, + HW_KM_RCP_INFO_A, + HW_KM_RCP_INFO_B, + HW_KM_RCP_FTM_A, + HW_KM_RCP_FTM_B, + HW_KM_RCP_BANK_A, + HW_KM_RCP_BANK_B, + HW_KM_RCP_KL_A, + HW_KM_RCP_KL_B, + HW_KM_RCP_KEYWAY_A, + HW_KM_RCP_KEYWAY_B, + HW_KM_RCP_SYNERGY_MODE, + HW_KM_RCP_DW0_B_DYN, + HW_KM_RCP_DW0_B_OFS, + HW_KM_RCP_DW2_B_DYN, + HW_KM_RCP_DW2_B_OFS, + HW_KM_RCP_SW4_B_DYN, + HW_KM_RCP_SW4_B_OFS, + HW_KM_RCP_SW5_B_DYN, + HW_KM_RCP_SW5_B_OFS, + HW_KM_CAM_W0, + HW_KM_CAM_W1, + HW_KM_CAM_W2, + HW_KM_CAM_W3, + HW_KM_CAM_W4, + HW_KM_CAM_W5, + HW_KM_CAM_FT0, + HW_KM_CAM_FT1, + HW_KM_CAM_FT2, + HW_KM_CAM_FT3, + HW_KM_CAM_FT4, + HW_KM_CAM_FT5, + HW_KM_TCAM_T, + HW_KM_TCI_COLOR, + HW_KM_TCI_FT, + HW_KM_TCQ_BANK_MASK, + HW_KM_TCQ_QUAL +}; + +bool hw_mod_km_present(struct flow_api_backend_s *be); +int hw_mod_km_alloc(struct flow_api_backend_s *be); +void hw_mod_km_free(struct flow_api_backend_s *be); +int hw_mod_km_reset(struct flow_api_backend_s *be); +int hw_mod_km_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_km_rcp_set(struct flow_api_backend_s *be, enum hw_km_e field, + int index, int word_off, uint32_t value); +int hw_mod_km_rcp_get(struct flow_api_backend_s *be, enum hw_km_e field, + int index, int word_off, uint32_t *value); +int hw_mod_km_cam_flush(struct flow_api_backend_s *be, int start_bank, + int start_record, int count); +int hw_mod_km_cam_set(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t value); +int hw_mod_km_cam_get(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t *value); +int hw_mod_km_tcam_flush(struct flow_api_backend_s *be, int start_bank, + int count); +int hw_mod_km_tcam_set(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int byte, int byte_val, uint32_t *value_set); +int hw_mod_km_tcam_get(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int byte, int byte_val, uint32_t *value_set); +int hw_mod_km_tci_flush(struct flow_api_backend_s *be, int start_bank, + int start_record, int count); +int hw_mod_km_tci_set(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t value); +int hw_mod_km_tci_get(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t *value); +int hw_mod_km_tcq_flush(struct flow_api_backend_s *be, int start_bank, + int start_record, int count); +int hw_mod_km_tcq_set(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t *value); +int hw_mod_km_tcq_get(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t *value); + +struct hst_func_s { + COMMON_FUNC_INFO_S; + uint32_t nb_hst_rcp_categories; + union { + struct hw_mod_hst_v2_s v2; + }; +}; + +enum hw_hst_e { + /* functions */ + HW_HST_RCP_PRESET_ALL = 0, + HW_HST_RCP_FIND, + HW_HST_RCP_COMPARE, + /* Control fields */ + HW_HST_RCP_STRIP_MODE = FIELD_START_INDEX, + HW_HST_RCP_START_DYN, + HW_HST_RCP_START_OFS, + HW_HST_RCP_END_DYN, + HW_HST_RCP_END_OFS, + HW_HST_RCP_MODIF0_CMD, + HW_HST_RCP_MODIF0_DYN, + HW_HST_RCP_MODIF0_OFS, + HW_HST_RCP_MODIF0_VALUE, + HW_HST_RCP_MODIF1_CMD, + HW_HST_RCP_MODIF1_DYN, + HW_HST_RCP_MODIF1_OFS, + HW_HST_RCP_MODIF1_VALUE, + HW_HST_RCP_MODIF2_CMD, + HW_HST_RCP_MODIF2_DYN, + HW_HST_RCP_MODIF2_OFS, + HW_HST_RCP_MODIF2_VALUE, + +}; + +bool hw_mod_hst_present(struct flow_api_backend_s *be); +int hw_mod_hst_alloc(struct flow_api_backend_s *be); +void hw_mod_hst_free(struct flow_api_backend_s *be); +int hw_mod_hst_reset(struct flow_api_backend_s *be); + +int hw_mod_hst_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_hst_rcp_set(struct flow_api_backend_s *be, enum hw_hst_e field, + int index, uint32_t value); +int hw_mod_hst_rcp_get(struct flow_api_backend_s *be, enum hw_hst_e field, + int index, uint32_t *value); + +struct flm_func_s { + COMMON_FUNC_INFO_S; + uint32_t nb_categories; + uint32_t nb_size_mb; + uint32_t nb_entry_size; + uint32_t nb_variant; + uint32_t nb_prios; + uint32_t nb_pst_profiles; + union { + struct hw_mod_flm_v17_s v17; + struct hw_mod_flm_v20_s v20; + }; +}; + +enum hw_flm_e { + /* functions */ + HW_FLM_CONTROL_PRESET_ALL = 0, + HW_FLM_RCP_PRESET_ALL, + HW_FLM_FLOW_LRN_DATA_V17, + HW_FLM_FLOW_INF_DATA_V17, + HW_FLM_FLOW_STA_DATA_V17, + /* Control fields */ + HW_FLM_CONTROL_ENABLE = FIELD_START_INDEX, + HW_FLM_CONTROL_INIT, + HW_FLM_CONTROL_LDS, + HW_FLM_CONTROL_LFS, + HW_FLM_CONTROL_LIS, + HW_FLM_CONTROL_UDS, + HW_FLM_CONTROL_UIS, + HW_FLM_CONTROL_RDS, + HW_FLM_CONTROL_RIS, + HW_FLM_CONTROL_PDS, + HW_FLM_CONTROL_PIS, + HW_FLM_CONTROL_CRCWR, + HW_FLM_CONTROL_CRCRD, + HW_FLM_CONTROL_RBL, + HW_FLM_CONTROL_EAB, + HW_FLM_CONTROL_SPLIT_SDRAM_USAGE, + HW_FLM_STATUS_CALIBDONE, + HW_FLM_STATUS_INITDONE, + HW_FLM_STATUS_IDLE, + HW_FLM_STATUS_CRITICAL, + HW_FLM_STATUS_PANIC, + HW_FLM_STATUS_CRCERR, + HW_FLM_STATUS_EFT_BP, + HW_FLM_TIMEOUT_T, + HW_FLM_SCRUB_I, + HW_FLM_LOAD_BIN, + HW_FLM_LOAD_PPS, + HW_FLM_LOAD_LPS, + HW_FLM_LOAD_APS, + HW_FLM_PRIO_LIMIT0, + HW_FLM_PRIO_FT0, + HW_FLM_PRIO_LIMIT1, + HW_FLM_PRIO_FT1, + HW_FLM_PRIO_LIMIT2, + HW_FLM_PRIO_FT2, + HW_FLM_PRIO_LIMIT3, + HW_FLM_PRIO_FT3, + HW_FLM_PST_PRESET_ALL, + HW_FLM_PST_BP, + HW_FLM_PST_PP, + HW_FLM_PST_TP, + HW_FLM_RCP_LOOKUP, + HW_FLM_RCP_QW0_DYN, + HW_FLM_RCP_QW0_OFS, + HW_FLM_RCP_QW0_SEL, + HW_FLM_RCP_QW4_DYN, + HW_FLM_RCP_QW4_OFS, + HW_FLM_RCP_SW8_DYN, + HW_FLM_RCP_SW8_OFS, + HW_FLM_RCP_SW8_SEL, + HW_FLM_RCP_SW9_DYN, + HW_FLM_RCP_SW9_OFS, + HW_FLM_RCP_MASK, + HW_FLM_RCP_KID, + HW_FLM_RCP_OPN, + HW_FLM_RCP_IPN, + HW_FLM_RCP_BYT_DYN, + HW_FLM_RCP_BYT_OFS, + HW_FLM_RCP_TXPLM, + HW_FLM_RCP_AUTO_IPV4_MASK, + HW_FLM_BUF_CTRL_LRN_FREE, + HW_FLM_BUF_CTRL_INF_AVAIL, + HW_FLM_BUF_CTRL_STA_AVAIL, + HW_FLM_STAT_LRN_DONE, + HW_FLM_STAT_LRN_IGNORE, + HW_FLM_STAT_LRN_FAIL, + HW_FLM_STAT_UNL_DONE, + HW_FLM_STAT_UNL_IGNORE, + HW_FLM_STAT_REL_DONE, + HW_FLM_STAT_REL_IGNORE, + HW_FLM_STAT_PRB_DONE, + HW_FLM_STAT_PRB_IGNORE, + HW_FLM_STAT_AUL_DONE, + HW_FLM_STAT_AUL_IGNORE, + HW_FLM_STAT_AUL_FAIL, + HW_FLM_STAT_TUL_DONE, + HW_FLM_STAT_FLOWS, + HW_FLM_STAT_STA_DONE, /* module ver 0.20 */ + HW_FLM_STAT_INF_DONE, /* module ver 0.20 */ + HW_FLM_STAT_INF_SKIP, /* module ver 0.20 */ + HW_FLM_STAT_PCK_HIT, /* module ver 0.20 */ + HW_FLM_STAT_PCK_MISS, /* module ver 0.20 */ + HW_FLM_STAT_PCK_UNH, /* module ver 0.20 */ + HW_FLM_STAT_PCK_DIS, /* module ver 0.20 */ + HW_FLM_STAT_CSH_HIT, /* module ver 0.20 */ + HW_FLM_STAT_CSH_MISS, /* module ver 0.20 */ + HW_FLM_STAT_CSH_UNH, /* module ver 0.20 */ + HW_FLM_STAT_CUC_START, /* module ver 0.20 */ + HW_FLM_STAT_CUC_MOVE, /* module ver 0.20 */ +}; + +bool hw_mod_flm_present(struct flow_api_backend_s *be); +int hw_mod_flm_alloc(struct flow_api_backend_s *be); +void hw_mod_flm_free(struct flow_api_backend_s *be); +int hw_mod_flm_reset(struct flow_api_backend_s *be); + +int hw_mod_flm_control_flush(struct flow_api_backend_s *be); +int hw_mod_flm_control_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value); +int hw_mod_flm_control_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value); + +int hw_mod_flm_status_flush(struct flow_api_backend_s *be); +int hw_mod_flm_status_update(struct flow_api_backend_s *be); +int hw_mod_flm_status_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value); +int hw_mod_flm_status_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value); + +int hw_mod_flm_timeout_flush(struct flow_api_backend_s *be); +int hw_mod_flm_timeout_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value); +int hw_mod_flm_timeout_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value); + +int hw_mod_flm_scrub_flush(struct flow_api_backend_s *be); +int hw_mod_flm_scrub_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value); +int hw_mod_flm_scrub_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value); + +int hw_mod_flm_load_bin_flush(struct flow_api_backend_s *be); +int hw_mod_flm_load_bin_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value); +int hw_mod_flm_load_bin_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value); + +int hw_mod_flm_load_pps_flush(struct flow_api_backend_s *be); +int hw_mod_flm_load_pps_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value); +int hw_mod_flm_load_pps_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value); + +int hw_mod_flm_load_lps_flush(struct flow_api_backend_s *be); +int hw_mod_flm_load_lps_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value); +int hw_mod_flm_load_lps_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value); + +int hw_mod_flm_load_aps_flush(struct flow_api_backend_s *be); +int hw_mod_flm_load_aps_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value); +int hw_mod_flm_load_aps_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value); + +int hw_mod_flm_prio_flush(struct flow_api_backend_s *be); +int hw_mod_flm_prio_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value); +int hw_mod_flm_prio_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value); + +int hw_mod_flm_pst_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_flm_pst_set(struct flow_api_backend_s *be, enum hw_flm_e field, + int index, uint32_t value); +int hw_mod_flm_pst_get(struct flow_api_backend_s *be, enum hw_flm_e field, + int index, uint32_t *value); + +int hw_mod_flm_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_flm_rcp_set_mask(struct flow_api_backend_s *be, enum hw_flm_e field, + int index, uint32_t *value); +int hw_mod_flm_rcp_set(struct flow_api_backend_s *be, enum hw_flm_e field, + int index, uint32_t value); +int hw_mod_flm_rcp_get(struct flow_api_backend_s *be, enum hw_flm_e field, + int index, uint32_t *value); + +int hw_mod_flm_buf_ctrl_update(struct flow_api_backend_s *be); +int hw_mod_flm_buf_ctrl_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value); + +int hw_mod_flm_stat_update(struct flow_api_backend_s *be); +int hw_mod_flm_stat_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value); + +int hw_mod_flm_lrn_data_set_flush(struct flow_api_backend_s *be, + enum hw_flm_e field, const uint32_t *value); +int hw_mod_flm_inf_data_update_get(struct flow_api_backend_s *be, + enum hw_flm_e field, uint32_t *value, + uint32_t word_cnt); +int hw_mod_flm_sta_data_update_get(struct flow_api_backend_s *be, + enum hw_flm_e field, uint32_t *value); + +struct hsh_func_s { + COMMON_FUNC_INFO_S; + uint32_t nb_rcp; + union { + struct hw_mod_hsh_v5_s v5; + }; +}; + +enum hw_hsh_e { + /* functions */ + HW_HSH_RCP_PRESET_ALL = 0, + HW_HSH_RCP_COMPARE, + HW_HSH_RCP_FIND, + /* fields */ + HW_HSH_RCP_LOAD_DIST_TYPE = FIELD_START_INDEX, + HW_HSH_RCP_MAC_PORT_MASK, + HW_HSH_RCP_SORT, + HW_HSH_RCP_QW0_PE, + HW_HSH_RCP_QW0_OFS, + HW_HSH_RCP_QW4_PE, + HW_HSH_RCP_QW4_OFS, + HW_HSH_RCP_W8_PE, + HW_HSH_RCP_W8_OFS, + HW_HSH_RCP_W8_SORT, + HW_HSH_RCP_W9_PE, + HW_HSH_RCP_W9_OFS, + HW_HSH_RCP_W9_SORT, + HW_HSH_RCP_W9_P, + HW_HSH_RCP_P_MASK, + HW_HSH_RCP_WORD_MASK, + HW_HSH_RCP_SEED, + HW_HSH_RCP_TNL_P, + HW_HSH_RCP_HSH_VALID, + HW_HSH_RCP_HSH_TYPE, + HW_HSH_RCP_AUTO_IPV4_MASK + +}; + +bool hw_mod_hsh_present(struct flow_api_backend_s *be); +int hw_mod_hsh_alloc(struct flow_api_backend_s *be); +void hw_mod_hsh_free(struct flow_api_backend_s *be); +int hw_mod_hsh_reset(struct flow_api_backend_s *be); +int hw_mod_hsh_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_hsh_rcp_set(struct flow_api_backend_s *be, enum hw_hsh_e field, + uint32_t index, uint32_t word_off, uint32_t value); +int hw_mod_hsh_rcp_get(struct flow_api_backend_s *be, enum hw_hsh_e field, + uint32_t index, uint32_t word_off, uint32_t *value); + +struct qsl_func_s { + COMMON_FUNC_INFO_S; + uint32_t nb_rcp_categories; + uint32_t nb_qst_entries; + union { + struct hw_mod_qsl_v7_s v7; + }; +}; + +enum hw_qsl_e { + /* functions */ + HW_QSL_RCP_PRESET_ALL = 0, + HW_QSL_RCP_COMPARE, + HW_QSL_RCP_FIND, + HW_QSL_QST_PRESET_ALL, + /* fields */ + HW_QSL_RCP_DISCARD = FIELD_START_INDEX, + HW_QSL_RCP_DROP, + HW_QSL_RCP_TBL_LO, + HW_QSL_RCP_TBL_HI, + HW_QSL_RCP_TBL_IDX, + HW_QSL_RCP_TBL_MSK, + HW_QSL_RCP_LR, + HW_QSL_RCP_TSA, + HW_QSL_RCP_VLI, + HW_QSL_QST_QUEUE, + HW_QSL_QST_EN, /* Alias: HW_QSL_QST_QEN */ + HW_QSL_QST_TX_PORT, + HW_QSL_QST_LRE, + HW_QSL_QST_TCI, + HW_QSL_QST_VEN, + HW_QSL_QEN_EN, + HW_QSL_UNMQ_DEST_QUEUE, + HW_QSL_UNMQ_EN, + +}; + +bool hw_mod_qsl_present(struct flow_api_backend_s *be); +int hw_mod_qsl_alloc(struct flow_api_backend_s *be); +void hw_mod_qsl_free(struct flow_api_backend_s *be); +int hw_mod_qsl_reset(struct flow_api_backend_s *be); +int hw_mod_qsl_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_qsl_rcp_set(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t value); +int hw_mod_qsl_rcp_get(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t *value); +int hw_mod_qsl_qst_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_qsl_qst_set(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t value); +int hw_mod_qsl_qst_get(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t *value); +int hw_mod_qsl_qen_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_qsl_qen_set(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t value); +int hw_mod_qsl_qen_get(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t *value); +int hw_mod_qsl_unmq_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_qsl_unmq_set(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t value); +int hw_mod_qsl_unmq_get(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t *value); + +struct slc_func_s { + COMMON_FUNC_INFO_S; + union { + struct hw_mod_slc_v1_s v1; + }; +}; + +enum hw_slc_e { + /* functions */ + HW_SLC_RCP_PRESET_ALL = 0, + HW_SLC_RCP_COMPARE, + HW_SLC_RCP_FIND, + /* fields */ + HW_SLC_RCP_SLC_EN = FIELD_START_INDEX, + HW_SLC_RCP_DYN, + HW_SLC_RCP_OFS, + HW_SLC_RCP_PCAP +}; + +bool hw_mod_slc_present(struct flow_api_backend_s *be); +int hw_mod_slc_alloc(struct flow_api_backend_s *be); +void hw_mod_slc_free(struct flow_api_backend_s *be); +int hw_mod_slc_reset(struct flow_api_backend_s *be); +int hw_mod_slc_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_slc_rcp_set(struct flow_api_backend_s *be, enum hw_slc_e field, + uint32_t index, uint32_t value); +int hw_mod_slc_rcp_get(struct flow_api_backend_s *be, enum hw_slc_e field, + uint32_t index, uint32_t *value); + +struct slc_lr_func_s { + COMMON_FUNC_INFO_S; + union { + struct hw_mod_slc_lr_v2_s v2; + }; +}; + +enum hw_slc_lr_e { + /* functions */ + HW_SLC_LR_RCP_PRESET_ALL = 0, + HW_SLC_LR_RCP_COMPARE, + HW_SLC_LR_RCP_FIND, + /* fields */ + HW_SLC_LR_RCP_SLC_EN = FIELD_START_INDEX, + HW_SLC_LR_RCP_DYN, + HW_SLC_LR_RCP_OFS, + HW_SLC_LR_RCP_PCAP +}; + +bool hw_mod_slc_lr_present(struct flow_api_backend_s *be); +int hw_mod_slc_lr_alloc(struct flow_api_backend_s *be); +void hw_mod_slc_lr_free(struct flow_api_backend_s *be); +int hw_mod_slc_lr_reset(struct flow_api_backend_s *be); +int hw_mod_slc_lr_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_slc_lr_rcp_set(struct flow_api_backend_s *be, enum hw_slc_lr_e field, + uint32_t index, uint32_t value); +int hw_mod_slc_lr_rcp_get(struct flow_api_backend_s *be, enum hw_slc_lr_e field, + uint32_t index, uint32_t *value); + +struct pdb_func_s { + COMMON_FUNC_INFO_S; + uint32_t nb_pdb_rcp_categories; + + union { + struct hw_mod_pdb_v9_s v9; + }; +}; + +enum hw_pdb_e { + /* functions */ + HW_PDB_RCP_PRESET_ALL = 0, + HW_PDB_RCP_COMPARE, + HW_PDB_RCP_FIND, + /* fields */ + HW_PDB_RCP_DESCRIPTOR = FIELD_START_INDEX, + HW_PDB_RCP_DESC_LEN, + HW_PDB_RCP_TX_PORT, + HW_PDB_RCP_TX_IGNORE, + HW_PDB_RCP_TX_NOW, + HW_PDB_RCP_CRC_OVERWRITE, + HW_PDB_RCP_ALIGN, + HW_PDB_RCP_OFS0_DYN, + HW_PDB_RCP_OFS0_REL, + HW_PDB_RCP_OFS1_DYN, + HW_PDB_RCP_OFS1_REL, + HW_PDB_RCP_OFS2_DYN, + HW_PDB_RCP_OFS2_REL, + HW_PDB_RCP_IP_PROT_TNL, + HW_PDB_RCP_PPC_HSH, + HW_PDB_RCP_DUPLICATE_EN, + HW_PDB_RCP_DUPLICATE_BIT, + HW_PDB_RCP_PCAP_KEEP_FCS, + HW_PDB_CONFIG_TS_FORMAT, + HW_PDB_CONFIG_PORT_OFS, +}; + +bool hw_mod_pdb_present(struct flow_api_backend_s *be); +int hw_mod_pdb_alloc(struct flow_api_backend_s *be); +void hw_mod_pdb_free(struct flow_api_backend_s *be); +int hw_mod_pdb_reset(struct flow_api_backend_s *be); +int hw_mod_pdb_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_pdb_rcp_set(struct flow_api_backend_s *be, enum hw_pdb_e field, + uint32_t index, uint32_t value); +int hw_mod_pdb_rcp_get(struct flow_api_backend_s *be, enum hw_pdb_e field, + uint32_t index, uint32_t *value); +int hw_mod_pdb_config_flush(struct flow_api_backend_s *be); +int hw_mod_pdb_config_set(struct flow_api_backend_s *be, enum hw_pdb_e field, + uint32_t value); + +struct ioa_func_s { + COMMON_FUNC_INFO_S; + uint32_t nb_rcp_categories; + uint32_t nb_roa_epp_entries; + union { + struct hw_mod_ioa_v4_s v4; + }; +}; + +enum hw_ioa_e { + /* functions */ + HW_IOA_RCP_PRESET_ALL = 0, + HW_IOA_RCP_COMPARE, + HW_IOA_RCP_FIND, + HW_IOA_ROA_EPP_PRESET_ALL, + HW_IOA_ROA_EPP_COMPARE, + HW_IOA_ROA_EPP_FIND, + /* fields */ + HW_IOA_RCP_TUNNEL_POP = FIELD_START_INDEX, + HW_IOA_RCP_VLAN_POP, + HW_IOA_RCP_VLAN_PUSH, + HW_IOA_RCP_VLAN_VID, + HW_IOA_RCP_VLAN_DEI, + HW_IOA_RCP_VLAN_PCP, + HW_IOA_RCP_VLAN_TPID_SEL, + HW_IOA_RCP_QUEUE_OVERRIDE_EN, + HW_IOA_RCP_QUEUE_ID, + HW_IOA_CONFIG_CUST_TPID_0, + HW_IOA_CONFIG_CUST_TPID_1, + HW_IOA_ROA_EPP_PUSH_TUNNEL, + HW_IOA_ROA_EPP_TX_PORT, +}; + +bool hw_mod_ioa_present(struct flow_api_backend_s *be); +int hw_mod_ioa_alloc(struct flow_api_backend_s *be); +void hw_mod_ioa_free(struct flow_api_backend_s *be); +int hw_mod_ioa_reset(struct flow_api_backend_s *be); +int hw_mod_ioa_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_ioa_rcp_set(struct flow_api_backend_s *be, enum hw_ioa_e field, + uint32_t index, uint32_t value); +int hw_mod_ioa_rcp_get(struct flow_api_backend_s *be, enum hw_ioa_e field, + uint32_t index, uint32_t *value); +int hw_mod_ioa_config_flush(struct flow_api_backend_s *be); +int hw_mod_ioa_config_set(struct flow_api_backend_s *be, enum hw_ioa_e field, + uint32_t value); + +int hw_mod_ioa_roa_epp_set(struct flow_api_backend_s *be, enum hw_ioa_e field, + uint32_t index, uint32_t value); +int hw_mod_ioa_roa_epp_get(struct flow_api_backend_s *be, enum hw_ioa_e field, + uint32_t index, uint32_t *value); +int hw_mod_ioa_roa_epp_flush(struct flow_api_backend_s *be, int start_idx, + int count); + +struct roa_func_s { + COMMON_FUNC_INFO_S; + uint32_t nb_tun_categories; + uint32_t nb_lag_entries; + union { + struct hw_mod_roa_v6_s v6; + }; +}; + +enum hw_roa_e { + /* functions */ + HW_ROA_TUNHDR_COMPARE = 0, + HW_ROA_TUNCFG_PRESET_ALL, + HW_ROA_TUNCFG_COMPARE, + HW_ROA_TUNCFG_FIND, + /* fields */ + HW_ROA_TUNHDR = FIELD_START_INDEX, + HW_ROA_TUNCFG_TUN_LEN, + HW_ROA_TUNCFG_TUN_TYPE, + HW_ROA_TUNCFG_TUN_VLAN, + HW_ROA_TUNCFG_IP_TYPE, + HW_ROA_TUNCFG_IPCS_UPD, + HW_ROA_TUNCFG_IPCS_PRECALC, + HW_ROA_TUNCFG_IPTL_UPD, + HW_ROA_TUNCFG_IPTL_PRECALC, + HW_ROA_TUNCFG_VXLAN_UDP_LEN_UPD, + HW_ROA_TUNCFG_TX_LAG_IX, + HW_ROA_TUNCFG_RECIRCULATE, + HW_ROA_TUNCFG_PUSH_TUNNEL, + HW_ROA_TUNCFG_RECIRC_PORT, + HW_ROA_TUNCFG_RECIRC_BYPASS, + HW_ROA_CONFIG_FWD_RECIRCULATE, + HW_ROA_CONFIG_FWD_NORMAL_PCKS, + HW_ROA_CONFIG_FWD_TXPORT0, + HW_ROA_CONFIG_FWD_TXPORT1, + HW_ROA_CONFIG_FWD_CELLBUILDER_PCKS, + HW_ROA_CONFIG_FWD_NON_NORMAL_PCKS, + HW_ROA_LAGCFG_TXPHY_PORT, + HW_ROA_IGS_PKT_DROP, + HW_ROA_IGS_BYTE_DROP, + HW_ROA_RCC_PKT_DROP, + HW_ROA_RCC_BYTE_DROP, +}; + +bool hw_mod_roa_present(struct flow_api_backend_s *be); +int hw_mod_roa_alloc(struct flow_api_backend_s *be); +void hw_mod_roa_free(struct flow_api_backend_s *be); +int hw_mod_roa_reset(struct flow_api_backend_s *be); +int hw_mod_roa_tunhdr_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_roa_tunhdr_set(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t index, uint32_t word_off, uint32_t value); +int hw_mod_roa_tunhdr_get(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t index, uint32_t word_off, uint32_t *value); +int hw_mod_roa_tuncfg_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_roa_tuncfg_set(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t index, uint32_t value); +int hw_mod_roa_tuncfg_get(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t index, uint32_t *value); +int hw_mod_roa_config_flush(struct flow_api_backend_s *be); +int hw_mod_roa_config_set(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t value); +int hw_mod_roa_config_get(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t *value); +int hw_mod_roa_lagcfg_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_roa_lagcfg_set(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t index, uint32_t value); +int hw_mod_roa_lagcfg_get(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t index, uint32_t *value); +int hw_mod_roa_igs_pkt_set(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t value); +int hw_mod_roa_igs_pkt_get(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t *value); +int hw_mod_roa_igs_pkt_flush(struct flow_api_backend_s *be); +int hw_mod_roa_igs_byte_set(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t value); +int hw_mod_roa_igs_byte_get(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t *value); +int hw_mod_roa_igs_byte_flush(struct flow_api_backend_s *be); +int hw_mod_roa_rcc_pkt_set(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t value); +int hw_mod_roa_rcc_pkt_get(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t *value); +int hw_mod_roa_rcc_pkt_flush(struct flow_api_backend_s *be); +int hw_mod_roa_rcc_byte_set(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t value); +int hw_mod_roa_rcc_byte_get(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t *value); +int hw_mod_roa_rcc_byte_flush(struct flow_api_backend_s *be); + +struct rmc_func_s { + COMMON_FUNC_INFO_S; + union { + struct hw_mod_rmc_v1_3_s v1_3; + }; +}; + +enum hw_rmc_e { + HW_RMC_BLOCK_STATT = FIELD_START_INDEX, + HW_RMC_BLOCK_KEEPA, + HW_RMC_BLOCK_RPP_SLICE, + HW_RMC_BLOCK_MAC_PORT, + HW_RMC_LAG_PHY_ODD_EVEN, +}; + +bool hw_mod_rmc_present(struct flow_api_backend_s *be); +int hw_mod_rmc_alloc(struct flow_api_backend_s *be); +void hw_mod_rmc_free(struct flow_api_backend_s *be); +int hw_mod_rmc_reset(struct flow_api_backend_s *be); +int hw_mod_rmc_ctrl_set(struct flow_api_backend_s *be, enum hw_rmc_e field, + uint32_t value); +int hw_mod_rmc_ctrl_get(struct flow_api_backend_s *be, enum hw_rmc_e field, + uint32_t *value); +int hw_mod_rmc_ctrl_flush(struct flow_api_backend_s *be); + +struct tpe_func_s { + COMMON_FUNC_INFO_S; + uint32_t nb_rcp_categories; + uint32_t nb_ifr_categories; + uint32_t nb_cpy_writers; + uint32_t nb_rpl_depth; + uint32_t nb_rpl_ext_categories; + union { + struct hw_mod_tpe_v1_s v1; + struct hw_mod_tpe_v2_s v2; + }; +}; + +enum hw_tpe_e { + /* functions */ + HW_TPE_PRESET_ALL = 0, + HW_TPE_FIND, + HW_TPE_COMPARE, + /* Control fields */ + HW_TPE_RPP_RCP_EXP = FIELD_START_INDEX, + HW_TPE_IFR_RCP_EN, + HW_TPE_IFR_RCP_MTU, + HW_TPE_INS_RCP_DYN, + HW_TPE_INS_RCP_OFS, + HW_TPE_INS_RCP_LEN, + HW_TPE_RPL_RCP_DYN, + HW_TPE_RPL_RCP_OFS, + HW_TPE_RPL_RCP_LEN, + HW_TPE_RPL_RCP_RPL_PTR, + HW_TPE_RPL_RCP_EXT_PRIO, + HW_TPE_RPL_EXT_RPL_PTR, + HW_TPE_RPL_EXT_META_RPL_LEN, /* SW only */ + HW_TPE_RPL_RPL_VALUE, + HW_TPE_CPY_RCP_READER_SELECT, + HW_TPE_CPY_RCP_DYN, + HW_TPE_CPY_RCP_OFS, + HW_TPE_CPY_RCP_LEN, + HW_TPE_HFU_RCP_LEN_A_WR, + HW_TPE_HFU_RCP_LEN_A_OUTER_L4_LEN, + HW_TPE_HFU_RCP_LEN_A_POS_DYN, + HW_TPE_HFU_RCP_LEN_A_POS_OFS, + HW_TPE_HFU_RCP_LEN_A_ADD_DYN, + HW_TPE_HFU_RCP_LEN_A_ADD_OFS, + HW_TPE_HFU_RCP_LEN_A_SUB_DYN, + HW_TPE_HFU_RCP_LEN_B_WR, + HW_TPE_HFU_RCP_LEN_B_POS_DYN, + HW_TPE_HFU_RCP_LEN_B_POS_OFS, + HW_TPE_HFU_RCP_LEN_B_ADD_DYN, + HW_TPE_HFU_RCP_LEN_B_ADD_OFS, + HW_TPE_HFU_RCP_LEN_B_SUB_DYN, + HW_TPE_HFU_RCP_LEN_C_WR, + HW_TPE_HFU_RCP_LEN_C_POS_DYN, + HW_TPE_HFU_RCP_LEN_C_POS_OFS, + HW_TPE_HFU_RCP_LEN_C_ADD_DYN, + HW_TPE_HFU_RCP_LEN_C_ADD_OFS, + HW_TPE_HFU_RCP_LEN_C_SUB_DYN, + HW_TPE_HFU_RCP_TTL_WR, + HW_TPE_HFU_RCP_TTL_POS_DYN, + HW_TPE_HFU_RCP_TTL_POS_OFS, + HW_TPE_HFU_RCP_CS_INF, + HW_TPE_HFU_RCP_L3_PRT, + HW_TPE_HFU_RCP_L3_FRAG, + HW_TPE_HFU_RCP_TUNNEL, + HW_TPE_HFU_RCP_L4_PRT, + HW_TPE_HFU_RCP_OUTER_L3_OFS, + HW_TPE_HFU_RCP_OUTER_L4_OFS, + HW_TPE_HFU_RCP_INNER_L3_OFS, + HW_TPE_HFU_RCP_INNER_L4_OFS, + HW_TPE_CSU_RCP_OUTER_L3_CMD, + HW_TPE_CSU_RCP_OUTER_L4_CMD, + HW_TPE_CSU_RCP_INNER_L3_CMD, + HW_TPE_CSU_RCP_INNER_L4_CMD, +}; + +bool hw_mod_tpe_present(struct flow_api_backend_s *be); +int hw_mod_tpe_alloc(struct flow_api_backend_s *be); +void hw_mod_tpe_free(struct flow_api_backend_s *be); +int hw_mod_tpe_reset(struct flow_api_backend_s *be); + +int hw_mod_tpe_rpp_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_tpe_rpp_rcp_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value); +int hw_mod_tpe_rpp_rcp_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value); + +int hw_mod_tpe_rpp_ifr_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_tpe_rpp_ifr_rcp_set(struct flow_api_backend_s *be, + enum hw_tpe_e field, int index, uint32_t value); +int hw_mod_tpe_rpp_ifr_rcp_get(struct flow_api_backend_s *be, + enum hw_tpe_e field, int index, uint32_t *value); + +int hw_mod_tpe_ifr_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_tpe_ifr_rcp_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value); +int hw_mod_tpe_ifr_rcp_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value); + +int hw_mod_tpe_ins_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_tpe_ins_rcp_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value); +int hw_mod_tpe_ins_rcp_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value); + +int hw_mod_tpe_rpl_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_tpe_rpl_rcp_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value); +int hw_mod_tpe_rpl_rcp_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value); + +int hw_mod_tpe_rpl_ext_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_tpe_rpl_ext_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value); +int hw_mod_tpe_rpl_ext_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value); + +int hw_mod_tpe_rpl_rpl_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_tpe_rpl_rpl_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value); +int hw_mod_tpe_rpl_rpl_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value); + +int hw_mod_tpe_cpy_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_tpe_cpy_rcp_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value); +int hw_mod_tpe_cpy_rcp_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value); + +int hw_mod_tpe_hfu_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_tpe_hfu_rcp_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value); +int hw_mod_tpe_hfu_rcp_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value); + +int hw_mod_tpe_csu_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count); +int hw_mod_tpe_csu_rcp_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value); +int hw_mod_tpe_csu_rcp_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value); + +enum debug_mode_e { + FLOW_BACKEND_DEBUG_MODE_NONE = 0x0000, + FLOW_BACKEND_DEBUG_MODE_WRITE = 0x0001 +}; + +struct flow_api_backend_ops { + int version; + int (*set_debug_mode)(void *dev, enum debug_mode_e mode); + int (*get_nb_phy_port)(void *dev); + int (*get_nb_rx_port)(void *dev); + int (*get_ltx_avail)(void *dev); + int (*get_nb_cat_funcs)(void *dev); + int (*get_nb_categories)(void *dev); + int (*get_nb_cat_km_if_cnt)(void *dev); + int (*get_nb_cat_km_if_m0)(void *dev); + int (*get_nb_cat_km_if_m1)(void *dev); + + int (*get_nb_queues)(void *dev); + int (*get_nb_km_flow_types)(void *dev); + int (*get_nb_pm_ext)(void *dev); + int (*get_nb_len)(void *dev); + int (*get_kcc_size)(void *dev); + int (*get_kcc_banks)(void *dev); + int (*get_nb_km_categories)(void *dev); + int (*get_nb_km_cam_banks)(void *dev); + int (*get_nb_km_cam_record_words)(void *dev); + int (*get_nb_km_cam_records)(void *dev); + int (*get_nb_km_tcam_banks)(void *dev); + int (*get_nb_km_tcam_bank_width)(void *dev); + int (*get_nb_flm_categories)(void *dev); + int (*get_nb_flm_size_mb)(void *dev); + int (*get_nb_flm_entry_size)(void *dev); + int (*get_nb_flm_variant)(void *dev); + int (*get_nb_flm_prios)(void *dev); + int (*get_nb_flm_pst_profiles)(void *dev); + int (*get_nb_hst_categories)(void *dev); + int (*get_nb_qsl_categories)(void *dev); + int (*get_nb_qsl_qst_entries)(void *dev); + int (*get_nb_pdb_categories)(void *dev); + int (*get_nb_ioa_categories)(void *dev); + int (*get_nb_roa_categories)(void *dev); + int (*get_nb_tpe_categories)(void *dev); + int (*get_nb_tx_cpy_writers)(void *dev); + int (*get_nb_tx_cpy_mask_mem)(void *dev); + int (*get_nb_tx_rpl_depth)(void *dev); + int (*get_nb_tx_rpl_ext_categories)(void *dev); + int (*get_nb_tpe_ifr_categories)(void *dev); + + int (*alloc_rx_queue)(void *dev, int queue_id); + int (*free_rx_queue)(void *dev, int hw_queue); + + /* CAT */ + bool (*get_cat_present)(void *dev); + uint32_t (*get_cat_version)(void *dev); + int (*cat_cfn_flush)(void *dev, const struct cat_func_s *cat, + int cat_func, int cnt); + int (*cat_kce_flush)(void *dev, const struct cat_func_s *cat, + int km_if_idx, int index, int cnt); + int (*cat_kcs_flush)(void *dev, const struct cat_func_s *cat, + int km_if_idx, int cat_func, int cnt); + int (*cat_fte_flush)(void *dev, const struct cat_func_s *cat, + int km_if_idx, int index, int cnt); + int (*cat_cte_flush)(void *dev, const struct cat_func_s *cat, + int cat_func, int cnt); + int (*cat_cts_flush)(void *dev, const struct cat_func_s *cat, int index, + int cnt); + int (*cat_cot_flush)(void *dev, const struct cat_func_s *cat, + int cat_func, int cnt); + int (*cat_cct_flush)(void *dev, const struct cat_func_s *cat, int index, + int cnt); + int (*cat_exo_flush)(void *dev, const struct cat_func_s *cat, int index, + int cnt); + int (*cat_rck_flush)(void *dev, const struct cat_func_s *cat, int index, + int cnt); + int (*cat_len_flush)(void *dev, const struct cat_func_s *cat, int index, + int cnt); + int (*cat_kcc_flush)(void *dev, const struct cat_func_s *cat, int index, + int cnt); + int (*cat_cce_flush)(void *dev, const struct cat_func_s *cat, int index, + int cnt); + int (*cat_ccs_flush)(void *dev, const struct cat_func_s *cat, int index, + int cnt); + + /* KM */ + bool (*get_km_present)(void *dev); + uint32_t (*get_km_version)(void *dev); + int (*km_rcp_flush)(void *dev, const struct km_func_s *km, int category, + int cnt); + int (*km_cam_flush)(void *dev, const struct km_func_s *km, int bank, + int record, int cnt); + int (*km_tcam_flush)(void *dev, const struct km_func_s *km, int bank, + int byte, int value, int cnt); + int (*km_tci_flush)(void *dev, const struct km_func_s *km, int bank, + int record, int cnt); + int (*km_tcq_flush)(void *dev, const struct km_func_s *km, int bank, + int record, int cnt); + + /* FLM */ + bool (*get_flm_present)(void *dev); + uint32_t (*get_flm_version)(void *dev); + int (*flm_control_flush)(void *dev, const struct flm_func_s *flm); + int (*flm_status_flush)(void *dev, const struct flm_func_s *flm); + int (*flm_status_update)(void *dev, const struct flm_func_s *flm); + int (*flm_timeout_flush)(void *dev, const struct flm_func_s *flm); + int (*flm_scrub_flush)(void *dev, const struct flm_func_s *flm); + int (*flm_load_bin_flush)(void *dev, const struct flm_func_s *flm); + int (*flm_load_pps_flush)(void *dev, const struct flm_func_s *flm); + int (*flm_load_lps_flush)(void *dev, const struct flm_func_s *flm); + int (*flm_load_aps_flush)(void *dev, const struct flm_func_s *flm); + int (*flm_prio_flush)(void *dev, const struct flm_func_s *flm); + int (*flm_pst_flush)(void *dev, const struct flm_func_s *flm, int index, + int cnt); + int (*flm_rcp_flush)(void *dev, const struct flm_func_s *flm, int index, + int cnt); + int (*flm_buf_ctrl_update)(void *dev, const struct flm_func_s *flm); + int (*flm_stat_update)(void *dev, const struct flm_func_s *flm); + int (*flm_lrn_data_flush)(void *be_dev, const struct flm_func_s *flm, + const uint32_t *lrn_data, uint32_t size); + int (*flm_inf_data_update)(void *be_dev, const struct flm_func_s *flm, + uint32_t *lrn_data, uint32_t size); + int (*flm_sta_data_update)(void *be_dev, const struct flm_func_s *flm, + uint32_t *lrn_data, uint32_t size); + + /* HSH */ + bool (*get_hsh_present)(void *dev); + uint32_t (*get_hsh_version)(void *dev); + int (*hsh_rcp_flush)(void *dev, const struct hsh_func_s *hsh, + int category, int cnt); + + /* HST */ + bool (*get_hst_present)(void *dev); + uint32_t (*get_hst_version)(void *dev); + int (*hst_rcp_flush)(void *dev, const struct hst_func_s *hst, + int category, int cnt); + + /* QSL */ + bool (*get_qsl_present)(void *dev); + uint32_t (*get_qsl_version)(void *dev); + int (*qsl_rcp_flush)(void *dev, const struct qsl_func_s *qsl, + int category, int cnt); + int (*qsl_qst_flush)(void *dev, const struct qsl_func_s *qsl, int entry, + int cnt); + int (*qsl_qen_flush)(void *dev, const struct qsl_func_s *qsl, int entry, + int cnt); + int (*qsl_unmq_flush)(void *dev, const struct qsl_func_s *qsl, + int entry, int cnt); + + /* SLC */ + bool (*get_slc_present)(void *dev); + uint32_t (*get_slc_version)(void *dev); + int (*slc_rcp_flush)(void *dev, const struct slc_func_s *slc, + int category, int cnt); + + /* SLC LR */ + bool (*get_slc_lr_present)(void *dev); + uint32_t (*get_slc_lr_version)(void *dev); + int (*slc_lr_rcp_flush)(void *dev, const struct slc_lr_func_s *slc_lr, + int category, int cnt); + + /* PDB */ + bool (*get_pdb_present)(void *dev); + uint32_t (*get_pdb_version)(void *dev); + int (*pdb_rcp_flush)(void *dev, const struct pdb_func_s *pdb, + int category, int cnt); + int (*pdb_config_flush)(void *dev, const struct pdb_func_s *pdb); + + /* IOA */ + bool (*get_ioa_present)(void *dev); + uint32_t (*get_ioa_version)(void *dev); + int (*ioa_rcp_flush)(void *dev, const struct ioa_func_s *ioa, int index, + int cnt); + int (*ioa_special_tpid_flush)(void *dev, const struct ioa_func_s *ioa); + int (*ioa_roa_epp_flush)(void *dev, const struct ioa_func_s *ioa, + int index, int cnt); + + /* ROA */ + bool (*get_roa_present)(void *dev); + uint32_t (*get_roa_version)(void *dev); + int (*roa_tunhdr_flush)(void *dev, const struct roa_func_s *roa, + int index, int cnt); + int (*roa_tuncfg_flush)(void *dev, const struct roa_func_s *roa, + int index, int cnt); + int (*roa_config_flush)(void *dev, const struct roa_func_s *roa); + int (*roa_lagcfg_flush)(void *dev, const struct roa_func_s *roa, + int index, int cnt); + + /* RMC */ + bool (*get_rmc_present)(void *dev); + uint32_t (*get_rmc_version)(void *dev); + int (*rmc_ctrl_flush)(void *dev, const struct rmc_func_s *rmc); + + /* TPE */ + bool (*get_tpe_present)(void *dev); + uint32_t (*get_tpe_version)(void *dev); + int (*tpe_rpp_rcp_flush)(void *dev, const struct tpe_func_s *tpe, + int index, int cnt); + int (*tpe_rpp_ifr_rcp_flush)(void *dev, const struct tpe_func_s *tpe, + int index, int cnt); + int (*tpe_ifr_rcp_flush)(void *dev, const struct tpe_func_s *tpe, + int index, int cnt); + int (*tpe_ins_rcp_flush)(void *dev, const struct tpe_func_s *tpe, + int index, int cnt); + int (*tpe_rpl_rcp_flush)(void *dev, const struct tpe_func_s *tpe, + int index, int cnt); + int (*tpe_rpl_ext_flush)(void *dev, const struct tpe_func_s *tpe, + int index, int cnt); + int (*tpe_rpl_rpl_flush)(void *dev, const struct tpe_func_s *tpe, + int index, int cnt); + int (*tpe_cpy_rcp_flush)(void *dev, const struct tpe_func_s *tpe, + int index, int cnt); + int (*tpe_hfu_rcp_flush)(void *dev, const struct tpe_func_s *tpe, + int index, int cnt); + int (*tpe_csu_rcp_flush)(void *dev, const struct tpe_func_s *tpe, + int index, int cnt); +}; + +struct flow_api_backend_s { + void *be_dev; + const struct flow_api_backend_ops *iface; + + /* flow filter FPGA modules */ + struct cat_func_s cat; + struct km_func_s km; + struct flm_func_s flm; + struct hsh_func_s hsh; + struct hst_func_s hst; + struct qsl_func_s qsl; + struct slc_func_s slc; + struct slc_lr_func_s slc_lr; + struct pdb_func_s pdb; + struct ioa_func_s ioa; + struct roa_func_s roa; + struct rmc_func_s rmc; + struct tpe_func_s tpe; + + /* NIC attributes */ + unsigned int num_phy_ports; + unsigned int num_rx_ports; + + /* flow filter resource capacities */ + unsigned int max_categories; + unsigned int max_queues; +}; + +int flow_api_backend_init(struct flow_api_backend_s *dev, + const struct flow_api_backend_ops *iface, + void *be_dev); +int flow_api_backend_reset(struct flow_api_backend_s *dev); +int flow_api_backend_done(struct flow_api_backend_s *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* __FLOW_API_BACKEND_H__ */ diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api_engine.h b/drivers/net/ntnic/nthw/flow_api/flow_api_engine.h new file mode 100644 index 0000000000..b63730c07e --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/flow_api_engine.h @@ -0,0 +1,475 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _FLOW_API_ENGINE_H_ +#define _FLOW_API_ENGINE_H_ + +#include +#include "stream_binary_flow_api.h" + +struct flow_elem; +/* + * **************************************************** + * Resource management + * **************************************************** + */ +#define BIT_CONTAINER_8_ALIGN(x) (((x) + 7) / 8) + +/* + * Resource management + * These are free resources in FPGA + * Other FPGA memory lists are linked to one of these + * and will implicitly follow them + */ +enum res_type_e { + RES_QUEUE, + RES_CAT_CFN, + RES_CAT_COT, + RES_CAT_EXO, + RES_CAT_LEN, + RES_KM_FLOW_TYPE, + RES_KM_CATEGORY, + RES_HSH_RCP, + RES_PDB_RCP, + RES_QSL_RCP, + RES_QSL_QST, + RES_SLC_RCP, + RES_IOA_RCP, + RES_ROA_RCP, + RES_FLM_FLOW_TYPE, + RES_FLM_RCP, + RES_HST_RCP, + RES_TPE_RCP, + RES_TPE_EXT, + RES_TPE_RPL, + RES_COUNT, + RES_INVALID +}; + +/* + * **************************************************** + * Flow NIC offload management + * **************************************************** + */ +#define MAX_OUTPUT_DEST (128) +#define NB_QSL_QEN_ADDR 32 + +#define INVALID_FLOW_STAT_ID 0xffffffff + +#define MAX_WORD_NUM 24 +#define MAX_BANKS 6 + +#define MAX_TCAM_START_OFFSETS 4 + +#define MAX_TAG_INDEX 8 + +#define MAX_FLM_MTRS_SUPPORTED 4 +#define MAX_CPY_WRITERS_SUPPORTED 8 + +/* + * 128 128 32 32 32 + * Have | QW0 || QW4 || SW8 || SW9 | SWX in FPGA + * + * Each word may start at any offset, though + * they are combined in chronological order, with all enabled to + * build the extracted match data, thus that is how the match key + * must be build + * + */ +enum extractor_e { + KM_USE_EXTRACTOR_UNDEF, + KM_USE_EXTRACTOR_QWORD, + KM_USE_EXTRACTOR_SWORD, +}; + +struct match_elem_s { + enum extractor_e extr; + int masked_for_tcam; /* if potentially selected for TCAM */ + uint32_t e_word[4]; + uint32_t e_mask[4]; + + int extr_start_offs_id; + int8_t rel_offs; + uint32_t word_len; +}; + +enum cam_tech_use_e { KM_CAM, KM_TCAM, KM_SYNERGY }; + +#define MAX_MATCH_FIELDS 16 + +struct km_flow_def_s { + struct flow_api_backend_s *be; + + /* For keeping track of identical entries */ + struct km_flow_def_s *reference; + struct km_flow_def_s *root; + + /* For collect flow elements and sorting */ + struct match_elem_s match[MAX_MATCH_FIELDS]; + struct match_elem_s *match_map[MAX_MATCH_FIELDS]; + int num_ftype_elem; + + /* Finally formatted CAM/TCAM entry */ + enum cam_tech_use_e target; + uint32_t entry_word[MAX_WORD_NUM]; + uint32_t entry_mask[MAX_WORD_NUM]; + int key_word_size; + + /* TCAM calculated possible bank start offsets */ + int start_offsets[MAX_TCAM_START_OFFSETS]; + int num_start_offsets; + + /* Flow information */ + + /* + * HW input port ID needed for compare. In port must be identical on flow + * types + */ + uint32_t port_id; + uint32_t info; /* used for color (actions) */ + int info_set; + int flow_type; /* 0 is illegal and used as unset */ + int flushed_to_target; /* if this km entry has been finally programmed into NIC hw */ + + /* CAM specific bank management */ + int cam_paired; + int record_indexes[MAX_BANKS]; + int bank_used; + uint32_t *cuckoo_moves; /* for CAM statistics only */ + struct cam_distrib_s *cam_dist; + struct hasher_s *hsh; + + /* TCAM specific bank management */ + struct tcam_distrib_s *tcam_dist; + int tcam_start_bank; + int tcam_record; +}; + +/* + * KCC-CAM + */ +struct kcc_key_s { + uint64_t sb_data : 32; + uint64_t sb_type : 8; + uint64_t cat_cfn : 8; + uint64_t port : 16; +}; + +#define KCC_ID_INVALID 0xffffffff + +struct kcc_flow_def_s { + struct flow_api_backend_s *be; + union { + uint64_t key64; + uint32_t key32[2]; + struct kcc_key_s key; + }; + uint32_t km_category; + uint32_t id; + + uint8_t *kcc_unique_ids; + + int flushed_to_target; + int record_indexes[MAX_BANKS]; + int bank_used; + uint32_t *cuckoo_moves; /* for CAM statistics only */ + struct kcc_cam_distrib_s *cam_dist; + struct hasher_s *hsh; +}; + +/* + * Tunnel encapsulation header definition + */ +enum { TUN_TYPE_VXLAN = 0, TUN_TYPE_NVGRE = 1 }; + +#define MAX_TUN_HDR_SIZE 128 + +struct tunnel_header_s { + union { + uint8_t hdr8[MAX_TUN_HDR_SIZE]; + uint32_t hdr32[(MAX_TUN_HDR_SIZE + 3) / 4]; + } d; + uint32_t user_port_id; + uint8_t len; + + uint8_t nb_vlans; + + uint8_t ip_version; /* 4: v4, 6: v6 */ + uint16_t ip_csum_precalc; + + uint8_t new_outer; + uint8_t l2_len; + uint8_t l3_len; + uint8_t l4_len; +}; + +enum port_type_e { + PORT_NONE, /* not defined or drop */ + PORT_INTERNAL, /* no queues attached */ + PORT_PHY, /* MAC phy output queue */ + PORT_VIRT, /* Memory queues to Host */ +}; + +enum special_partial_match_e { + SPECIAL_MATCH_NONE, + SPECIAL_MATCH_LACP, +}; + +#define PORT_ID_NONE 0xffffffff + +struct output_s { + uint32_t owning_port_id; /* the port who owns this output destination */ + enum port_type_e type; + int id; /* depending on port type: queue ID or physical port id or not used */ + int active; /* activated */ +}; + +struct nic_flow_def { + /* + * Frame Decoder match info collected + */ + int l2_prot; + int l3_prot; + int l4_prot; + int tunnel_prot; + int tunnel_l3_prot; + int tunnel_l4_prot; + int vlans; + int fragmentation; + /* + * Additional meta data for various functions + */ + int in_port_override; + int l4_dst_port; + /* + * Output destination info collection + */ + struct output_s dst_id[MAX_OUTPUT_DEST]; /* define the output to use */ + /* total number of available queues defined for all outputs - i.e. number of dst_id's */ + int dst_num_avail; + + /* + * To identify high priority match with mark for special SW processing (non-OVS) + */ + enum special_partial_match_e special_match; + + /* + * Mark or Action info collection + */ + uint32_t mark; + uint64_t roa_actions; + uint64_t ioa_actions; + + uint32_t jump_to_group; + + uint32_t mtr_ids[MAX_FLM_MTRS_SUPPORTED]; + + int full_offload; + /* + * Action push tunnel + */ + struct tunnel_header_s tun_hdr; + + /* + * If DPDK RTE tunnel helper API used + * this holds the tunnel if used in flow + */ + struct tunnel_s *tnl; + + /* + * Header Stripper + */ + int header_strip_start_dyn; + int header_strip_start_ofs; + int header_strip_end_dyn; + int header_strip_end_ofs; + int header_strip_removed_outer_ip; + + /* + * Modify field + */ + struct { + uint32_t select; + uint32_t dyn; + uint32_t ofs; + uint32_t len; + uint32_t level; + union { + uint8_t value8[16]; + uint16_t value16[8]; + uint32_t value32[4]; + }; + } modify_field[MAX_CPY_WRITERS_SUPPORTED]; + + uint32_t modify_field_count; + uint8_t ttl_sub_enable; + uint8_t ttl_sub_ipv4; + uint8_t ttl_sub_outer; + + /* + * Key Matcher flow definitions + */ + struct km_flow_def_s km; + + /* + * Key Matcher Category CAM + */ + struct kcc_flow_def_s *kcc; + int kcc_referenced; + + /* + * TX fragmentation IFR/RPP_LR MTU recipe + */ + uint8_t flm_mtu_fragmentation_recipe; +}; + +enum flow_handle_type { + FLOW_HANDLE_TYPE_FLOW, + FLOW_HANDLE_TYPE_FLM, +}; + +struct flow_handle { + enum flow_handle_type type; + + struct flow_eth_dev *dev; + struct flow_handle *next; + struct flow_handle *prev; + + union { + struct { + /* + * 1st step conversion and validation of flow + * verified and converted flow match + actions structure + */ + struct nic_flow_def *fd; + /* + * 2nd step NIC HW resource allocation and configuration + * NIC resource management structures + */ + struct { + int index; /* allocation index into NIC raw resource table */ + /* number of contiguous allocations needed for this resource */ + int count; + /* + * This resource if not initially created by this flow, but reused + * by it + */ + int referenced; + } resource[RES_COUNT]; + int flushed; + + uint32_t flow_stat_id; + uint32_t color; + int cao_enabled; + uint32_t cte; + + uint32_t port_id; /* MAC port ID or override of virtual in_port */ + uint32_t flm_ref_count; + uint8_t flm_group_index; + uint8_t flm_ft_index; + }; + + struct { + uint32_t flm_data[10]; + uint8_t flm_prot; + uint8_t flm_kid; + uint8_t flm_prio; + + uint16_t flm_rpl_ext_ptr; + uint32_t flm_nat_ipv4; + uint16_t flm_nat_port; + uint8_t flm_dscp; + uint32_t flm_teid; + uint8_t flm_rqi; + uint8_t flm_qfi; + + uint8_t flm_mtu_fragmentation_recipe; + + struct flow_handle *flm_owner; + }; + }; +}; + +void km_attach_ndev_resource_management(struct km_flow_def_s *km, + void **handle); +void km_free_ndev_resource_management(void **handle); + +int km_get_cam_population_level(void *cam_dist, uint32_t *cam_elem, + uint32_t *cuckoo_moves); + +int km_add_match_elem(struct km_flow_def_s *km, uint32_t e_word[4], + uint32_t e_mask[4], uint32_t word_len, + enum frame_offs_e start, int8_t offset); + +int km_key_create(struct km_flow_def_s *km, uint32_t port_id); +/* + * Compares 2 KM key definitions after first collect validate and optimization. + * km is compared against an existing km1. + * if identical, km1 flow_type is returned + */ +int km_key_compare(struct km_flow_def_s *km, struct km_flow_def_s *km1); + +void km_set_info(struct km_flow_def_s *km, int on); +int km_rcp_set(struct km_flow_def_s *km, int index); + +int km_refer_data_match_entry(struct km_flow_def_s *km, + struct km_flow_def_s *km1); +int km_write_data_match_entry(struct km_flow_def_s *km, uint32_t color); +int km_clear_data_match_entry(struct km_flow_def_s *km); + +void kcc_attach_ndev_resource_management(struct kcc_flow_def_s *kcc, + void **handle); +void kcc_free_ndev_resource_management(void **handle); +int kcc_alloc_unique_id(struct kcc_flow_def_s *kcc); +void kcc_free_unique_id(struct kcc_flow_def_s *kcc); +int kcc_key_compare(struct kcc_flow_def_s *kcc, struct kcc_flow_def_s *kcc1); +int kcc_add_km_category(struct kcc_flow_def_s *kcc, uint32_t category); + +int kcc_key_add_no_sideband(struct kcc_flow_def_s *kcc); +int kcc_key_add_vlan(struct kcc_flow_def_s *kcc, uint16_t tpid, uint16_t vid); +int kcc_key_add_vxlan(struct kcc_flow_def_s *kcc, uint32_t vni); +int kcc_key_add_port(struct kcc_flow_def_s *kcc, uint16_t port); +int kcc_key_add_cat_cfn(struct kcc_flow_def_s *kcc, uint8_t cat_cfn); +uint8_t kcc_key_get_cat_cfn(struct kcc_flow_def_s *kcc); + +int kcc_write_data_match_entry(struct kcc_flow_def_s *kcc); +int kcc_key_ref_count_add(struct kcc_flow_def_s *kcc); +int kcc_key_ref_count_dec(struct kcc_flow_def_s *kcc); + +/* + * Group management + */ +int flow_group_handle_create(void **handle, uint32_t group_count); +int flow_group_handle_destroy(void **handle); + +int flow_group_translate_get(void *handle, uint8_t owner_id, uint32_t group_in, + uint32_t *group_out); +int flow_group_translate_release(void *handle, uint32_t translated_group); + +/* + * Actions management + */ +uint8_t flow_tunnel_alloc_virt_port(void); +uint8_t flow_tunnel_free_virt_port(uint8_t virt_port); +struct tunnel_s *tunnel_parse(const struct flow_elem *elem, int *idx, + uint32_t *vni); +int tunnel_release(struct tunnel_s *tnl); +uint8_t get_tunnel_vport(struct tunnel_s *rtnl); +void tunnel_set_flow_stat_id(struct tunnel_s *rtnl, uint32_t flow_stat_id); +int tunnel_get_definition(struct tunnel_cfg_s *tun, uint32_t flow_stat_id, + uint8_t vport); + +int is_virtual_port(uint8_t virt_port); +int flow_tunnel_create_vxlan_hdr(struct flow_api_backend_s *be, + struct nic_flow_def *fd, + const struct flow_elem *elem); + +/* + * statistics + */ +uint32_t flow_actions_create_flow_stat_id(uint32_t *stat_map, uint32_t mark); +void flow_actions_delete_flow_stat_id(uint32_t *stat_map, + uint32_t flow_stat_id); + +#endif /* _FLOW_API_ENGINE_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api_nic_setup.h b/drivers/net/ntnic/nthw/flow_api/flow_api_nic_setup.h new file mode 100644 index 0000000000..c4db0f4c5c --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/flow_api_nic_setup.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __FLOW_API_NIC_SETUP_H__ +#define __FLOW_API_NIC_SETUP_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct flow_api_backend_ops; /* Operation list for common FPGA module API for backend */ +struct flow_nic_dev; /* adapter device */ + +/* + * Flow capable NIC backend - creating flow api instance for adapter nr (backend) + */ +struct flow_nic_dev *flow_api_create(uint8_t adapter_no, + const struct flow_api_backend_ops *be_if, + void *be_dev); +int flow_api_done(struct flow_nic_dev *dev); +void *flow_api_get_be_dev(struct flow_nic_dev *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* __FLOW_API_NIC_SETUP_H__ */ diff --git a/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_group.c b/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_group.c new file mode 100644 index 0000000000..9b6e5484a0 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_group.c @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "flow_api_backend.h" +#include "flow_api_engine.h" + +#include +#include + +#define OWNER_ID_COUNT 256 + +struct group_lookup_entry_s { + uint64_t ref_counter; + uint32_t *reverse_lookup; +}; + +struct group_handle_s { + uint32_t group_count; + + uint32_t *translation_table; + + struct group_lookup_entry_s *lookup_entries; +}; + +int flow_group_handle_create(void **handle, uint32_t group_count) +{ + struct group_handle_s *group_handle; + + *handle = calloc(1, sizeof(struct group_handle_s)); + group_handle = *handle; + + group_handle->group_count = group_count; + group_handle->translation_table = calloc((uint32_t)(group_count * OWNER_ID_COUNT), + sizeof(uint32_t)); + group_handle->lookup_entries = + calloc(group_count, sizeof(struct group_lookup_entry_s)); + + return *handle != NULL ? 0 : -1; +} + +int flow_group_handle_destroy(void **handle) +{ + if (*handle) { + struct group_handle_s *group_handle = + (struct group_handle_s *)*handle; + + free(group_handle->translation_table); + free(group_handle->lookup_entries); + + free(*handle); + *handle = NULL; + } + + return 0; +} + +int flow_group_translate_get(void *handle, uint8_t owner_id, uint32_t group_in, + uint32_t *group_out) +{ + struct group_handle_s *group_handle = (struct group_handle_s *)handle; + uint32_t *table_ptr; + uint32_t lookup; + + if (group_handle == NULL || group_in >= group_handle->group_count) + return -1; + + /* Don't translate group 0 */ + if (group_in == 0) { + *group_out = 0; + return 0; + } + + table_ptr = &group_handle->translation_table[owner_id * OWNER_ID_COUNT + + group_in]; + lookup = *table_ptr; + + if (lookup == 0) { + for (lookup = 1; + lookup < group_handle->group_count && + group_handle->lookup_entries[lookup].ref_counter > 0; + ++lookup) + ; + + if (lookup < group_handle->group_count) { + group_handle->lookup_entries[lookup].reverse_lookup = + table_ptr; + group_handle->lookup_entries[lookup].ref_counter += 1; + + *table_ptr = lookup; + } else { + return -1; + } + } else { + group_handle->lookup_entries[lookup].ref_counter += 1; + } + *group_out = lookup; + return 0; +} + +int flow_group_translate_release(void *handle, uint32_t translated_group) +{ + struct group_handle_s *group_handle = (struct group_handle_s *)handle; + struct group_lookup_entry_s *lookup; + + if (group_handle == NULL || + translated_group >= group_handle->group_count) + return -1; + + /* Don't translate group 0 */ + if (translated_group == 0) + return 0; + + lookup = &group_handle->lookup_entries[translated_group]; + + if (lookup->reverse_lookup && lookup->ref_counter > 0) { + lookup->ref_counter -= 1; + if (lookup->ref_counter == 0) { + *lookup->reverse_lookup = 0; + lookup->reverse_lookup = NULL; + } + } + + return 0; +} diff --git a/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_hasher.c b/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_hasher.c new file mode 100644 index 0000000000..6982129e17 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_hasher.c @@ -0,0 +1,213 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "flow_hasher.h" + +#include + +/* #define TESTING */ + +#ifdef TESTING +#include +int hash_test(struct hasher_s *hsh, int banks, int record_bw); +#endif + +static uint32_t shuffle(uint32_t x) +{ + return (((x & 0x00000002) << 29) | ((x & 0xAAAAAAA8) >> 3) | + ((x & 0x15555555) << 3) | ((x & 0x40000000) >> 29)); +} + +static uint32_t ror_inv(uint32_t x, const int s) +{ + return ((x >> s) | ((~x) << (32 - s))); +} + +static uint32_t combine(uint32_t x, uint32_t y) +{ + uint32_t x1 = ror_inv(x, 15); + uint32_t x2 = ror_inv(x, 13); + uint32_t y1 = ror_inv(y, 3); + uint32_t y2 = ror_inv(y, 27); + + return (x ^ y ^ + ((x1 & y1 & ~x2 & ~y2) | (x1 & ~y1 & x2 & ~y2) | + (x1 & ~y1 & ~x2 & y2) | (~x1 & y1 & x2 & ~y2) | + (~x1 & y1 & ~x2 & y2) | (~x1 & ~y1 & x2 & y2))); +} + +static uint32_t mix(uint32_t x, uint32_t y) +{ + return shuffle(combine(x, y)); +} + +static uint64_t ror_inv3(uint64_t x) +{ + const uint64_t m = 0xE0000000E0000000ULL; + + return (((x >> 3) | m) ^ ((x << 29) & m)); +} + +static uint64_t ror_inv13(uint64_t x) +{ + const uint64_t m = 0xFFF80000FFF80000ULL; + + return (((x >> 13) | m) ^ ((x << 19) & m)); +} + +static uint64_t ror_inv15(uint64_t x) +{ + const uint64_t m = 0xFFFE0000FFFE0000ULL; + + return (((x >> 15) | m) ^ ((x << 17) & m)); +} + +static uint64_t ror_inv27(uint64_t x) +{ + const uint64_t m = 0xFFFFFFE0FFFFFFE0ULL; + + return (((x >> 27) | m) ^ ((x << 5) & m)); +} + +static uint64_t shuffle64(uint64_t x) +{ + return (((x & 0x0000000200000002) << 29) | + ((x & 0xAAAAAAA8AAAAAAA8) >> 3) | + ((x & 0x1555555515555555) << 3) | + ((x & 0x4000000040000000) >> 29)); +} + +static uint64_t pair(uint32_t x, uint32_t y) +{ + return (((uint64_t)x << 32) | y); +} + +static uint64_t combine64(uint64_t x, uint64_t y) +{ + uint64_t x1 = ror_inv15(x); + uint64_t x2 = ror_inv13(x); + uint64_t y1 = ror_inv3(y); + uint64_t y2 = ror_inv27(y); + + return (x ^ y ^ + ((x1 & y1 & ~x2 & ~y2) | (x1 & ~y1 & x2 & ~y2) | + (x1 & ~y1 & ~x2 & y2) | (~x1 & y1 & x2 & ~y2) | + (~x1 & y1 & ~x2 & y2) | (~x1 & ~y1 & x2 & y2))); +} + +static uint64_t mix64(uint64_t x, uint64_t y) +{ + return shuffle64(combine64(x, y)); +} + +static uint32_t calc16(const uint32_t key[16]) +{ + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Layer 0 */ + /* \./ \./ \./ \./ \./ \./ \./ \./ */ + /* 0 1 2 3 4 5 6 7 Layer 1 */ + /* \__.__/ \__.__/ \__.__/ \__.__/ */ + /* 0 1 2 3 Layer 2 */ + /* \______.______/ \______.______/ */ + /* 0 1 Layer 3 */ + /* \______________.______________/ */ + /* 0 Layer 4 */ + /* / \ */ + /* \./ */ + /* 0 Layer 5 */ + /* / \ */ + /* \./ Layer 6 */ + /* value */ + + uint64_t z; + uint32_t x; + + z = mix64(mix64(mix64(pair(key[0], key[8]), pair(key[1], key[9])), + mix64(pair(key[2], key[10]), pair(key[3], key[11]))), + mix64(mix64(pair(key[4], key[12]), pair(key[5], key[13])), + mix64(pair(key[6], key[14]), pair(key[7], key[15])))); + + x = mix((uint32_t)(z >> 32), (uint32_t)z); + x = mix(x, ror_inv(x, 17)); + x = combine(x, ror_inv(x, 17)); + + return x; +} + +uint32_t gethash(struct hasher_s *hsh, const uint32_t key[16], int *result) +{ + uint64_t val; + uint32_t res; + + val = calc16(key); + res = (uint32_t)val; + + if (hsh->cam_bw > 32) + val = (val << (hsh->cam_bw - 32)) ^ val; + + for (int i = 0; i < hsh->banks; i++) { + result[i] = (unsigned int)(val & hsh->cam_records_bw_mask); + val = val >> hsh->cam_records_bw; + } + return res; +} + +int init_hasher(struct hasher_s *hsh, int banks, int nb_records) +{ + hsh->banks = banks; + hsh->cam_records_bw = (int)(log2(nb_records - 1) + 1); + hsh->cam_records_bw_mask = (1U << hsh->cam_records_bw) - 1; + hsh->cam_bw = hsh->banks * hsh->cam_records_bw; + +#ifdef TESTING + int res = hash_test(hsh, _banks, (int)log2(nb_records - 1) + 1); + + if (res) + printf("ERROR: testing hasher\n"); +#endif + + return 0; +} + +#ifdef TESTING +int hash_test(struct hasher_s *hsh, int banks, int record_bw) +{ + int res = 0; + int val[10], resval[10]; + uint32_t bits = 0; + + uint32_t inval[16] = { 0xaaaabbbb, 0xccccdddd, 0xeeeeffff, 0x88881111 }; + const uint32_t result = 0xACECAE65; + + for (int i = 0; i < 16; i++) + printf("%08x,", inval[i]); + printf("\nbanks %i, records bit width: %i\n", banks, record_bw); + + uint32_t ret = gethash(hsh, inval, val); + + printf("Return VAL = %08X == %08X\n", ret, result); + res += (ret != result) ? 1 : 0; + + int shft = (banks * record_bw) - 32; + int mask = (1 << record_bw) - 1; + + if (shft > 0) { + bits = (ret >> (32 - shft)); + ret ^= ret << shft; + } + + resval[0] = ret & mask; + ret >>= record_bw; + resval[1] = ret & mask; + ret >>= record_bw; + resval[2] = ret & mask; + resval[2] |= (bits << (record_bw - shft)); + + for (int i = 0; i < 3; i++) { + printf("HASH %i: %i == %i\n", i, val[i], resval[i]); + res += (val[i] != resval[i]) ? 1 : 0; + } + + return res; +} +#endif diff --git a/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_hasher.h b/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_hasher.h new file mode 100644 index 0000000000..6365a396d2 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_hasher.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _FLOW_HASHER_H_ +#define _FLOW_HASHER_H_ + +#include + +struct hasher_s { + int banks; + int cam_records_bw; + uint32_t cam_records_bw_mask; + int cam_bw; +}; + +int init_hasher(struct hasher_s *hsh, int banks, int nb_records); +uint32_t gethash(struct hasher_s *hsh, const uint32_t key[16], int *result); + +#endif /* _FLOW_HASHER_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_kcc.c b/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_kcc.c new file mode 100644 index 0000000000..ddf1742588 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_kcc.c @@ -0,0 +1,434 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include +#include "flow_api_backend.h" +#include "flow_api_engine.h" +#include "flow_hasher.h" + +/* + * KCC-CAM structures and defines + */ +struct kcc_cam_distrib_s { + struct kcc_flow_def_s *kcc_owner; + int ref_cnt; +}; + +#define BE_CAM_KCC_DIST_IDX(bnk) \ + ({ \ + int _temp_bnk = (bnk); \ + (_temp_bnk * kcc->be->cat.kcc_records + kcc->record_indexes[_temp_bnk]); \ + }) + + +#define BE_CAM_ENTRIES \ + (kcc->be->cat.kcc_size * sizeof(struct kcc_cam_distrib_s)) +#define BE_UNIQUE_IDS_SIZE ((1U << kcc->be->cat.kcc_id_bit_size) / 8) + +#define KCC_CUCKOO_MOVE_MAX_DEPTH 8 +static int kcc_cam_addr_reserved_stack[KCC_CUCKOO_MOVE_MAX_DEPTH]; + +void kcc_attach_ndev_resource_management(struct kcc_flow_def_s *kcc, + void **handle) +{ + /* + * KCC entries occupied in CAM - to manage the cuckoo shuffling + * and manage CAM population and usage + */ + if (!*handle) { + *handle = calloc(1, BE_CAM_ENTRIES + sizeof(uint32_t) + + BE_UNIQUE_IDS_SIZE + + sizeof(struct hasher_s)); + NT_LOG(DBG, FILTER, + "Allocate NIC DEV KCC-CAM record manager\n"); + } + kcc->cam_dist = (struct kcc_cam_distrib_s *)*handle; + kcc->cuckoo_moves = + (uint32_t *)((char *)kcc->cam_dist + BE_CAM_ENTRIES); + kcc->kcc_unique_ids = (uint8_t *)((char *)kcc->cam_dist + + BE_CAM_ENTRIES + sizeof(uint32_t)); + + kcc->hsh = (struct hasher_s *)((char *)kcc->kcc_unique_ids + + BE_UNIQUE_IDS_SIZE); + init_hasher(kcc->hsh, kcc->be->cat.kcc_banks, kcc->be->cat.kcc_records); +} + +void kcc_free_ndev_resource_management(void **handle) +{ + if (*handle) { + free(*handle); + NT_LOG(DBG, FILTER, "Free NIC DEV KCC-CAM record manager\n"); + } + *handle = NULL; +} + +/* + * Key for KCC CAM + */ +int kcc_key_add_no_sideband(struct kcc_flow_def_s *kcc) +{ + kcc->key.sb_data = 0xffffffff; + kcc->key.sb_type = 0; + return 0; +} + +int kcc_key_add_vlan(struct kcc_flow_def_s *kcc, uint16_t tpid, uint16_t vid) +{ + kcc->key.sb_data = ((uint32_t)tpid << 16) | (vid & 0x0fff); + kcc->key.sb_type = 1; + return 0; +} + +int kcc_key_add_vxlan(struct kcc_flow_def_s *kcc, uint32_t vni) +{ + kcc->key.sb_data = (vni & 0x00ffffff) | 0x02000000; + kcc->key.sb_type = 2; + return 0; +} + +int kcc_key_add_port(struct kcc_flow_def_s *kcc, uint16_t port) +{ + kcc->key.port = port; + return 0; +} + +int kcc_key_add_cat_cfn(struct kcc_flow_def_s *kcc, uint8_t cat_cfn) +{ + kcc->key.cat_cfn = cat_cfn; + return 0; +} + +uint8_t kcc_key_get_cat_cfn(struct kcc_flow_def_s *kcc) +{ + return kcc->key.cat_cfn; +} + +/* + * other settings for KCC CAM + */ +int kcc_add_km_category(struct kcc_flow_def_s *kcc, uint32_t category) +{ + kcc->km_category = category; + return 0; +} + +int kcc_alloc_unique_id(struct kcc_flow_def_s *kcc) +{ + uint32_t i, ii; + /* search a free unique ID in allocation bitmap */ + for (i = 0; i < BE_UNIQUE_IDS_SIZE; i++) + if (kcc->kcc_unique_ids[i] != 0xff) + break; + + if (i == BE_UNIQUE_IDS_SIZE) + return -1; + + for (ii = 0; ii < 8; ii++) { + if ((kcc->kcc_unique_ids[i] & (uint8_t)(1U << ii)) == 0) { + kcc->kcc_unique_ids[i] = + (uint8_t)(kcc->kcc_unique_ids[i] | + (uint8_t)(1U << ii)); + kcc->id = (uint16_t)(i * 8 + ii); + NT_LOG(DBG, FILTER, "Allocate new KCC ID : %i\n", + kcc->id); + return (int)kcc->id; + } + } + return -1; +} + +void kcc_free_unique_id(struct kcc_flow_def_s *kcc) +{ + if (kcc->id == KCC_ID_INVALID) + return; + + uint32_t idx = kcc->id >> 3; + uint8_t shft = (uint8_t)(kcc->id & 7); + + assert(idx < BE_UNIQUE_IDS_SIZE); + if (idx < BE_UNIQUE_IDS_SIZE) { + assert(kcc->kcc_unique_ids[idx] & (uint8_t)(1 << shft)); + kcc->kcc_unique_ids[idx] &= (uint8_t)~(1 << shft); + NT_LOG(DBG, FILTER, "Free KCC ID : %i\n", kcc->id); + kcc->id = KCC_ID_INVALID; + } +} + +int kcc_key_compare(struct kcc_flow_def_s *kcc, struct kcc_flow_def_s *kcc1) +{ + if (kcc->key64 == kcc1->key64) + return 1; + return 0; +} + +static int kcc_cam_populate(struct kcc_flow_def_s *kcc, int bank) +{ + int res; + int idx = bank * kcc->be->cat.kcc_records + kcc->record_indexes[bank]; + + res = hw_mod_cat_kcc_set(kcc->be, HW_CAT_KCC_KEY, idx, 0, + kcc->key32[0]); + if (res) + return -1; + res = hw_mod_cat_kcc_set(kcc->be, HW_CAT_KCC_KEY, idx, 1, + kcc->key32[1]); + if (res) + return -1; + res = hw_mod_cat_kcc_set(kcc->be, HW_CAT_KCC_CATEGORY, idx, 0, + kcc->km_category); + if (res) + return -1; + res = hw_mod_cat_kcc_set(kcc->be, HW_CAT_KCC_ID, idx, 0, kcc->id); + if (res) + return -1; + res = hw_mod_cat_kcc_flush(kcc->be, idx, 1); + + kcc->cam_dist[BE_CAM_KCC_DIST_IDX(bank)].kcc_owner = kcc; + kcc->cam_dist[BE_CAM_KCC_DIST_IDX(bank)].ref_cnt = 1; + return res; +} + +static int kcc_cam_reset_entry(struct kcc_flow_def_s *kcc, int bank) +{ + int res = 0; + int idx = bank * kcc->be->cat.kcc_records + kcc->record_indexes[bank]; + + res = hw_mod_cat_kcc_set(kcc->be, HW_CAT_KCC_KEY, idx, 0, 0); + if (res) + return -1; + res = hw_mod_cat_kcc_set(kcc->be, HW_CAT_KCC_KEY, idx, 1, 0); + if (res) + return -1; + res = hw_mod_cat_kcc_set(kcc->be, HW_CAT_KCC_CATEGORY, idx, 0, 0); + if (res) + return -1; + res = hw_mod_cat_kcc_set(kcc->be, HW_CAT_KCC_ID, idx, 0, 0); + if (res) + return -1; + res = hw_mod_cat_kcc_flush(kcc->be, idx, 1); + + kcc->cam_dist[BE_CAM_KCC_DIST_IDX(bank)].kcc_owner = NULL; + kcc->cam_dist[BE_CAM_KCC_DIST_IDX(bank)].ref_cnt = 0; + + kcc->key64 = 0UL; + kcc->km_category = 0; + /* "kcc->id" holds an allocated unique id, so cleared/freed later */ + return res; +} + +static int kcc_move_cuckoo_index(struct kcc_flow_def_s *kcc) +{ + assert(kcc->cam_dist[BE_CAM_KCC_DIST_IDX(kcc->bank_used)].kcc_owner); + + for (uint32_t bank = 0; bank < kcc->be->cat.kcc_banks; bank++) { + /* It will not select itself */ + if (kcc->cam_dist[BE_CAM_KCC_DIST_IDX(bank)].kcc_owner == + NULL) { + /* + * Populate in new position + */ + int res = kcc_cam_populate(kcc, bank); + + if (res) { + NT_LOG(DBG, FILTER, + "Error: failed to write to KM CAM in cuckoo move\n"); + return 0; + } + + /* + * Reset/free entry in old bank + * HW flushes are really not needed, the old addresses are always taken over + * by the caller If you change this code in future updates, this may no + * longer be true then! + */ + kcc->cam_dist[BE_CAM_KCC_DIST_IDX(kcc->bank_used)] + .kcc_owner = NULL; + NT_LOG(DBG, FILTER, + "KCC Cuckoo hash moved from bank %i to bank %i (%04X => %04X)\n", + kcc->bank_used, bank, + BE_CAM_KCC_DIST_IDX(kcc->bank_used), + BE_CAM_KCC_DIST_IDX(bank)); + + kcc->bank_used = bank; + (*kcc->cuckoo_moves)++; + return 1; + } + } + return 0; +} + +static int kcc_move_cuckoo_index_level(struct kcc_flow_def_s *kcc_parent, + int bank_idx, int levels, + int cam_adr_list_len) +{ + struct kcc_flow_def_s *kcc = kcc_parent->cam_dist[bank_idx].kcc_owner; + + assert(levels <= KCC_CUCKOO_MOVE_MAX_DEPTH); + + if (kcc_move_cuckoo_index(kcc)) + return 1; + if (levels <= 1) + return 0; + + assert(cam_adr_list_len < KCC_CUCKOO_MOVE_MAX_DEPTH); + + kcc_cam_addr_reserved_stack[cam_adr_list_len++] = bank_idx; + + for (uint32_t i = 0; i < kcc->be->cat.kcc_banks; i++) { + int reserved = 0; + int new_idx = BE_CAM_KCC_DIST_IDX(i); + + for (int i_reserved = 0; i_reserved < cam_adr_list_len; + i_reserved++) { + if (kcc_cam_addr_reserved_stack[i_reserved] == + new_idx) { + reserved = 1; + break; + } + } + if (reserved) + continue; + + int res = kcc_move_cuckoo_index_level(kcc, new_idx, levels - 1, + cam_adr_list_len); + if (res) { + if (kcc_move_cuckoo_index(kcc)) + return 1; + + else + assert(0); + } + } + + return 0; +} + +static uint32_t kcc_hsh_key[16]; + +static int kcc_write_data_to_cam(struct kcc_flow_def_s *kcc) +{ + int res = 0; + int val[MAX_BANKS]; + + kcc_hsh_key[0] = kcc->key32[1]; + kcc_hsh_key[1] = kcc->key32[0]; + NT_LOG(DBG, FILTER, "TEMP TEMP TEMP"); + NT_LOG(DBG, FILTER, "Hash key[0] %08x", kcc_hsh_key[0]); + NT_LOG(DBG, FILTER, "Hash key[1] %08x", kcc_hsh_key[1]); + NT_LOG(DBG, FILTER, "TEMP TEMP TEMP - swapped"); + + /* 2-15 never changed - remains zero */ + + gethash(kcc->hsh, kcc_hsh_key, val); + + for (uint32_t i = 0; i < kcc->be->cat.kcc_banks; i++) + kcc->record_indexes[i] = val[i]; + NT_LOG(DBG, FILTER, "KCC HASH [%03X, %03X, %03X]\n", + kcc->record_indexes[0], kcc->record_indexes[1], + kcc->record_indexes[2]); + + int bank = -1; + /* + * first step, see if any of the banks are free + */ + for (uint32_t i_bank = 0; i_bank < kcc->be->cat.kcc_banks; i_bank++) { + if (kcc->cam_dist[BE_CAM_KCC_DIST_IDX(i_bank)].kcc_owner == + NULL) { + bank = i_bank; + break; + } + } + + if (bank < 0) { + /* + * Second step - cuckoo move existing flows if possible + */ + for (uint32_t i_bank = 0; i_bank < kcc->be->cat.kcc_banks; + i_bank++) { + if (kcc_move_cuckoo_index_level(kcc, + BE_CAM_KCC_DIST_IDX(i_bank), + 4, 0)) { + bank = i_bank; + break; + } + } + + if (bank < 0) + return -1; + } + + /* populate CAM */ + NT_LOG(DBG, FILTER, "KCC Bank = %i (addr %04X)\n", bank, + BE_CAM_KCC_DIST_IDX(bank)); + res = kcc_cam_populate(kcc, bank); + if (res == 0) { + kcc->flushed_to_target = 1; + kcc->bank_used = bank; + } else { + NT_LOG(DBG, FILTER, "KCC CAM populate failed\n"); + } + return res; +} + +int kcc_write_data_match_entry(struct kcc_flow_def_s *kcc) +{ + int res = -1; + + NT_LOG(DBG, FILTER, + "KCC Write Data entry. Create New Key: %016lx, KM category %i, id %i\n", + kcc->key64, kcc->km_category, kcc->id); + res = kcc_write_data_to_cam(kcc); + return res; +} + +static int kcc_clear_data_match_entry(struct kcc_flow_def_s *kcc) +{ + int res = 0; + + if (kcc->flushed_to_target) { + res = kcc_cam_reset_entry(kcc, kcc->bank_used); + kcc->flushed_to_target = 0; + kcc->bank_used = 0; + } + return res; +} + +int kcc_key_ref_count_add(struct kcc_flow_def_s *kcc) +{ + assert(kcc->bank_used >= 0 && + kcc->bank_used < (int)kcc->be->cat.kcc_banks); + + struct kcc_cam_distrib_s *cam_entry = + &kcc->cam_dist[BE_CAM_KCC_DIST_IDX(kcc->bank_used)]; + + NT_LOG(DBG, FILTER, + "KCC ADD Ref existing Key: %016lx, KM category %i, id %i (new ref count %i)\n", + kcc->key64, kcc->km_category, kcc->id, cam_entry->ref_cnt + 1); + return ++cam_entry->ref_cnt; +} + +int kcc_key_ref_count_dec(struct kcc_flow_def_s *kcc) +{ + if (kcc->bank_used < 0 || kcc->bank_used >= (int)kcc->be->cat.kcc_banks) + return -1; + + struct kcc_cam_distrib_s *cam_entry = + &kcc->cam_dist[BE_CAM_KCC_DIST_IDX(kcc->bank_used)]; + + if (cam_entry->ref_cnt) { + if (--cam_entry->ref_cnt == 0) { + kcc_clear_data_match_entry(kcc); + NT_LOG(DBG, FILTER, + "KCC DEC Ref on Key became zero - Delete\n"); + } + } + + NT_LOG(DBG, FILTER, + "KCC DEC Ref on Key: %016lx, KM category %i, id %i (new ref count %i)\n", + kcc->key64, kcc->km_category, kcc->id, cam_entry->ref_cnt); + return cam_entry->ref_cnt; +} diff --git a/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_km.c b/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_km.c new file mode 100644 index 0000000000..560be9f7d3 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_km.c @@ -0,0 +1,1434 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include + +#include "flow_api_backend.h" +#include "flow_api_engine.h" +#include "flow_hasher.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +static const struct cam_match_masks_s { + uint32_t word_len; + uint32_t key_mask[4]; +} cam_masks[] = { + { 4, + { 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff + } + }, /* IP6_SRC, IP6_DST */ + { 4, + { 0xffffffff, 0xffffffff, 0xffffffff, + 0xffff0000 + } + }, /* DMAC,SMAC,ethtype */ + { 4, + { 0xffffffff, 0xffff0000, 0x00000000, + 0xffff0000 + } + }, /* DMAC,ethtype */ + { 4, + { 0x00000000, 0x0000ffff, 0xffffffff, + 0xffff0000 + } + }, /* SMAC,ethtype */ + { 4, { 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000 } }, /* ETH_128 */ + { 2, + { 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000 + } + }, /* IP4_COMBINED */ + { 1, { 0xffffffff, 0x00000000, 0x00000000, 0x00000000 } }, + /* + * ETH_TYPE, IP4_TTL_PROTO, IP4_SRC, IP4_DST, IP6_FLOW_TC, + * IP6_NEXT_HDR_HOP, TP_PORT_COMBINED, SIDEBAND_VNI + */ + { 1, + { 0xffff0000, 0x00000000, 0x00000000, + 0x00000000 + } + }, /* IP4_IHL_TOS, TP_PORT_SRC32_OR_ICMP, TCP_CTRL */ + { 1, + { 0x0000ffff, 0x00000000, 0x00000000, + 0x00000000 + } + }, /* TP_PORT_DST32 */ + { 1, + { 0x00030000, 0x00000000, 0x00000000, + 0x00000000 + } + }, /* IPv4 TOS mask bits used often by OVS */ + { 1, + { 0x00300000, 0x00000000, 0x00000000, + 0x00000000 + } + }, /* IPv6 TOS mask bits used often by OVS */ +}; + +#define NUM_CAM_MASKS (ARRAY_SIZE(cam_masks)) + +/* + * CAM structures and defines + */ +struct cam_distrib_s { + struct km_flow_def_s *km_owner; +}; + +#define CAM_DIST_IDX(bnk, rec) ((bnk) * km->be->km.nb_cam_records + (rec)) +#define CAM_KM_DIST_IDX(bnk) \ + ({ \ + int _temp_bnk = (bnk); \ + CAM_DIST_IDX(_temp_bnk, km->record_indexes[_temp_bnk]); \ + }) + +#define CUCKOO_MOVE_MAX_DEPTH 8 +static int cam_addr_reserved_stack[CUCKOO_MOVE_MAX_DEPTH]; + +/* + * TCAM structures and defines + */ +struct tcam_distrib_s { + struct km_flow_def_s *km_owner; +}; + +#define TCAM_DIST_IDX(bnk, rec) ((bnk) * km->be->km.nb_tcam_bank_width + (rec)) + +static int tcam_find_mapping(struct km_flow_def_s *km); + +void km_attach_ndev_resource_management(struct km_flow_def_s *km, void **handle) +{ +#define CAM_ENTRIES \ + (km->be->km.nb_cam_banks * km->be->km.nb_cam_records * \ + sizeof(struct cam_distrib_s)) +#define TCAM_ENTRIES \ + (km->be->km.nb_tcam_bank_width * km->be->km.nb_tcam_banks * \ + sizeof(struct tcam_distrib_s)) + /* + * KM entries occupied in CAM - to manage the cuckoo shuffling + * and manage CAM population and usage + * KM entries occupied in TCAM - to manage population and usage + */ + if (!*handle) { + *handle = calloc(1, (size_t)CAM_ENTRIES + sizeof(uint32_t) + + (size_t)TCAM_ENTRIES + + sizeof(struct hasher_s)); + NT_LOG(DBG, FILTER, + "Allocate NIC DEV CAM and TCAM record manager\n"); + } + km->cam_dist = (struct cam_distrib_s *)*handle; + km->cuckoo_moves = (uint32_t *)((char *)km->cam_dist + CAM_ENTRIES); + km->tcam_dist = + (struct tcam_distrib_s *)((char *)km->cam_dist + CAM_ENTRIES + + sizeof(uint32_t)); + + km->hsh = (struct hasher_s *)((char *)km->tcam_dist + TCAM_ENTRIES); + init_hasher(km->hsh, km->be->km.nb_cam_banks, + km->be->km.nb_cam_records); +} + +void km_free_ndev_resource_management(void **handle) +{ + if (*handle) { + free(*handle); + NT_LOG(DBG, FILTER, + "Free NIC DEV CAM and TCAM record manager\n"); + } + *handle = NULL; +} + +int km_add_match_elem(struct km_flow_def_s *km, uint32_t e_word[4], + uint32_t e_mask[4], uint32_t word_len, + enum frame_offs_e start_id, int8_t offset) +{ +#ifdef FLOW_DEBUG + char *s = ntlog_helper_str_alloc("MATCH: "); + + for (unsigned int i = 0; i < word_len; i++) + ntlog_helper_str_add(s, "%08x, ", e_word[i]); + NT_LOG(DBG, FILTER, "%s", s); + ntlog_helper_str_reset(s, "MASK : "); + for (unsigned int i = 0; i < word_len; i++) + ntlog_helper_str_add(s, "%08x, ", e_mask[i]); + NT_LOG(DBG, FILTER, "%s", s); + ntlog_helper_str_free(s); +#endif + + /* valid word_len 1,2,4 */ + if (word_len == 3) { + word_len = 4; + e_word[3] = 0; + e_mask[3] = 0; + } + if (word_len < 1 || word_len > 4) { + assert(0); + return -1; + } + + for (unsigned int i = 0; i < word_len; i++) { + km->match[km->num_ftype_elem].e_word[i] = e_word[i]; + km->match[km->num_ftype_elem].e_mask[i] = e_mask[i]; + } + + km->match[km->num_ftype_elem].word_len = word_len; + km->match[km->num_ftype_elem].rel_offs = offset; + km->match[km->num_ftype_elem].extr_start_offs_id = start_id; + + /* + * Determine here if this flow may better be put into TCAM + * Otherwise it will go into CAM + * This is dependent on a cam_masks list defined above + */ + km->match[km->num_ftype_elem].masked_for_tcam = 1; + for (unsigned int msk = 0; msk < NUM_CAM_MASKS; msk++) { + if (word_len == cam_masks[msk].word_len) { + int match = 1; + + for (unsigned int wd = 0; wd < word_len; wd++) { + if (e_mask[wd] != cam_masks[msk].key_mask[wd]) { + match = 0; + break; + } + } + if (match) { + /* Can go into CAM */ + km->match[km->num_ftype_elem].masked_for_tcam = + 0; + } + } + } + + km->num_ftype_elem++; + return 0; +} + +void km_set_info(struct km_flow_def_s *km, int on) +{ + km->info_set = !!on; +} + +static int get_word(struct km_flow_def_s *km, uint32_t size, int marked[]) +{ + for (int i = 0; i < km->num_ftype_elem; i++) { + if (!marked[i] && + !(km->match[i].extr_start_offs_id & SWX_INFO) && + km->match[i].word_len == size) + return i; + } + return -1; +} + +#ifdef FLOW_DEBUG +static const char *get_prot_offset_descr(int idx) +{ + switch (idx) { + case DYN_SOF: + return "SOF"; + case DYN_L2: + return "L2 header"; + case DYN_FIRST_VLAN: + return "First VLAN"; + case DYN_MPLS: + return "First MPLS"; + case DYN_L3: + return "L3 header"; + case DYN_ID_IPV4_6: + return "ID field IPv4/6"; + case DYN_FINAL_IP_DST: + return "Final IP dest"; + case DYN_L4: + return "L4 header"; + case DYN_L4_PAYLOAD: + return "L4 payload"; + case DYN_TUN_PAYLOAD: + return "Tunnel payload"; + case DYN_TUN_L2: + return "Tunnel L2 header"; + case DYN_TUN_VLAN: + return "First tunneled VLAN"; + case DYN_TUN_MPLS: + return "First tunneled MPLS"; + case DYN_TUN_L3: + return "Tunnel L3 header"; + case DYN_TUN_ID_IPV4_6: + return "Tunnel ID field IPv4/6"; + case DYN_TUN_FINAL_IP_DST: + return "Tunnel final IP dest"; + case DYN_TUN_L4: + return "Tunnel L4 header"; + case DYN_TUN_L4_PAYLOAD: + return "Tunnel L4 payload"; + case SB_VNI: + return "VNI"; + case SB_MAC_PORT: + return "In Port"; + case SB_KCC_ID: + return "KCC ID"; + default: + break; + } + return ""; +} +#endif + +#define MAX_QWORDS 2 +#define MAX_SWORDS 2 + +int km_key_create(struct km_flow_def_s *km, uint32_t port_id) +{ + /* + * Create combined extractor mappings + * if key fields may be changed to cover un-mappable otherwise? + * split into cam and tcam and use synergy mode when available + * + */ + int match_marked[MAX_MATCH_FIELDS]; + int idx = 0; + int next = 0; + int m_idx; + int size; + + memset(match_marked, 0, sizeof(match_marked)); + + /* build QWords */ + for (int qwords = 0; qwords < MAX_QWORDS; qwords++) { + size = 4; + m_idx = get_word(km, size, match_marked); + if (m_idx < 0) { + size = 2; + m_idx = get_word(km, size, match_marked); + + if (m_idx < 0) { + size = 1; + m_idx = get_word(km, 1, match_marked); + } + } + if (m_idx < 0) { + /* no more defined */ + break; + } + + match_marked[m_idx] = 1; + + /* build match map list and set final extractor to use */ + km->match_map[next] = &km->match[m_idx]; + km->match[m_idx].extr = KM_USE_EXTRACTOR_QWORD; + + /* build final entry words and mask array */ + for (int i = 0; i < size; i++) { + km->entry_word[idx + i] = km->match[m_idx].e_word[i]; + km->entry_mask[idx + i] = km->match[m_idx].e_mask[i]; + } + + idx += size; + next++; + } + + m_idx = get_word(km, 4, match_marked); + if (m_idx >= 0) { + /* cannot match more QWords */ + return -1; + } + + /* + * On km v6+ we have DWORDs here instead. However, we only use them as SWORDs for now + * No match would be able to exploit these as DWORDs because of maximum length of 12 words + * in CAM + * The last 2 words are taken by KCC-ID/SWX and Color. You could have one or none QWORDs + * where then both these DWORDs were possible in 10 words, but we don't have such use case + * built in yet + */ + /* build SWords */ + for (int swords = 0; swords < MAX_SWORDS; swords++) { + m_idx = get_word(km, 1, match_marked); + if (m_idx < 0) { + /* no more defined */ + break; + } + + match_marked[m_idx] = 1; + /* build match map list and set final extractor to use */ + km->match_map[next] = &km->match[m_idx]; + km->match[m_idx].extr = KM_USE_EXTRACTOR_SWORD; + + /* build final entry words and mask array */ + km->entry_word[idx] = km->match[m_idx].e_word[0]; + km->entry_mask[idx] = km->match[m_idx].e_mask[0]; + idx++; + next++; + } + + /* + * Make sure we took them all + */ + m_idx = get_word(km, 1, match_marked); + if (m_idx >= 0) { + /* cannot match more SWords */ + return -1; + } + + /* + * Handle SWX words specially + */ + int swx_found = 0; + + for (int i = 0; i < km->num_ftype_elem; i++) { + if (km->match[i].extr_start_offs_id & SWX_INFO) { + km->match_map[next] = &km->match[i]; + km->match[i].extr = KM_USE_EXTRACTOR_SWORD; + /* build final entry words and mask array */ + km->entry_word[idx] = km->match[i].e_word[0]; + km->entry_mask[idx] = km->match[i].e_mask[0]; + idx++; + next++; + swx_found = 1; + } + } + + assert(next == km->num_ftype_elem); + + km->key_word_size = idx; + km->port_id = port_id; + + km->target = KM_CAM; + /* + * Finally decide if we want to put this match->action into the TCAM + * When SWX word used we need to put it into CAM always, no matter what mask pattern + * Later, when synergy mode is applied, we can do a split + */ + if (!swx_found && km->key_word_size <= 6) { + for (int i = 0; i < km->num_ftype_elem; i++) { + if (km->match_map[i]->masked_for_tcam) { + /* At least one */ + km->target = KM_TCAM; + } + } + } + + NT_LOG(DBG, FILTER, "This flow goes into %s\n", + (km->target == KM_TCAM) ? "TCAM" : "CAM"); + + if (km->target == KM_TCAM) { + if (km->key_word_size > 10) { + /* do not support SWX in TCAM */ + return -1; + } + /* + * adjust for unsupported key word size in TCAM + */ + if ((km->key_word_size == 5 || km->key_word_size == 7 || + km->key_word_size == 9)) { + km->entry_mask[km->key_word_size] = 0; + km->key_word_size++; + } + + /* + * 1. the fact that the length of a key cannot change among the same used banks + * + * calculate possible start indexes + * unfortunately restrictions in TCAM lookup + * makes it hard to handle key lengths larger than 6 + * when other sizes should be possible too + */ + switch (km->key_word_size) { + case 1: + for (int i = 0; i < 4; i++) + km->start_offsets[0] = 8 + i; + km->num_start_offsets = 4; + break; + case 2: + km->start_offsets[0] = 6; + km->num_start_offsets = 1; + break; + case 3: + km->start_offsets[0] = 0; + km->num_start_offsets = 1; + /* enlarge to 6 */ + km->entry_mask[km->key_word_size++] = 0; + km->entry_mask[km->key_word_size++] = 0; + km->entry_mask[km->key_word_size++] = 0; + break; + case 4: + km->start_offsets[0] = 0; + km->num_start_offsets = 1; + /* enlarge to 6 */ + km->entry_mask[km->key_word_size++] = 0; + km->entry_mask[km->key_word_size++] = 0; + break; + case 6: + km->start_offsets[0] = 0; + km->num_start_offsets = 1; + break; + + default: + NT_LOG(DBG, FILTER, + "Final Key word size too large: %i\n", + km->key_word_size); + return -1; + } + +#ifdef FLOW_DEBUG + char *s = ntlog_helper_str_alloc("TCAM offs: "); + + for (int i = 0; i < km->num_start_offsets; i++) + ntlog_helper_str_add(s, "%i,", km->start_offsets[i]); + NT_LOG(DBG, FILTER, "%s", s); + ntlog_helper_str_free(s); +#endif + } + +#ifdef FLOW_DEBUG + for (int i = 0; i < km->num_ftype_elem; i++) { + NT_LOG(DBG, FILTER, + "size %i -> Extr: %s, offset id: %s, rel offset: %i\n", + km->match_map[i]->word_len, + (km->match_map[i]->extr_start_offs_id & SWX_INFO) ? + "SIDEBAND" : + km->match_map[i]->extr == KM_USE_EXTRACTOR_SWORD ? + "SWORD" : + "QWORD", + get_prot_offset_descr(km->match_map[i]->extr_start_offs_id), + km->match_map[i]->rel_offs); + } + char *s = ntlog_helper_str_alloc(""); + + for (int i = 0; i < km->key_word_size; i++) + ntlog_helper_str_add(s, "%08x,", km->entry_word[i]); + + NT_LOG(DBG, FILTER, "%s", s); + + ntlog_helper_str_reset(s, ""); + for (int i = 0; i < km->key_word_size; i++) + ntlog_helper_str_add(s, "%08x,", km->entry_mask[i]); + + NT_LOG(DBG, FILTER, "%s", s); + ntlog_helper_str_free(s); +#endif + + return 0; +} + +int km_key_compare(struct km_flow_def_s *km, struct km_flow_def_s *km1) +{ + if (km->target != km1->target || + km->num_ftype_elem != km1->num_ftype_elem || + km->key_word_size != km1->key_word_size || + km->info_set != km1->info_set) + return 0; + + /* + * before KCC-CAM: + * if port is added to match, then we can have different ports in CAT + * that reuses this flow type + */ + int port_match_included = 0, kcc_swx_used = 0; + + for (int i = 0; i < km->num_ftype_elem; i++) { + if (km->match[i].extr_start_offs_id == SB_MAC_PORT) { + port_match_included = 1; + break; + } else if (km->match_map[i]->extr_start_offs_id == SB_KCC_ID) { + kcc_swx_used = 1; + break; + } + } + + /* + * If not using KCC and if port match is not included in CAM, + * we need to have same port_id to reuse + */ + if (!kcc_swx_used && !port_match_included && + km->port_id != km1->port_id) + return 0; + + for (int i = 0; i < km->num_ftype_elem; i++) { + /* using same extractor types in same sequence */ + if (km->match_map[i]->extr_start_offs_id != km1->match_map[i]->extr_start_offs_id || + km->match_map[i]->rel_offs != km1->match_map[i]->rel_offs || + km->match_map[i]->extr != km1->match_map[i]->extr || + km->match_map[i]->word_len != km1->match_map[i]->word_len) + return 0; + } + + if (km->target == KM_CAM) { + /* in CAM must exactly match on all masks */ + for (int i = 0; i < km->key_word_size; i++) { + if (km->entry_mask[i] != km1->entry_mask[i]) + return 0; + } + + /* Would be set later if not reusing from km1 */ + km->cam_paired = km1->cam_paired; + } else if (km->target == KM_TCAM) { + /* + * If TCAM, we must make sure Recipe Key Mask does not + * mask out enable bits in masks + * Note: it is important that km1 is the original creator + * of the KM Recipe, since it contains its true masks + */ + for (int i = 0; i < km->key_word_size; i++) { + if ((km->entry_mask[i] & km1->entry_mask[i]) != + km->entry_mask[i]) + return 0; + } + + km->tcam_start_bank = km1->tcam_start_bank; + km->tcam_record = -1; /* needs to be found later */ + } else { + NT_LOG(DBG, FILTER, + "ERROR - KM target not defined or supported\n"); + return 0; + } + + /* + * Check for a flow clash. If already programmed return with -1 + */ + int double_match = 1; + + for (int i = 0; i < km->key_word_size; i++) { + if ((km->entry_word[i] & km->entry_mask[i]) != + (km1->entry_word[i] & km1->entry_mask[i])) { + double_match = 0; + break; + } + } + + if (double_match) + return -1; + + /* + * Note that TCAM and CAM may reuse same RCP and flow type + * when this happens, CAM entry wins on overlap + */ + + /* Use same KM Recipe and same flow type - return flow type */ + return km1->flow_type; +} + +int km_rcp_set(struct km_flow_def_s *km, int index) +{ + int qw = 0; + int sw = 0; + int swx = 0; + + hw_mod_km_rcp_set(km->be, HW_KM_RCP_PRESET_ALL, index, 0, 0); + + /* set extractor words, offs, contrib */ + for (int i = 0; i < km->num_ftype_elem; i++) { + switch (km->match_map[i]->extr) { + case KM_USE_EXTRACTOR_SWORD: + if (km->match_map[i]->extr_start_offs_id & SWX_INFO) { + if (km->target == KM_CAM && swx == 0) { + /* SWX */ + if (km->match_map[i] + ->extr_start_offs_id == + SB_VNI) { + NT_LOG(DBG, FILTER, + "Set KM SWX sel A - VNI\n"); + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_SWX_CCH, + index, 0, 1); + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_SWX_SEL_A, + index, 0, + SWX_SEL_ALL32); + } else if (km->match_map[i] + ->extr_start_offs_id == + SB_MAC_PORT) { + NT_LOG(DBG, FILTER, + "Set KM SWX sel A - PTC + MAC\n"); + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_SWX_SEL_A, + index, 0, + SWX_SEL_ALL32); + } else if (km->match_map[i] + ->extr_start_offs_id == + SB_KCC_ID) { + NT_LOG(DBG, FILTER, + "Set KM SWX sel A - KCC ID\n"); + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_SWX_CCH, + index, 0, 1); + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_SWX_SEL_A, + index, 0, + SWX_SEL_ALL32); + } else { + return -1; + } + } else { + return -1; + } + swx++; + } else { + if (sw == 0) { + /* DW8 */ + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_DW8_DYN, + index, 0, + km->match_map[i] + ->extr_start_offs_id); + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_DW8_OFS, + index, 0, + km->match_map[i]->rel_offs); + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_DW8_SEL_A, + index, 0, + DW8_SEL_FIRST32); + NT_LOG(DBG, FILTER, + "Set KM DW8 sel A: dyn: %i, offs: %i\n", + km->match_map[i] + ->extr_start_offs_id, + km->match_map[i]->rel_offs); + } else if (sw == 1) { + /* DW10 */ + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_DW10_DYN, + index, 0, + km->match_map[i] + ->extr_start_offs_id); + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_DW10_OFS, + index, 0, + km->match_map[i]->rel_offs); + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_DW10_SEL_A, + index, 0, + DW10_SEL_FIRST32); + NT_LOG(DBG, FILTER, + "Set KM DW10 sel A: dyn: %i, offs: %i\n", + km->match_map[i] + ->extr_start_offs_id, + km->match_map[i]->rel_offs); + } else { + return -1; + } + sw++; + } + break; + + case KM_USE_EXTRACTOR_QWORD: + if (qw == 0) { + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_QW0_DYN, + index, 0, + km->match_map[i]->extr_start_offs_id); + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_QW0_OFS, + index, 0, + km->match_map[i]->rel_offs); + switch (km->match_map[i]->word_len) { + case 1: + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_QW0_SEL_A, + index, 0, + QW0_SEL_FIRST32); + break; + case 2: + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_QW0_SEL_A, + index, 0, + QW0_SEL_FIRST64); + break; + case 4: + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_QW0_SEL_A, + index, 0, + QW0_SEL_ALL128); + break; + default: + return -1; + } + NT_LOG(DBG, FILTER, + "Set KM QW0 sel A: dyn: %i, offs: %i, size: %i\n", + km->match_map[i]->extr_start_offs_id, + km->match_map[i]->rel_offs, + km->match_map[i]->word_len); + } else if (qw == 1) { + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_QW4_DYN, + index, 0, + km->match_map[i]->extr_start_offs_id); + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_QW4_OFS, + index, 0, + km->match_map[i]->rel_offs); + switch (km->match_map[i]->word_len) { + case 1: + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_QW4_SEL_A, + index, 0, + QW4_SEL_FIRST32); + break; + case 2: + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_QW4_SEL_A, + index, 0, + QW4_SEL_FIRST64); + break; + case 4: + hw_mod_km_rcp_set(km->be, + HW_KM_RCP_QW4_SEL_A, + index, 0, + QW4_SEL_ALL128); + break; + default: + return -1; + } + NT_LOG(DBG, FILTER, + "Set KM QW4 sel A: dyn: %i, offs: %i, size: %i\n", + km->match_map[i]->extr_start_offs_id, + km->match_map[i]->rel_offs, + km->match_map[i]->word_len); + } else { + return -1; + } + qw++; + break; + default: + return -1; + } + } + + /* set mask A */ + for (int i = 0; i < km->key_word_size; i++) { + hw_mod_km_rcp_set(km->be, HW_KM_RCP_MASK_A, index, + (km->be->km.nb_km_rcp_mask_a_word_size - 1) - + i, + km->entry_mask[i]); + NT_LOG(DBG, FILTER, "Set KM mask A: %08x\n", km->entry_mask[i]); + } + + if (km->target == KM_CAM) { + /* set info - Color */ + if (km->info_set) { + hw_mod_km_rcp_set(km->be, HW_KM_RCP_INFO_A, index, 0, + 1); + NT_LOG(DBG, FILTER, "Set KM info A\n"); + } + /* set key length A */ + hw_mod_km_rcp_set(km->be, HW_KM_RCP_EL_A, index, 0, + km->key_word_size + !!km->info_set - + 1); /* select id is -1 */ + /* set Flow Type for Key A */ + NT_LOG(DBG, FILTER, "Set KM EL A: %i\n", + km->key_word_size + !!km->info_set - 1); + + hw_mod_km_rcp_set(km->be, HW_KM_RCP_FTM_A, index, 0, + 1 << km->flow_type); + + NT_LOG(DBG, FILTER, "Set KM FTM A - ft: %i\n", km->flow_type); + + /* Set Paired - only on the CAM part though... */ + if ((uint32_t)(km->key_word_size + !!km->info_set) > + km->be->km.nb_cam_record_words) { + hw_mod_km_rcp_set(km->be, HW_KM_RCP_PAIRED, + index, 0, 1); + NT_LOG(DBG, FILTER, "Set KM CAM Paired\n"); + km->cam_paired = 1; + } + } else if (km->target == KM_TCAM) { + uint32_t bank_bm = 0; + + if (tcam_find_mapping(km) < 0) { + /* failed mapping into TCAM */ + NT_LOG(DBG, FILTER, "INFO: TCAM mapping flow failed\n"); + return -1; + } + + assert((uint32_t)(km->tcam_start_bank + km->key_word_size) <= + km->be->km.nb_tcam_banks); + + for (int i = 0; i < km->key_word_size; i++) { + bank_bm |= (1 << (km->be->km.nb_tcam_banks - 1 - + (km->tcam_start_bank + i))); + } + + /* Set BANK_A */ + hw_mod_km_rcp_set(km->be, HW_KM_RCP_BANK_A, index, 0, bank_bm); + /* Set Kl_A */ + hw_mod_km_rcp_set(km->be, HW_KM_RCP_KL_A, index, 0, + km->key_word_size - 1); + + } else { + return -1; + } + return 0; +} + +static int cam_populate(struct km_flow_def_s *km, int bank) +{ + int res = 0; + int cnt = km->key_word_size + !!km->info_set; + + for (uint32_t i = 0; i < km->be->km.nb_cam_record_words && cnt; + i++, cnt--) { + res |= hw_mod_km_cam_set(km->be, HW_KM_CAM_W0 + i, bank, + km->record_indexes[bank], + km->entry_word[i]); + res |= hw_mod_km_cam_set(km->be, HW_KM_CAM_FT0 + i, bank, + km->record_indexes[bank], + km->flow_type); + } + km->cam_dist[CAM_KM_DIST_IDX(bank)].km_owner = km; + + if (cnt) { + assert(km->cam_paired); + for (uint32_t i = 0; i < km->be->km.nb_cam_record_words && cnt; + i++, cnt--) { + res |= hw_mod_km_cam_set(km->be, + HW_KM_CAM_W0 + i, + bank, + km->record_indexes[bank] + 1, + km->entry_word[km->be->km.nb_cam_record_words + + i]); + res |= hw_mod_km_cam_set(km->be, HW_KM_CAM_FT0 + i, + bank, + km->record_indexes[bank] + 1, + km->flow_type); + } + km->cam_dist[CAM_KM_DIST_IDX(bank) + 1].km_owner = km; + } + + res |= hw_mod_km_cam_flush(km->be, bank, km->record_indexes[bank], + km->cam_paired ? 2 : 1); + + return res; +} + +static int cam_reset_entry(struct km_flow_def_s *km, int bank) +{ + int res = 0; + int cnt = km->key_word_size + !!km->info_set; + + for (uint32_t i = 0; i < km->be->km.nb_cam_record_words && cnt; + i++, cnt--) { + res |= hw_mod_km_cam_set(km->be, HW_KM_CAM_W0 + i, bank, + km->record_indexes[bank], 0); + res |= hw_mod_km_cam_set(km->be, HW_KM_CAM_FT0 + i, bank, + km->record_indexes[bank], 0); + } + km->cam_dist[CAM_KM_DIST_IDX(bank)].km_owner = NULL; + + if (cnt) { + assert(km->cam_paired); + for (uint32_t i = 0; i < km->be->km.nb_cam_record_words && cnt; + i++, cnt--) { + res |= hw_mod_km_cam_set(km->be, HW_KM_CAM_W0 + i, bank, + km->record_indexes[bank] + 1, + 0); + res |= hw_mod_km_cam_set(km->be, HW_KM_CAM_FT0 + i, + bank, + km->record_indexes[bank] + 1, + 0); + } + km->cam_dist[CAM_KM_DIST_IDX(bank) + 1].km_owner = NULL; + } + res |= hw_mod_km_cam_flush(km->be, bank, km->record_indexes[bank], + km->cam_paired ? 2 : 1); + return res; +} + +static int move_cuckoo_index(struct km_flow_def_s *km) +{ + assert(km->cam_dist[CAM_KM_DIST_IDX(km->bank_used)].km_owner); + + for (uint32_t bank = 0; bank < km->be->km.nb_cam_banks; bank++) { + /* It will not select itself */ + if (km->cam_dist[CAM_KM_DIST_IDX(bank)].km_owner == NULL) { + if (km->cam_paired) { + if (km->cam_dist[CAM_KM_DIST_IDX(bank) + 1] + .km_owner != NULL) + continue; + } + + /* + * Populate in new position + */ + int res = cam_populate(km, bank); + + if (res) { + NT_LOG(DBG, FILTER, + "Error: failed to write to KM CAM in cuckoo move\n"); + return 0; + } + + /* + * Reset/free entry in old bank + * HW flushes are really not needed, the old addresses are always taken over + * by the caller + * If you change this code in future updates, this may no longer be true + * then! + */ + km->cam_dist[CAM_KM_DIST_IDX(km->bank_used)].km_owner = + NULL; + if (km->cam_paired) + km->cam_dist[CAM_KM_DIST_IDX(km->bank_used) + 1] + .km_owner = NULL; + + NT_LOG(DBG, FILTER, + "KM Cuckoo hash moved from bank %i to bank %i (%04X => %04X)\n", + km->bank_used, bank, + CAM_KM_DIST_IDX(km->bank_used), + CAM_KM_DIST_IDX(bank)); + km->bank_used = bank; + (*km->cuckoo_moves)++; + return 1; + } + } + return 0; +} + +static int move_cuckoo_index_level(struct km_flow_def_s *km_parent, + int bank_idx, int levels, + int cam_adr_list_len) +{ + struct km_flow_def_s *km = km_parent->cam_dist[bank_idx].km_owner; + + assert(levels <= CUCKOO_MOVE_MAX_DEPTH); + + /* + * Only move if same pairness + * Can be extended later to handle both move of paired and single entries + */ + if (!km || km_parent->cam_paired != km->cam_paired) + return 0; + + if (move_cuckoo_index(km)) + return 1; + if (levels <= 1) + return 0; + + assert(cam_adr_list_len < CUCKOO_MOVE_MAX_DEPTH); + + cam_addr_reserved_stack[cam_adr_list_len++] = bank_idx; + + for (uint32_t i = 0; i < km->be->km.nb_cam_banks; i++) { + int reserved = 0; + int new_idx = CAM_KM_DIST_IDX(i); + + for (int i_reserved = 0; i_reserved < cam_adr_list_len; + i_reserved++) { + if (cam_addr_reserved_stack[i_reserved] == new_idx) { + reserved = 1; + break; + } + } + if (reserved) + continue; + + int res = move_cuckoo_index_level(km, new_idx, levels - 1, + cam_adr_list_len); + if (res) { + if (move_cuckoo_index(km)) + return 1; + + else + assert(0); + } + } + + return 0; +} + +static int km_write_data_to_cam(struct km_flow_def_s *km) +{ + int res = 0; + int val[MAX_BANKS]; + + assert(km->be->km.nb_cam_banks <= MAX_BANKS); + assert(km->cam_dist); + + /* word list without info set */ + gethash(km->hsh, km->entry_word, val); + + for (uint32_t i = 0; i < km->be->km.nb_cam_banks; i++) { + /* if paired we start always on an even address - reset bit 0 */ + km->record_indexes[i] = (km->cam_paired) ? val[i] & ~1 : val[i]; + } + NT_LOG(DBG, FILTER, "KM HASH [%03X, %03X, %03X]\n", + km->record_indexes[0], km->record_indexes[1], + km->record_indexes[2]); + + if (km->info_set) { + km->entry_word[km->key_word_size] = + km->info; /* finally set info */ + } + + int bank = -1; + /* + * first step, see if any of the banks are free + */ + for (uint32_t i_bank = 0; i_bank < km->be->km.nb_cam_banks; i_bank++) { + if (km->cam_dist[CAM_KM_DIST_IDX(i_bank)].km_owner == NULL) { + if (km->cam_paired == 0 || + (km->cam_dist[CAM_KM_DIST_IDX(i_bank) + 1] + .km_owner == NULL)) { + bank = i_bank; + break; + } + } + } + + if (bank < 0) { + /* + * Second step - cuckoo move existing flows if possible + */ + for (uint32_t i_bank = 0; i_bank < km->be->km.nb_cam_banks; + i_bank++) { + if (move_cuckoo_index_level(km, CAM_KM_DIST_IDX(i_bank), + 4, 0)) { + bank = i_bank; + break; + } + } + } + if (bank < 0) + return -1; + + /* populate CAM */ + NT_LOG(DBG, FILTER, "KM Bank = %i (addr %04X)\n", bank, + CAM_KM_DIST_IDX(bank)); + res = cam_populate(km, bank); + if (res == 0) { + km->flushed_to_target = 1; + km->bank_used = bank; + } + + return res; +} + +/* + * TCAM + */ +static int tcam_find_free_record(struct km_flow_def_s *km, int start_bank) +{ + for (uint32_t rec = 0; rec < km->be->km.nb_tcam_bank_width; rec++) { + if (km->tcam_dist[TCAM_DIST_IDX(start_bank, rec)].km_owner == + NULL) { + int pass = 1; + + for (int ii = 1; ii < km->key_word_size; ii++) { + if (km->tcam_dist[TCAM_DIST_IDX(start_bank + ii, + rec)] + .km_owner != NULL) { + pass = 0; + break; + } + } + if (pass) { + km->tcam_record = rec; + return 1; + } + } + } + + return 0; +} + +static int tcam_find_mapping(struct km_flow_def_s *km) +{ + /* Search record and start index for this flow */ + for (int bs_idx = 0; bs_idx < km->num_start_offsets; bs_idx++) { + if (tcam_find_free_record(km, km->start_offsets[bs_idx])) { + km->tcam_start_bank = km->start_offsets[bs_idx]; + NT_LOG(DBG, FILTER, + "Found space in TCAM start bank %i, record %i\n", + km->tcam_start_bank, km->tcam_record); + return 0; + } + } + return -1; +} + +static int tcam_write_word(struct km_flow_def_s *km, int bank, int record, + uint32_t word, uint32_t mask) +{ + int err = 0; + uint32_t all_recs[3]; + + int rec_val = record / 32; + int rec_bit_shft = record % 32; + uint32_t rec_bit = (1 << rec_bit_shft); + + assert((km->be->km.nb_tcam_bank_width + 31) / 32 <= 3); + + for (int byte = 0; byte < 4; byte++) { + uint8_t a = (uint8_t)((word >> (24 - (byte * 8))) & 0xff); + uint8_t a_m = (uint8_t)((mask >> (24 - (byte * 8))) & 0xff); + /* calculate important value bits */ + a = a & a_m; + +#ifdef FLOW_DEBUG + if (a_m == 0) { + NT_LOG(DBG, FILTER, + "bank %i, byte %i, All values, rec_val %i rec bit %08x\n", + bank, byte, rec_val, rec_bit); + } +#endif + + for (int val = 0; val < 256; val++) { + err |= hw_mod_km_tcam_get(km->be, HW_KM_TCAM_T, bank, + byte, val, all_recs); + if ((val & a_m) == a) { + all_recs[rec_val] |= rec_bit; +#ifdef FLOW_DEBUG + if (a_m) { + NT_LOG(DBG, FILTER, + "bank %i, byte %i, val %i(%02x), " + "rec_val %i rec bit %08x\n", + bank, byte, val, val, rec_val, + rec_bit); + } +#endif + } else { + all_recs[rec_val] &= ~rec_bit; + } + err |= hw_mod_km_tcam_set(km->be, HW_KM_TCAM_T, bank, + byte, val, all_recs); + if (err) + break; + } + } + /* flush bank */ + err |= hw_mod_km_tcam_flush(km->be, bank, ALL_BANK_ENTRIES); + if (err == 0) { + assert(km->tcam_dist[TCAM_DIST_IDX(bank, record)].km_owner == + NULL); + km->tcam_dist[TCAM_DIST_IDX(bank, record)].km_owner = km; + } + return err; +} + +static int km_write_data_to_tcam(struct km_flow_def_s *km) +{ + int err = 0; + + if (km->tcam_record < 0) { + tcam_find_free_record(km, km->tcam_start_bank); + if (km->tcam_record < 0) { + NT_LOG(DBG, FILTER, + "FAILED to find space in TCAM for flow\n"); + return -1; + } + NT_LOG(DBG, FILTER, + "Reused RCP: Found space in TCAM start bank %i, record %i\n", + km->tcam_start_bank, km->tcam_record); + } + + /* Write KM_TCI */ + err |= hw_mod_km_tci_set(km->be, HW_KM_TCI_COLOR, km->tcam_start_bank, + km->tcam_record, km->info); + err |= hw_mod_km_tci_set(km->be, HW_KM_TCI_FT, km->tcam_start_bank, + km->tcam_record, km->flow_type); + err |= hw_mod_km_tci_flush(km->be, km->tcam_start_bank, km->tcam_record, + 1); + +#ifdef FLOW_DEBUG + km->be->iface->set_debug_mode(km->be->be_dev, + FLOW_BACKEND_DEBUG_MODE_NONE); +#endif + + for (int i = 0; i < km->key_word_size && !err; i++) { + err = tcam_write_word(km, km->tcam_start_bank + i, + km->tcam_record, km->entry_word[i], + km->entry_mask[i]); + } +#ifdef FLOW_DEBUG + km->be->iface->set_debug_mode(km->be->be_dev, + FLOW_BACKEND_DEBUG_MODE_WRITE); +#endif + + if (err == 0) + km->flushed_to_target = 1; + + return err; +} + +static int tcam_reset_bank(struct km_flow_def_s *km, int bank, int record) +{ + int err = 0; + uint32_t all_recs[3]; + + int rec_val = record / 32; + int rec_bit_shft = record % 32; + uint32_t rec_bit = (1 << rec_bit_shft); + + assert((km->be->km.nb_tcam_bank_width + 31) / 32 <= 3); + + for (int byte = 0; byte < 4; byte++) { + for (int val = 0; val < 256; val++) { + err = hw_mod_km_tcam_get(km->be, HW_KM_TCAM_T, bank, + byte, val, all_recs); + if (err) + break; + all_recs[rec_val] &= ~rec_bit; + err = hw_mod_km_tcam_set(km->be, HW_KM_TCAM_T, bank, + byte, val, all_recs); + if (err) + break; + } + } + if (err) + return err; + + /* flush bank */ + err = hw_mod_km_tcam_flush(km->be, bank, ALL_BANK_ENTRIES); + km->tcam_dist[TCAM_DIST_IDX(bank, record)].km_owner = NULL; + + NT_LOG(DBG, FILTER, "Reset TCAM bank %i, rec_val %i rec bit %08x\n", + bank, rec_val, rec_bit); + + return err; +} + +static int tcam_reset_entry(struct km_flow_def_s *km) +{ + int err = 0; + + if (km->tcam_start_bank < 0 || km->tcam_record < 0) { + NT_LOG(DBG, FILTER, "FAILED to find space in TCAM for flow\n"); + return -1; + } + + /* Write KM_TCI */ + hw_mod_km_tci_set(km->be, HW_KM_TCI_COLOR, km->tcam_start_bank, + km->tcam_record, 0); + hw_mod_km_tci_set(km->be, HW_KM_TCI_FT, km->tcam_start_bank, + km->tcam_record, 0); + hw_mod_km_tci_flush(km->be, km->tcam_start_bank, km->tcam_record, 1); + +#ifdef FLOW_DEBUG + km->be->iface->set_debug_mode(km->be->be_dev, + FLOW_BACKEND_DEBUG_MODE_NONE); +#endif + + for (int i = 0; i < km->key_word_size && !err; i++) { + err = tcam_reset_bank(km, km->tcam_start_bank + i, + km->tcam_record); + } +#ifdef FLOW_DEBUG + km->be->iface->set_debug_mode(km->be->be_dev, + FLOW_BACKEND_DEBUG_MODE_WRITE); +#endif + + return err; +} + +int km_refer_data_match_entry(struct km_flow_def_s *km, + struct km_flow_def_s *km1) +{ + int res = 0; + + km->root = km1->root ? km1->root : km1; + while (km1->reference) + km1 = km1->reference; + km1->reference = km; + + km->info = km1->info; + + switch (km->target) { + case KM_CAM: + km->cam_paired = km1->cam_paired; + km->bank_used = km1->bank_used; + km->flushed_to_target = km1->flushed_to_target; + break; + case KM_TCAM: + km->tcam_start_bank = km1->tcam_start_bank; + km->tcam_record = km1->tcam_record; + km->flushed_to_target = km1->flushed_to_target; + break; + case KM_SYNERGY: + default: + res = -1; + break; + } + + return res; +} + +int km_write_data_match_entry(struct km_flow_def_s *km, uint32_t color) +{ + int res = -1; + + km->info = color; + NT_LOG(DBG, FILTER, "Write Data entry Color: %08x\n", color); + + switch (km->target) { + case KM_CAM: + res = km_write_data_to_cam(km); + break; + case KM_TCAM: + res = km_write_data_to_tcam(km); + break; + case KM_SYNERGY: + default: + break; + } + return res; +} + +int km_clear_data_match_entry(struct km_flow_def_s *km) +{ + int res = 0; + + if (km->root) { + struct km_flow_def_s *km1 = km->root; + + while (km1->reference != km) + km1 = km1->reference; + + km1->reference = km->reference; + + km->flushed_to_target = 0; + km->bank_used = 0; + } else if (km->reference) { + km->reference->root = NULL; + + switch (km->target) { + case KM_CAM: + km->cam_dist[CAM_KM_DIST_IDX(km->bank_used)].km_owner = + km->reference; + if (km->key_word_size + !!km->info_set > 1) { + assert(km->cam_paired); + km->cam_dist[CAM_KM_DIST_IDX(km->bank_used) + 1] + .km_owner = km->reference; + } + break; + case KM_TCAM: + for (int i = 0; i < km->key_word_size; i++) { + km->tcam_dist[TCAM_DIST_IDX(km->tcam_start_bank + i, + km->tcam_record)].km_owner = km->reference; + } + break; + case KM_SYNERGY: + default: + res = -1; + break; + } + + km->flushed_to_target = 0; + km->bank_used = 0; + } else if (km->flushed_to_target) { + switch (km->target) { + case KM_CAM: + res = cam_reset_entry(km, km->bank_used); + break; + case KM_TCAM: + res = tcam_reset_entry(km); + break; + case KM_SYNERGY: + default: + res = -1; + break; + } + km->flushed_to_target = 0; + km->bank_used = 0; + } + + return res; +} diff --git a/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_tunnel.c b/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_tunnel.c new file mode 100644 index 0000000000..17717da8e2 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/flow_engine/flow_tunnel.c @@ -0,0 +1,787 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include +#include /* htons, htonl, ntohs */ +#include +#include "stream_binary_flow_api.h" + +#include "flow_api_backend.h" +#include "flow_api_engine.h" + +#define MAX_HW_VIRT_PORTS 127 /* 255 reserved */ +#define VIRTUAL_TUNNEL_PORT_OFFSET 72 + +struct tunnel_s { + struct tunnel_cfg_s cfg; + struct tunnel_cfg_s cfg_mask; + uint32_t flow_stat_id; + uint8_t vport; + int refcnt; + struct tunnel_s *next; /* linked list of defined tunnels */ +}; + +int is_virtual_port(uint8_t virt_port) +{ + return !!(virt_port >= VIRTUAL_TUNNEL_PORT_OFFSET && + virt_port < MAX_HW_VIRT_PORTS); +} + +/* + * New function for use with OVS 2.17.2 + */ +static struct tunnel_s *tunnels; + +static uint8_t vport[MAX_HW_VIRT_PORTS - VIRTUAL_TUNNEL_PORT_OFFSET + 1]; + +uint8_t flow_tunnel_alloc_virt_port(void) +{ + for (uint8_t i = VIRTUAL_TUNNEL_PORT_OFFSET; i < MAX_HW_VIRT_PORTS; + i++) { + if (!vport[i - VIRTUAL_TUNNEL_PORT_OFFSET]) { + vport[i - VIRTUAL_TUNNEL_PORT_OFFSET] = 1; + return i; + } + } + + /* no more virtual ports */ + return 255; +} + +uint8_t flow_tunnel_free_virt_port(uint8_t virt_port) +{ + if (virt_port >= VIRTUAL_TUNNEL_PORT_OFFSET && + virt_port < MAX_HW_VIRT_PORTS) { + vport[virt_port - VIRTUAL_TUNNEL_PORT_OFFSET] = 0; + return 0; + } + return -1; +} + +#define check(_v1, _v2, _msk1, _msk2) ({ \ + __typeof__(_v1) (v1) = (_v1); \ + __typeof__(_v2) (v2) = (_v2); \ + __typeof__(_msk1) (msk1) = (_msk1); \ + __typeof__(_msk2) (msk2) = (_msk2); \ + (((v1) & (msk1) & (msk2)) == ((v2) & (msk1) & (msk2))); \ +}) + +#define check_tun_v4_equal(_tun_cfg, _tun_msk, _tun1_cfg, _tun1_msk) ({ \ + __typeof__(_tun_cfg) (tun_cfg) = (_tun_cfg); \ + __typeof__(_tun_msk) (tun_msk) = (_tun_msk); \ + __typeof__(_tun1_cfg) (tun1_cfg) = (_tun1_cfg); \ + __typeof__(_tun1_msk) (tun1_msk) = (_tun1_msk); \ + (check((tun_cfg)->v4.src_ip, (tun1_cfg)->v4.src_ip, \ + (tun_msk)->v4.src_ip, (tun1_msk)->v4.src_ip) && \ + check((tun_cfg)->v4.dst_ip, (tun1_cfg)->v4.dst_ip, \ + (tun_msk)->v4.dst_ip, (tun1_msk)->v4.dst_ip) && \ + check((tun_cfg)->s_port, (tun1_cfg)->s_port, (tun_msk)->s_port, \ + (tun1_msk)->s_port) && \ + check((tun_cfg)->d_port, (tun1_cfg)->d_port, (tun_msk)->d_port, \ + (tun1_msk)->d_port)); \ +}) + +#define check_tun_v6_equal(_tun_cfg, _tun_msk, _tun1_cfg, _tun1_msk) ({ \ + __typeof__(_tun_cfg) (tun_cfg) = (_tun_cfg); \ + __typeof__(_tun_msk) (tun_msk) = (_tun_msk); \ + __typeof__(_tun1_cfg) (tun1_cfg) = (_tun1_cfg); \ + __typeof__(_tun1_msk) (tun1_msk) = (_tun1_msk); \ + (check((tun_cfg)->v6_long.src_ip[0], (tun1_cfg)->v6_long.src_ip[0], \ + (tun_msk)->v6_long.src_ip[0], (tun1_msk)->v6_long.src_ip[0]) && \ + check((tun_cfg)->v6_long.src_ip[1], (tun1_cfg)->v6_long.src_ip[1], \ + (tun_msk)->v6_long.src_ip[1], (tun1_msk)->v6_long.src_ip[1]) && \ + check((tun_cfg)->v6_long.dst_ip[0], (tun1_cfg)->v6_long.dst_ip[0], \ + (tun_msk)->v6_long.dst_ip[0], (tun1_msk)->v6_long.dst_ip[0]) && \ + check((tun_cfg)->v6_long.dst_ip[1], (tun1_cfg)->v6_long.dst_ip[1], \ + (tun_msk)->v6_long.dst_ip[1], (tun1_msk)->v6_long.dst_ip[1]) && \ + check((tun_cfg)->s_port, (tun1_cfg)->s_port, (tun_msk)->s_port, \ + (tun1_msk)->s_port) && \ + check((tun_cfg)->d_port, (tun1_cfg)->d_port, (tun_msk)->d_port, \ + (tun1_msk)->d_port)); \ +}) + +static int check_tun_match(struct tunnel_s *tun, + const struct tunnel_cfg_s *tnlcfg, + const struct tunnel_cfg_s *tnlcfg_mask) +{ + if (tun->cfg.tun_type == tnlcfg->tun_type) { + if (tun->cfg.ipversion == 4) { + return check_tun_v4_equal(&tun->cfg, &tun->cfg_mask, + tnlcfg, tnlcfg_mask); + } else { + return check_tun_v6_equal(&tun->cfg, &tun->cfg_mask, + tnlcfg, tnlcfg_mask); + } + } + return 0; +} + +static struct tunnel_s *tunnel_get(const struct tunnel_cfg_s *tnlcfg, + const struct tunnel_cfg_s *tnlcfg_mask, + int tun_set) +{ + struct tunnel_s *tun = tunnels; + + while (tun) { + if (tun->flow_stat_id != (uint32_t)-1) { + /* This tun is already defined and set */ + if (tun_set) { + /* + * A tunnel full match definition - search for duplicate + */ + if (memcmp(&tun->cfg, tnlcfg, + sizeof(struct tunnel_cfg_s)) == 0 && + memcmp(&tun->cfg_mask, tnlcfg_mask, + sizeof(struct tunnel_cfg_s)) == 0) + break; + } else { + /* + * A tunnel match search + */ + if (check_tun_match(tun, tnlcfg, tnlcfg_mask)) + break; + } + + } else if (tun_set) { + /* + * Check if this is a pre-configured tunnel for this one to be set + * try match them + */ + if (check_tun_match(tun, tnlcfg, tnlcfg_mask)) { + /* + * Change the tun into the defining one - flow_stat_id is set later + */ + memcpy(&tun->cfg, tnlcfg, + sizeof(struct tunnel_cfg_s)); + memcpy(&tun->cfg_mask, tnlcfg_mask, + sizeof(struct tunnel_cfg_s)); + + break; + } + + } /* else ignore - both unset */ + tun = tun->next; + } + + /* + * If not found, create and add it to db + */ + if (!tun) { + uint8_t vport = flow_tunnel_alloc_virt_port(); + + NT_LOG(DBG, FILTER, "Create NEW tunnel allocate vport %i\n", + vport); + + if (vport < 0xff) { + tun = calloc(1, sizeof(struct tunnel_s)); + memcpy(&tun->cfg, tnlcfg, sizeof(struct tunnel_cfg_s)); + memcpy(&tun->cfg_mask, tnlcfg_mask, + sizeof(struct tunnel_cfg_s)); + + /* flow_stat_id is set later from flow code */ + tun->flow_stat_id = (uint32_t)-1; + tun->vport = vport; + tun->refcnt = 1; + + tun->next = tunnels; + tunnels = tun; + } + } else { + tun->refcnt++; + NT_LOG(DBG, FILTER, "Found tunnel has vport %i - ref %i\n", + tun->vport, tun->refcnt); + } + + return tun; +} + +int tunnel_release(struct tunnel_s *tnl) +{ + struct tunnel_s *tun = tunnels, *prev = NULL; + + NT_LOG(DBG, FILTER, "release tunnel vport %i, ref cnt %i..\n", + tnl->vport, tnl->refcnt); + /* find tunnel in list */ + while (tun) { + if (tun == tnl) + break; + prev = tun; + tun = tun->next; + } + + if (!tun) { + NT_LOG(DBG, FILTER, + "ERROR: Tunnel not found in tunnel release!\n"); + return -1; + } + + /* if last ref, take out of list */ + if (--tun->refcnt == 0) { + if (prev) + prev->next = tun->next; + else + tunnels = tun->next; + flow_tunnel_free_virt_port(tun->vport); + + NT_LOG(DBG, FILTER, + "tunnel ref count == 0 remove tunnel vport %i\n", + tun->vport); + free(tun); + } + + return 0; +} + +struct tunnel_s *tunnel_parse(const struct flow_elem *elem, int *idx, + uint32_t *vni) +{ + int eidx = *idx; + struct tunnel_cfg_s tnlcfg; + struct tunnel_cfg_s tnlcfg_mask; + struct tunnel_s *rtnl = NULL; + + if (elem) { + eidx++; + memset(&tnlcfg, 0, sizeof(struct tunnel_cfg_s)); + int valid = 1; + enum flow_elem_type last_type = FLOW_ELEM_TYPE_END; + + tnlcfg.d_port = 0xffff; + tnlcfg.tun_type = -1; + + if (vni) + *vni = (uint32_t)-1; + + while (elem[eidx].type != FLOW_ELEM_TYPE_END && + elem[eidx].type >= last_type && valid) { + switch (elem[eidx].type) { + case FLOW_ELEM_TYPE_ANY: + case FLOW_ELEM_TYPE_ETH: + /* Ignore */ + break; + case FLOW_ELEM_TYPE_IPV4: { + const struct flow_elem_ipv4 *ipv4 = + (const struct flow_elem_ipv4 *)elem[eidx] + .spec; + const struct flow_elem_ipv4 *ipv4_mask = + (const struct flow_elem_ipv4 *)elem[eidx] + .mask; + + tnlcfg.v4.src_ip = ipv4->hdr.src_ip; + tnlcfg.v4.dst_ip = ipv4->hdr.dst_ip; + tnlcfg_mask.v4.src_ip = ipv4_mask->hdr.src_ip; + tnlcfg_mask.v4.dst_ip = ipv4_mask->hdr.dst_ip; + + tnlcfg.ipversion = 4; + } + break; + case FLOW_ELEM_TYPE_IPV6: { + const struct flow_elem_ipv6 *ipv6 = + (const struct flow_elem_ipv6 *)elem[eidx] + .spec; + const struct flow_elem_ipv6 *ipv6_mask = + (const struct flow_elem_ipv6 *)elem[eidx] + .mask; + + memcpy(tnlcfg.v6.src_ip, ipv6->hdr.src_addr, + sizeof(tnlcfg.v6.src_ip)); + memcpy(tnlcfg.v6.dst_ip, ipv6->hdr.dst_addr, + sizeof(tnlcfg.v6.dst_ip)); + memcpy(tnlcfg_mask.v6.src_ip, + ipv6_mask->hdr.src_addr, + sizeof(tnlcfg.v6.src_ip)); + memcpy(tnlcfg_mask.v6.dst_ip, + ipv6_mask->hdr.dst_addr, + sizeof(tnlcfg.v6.dst_ip)); + + tnlcfg.ipversion = 6; + } + break; + + case FLOW_ELEM_TYPE_UDP: { + const struct flow_elem_udp *udp = + (const struct flow_elem_udp *)elem[eidx] + .spec; + const struct flow_elem_udp *udp_mask = + (const struct flow_elem_udp *)elem[eidx] + .mask; + + tnlcfg.s_port = udp->hdr.src_port; + tnlcfg.d_port = udp->hdr.dst_port; + tnlcfg_mask.s_port = udp_mask->hdr.src_port; + tnlcfg_mask.d_port = udp_mask->hdr.dst_port; + } + break; + + case FLOW_ELEM_TYPE_VXLAN: { + const struct flow_elem_vxlan *vxlan = + (const struct flow_elem_vxlan *) + elem[eidx] + .spec; + if (vni) + *vni = (uint32_t)(((uint32_t) + vxlan->vni[0] + << 16) | + ((uint32_t) + vxlan->vni[1] + << 8) | + ((uint32_t)vxlan + ->vni[2])); + + tnlcfg.tun_type = FLOW_ELEM_TYPE_VXLAN; + } + break; + default: + valid = 0; + break; + } + + last_type = elem[eidx].type; + eidx++; + } + + /* + * vxlan ports : 4789 or 8472 + */ + if (tnlcfg.tun_type < 0 && + (tnlcfg.d_port == 0xb512 || tnlcfg.d_port == 0x1821)) + tnlcfg.tun_type = FLOW_ELEM_TYPE_VXLAN; + + if (!valid || tnlcfg.ipversion == 0 || tnlcfg.tun_type < 0 || + tnlcfg.d_port == 0xffff) { + NT_LOG(DBG, FILTER, "Invalid tunnel received\n"); + return NULL; + } + + /* search/add to DB */ + rtnl = tunnel_get(&tnlcfg, &tnlcfg_mask, + vni ? 0 : + 1); /* if vni == NULL it is a tun set command */ + +#ifdef FLOW_DEBUG + if (rtnl) { + if (vni) + NT_LOG(DBG, FILTER, + "MATCH A TUNNEL DEFINITION - PRESET " + "(PREALLOC VPORT) IF NOT FOUND:\n"); + else + NT_LOG(DBG, FILTER, + "SET A TUNNEL DEFINITION:\n"); + struct in_addr addr, mask; + char buf[64]; + + addr.s_addr = rtnl->cfg.v4.src_ip; + sprintf(buf, "%s", inet_ntoa(addr)); + mask.s_addr = rtnl->cfg_mask.v4.src_ip; + NT_LOG(DBG, FILTER, " tun src IP: %s / %s\n", buf, + inet_ntoa(mask)); + addr.s_addr = rtnl->cfg.v4.dst_ip; + sprintf(buf, "%s", inet_ntoa(addr)); + mask.s_addr = rtnl->cfg_mask.v4.dst_ip; + NT_LOG(DBG, FILTER, " tun dst IP: %s / %s\n", buf, + inet_ntoa(mask)); + NT_LOG(DBG, FILTER, " tun tp_src: %i / %04x\n", + htons(rtnl->cfg.s_port), + htons(rtnl->cfg_mask.s_port)); + NT_LOG(DBG, FILTER, " tun tp_dst: %i / %04x\n", + htons(rtnl->cfg.d_port), + htons(rtnl->cfg_mask.d_port)); + NT_LOG(DBG, FILTER, " tun ipver: %i\n", + rtnl->cfg.ipversion); + NT_LOG(DBG, FILTER, " tun flow_stat_id: %i\n", + rtnl->flow_stat_id); + NT_LOG(DBG, FILTER, " tun vport: %i\n", + rtnl->vport); + NT_LOG(DBG, FILTER, " tun refcnt: %i\n", + rtnl->refcnt); + } +#endif + + *idx = eidx; /* pointing to next or END */ + } + + return rtnl; +} + +uint8_t get_tunnel_vport(struct tunnel_s *rtnl) +{ + return rtnl->vport; +} + +void tunnel_set_flow_stat_id(struct tunnel_s *rtnl, uint32_t flow_stat_id) +{ + rtnl->flow_stat_id = flow_stat_id; +} + +int tunnel_get_definition(struct tunnel_cfg_s *tuncfg, uint32_t flow_stat_id, + uint8_t vport) +{ + struct tunnel_s *tun = tunnels; + + while (tun) { + if (tun->vport == vport && (flow_stat_id == tun->flow_stat_id || + flow_stat_id == (uint32_t)-1)) { + memcpy(tuncfg, &tun->cfg, sizeof(struct tunnel_cfg_s)); + return 0; + } + tun = tun->next; + } + + return -1; +} + +static be16_t ip_checksum_sum(const be16_t *data, unsigned int size, + be16_t seed) +{ + unsigned int sum = seed; + unsigned int idx; + + for (idx = 0; idx < size / 2; idx++) + sum += (unsigned int)(data[idx]); + if (size & 1) + sum += (unsigned char)data[idx]; + /* unfold */ + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + return (be16_t)sum; +} + +static void copy_unmasked(uint8_t *result, const struct flow_elem *elem, + uint8_t size) +{ + for (uint8_t i = 0; i < size; i++) + result[i] = ((const uint8_t *)elem->spec)[i]; +} + +int flow_tunnel_create_vxlan_hdr(struct flow_api_backend_s *be, + struct nic_flow_def *fd, + const struct flow_elem *elem) +{ + uint32_t eidx = 0; + uint8_t size; + struct ipv4_hdr_s *tun_ipv4 = NULL; + uint16_t *tun_hdr_eth_type_p = NULL; + + if (elem) { + while (elem[eidx].type != FLOW_ELEM_TYPE_END) { + switch (elem[eidx].type) { + case FLOW_ELEM_TYPE_ETH: { + NT_LOG(DBG, FILTER, + "Tunnel: RTE_FLOW_ITEM_TYPE_ETH\n"); + struct flow_elem_eth eth; + + size = sizeof(struct flow_elem_eth); + + copy_unmasked((uint8_t *)ð, &elem[eidx], + size); + + memcpy(&fd->tun_hdr.d.hdr8[fd->tun_hdr.len], + ð, size); + + /* + * Save a pointer to the tun header ethtype field + * (needed later in the IPv4 and IPv6 flow elem cases) + */ + tun_hdr_eth_type_p = + (uint16_t *)&fd->tun_hdr.d + .hdr8[fd->tun_hdr.len + 12]; + +#ifdef FLOW_DEBUG + NT_LOG(DBG, FILTER, + "dmac : %02x:%02x:%02x:%02x:%02x:%02x\n", + eth.d_addr.addr_b[0], + eth.d_addr.addr_b[1], + eth.d_addr.addr_b[2], + eth.d_addr.addr_b[3], + eth.d_addr.addr_b[5], + eth.d_addr.addr_b[5]); + NT_LOG(DBG, FILTER, + "smac : %02x:%02x:%02x:%02x:%02x:%02x\n", + eth.s_addr.addr_b[0], + eth.s_addr.addr_b[1], + eth.s_addr.addr_b[2], + eth.s_addr.addr_b[3], + eth.s_addr.addr_b[5], + eth.s_addr.addr_b[5]); + NT_LOG(DBG, FILTER, "type : %04x\n", + ntohs(eth.ether_type)); +#endif + fd->tun_hdr.len = + (uint8_t)(fd->tun_hdr.len + size); + } + break; + /* VLAN is not supported */ + + case FLOW_ELEM_TYPE_IPV4: { + NT_LOG(DBG, FILTER, + "Tunnel: RTE_FLOW_ITEM_TYPE_IPV4\n"); + struct flow_elem_ipv4 ipv4; + + size = sizeof(struct flow_elem_ipv4); + + copy_unmasked((uint8_t *)&ipv4, &elem[eidx], + size); + + if (ipv4.hdr.version_ihl != 0x45) + ipv4.hdr.version_ihl = 0x45; + + if (ipv4.hdr.ttl == 0) + ipv4.hdr.ttl = 64; + + if (ipv4.hdr.next_proto_id != + 17) /* must be UDP */ + ipv4.hdr.next_proto_id = 17; + + ipv4.hdr.frag_offset = + htons(1 << 14); /* DF flag */ + + size = sizeof(struct ipv4_hdr_s); + memcpy(&fd->tun_hdr.d.hdr8[fd->tun_hdr.len], + &ipv4.hdr, size); + + /* Set the tun header ethtype field to IPv4 (if empty) */ + if (tun_hdr_eth_type_p && + (*tun_hdr_eth_type_p == 0)) { + *tun_hdr_eth_type_p = + htons(0x0800); /* IPv4 */ + } + + tun_ipv4 = (struct ipv4_hdr_s *)&fd->tun_hdr.d + .hdr8[fd->tun_hdr.len]; + + NT_LOG(DBG, FILTER, "v_ihl : %02x\n", + tun_ipv4->version_ihl); + NT_LOG(DBG, FILTER, "tos : %02x\n", + tun_ipv4->tos); + NT_LOG(DBG, FILTER, "len : %d\n", + ntohs(tun_ipv4->length)); + NT_LOG(DBG, FILTER, "id : %02x\n", + tun_ipv4->id); + NT_LOG(DBG, FILTER, "fl/frg : %04x\n", + ntohs(tun_ipv4->frag_offset)); + NT_LOG(DBG, FILTER, "ttl : %02x\n", + tun_ipv4->ttl); + NT_LOG(DBG, FILTER, "prot : %02x\n", + tun_ipv4->next_proto_id); + NT_LOG(DBG, FILTER, "chksum : %04x\n", + ntohs(tun_ipv4->hdr_csum)); + NT_LOG(DBG, FILTER, "src : %d.%d.%d.%d\n", + (tun_ipv4->src_ip & 0xff), + ((tun_ipv4->src_ip >> 8) & 0xff), + ((tun_ipv4->src_ip >> 16) & 0xff), + ((tun_ipv4->src_ip >> 24) & 0xff)); + NT_LOG(DBG, FILTER, "dst : %d.%d.%d.%d\n", + (tun_ipv4->dst_ip & 0xff), + ((tun_ipv4->dst_ip >> 8) & 0xff), + ((tun_ipv4->dst_ip >> 16) & 0xff), + ((tun_ipv4->dst_ip >> 24) & 0xff)); + + fd->tun_hdr.len = + (uint8_t)(fd->tun_hdr.len + size); + fd->tun_hdr.ip_version = 4; + } + break; + + case FLOW_ELEM_TYPE_IPV6: { + if (be->roa.ver < 6) { + NT_LOG(ERR, FILTER, + "Tunnel flow element type IPv6 requires ROA version 6 or higher (current version=%d)\n", + be->roa.ver); + return -1; + } + + NT_LOG(DBG, FILTER, + "Tunnel: RTE_FLOW_ITEM_TYPE_IPV6\n"); + struct flow_elem_ipv6 ipv6; + + size = sizeof(struct flow_elem_ipv6); + + copy_unmasked((uint8_t *)&ipv6, &elem[eidx], + size); + + /* + * Make sure the version field (the 4 most significant bits of + * "vtc_flow") is set to 6 + */ + if ((ipv6.hdr.vtc_flow & htonl(0x60000000)) == + 0) { + ipv6.hdr.vtc_flow |= htonl(0x60000000); /* Version = 6 */ + } + + if (ipv6.hdr.proto != 17) /* must be UDP */ + ipv6.hdr.proto = 17; + + if (ipv6.hdr.hop_limits == 0) + ipv6.hdr.hop_limits = 64; + + size = sizeof(struct ipv6_hdr_s); + memcpy(&fd->tun_hdr.d.hdr8[fd->tun_hdr.len], + &ipv6.hdr, size); + + /* Set the tun header ethtype field to IPv6 (if empty) */ + if (tun_hdr_eth_type_p && + (*tun_hdr_eth_type_p == 0)) { + *tun_hdr_eth_type_p = + htons(0x86DD); /* IPv6 */ + } + + NT_LOG(DBG, FILTER, "vtc_flow : %08x\n", + ntohl(ipv6.hdr.vtc_flow)); + NT_LOG(DBG, FILTER, "payload_len : %04x\n", + ntohs(ipv6.hdr.payload_len)); + NT_LOG(DBG, FILTER, "proto : %02x\n", + ipv6.hdr.proto); + NT_LOG(DBG, FILTER, "hop_limits : %02x\n", + ipv6.hdr.hop_limits); + NT_LOG(DBG, FILTER, + "src : %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", + ipv6.hdr.src_addr[0], + ipv6.hdr.src_addr[1], + ipv6.hdr.src_addr[2], + ipv6.hdr.src_addr[3], + ipv6.hdr.src_addr[4], + ipv6.hdr.src_addr[5], + ipv6.hdr.src_addr[6], + ipv6.hdr.src_addr[7], + ipv6.hdr.src_addr[8], + ipv6.hdr.src_addr[9], + ipv6.hdr.src_addr[10], + ipv6.hdr.src_addr[11], + ipv6.hdr.src_addr[12], + ipv6.hdr.src_addr[13], + ipv6.hdr.src_addr[14], + ipv6.hdr.src_addr[15]); + NT_LOG(DBG, FILTER, + "dst : %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", + ipv6.hdr.dst_addr[0], + ipv6.hdr.dst_addr[1], + ipv6.hdr.dst_addr[2], + ipv6.hdr.dst_addr[3], + ipv6.hdr.dst_addr[4], + ipv6.hdr.dst_addr[5], + ipv6.hdr.dst_addr[6], + ipv6.hdr.dst_addr[7], + ipv6.hdr.dst_addr[8], + ipv6.hdr.dst_addr[9], + ipv6.hdr.dst_addr[10], + ipv6.hdr.dst_addr[11], + ipv6.hdr.dst_addr[12], + ipv6.hdr.dst_addr[13], + ipv6.hdr.dst_addr[14], + ipv6.hdr.dst_addr[15]); + + fd->tun_hdr.len = + (uint8_t)(fd->tun_hdr.len + size); + fd->tun_hdr.ip_version = 6; + } + break; + + case FLOW_ELEM_TYPE_UDP: { + NT_LOG(DBG, FILTER, + "Tunnel: RTE_FLOW_ITEM_TYPE_UDP\n"); + struct flow_elem_udp udp; + + size = sizeof(struct flow_elem_udp); + + copy_unmasked((uint8_t *)&udp, &elem[eidx], + size); + + udp.hdr.cksum = + 0; /* set always the UDP checksum to 0 */ + + size = sizeof(struct udp_hdr_s); + memcpy(&fd->tun_hdr.d.hdr8[fd->tun_hdr.len], + &udp.hdr, size); + + NT_LOG(DBG, FILTER, "src p : %d\n", + ntohs(udp.hdr.src_port)); + NT_LOG(DBG, FILTER, "dst p : %d\n", + ntohs(udp.hdr.dst_port)); + NT_LOG(DBG, FILTER, "len : %d\n", + ntohs(udp.hdr.len)); + NT_LOG(DBG, FILTER, "chksum : %04x\n", + ntohs(udp.hdr.cksum)); + + fd->tun_hdr.len = + (uint8_t)(fd->tun_hdr.len + size); + } + break; + + case FLOW_ELEM_TYPE_VXLAN: { + struct flow_elem_vxlan vxlan_m; + + size = sizeof(struct flow_elem_vxlan); + + copy_unmasked((uint8_t *)&vxlan_m, &elem[eidx], + size); + + vxlan_m.flags = + 0x08; /* set always I-flag - valid VNI */ + + NT_LOG(DBG, FILTER, + "Tunnel: RTE_FLOW_ITEM_TYPE_VXLAN - vni %u\n", + (vxlan_m.vni[0] << 16) + + (vxlan_m.vni[1] << 8) + + vxlan_m.vni[2]); + + memcpy(&fd->tun_hdr.d.hdr8[fd->tun_hdr.len], + &vxlan_m, size); + + NT_LOG(DBG, FILTER, "flags : %02x\n", + vxlan_m.flags); + NT_LOG(DBG, FILTER, "vni : %d\n", + (vxlan_m.vni[0] << 16) + + (vxlan_m.vni[1] << 8) + + vxlan_m.vni[2]); + + fd->tun_hdr.len = + (uint8_t)(fd->tun_hdr.len + size); + } + break; + + case FLOW_ELEM_TYPE_PORT_ID: { + const struct flow_elem_port_id *port = + (const struct flow_elem_port_id *) + elem[eidx] + .spec; + fd->tun_hdr.user_port_id = port->id; + } + break; + + case FLOW_ELEM_TYPE_VOID: { + NT_LOG(DBG, FILTER, + "Tunnel: RTE_FLOW_ITEM_TYPE_VOID (ignoring)\n"); + } + break; + + default: + NT_LOG(INF, FILTER, + "unsupported Tunnel flow element type %u\n", + elem[eidx].type); + return -1; + } + + eidx++; + } + } + + if (tun_ipv4) { + tun_ipv4->hdr_csum = 0; + tun_ipv4->length = 0; + fd->tun_hdr.ip_csum_precalc = ntohs(ip_checksum_sum((const be16_t *)&fd->tun_hdr.d + .hdr8[14], + (unsigned int)sizeof(struct ipv4_hdr_s), + (be16_t)htons((uint16_t)(fd->tun_hdr.len - sizeof(struct flow_elem_eth))))); + + NT_LOG(DBG, FILTER, + "chksum precalc: %04x, precalc hdr len %u\n", + fd->tun_hdr.ip_csum_precalc, + fd->tun_hdr.len - sizeof(struct flow_elem_eth)); + } + + return 0; +} diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c new file mode 100644 index 0000000000..5a62343718 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c @@ -0,0 +1,1789 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include +#include "flow_api_backend.h" + +#define _MOD_ "CAT" +#define _VER_ be->cat.ver + +static int hw_mod_cat_kce_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int km_if_id, + int start_idx, int count); +static int hw_mod_cat_kcs_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int km_if_id, + int start_idx, int count); +static int hw_mod_cat_fte_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int km_if_id, + int start_idx, int count); + +bool hw_mod_cat_present(struct flow_api_backend_s *be) +{ + return be->iface->get_cat_present(be->be_dev); +} + +int hw_mod_cat_alloc(struct flow_api_backend_s *be) +{ + _VER_ = be->iface->get_cat_version(be->be_dev); + NT_LOG(DBG, FILTER, "CAT MODULE VERSION %i.%i\n", VER_MAJOR(_VER_), + VER_MINOR(_VER_)); + + int nb = be->iface->get_nb_cat_funcs(be->be_dev); + + if (nb <= 0) + return error_resource_count(__func__, "cat_funcs", _MOD_, _VER_); + be->cat.nb_cat_funcs = (uint32_t)nb; + + nb = be->iface->get_nb_km_flow_types(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "km_flow_types", _MOD_, _VER_); + be->cat.nb_flow_types = (uint32_t)nb; + + nb = be->iface->get_nb_pm_ext(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "pm_ext", _MOD_, _VER_); + be->cat.nb_pm_ext = (uint32_t)nb; + + nb = be->iface->get_nb_len(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "len", _MOD_, _VER_); + be->cat.nb_len = (uint32_t)nb; + + nb = be->iface->get_kcc_size(be->be_dev); + if (nb < 0) + return error_resource_count(__func__, "kcc_size", _MOD_, _VER_); + be->cat.kcc_size = (uint32_t)nb; + + nb = be->iface->get_kcc_banks(be->be_dev); + if (nb < 0) + return error_resource_count(__func__, "kcc_banks", _MOD_, _VER_); + be->cat.kcc_banks = (uint32_t)nb; + + nb = be->iface->get_nb_cat_km_if_cnt(be->be_dev); + if (nb < 0) + return error_resource_count(__func__, "km_if_count", _MOD_, _VER_); + be->cat.km_if_count = (uint32_t)nb; + + int idx = be->iface->get_nb_cat_km_if_m0(be->be_dev); + + be->cat.km_if_m0 = idx; + + idx = be->iface->get_nb_cat_km_if_m1(be->be_dev); + be->cat.km_if_m1 = idx; + + if (be->cat.kcc_banks) + be->cat.kcc_records = be->cat.kcc_size / be->cat.kcc_banks; + else + be->cat.kcc_records = 0; + + be->cat.kcc_id_bit_size = 10; + + switch (_VER_) { + case 18: + be->cat.cts_num = 11; + if (!callocate_mod(CAST_COMMON(&be->cat), 12, + &be->cat.v18.cfn, + be->cat.nb_cat_funcs, + sizeof(struct cat_v18_cfn_s), + &be->cat.v18.kce, + (be->cat.nb_cat_funcs / 8), + sizeof(struct cat_v18_kce_s), + &be->cat.v18.kcs, + be->cat.nb_cat_funcs, + sizeof(struct cat_v18_kcs_s), + &be->cat.v18.fte, + (be->cat.nb_cat_funcs / 8) * be->cat.nb_flow_types * 2, + sizeof(struct cat_v18_fte_s), + &be->cat.v18.cte, + be->cat.nb_cat_funcs, + sizeof(struct cat_v18_cte_s), + &be->cat.v18.cts, + be->cat.nb_cat_funcs * ((be->cat.cts_num + 1) / 2), + sizeof(struct cat_v18_cts_s), + &be->cat.v18.cot, + be->max_categories, + sizeof(struct cat_v18_cot_s), + &be->cat.v18.cct, + be->max_categories * 4, + sizeof(struct cat_v18_cct_s), + &be->cat.v18.exo, + be->cat.nb_pm_ext, + sizeof(struct cat_v18_exo_s), + &be->cat.v18.rck, + be->cat.nb_pm_ext * 64, + sizeof(struct cat_v18_rck_s), + &be->cat.v18.len, + be->cat.nb_len, + sizeof(struct cat_v18_len_s), + &be->cat.v18.kcc_cam, + be->cat.kcc_size, + sizeof(struct cat_v18_kcc_s))) + return -1; + + break; + /* end case 18 */ + case 21: + be->cat.cts_num = 11; + if (!callocate_mod(CAST_COMMON(&be->cat), 12, + &be->cat.v21.cfn, + be->cat.nb_cat_funcs, + sizeof(struct cat_v21_cfn_s), + &be->cat.v21.kce, + (be->cat.nb_cat_funcs / 8), + sizeof(struct cat_v21_kce_s), + &be->cat.v21.kcs, + be->cat.nb_cat_funcs, + sizeof(struct cat_v21_kcs_s), + &be->cat.v21.fte, + (be->cat.nb_cat_funcs / 8) * be->cat.nb_flow_types * 4, + sizeof(struct cat_v21_fte_s), + &be->cat.v21.cte, + be->cat.nb_cat_funcs, + sizeof(struct cat_v18_cte_s), + &be->cat.v21.cts, + be->cat.nb_cat_funcs * ((be->cat.cts_num + 1) / 2), + sizeof(struct cat_v18_cts_s), + &be->cat.v21.cot, + be->max_categories, + sizeof(struct cat_v18_cot_s), + &be->cat.v21.cct, + be->max_categories * 4, + sizeof(struct cat_v18_cct_s), + &be->cat.v21.exo, + be->cat.nb_pm_ext, + sizeof(struct cat_v18_exo_s), + &be->cat.v21.rck, + be->cat.nb_pm_ext * 64, + sizeof(struct cat_v18_rck_s), + &be->cat.v21.len, + be->cat.nb_len, + sizeof(struct cat_v18_len_s), + &be->cat.v21.kcc_cam, + be->cat.kcc_size, + sizeof(struct cat_v18_kcc_s))) + return -1; + + break; + /* end case 21 */ + case 22: + be->cat.cts_num = 12; + if (!callocate_mod(CAST_COMMON(&be->cat), 14, + &be->cat.v22.cfn, + be->cat.nb_cat_funcs, + sizeof(struct cat_v21_cfn_s), + &be->cat.v22.kce, + (be->cat.nb_cat_funcs / 8), + sizeof(struct cat_v21_kce_s), + &be->cat.v22.kcs, + be->cat.nb_cat_funcs, + sizeof(struct cat_v21_kcs_s), + &be->cat.v22.fte, + (be->cat.nb_cat_funcs / 8) * be->cat.nb_flow_types * 4, + sizeof(struct cat_v21_fte_s), + &be->cat.v22.cte, + be->cat.nb_cat_funcs, + sizeof(struct cat_v22_cte_s), + &be->cat.v22.cts, + be->cat.nb_cat_funcs * ((be->cat.cts_num + 1) / 2), + sizeof(struct cat_v18_cts_s), + &be->cat.v22.cot, + be->max_categories, + sizeof(struct cat_v18_cot_s), + &be->cat.v22.cct, + be->max_categories * 4, + sizeof(struct cat_v18_cct_s), + &be->cat.v22.exo, + be->cat.nb_pm_ext, + sizeof(struct cat_v18_exo_s), + &be->cat.v22.rck, + be->cat.nb_pm_ext * 64, + sizeof(struct cat_v18_rck_s), + &be->cat.v22.len, + be->cat.nb_len, + sizeof(struct cat_v18_len_s), + &be->cat.v22.kcc_cam, + be->cat.kcc_size, + sizeof(struct cat_v18_kcc_s), + &be->cat.v22.cce, + 4, + sizeof(struct cat_v22_cce_s), + &be->cat.v22.ccs, + 1024, + sizeof(struct cat_v22_ccs_s))) + return -1; + + break; + /* end case 22 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +void hw_mod_cat_free(struct flow_api_backend_s *be) +{ + if (be->cat.base) { + free(be->cat.base); + be->cat.base = NULL; + } +} + +static int cfn_reset(struct flow_api_backend_s *be, int i) +{ + int err = hw_mod_cat_cfn_set(be, HW_CAT_CFN_PRESET_ALL, i, 0, 0); + + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_ISL, i, 0, + 0xffffffff); /* accept both ISL or not ISL */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_CFP, i, 0, + 0xffffffff); /* accept both CFP or not CFP */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_MAC, i, 0, + 0xffffffff); /* accept all MACs */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_L2, i, 0, + 0xffffffff); /* accept all L2 prot */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_VNTAG, i, 0, + 0xffffffff); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_VLAN, i, 0, + 0xffffffff); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_MPLS, i, 0, + 0xffffffff); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_L3, i, 0, + 0xffffffff); /* accept all L3 prot */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_FRAG, i, 0, + 0xffffffff); /* accept all fragments */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_IP_PROT, i, 0, + 0xffffffff); /* IP prot check disabled */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_L4, i, 0, + 0xffffffff); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TUNNEL, i, 0, + 0xffffffff); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_L2, i, 0, + 0xffffffff); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_VLAN, i, 0, + 0xffffffff); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_MPLS, i, 0, + 0xffffffff); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_L3, i, 0, + 0xffffffff); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_FRAG, i, 0, + 0xffffffff); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_IP_PROT, i, 0, + 0xffffffff); /* inner IP prot check disabled */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_L4, i, 0, + 0xffffffff); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_CV, i, 0, 3); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_FCS, i, 0, 3); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TRUNC, i, 0, + 0xffffffff); /* accept all truncations */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_L3_CS, i, 0, 3); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_L4_CS, i, 0, 3); /* accept all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_PM_OR_INV, i, 0, 1); /* */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_LC_INV, i, 0, 1); /* */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_KM0_OR, i, 0, + 0xffffffff); /* or all */ + if (_VER_ >= 21) { + hw_mod_cat_cfn_set(be, HW_CAT_CFN_KM1_OR, i, 0, + 0xffffffff); /* or all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TNL_L3_CS, i, 0, + 0xffffffff); /* or all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TNL_L4_CS, i, 0, + 0xffffffff); /* or all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TTL_EXP, i, 0, + 0xffffffff); /* or all */ + hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TNL_TTL_EXP, i, 0, + 0xffffffff); /* or all */ + } + return err; +} + +int hw_mod_cat_reset(struct flow_api_backend_s *be) +{ + /* Zero entire cache area */ + ZERO_MOD_CACHE(&be->cat); + + NT_LOG(DBG, FILTER, "INIT CAT CFN\n"); + if (hw_mod_cat_cfn_flush(be, 0, ALL_ENTRIES)) + return -1; + + if (_VER_ <= 18) { + NT_LOG(DBG, FILTER, "INIT CAT KCE\n"); + if (hw_mod_cat_kce_flush(be, KM_FLM_IF_FIRST, 0, 0, + ALL_ENTRIES)) + return -1; + + NT_LOG(DBG, FILTER, "INIT CAT KCS\n"); + if (hw_mod_cat_kcs_flush(be, KM_FLM_IF_FIRST, 0, 0, + ALL_ENTRIES)) + return -1; + + NT_LOG(DBG, FILTER, "INIT CAT FTE\n"); + if (hw_mod_cat_fte_flush(be, KM_FLM_IF_FIRST, 0, 0, + ALL_ENTRIES)) + return -1; + } else { + NT_LOG(DBG, FILTER, "INIT CAT KCE 0\n"); + if (hw_mod_cat_kce_flush(be, KM_FLM_IF_FIRST, be->cat.km_if_m0, + 0, ALL_ENTRIES)) + return -1; + + NT_LOG(DBG, FILTER, "INIT CAT KCS 0\n"); + if (hw_mod_cat_kcs_flush(be, KM_FLM_IF_FIRST, be->cat.km_if_m0, + 0, ALL_ENTRIES)) + return -1; + + NT_LOG(DBG, FILTER, "INIT CAT FTE 0\n"); + if (hw_mod_cat_fte_flush(be, KM_FLM_IF_FIRST, be->cat.km_if_m0, + 0, ALL_ENTRIES)) + return -1; + + if (be->cat.km_if_count > 1) { + NT_LOG(DBG, FILTER, "INIT CAT KCE 1\n"); + if (hw_mod_cat_kce_flush(be, KM_FLM_IF_SECOND, + be->cat.km_if_m1, 0, + ALL_ENTRIES)) + return -1; + + NT_LOG(DBG, FILTER, "INIT CAT KCS 1\n"); + if (hw_mod_cat_kcs_flush(be, KM_FLM_IF_SECOND, + be->cat.km_if_m1, 0, + ALL_ENTRIES)) + return -1; + + NT_LOG(DBG, FILTER, "INIT CAT FTE 1\n"); + if (hw_mod_cat_fte_flush(be, KM_FLM_IF_SECOND, + be->cat.km_if_m1, 0, + ALL_ENTRIES)) + return -1; + } + } + + NT_LOG(DBG, FILTER, "INIT CAT CTE\n"); + if (hw_mod_cat_cte_flush(be, 0, ALL_ENTRIES)) + return -1; + + NT_LOG(DBG, FILTER, "INIT CAT CTS\n"); + if (hw_mod_cat_cts_flush(be, 0, ALL_ENTRIES)) + return -1; + + NT_LOG(DBG, FILTER, "INIT CAT COT\n"); + if (hw_mod_cat_cot_flush(be, 0, ALL_ENTRIES)) + return -1; + + NT_LOG(DBG, FILTER, "INIT CAT CCT\n"); + if (hw_mod_cat_cct_flush(be, 0, ALL_ENTRIES)) + return -1; + + NT_LOG(DBG, FILTER, "INIT CAT EXO\n"); + if (hw_mod_cat_exo_flush(be, 0, ALL_ENTRIES)) + return -1; + + NT_LOG(DBG, FILTER, "INIT CAT RCK\n"); + if (hw_mod_cat_rck_flush(be, 0, ALL_ENTRIES)) + return -1; + + NT_LOG(DBG, FILTER, "INIT CAT LEN\n"); + if (hw_mod_cat_len_flush(be, 0, ALL_ENTRIES)) + return -1; + + if (be->cat.kcc_size) { + NT_LOG(DBG, FILTER, "INIT CAT KCC\n"); + if (hw_mod_cat_kcc_flush(be, 0, ALL_ENTRIES)) + return -1; + } + + if (_VER_ > 21) { + NT_LOG(DBG, FILTER, "INIT CAT CCE\n"); + if (hw_mod_cat_cce_flush(be, 0, ALL_ENTRIES)) + return -1; + NT_LOG(DBG, FILTER, "INIT CAT CCS\n"); + if (hw_mod_cat_ccs_flush(be, 0, ALL_ENTRIES)) + return -1; + } + + return 0; +} + +int hw_mod_cat_cfn_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + switch (count) { + case ALL_ENTRIES: + if (start_idx != 0) + return error_index_too_large(__func__); + return be->iface->cat_cfn_flush(be->be_dev, &be->cat, start_idx, + be->cat.nb_cat_funcs); + + default: + if ((unsigned int)(start_idx + count) > be->cat.nb_cat_funcs) + return error_index_too_large(__func__); + return be->iface->cat_cfn_flush(be->be_dev, &be->cat, start_idx, + count); + } +} + +static int hw_mod_cat_cfn_mod(struct flow_api_backend_s *be, + enum hw_cat_e field, int index, int word_off, + uint32_t *value, int get) +{ + int rv = 0; + if ((unsigned int)index >= be->cat.nb_cat_funcs) + return error_index_too_large(__func__); + switch (_VER_) { + case 18: + switch (field) { + case HW_CAT_CFN_SET_ALL_DEFAULTS: + if (get) + return error_unsup_field(__func__); + return cfn_reset(be, index); + case HW_CAT_CFN_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->cat.v18.cfn[index], (uint8_t)*value, + sizeof(struct cat_v18_cfn_s)); + break; + case HW_CAT_CFN_COMPARE: + rv = do_compare_indexes(be->cat.v18.cfn, + sizeof(struct cat_v18_cfn_s), index, word_off, + be->cat.nb_cat_funcs, get, __func__); + if (rv != 0) + return rv; + break; + case HW_CAT_CFN_FIND: + rv = find_equal_index(be->cat.v18.cfn, + sizeof(struct cat_v18_cfn_s), index, word_off, + be->cat.nb_cat_funcs, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_CAT_CFN_ENABLE: + get_set(&be->cat.v18.cfn[index].enable, value, get); + break; + case HW_CAT_CFN_INV: + get_set(&be->cat.v18.cfn[index].inv, value, get); + break; + case HW_CAT_CFN_PTC_INV: + get_set(&be->cat.v18.cfn[index].ptc_inv, value, get); + break; + case HW_CAT_CFN_PTC_ISL: + get_set(&be->cat.v18.cfn[index].ptc_isl, value, get); + break; + case HW_CAT_CFN_PTC_CFP: + get_set(&be->cat.v18.cfn[index].ptc_cfp, value, get); + break; + case HW_CAT_CFN_PTC_MAC: + get_set(&be->cat.v18.cfn[index].ptc_mac, value, get); + break; + case HW_CAT_CFN_PTC_L2: + get_set(&be->cat.v18.cfn[index].ptc_l2, value, get); + break; + case HW_CAT_CFN_PTC_VNTAG: + get_set(&be->cat.v18.cfn[index].ptc_vntag, value, get); + break; + case HW_CAT_CFN_PTC_VLAN: + get_set(&be->cat.v18.cfn[index].ptc_vlan, value, get); + break; + case HW_CAT_CFN_PTC_MPLS: + get_set(&be->cat.v18.cfn[index].ptc_mpls, value, get); + break; + case HW_CAT_CFN_PTC_L3: + get_set(&be->cat.v18.cfn[index].ptc_l3, value, get); + break; + case HW_CAT_CFN_PTC_FRAG: + get_set(&be->cat.v18.cfn[index].ptc_frag, value, get); + break; + case HW_CAT_CFN_PTC_IP_PROT: + get_set(&be->cat.v18.cfn[index].ptc_ip_prot, value, get); + break; + case HW_CAT_CFN_PTC_L4: + get_set(&be->cat.v18.cfn[index].ptc_l4, value, get); + break; + case HW_CAT_CFN_PTC_TUNNEL: + get_set(&be->cat.v18.cfn[index].ptc_tunnel, value, get); + break; + case HW_CAT_CFN_PTC_TNL_L2: + get_set(&be->cat.v18.cfn[index].ptc_tnl_l2, value, get); + break; + case HW_CAT_CFN_PTC_TNL_VLAN: + get_set(&be->cat.v18.cfn[index].ptc_tnl_vlan, value, get); + break; + case HW_CAT_CFN_PTC_TNL_MPLS: + get_set(&be->cat.v18.cfn[index].ptc_tnl_mpls, value, get); + break; + case HW_CAT_CFN_PTC_TNL_L3: + get_set(&be->cat.v18.cfn[index].ptc_tnl_l3, value, get); + break; + case HW_CAT_CFN_PTC_TNL_FRAG: + get_set(&be->cat.v18.cfn[index].ptc_tnl_frag, value, get); + break; + case HW_CAT_CFN_PTC_TNL_IP_PROT: + get_set(&be->cat.v18.cfn[index].ptc_tnl_ip_prot, value, get); + break; + case HW_CAT_CFN_PTC_TNL_L4: + get_set(&be->cat.v18.cfn[index].ptc_tnl_l4, value, get); + break; + case HW_CAT_CFN_ERR_INV: + get_set(&be->cat.v18.cfn[index].err_inv, value, get); + break; + case HW_CAT_CFN_ERR_CV: + get_set(&be->cat.v18.cfn[index].err_cv, value, get); + break; + case HW_CAT_CFN_ERR_FCS: + get_set(&be->cat.v18.cfn[index].err_fcs, value, get); + break; + case HW_CAT_CFN_ERR_TRUNC: + get_set(&be->cat.v18.cfn[index].err_trunc, value, get); + break; + case HW_CAT_CFN_ERR_L3_CS: + get_set(&be->cat.v18.cfn[index].err_l3_cs, value, get); + break; + case HW_CAT_CFN_ERR_L4_CS: + get_set(&be->cat.v18.cfn[index].err_l4_cs, value, get); + break; + case HW_CAT_CFN_MAC_PORT: + get_set(&be->cat.v18.cfn[index].mac_port, value, get); + break; + case HW_CAT_CFN_PM_CMP: + if (word_off > 1) + return error_word_off_too_large(__func__); + get_set(&be->cat.v18.cfn[index].pm_cmp[word_off], value, get); + break; + case HW_CAT_CFN_PM_DCT: + get_set(&be->cat.v18.cfn[index].pm_dct, value, get); + break; + case HW_CAT_CFN_PM_EXT_INV: + get_set(&be->cat.v18.cfn[index].pm_ext_inv, value, get); + break; + case HW_CAT_CFN_PM_CMB: + get_set(&be->cat.v18.cfn[index].pm_cmb, value, get); + break; + case HW_CAT_CFN_PM_AND_INV: + get_set(&be->cat.v18.cfn[index].pm_and_inv, value, get); + break; + case HW_CAT_CFN_PM_OR_INV: + get_set(&be->cat.v18.cfn[index].pm_or_inv, value, get); + break; + case HW_CAT_CFN_PM_INV: + get_set(&be->cat.v18.cfn[index].pm_inv, value, get); + break; + case HW_CAT_CFN_LC: + get_set(&be->cat.v18.cfn[index].lc, value, get); + break; + case HW_CAT_CFN_LC_INV: + get_set(&be->cat.v18.cfn[index].lc_inv, value, get); + break; + case HW_CAT_CFN_KM0_OR: + get_set(&be->cat.v18.cfn[index].km_or, value, get); + break; + default: + return error_unsup_field(__func__); + } + break; + /* end case 18 */ + case 21: + case 22: + switch (field) { + case HW_CAT_CFN_SET_ALL_DEFAULTS: + if (get) + return error_unsup_field(__func__); + return cfn_reset(be, index); + case HW_CAT_CFN_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->cat.v21.cfn[index], (uint8_t)*value, + sizeof(struct cat_v21_cfn_s)); + break; + case HW_CAT_CFN_COMPARE: + rv = do_compare_indexes(be->cat.v21.cfn, + sizeof(struct cat_v21_cfn_s), index, word_off, + be->cat.nb_cat_funcs, get, __func__); + if (rv != 0) + return rv; + break; + case HW_CAT_CFN_FIND: + rv = find_equal_index(be->cat.v21.cfn, + sizeof(struct cat_v21_cfn_s), index, word_off, + be->cat.nb_cat_funcs, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_CAT_CFN_COPY_FROM: + if (get) + return error_unsup_field(__func__); + memcpy(&be->cat.v21.cfn[index], + &be->cat.v21.cfn[*value], + sizeof(struct cat_v21_cfn_s)); + break; + case HW_CAT_CFN_ENABLE: + get_set(&be->cat.v21.cfn[index].enable, value, get); + break; + case HW_CAT_CFN_INV: + get_set(&be->cat.v21.cfn[index].inv, value, get); + break; + case HW_CAT_CFN_PTC_INV: + get_set(&be->cat.v21.cfn[index].ptc_inv, value, get); + break; + case HW_CAT_CFN_PTC_ISL: + get_set(&be->cat.v21.cfn[index].ptc_isl, value, get); + break; + case HW_CAT_CFN_PTC_CFP: + get_set(&be->cat.v21.cfn[index].ptc_cfp, value, get); + break; + case HW_CAT_CFN_PTC_MAC: + get_set(&be->cat.v21.cfn[index].ptc_mac, value, get); + break; + case HW_CAT_CFN_PTC_L2: + get_set(&be->cat.v21.cfn[index].ptc_l2, value, get); + break; + case HW_CAT_CFN_PTC_VNTAG: + get_set(&be->cat.v21.cfn[index].ptc_vntag, value, get); + break; + case HW_CAT_CFN_PTC_VLAN: + get_set(&be->cat.v21.cfn[index].ptc_vlan, value, get); + break; + case HW_CAT_CFN_PTC_MPLS: + get_set(&be->cat.v21.cfn[index].ptc_mpls, value, get); + break; + case HW_CAT_CFN_PTC_L3: + get_set(&be->cat.v21.cfn[index].ptc_l3, value, get); + break; + case HW_CAT_CFN_PTC_FRAG: + get_set(&be->cat.v21.cfn[index].ptc_frag, value, get); + break; + case HW_CAT_CFN_PTC_IP_PROT: + get_set(&be->cat.v21.cfn[index].ptc_ip_prot, value, get); + break; + case HW_CAT_CFN_PTC_L4: + get_set(&be->cat.v21.cfn[index].ptc_l4, value, get); + break; + case HW_CAT_CFN_PTC_TUNNEL: + get_set(&be->cat.v21.cfn[index].ptc_tunnel, value, get); + break; + case HW_CAT_CFN_PTC_TNL_L2: + get_set(&be->cat.v21.cfn[index].ptc_tnl_l2, value, get); + break; + case HW_CAT_CFN_PTC_TNL_VLAN: + get_set(&be->cat.v21.cfn[index].ptc_tnl_vlan, value, get); + break; + case HW_CAT_CFN_PTC_TNL_MPLS: + get_set(&be->cat.v21.cfn[index].ptc_tnl_mpls, value, get); + break; + case HW_CAT_CFN_PTC_TNL_L3: + get_set(&be->cat.v21.cfn[index].ptc_tnl_l3, value, get); + break; + case HW_CAT_CFN_PTC_TNL_FRAG: + get_set(&be->cat.v21.cfn[index].ptc_tnl_frag, value, get); + break; + case HW_CAT_CFN_PTC_TNL_IP_PROT: + get_set(&be->cat.v21.cfn[index].ptc_tnl_ip_prot, value, get); + break; + case HW_CAT_CFN_PTC_TNL_L4: + get_set(&be->cat.v21.cfn[index].ptc_tnl_l4, value, get); + break; + case HW_CAT_CFN_ERR_INV: + get_set(&be->cat.v21.cfn[index].err_inv, value, get); + break; + case HW_CAT_CFN_ERR_CV: + get_set(&be->cat.v21.cfn[index].err_cv, value, get); + break; + case HW_CAT_CFN_ERR_FCS: + get_set(&be->cat.v21.cfn[index].err_fcs, value, get); + break; + case HW_CAT_CFN_ERR_TRUNC: + get_set(&be->cat.v21.cfn[index].err_trunc, value, get); + break; + case HW_CAT_CFN_ERR_L3_CS: + get_set(&be->cat.v21.cfn[index].err_l3_cs, value, get); + break; + case HW_CAT_CFN_ERR_L4_CS: + get_set(&be->cat.v21.cfn[index].err_l4_cs, value, get); + break; + case HW_CAT_CFN_ERR_TNL_L3_CS: + get_set(&be->cat.v21.cfn[index].err_tnl_l3_cs, value, get); + break; + case HW_CAT_CFN_ERR_TNL_L4_CS: + get_set(&be->cat.v21.cfn[index].err_tnl_l4_cs, value, get); + break; + case HW_CAT_CFN_ERR_TTL_EXP: + get_set(&be->cat.v21.cfn[index].err_ttl_exp, value, get); + break; + case HW_CAT_CFN_ERR_TNL_TTL_EXP: + get_set(&be->cat.v21.cfn[index].err_tnl_ttl_exp, value, get); + break; + case HW_CAT_CFN_MAC_PORT: + get_set(&be->cat.v21.cfn[index].mac_port, value, get); + break; + case HW_CAT_CFN_PM_CMP: + if (word_off > 1) + return error_word_off_too_large(__func__); + get_set(&be->cat.v21.cfn[index].pm_cmp[word_off], value, get); + break; + case HW_CAT_CFN_PM_DCT: + get_set(&be->cat.v21.cfn[index].pm_dct, value, get); + break; + case HW_CAT_CFN_PM_EXT_INV: + get_set(&be->cat.v21.cfn[index].pm_ext_inv, value, get); + break; + case HW_CAT_CFN_PM_CMB: + get_set(&be->cat.v21.cfn[index].pm_cmb, value, get); + break; + case HW_CAT_CFN_PM_AND_INV: + get_set(&be->cat.v21.cfn[index].pm_and_inv, value, get); + break; + case HW_CAT_CFN_PM_OR_INV: + get_set(&be->cat.v21.cfn[index].pm_or_inv, value, get); + break; + case HW_CAT_CFN_PM_INV: + get_set(&be->cat.v21.cfn[index].pm_inv, value, get); + break; + case HW_CAT_CFN_LC: + get_set(&be->cat.v21.cfn[index].lc, value, get); + break; + case HW_CAT_CFN_LC_INV: + get_set(&be->cat.v21.cfn[index].lc_inv, value, get); + break; + case HW_CAT_CFN_KM0_OR: + get_set(&be->cat.v21.cfn[index].km0_or, value, get); + break; + case HW_CAT_CFN_KM1_OR: + get_set(&be->cat.v21.cfn[index].km1_or, value, get); + break; + default: + return error_unsup_field(__func__); + } + break; + /* end case 21/22 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + return 0; +} + +int hw_mod_cat_cfn_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, int word_off, uint32_t value) +{ + return hw_mod_cat_cfn_mod(be, field, index, word_off, &value, 0); +} + +int hw_mod_cat_cfn_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, int word_off, uint32_t *value) +{ + return hw_mod_cat_cfn_mod(be, field, index, word_off, value, 1); +} + +static inline int +find_km_flm_module_interface_index(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int km_if_id) +{ + int km_if_idx; + + if (_VER_ == 18) { + km_if_idx = 0; + } else { + if (if_num == KM_FLM_IF_SECOND) { + if (be->cat.km_if_m1 == km_if_id) + km_if_idx = 1; + else + return error_unsup_field(__func__); + } else { + if (be->cat.km_if_m0 == km_if_id) + km_if_idx = 0; + else if (be->cat.km_if_m1 == km_if_id) + km_if_idx = 1; + else + return error_unsup_field(__func__); + } + } + return km_if_idx; +} + +/* + * KCE + */ + +static int hw_mod_cat_kce_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int km_if_id, + int start_idx, int count) +{ + /* writes 8 bits - one for each cfn - at a time */ + if (count == ALL_ENTRIES) + count = be->cat.nb_cat_funcs / 8; + if ((unsigned int)(start_idx + count) > (be->cat.nb_cat_funcs / 8)) + return error_index_too_large(__func__); + /* find KM module */ + int km_if_idx; + + km_if_idx = find_km_flm_module_interface_index(be, if_num, km_if_id); + if (km_if_idx < 0) + return km_if_idx; + + return be->iface->cat_kce_flush(be->be_dev, &be->cat, km_if_idx, + start_idx, count); +} + +int hw_mod_cat_kce_km_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int start_idx, + int count) +{ + return hw_mod_cat_kce_flush(be, if_num, 0, start_idx, count); +} + +int hw_mod_cat_kce_flm_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int start_idx, + int count) +{ + return hw_mod_cat_kce_flush(be, if_num, 1, start_idx, count); +} + +static int hw_mod_cat_kce_mod(struct flow_api_backend_s *be, + enum hw_cat_e field, + enum km_flm_if_select_e if_num, int km_if_id, + int index, uint32_t *value, int get) +{ + if ((unsigned int)index >= (be->cat.nb_cat_funcs / 8)) + return error_index_too_large(__func__); + + /* find KM module */ + int km_if_idx; + + km_if_idx = find_km_flm_module_interface_index(be, if_num, km_if_id); + if (km_if_idx < 0) + return km_if_idx; + + switch (_VER_) { + case 18: + switch (field) { + case HW_CAT_KCE_ENABLE_BM: + get_set(&be->cat.v18.kce[index].enable_bm, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 18 */ + case 21: + case 22: + switch (field) { + case HW_CAT_KCE_ENABLE_BM: + get_set(&be->cat.v21.kce[index].enable_bm[km_if_idx], + value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 21/22 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_cat_kce_km_set(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t value) +{ + return hw_mod_cat_kce_mod(be, field, if_num, 0, index, &value, 0); +} + +int hw_mod_cat_kce_km_get(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t *value) +{ + return hw_mod_cat_kce_mod(be, field, if_num, 0, index, value, 1); +} + +int hw_mod_cat_kce_flm_set(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t value) +{ + return hw_mod_cat_kce_mod(be, field, if_num, 1, index, &value, 0); +} + +int hw_mod_cat_kce_flm_get(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t *value) +{ + return hw_mod_cat_kce_mod(be, field, if_num, 1, index, value, 1); +} + +/* + * KCS + */ +static int hw_mod_cat_kcs_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int km_if_id, + int start_idx, int count) +{ + if (count == ALL_ENTRIES) + count = be->cat.nb_cat_funcs; + if ((unsigned int)(start_idx + count) > be->cat.nb_cat_funcs) + return error_index_too_large(__func__); + + /* find KM module */ + int km_if_idx; + + km_if_idx = find_km_flm_module_interface_index(be, if_num, km_if_id); + if (km_if_idx < 0) + return km_if_idx; + + return be->iface->cat_kcs_flush(be->be_dev, &be->cat, km_if_idx, + start_idx, count); +} + +int hw_mod_cat_kcs_km_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int start_idx, + int count) +{ + return hw_mod_cat_kcs_flush(be, if_num, 0, start_idx, count); +} + +int hw_mod_cat_kcs_flm_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int start_idx, + int count) +{ + return hw_mod_cat_kcs_flush(be, if_num, 1, start_idx, count); +} + +static int hw_mod_cat_kcs_mod(struct flow_api_backend_s *be, + enum hw_cat_e field, + enum km_flm_if_select_e if_num, int km_if_id, + int index, uint32_t *value, int get) +{ + if ((unsigned int)index >= be->cat.nb_cat_funcs) + return error_index_too_large(__func__); + /* find KM module */ + int km_if_idx; + + km_if_idx = find_km_flm_module_interface_index(be, if_num, km_if_id); + if (km_if_idx < 0) + return km_if_idx; + + switch (_VER_) { + case 18: + switch (field) { + case HW_CAT_KCS_CATEGORY: + get_set(&be->cat.v18.kcs[index].category, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 18 */ + case 21: + case 22: + switch (field) { + case HW_CAT_KCS_CATEGORY: + get_set(&be->cat.v21.kcs[index].category[km_if_idx], + value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 21/22 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_cat_kcs_km_set(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t value) +{ + return hw_mod_cat_kcs_mod(be, field, if_num, 0, index, &value, 0); +} + +int hw_mod_cat_kcs_km_get(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t *value) +{ + return hw_mod_cat_kcs_mod(be, field, if_num, 0, index, value, 1); +} + +int hw_mod_cat_kcs_flm_set(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t value) +{ + return hw_mod_cat_kcs_mod(be, field, if_num, 1, index, &value, 0); +} + +int hw_mod_cat_kcs_flm_get(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t *value) +{ + return hw_mod_cat_kcs_mod(be, field, if_num, 1, index, value, 1); +} + +/* + * FTE + */ +static int hw_mod_cat_fte_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int km_if_id, + int start_idx, int count) +{ + const uint32_t key_cnt = (_VER_ >= 20) ? 4 : 2; + + if (count == ALL_ENTRIES) + count = be->cat.nb_cat_funcs / 8 * be->cat.nb_flow_types * + key_cnt; + if ((unsigned int)(start_idx + count) > + (be->cat.nb_cat_funcs / 8 * be->cat.nb_flow_types * key_cnt)) + return error_index_too_large(__func__); + + /* find KM module */ + int km_if_idx; + + km_if_idx = find_km_flm_module_interface_index(be, if_num, km_if_id); + if (km_if_idx < 0) + return km_if_idx; + + return be->iface->cat_fte_flush(be->be_dev, &be->cat, km_if_idx, + start_idx, count); +} + +int hw_mod_cat_fte_km_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int start_idx, + int count) +{ + return hw_mod_cat_fte_flush(be, if_num, 0, start_idx, count); +} + +int hw_mod_cat_fte_flm_flush(struct flow_api_backend_s *be, + enum km_flm_if_select_e if_num, int start_idx, + int count) +{ + return hw_mod_cat_fte_flush(be, if_num, 1, start_idx, count); +} + +static int hw_mod_cat_fte_mod(struct flow_api_backend_s *be, + enum hw_cat_e field, + enum km_flm_if_select_e if_num, int km_if_id, + int index, uint32_t *value, int get) +{ + const uint32_t key_cnt = (_VER_ >= 20) ? 4 : 2; + + if ((unsigned int)index >= + (be->cat.nb_cat_funcs / 8 * be->cat.nb_flow_types * key_cnt)) + return error_index_too_large(__func__); + /* find KM module */ + int km_if_idx; + + km_if_idx = find_km_flm_module_interface_index(be, if_num, km_if_id); + if (km_if_idx < 0) + return km_if_idx; + + switch (_VER_) { + case 18: + switch (field) { + case HW_CAT_FTE_ENABLE_BM: + get_set(&be->cat.v18.fte[index].enable_bm, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 18 */ + case 21: + case 22: + switch (field) { + case HW_CAT_FTE_ENABLE_BM: + get_set(&be->cat.v21.fte[index].enable_bm[km_if_idx], + value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 21/22 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_cat_fte_km_set(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t value) +{ + return hw_mod_cat_fte_mod(be, field, if_num, 0, index, &value, 0); +} + +int hw_mod_cat_fte_km_get(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t *value) +{ + return hw_mod_cat_fte_mod(be, field, if_num, 0, index, value, 1); +} + +int hw_mod_cat_fte_flm_set(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t value) +{ + return hw_mod_cat_fte_mod(be, field, if_num, 1, index, &value, 0); +} + +int hw_mod_cat_fte_flm_get(struct flow_api_backend_s *be, enum hw_cat_e field, + enum km_flm_if_select_e if_num, int index, + uint32_t *value) +{ + return hw_mod_cat_fte_mod(be, field, if_num, 1, index, value, 1); +} + +int hw_mod_cat_cte_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->cat.nb_cat_funcs; + if ((unsigned int)(start_idx + count) > be->cat.nb_cat_funcs) + return error_index_too_large(__func__); + return be->iface->cat_cte_flush(be->be_dev, &be->cat, start_idx, count); +} + +static int hw_mod_cat_cte_mod(struct flow_api_backend_s *be, + enum hw_cat_e field, int index, uint32_t *value, + int get) +{ + if ((unsigned int)index >= be->cat.nb_cat_funcs) + return error_index_too_large(__func__); + switch (_VER_) { + case 18: + case 21: + case 22: + switch (field) { + case HW_CAT_CTE_ENABLE_BM: + get_set(&be->cat.v18.cte[index].enable_bm, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 18/21/22 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_cat_cte_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value) +{ + return hw_mod_cat_cte_mod(be, field, index, &value, 0); +} + +int hw_mod_cat_cte_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value) +{ + return hw_mod_cat_cte_mod(be, field, index, value, 1); +} + +int hw_mod_cat_cts_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + int addr_size = (_VER_ < 15) ? 8 : ((be->cat.cts_num + 1) / 2); + + if (count == ALL_ENTRIES) + count = be->cat.nb_cat_funcs * addr_size; + if ((unsigned int)(start_idx + count) > + (be->cat.nb_cat_funcs * addr_size)) + return error_index_too_large(__func__); + return be->iface->cat_cts_flush(be->be_dev, &be->cat, start_idx, count); +} + +static int hw_mod_cat_cts_mod(struct flow_api_backend_s *be, + enum hw_cat_e field, int index, uint32_t *value, + int get) +{ + int addr_size = (be->cat.cts_num + 1) / 2; + + if ((unsigned int)index >= (be->cat.nb_cat_funcs * addr_size)) + return error_index_too_large(__func__); + + switch (_VER_) { + case 18: + case 21: + case 22: + switch (field) { + case HW_CAT_CTS_CAT_A: + get_set(&be->cat.v18.cts[index].cat_a, value, get); + break; + case HW_CAT_CTS_CAT_B: + get_set(&be->cat.v18.cts[index].cat_b, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 18/21/22 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_cat_cts_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value) +{ + return hw_mod_cat_cts_mod(be, field, index, &value, 0); +} + +int hw_mod_cat_cts_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value) +{ + return hw_mod_cat_cts_mod(be, field, index, value, 1); +} + +int hw_mod_cat_cot_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->max_categories; + if ((unsigned int)(start_idx + count) > be->max_categories) + return error_index_too_large(__func__); + return be->iface->cat_cot_flush(be->be_dev, &be->cat, start_idx, count); +} + +static int hw_mod_cat_cot_mod(struct flow_api_backend_s *be, + enum hw_cat_e field, int index, uint32_t *value, + int get) +{ + int rv = 0; + if ((unsigned int)index >= be->max_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 18: + case 21: + case 22: + switch (field) { + case HW_CAT_COT_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->cat.v18.cot[index], (uint8_t)*value, + sizeof(struct cat_v18_cot_s)); + break; + case HW_CAT_COT_COMPARE: + rv = do_compare_indexes(be->cat.v18.cot, + sizeof(struct cat_v18_cot_s), index, *value, + be->max_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_CAT_COT_FIND: + rv = find_equal_index(be->cat.v18.cot, + sizeof(struct cat_v18_cot_s), index, *value, + be->max_categories, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_CAT_COT_COLOR: + get_set(&be->cat.v18.cot[index].color, value, get); + break; + case HW_CAT_COT_KM: + get_set(&be->cat.v18.cot[index].km, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 18/21/22 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_cat_cot_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value) +{ + return hw_mod_cat_cot_mod(be, field, index, &value, 0); +} + +int hw_mod_cat_cot_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value) +{ + return hw_mod_cat_cot_mod(be, field, index, value, 1); +} + +int hw_mod_cat_cct_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->cat.nb_cat_funcs * 4; + if ((unsigned int)(start_idx + count) > be->cat.nb_cat_funcs * 4) + return error_index_too_large(__func__); + return be->iface->cat_cct_flush(be->be_dev, &be->cat, start_idx, count); +} + +static int hw_mod_cat_cct_mod(struct flow_api_backend_s *be, + enum hw_cat_e field, int index, uint32_t *value, + int get) +{ + if ((unsigned int)index >= be->cat.nb_cat_funcs * 4) + return error_index_too_large(__func__); + switch (_VER_) { + case 18: + case 21: + case 22: + switch (field) { + case HW_CAT_CCT_COLOR: + get_set(&be->cat.v18.cct[index].color, value, get); + break; + case HW_CAT_CCT_KM: + get_set(&be->cat.v18.cct[index].km, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 18/21/22 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_cat_cct_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value) +{ + return hw_mod_cat_cct_mod(be, field, index, &value, 0); +} + +int hw_mod_cat_cct_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value) +{ + return hw_mod_cat_cct_mod(be, field, index, value, 1); +} + +int hw_mod_cat_kcc_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->cat.kcc_size; + if ((unsigned int)(start_idx + count) > be->cat.kcc_size) + return error_index_too_large(__func__); + return be->iface->cat_kcc_flush(be->be_dev, &be->cat, start_idx, count); +} + +static int hw_mod_cat_kcc_mod(struct flow_api_backend_s *be, + enum hw_cat_e field, int index, int word_off, + uint32_t *value, int get) +{ + if ((unsigned int)index >= be->cat.kcc_size) + return error_index_too_large(__func__); + switch (_VER_) { + case 18: + case 21: + case 22: + switch (field) { + case HW_CAT_KCC_KEY: + if (word_off > 1) + return error_word_off_too_large(__func__); + get_set(&be->cat.v18.kcc_cam[index].key[word_off], value, + get); + break; + + case HW_CAT_KCC_CATEGORY: + get_set(&be->cat.v18.kcc_cam[index].category, value, get); + break; + + case HW_CAT_KCC_ID: + get_set(&be->cat.v18.kcc_cam[index].id, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 18/21/22 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_cat_kcc_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, int word_off, uint32_t value) +{ + return hw_mod_cat_kcc_mod(be, field, index, word_off, &value, 0); +} + +int hw_mod_cat_kcc_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, int word_off, uint32_t *value) +{ + return hw_mod_cat_kcc_mod(be, field, index, word_off, value, 1); +} + +int hw_mod_cat_exo_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->cat.nb_pm_ext; + if ((unsigned int)(start_idx + count) > be->cat.nb_pm_ext) + return error_index_too_large(__func__); + return be->iface->cat_exo_flush(be->be_dev, &be->cat, start_idx, count); +} + +static int hw_mod_cat_exo_mod(struct flow_api_backend_s *be, + enum hw_cat_e field, int index, uint32_t *value, + int get) +{ + if ((unsigned int)index >= be->cat.nb_pm_ext) + return error_index_too_large(__func__); + switch (_VER_) { + case 18: + case 21: + case 22: + switch (field) { + case HW_CAT_EXO_DYN: + get_set(&be->cat.v18.exo[index].dyn, value, get); + break; + case HW_CAT_EXO_OFS: + get_set_signed(&be->cat.v18.exo[index].ofs, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 18/21/22 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_cat_exo_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value) +{ + return hw_mod_cat_exo_mod(be, field, index, &value, 0); +} + +int hw_mod_cat_exo_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value) +{ + return hw_mod_cat_exo_mod(be, field, index, value, 1); +} + +int hw_mod_cat_rck_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->cat.nb_pm_ext * 64; + if ((unsigned int)(start_idx + count) > (be->cat.nb_pm_ext * 64)) + return error_index_too_large(__func__); + return be->iface->cat_rck_flush(be->be_dev, &be->cat, start_idx, count); +} + +static int hw_mod_cat_rck_mod(struct flow_api_backend_s *be, + enum hw_cat_e field, int index, uint32_t *value, + int get) +{ + if ((unsigned int)index >= (be->cat.nb_pm_ext * 64)) + return error_index_too_large(__func__); + switch (_VER_) { + case 18: + case 21: + case 22: + switch (field) { + case HW_CAT_RCK_DATA: + get_set(&be->cat.v18.rck[index].rck_data, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 18/21/22 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_cat_rck_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value) +{ + return hw_mod_cat_rck_mod(be, field, index, &value, 0); +} + +int hw_mod_cat_rck_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value) +{ + return hw_mod_cat_rck_mod(be, field, index, value, 1); +} + +int hw_mod_cat_len_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->cat.nb_len; + if ((unsigned int)(start_idx + count) > be->cat.nb_len) + return error_index_too_large(__func__); + return be->iface->cat_len_flush(be->be_dev, &be->cat, start_idx, count); +} + +static int hw_mod_cat_len_mod(struct flow_api_backend_s *be, + enum hw_cat_e field, int index, uint32_t *value, + int get) +{ + if ((unsigned int)index >= be->cat.nb_len) + return error_index_too_large(__func__); + switch (_VER_) { + case 18: + case 21: + case 22: + switch (field) { + case HW_CAT_LEN_LOWER: + get_set(&be->cat.v18.len[index].lower, value, get); + break; + case HW_CAT_LEN_UPPER: + get_set(&be->cat.v18.len[index].upper, value, get); + break; + case HW_CAT_LEN_DYN1: + get_set(&be->cat.v18.len[index].dyn1, value, get); + break; + case HW_CAT_LEN_DYN2: + get_set(&be->cat.v18.len[index].dyn2, value, get); + break; + case HW_CAT_LEN_INV: + get_set(&be->cat.v18.len[index].inv, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 18/21/22 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_cat_len_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value) +{ + return hw_mod_cat_len_mod(be, field, index, &value, 0); +} + +int hw_mod_cat_len_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value) +{ + return hw_mod_cat_len_mod(be, field, index, value, 1); +} + +int hw_mod_cat_cce_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = 4; + if ((unsigned int)(start_idx + count) > 4) + return error_index_too_large(__func__); + return be->iface->cat_cce_flush(be->be_dev, &be->cat, start_idx, count); +} + +static int hw_mod_cat_cce_mod(struct flow_api_backend_s *be, + enum hw_cat_e field, int index, uint32_t *value, + int get) +{ + if ((unsigned int)index >= be->cat.nb_len) + return error_index_too_large(__func__); + switch (_VER_) { + case 22: + switch (field) { + case HW_CAT_CCE_IMM: + get_set(&be->cat.v22.cce[index].imm, value, get); + break; + case HW_CAT_CCE_IND: + get_set(&be->cat.v22.cce[index].ind, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 22 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_cat_cce_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value) +{ + return hw_mod_cat_cce_mod(be, field, index, &value, 0); +} + +int hw_mod_cat_cce_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value) +{ + return hw_mod_cat_cce_mod(be, field, index, value, 1); +} + +int hw_mod_cat_ccs_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = 1024; + if ((unsigned int)(start_idx + count) > 1024) + return error_index_too_large(__func__); + return be->iface->cat_ccs_flush(be->be_dev, &be->cat, start_idx, count); +} + +static int hw_mod_cat_ccs_mod(struct flow_api_backend_s *be, + enum hw_cat_e field, int index, uint32_t *value, + int get) +{ + if ((unsigned int)index >= be->cat.nb_len) + return error_index_too_large(__func__); + switch (_VER_) { + case 22: + switch (field) { + case HW_CAT_CCS_COR_EN: + get_set(&be->cat.v22.ccs[index].cor_en, value, get); + break; + case HW_CAT_CCS_COR: + get_set(&be->cat.v22.ccs[index].cor, value, get); + break; + case HW_CAT_CCS_HSH_EN: + get_set(&be->cat.v22.ccs[index].hsh_en, value, get); + break; + case HW_CAT_CCS_HSH: + get_set(&be->cat.v22.ccs[index].hsh, value, get); + break; + case HW_CAT_CCS_QSL_EN: + get_set(&be->cat.v22.ccs[index].qsl_en, value, get); + break; + case HW_CAT_CCS_QSL: + get_set(&be->cat.v22.ccs[index].qsl, value, get); + break; + case HW_CAT_CCS_IPF_EN: + get_set(&be->cat.v22.ccs[index].ipf_en, value, get); + break; + case HW_CAT_CCS_IPF: + get_set(&be->cat.v22.ccs[index].ipf, value, get); + break; + case HW_CAT_CCS_SLC_EN: + get_set(&be->cat.v22.ccs[index].slc_en, value, get); + break; + case HW_CAT_CCS_SLC: + get_set(&be->cat.v22.ccs[index].slc, value, get); + break; + case HW_CAT_CCS_PDB_EN: + get_set(&be->cat.v22.ccs[index].pdb_en, value, get); + break; + case HW_CAT_CCS_PDB: + get_set(&be->cat.v22.ccs[index].pdb, value, get); + break; + case HW_CAT_CCS_MSK_EN: + get_set(&be->cat.v22.ccs[index].msk_en, value, get); + break; + case HW_CAT_CCS_MSK: + get_set(&be->cat.v22.ccs[index].msk, value, get); + break; + case HW_CAT_CCS_HST_EN: + get_set(&be->cat.v22.ccs[index].hst_en, value, get); + break; + case HW_CAT_CCS_HST: + get_set(&be->cat.v22.ccs[index].hst, value, get); + break; + case HW_CAT_CCS_EPP_EN: + get_set(&be->cat.v22.ccs[index].epp_en, value, get); + break; + case HW_CAT_CCS_EPP: + get_set(&be->cat.v22.ccs[index].epp, value, get); + break; + case HW_CAT_CCS_TPE_EN: + get_set(&be->cat.v22.ccs[index].tpe_en, value, get); + break; + case HW_CAT_CCS_TPE: + get_set(&be->cat.v22.ccs[index].tpe, value, get); + break; + case HW_CAT_CCS_RRB_EN: + get_set(&be->cat.v22.ccs[index].rrb_en, value, get); + break; + case HW_CAT_CCS_RRB: + get_set(&be->cat.v22.ccs[index].rrb, value, get); + break; + case HW_CAT_CCS_SB0_TYPE: + get_set(&be->cat.v22.ccs[index].sb0_type, value, get); + break; + case HW_CAT_CCS_SB0_DATA: + get_set(&be->cat.v22.ccs[index].sb0_data, value, get); + break; + case HW_CAT_CCS_SB1_TYPE: + get_set(&be->cat.v22.ccs[index].sb1_type, value, get); + break; + case HW_CAT_CCS_SB1_DATA: + get_set(&be->cat.v22.ccs[index].sb1_data, value, get); + break; + case HW_CAT_CCS_SB2_TYPE: + get_set(&be->cat.v22.ccs[index].sb2_type, value, get); + break; + case HW_CAT_CCS_SB2_DATA: + get_set(&be->cat.v22.ccs[index].sb2_data, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 22 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_cat_ccs_set(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t value) +{ + return hw_mod_cat_ccs_mod(be, field, index, &value, 0); +} + +int hw_mod_cat_ccs_get(struct flow_api_backend_s *be, enum hw_cat_e field, + int index, uint32_t *value) +{ + return hw_mod_cat_ccs_mod(be, field, index, value, 1); +} diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat_v18.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat_v18.h new file mode 100644 index 0000000000..3dc4a0aac7 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat_v18.h @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_CAT_V18_H_ +#define _HW_MOD_CAT_V18_H_ + +struct cat_v18_cfn_s { + uint32_t enable; + uint32_t inv; + /* protocol checks */ + uint32_t ptc_inv; + uint32_t ptc_isl; + uint32_t ptc_cfp; + uint32_t ptc_mac; + uint32_t ptc_l2; + uint32_t ptc_vntag; + uint32_t ptc_vlan; + uint32_t ptc_mpls; + uint32_t ptc_l3; + uint32_t ptc_frag; + uint32_t ptc_ip_prot; + uint32_t ptc_l4; + uint32_t ptc_tunnel; + uint32_t ptc_tnl_l2; + uint32_t ptc_tnl_vlan; + uint32_t ptc_tnl_mpls; + uint32_t ptc_tnl_l3; + uint32_t ptc_tnl_frag; + uint32_t ptc_tnl_ip_prot; + uint32_t ptc_tnl_l4; + /* error checks */ + uint32_t err_inv; + uint32_t err_cv; + uint32_t err_fcs; + uint32_t err_trunc; + uint32_t err_l3_cs; + uint32_t err_l4_cs; + /* in port */ + uint32_t mac_port; + /* pattern matcher */ + uint32_t pm_cmp[2]; + uint32_t pm_dct; + uint32_t pm_ext_inv; + uint32_t pm_cmb; + uint32_t pm_and_inv; + uint32_t pm_or_inv; + uint32_t pm_inv; + uint32_t lc; + uint32_t lc_inv; + uint32_t km_or; +}; + +struct cat_v18_kce_s { + uint32_t enable_bm; +}; + +struct cat_v18_kcs_s { + uint32_t category; +}; + +struct cat_v18_fte_s { + uint32_t enable_bm; +}; + +struct cat_v18_cte_s { + union { + uint32_t enable_bm; + struct { + uint32_t col : 1; + uint32_t cor : 1; + uint32_t hsh : 1; + uint32_t qsl : 1; + uint32_t ipf : 1; + uint32_t slc : 1; + uint32_t pdb : 1; + uint32_t msk : 1; + uint32_t hst : 1; + uint32_t epp : 1; + uint32_t tpe : 1; + } b; + }; +}; + +struct cat_v18_cts_s { + uint32_t cat_a; + uint32_t cat_b; +}; + +struct cat_v18_cot_s { + uint32_t color; + uint32_t km; +}; + +struct cat_v18_cct_s { + uint32_t color; + uint32_t km; +}; + +struct cat_v18_exo_s { + uint32_t dyn; + int32_t ofs; +}; + +struct cat_v18_rck_s { + uint32_t rck_data; +}; + +struct cat_v18_len_s { + uint32_t lower; + uint32_t upper; + uint32_t dyn1; + uint32_t dyn2; + uint32_t inv; +}; + +struct cat_v18_kcc_s { + uint32_t key[2]; + uint32_t category; + uint32_t id; +}; + +struct hw_mod_cat_v18_s { + struct cat_v18_cfn_s *cfn; + struct cat_v18_kce_s *kce; + struct cat_v18_kcs_s *kcs; + struct cat_v18_fte_s *fte; + struct cat_v18_cte_s *cte; + struct cat_v18_cts_s *cts; + struct cat_v18_cot_s *cot; + struct cat_v18_cct_s *cct; + struct cat_v18_exo_s *exo; + struct cat_v18_rck_s *rck; + struct cat_v18_len_s *len; + struct cat_v18_kcc_s *kcc_cam; +}; + +#endif /* _HW_MOD_CAT_V18_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat_v21.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat_v21.h new file mode 100644 index 0000000000..fa69ec11f3 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat_v21.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_CAT_V21_H_ +#define _HW_MOD_CAT_V21_H_ + +#include "hw_mod_cat_v18.h" + +struct cat_v21_cfn_s { + uint32_t enable; + uint32_t inv; + /* protocol checks */ + uint32_t ptc_inv; + uint32_t ptc_isl; + uint32_t ptc_cfp; + uint32_t ptc_mac; + uint32_t ptc_l2; + uint32_t ptc_vntag; + uint32_t ptc_vlan; + uint32_t ptc_mpls; + uint32_t ptc_l3; + uint32_t ptc_frag; + uint32_t ptc_ip_prot; + uint32_t ptc_l4; + uint32_t ptc_tunnel; + uint32_t ptc_tnl_l2; + uint32_t ptc_tnl_vlan; + uint32_t ptc_tnl_mpls; + uint32_t ptc_tnl_l3; + uint32_t ptc_tnl_frag; + uint32_t ptc_tnl_ip_prot; + uint32_t ptc_tnl_l4; + /* error checks */ + uint32_t err_inv; + uint32_t err_cv; + uint32_t err_fcs; + uint32_t err_trunc; + uint32_t err_l3_cs; + uint32_t err_l4_cs; + uint32_t err_tnl_l3_cs; + uint32_t err_tnl_l4_cs; + uint32_t err_ttl_exp; + uint32_t err_tnl_ttl_exp; + /* in port */ + uint32_t mac_port; + /* pattern matcher */ + uint32_t pm_cmp[2]; + uint32_t pm_dct; + uint32_t pm_ext_inv; + uint32_t pm_cmb; + uint32_t pm_and_inv; + uint32_t pm_or_inv; + uint32_t pm_inv; + uint32_t lc; + uint32_t lc_inv; + uint32_t km0_or; + uint32_t km1_or; +}; + +struct cat_v21_kce_s { + uint32_t enable_bm[2]; +}; + +struct cat_v21_kcs_s { + uint32_t category[2]; +}; + +struct cat_v21_fte_s { + uint32_t enable_bm[2]; +}; + +struct hw_mod_cat_v21_s { + struct cat_v21_cfn_s *cfn; + struct cat_v21_kce_s *kce; + struct cat_v21_kcs_s *kcs; + struct cat_v21_fte_s *fte; + struct cat_v18_cte_s *cte; + struct cat_v18_cts_s *cts; + struct cat_v18_cot_s *cot; + struct cat_v18_cct_s *cct; + struct cat_v18_exo_s *exo; + struct cat_v18_rck_s *rck; + struct cat_v18_len_s *len; + struct cat_v18_kcc_s *kcc_cam; +}; + +#endif /* _HW_MOD_CAT_V21_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat_v22.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat_v22.h new file mode 100644 index 0000000000..fa7dc6f441 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat_v22.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_CAT_V22_H_ +#define _HW_MOD_CAT_V22_H_ + +#include "hw_mod_cat_v21.h" + +struct cat_v22_cte_s { + union { + uint32_t enable_bm; + struct { + uint32_t col : 1; + uint32_t cor : 1; + uint32_t hsh : 1; + uint32_t qsl : 1; + uint32_t ipf : 1; + uint32_t slc : 1; + uint32_t pdb : 1; + uint32_t msk : 1; + uint32_t hst : 1; + uint32_t epp : 1; + uint32_t tpe : 1; + uint32_t rrb : 1; + } b; + }; +}; + +struct cat_v22_cce_s { + uint32_t imm; + uint32_t ind; +}; + +struct cat_v22_ccs_s { + uint32_t cor_en; + uint32_t cor; + uint32_t hsh_en; + uint32_t hsh; + uint32_t qsl_en; + uint32_t qsl; + uint32_t ipf_en; + uint32_t ipf; + uint32_t slc_en; + uint32_t slc; + uint32_t pdb_en; + uint32_t pdb; + uint32_t msk_en; + uint32_t msk; + uint32_t hst_en; + uint32_t hst; + uint32_t epp_en; + uint32_t epp; + uint32_t tpe_en; + uint32_t tpe; + uint32_t rrb_en; + uint32_t rrb; + uint32_t sb0_type; + uint32_t sb0_data; + uint32_t sb1_type; + uint32_t sb1_data; + uint32_t sb2_type; + uint32_t sb2_data; +}; + +struct hw_mod_cat_v22_s { + struct cat_v21_cfn_s *cfn; + struct cat_v21_kce_s *kce; /* KCE 0/1 */ + struct cat_v21_kcs_s *kcs; /* KCS 0/1 */ + struct cat_v21_fte_s *fte; /* FTE 0/1 */ + struct cat_v22_cte_s *cte; + struct cat_v18_cts_s *cts; + struct cat_v18_cot_s *cot; + struct cat_v18_cct_s *cct; + struct cat_v18_exo_s *exo; + struct cat_v18_rck_s *rck; + struct cat_v18_len_s *len; + struct cat_v18_kcc_s *kcc_cam; + struct cat_v22_cce_s *cce; + struct cat_v22_ccs_s *ccs; +}; + +#endif /* _HW_MOD_CAT_V22_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm.c new file mode 100644 index 0000000000..404add5fe6 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm.c @@ -0,0 +1,1099 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include +#include "flow_api_backend.h" + +#define _MOD_ "FLM" +#define _VER_ be->flm.ver + +bool hw_mod_flm_present(struct flow_api_backend_s *be) +{ + return be->iface->get_flm_present(be->be_dev); +} + +int hw_mod_flm_alloc(struct flow_api_backend_s *be) +{ + int nb; + + _VER_ = be->iface->get_flm_version(be->be_dev); + NT_LOG(DBG, FILTER, "FLM MODULE VERSION %i.%i\n", VER_MAJOR(_VER_), + VER_MINOR(_VER_)); + + nb = be->iface->get_nb_flm_categories(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "flm_categories", _MOD_, _VER_); + be->flm.nb_categories = (uint32_t)nb; + + nb = be->iface->get_nb_flm_size_mb(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "flm_size_mb", _MOD_, _VER_); + be->flm.nb_size_mb = (uint32_t)nb; + + nb = be->iface->get_nb_flm_entry_size(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "flm_entry_size", _MOD_, _VER_); + be->flm.nb_entry_size = (uint32_t)nb; + + nb = be->iface->get_nb_flm_variant(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "flm_variant", _MOD_, _VER_); + be->flm.nb_variant = (uint32_t)nb; + + nb = be->iface->get_nb_flm_prios(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "flm_prios", _MOD_, _VER_); + be->flm.nb_prios = (uint32_t)nb; + + nb = be->iface->get_nb_flm_pst_profiles(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "flm_variant", _MOD_, _VER_); + be->flm.nb_pst_profiles = (uint32_t)nb; + + switch (_VER_) { + case 17: + if (!callocate_mod(CAST_COMMON(&be->flm), 26, + &be->flm.v17.control, 1, + sizeof(struct flm_v17_control_s), + &be->flm.v17.status, 1, + sizeof(struct flm_v17_status_s), + &be->flm.v17.timeout, 1, + sizeof(struct flm_v17_timeout_s), + &be->flm.v17.scrub, 1, + sizeof(struct flm_v17_scrub_s), + &be->flm.v17.load_bin, 1, + sizeof(struct flm_v17_load_bin_s), + &be->flm.v17.load_pps, 1, + sizeof(struct flm_v17_load_pps_s), + &be->flm.v17.load_lps, 1, + sizeof(struct flm_v17_load_lps_s), + &be->flm.v17.load_aps, 1, + sizeof(struct flm_v17_load_aps_s), + &be->flm.v17.prio, 1, + sizeof(struct flm_v17_prio_s), + &be->flm.v17.pst, be->flm.nb_pst_profiles, + sizeof(struct flm_v17_pst_s), + &be->flm.v17.rcp, be->flm.nb_categories, + sizeof(struct flm_v17_rcp_s), + &be->flm.v17.buf_ctrl, 1, + sizeof(struct flm_v17_buf_ctrl_s), + &be->flm.v17.lrn_done, 1, + sizeof(struct flm_v17_stat_lrn_done_s), + &be->flm.v17.lrn_ignore, 1, + sizeof(struct flm_v17_stat_lrn_ignore_s), + &be->flm.v17.lrn_fail, 1, + sizeof(struct flm_v17_stat_lrn_fail_s), + &be->flm.v17.unl_done, 1, + sizeof(struct flm_v17_stat_unl_done_s), + &be->flm.v17.unl_ignore, 1, + sizeof(struct flm_v17_stat_unl_ignore_s), + &be->flm.v17.rel_done, 1, + sizeof(struct flm_v17_stat_rel_done_s), + &be->flm.v17.rel_ignore, 1, + sizeof(struct flm_v17_stat_rel_ignore_s), + &be->flm.v17.aul_done, 1, + sizeof(struct flm_v17_stat_aul_done_s), + &be->flm.v17.aul_ignore, 1, + sizeof(struct flm_v17_stat_aul_ignore_s), + &be->flm.v17.aul_fail, 1, + sizeof(struct flm_v17_stat_aul_fail_s), + &be->flm.v17.tul_done, 1, + sizeof(struct flm_v17_stat_tul_done_s), + &be->flm.v17.flows, 1, + sizeof(struct flm_v17_stat_flows_s), + &be->flm.v17.prb_done, 1, + sizeof(struct flm_v17_stat_prb_done_s), + &be->flm.v17.prb_ignore, 1, + sizeof(struct flm_v17_stat_prb_ignore_s))) + return -1; + break; + + case 20: + if (!callocate_mod(CAST_COMMON(&be->flm), 38, + &be->flm.v17.control, 1, + sizeof(struct flm_v17_control_s), + &be->flm.v17.status, 1, + sizeof(struct flm_v17_status_s), + &be->flm.v17.timeout, 1, + sizeof(struct flm_v17_timeout_s), + &be->flm.v17.scrub, 1, + sizeof(struct flm_v17_scrub_s), + &be->flm.v17.load_bin, 1, + sizeof(struct flm_v17_load_bin_s), + &be->flm.v17.load_pps, 1, + sizeof(struct flm_v17_load_pps_s), + &be->flm.v17.load_lps, 1, + sizeof(struct flm_v17_load_lps_s), + &be->flm.v17.load_aps, 1, + sizeof(struct flm_v17_load_aps_s), + &be->flm.v17.prio, 1, + sizeof(struct flm_v17_prio_s), + &be->flm.v17.pst, be->flm.nb_pst_profiles, + sizeof(struct flm_v17_pst_s), + &be->flm.v17.rcp, be->flm.nb_categories, + sizeof(struct flm_v17_rcp_s), + &be->flm.v17.buf_ctrl, 1, + sizeof(struct flm_v17_buf_ctrl_s), + &be->flm.v17.lrn_done, 1, + sizeof(struct flm_v17_stat_lrn_done_s), + &be->flm.v17.lrn_ignore, 1, + sizeof(struct flm_v17_stat_lrn_ignore_s), + &be->flm.v17.lrn_fail, 1, + sizeof(struct flm_v17_stat_lrn_fail_s), + &be->flm.v17.unl_done, 1, + sizeof(struct flm_v17_stat_unl_done_s), + &be->flm.v17.unl_ignore, 1, + sizeof(struct flm_v17_stat_unl_ignore_s), + &be->flm.v17.rel_done, 1, + sizeof(struct flm_v17_stat_rel_done_s), + &be->flm.v17.rel_ignore, 1, + sizeof(struct flm_v17_stat_rel_ignore_s), + &be->flm.v17.aul_done, 1, + sizeof(struct flm_v17_stat_aul_done_s), + &be->flm.v17.aul_ignore, 1, + sizeof(struct flm_v17_stat_aul_ignore_s), + &be->flm.v17.aul_fail, 1, + sizeof(struct flm_v17_stat_aul_fail_s), + &be->flm.v17.tul_done, 1, + sizeof(struct flm_v17_stat_tul_done_s), + &be->flm.v17.flows, 1, + sizeof(struct flm_v17_stat_flows_s), + &be->flm.v17.prb_done, 1, + sizeof(struct flm_v17_stat_prb_done_s), + &be->flm.v17.prb_ignore, 1, + sizeof(struct flm_v17_stat_prb_ignore_s), + &be->flm.v20.sta_done, 1, + sizeof(struct flm_v20_stat_sta_done_s), + &be->flm.v20.inf_done, 1, + sizeof(struct flm_v20_stat_inf_done_s), + &be->flm.v20.inf_skip, 1, + sizeof(struct flm_v20_stat_inf_skip_s), + &be->flm.v20.pck_hit, 1, + sizeof(struct flm_v20_stat_pck_hit_s), + &be->flm.v20.pck_miss, 1, + sizeof(struct flm_v20_stat_pck_miss_s), + &be->flm.v20.pck_unh, 1, + sizeof(struct flm_v20_stat_pck_unh_s), + &be->flm.v20.pck_dis, 1, + sizeof(struct flm_v20_stat_pck_dis_s), + &be->flm.v20.csh_hit, 1, + sizeof(struct flm_v20_stat_csh_hit_s), + &be->flm.v20.csh_miss, 1, + sizeof(struct flm_v20_stat_csh_miss_s), + &be->flm.v20.csh_unh, 1, + sizeof(struct flm_v20_stat_csh_unh_s), + &be->flm.v20.cuc_start, 1, + sizeof(struct flm_v20_stat_cuc_start_s), + &be->flm.v20.cuc_move, 1, + sizeof(struct flm_v20_stat_cuc_move_s))) + return -1; + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +void hw_mod_flm_free(struct flow_api_backend_s *be) +{ + if (be->flm.base) { + free(be->flm.base); + be->flm.base = NULL; + } +} + +int hw_mod_flm_reset(struct flow_api_backend_s *be) +{ + /* Zero entire cache area */ + ZERO_MOD_CACHE(&be->flm); + + NT_LOG(DBG, FILTER, "INIT FLM\n"); + hw_mod_flm_control_set(be, HW_FLM_CONTROL_SPLIT_SDRAM_USAGE, 0x10); + + hw_mod_flm_control_flush(be); + hw_mod_flm_timeout_flush(be); + hw_mod_flm_scrub_flush(be); + hw_mod_flm_rcp_flush(be, 0, ALL_ENTRIES); + + return 0; +} + +int hw_mod_flm_control_flush(struct flow_api_backend_s *be) +{ + return be->iface->flm_control_flush(be->be_dev, &be->flm); +} + +static int hw_mod_flm_control_mod(struct flow_api_backend_s *be, + enum hw_flm_e field, uint32_t *value, int get) +{ + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_CONTROL_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(be->flm.v17.control, (uint8_t)*value, + sizeof(struct flm_v17_control_s)); + break; + case HW_FLM_CONTROL_ENABLE: + get_set(&be->flm.v17.control->enable, value, get); + break; + case HW_FLM_CONTROL_INIT: + get_set(&be->flm.v17.control->init, value, get); + break; + case HW_FLM_CONTROL_LDS: + get_set(&be->flm.v17.control->lds, value, get); + break; + case HW_FLM_CONTROL_LFS: + get_set(&be->flm.v17.control->lfs, value, get); + break; + case HW_FLM_CONTROL_LIS: + get_set(&be->flm.v17.control->lis, value, get); + break; + case HW_FLM_CONTROL_UDS: + get_set(&be->flm.v17.control->uds, value, get); + break; + case HW_FLM_CONTROL_UIS: + get_set(&be->flm.v17.control->uis, value, get); + break; + case HW_FLM_CONTROL_RDS: + get_set(&be->flm.v17.control->rds, value, get); + break; + case HW_FLM_CONTROL_RIS: + get_set(&be->flm.v17.control->ris, value, get); + break; + case HW_FLM_CONTROL_PDS: + get_set(&be->flm.v17.control->pds, value, get); + break; + case HW_FLM_CONTROL_PIS: + get_set(&be->flm.v17.control->pis, value, get); + break; + case HW_FLM_CONTROL_CRCWR: + get_set(&be->flm.v17.control->crcwr, value, get); + break; + case HW_FLM_CONTROL_CRCRD: + get_set(&be->flm.v17.control->crcrd, value, get); + break; + case HW_FLM_CONTROL_RBL: + get_set(&be->flm.v17.control->rbl, value, get); + break; + case HW_FLM_CONTROL_EAB: + get_set(&be->flm.v17.control->eab, value, get); + break; + case HW_FLM_CONTROL_SPLIT_SDRAM_USAGE: + get_set(&be->flm.v17.control->split_sdram_usage, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_flm_control_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value) +{ + return hw_mod_flm_control_mod(be, field, &value, 0); +} + +int hw_mod_flm_control_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value) +{ + return hw_mod_flm_control_mod(be, field, value, 1); +} + +int hw_mod_flm_status_flush(struct flow_api_backend_s *be) +{ + return be->iface->flm_status_flush(be->be_dev, &be->flm); +} + +int hw_mod_flm_status_update(struct flow_api_backend_s *be) +{ + return be->iface->flm_status_update(be->be_dev, &be->flm); +} + +static int hw_mod_flm_status_mod(struct flow_api_backend_s *be, + enum hw_flm_e field, uint32_t *value, int get) +{ + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_STATUS_CALIBDONE: + get_set(&be->flm.v17.status->calibdone, value, get); + break; + case HW_FLM_STATUS_INITDONE: + get_set(&be->flm.v17.status->initdone, value, get); + break; + case HW_FLM_STATUS_IDLE: + get_set(&be->flm.v17.status->idle, value, get); + break; + case HW_FLM_STATUS_CRITICAL: + get_set(&be->flm.v17.status->critical, value, get); + break; + case HW_FLM_STATUS_PANIC: + get_set(&be->flm.v17.status->panic, value, get); + break; + case HW_FLM_STATUS_CRCERR: + get_set(&be->flm.v17.status->crcerr, value, get); + break; + case HW_FLM_STATUS_EFT_BP: + get_set(&be->flm.v17.status->eft_bp, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_flm_status_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value) +{ + return hw_mod_flm_status_mod(be, field, &value, 0); +} + +int hw_mod_flm_status_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value) +{ + return hw_mod_flm_status_mod(be, field, value, 1); +} + +int hw_mod_flm_timeout_flush(struct flow_api_backend_s *be) +{ + return be->iface->flm_timeout_flush(be->be_dev, &be->flm); +} + +static int hw_mod_flm_timeout_mod(struct flow_api_backend_s *be, + enum hw_flm_e field, uint32_t *value, int get) +{ + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_TIMEOUT_T: + get_set(&be->flm.v17.timeout->t, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_flm_timeout_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value) +{ + return hw_mod_flm_timeout_mod(be, field, &value, 0); +} + +int hw_mod_flm_timeout_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value) +{ + return hw_mod_flm_timeout_mod(be, field, value, 1); +} + +int hw_mod_flm_scrub_flush(struct flow_api_backend_s *be) +{ + return be->iface->flm_scrub_flush(be->be_dev, &be->flm); +} + +static int hw_mod_flm_scrub_mod(struct flow_api_backend_s *be, + enum hw_flm_e field, uint32_t *value, int get) +{ + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_SCRUB_I: + get_set(&be->flm.v17.scrub->i, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_flm_scrub_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value) +{ + return hw_mod_flm_scrub_mod(be, field, &value, 0); +} + +int hw_mod_flm_scrub_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value) +{ + return hw_mod_flm_scrub_mod(be, field, value, 1); +} + +int hw_mod_flm_load_bin_flush(struct flow_api_backend_s *be) +{ + return be->iface->flm_load_bin_flush(be->be_dev, &be->flm); +} + +static int hw_mod_flm_load_bin_mod(struct flow_api_backend_s *be, + enum hw_flm_e field, uint32_t *value, + int get) +{ + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_LOAD_BIN: + get_set(&be->flm.v17.load_bin->bin, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_flm_load_bin_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value) +{ + return hw_mod_flm_load_bin_mod(be, field, &value, 0); +} + +int hw_mod_flm_load_bin_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value) +{ + return hw_mod_flm_load_bin_mod(be, field, value, 1); +} + +int hw_mod_flm_load_pps_flush(struct flow_api_backend_s *be) +{ + return be->iface->flm_load_pps_flush(be->be_dev, &be->flm); +} + +static int hw_mod_flm_load_pps_mod(struct flow_api_backend_s *be, + enum hw_flm_e field, uint32_t *value, + int get) +{ + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_LOAD_PPS: + get_set(&be->flm.v17.load_pps->pps, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_flm_load_pps_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value) +{ + return hw_mod_flm_load_pps_mod(be, field, &value, 0); +} + +int hw_mod_flm_load_pps_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value) +{ + return hw_mod_flm_load_pps_mod(be, field, value, 1); +} + +int hw_mod_flm_load_lps_flush(struct flow_api_backend_s *be) +{ + return be->iface->flm_load_lps_flush(be->be_dev, &be->flm); +} + +static int hw_mod_flm_load_lps_mod(struct flow_api_backend_s *be, + enum hw_flm_e field, uint32_t *value, + int get) +{ + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_LOAD_LPS: + get_set(&be->flm.v17.load_lps->lps, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_flm_load_lps_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value) +{ + return hw_mod_flm_load_lps_mod(be, field, &value, 0); +} + +int hw_mod_flm_load_lps_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value) +{ + return hw_mod_flm_load_lps_mod(be, field, value, 1); +} + +int hw_mod_flm_load_aps_flush(struct flow_api_backend_s *be) +{ + return be->iface->flm_load_aps_flush(be->be_dev, &be->flm); +} + +static int hw_mod_flm_load_aps_mod(struct flow_api_backend_s *be, + enum hw_flm_e field, uint32_t *value, + int get) +{ + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_LOAD_APS: + get_set(&be->flm.v17.load_aps->aps, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_flm_load_aps_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value) +{ + return hw_mod_flm_load_aps_mod(be, field, &value, 0); +} + +int hw_mod_flm_load_aps_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value) +{ + return hw_mod_flm_load_aps_mod(be, field, value, 1); +} + +int hw_mod_flm_prio_flush(struct flow_api_backend_s *be) +{ + return be->iface->flm_prio_flush(be->be_dev, &be->flm); +} + +static int hw_mod_flm_prio_mod(struct flow_api_backend_s *be, + enum hw_flm_e field, uint32_t *value, int get) +{ + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_PRIO_LIMIT0: + get_set(&be->flm.v17.prio->limit0, value, get); + break; + case HW_FLM_PRIO_FT0: + get_set(&be->flm.v17.prio->ft0, value, get); + break; + case HW_FLM_PRIO_LIMIT1: + get_set(&be->flm.v17.prio->limit1, value, get); + break; + case HW_FLM_PRIO_FT1: + get_set(&be->flm.v17.prio->ft1, value, get); + break; + case HW_FLM_PRIO_LIMIT2: + get_set(&be->flm.v17.prio->limit2, value, get); + break; + case HW_FLM_PRIO_FT2: + get_set(&be->flm.v17.prio->ft2, value, get); + break; + case HW_FLM_PRIO_LIMIT3: + get_set(&be->flm.v17.prio->limit3, value, get); + break; + case HW_FLM_PRIO_FT3: + get_set(&be->flm.v17.prio->ft3, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_flm_prio_set(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t value) +{ + return hw_mod_flm_prio_mod(be, field, &value, 0); +} + +int hw_mod_flm_prio_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value) +{ + return hw_mod_flm_prio_mod(be, field, value, 1); +} + +int hw_mod_flm_pst_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->flm.nb_pst_profiles; + if ((unsigned int)(start_idx + count) > be->flm.nb_pst_profiles) + return error_index_too_large(__func__); + return be->iface->flm_pst_flush(be->be_dev, &be->flm, start_idx, count); +} + +static int hw_mod_flm_pst_mod(struct flow_api_backend_s *be, + enum hw_flm_e field, int index, uint32_t *value, + int get) +{ + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_PST_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->flm.v17.pst[index], (uint8_t)*value, + sizeof(struct flm_v17_pst_s)); + break; + case HW_FLM_PST_BP: + get_set(&be->flm.v17.pst[index].bp, value, get); + break; + case HW_FLM_PST_PP: + get_set(&be->flm.v17.pst[index].pp, value, get); + break; + case HW_FLM_PST_TP: + get_set(&be->flm.v17.pst[index].tp, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_flm_pst_set(struct flow_api_backend_s *be, enum hw_flm_e field, + int index, uint32_t value) +{ + return hw_mod_flm_pst_mod(be, field, index, &value, 0); +} + +int hw_mod_flm_pst_get(struct flow_api_backend_s *be, enum hw_flm_e field, + int index, uint32_t *value) +{ + return hw_mod_flm_pst_mod(be, field, index, value, 1); +} + +int hw_mod_flm_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->flm.nb_categories; + if ((unsigned int)(start_idx + count) > be->flm.nb_categories) + return error_index_too_large(__func__); + return be->iface->flm_rcp_flush(be->be_dev, &be->flm, start_idx, count); +} + +static int hw_mod_flm_rcp_mod(struct flow_api_backend_s *be, + enum hw_flm_e field, int index, uint32_t *value, + int get) +{ + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_RCP_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->flm.v17.rcp[index], (uint8_t)*value, + sizeof(struct flm_v17_rcp_s)); + break; + case HW_FLM_RCP_LOOKUP: + get_set(&be->flm.v17.rcp[index].lookup, value, get); + break; + case HW_FLM_RCP_QW0_DYN: + get_set(&be->flm.v17.rcp[index].qw0_dyn, value, get); + break; + case HW_FLM_RCP_QW0_OFS: + get_set(&be->flm.v17.rcp[index].qw0_ofs, value, get); + break; + case HW_FLM_RCP_QW0_SEL: + get_set(&be->flm.v17.rcp[index].qw0_sel, value, get); + break; + case HW_FLM_RCP_QW4_DYN: + get_set(&be->flm.v17.rcp[index].qw4_dyn, value, get); + break; + case HW_FLM_RCP_QW4_OFS: + get_set(&be->flm.v17.rcp[index].qw4_ofs, value, get); + break; + case HW_FLM_RCP_SW8_DYN: + get_set(&be->flm.v17.rcp[index].sw8_dyn, value, get); + break; + case HW_FLM_RCP_SW8_OFS: + get_set(&be->flm.v17.rcp[index].sw8_ofs, value, get); + break; + case HW_FLM_RCP_SW8_SEL: + get_set(&be->flm.v17.rcp[index].sw8_sel, value, get); + break; + case HW_FLM_RCP_SW9_DYN: + get_set(&be->flm.v17.rcp[index].sw9_dyn, value, get); + break; + case HW_FLM_RCP_SW9_OFS: + get_set(&be->flm.v17.rcp[index].sw9_ofs, value, get); + break; + case HW_FLM_RCP_MASK: + if (get) { + memcpy(value, be->flm.v17.rcp[index].mask, + sizeof(((struct flm_v17_rcp_s *)0) + ->mask)); + } else { + memcpy(be->flm.v17.rcp[index].mask, value, + sizeof(((struct flm_v17_rcp_s *)0) + ->mask)); + } + break; + case HW_FLM_RCP_KID: + get_set(&be->flm.v17.rcp[index].kid, value, get); + break; + case HW_FLM_RCP_OPN: + get_set(&be->flm.v17.rcp[index].opn, value, get); + break; + case HW_FLM_RCP_IPN: + get_set(&be->flm.v17.rcp[index].ipn, value, get); + break; + case HW_FLM_RCP_BYT_DYN: + get_set(&be->flm.v17.rcp[index].byt_dyn, value, get); + break; + case HW_FLM_RCP_BYT_OFS: + get_set(&be->flm.v17.rcp[index].byt_ofs, value, get); + break; + case HW_FLM_RCP_TXPLM: + get_set(&be->flm.v17.rcp[index].txplm, value, get); + break; + case HW_FLM_RCP_AUTO_IPV4_MASK: + get_set(&be->flm.v17.rcp[index].auto_ipv4_mask, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_flm_rcp_set_mask(struct flow_api_backend_s *be, enum hw_flm_e field, + int index, uint32_t *value) +{ + if (field != HW_FLM_RCP_MASK) + return error_unsup_ver(__func__, _MOD_, _VER_); + return hw_mod_flm_rcp_mod(be, field, index, value, 0); +} + +int hw_mod_flm_rcp_set(struct flow_api_backend_s *be, enum hw_flm_e field, + int index, uint32_t value) +{ + if (field == HW_FLM_RCP_MASK) + return error_unsup_ver(__func__, _MOD_, _VER_); + return hw_mod_flm_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_flm_rcp_get(struct flow_api_backend_s *be, enum hw_flm_e field, + int index, uint32_t *value) +{ + return hw_mod_flm_rcp_mod(be, field, index, value, 1); +} + +int hw_mod_flm_buf_ctrl_update(struct flow_api_backend_s *be) +{ + return be->iface->flm_buf_ctrl_update(be->be_dev, &be->flm); +} + +static int hw_mod_flm_buf_ctrl_mod_get(struct flow_api_backend_s *be, + enum hw_flm_e field, uint32_t *value) +{ + int get = 1; /* Only get supported */ + + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_BUF_CTRL_LRN_FREE: + get_set(&be->flm.v17.buf_ctrl->lrn_free, value, get); + break; + case HW_FLM_BUF_CTRL_INF_AVAIL: + get_set(&be->flm.v17.buf_ctrl->inf_avail, value, get); + break; + case HW_FLM_BUF_CTRL_STA_AVAIL: + get_set(&be->flm.v17.buf_ctrl->sta_avail, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_flm_buf_ctrl_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value) +{ + return hw_mod_flm_buf_ctrl_mod_get(be, field, value); +} + +int hw_mod_flm_stat_update(struct flow_api_backend_s *be) +{ + return be->iface->flm_stat_update(be->be_dev, &be->flm); +} + +int hw_mod_flm_stat_get(struct flow_api_backend_s *be, enum hw_flm_e field, + uint32_t *value) +{ + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_STAT_LRN_DONE: + *value = be->flm.v17.lrn_done->cnt; + break; + case HW_FLM_STAT_LRN_IGNORE: + *value = be->flm.v17.lrn_ignore->cnt; + break; + case HW_FLM_STAT_LRN_FAIL: + *value = be->flm.v17.lrn_fail->cnt; + break; + case HW_FLM_STAT_UNL_DONE: + *value = be->flm.v17.unl_done->cnt; + break; + case HW_FLM_STAT_UNL_IGNORE: + *value = be->flm.v17.unl_ignore->cnt; + break; + case HW_FLM_STAT_REL_DONE: + *value = be->flm.v17.rel_done->cnt; + break; + case HW_FLM_STAT_REL_IGNORE: + *value = be->flm.v17.rel_ignore->cnt; + break; + case HW_FLM_STAT_PRB_DONE: + *value = be->flm.v17.prb_done->cnt; + break; + case HW_FLM_STAT_PRB_IGNORE: + *value = be->flm.v17.prb_ignore->cnt; + break; + case HW_FLM_STAT_AUL_DONE: + *value = be->flm.v17.aul_done->cnt; + break; + case HW_FLM_STAT_AUL_IGNORE: + *value = be->flm.v17.aul_ignore->cnt; + break; + case HW_FLM_STAT_AUL_FAIL: + *value = be->flm.v17.aul_fail->cnt; + break; + case HW_FLM_STAT_TUL_DONE: + *value = be->flm.v17.tul_done->cnt; + break; + case HW_FLM_STAT_FLOWS: + *value = be->flm.v17.flows->cnt; + break; + + default: { + if (_VER_ < 18) + return error_unsup_field(__func__); + + switch (field) { + case HW_FLM_STAT_STA_DONE: + *value = be->flm.v20.sta_done->cnt; + break; + case HW_FLM_STAT_INF_DONE: + *value = be->flm.v20.inf_done->cnt; + break; + case HW_FLM_STAT_INF_SKIP: + *value = be->flm.v20.inf_skip->cnt; + break; + case HW_FLM_STAT_PCK_HIT: + *value = be->flm.v20.pck_hit->cnt; + break; + case HW_FLM_STAT_PCK_MISS: + *value = be->flm.v20.pck_miss->cnt; + break; + case HW_FLM_STAT_PCK_UNH: + *value = be->flm.v20.pck_unh->cnt; + break; + case HW_FLM_STAT_PCK_DIS: + *value = be->flm.v20.pck_dis->cnt; + break; + case HW_FLM_STAT_CSH_HIT: + *value = be->flm.v20.csh_hit->cnt; + break; + case HW_FLM_STAT_CSH_MISS: + *value = be->flm.v20.csh_miss->cnt; + break; + case HW_FLM_STAT_CSH_UNH: + *value = be->flm.v20.csh_unh->cnt; + break; + case HW_FLM_STAT_CUC_START: + *value = be->flm.v20.cuc_start->cnt; + break; + case HW_FLM_STAT_CUC_MOVE: + *value = be->flm.v20.cuc_move->cnt; + break; + + default: + return error_unsup_field(__func__); + } + } + break; + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_flm_lrn_data_set_flush(struct flow_api_backend_s *be, + enum hw_flm_e field, const uint32_t *value) +{ + int ret = 0; + + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_FLOW_LRN_DATA_V17: + ret = be->iface->flm_lrn_data_flush(be->be_dev, + &be->flm, value, + sizeof(struct flm_v17_lrn_data_s) / + sizeof(uint32_t)); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return ret; +} + +int hw_mod_flm_inf_data_update_get(struct flow_api_backend_s *be, + enum hw_flm_e field, uint32_t *value, + uint32_t word_cnt) +{ + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_FLOW_INF_DATA_V17: + be->iface->flm_inf_data_update(be->be_dev, &be->flm, + value, word_cnt); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_flm_sta_data_update_get(struct flow_api_backend_s *be, + enum hw_flm_e field, uint32_t *value) +{ + switch (_VER_) { + case 17: + case 20: + switch (field) { + case HW_FLM_FLOW_STA_DATA_V17: + be->iface->flm_sta_data_update(be->be_dev, + &be->flm, value, + sizeof(struct flm_v17_sta_data_s) / + sizeof(uint32_t)); + break; + + default: + return error_unsup_field(__func__); + } + break; + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm_v17.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm_v17.h new file mode 100644 index 0000000000..9b4ee1991e --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm_v17.h @@ -0,0 +1,265 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_FLM_V17_H_ +#define _HW_MOD_FLM_V17_H_ + +struct flm_v17_mbr_idx_overlay { + uint64_t a : 28; + uint64_t b : 28; + uint64_t pad : 4; +}; + +struct flm_v17_control_s { + uint32_t enable; + uint32_t init; + uint32_t lds; + uint32_t lfs; + uint32_t lis; + uint32_t uds; + uint32_t uis; + uint32_t rds; + uint32_t ris; + uint32_t pds; + uint32_t pis; + uint32_t crcwr; + uint32_t crcrd; + uint32_t rbl; + uint32_t eab; + uint32_t split_sdram_usage; +}; + +struct flm_v17_status_s { + uint32_t calibdone; + uint32_t initdone; + uint32_t idle; + uint32_t critical; + uint32_t panic; + uint32_t crcerr; + uint32_t eft_bp; +}; + +struct flm_v17_timeout_s { + uint32_t t; +}; + +struct flm_v17_scrub_s { + uint32_t i; +}; + +struct flm_v17_load_bin_s { + uint32_t bin; +}; + +struct flm_v17_load_pps_s { + uint32_t pps; +}; + +struct flm_v17_load_lps_s { + uint32_t lps; +}; + +struct flm_v17_load_aps_s { + uint32_t aps; +}; + +struct flm_v17_prio_s { + uint32_t limit0; + uint32_t ft0; + uint32_t limit1; + uint32_t ft1; + uint32_t limit2; + uint32_t ft2; + uint32_t limit3; + uint32_t ft3; +}; + +struct flm_v17_pst_s { + uint32_t bp; + uint32_t pp; + uint32_t tp; +}; + +struct flm_v17_rcp_s { + uint32_t lookup; + uint32_t qw0_dyn; + uint32_t qw0_ofs; + uint32_t qw0_sel; + uint32_t qw4_dyn; + uint32_t qw4_ofs; + uint32_t sw8_dyn; + uint32_t sw8_ofs; + uint32_t sw8_sel; + uint32_t sw9_dyn; + uint32_t sw9_ofs; + uint32_t mask[10]; + uint32_t kid; + uint32_t opn; + uint32_t ipn; + uint32_t byt_dyn; + uint32_t byt_ofs; + uint32_t txplm; + uint32_t auto_ipv4_mask; +}; + +struct flm_v17_buf_ctrl_s { + uint32_t lrn_free; + uint32_t inf_avail; + uint32_t sta_avail; +}; + +#pragma pack(1) +struct flm_v17_lrn_data_s { + uint32_t sw9; /* 31:0 (32) */ + uint32_t sw8; /* 63:32 (32) */ + uint32_t qw4[4]; /* 191:64 (128) */ + uint32_t qw0[4]; /* 319:192 (128) */ + uint8_t prot; /* 327:320 (8) */ + uint8_t kid; /* 335:328 (8) */ + uint32_t nat_ip; /* 367:336 (32) */ + uint32_t teid; /* 399:368 (32) */ + uint16_t nat_port; /* 415:400 (16) */ + uint16_t rate; /* 431:416 (16) */ + uint16_t size; /* 447:432 (16) */ + uint32_t color; /* 479:448 (32) */ + uint32_t adj; /* 511:480 (32) */ + uint8_t id[9]; /* 583:512 (72) */ + uint16_t fill : 12; /* 595:584 (12) */ + uint16_t ft : 4; /* 599:596 (4) */ + uint8_t ft_mbr : 4; /* 603:600 (4) */ + uint8_t ft_miss : 4; /* 607:604 (5) */ + + /* 635:608, 663:636, 691:664, 719:692 (4 x 28) Get/set with macros FLM_V17_MBR_IDx */ + uint8_t mbr_idx[14]; + uint32_t vol_idx : 3; /* 722:720 (3) */ + uint32_t stat_prof : 4; /* 726:723 (4) */ + uint32_t prio : 2; /* 728:727 (2) */ + uint32_t ent : 1; /* 729:729 (1) */ + uint32_t op : 4; /* 733:730 (4) */ + uint32_t dscp : 6; /* 739:734 (6) */ + uint32_t qfi : 6; /* 745:740 (6) */ + uint32_t rqi : 1; /* 746:746 (1) */ + uint32_t nat_en : 1; /* 747:747 (1) */ + uint32_t pad0 : 4; /* 751:748 (4) */ + uint16_t pad1 : 15; /* 752:766 (15) */ + uint16_t eor : 1; /* 767:767 (1) */ +}; + +struct flm_v17_inf_data_s { + uint64_t bytes; + uint64_t packets; + uint64_t ts; + uint64_t id0; /* id0 and id1 results in a 72-bit int */ + uint32_t id1 : 8; + uint32_t cause : 3; + uint32_t pad : 20; + uint32_t eor : 1; +}; + +struct flm_v17_sta_data_s { + uint64_t id0; /* id0 and id1 results in a 72-bit int */ + uint32_t id1 : 8; + uint32_t lds : 1; + uint32_t lfs : 1; + uint32_t lis : 1; + uint32_t uds : 1; + uint32_t uis : 1; + uint32_t rds : 1; + uint32_t ris : 1; + uint32_t pds : 1; + uint32_t pis : 1; + uint32_t pad : 14; + uint32_t eor : 1; +}; + +#pragma pack() +struct flm_v17_stat_lrn_done_s { + uint32_t cnt; +}; + +struct flm_v17_stat_lrn_ignore_s { + uint32_t cnt; +}; + +struct flm_v17_stat_lrn_fail_s { + uint32_t cnt; +}; + +struct flm_v17_stat_unl_done_s { + uint32_t cnt; +}; + +struct flm_v17_stat_unl_ignore_s { + uint32_t cnt; +}; + +struct flm_v17_stat_rel_done_s { + uint32_t cnt; +}; + +struct flm_v17_stat_rel_ignore_s { + uint32_t cnt; +}; + +struct flm_v17_stat_aul_done_s { + uint32_t cnt; +}; + +struct flm_v17_stat_aul_ignore_s { + uint32_t cnt; +}; + +struct flm_v17_stat_aul_fail_s { + uint32_t cnt; +}; + +struct flm_v17_stat_tul_done_s { + uint32_t cnt; +}; + +struct flm_v17_stat_flows_s { + uint32_t cnt; +}; + +struct flm_v17_stat_prb_done_s { + uint32_t cnt; +}; + +struct flm_v17_stat_prb_ignore_s { + uint32_t cnt; +}; + +struct hw_mod_flm_v17_s { + struct flm_v17_control_s *control; + struct flm_v17_status_s *status; + struct flm_v17_timeout_s *timeout; + struct flm_v17_scrub_s *scrub; + struct flm_v17_load_bin_s *load_bin; + struct flm_v17_load_pps_s *load_pps; + struct flm_v17_load_lps_s *load_lps; + struct flm_v17_load_aps_s *load_aps; + struct flm_v17_prio_s *prio; + struct flm_v17_pst_s *pst; + struct flm_v17_rcp_s *rcp; + struct flm_v17_buf_ctrl_s *buf_ctrl; + /* lrn_data is not handled by struct */ + /* inf_data is not handled by struct */ + /* sta_data is not handled by struct */ + struct flm_v17_stat_lrn_done_s *lrn_done; + struct flm_v17_stat_lrn_ignore_s *lrn_ignore; + struct flm_v17_stat_lrn_fail_s *lrn_fail; + struct flm_v17_stat_unl_done_s *unl_done; + struct flm_v17_stat_unl_ignore_s *unl_ignore; + struct flm_v17_stat_rel_done_s *rel_done; + struct flm_v17_stat_rel_ignore_s *rel_ignore; + struct flm_v17_stat_aul_done_s *aul_done; + struct flm_v17_stat_aul_ignore_s *aul_ignore; + struct flm_v17_stat_aul_fail_s *aul_fail; + struct flm_v17_stat_tul_done_s *tul_done; + struct flm_v17_stat_flows_s *flows; + struct flm_v17_stat_prb_done_s *prb_done; + struct flm_v17_stat_prb_ignore_s *prb_ignore; +}; + +#endif /* _HW_MOD_FLM_V17_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm_v20.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm_v20.h new file mode 100644 index 0000000000..e33d4353c3 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm_v20.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_FLM_V20_H_ +#define _HW_MOD_FLM_V20_H_ + +struct flm_v20_stat_sta_done_s { + uint32_t cnt; +}; + +struct flm_v20_stat_inf_done_s { + uint32_t cnt; +}; + +struct flm_v20_stat_inf_skip_s { + uint32_t cnt; +}; + +struct flm_v20_stat_pck_hit_s { + uint32_t cnt; +}; + +struct flm_v20_stat_pck_miss_s { + uint32_t cnt; +}; + +struct flm_v20_stat_pck_unh_s { + uint32_t cnt; +}; + +struct flm_v20_stat_pck_dis_s { + uint32_t cnt; +}; + +struct flm_v20_stat_csh_hit_s { + uint32_t cnt; +}; + +struct flm_v20_stat_csh_miss_s { + uint32_t cnt; +}; + +struct flm_v20_stat_csh_unh_s { + uint32_t cnt; +}; + +struct flm_v20_stat_cuc_start_s { + uint32_t cnt; +}; + +struct flm_v20_stat_cuc_move_s { + uint32_t cnt; +}; + +struct hw_mod_flm_v20_s { + struct flm_v17_control_s *control; + struct flm_v17_status_s *status; + struct flm_v17_timeout_s *timeout; + struct flm_v17_scrub_s *scrub; + struct flm_v17_load_bin_s *load_bin; + struct flm_v17_load_pps_s *load_pps; + struct flm_v17_load_lps_s *load_lps; + struct flm_v17_load_aps_s *load_aps; + struct flm_v17_prio_s *prio; + struct flm_v17_pst_s *pst; + struct flm_v17_rcp_s *rcp; + struct flm_v17_buf_ctrl_s *buf_ctrl; + /* + * lrn_data is not handled by struct + * inf_data is not handled by struct + * sta_data is not handled by struct + */ + struct flm_v17_stat_lrn_done_s *lrn_done; + struct flm_v17_stat_lrn_ignore_s *lrn_ignore; + struct flm_v17_stat_lrn_fail_s *lrn_fail; + struct flm_v17_stat_unl_done_s *unl_done; + struct flm_v17_stat_unl_ignore_s *unl_ignore; + struct flm_v17_stat_rel_done_s *rel_done; + struct flm_v17_stat_rel_ignore_s *rel_ignore; + struct flm_v17_stat_aul_done_s *aul_done; + struct flm_v17_stat_aul_ignore_s *aul_ignore; + struct flm_v17_stat_aul_fail_s *aul_fail; + struct flm_v17_stat_tul_done_s *tul_done; + struct flm_v17_stat_flows_s *flows; + struct flm_v17_stat_prb_done_s *prb_done; + struct flm_v17_stat_prb_ignore_s *prb_ignore; + struct flm_v20_stat_sta_done_s *sta_done; + struct flm_v20_stat_inf_done_s *inf_done; + struct flm_v20_stat_inf_skip_s *inf_skip; + struct flm_v20_stat_pck_hit_s *pck_hit; + struct flm_v20_stat_pck_miss_s *pck_miss; + struct flm_v20_stat_pck_unh_s *pck_unh; + struct flm_v20_stat_pck_dis_s *pck_dis; + struct flm_v20_stat_csh_hit_s *csh_hit; + struct flm_v20_stat_csh_miss_s *csh_miss; + struct flm_v20_stat_csh_unh_s *csh_unh; + struct flm_v20_stat_cuc_start_s *cuc_start; + struct flm_v20_stat_cuc_move_s *cuc_move; +}; + +#endif /* _HW_MOD_FLM_V20_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hsh.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hsh.c new file mode 100644 index 0000000000..1b8896d5c2 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hsh.c @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include +#include "flow_api_backend.h" + +#define _MOD_ "HSH" +#define _VER_ be->hsh.ver + +#define HSH_RCP_ENTRIES_V4 16 +#define HSH_RCP_ENTRIES_V5 32 +#define HSH_RCP_MAC_PORT_MASK_SIZE 4 +#define HSH_RCP_WORD_MASK_SIZE 10 + +bool hw_mod_hsh_present(struct flow_api_backend_s *be) +{ + return be->iface->get_hsh_present(be->be_dev); +} + +int hw_mod_hsh_alloc(struct flow_api_backend_s *be) +{ + _VER_ = be->iface->get_hsh_version(be->be_dev); + NT_LOG(DBG, FILTER, "HSH MODULE VERSION %i.%i\n", VER_MAJOR(_VER_), + VER_MINOR(_VER_)); + + switch (_VER_) { + case 5: + be->hsh.nb_rcp = HSH_RCP_ENTRIES_V5; + if (!callocate_mod(CAST_COMMON(&be->hsh), 1, + &be->hsh.v5.rcp, + be->hsh.nb_rcp, + sizeof(struct hsh_v5_rcp_s))) + return -1; + break; + /* end case 5 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + return 0; +} + +void hw_mod_hsh_free(struct flow_api_backend_s *be) +{ + if (be->hsh.base) { + free(be->hsh.base); + be->hsh.base = NULL; + } +} + +int hw_mod_hsh_reset(struct flow_api_backend_s *be) +{ + /* Zero entire cache area */ + ZERO_MOD_CACHE(&be->hsh); + + NT_LOG(DBG, FILTER, "INIT HSH RCP\n"); + return hw_mod_hsh_rcp_flush(be, 0, be->hsh.nb_rcp); +} + +int hw_mod_hsh_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->hsh.nb_rcp; + if ((start_idx + count) > (int)be->hsh.nb_rcp) + return error_index_too_large(__func__); + return be->iface->hsh_rcp_flush(be->be_dev, &be->hsh, start_idx, count); +} + +static int hw_mod_hsh_rcp_mod(struct flow_api_backend_s *be, + enum hw_hsh_e field, uint32_t index, + uint32_t word_off, uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->hsh.nb_rcp) + return error_index_too_large(__func__); + switch (_VER_) { + case 5: + switch (field) { + case HW_HSH_RCP_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->hsh.v5.rcp[index], (uint8_t)*value, + sizeof(struct hsh_v5_rcp_s)); + break; + case HW_HSH_RCP_COMPARE: + rv = do_compare_indexes(be->hsh.v5.rcp, + sizeof(struct hsh_v5_rcp_s), index, word_off, + be->hsh.nb_rcp, get, __func__); + if (rv != 0) + return rv; + break; + case HW_HSH_RCP_FIND: + rv = find_equal_index(be->hsh.v5.rcp, + sizeof(struct hsh_v5_rcp_s), index, word_off, + be->hsh.nb_rcp, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_HSH_RCP_LOAD_DIST_TYPE: + get_set(&be->hsh.v5.rcp[index].load_dist_type, value, get); + break; + case HW_HSH_RCP_MAC_PORT_MASK: + if (word_off > HSH_RCP_MAC_PORT_MASK_SIZE) + return error_word_off_too_large(__func__); + get_set(&be->hsh.v5.rcp[index].mac_port_mask[word_off], + value, get); + break; + case HW_HSH_RCP_SORT: + get_set(&be->hsh.v5.rcp[index].sort, value, get); + break; + case HW_HSH_RCP_QW0_PE: + get_set(&be->hsh.v5.rcp[index].qw0_pe, value, get); + break; + case HW_HSH_RCP_QW0_OFS: + get_set_signed(&be->hsh.v5.rcp[index].qw0_ofs, value, get); + break; + case HW_HSH_RCP_QW4_PE: + get_set(&be->hsh.v5.rcp[index].qw4_pe, value, get); + break; + case HW_HSH_RCP_QW4_OFS: + get_set_signed(&be->hsh.v5.rcp[index].qw4_ofs, value, get); + break; + case HW_HSH_RCP_W8_PE: + get_set(&be->hsh.v5.rcp[index].w8_pe, value, get); + break; + case HW_HSH_RCP_W8_OFS: + get_set_signed(&be->hsh.v5.rcp[index].w8_ofs, value, get); + break; + case HW_HSH_RCP_W8_SORT: + get_set(&be->hsh.v5.rcp[index].w8_sort, value, get); + break; + case HW_HSH_RCP_W9_PE: + get_set(&be->hsh.v5.rcp[index].w9_pe, value, get); + break; + case HW_HSH_RCP_W9_OFS: + get_set_signed(&be->hsh.v5.rcp[index].w9_ofs, value, get); + break; + case HW_HSH_RCP_W9_SORT: + get_set(&be->hsh.v5.rcp[index].w9_sort, value, get); + break; + case HW_HSH_RCP_W9_P: + get_set(&be->hsh.v5.rcp[index].w9_p, value, get); + break; + case HW_HSH_RCP_P_MASK: + get_set(&be->hsh.v5.rcp[index].p_mask, value, get); + break; + case HW_HSH_RCP_WORD_MASK: + if (word_off > HSH_RCP_WORD_MASK_SIZE) + return error_word_off_too_large(__func__); + get_set(&be->hsh.v5.rcp[index].word_mask[word_off], + value, get); + break; + case HW_HSH_RCP_SEED: + get_set(&be->hsh.v5.rcp[index].seed, value, get); + break; + case HW_HSH_RCP_TNL_P: + get_set(&be->hsh.v5.rcp[index].tnl_p, value, get); + break; + case HW_HSH_RCP_HSH_VALID: + get_set(&be->hsh.v5.rcp[index].hsh_valid, value, get); + break; + case HW_HSH_RCP_HSH_TYPE: + get_set(&be->hsh.v5.rcp[index].hsh_type, value, get); + break; + case HW_HSH_RCP_AUTO_IPV4_MASK: + get_set(&be->hsh.v5.rcp[index].auto_ipv4_mask, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 5 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_hsh_rcp_set(struct flow_api_backend_s *be, enum hw_hsh_e field, + uint32_t index, uint32_t word_off, uint32_t value) +{ + return hw_mod_hsh_rcp_mod(be, field, index, word_off, &value, 0); +} + +int hw_mod_hsh_rcp_get(struct flow_api_backend_s *be, enum hw_hsh_e field, + uint32_t index, uint32_t word_off, uint32_t *value) +{ + return hw_mod_hsh_rcp_mod(be, field, index, word_off, value, 1); +} diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hsh_v5.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hsh_v5.h new file mode 100644 index 0000000000..8588750ff0 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hsh_v5.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_HSH_V5_H_ +#define _HW_MOD_HSH_V5_H_ + +struct hsh_v5_rcp_s { + uint32_t load_dist_type; + uint32_t mac_port_mask[4]; + uint32_t sort; + uint32_t qw0_pe; + int32_t qw0_ofs; + uint32_t qw4_pe; + int32_t qw4_ofs; + uint32_t w8_pe; + int32_t w8_ofs; + uint32_t w8_sort; + uint32_t w9_pe; + int32_t w9_ofs; + uint32_t w9_sort; + uint32_t w9_p; + uint32_t p_mask; + uint32_t word_mask[10]; + uint32_t seed; + uint32_t tnl_p; + uint32_t hsh_valid; + uint32_t hsh_type; + uint32_t auto_ipv4_mask; +}; + +struct hw_mod_hsh_v5_s { + struct hsh_v5_rcp_s *rcp; +}; + +#endif /* _HW_MOD_HSH_V5_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hst.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hst.c new file mode 100644 index 0000000000..751c7b3ffe --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hst.c @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include "flow_api_backend.h" + +#define _MOD_ "HST" +#define _VER_ be->hst.ver + +bool hw_mod_hst_present(struct flow_api_backend_s *be) +{ + return be->iface->get_hst_present(be->be_dev); +} + +int hw_mod_hst_alloc(struct flow_api_backend_s *be) +{ + int nb; + + _VER_ = be->iface->get_hst_version(be->be_dev); + NT_LOG(DBG, FILTER, "HST MODULE VERSION %i.%i\n", VER_MAJOR(_VER_), + VER_MINOR(_VER_)); + + nb = be->iface->get_nb_hst_categories(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "hst_categories", _MOD_, _VER_); + be->hst.nb_hst_rcp_categories = (uint32_t)nb; + + switch (_VER_) { + case 2: + if (!callocate_mod(CAST_COMMON(&be->hst), 1, + &be->hst.v2.rcp, + be->hst.nb_hst_rcp_categories, + sizeof(struct hst_v2_rcp_s))) + return -1; + break; + /* end case 2 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +void hw_mod_hst_free(struct flow_api_backend_s *be) +{ + if (be->hst.base) { + free(be->hst.base); + be->hst.base = NULL; + } +} + +int hw_mod_hst_reset(struct flow_api_backend_s *be) +{ + /* Zero entire cache area */ + ZERO_MOD_CACHE(&be->hst); + + NT_LOG(DBG, FILTER, "INIT HST RCP\n"); + return hw_mod_hst_rcp_flush(be, 0, ALL_ENTRIES); +} + +int hw_mod_hst_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->hst.nb_hst_rcp_categories; + if ((unsigned int)(start_idx + count) > be->hst.nb_hst_rcp_categories) + return error_index_too_large(__func__); + return be->iface->hst_rcp_flush(be->be_dev, &be->hst, start_idx, count); +} + +static int hw_mod_hst_rcp_mod(struct flow_api_backend_s *be, + enum hw_hst_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->hst.nb_hst_rcp_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 2: + switch (field) { + case HW_HST_RCP_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->hst.v2.rcp[index], (uint8_t)*value, + sizeof(struct hst_v2_rcp_s)); + break; + case HW_HST_RCP_FIND: + find_equal_index(be->hst.v2.rcp, + sizeof(struct hst_v2_rcp_s), index, *value, + be->hst.nb_hst_rcp_categories, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_HST_RCP_COMPARE: + rv = do_compare_indexes(be->hst.v2.rcp, + sizeof(struct hst_v2_rcp_s), index, *value, + be->hst.nb_hst_rcp_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_HST_RCP_STRIP_MODE: + get_set(&be->hst.v2.rcp[index].strip_mode, value, get); + break; + case HW_HST_RCP_START_DYN: + get_set(&be->hst.v2.rcp[index].start_dyn, value, get); + break; + case HW_HST_RCP_START_OFS: + get_set(&be->hst.v2.rcp[index].start_ofs, value, get); + break; + case HW_HST_RCP_END_DYN: + get_set(&be->hst.v2.rcp[index].end_dyn, value, get); + break; + case HW_HST_RCP_END_OFS: + get_set(&be->hst.v2.rcp[index].end_ofs, value, get); + break; + case HW_HST_RCP_MODIF0_CMD: + get_set(&be->hst.v2.rcp[index].modif0_cmd, value, get); + break; + case HW_HST_RCP_MODIF0_DYN: + get_set(&be->hst.v2.rcp[index].modif0_dyn, value, get); + break; + case HW_HST_RCP_MODIF0_OFS: + get_set(&be->hst.v2.rcp[index].modif0_ofs, value, get); + break; + case HW_HST_RCP_MODIF0_VALUE: + get_set(&be->hst.v2.rcp[index].modif0_value, value, get); + break; + case HW_HST_RCP_MODIF1_CMD: + get_set(&be->hst.v2.rcp[index].modif1_cmd, value, get); + break; + case HW_HST_RCP_MODIF1_DYN: + get_set(&be->hst.v2.rcp[index].modif1_dyn, value, get); + break; + case HW_HST_RCP_MODIF1_OFS: + get_set(&be->hst.v2.rcp[index].modif1_ofs, value, get); + break; + case HW_HST_RCP_MODIF1_VALUE: + get_set(&be->hst.v2.rcp[index].modif1_value, value, get); + break; + case HW_HST_RCP_MODIF2_CMD: + get_set(&be->hst.v2.rcp[index].modif2_cmd, value, get); + break; + case HW_HST_RCP_MODIF2_DYN: + get_set(&be->hst.v2.rcp[index].modif2_dyn, value, get); + break; + case HW_HST_RCP_MODIF2_OFS: + get_set(&be->hst.v2.rcp[index].modif2_ofs, value, get); + break; + case HW_HST_RCP_MODIF2_VALUE: + get_set(&be->hst.v2.rcp[index].modif2_value, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 2 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_hst_rcp_set(struct flow_api_backend_s *be, enum hw_hst_e field, + int index, uint32_t value) +{ + return hw_mod_hst_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_hst_rcp_get(struct flow_api_backend_s *be, enum hw_hst_e field, + int index, uint32_t *value) +{ + return hw_mod_hst_rcp_mod(be, field, index, value, 1); +} diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hst_v2.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hst_v2.h new file mode 100644 index 0000000000..230c70b56d --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hst_v2.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_HST_V2_H_ +#define _HW_MOD_HST_V2_H_ + +struct hst_v2_rcp_s { + uint32_t strip_mode; + uint32_t start_dyn; + uint32_t start_ofs; + uint32_t end_dyn; + uint32_t end_ofs; + uint32_t modif0_cmd; + uint32_t modif0_dyn; + uint32_t modif0_ofs; + uint32_t modif0_value; + uint32_t modif1_cmd; + uint32_t modif1_dyn; + uint32_t modif1_ofs; + uint32_t modif1_value; + uint32_t modif2_cmd; + uint32_t modif2_dyn; + uint32_t modif2_ofs; + uint32_t modif2_value; +}; + +struct hw_mod_hst_v2_s { + struct hst_v2_rcp_s *rcp; +}; + +#endif /* _HW_MOD_HST_V2_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_ioa.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_ioa.c new file mode 100644 index 0000000000..c8e3593637 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_ioa.c @@ -0,0 +1,271 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include +#include "flow_api_backend.h" + +#define _MOD_ "IOA" +#define _VER_ be->ioa.ver + +bool hw_mod_ioa_present(struct flow_api_backend_s *be) +{ + return be->iface->get_ioa_present(be->be_dev); +} + +int hw_mod_ioa_alloc(struct flow_api_backend_s *be) +{ + _VER_ = be->iface->get_ioa_version(be->be_dev); + NT_LOG(DBG, FILTER, "IOA MODULE VERSION %i.%i\n", VER_MAJOR(_VER_), + VER_MINOR(_VER_)); + + int nb = be->iface->get_nb_ioa_categories(be->be_dev); + + if (nb <= 0) + return error_resource_count(__func__, "ioa_categories", _MOD_, _VER_); + be->ioa.nb_rcp_categories = (uint32_t)nb; + + /* NOTE: ROA number of categories are called here. FPGA uses a cross-indexing here - bad! */ + nb = be->iface->get_nb_roa_categories(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "roa_epp_entries", _MOD_, _VER_); + be->ioa.nb_roa_epp_entries = (uint32_t)nb; + + switch (_VER_) { + case 4: + if (!callocate_mod(CAST_COMMON(&be->ioa), 3, + &be->ioa.v4.rcp, be->ioa.nb_rcp_categories, + sizeof(struct ioa_v4_rcp_s), + &be->ioa.v4.tpid, 1, + sizeof(struct ioa_v4_special_tpid_s), + &be->ioa.v4.roa_epp, be->ioa.nb_roa_epp_entries, + sizeof(struct ioa_v4_roa_epp_s))) + return -1; + break; + /* end case 4 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + return 0; +} + +void hw_mod_ioa_free(struct flow_api_backend_s *be) +{ + if (be->ioa.base) { + free(be->ioa.base); + be->ioa.base = NULL; + } +} + +int hw_mod_ioa_reset(struct flow_api_backend_s *be) +{ + /* Zero entire cache area */ + ZERO_MOD_CACHE(&be->ioa); + + NT_LOG(DBG, FILTER, "INIT IOA RCP\n"); + hw_mod_ioa_rcp_flush(be, 0, ALL_ENTRIES); + NT_LOG(DBG, FILTER, "INIT IOA SPECIAL TPID\n"); + hw_mod_ioa_config_set(be, HW_IOA_CONFIG_CUST_TPID_0, 0x8200); + hw_mod_ioa_config_set(be, HW_IOA_CONFIG_CUST_TPID_1, 0x8300); + hw_mod_ioa_config_flush(be); + NT_LOG(DBG, FILTER, "INIT IOA ROA EPP\n"); + hw_mod_ioa_roa_epp_flush(be, 0, ALL_ENTRIES); + return 0; +} + +int hw_mod_ioa_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->ioa.nb_rcp_categories; + if ((unsigned int)(start_idx + count) > be->ioa.nb_rcp_categories) + return error_index_too_large(__func__); + return be->iface->ioa_rcp_flush(be->be_dev, &be->ioa, start_idx, count); +} + +static int hw_mod_ioa_rcp_mod(struct flow_api_backend_s *be, + enum hw_ioa_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->ioa.nb_rcp_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 4: + switch (field) { + case HW_IOA_RCP_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->ioa.v4.rcp[index], (uint8_t)*value, + sizeof(struct ioa_v4_rcp_s)); + break; + case HW_IOA_RCP_FIND: + rv = find_equal_index(be->ioa.v4.rcp, + sizeof(struct ioa_v4_rcp_s), index, *value, + be->ioa.nb_rcp_categories, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_IOA_RCP_COMPARE: + rv = do_compare_indexes(be->ioa.v4.rcp, + sizeof(struct ioa_v4_rcp_s), index, *value, + be->ioa.nb_rcp_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_IOA_RCP_TUNNEL_POP: + get_set(&be->ioa.v4.rcp[index].tunnel_pop, value, get); + break; + case HW_IOA_RCP_VLAN_POP: + get_set(&be->ioa.v4.rcp[index].vlan_pop, value, get); + break; + case HW_IOA_RCP_VLAN_PUSH: + get_set(&be->ioa.v4.rcp[index].vlan_push, value, get); + break; + case HW_IOA_RCP_VLAN_VID: + get_set(&be->ioa.v4.rcp[index].vlan_vid, value, get); + break; + case HW_IOA_RCP_VLAN_DEI: + get_set(&be->ioa.v4.rcp[index].vlan_dei, value, get); + break; + case HW_IOA_RCP_VLAN_PCP: + get_set(&be->ioa.v4.rcp[index].vlan_pcp, value, get); + break; + case HW_IOA_RCP_VLAN_TPID_SEL: + get_set(&be->ioa.v4.rcp[index].vlan_tpid_sel, value, get); + break; + case HW_IOA_RCP_QUEUE_OVERRIDE_EN: + get_set(&be->ioa.v4.rcp[index].queue_override_en, value, get); + break; + case HW_IOA_RCP_QUEUE_ID: + get_set(&be->ioa.v4.rcp[index].queue_id, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 4 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_ioa_rcp_set(struct flow_api_backend_s *be, enum hw_ioa_e field, + uint32_t index, uint32_t value) +{ + return hw_mod_ioa_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_ioa_rcp_get(struct flow_api_backend_s *be, enum hw_ioa_e field, + uint32_t index, uint32_t *value) +{ + return hw_mod_ioa_rcp_mod(be, field, index, value, 1); +} + +int hw_mod_ioa_config_flush(struct flow_api_backend_s *be) +{ + return be->iface->ioa_special_tpid_flush(be->be_dev, &be->ioa); +} + +int hw_mod_ioa_config_set(struct flow_api_backend_s *be, enum hw_ioa_e field, + uint32_t value) +{ + switch (_VER_) { + case 4: + switch (field) { + case HW_IOA_CONFIG_CUST_TPID_0: + be->ioa.v4.tpid->cust_tpid_0 = value; + break; + case HW_IOA_CONFIG_CUST_TPID_1: + be->ioa.v4.tpid->cust_tpid_1 = value; + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 4 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_ioa_roa_epp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->ioa.nb_roa_epp_entries; + if ((unsigned int)(start_idx + count) > be->ioa.nb_roa_epp_entries) + return error_index_too_large(__func__); + return be->iface->ioa_roa_epp_flush(be->be_dev, &be->ioa, start_idx, + count); +} + +static int hw_mod_ioa_roa_epp_mod(struct flow_api_backend_s *be, + enum hw_ioa_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->ioa.nb_roa_epp_entries) + return error_index_too_large(__func__); + switch (_VER_) { + case 4: + switch (field) { + case HW_IOA_ROA_EPP_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->ioa.v4.roa_epp[index], (uint8_t)*value, + sizeof(struct ioa_v4_roa_epp_s)); + break; + case HW_IOA_ROA_EPP_FIND: + rv = find_equal_index(be->ioa.v4.roa_epp, + sizeof(struct ioa_v4_roa_epp_s), index, *value, + be->ioa.nb_roa_epp_entries, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_IOA_ROA_EPP_COMPARE: + rv = do_compare_indexes(be->ioa.v4.roa_epp, + sizeof(struct ioa_v4_roa_epp_s), index, *value, + be->ioa.nb_roa_epp_entries, get, __func__); + if (rv != 0) + return rv; + break; + case HW_IOA_ROA_EPP_PUSH_TUNNEL: + get_set(&be->ioa.v4.roa_epp[index].push_tunnel, value, get); + break; + case HW_IOA_ROA_EPP_TX_PORT: + get_set(&be->ioa.v4.roa_epp[index].tx_port, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 4 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_ioa_roa_epp_set(struct flow_api_backend_s *be, enum hw_ioa_e field, + uint32_t index, uint32_t value) +{ + return hw_mod_ioa_roa_epp_mod(be, field, index, &value, 0); +} + +int hw_mod_ioa_roa_epp_get(struct flow_api_backend_s *be, enum hw_ioa_e field, + uint32_t index, uint32_t *value) +{ + return hw_mod_ioa_roa_epp_mod(be, field, index, value, 1); +} diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_ioa_v4.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_ioa_v4.h new file mode 100644 index 0000000000..309b53ff76 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_ioa_v4.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_IOA_V4_H_ +#define _HW_MOD_IOA_V4_H_ + +struct ioa_v4_rcp_s { + uint32_t tunnel_pop; + uint32_t vlan_pop; + uint32_t vlan_push; + uint32_t vlan_vid; + uint32_t vlan_dei; + uint32_t vlan_pcp; + uint32_t vlan_tpid_sel; + uint32_t queue_override_en; + uint32_t queue_id; +}; + +struct ioa_v4_special_tpid_s { + uint32_t cust_tpid_0; + uint32_t cust_tpid_1; +}; + +struct ioa_v4_roa_epp_s { + uint32_t push_tunnel; + uint32_t tx_port; +}; + +struct hw_mod_ioa_v4_s { + struct ioa_v4_rcp_s *rcp; + struct ioa_v4_special_tpid_s *tpid; + struct ioa_v4_roa_epp_s *roa_epp; +}; + +#endif /* _HW_MOD_IOA_V4_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_km.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_km.c new file mode 100644 index 0000000000..a91f0e0a7d --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_km.c @@ -0,0 +1,629 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include +#include "flow_api_backend.h" + +#define _MOD_ "KM" +#define _VER_ be->km.ver + +#define KM_TCQ_ENTRIES 2048 +#define KM_RCP_MASK_A_SIZE 11 +#define KM_RCP_MASK_D_A_SIZE \ + 12 /* Mask for double size word extractors for DW8/DW10 */ +#define KM_RCP_MASK_B_SIZE 6 + +bool hw_mod_km_present(struct flow_api_backend_s *be) +{ + return be->iface->get_km_present(be->be_dev); +} + +int hw_mod_km_alloc(struct flow_api_backend_s *be) +{ + int nb; + + _VER_ = be->iface->get_km_version(be->be_dev); + NT_LOG(DBG, FILTER, "KM MODULE VERSION %i.%i\n", VER_MAJOR(_VER_), + VER_MINOR(_VER_)); + + nb = be->iface->get_nb_km_categories(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "km_categories", _MOD_, _VER_); + be->km.nb_categories = (uint32_t)nb; + + nb = be->iface->get_nb_km_cam_banks(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "cam_banks", _MOD_, _VER_); + be->km.nb_cam_banks = (uint32_t)nb; + + nb = be->iface->get_nb_km_cam_records(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "cam_records", _MOD_, _VER_); + be->km.nb_cam_records = (uint32_t)nb; + + nb = be->iface->get_nb_km_cam_record_words(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "cam_record_words", _MOD_, _VER_); + be->km.nb_cam_record_words = (uint32_t)nb; + + nb = be->iface->get_nb_km_tcam_banks(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "tcam_banks", _MOD_, _VER_); + be->km.nb_tcam_banks = (uint32_t)nb; + + nb = be->iface->get_nb_km_tcam_bank_width(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "tcam_bank_width", _MOD_, _VER_); + be->km.nb_tcam_bank_width = (uint32_t)nb; + + switch (_VER_) { + case 7: + be->km.nb_km_rcp_mask_a_word_size = 12; + be->km.nb_km_rcp_mask_b_word_size = 6; + if (!callocate_mod(CAST_COMMON(&be->km), 5, + &be->km.v7.rcp, + be->km.nb_categories, + sizeof(struct km_v7_rcp_s), + &be->km.v7.cam, + be->km.nb_cam_banks * be->km.nb_cam_records, + sizeof(struct km_v7_cam_s), + &be->km.v7.tcam, + be->km.nb_tcam_banks * 4 * 256, + sizeof(struct km_v7_tcam_s), + &be->km.v7.tci, + be->km.nb_tcam_banks * be->km.nb_tcam_bank_width, + sizeof(struct km_v7_tci_s), + &be->km.v7.tcq, + KM_TCQ_ENTRIES, + sizeof(struct km_v7_tcq_s))) + return -1; + break; + /* end case 7 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +void hw_mod_km_free(struct flow_api_backend_s *be) +{ + if (be->km.base) { + free(be->km.base); + be->km.base = NULL; + } +} + +int hw_mod_km_reset(struct flow_api_backend_s *be) +{ + uint32_t tcam_v_set[3] = { 0x00000000, 0x00000000, 0x00000000 }; + /* int err = 0; */ + + /* Zero entire cache area */ + ZERO_MOD_CACHE(&be->km); + + NT_LOG(DBG, FILTER, "INIT KM RCP\n"); + hw_mod_km_rcp_flush(be, 0, ALL_ENTRIES); + + /* init CAM - all zero */ + NT_LOG(DBG, FILTER, "INIT KM CAM\n"); + hw_mod_km_cam_flush(be, 0, 0, ALL_ENTRIES); + + /* init TCAM - all zero */ + NT_LOG(DBG, FILTER, "INIT KM TCAM\n"); + for (unsigned int i = 0; i < be->km.nb_tcam_banks; i++) { + /* + * TCAM entries are cache controlled, thus need to hard reset initially to sync + * cache with HW + */ + hw_mod_km_tcam_set(be, HW_KM_TCAM_BANK_RESET, i, 0, 0, + tcam_v_set); + } + hw_mod_km_tcam_flush(be, 0, ALL_ENTRIES); + + /* init TCI - all zero */ + NT_LOG(DBG, FILTER, "INIT KM TCI\n"); + hw_mod_km_tci_flush(be, 0, 0, ALL_ENTRIES); + + NT_LOG(DBG, FILTER, "INIT KM TCQ\n"); + for (unsigned int i = 0; i < be->km.nb_tcam_bank_width; i++) + hw_mod_km_tcq_flush(be, 0, i, be->km.nb_tcam_banks); + + return 0; +} + +int hw_mod_km_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count) +{ + if (count == ALL_ENTRIES) + count = be->km.nb_categories; + if ((unsigned int)(start_idx + count) > be->km.nb_categories) + return error_index_too_large(__func__); + return be->iface->km_rcp_flush(be->be_dev, &be->km, start_idx, count); +} + +static int hw_mod_km_rcp_mod(struct flow_api_backend_s *be, enum hw_km_e field, + int index, int word_off, uint32_t *value, int get) +{ + if ((unsigned int)index >= be->km.nb_categories) + return error_index_too_large(__func__); + + switch (_VER_) { + case 7: + switch (field) { + case HW_KM_RCP_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->km.v7.rcp[index], (uint8_t)*value, + sizeof(struct km_v7_rcp_s)); + break; + case HW_KM_RCP_QW0_DYN: + get_set(&be->km.v7.rcp[index].qw0_dyn, value, get); + break; + case HW_KM_RCP_QW0_OFS: + get_set_signed(&be->km.v7.rcp[index].qw0_ofs, value, get); + break; + case HW_KM_RCP_QW0_SEL_A: + get_set(&be->km.v7.rcp[index].qw0_sel_a, value, get); + break; + case HW_KM_RCP_QW0_SEL_B: + get_set(&be->km.v7.rcp[index].qw0_sel_b, value, get); + break; + case HW_KM_RCP_QW4_DYN: + get_set(&be->km.v7.rcp[index].qw4_dyn, value, get); + break; + case HW_KM_RCP_QW4_OFS: + get_set_signed(&be->km.v7.rcp[index].qw4_ofs, value, get); + break; + case HW_KM_RCP_QW4_SEL_A: + get_set(&be->km.v7.rcp[index].qw4_sel_a, value, get); + break; + case HW_KM_RCP_QW4_SEL_B: + get_set(&be->km.v7.rcp[index].qw4_sel_b, value, get); + break; + case HW_KM_RCP_DW8_DYN: + get_set(&be->km.v7.rcp[index].dw8_dyn, value, get); + break; + case HW_KM_RCP_DW8_OFS: + get_set_signed(&be->km.v7.rcp[index].dw8_ofs, value, get); + break; + case HW_KM_RCP_DW8_SEL_A: + get_set(&be->km.v7.rcp[index].dw8_sel_a, value, get); + break; + case HW_KM_RCP_DW8_SEL_B: + get_set(&be->km.v7.rcp[index].dw8_sel_b, value, get); + break; + case HW_KM_RCP_DW10_DYN: + get_set(&be->km.v7.rcp[index].dw10_dyn, value, get); + break; + case HW_KM_RCP_DW10_OFS: + get_set_signed(&be->km.v7.rcp[index].dw10_ofs, value, get); + break; + case HW_KM_RCP_DW10_SEL_A: + get_set(&be->km.v7.rcp[index].dw10_sel_a, value, get); + break; + case HW_KM_RCP_DW10_SEL_B: + get_set(&be->km.v7.rcp[index].dw10_sel_b, value, get); + break; + case HW_KM_RCP_SWX_CCH: + get_set(&be->km.v7.rcp[index].swx_cch, value, get); + break; + case HW_KM_RCP_SWX_SEL_A: + get_set(&be->km.v7.rcp[index].swx_sel_a, value, get); + break; + case HW_KM_RCP_SWX_SEL_B: + get_set(&be->km.v7.rcp[index].swx_sel_b, value, get); + break; + case HW_KM_RCP_MASK_A: + if (word_off > KM_RCP_MASK_D_A_SIZE) + return error_word_off_too_large(__func__); + get_set(&be->km.v7.rcp[index].mask_d_a[word_off], value, get); + break; + case HW_KM_RCP_MASK_B: + if (word_off > KM_RCP_MASK_B_SIZE) + return error_word_off_too_large(__func__); + get_set(&be->km.v7.rcp[index].mask_b[word_off], value, get); + break; + case HW_KM_RCP_DUAL: + get_set(&be->km.v7.rcp[index].dual, value, get); + break; + case HW_KM_RCP_PAIRED: + get_set(&be->km.v7.rcp[index].paired, value, get); + break; + case HW_KM_RCP_EL_A: + get_set(&be->km.v7.rcp[index].el_a, value, get); + break; + case HW_KM_RCP_EL_B: + get_set(&be->km.v7.rcp[index].el_b, value, get); + break; + case HW_KM_RCP_INFO_A: + get_set(&be->km.v7.rcp[index].info_a, value, get); + break; + case HW_KM_RCP_INFO_B: + get_set(&be->km.v7.rcp[index].info_b, value, get); + break; + case HW_KM_RCP_FTM_A: + get_set(&be->km.v7.rcp[index].ftm_a, value, get); + break; + case HW_KM_RCP_FTM_B: + get_set(&be->km.v7.rcp[index].ftm_b, value, get); + break; + case HW_KM_RCP_BANK_A: + get_set(&be->km.v7.rcp[index].bank_a, value, get); + break; + case HW_KM_RCP_BANK_B: + get_set(&be->km.v7.rcp[index].bank_b, value, get); + break; + case HW_KM_RCP_KL_A: + get_set(&be->km.v7.rcp[index].kl_a, value, get); + break; + case HW_KM_RCP_KL_B: + get_set(&be->km.v7.rcp[index].kl_b, value, get); + break; + case HW_KM_RCP_KEYWAY_A: + get_set(&be->km.v7.rcp[index].keyway_a, value, get); + break; + case HW_KM_RCP_KEYWAY_B: + get_set(&be->km.v7.rcp[index].keyway_b, value, get); + break; + case HW_KM_RCP_SYNERGY_MODE: + get_set(&be->km.v7.rcp[index].synergy_mode, value, get); + break; + case HW_KM_RCP_DW0_B_DYN: + get_set(&be->km.v7.rcp[index].dw0_b_dyn, value, get); + break; + case HW_KM_RCP_DW0_B_OFS: + get_set_signed(&be->km.v7.rcp[index].dw0_b_ofs, value, get); + break; + case HW_KM_RCP_DW2_B_DYN: + get_set(&be->km.v7.rcp[index].dw2_b_dyn, value, get); + break; + case HW_KM_RCP_DW2_B_OFS: + get_set_signed(&be->km.v7.rcp[index].dw2_b_ofs, value, get); + break; + case HW_KM_RCP_SW4_B_DYN: + get_set(&be->km.v7.rcp[index].sw4_b_dyn, value, get); + break; + case HW_KM_RCP_SW4_B_OFS: + get_set_signed(&be->km.v7.rcp[index].sw4_b_ofs, value, get); + break; + case HW_KM_RCP_SW5_B_DYN: + get_set(&be->km.v7.rcp[index].sw5_b_dyn, value, get); + break; + case HW_KM_RCP_SW5_B_OFS: + get_set_signed(&be->km.v7.rcp[index].sw5_b_ofs, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 7 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_km_rcp_set(struct flow_api_backend_s *be, enum hw_km_e field, + int index, int word_off, uint32_t value) +{ + return hw_mod_km_rcp_mod(be, field, index, word_off, &value, 0); +} + +int hw_mod_km_rcp_get(struct flow_api_backend_s *be, enum hw_km_e field, + int index, int word_off, uint32_t *value) +{ + return hw_mod_km_rcp_mod(be, field, index, word_off, value, 1); +} + +int hw_mod_km_cam_flush(struct flow_api_backend_s *be, int start_bank, + int start_record, int count) +{ + if (count == ALL_ENTRIES) + count = be->km.nb_cam_records * be->km.nb_cam_banks; + + unsigned int end = + start_bank * be->km.nb_cam_records + start_record + count; + if (end > (be->km.nb_cam_banks * be->km.nb_cam_records)) + return error_index_too_large(__func__); + + return be->iface->km_cam_flush(be->be_dev, &be->km, start_bank, + start_record, count); +} + +static int hw_mod_km_cam_mod(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t *value, int get) +{ + if ((unsigned int)bank >= be->km.nb_cam_banks) + return error_index_too_large(__func__); + if ((unsigned int)record >= be->km.nb_cam_records) + return error_index_too_large(__func__); + + unsigned int index = bank * be->km.nb_cam_records + record; + + switch (_VER_) { + case 7: + switch (field) { + case HW_KM_CAM_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->km.v7.cam[index], (uint8_t)*value, + sizeof(struct km_v7_cam_s)); + break; + case HW_KM_CAM_W0: + get_set(&be->km.v7.cam[index].w0, value, get); + break; + case HW_KM_CAM_W1: + get_set(&be->km.v7.cam[index].w1, value, get); + break; + case HW_KM_CAM_W2: + get_set(&be->km.v7.cam[index].w2, value, get); + break; + case HW_KM_CAM_W3: + get_set(&be->km.v7.cam[index].w3, value, get); + break; + case HW_KM_CAM_W4: + get_set(&be->km.v7.cam[index].w4, value, get); + break; + case HW_KM_CAM_W5: + get_set(&be->km.v7.cam[index].w5, value, get); + break; + case HW_KM_CAM_FT0: + get_set(&be->km.v7.cam[index].ft0, value, get); + break; + case HW_KM_CAM_FT1: + get_set(&be->km.v7.cam[index].ft1, value, get); + break; + case HW_KM_CAM_FT2: + get_set(&be->km.v7.cam[index].ft2, value, get); + break; + case HW_KM_CAM_FT3: + get_set(&be->km.v7.cam[index].ft3, value, get); + break; + case HW_KM_CAM_FT4: + get_set(&be->km.v7.cam[index].ft4, value, get); + break; + case HW_KM_CAM_FT5: + get_set(&be->km.v7.cam[index].ft5, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 7 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + return 0; +} + +int hw_mod_km_cam_set(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t value) +{ + return hw_mod_km_cam_mod(be, field, bank, record, &value, 0); +} + +int hw_mod_km_cam_get(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t *value) +{ + return hw_mod_km_cam_mod(be, field, bank, record, value, 1); +} + +int hw_mod_km_tcam_flush(struct flow_api_backend_s *be, int start_bank, + int count) +{ + if (count == ALL_ENTRIES) + count = be->km.nb_tcam_banks * 4 * 256; + else if (count == ALL_BANK_ENTRIES) + count = 4 * 256; + + unsigned int end = start_bank * 4 * 256 + count; + + if (end > (be->km.nb_tcam_banks * 4 * 256)) + return error_index_too_large(__func__); + + return be->iface->km_tcam_flush(be->be_dev, &be->km, start_bank, 0, 0, + count); +} + +static int hw_mod_km_tcam_mod(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int byte, int byte_val, + uint32_t *value_set, int get) +{ + unsigned int start_index = bank * 4 * 256 + (int)byte * 256 + byte_val; + + if (start_index >= (be->km.nb_tcam_banks * 4 * 256)) + return error_index_too_large(__func__); + + switch (_VER_) { + case 7: + switch (field) { + case HW_KM_TCAM_BANK_RESET: + if (get) + return error_unsup_field(__func__); + { + int start_idx = bank * 4 * 256; + + for (int i = 0; i < 4 * 256; i++) { + be->km.v7.tcam[start_idx + i].t[0] = + value_set[0]; + be->km.v7.tcam[start_idx + i].t[1] = + value_set[1]; + be->km.v7.tcam[start_idx + i].t[2] = + value_set[2]; + be->km.v7.tcam[start_idx + i].dirty = 1; + } + } + break; + case HW_KM_TCAM_T: { + int index = bank * 4 * 256 + byte * 256 + byte_val; + + if (get) { + value_set[0] = be->km.v7.tcam[index].t[0]; + value_set[1] = be->km.v7.tcam[index].t[1]; + value_set[2] = be->km.v7.tcam[index].t[2]; + } else { + /* only change if any bits has to be changed */ + if (be->km.v7.tcam[index].t[0] != + value_set[0] || + be->km.v7.tcam[index].t[1] != + value_set[1] || + be->km.v7.tcam[index].t[2] != + value_set[2]) { + be->km.v7.tcam[index].t[0] = + value_set[0]; + be->km.v7.tcam[index].t[1] = + value_set[1]; + be->km.v7.tcam[index].t[2] = + value_set[2]; + be->km.v7.tcam[index].dirty = 1; + } + } + } + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 7 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + return 0; +} + +int hw_mod_km_tcam_set(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int byte, int byte_val, uint32_t *value_set) +{ + return hw_mod_km_tcam_mod(be, field, bank, byte, byte_val, value_set, + 0); +} + +int hw_mod_km_tcam_get(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int byte, int byte_val, uint32_t *value_set) +{ + return hw_mod_km_tcam_mod(be, field, bank, byte, byte_val, value_set, + 1); +} + +int hw_mod_km_tci_flush(struct flow_api_backend_s *be, int start_bank, + int start_record, int count) +{ + if (count == ALL_ENTRIES) + count = be->km.nb_tcam_banks * be->km.nb_tcam_bank_width; + + unsigned int end = (int)start_bank * be->km.nb_tcam_bank_width + + start_record + count; + + if (end > (be->km.nb_tcam_banks * be->km.nb_tcam_bank_width)) + return error_index_too_large(__func__); + + return be->iface->km_tci_flush(be->be_dev, &be->km, start_bank, + start_record, count); +} + +static int hw_mod_km_tci_mod(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t *value, int get) +{ + unsigned int index = bank * be->km.nb_tcam_bank_width + record; + + if (index >= (be->km.nb_tcam_banks * be->km.nb_tcam_bank_width)) + return error_index_too_large(__func__); + + switch (_VER_) { + case 7: + switch (field) { + case HW_KM_TCI_COLOR: + get_set(&be->km.v7.tci[index].color, value, get); + break; + case HW_KM_TCI_FT: + get_set(&be->km.v7.tci[index].ft, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 7 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + return 0; +} + +int hw_mod_km_tci_set(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t value) +{ + return hw_mod_km_tci_mod(be, field, bank, record, &value, 0); +} + +int hw_mod_km_tci_get(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t *value) +{ + return hw_mod_km_tci_mod(be, field, bank, record, value, 1); +} + +int hw_mod_km_tcq_flush(struct flow_api_backend_s *be, int start_bank, + int start_record, int count) +{ + if (count == ALL_ENTRIES) + count = be->km.nb_tcam_banks * be->km.nb_tcam_bank_width; + + unsigned int end = (int)start_bank * be->km.nb_tcam_bank_width + + start_record + count; + + if (end > (be->km.nb_tcam_banks * be->km.nb_tcam_bank_width)) + return error_index_too_large(__func__); + + return be->iface->km_tcq_flush(be->be_dev, &be->km, start_bank, + start_record, count); +} + +static int hw_mod_km_tcq_mod(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t *value, int get) +{ + unsigned int index = bank * be->km.nb_tcam_bank_width + record; + + if (index >= (be->km.nb_tcam_banks * be->km.nb_tcam_bank_width)) + return error_index_too_large(__func__); + + switch (_VER_) { + case 7: + switch (field) { + case HW_KM_TCQ_BANK_MASK: + get_set(&be->km.v7.tcq[index].bank_mask, value, get); + break; + case HW_KM_TCQ_QUAL: + get_set(&be->km.v7.tcq[index].qual, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 7 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + return 0; +} + +int hw_mod_km_tcq_set(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t *value) +{ + return hw_mod_km_tcq_mod(be, field, bank, record, value, 0); +} + +int hw_mod_km_tcq_get(struct flow_api_backend_s *be, enum hw_km_e field, + int bank, int record, uint32_t *value) +{ + return hw_mod_km_tcq_mod(be, field, bank, record, value, 1); +} diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_km_v7.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_km_v7.h new file mode 100644 index 0000000000..798a175609 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_km_v7.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_KM_V7_H_ +#define _HW_MOD_KM_V7_H_ + +struct km_v7_rcp_s { + uint32_t qw0_dyn; + int32_t qw0_ofs; + uint32_t qw0_sel_a; + uint32_t qw0_sel_b; + uint32_t qw4_dyn; + int32_t qw4_ofs; + uint32_t qw4_sel_a; + uint32_t qw4_sel_b; + uint32_t dw8_dyn; + int32_t dw8_ofs; + uint32_t dw8_sel_a; + uint32_t dw8_sel_b; + uint32_t dw10_dyn; + int32_t dw10_ofs; + uint32_t dw10_sel_a; + uint32_t dw10_sel_b; + uint32_t swx_cch; + uint32_t swx_sel_a; + uint32_t swx_sel_b; + uint32_t mask_d_a[12]; + uint32_t mask_b[6]; + uint32_t dual; + uint32_t paired; + uint32_t el_a; + uint32_t el_b; + uint32_t info_a; + uint32_t info_b; + uint32_t ftm_a; + uint32_t ftm_b; + uint32_t bank_a; + uint32_t bank_b; + uint32_t kl_a; + uint32_t kl_b; + uint32_t keyway_a; + uint32_t keyway_b; + uint32_t synergy_mode; + uint32_t dw0_b_dyn; + int32_t dw0_b_ofs; + uint32_t dw2_b_dyn; + int32_t dw2_b_ofs; + uint32_t sw4_b_dyn; + int32_t sw4_b_ofs; + uint32_t sw5_b_dyn; + int32_t sw5_b_ofs; +}; + +struct km_v7_cam_s { + uint32_t w0; + uint32_t w1; + uint32_t w2; + uint32_t w3; + uint32_t w4; + uint32_t w5; + uint32_t ft0; + uint32_t ft1; + uint32_t ft2; + uint32_t ft3; + uint32_t ft4; + uint32_t ft5; +}; + +struct km_v7_tcam_s { + uint32_t t[3]; + uint32_t dirty; +}; + +struct km_v7_tci_s { + uint32_t color; + uint32_t ft; +}; + +struct km_v7_tcq_s { + uint32_t bank_mask; + uint32_t qual; +}; + +struct hw_mod_km_v7_s { + struct km_v7_rcp_s *rcp; + struct km_v7_cam_s *cam; + struct km_v7_tcam_s *tcam; + struct km_v7_tci_s *tci; + struct km_v7_tcq_s *tcq; +}; + +#endif /* _HW_MOD_KM_V7_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_pdb.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_pdb.c new file mode 100644 index 0000000000..8d0d70cae2 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_pdb.c @@ -0,0 +1,219 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include +#include "flow_api_backend.h" + +#define _MOD_ "PDB" +#define _VER_ be->pdb.ver + +bool hw_mod_pdb_present(struct flow_api_backend_s *be) +{ + return be->iface->get_pdb_present(be->be_dev); +} + +int hw_mod_pdb_alloc(struct flow_api_backend_s *be) +{ + int nb; + + _VER_ = be->iface->get_pdb_version(be->be_dev); + NT_LOG(DBG, FILTER, "PDB MODULE VERSION %i.%i\n", VER_MAJOR(_VER_), + VER_MINOR(_VER_)); + + nb = be->iface->get_nb_pdb_categories(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "pdb_categories", _MOD_, _VER_); + be->pdb.nb_pdb_rcp_categories = (uint32_t)nb; + + switch (_VER_) { + case 9: + if (!callocate_mod(CAST_COMMON(&be->pdb), 2, + &be->pdb.v9.rcp, + be->pdb.nb_pdb_rcp_categories, + sizeof(struct pdb_v9_rcp_s), + &be->pdb.v9.config, + 1, + sizeof(struct pdb_v9_config_s))) + return -1; + break; + /* end case 9 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + return 0; +} + +void hw_mod_pdb_free(struct flow_api_backend_s *be) +{ + if (be->pdb.base) { + free(be->pdb.base); + be->pdb.base = NULL; + } +} + +int hw_mod_pdb_reset(struct flow_api_backend_s *be) +{ + int err = 0; + /* Zero entire cache area */ + ZERO_MOD_CACHE(&be->pdb); + + NT_LOG(DBG, FILTER, "INIT PDB RCP\n"); + err |= hw_mod_pdb_rcp_flush(be, 0, ALL_ENTRIES); + + NT_LOG(DBG, FILTER, "INIT PDB CONFIG\n"); + err |= hw_mod_pdb_config_flush(be); + return err; +} + +int hw_mod_pdb_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->pdb.nb_pdb_rcp_categories; + if ((unsigned int)(start_idx + count) > be->pdb.nb_pdb_rcp_categories) + return error_index_too_large(__func__); + return be->iface->pdb_rcp_flush(be->be_dev, &be->pdb, start_idx, count); +} + +static int hw_mod_pdb_rcp_mod(struct flow_api_backend_s *be, + enum hw_pdb_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->pdb.nb_pdb_rcp_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 9: + switch (field) { + case HW_PDB_RCP_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->pdb.v9.rcp[index], (uint8_t)*value, + sizeof(struct pdb_v9_rcp_s)); + break; + case HW_PDB_RCP_FIND: + rv = find_equal_index(be->pdb.v9.rcp, + sizeof(struct pdb_v9_rcp_s), index, *value, + be->pdb.nb_pdb_rcp_categories, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_PDB_RCP_COMPARE: + rv = do_compare_indexes(be->pdb.v9.rcp, + sizeof(struct pdb_v9_rcp_s), index, *value, + be->pdb.nb_pdb_rcp_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_PDB_RCP_DESCRIPTOR: + get_set(&be->pdb.v9.rcp[index].descriptor, value, get); + break; + case HW_PDB_RCP_DESC_LEN: + get_set(&be->pdb.v9.rcp[index].desc_len, value, get); + break; + case HW_PDB_RCP_TX_PORT: + get_set(&be->pdb.v9.rcp[index].tx_port, value, get); + break; + case HW_PDB_RCP_TX_IGNORE: + get_set(&be->pdb.v9.rcp[index].tx_ignore, value, get); + break; + case HW_PDB_RCP_TX_NOW: + get_set(&be->pdb.v9.rcp[index].tx_now, value, get); + break; + case HW_PDB_RCP_CRC_OVERWRITE: + get_set(&be->pdb.v9.rcp[index].crc_overwrite, value, get); + break; + case HW_PDB_RCP_ALIGN: + get_set(&be->pdb.v9.rcp[index].align, value, get); + break; + case HW_PDB_RCP_OFS0_DYN: + get_set(&be->pdb.v9.rcp[index].ofs0_dyn, value, get); + break; + case HW_PDB_RCP_OFS0_REL: + get_set_signed(&be->pdb.v9.rcp[index].ofs0_rel, value, get); + break; + case HW_PDB_RCP_OFS1_DYN: + get_set(&be->pdb.v9.rcp[index].ofs1_dyn, value, get); + break; + case HW_PDB_RCP_OFS1_REL: + get_set_signed(&be->pdb.v9.rcp[index].ofs1_rel, value, get); + break; + case HW_PDB_RCP_OFS2_DYN: + get_set(&be->pdb.v9.rcp[index].ofs2_dyn, value, get); + break; + case HW_PDB_RCP_OFS2_REL: + get_set_signed(&be->pdb.v9.rcp[index].ofs2_rel, value, get); + break; + case HW_PDB_RCP_IP_PROT_TNL: + get_set(&be->pdb.v9.rcp[index].ip_prot_tnl, value, get); + break; + case HW_PDB_RCP_PPC_HSH: + get_set(&be->pdb.v9.rcp[index].ppc_hsh, value, get); + break; + case HW_PDB_RCP_DUPLICATE_EN: + get_set(&be->pdb.v9.rcp[index].duplicate_en, value, get); + break; + case HW_PDB_RCP_DUPLICATE_BIT: + get_set(&be->pdb.v9.rcp[index].duplicate_bit, value, get); + break; + case HW_PDB_RCP_PCAP_KEEP_FCS: + get_set(&be->pdb.v9.rcp[index].pcap_keep_fcs, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 9 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_pdb_rcp_set(struct flow_api_backend_s *be, enum hw_pdb_e field, + uint32_t index, uint32_t value) +{ + return hw_mod_pdb_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_pdb_rcp_get(struct flow_api_backend_s *be, enum hw_pdb_e field, + uint32_t index, uint32_t *value) +{ + return hw_mod_pdb_rcp_mod(be, field, index, value, 1); +} + +int hw_mod_pdb_config_flush(struct flow_api_backend_s *be) +{ + return be->iface->pdb_config_flush(be->be_dev, &be->pdb); +} + +int hw_mod_pdb_config_set(struct flow_api_backend_s *be, enum hw_pdb_e field, + uint32_t value) +{ + switch (_VER_) { + case 9: + switch (field) { + case HW_PDB_CONFIG_TS_FORMAT: + be->pdb.v9.config->ts_format = value; + break; + case HW_PDB_CONFIG_PORT_OFS: + be->pdb.v9.config->port_ofs = value; + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 9 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_pdb_v9.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_pdb_v9.h new file mode 100644 index 0000000000..b14c10bc53 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_pdb_v9.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_PDB_V9_H_ +#define _HW_MOD_PDB_V9_H_ + +struct pdb_v9_rcp_s { + uint32_t descriptor; + uint32_t desc_len; + uint32_t tx_port; + uint32_t tx_ignore; + uint32_t tx_now; + uint32_t crc_overwrite; + uint32_t align; + uint32_t ofs0_dyn; + int32_t ofs0_rel; + uint32_t ofs1_dyn; + int32_t ofs1_rel; + uint32_t ofs2_dyn; + int32_t ofs2_rel; + uint32_t ip_prot_tnl; + uint32_t ppc_hsh; + uint32_t duplicate_en; + uint32_t duplicate_bit; + uint32_t pcap_keep_fcs; /* only field added to v9 cmp to v7/8 */ +}; + +struct pdb_v9_config_s { + uint32_t ts_format; + uint32_t port_ofs; +}; + +struct hw_mod_pdb_v9_s { + struct pdb_v9_rcp_s *rcp; + struct pdb_v9_config_s *config; +}; + +#endif /* _HW_MOD_PDB_V9_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_qsl.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_qsl.c new file mode 100644 index 0000000000..86d23ea683 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_qsl.c @@ -0,0 +1,348 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include +#include "flow_api_backend.h" + +#define _MOD_ "QSL" +#define _VER_ be->qsl.ver + +#define QSL_QEN_ENTRIES 32 +#define QSL_QNMQ_ENTRIES 256 + +bool hw_mod_qsl_present(struct flow_api_backend_s *be) +{ + return be->iface->get_qsl_present(be->be_dev); +} + +int hw_mod_qsl_alloc(struct flow_api_backend_s *be) +{ + int nb; + + _VER_ = be->iface->get_qsl_version(be->be_dev); + NT_LOG(DBG, FILTER, "QSL MODULE VERSION %i.%i\n", VER_MAJOR(_VER_), + VER_MINOR(_VER_)); + + nb = be->iface->get_nb_qsl_categories(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "qsl_categories", _MOD_, _VER_); + be->qsl.nb_rcp_categories = (uint32_t)nb; + + nb = be->iface->get_nb_qsl_qst_entries(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "qsl_qst_entries", _MOD_, _VER_); + be->qsl.nb_qst_entries = (uint32_t)nb; + + switch (_VER_) { + case 7: + if (!callocate_mod(CAST_COMMON(&be->qsl), 4, + &be->qsl.v7.rcp, + be->qsl.nb_rcp_categories, + sizeof(struct qsl_v7_rcp_s), + &be->qsl.v7.qst, + be->qsl.nb_qst_entries, + sizeof(struct qsl_v7_qst_s), + &be->qsl.v7.qen, + QSL_QEN_ENTRIES, + sizeof(struct qsl_v7_qen_s), + &be->qsl.v7.unmq, + QSL_QNMQ_ENTRIES, + sizeof(struct qsl_v7_unmq_s))) + return -1; + break; + /* end case 7 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + return 0; +} + +void hw_mod_qsl_free(struct flow_api_backend_s *be) +{ + if (be->qsl.base) { + free(be->qsl.base); + be->qsl.base = NULL; + } +} + +int hw_mod_qsl_reset(struct flow_api_backend_s *be) +{ + /* Zero entire cache area */ + ZERO_MOD_CACHE(&be->qsl); + + NT_LOG(DBG, FILTER, "INIT QSL RCP\n"); + hw_mod_qsl_rcp_flush(be, 0, ALL_ENTRIES); + + NT_LOG(DBG, FILTER, "INIT QSL QST\n"); + hw_mod_qsl_qst_flush(be, 0, ALL_ENTRIES); + + NT_LOG(DBG, FILTER, "INIT QSL QEN\n"); + hw_mod_qsl_qen_flush(be, 0, ALL_ENTRIES); + + NT_LOG(DBG, FILTER, "INIT QSL UNMQ\n"); + be->iface->qsl_unmq_flush(be->be_dev, &be->qsl, 0, 256); + + return 0; +} + +int hw_mod_qsl_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->qsl.nb_rcp_categories; + if ((unsigned int)(start_idx + count) > be->qsl.nb_rcp_categories) + return error_index_too_large(__func__); + return be->iface->qsl_rcp_flush(be->be_dev, &be->qsl, start_idx, count); +} + +static int hw_mod_qsl_rcp_mod(struct flow_api_backend_s *be, + enum hw_qsl_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->qsl.nb_rcp_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 7: + switch (field) { + case HW_QSL_RCP_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->qsl.v7.rcp[index], (uint8_t)*value, + sizeof(struct qsl_v7_rcp_s)); + break; + case HW_QSL_RCP_FIND: + rv = find_equal_index(be->qsl.v7.rcp, + sizeof(struct qsl_v7_rcp_s), index, *value, + be->qsl.nb_rcp_categories, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_QSL_RCP_COMPARE: + rv = do_compare_indexes(be->qsl.v7.rcp, + sizeof(struct qsl_v7_rcp_s), index, *value, + be->qsl.nb_rcp_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_QSL_RCP_DISCARD: + get_set(&be->qsl.v7.rcp[index].discard, value, get); + break; + case HW_QSL_RCP_DROP: + get_set(&be->qsl.v7.rcp[index].drop, value, get); + break; + case HW_QSL_RCP_TBL_LO: + get_set(&be->qsl.v7.rcp[index].tbl_lo, value, get); + break; + case HW_QSL_RCP_TBL_HI: + get_set(&be->qsl.v7.rcp[index].tbl_hi, value, get); + break; + case HW_QSL_RCP_TBL_IDX: + get_set(&be->qsl.v7.rcp[index].tbl_idx, value, get); + break; + case HW_QSL_RCP_TBL_MSK: + get_set(&be->qsl.v7.rcp[index].tbl_msk, value, get); + break; + case HW_QSL_RCP_LR: + get_set(&be->qsl.v7.rcp[index].lr, value, get); + break; + case HW_QSL_RCP_TSA: + get_set(&be->qsl.v7.rcp[index].tsa, value, get); + break; + case HW_QSL_RCP_VLI: + get_set(&be->qsl.v7.rcp[index].vli, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 7 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_qsl_rcp_set(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t value) +{ + return hw_mod_qsl_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_qsl_rcp_get(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t *value) +{ + return hw_mod_qsl_rcp_mod(be, field, index, value, 1); +} + +int hw_mod_qsl_qst_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->qsl.nb_qst_entries; + if ((unsigned int)(start_idx + count) > be->qsl.nb_qst_entries) + return error_index_too_large(__func__); + return be->iface->qsl_qst_flush(be->be_dev, &be->qsl, start_idx, count); +} + +static int hw_mod_qsl_qst_mod(struct flow_api_backend_s *be, + enum hw_qsl_e field, uint32_t index, + uint32_t *value, int get) +{ + if (index >= be->qsl.nb_qst_entries) + return error_index_too_large(__func__); + switch (_VER_) { + case 7: + switch (field) { + case HW_QSL_QST_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->qsl.v7.qst[index], (uint8_t)*value, + sizeof(struct qsl_v7_qst_s)); + break; + case HW_QSL_QST_QUEUE: + get_set(&be->qsl.v7.qst[index].queue, value, get); + break; + case HW_QSL_QST_EN: + get_set(&be->qsl.v7.qst[index].en, value, get); + break; + case HW_QSL_QST_TX_PORT: + get_set(&be->qsl.v7.qst[index].tx_port, value, get); + break; + case HW_QSL_QST_LRE: + get_set(&be->qsl.v7.qst[index].lre, value, get); + break; + case HW_QSL_QST_TCI: + get_set(&be->qsl.v7.qst[index].tci, value, get); + break; + case HW_QSL_QST_VEN: + get_set(&be->qsl.v7.qst[index].ven, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 7 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_qsl_qst_set(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t value) +{ + return hw_mod_qsl_qst_mod(be, field, index, &value, 0); +} + +int hw_mod_qsl_qst_get(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t *value) +{ + return hw_mod_qsl_qst_mod(be, field, index, value, 1); +} + +int hw_mod_qsl_qen_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = QSL_QEN_ENTRIES; + if ((start_idx + count) > QSL_QEN_ENTRIES) + return error_index_too_large(__func__); + return be->iface->qsl_qen_flush(be->be_dev, &be->qsl, start_idx, count); +} + +static int hw_mod_qsl_qen_mod(struct flow_api_backend_s *be, + enum hw_qsl_e field, uint32_t index, + uint32_t *value, int get) +{ + if (index >= QSL_QEN_ENTRIES) + return error_index_too_large(__func__); + switch (_VER_) { + case 7: + switch (field) { + case HW_QSL_QEN_EN: + get_set(&be->qsl.v7.qen[index].en, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 7 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_qsl_qen_set(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t value) +{ + return hw_mod_qsl_qen_mod(be, field, index, &value, 0); +} + +int hw_mod_qsl_qen_get(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t *value) +{ + return hw_mod_qsl_qen_mod(be, field, index, value, 1); +} + +int hw_mod_qsl_unmq_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = QSL_QNMQ_ENTRIES; + if ((start_idx + count) > QSL_QNMQ_ENTRIES) + return error_index_too_large(__func__); + return be->iface->qsl_unmq_flush(be->be_dev, &be->qsl, start_idx, + count); +} + +static int hw_mod_qsl_unmq_mod(struct flow_api_backend_s *be, + enum hw_qsl_e field, uint32_t index, + uint32_t *value, int get) +{ + if (index >= QSL_QNMQ_ENTRIES) + return error_index_too_large(__func__); + switch (_VER_) { + case 7: + switch (field) { + case HW_QSL_UNMQ_DEST_QUEUE: + get_set(&be->qsl.v7.unmq[index].dest_queue, value, get); + break; + case HW_QSL_UNMQ_EN: + get_set(&be->qsl.v7.unmq[index].en, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 7 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_qsl_unmq_set(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t value) +{ + return hw_mod_qsl_unmq_mod(be, field, index, &value, 0); +} + +int hw_mod_qsl_unmq_get(struct flow_api_backend_s *be, enum hw_qsl_e field, + uint32_t index, uint32_t *value) +{ + return hw_mod_qsl_unmq_mod(be, field, index, value, 1); +} diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_qsl_v7.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_qsl_v7.h new file mode 100644 index 0000000000..747da4bc43 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_qsl_v7.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_QSL_V7_H_ +#define _HW_MOD_QSL_V7_H_ + +struct qsl_v7_rcp_s { + uint32_t discard; + uint32_t drop; + uint32_t tbl_lo; + uint32_t tbl_hi; + uint32_t tbl_idx; + uint32_t tbl_msk; + uint32_t lr; + uint32_t tsa; + uint32_t vli; +}; + +struct qsl_v7_qst_s { + uint32_t queue; + uint32_t en; + uint32_t tx_port; + uint32_t lre; + uint32_t tci; + uint32_t ven; +}; + +struct qsl_v7_qen_s { + uint32_t en; +}; + +struct qsl_v7_unmq_s { + uint32_t dest_queue; + uint32_t en; +}; + +struct hw_mod_qsl_v7_s { + struct qsl_v7_rcp_s *rcp; + struct qsl_v7_qst_s *qst; + struct qsl_v7_qen_s *qen; + struct qsl_v7_unmq_s *unmq; +}; + +#endif /* _HW_MOD_QSL_V7_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_rmc.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_rmc.c new file mode 100644 index 0000000000..7f1d695a90 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_rmc.c @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include "flow_api_backend.h" + +#define _MOD_ "RMC" +#define _VER_ be->rmc.ver + +bool hw_mod_rmc_present(struct flow_api_backend_s *be) +{ + return be->iface->get_rmc_present(be->be_dev); +} + +int hw_mod_rmc_alloc(struct flow_api_backend_s *be) +{ + _VER_ = be->iface->get_rmc_version(be->be_dev); + NT_LOG(DBG, FILTER, "RMC MODULE VERSION %i.%i\n", VER_MAJOR(_VER_), + VER_MINOR(_VER_)); + + switch (_VER_) { + case 0x10003: + if (!callocate_mod(CAST_COMMON(&be->rmc), 1, + &be->rmc.v1_3.ctrl, 1, sizeof(struct rmc_v1_3_ctrl_s))) + return -1; + break; + /* end case 1_3 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +void hw_mod_rmc_free(struct flow_api_backend_s *be) +{ + if (be->rmc.base) { + free(be->rmc.base); + be->rmc.base = NULL; + } +} + +int hw_mod_rmc_reset(struct flow_api_backend_s *be) +{ + /* Zero entire cache area */ + ZERO_MOD_CACHE(&be->rmc); + + NT_LOG(DBG, FILTER, "INIT RMC CTRL\n"); + /* disable block stat, block keep alive */ + hw_mod_rmc_ctrl_set(be, HW_RMC_BLOCK_STATT, 1); + hw_mod_rmc_ctrl_set(be, HW_RMC_BLOCK_KEEPA, 1); + hw_mod_rmc_ctrl_set(be, HW_RMC_BLOCK_MAC_PORT, + 0xff); /* initially block all ports */ + hw_mod_rmc_ctrl_set(be, HW_RMC_BLOCK_STATT, 1); + hw_mod_rmc_ctrl_set(be, HW_RMC_BLOCK_RPP_SLICE, 0xf); + return hw_mod_rmc_ctrl_flush(be); +} + +int hw_mod_rmc_ctrl_flush(struct flow_api_backend_s *be) +{ + return be->iface->rmc_ctrl_flush(be->be_dev, &be->rmc); +} + +static int hw_mod_rmc_ctrl_mod(struct flow_api_backend_s *be, + enum hw_rmc_e field, uint32_t *value, int get) +{ + switch (_VER_) { + case 0x10003: + switch (field) { + case HW_RMC_BLOCK_STATT: + get_set(&be->rmc.v1_3.ctrl->block_statt, value, get); + break; + case HW_RMC_BLOCK_KEEPA: + get_set(&be->rmc.v1_3.ctrl->block_keepa, value, get); + break; + case HW_RMC_BLOCK_RPP_SLICE: + get_set(&be->rmc.v1_3.ctrl->block_rpp_slice, value, get); + break; + case HW_RMC_BLOCK_MAC_PORT: + get_set(&be->rmc.v1_3.ctrl->block_mac_port, value, get); + break; + case HW_RMC_LAG_PHY_ODD_EVEN: + get_set(&be->rmc.v1_3.ctrl->lag_phy_odd_even, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 1.3 */ + + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_rmc_ctrl_set(struct flow_api_backend_s *be, enum hw_rmc_e field, + uint32_t value) +{ + return hw_mod_rmc_ctrl_mod(be, field, &value, 0); +} + +int hw_mod_rmc_ctrl_get(struct flow_api_backend_s *be, enum hw_rmc_e field, + uint32_t *value) +{ + return hw_mod_rmc_ctrl_mod(be, field, value, 1); +} diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_rmc_v1_3.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_rmc_v1_3.h new file mode 100644 index 0000000000..8f90695821 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_rmc_v1_3.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_RMC_V1_3_H_ +#define _HW_MOD_RMC_V1_3_H_ + +struct rmc_v1_3_ctrl_s { + uint32_t block_statt; + uint32_t block_keepa; + uint32_t block_rpp_slice; + uint32_t block_mac_port; + uint32_t lag_phy_odd_even; +}; + +struct hw_mod_rmc_v1_3_s { + struct rmc_v1_3_ctrl_s *ctrl; +}; + +#endif /* _HW_MOD_RMC_V1_3_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_roa.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_roa.c new file mode 100644 index 0000000000..933caf9fd5 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_roa.c @@ -0,0 +1,358 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include +#include "flow_api_backend.h" + +#define _MOD_ "ROA" +#define _VER_ be->roa.ver + +#define ROA_LAGCFG_ENTRIES 512 + +bool hw_mod_roa_present(struct flow_api_backend_s *be) +{ + return be->iface->get_roa_present(be->be_dev); +} + +int hw_mod_roa_alloc(struct flow_api_backend_s *be) +{ + int nb; + + _VER_ = be->iface->get_roa_version(be->be_dev); + NT_LOG(DBG, FILTER, "ROA MODULE VERSION %i.%i\n", VER_MAJOR(_VER_), + VER_MINOR(_VER_)); + + nb = be->iface->get_nb_roa_categories(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "roa_categories", _MOD_, _VER_); + be->roa.nb_tun_categories = (uint32_t)nb; + + be->roa.nb_tun_categories /= 4; + + switch (_VER_) { + case 6: + be->roa.nb_lag_entries = ROA_LAGCFG_ENTRIES; + if (!callocate_mod(CAST_COMMON(&be->roa), 4, + &be->roa.v6.tunhdr, + be->roa.nb_tun_categories, + sizeof(struct roa_v6_tunhdr_s), + &be->roa.v6.tuncfg, + be->roa.nb_tun_categories, + sizeof(struct roa_v6_tuncfg_s), + &be->roa.v6.config, + 1, + sizeof(struct roa_v6_config_s), + &be->roa.v6.lagcfg, + be->roa.nb_lag_entries, + sizeof(struct roa_v6_lagcfg_s))) + return -1; + break; + /* end case 6 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + return 0; +} + +void hw_mod_roa_free(struct flow_api_backend_s *be) +{ + if (be->roa.base) { + free(be->roa.base); + be->roa.base = NULL; + } +} + +int hw_mod_roa_reset(struct flow_api_backend_s *be) +{ + int err = 0; + + /* Zero entire cache area */ + ZERO_MOD_CACHE(&be->roa); + + NT_LOG(DBG, FILTER, "INIT ROA TUNHDR\n"); + err = hw_mod_roa_tunhdr_flush(be, 0, ALL_ENTRIES); + + NT_LOG(DBG, FILTER, "INIT ROA TUNCFG\n"); + hw_mod_roa_tuncfg_flush(be, 0, ALL_ENTRIES); + + NT_LOG(DBG, FILTER, "INIT ROA CONFIG\n"); + hw_mod_roa_config_set(be, HW_ROA_CONFIG_FWD_RECIRCULATE, 1); + hw_mod_roa_config_set(be, HW_ROA_CONFIG_FWD_NORMAL_PCKS, 1); + hw_mod_roa_config_set(be, HW_ROA_CONFIG_FWD_TXPORT0, 1); + hw_mod_roa_config_set(be, HW_ROA_CONFIG_FWD_TXPORT1, 1); + hw_mod_roa_config_flush(be); + + NT_LOG(DBG, FILTER, "INIT ROA LAGCFG\n"); + hw_mod_roa_lagcfg_flush(be, 0, ALL_ENTRIES); + + return err; +} + +int hw_mod_roa_tunhdr_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->roa.nb_tun_categories; + if ((unsigned int)(start_idx + count) > be->roa.nb_tun_categories) + return error_index_too_large(__func__); + return be->iface->roa_tunhdr_flush(be->be_dev, &be->roa, start_idx, + count); +} + +static int hw_mod_roa_tunhdr_mod(struct flow_api_backend_s *be, + enum hw_roa_e field, uint32_t index, + uint32_t word_off, uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->roa.nb_tun_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 6: + switch (field) { + case HW_ROA_TUNHDR_COMPARE: + rv = do_compare_indexes(be->roa.v6.tunhdr, + sizeof(struct roa_v6_tunhdr_s), index, word_off, + be->roa.nb_tun_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_ROA_TUNHDR: + get_set(&be->roa.v6.tunhdr[index].tunnel_hdr[word_off], + value, get); + break; + default: + return error_unsup_field(__func__); + } + break; + /* end case 6 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_roa_tunhdr_set(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t index, uint32_t word_off, uint32_t value) +{ + return hw_mod_roa_tunhdr_mod(be, field, index, word_off, &value, 0); +} + +int hw_mod_roa_tunhdr_get(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t index, uint32_t word_off, uint32_t *value) +{ + return hw_mod_roa_tunhdr_mod(be, field, index, word_off, value, 1); +} + +int hw_mod_roa_tuncfg_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->roa.nb_tun_categories; + if ((unsigned int)(start_idx + count) > be->roa.nb_tun_categories) + return error_index_too_large(__func__); + return be->iface->roa_tuncfg_flush(be->be_dev, &be->roa, start_idx, + count); +} + +static int hw_mod_roa_tuncfg_mod(struct flow_api_backend_s *be, + enum hw_roa_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->roa.nb_tun_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 6: + switch (field) { + case HW_ROA_TUNCFG_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->roa.v6.tuncfg[index], (uint8_t)*value, + sizeof(struct roa_v6_tuncfg_s)); + break; + case HW_ROA_TUNCFG_FIND: + rv = find_equal_index(be->roa.v6.tuncfg, + sizeof(struct roa_v6_tuncfg_s), index, *value, + be->roa.nb_tun_categories, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_ROA_TUNCFG_COMPARE: + rv = do_compare_indexes(be->roa.v6.tuncfg, + sizeof(struct roa_v6_tuncfg_s), index, *value, + be->roa.nb_tun_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_ROA_TUNCFG_TUN_LEN: + get_set(&be->roa.v6.tuncfg[index].tun_len, value, get); + break; + case HW_ROA_TUNCFG_TUN_TYPE: + get_set(&be->roa.v6.tuncfg[index].tun_type, value, get); + break; + case HW_ROA_TUNCFG_TUN_VLAN: + get_set(&be->roa.v6.tuncfg[index].tun_vlan, value, get); + break; + case HW_ROA_TUNCFG_IP_TYPE: + get_set(&be->roa.v6.tuncfg[index].ip_type, value, get); + break; + case HW_ROA_TUNCFG_IPCS_UPD: + get_set(&be->roa.v6.tuncfg[index].ipcs_upd, value, get); + break; + case HW_ROA_TUNCFG_IPCS_PRECALC: + get_set(&be->roa.v6.tuncfg[index].ipcs_precalc, value, get); + break; + case HW_ROA_TUNCFG_IPTL_UPD: + get_set(&be->roa.v6.tuncfg[index].iptl_upd, value, get); + break; + case HW_ROA_TUNCFG_IPTL_PRECALC: + get_set(&be->roa.v6.tuncfg[index].iptl_precalc, value, get); + break; + case HW_ROA_TUNCFG_VXLAN_UDP_LEN_UPD: + get_set(&be->roa.v6.tuncfg[index].vxlan_udp_len_upd, + value, get); + break; + case HW_ROA_TUNCFG_TX_LAG_IX: + get_set(&be->roa.v6.tuncfg[index].tx_lag_ix, value, get); + break; + case HW_ROA_TUNCFG_RECIRCULATE: + get_set(&be->roa.v6.tuncfg[index].recirculate, value, get); + break; + case HW_ROA_TUNCFG_PUSH_TUNNEL: + get_set(&be->roa.v6.tuncfg[index].push_tunnel, value, get); + break; + case HW_ROA_TUNCFG_RECIRC_PORT: + get_set(&be->roa.v6.tuncfg[index].recirc_port, value, get); + break; + case HW_ROA_TUNCFG_RECIRC_BYPASS: + get_set(&be->roa.v6.tuncfg[index].recirc_bypass, value, get); + break; + default: + return error_unsup_field(__func__); + } + break; + /* end case 6 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_roa_tuncfg_set(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t index, uint32_t value) +{ + return hw_mod_roa_tuncfg_mod(be, field, index, &value, 0); +} + +int hw_mod_roa_tuncfg_get(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t index, uint32_t *value) +{ + return hw_mod_roa_tuncfg_mod(be, field, index, value, 1); +} + +int hw_mod_roa_config_flush(struct flow_api_backend_s *be) +{ + return be->iface->roa_config_flush(be->be_dev, &be->roa); +} + +static int hw_mod_roa_config_mod(struct flow_api_backend_s *be, + enum hw_roa_e field, uint32_t *value, int get) +{ + switch (_VER_) { + case 6: + switch (field) { + case HW_ROA_CONFIG_FWD_RECIRCULATE: + get_set(&be->roa.v6.config->fwd_recirculate, value, get); + break; + case HW_ROA_CONFIG_FWD_NORMAL_PCKS: + get_set(&be->roa.v6.config->fwd_normal_pcks, value, get); + break; + case HW_ROA_CONFIG_FWD_TXPORT0: + get_set(&be->roa.v6.config->fwd_txport0, value, get); + break; + case HW_ROA_CONFIG_FWD_TXPORT1: + get_set(&be->roa.v6.config->fwd_txport1, value, get); + break; + case HW_ROA_CONFIG_FWD_CELLBUILDER_PCKS: + get_set(&be->roa.v6.config->fwd_cellbuilder_pcks, value, get); + break; + case HW_ROA_CONFIG_FWD_NON_NORMAL_PCKS: + get_set(&be->roa.v6.config->fwd_non_normal_pcks, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 6 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_roa_config_set(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t value) +{ + return hw_mod_roa_config_mod(be, field, &value, 0); +} + +int hw_mod_roa_config_get(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t *value) +{ + return hw_mod_roa_config_mod(be, field, value, 1); +} + +int hw_mod_roa_lagcfg_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->roa.nb_lag_entries; + if ((unsigned int)(start_idx + count) > be->roa.nb_lag_entries) + return error_index_too_large(__func__); + return be->iface->roa_lagcfg_flush(be->be_dev, &be->roa, start_idx, + count); +} + +static int hw_mod_roa_lagcfg_mod(struct flow_api_backend_s *be, + enum hw_roa_e field, uint32_t index, + uint32_t *value, int get) +{ + if (index >= be->roa.nb_lag_entries) + return error_index_too_large(__func__); + switch (_VER_) { + case 6: + switch (field) { + case HW_ROA_LAGCFG_TXPHY_PORT: + get_set(&be->roa.v6.lagcfg[index].txphy_port, value, get); + break; + default: + return error_unsup_field(__func__); + } + break; + /* end case 6 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_roa_lagcfg_set(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t index, uint32_t value) +{ + return hw_mod_roa_lagcfg_mod(be, field, index, &value, 0); +} + +int hw_mod_roa_lagcfg_get(struct flow_api_backend_s *be, enum hw_roa_e field, + uint32_t index, uint32_t *value) +{ + return hw_mod_roa_lagcfg_mod(be, field, index, value, 1); +} diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_roa_v6.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_roa_v6.h new file mode 100644 index 0000000000..9930c52428 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_roa_v6.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_ROA_V6_H_ +#define _HW_MOD_ROA_V6_H_ + +struct roa_v6_tunhdr_s { + uint32_t tunnel_hdr[4 * 4]; +}; + +struct roa_v6_tuncfg_s { + uint32_t tun_len; + uint32_t tun_type; + uint32_t tun_vlan; + uint32_t ip_type; + uint32_t ipcs_upd; + uint32_t ipcs_precalc; + uint32_t iptl_upd; + uint32_t iptl_precalc; + uint32_t vxlan_udp_len_upd; + uint32_t tx_lag_ix; + uint32_t recirculate; + uint32_t push_tunnel; + uint32_t recirc_port; + uint32_t recirc_bypass; +}; + +struct roa_v6_config_s { + uint32_t fwd_recirculate; + uint32_t fwd_normal_pcks; + uint32_t fwd_txport0; + uint32_t fwd_txport1; + uint32_t fwd_cellbuilder_pcks; + uint32_t fwd_non_normal_pcks; +}; + +struct roa_v6_lagcfg_s { + uint32_t txphy_port; +}; + +struct hw_mod_roa_v6_s { + struct roa_v6_tunhdr_s *tunhdr; + struct roa_v6_tuncfg_s *tuncfg; + struct roa_v6_config_s *config; + struct roa_v6_lagcfg_s *lagcfg; +}; + +#endif /* _HW_MOD_ROA_V6_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc.c new file mode 100644 index 0000000000..ca65db7232 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc.c @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include "flow_api_backend.h" + +#define _MOD_ "SLC" +#define _VER_ be->slc.ver + +bool hw_mod_slc_present(struct flow_api_backend_s *be) +{ + return be->iface->get_slc_present(be->be_dev); +} + +int hw_mod_slc_alloc(struct flow_api_backend_s *be) +{ + _VER_ = be->iface->get_slc_version(be->be_dev); + NT_LOG(DBG, FILTER, "SLC MODULE VERSION %i.%i\n", VER_MAJOR(_VER_), + VER_MINOR(_VER_)); + + switch (_VER_) { + case 1: + if (!callocate_mod(CAST_COMMON(&be->slc), 1, + &be->slc.v1.rcp, + be->max_categories, + sizeof(struct slc_v1_rcp_s))) + return -1; + break; + /* end case 1 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +void hw_mod_slc_free(struct flow_api_backend_s *be) +{ + if (be->slc.base) { + free(be->slc.base); + be->slc.base = NULL; + } +} + +int hw_mod_slc_reset(struct flow_api_backend_s *be) +{ + /* Zero entire cache area */ + ZERO_MOD_CACHE(&be->slc); + + NT_LOG(DBG, FILTER, "INIT SLC RCP\n"); + return hw_mod_slc_rcp_flush(be, 0, be->max_categories); +} + +int hw_mod_slc_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->max_categories; + if ((unsigned int)(start_idx + count) > be->max_categories) + return error_index_too_large(__func__); + return be->iface->slc_rcp_flush(be->be_dev, &be->slc, start_idx, count); +} + +static int hw_mod_slc_rcp_mod(struct flow_api_backend_s *be, + enum hw_slc_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->max_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 1: + switch (field) { + case HW_SLC_RCP_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->slc.v1.rcp[index], (uint8_t)*value, + sizeof(struct hw_mod_slc_v1_s)); + break; + case HW_SLC_RCP_FIND: + rv = find_equal_index(be->slc.v1.rcp, + sizeof(struct hw_mod_slc_v1_s), index, *value, + be->max_categories, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_SLC_RCP_COMPARE: + rv = do_compare_indexes(be->slc.v1.rcp, + sizeof(struct hw_mod_slc_v1_s), index, *value, + be->max_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_SLC_RCP_SLC_EN: + get_set(&be->slc.v1.rcp[index].tail_slc_en, value, get); + break; + case HW_SLC_RCP_DYN: + get_set(&be->slc.v1.rcp[index].tail_dyn, value, get); + break; + case HW_SLC_RCP_OFS: + get_set_signed(&be->slc.v1.rcp[index].tail_ofs, value, get); + break; + case HW_SLC_RCP_PCAP: + get_set(&be->slc.v1.rcp[index].pcap, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 1 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_slc_rcp_set(struct flow_api_backend_s *be, enum hw_slc_e field, + uint32_t index, uint32_t value) +{ + return hw_mod_slc_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_slc_rcp_get(struct flow_api_backend_s *be, enum hw_slc_e field, + uint32_t index, uint32_t *value) +{ + return hw_mod_slc_rcp_mod(be, field, index, value, 1); +} diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_lr.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_lr.c new file mode 100644 index 0000000000..9f40563e8a --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_lr.c @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include "flow_api_backend.h" + +#define _MOD_ "SLC_LR" +#define _VER_ be->slc_lr.ver + +bool hw_mod_slc_lr_present(struct flow_api_backend_s *be) +{ + return be->iface->get_slc_lr_present(be->be_dev); +} + +int hw_mod_slc_lr_alloc(struct flow_api_backend_s *be) +{ + _VER_ = be->iface->get_slc_lr_version(be->be_dev); + NT_LOG(DBG, FILTER, "SLC LR MODULE VERSION %i.%i\n", VER_MAJOR(_VER_), + VER_MINOR(_VER_)); + + switch (_VER_) { + case 2: + if (!callocate_mod(CAST_COMMON(&be->slc_lr), 1, + &be->slc_lr.v2.rcp, + be->max_categories, + sizeof(struct slc_lr_v2_rcp_s))) + return -1; + break; + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +void hw_mod_slc_lr_free(struct flow_api_backend_s *be) +{ + if (be->slc_lr.base) { + free(be->slc_lr.base); + be->slc_lr.base = NULL; + } +} + +int hw_mod_slc_lr_reset(struct flow_api_backend_s *be) +{ + /* Zero entire cache area */ + ZERO_MOD_CACHE(&be->slc_lr); + + NT_LOG(DBG, FILTER, "INIT SLC LR RCP\n"); + return hw_mod_slc_lr_rcp_flush(be, 0, be->max_categories); +} + +int hw_mod_slc_lr_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->max_categories; + if ((unsigned int)(start_idx + count) > be->max_categories) + return error_index_too_large(__func__); + return be->iface->slc_lr_rcp_flush(be->be_dev, &be->slc_lr, start_idx, + count); +} + +static int hw_mod_slc_lr_rcp_mod(struct flow_api_backend_s *be, + enum hw_slc_lr_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->max_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 2: + switch (field) { + case HW_SLC_LR_RCP_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->slc_lr.v2.rcp[index], (uint8_t)*value, + sizeof(struct hw_mod_slc_lr_v2_s)); + break; + case HW_SLC_LR_RCP_FIND: + rv = find_equal_index(be->slc_lr.v2.rcp, + sizeof(struct hw_mod_slc_lr_v2_s), index, *value, + be->max_categories, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_SLC_LR_RCP_COMPARE: + rv = do_compare_indexes(be->slc_lr.v2.rcp, + sizeof(struct hw_mod_slc_lr_v2_s), index, *value, + be->max_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_SLC_LR_RCP_SLC_EN: + get_set(&be->slc_lr.v2.rcp[index].tail_slc_en, value, get); + break; + case HW_SLC_LR_RCP_DYN: + get_set(&be->slc_lr.v2.rcp[index].tail_dyn, value, get); + break; + case HW_SLC_LR_RCP_OFS: + get_set_signed(&be->slc_lr.v2.rcp[index].tail_ofs, + value, get); + break; + case HW_SLC_LR_RCP_PCAP: + get_set(&be->slc_lr.v2.rcp[index].pcap, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_slc_lr_rcp_set(struct flow_api_backend_s *be, enum hw_slc_lr_e field, + uint32_t index, uint32_t value) +{ + return hw_mod_slc_lr_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_slc_lr_rcp_get(struct flow_api_backend_s *be, enum hw_slc_lr_e field, + uint32_t index, uint32_t *value) +{ + return hw_mod_slc_lr_rcp_mod(be, field, index, value, 1); +} diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_lr_v2.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_lr_v2.h new file mode 100644 index 0000000000..d03b206e6d --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_lr_v2.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_SLC_LR_V2_H_ +#define _HW_MOD_SLC_LR_V2_H_ + +struct slc_lr_v2_rcp_s { + uint32_t tail_slc_en; + uint32_t tail_dyn; + int32_t tail_ofs; + uint32_t pcap; +}; + +struct hw_mod_slc_lr_v2_s { + struct slc_lr_v2_rcp_s *rcp; +}; + +#endif /* _HW_MOD_SLC_V2_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_v1.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_v1.h new file mode 100644 index 0000000000..01f60bfb18 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_v1.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_SLC_V1_H_ +#define _HW_MOD_SLC_V1_H_ + +struct slc_v1_rcp_s { + uint32_t tail_slc_en; + uint32_t tail_dyn; + int32_t tail_ofs; + uint32_t pcap; +}; + +struct hw_mod_slc_v1_s { + struct slc_v1_rcp_s *rcp; +}; + +#endif /* _HW_MOD_SLC_V1_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe.c new file mode 100644 index 0000000000..dd6f06b2c4 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe.c @@ -0,0 +1,983 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include "flow_api_backend.h" + +#define _MOD_ "TPE" +#define _VER_ be->tpe.ver + +bool hw_mod_tpe_present(struct flow_api_backend_s *be) +{ + return be->iface->get_tpe_present(be->be_dev); +} + +int hw_mod_tpe_alloc(struct flow_api_backend_s *be) +{ + int nb; + + _VER_ = be->iface->get_tpe_version(be->be_dev); + NT_LOG(DBG, FILTER, _MOD_ " MODULE VERSION %i.%i\n", VER_MAJOR(_VER_), + VER_MINOR(_VER_)); + + nb = be->iface->get_nb_tpe_categories(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "tpe_categories", _MOD_, _VER_); + be->tpe.nb_rcp_categories = (uint32_t)nb; + + be->tpe.nb_ifr_categories = 0; + if (_VER_ > 1) { + nb = be->iface->get_nb_tpe_ifr_categories(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "tpe_ifr_categories", _MOD_, _VER_); + be->tpe.nb_ifr_categories = (uint32_t)nb; + } + + nb = be->iface->get_nb_tx_cpy_writers(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "tx_cpy_writers", _MOD_, _VER_); + be->tpe.nb_cpy_writers = (uint32_t)nb; + + nb = be->iface->get_nb_tx_rpl_depth(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "tx_rpl_depth", _MOD_, _VER_); + be->tpe.nb_rpl_depth = (uint32_t)nb; + + nb = be->iface->get_nb_tx_rpl_ext_categories(be->be_dev); + if (nb <= 0) + return error_resource_count(__func__, "tx_rpl_ext_categories", _MOD_, _VER_); + be->tpe.nb_rpl_ext_categories = (uint32_t)nb; + + switch (_VER_) { + case 1: + if (!callocate_mod(CAST_COMMON(&be->tpe), 8, + &be->tpe.v1.rpp_rcp, be->tpe.nb_rcp_categories, + sizeof(struct tpe_v1_rpp_v0_rcp_s), + &be->tpe.v1.ins_rcp, be->tpe.nb_rcp_categories, + sizeof(struct tpe_v1_ins_v1_rcp_s), + &be->tpe.v1.rpl_rcp, be->tpe.nb_rcp_categories, + sizeof(struct tpe_v1_rpl_v2_rcp_s), + &be->tpe.v1.rpl_ext, be->tpe.nb_rpl_ext_categories, + sizeof(struct tpe_v1_rpl_v2_ext_s), + &be->tpe.v1.rpl_rpl, be->tpe.nb_rpl_depth, + sizeof(struct tpe_v1_rpl_v2_rpl_s), + &be->tpe.v1.cpy_rcp, + be->tpe.nb_cpy_writers * be->tpe.nb_rcp_categories, + sizeof(struct tpe_v1_cpy_v1_rcp_s), + &be->tpe.v1.hfu_rcp, be->tpe.nb_rcp_categories, + sizeof(struct tpe_v1_hfu_v1_rcp_s), + &be->tpe.v1.csu_rcp, be->tpe.nb_rcp_categories, + sizeof(struct tpe_v1_csu_v0_rcp_s))) + return -1; + break; + case 2: + if (!callocate_mod(CAST_COMMON(&be->tpe), 10, + &be->tpe.v2.rpp_rcp, be->tpe.nb_rcp_categories, + sizeof(struct tpe_v1_rpp_v0_rcp_s), + &be->tpe.v2.rpp_ifr_rcp, be->tpe.nb_ifr_categories, + sizeof(struct tpe_v2_rpp_v1_ifr_rcp_s), + &be->tpe.v2.ifr_rcp, be->tpe.nb_ifr_categories, + sizeof(struct tpe_v2_ifr_v1_rcp_s), + &be->tpe.v2.ins_rcp, be->tpe.nb_rcp_categories, + sizeof(struct tpe_v1_ins_v1_rcp_s), + &be->tpe.v2.rpl_rcp, be->tpe.nb_rcp_categories, + sizeof(struct tpe_v1_rpl_v2_rcp_s), + &be->tpe.v2.rpl_ext, be->tpe.nb_rpl_ext_categories, + sizeof(struct tpe_v1_rpl_v2_ext_s), + &be->tpe.v2.rpl_rpl, be->tpe.nb_rpl_depth, + sizeof(struct tpe_v1_rpl_v2_rpl_s), + &be->tpe.v2.cpy_rcp, + be->tpe.nb_cpy_writers * be->tpe.nb_rcp_categories, + sizeof(struct tpe_v1_cpy_v1_rcp_s), + &be->tpe.v2.hfu_rcp, be->tpe.nb_rcp_categories, + sizeof(struct tpe_v1_hfu_v1_rcp_s), + &be->tpe.v2.csu_rcp, be->tpe.nb_rcp_categories, + sizeof(struct tpe_v1_csu_v0_rcp_s))) + return -1; + break; + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +void hw_mod_tpe_free(struct flow_api_backend_s *be) +{ + if (be->tpe.base) { + free(be->tpe.base); + be->tpe.base = NULL; + } +} + +int hw_mod_tpe_reset(struct flow_api_backend_s *be) +{ + int err = 0; + + /* Zero entire cache area */ + ZERO_MOD_CACHE(&be->tpe); + + NT_LOG(DBG, FILTER, "INIT TPE\n"); + err |= hw_mod_tpe_rpp_rcp_flush(be, 0, ALL_ENTRIES); + err |= hw_mod_tpe_ins_rcp_flush(be, 0, ALL_ENTRIES); + err |= hw_mod_tpe_rpl_rcp_flush(be, 0, ALL_ENTRIES); + err |= hw_mod_tpe_rpl_ext_flush(be, 0, ALL_ENTRIES); + err |= hw_mod_tpe_rpl_rpl_flush(be, 0, ALL_ENTRIES); + err |= hw_mod_tpe_cpy_rcp_flush(be, 0, ALL_ENTRIES); + err |= hw_mod_tpe_hfu_rcp_flush(be, 0, ALL_ENTRIES); + err |= hw_mod_tpe_csu_rcp_flush(be, 0, ALL_ENTRIES); + + if (_VER_ == 2) { + err |= hw_mod_tpe_rpp_ifr_rcp_flush(be, 0, ALL_ENTRIES); + err |= hw_mod_tpe_ifr_rcp_flush(be, 0, ALL_ENTRIES); + } + + return err; +} + +/* + * RPP_IFR_RCP + */ + +int hw_mod_tpe_rpp_ifr_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->tpe.nb_ifr_categories; + if ((unsigned int)(start_idx + count) > be->tpe.nb_ifr_categories) + return error_index_too_large(__func__); + return be->iface->tpe_rpp_ifr_rcp_flush(be->be_dev, &be->tpe, start_idx, + count); +} + +static int hw_mod_tpe_rpp_ifr_rcp_mod(struct flow_api_backend_s *be, + enum hw_tpe_e field, uint32_t index, + uint32_t *value, int get) +{ + if (index >= be->tpe.nb_ifr_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 2: + switch (field) { + case HW_TPE_IFR_RCP_EN: + get_set(&be->tpe.v2.rpp_ifr_rcp[index].en, value, get); + break; + + case HW_TPE_IFR_RCP_MTU: + get_set(&be->tpe.v2.rpp_ifr_rcp[index].mtu, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_tpe_rpp_ifr_rcp_set(struct flow_api_backend_s *be, + enum hw_tpe_e field, int index, uint32_t value) +{ + return hw_mod_tpe_rpp_ifr_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_tpe_rpp_ifr_rcp_get(struct flow_api_backend_s *be, + enum hw_tpe_e field, int index, uint32_t *value) +{ + return hw_mod_tpe_rpp_ifr_rcp_mod(be, field, index, value, 1); +} + +/* + * RPP_RCP + */ + +int hw_mod_tpe_rpp_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->tpe.nb_rcp_categories; + if ((unsigned int)(start_idx + count) > be->tpe.nb_rcp_categories) + return error_index_too_large(__func__); + return be->iface->tpe_rpp_rcp_flush(be->be_dev, &be->tpe, start_idx, + count); +} + +static int hw_mod_tpe_rpp_rcp_mod(struct flow_api_backend_s *be, + enum hw_tpe_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->tpe.nb_rcp_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 1: + case 2: + switch (field) { + case HW_TPE_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->tpe.v1.rpp_rcp[index], (uint8_t)*value, + sizeof(struct tpe_v1_rpp_v0_rcp_s)); + break; + case HW_TPE_FIND: + rv = find_equal_index(be->tpe.v1.rpp_rcp, + sizeof(struct tpe_v1_rpp_v0_rcp_s), index, *value, + be->tpe.nb_rcp_categories, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_COMPARE: + rv = do_compare_indexes(be->tpe.v1.rpp_rcp, + sizeof(struct tpe_v1_rpp_v0_rcp_s), index, *value, + be->tpe.nb_rcp_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_RPP_RCP_EXP: + get_set(&be->tpe.v1.rpp_rcp[index].exp, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_tpe_rpp_rcp_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value) +{ + return hw_mod_tpe_rpp_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_tpe_rpp_rcp_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value) +{ + return hw_mod_tpe_rpp_rcp_mod(be, field, index, value, 1); +} + +/* + * IFR_RCP + */ + +int hw_mod_tpe_ifr_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->tpe.nb_ifr_categories; + if ((unsigned int)(start_idx + count) > be->tpe.nb_ifr_categories) + return error_index_too_large(__func__); + return be->iface->tpe_ifr_rcp_flush(be->be_dev, &be->tpe, start_idx, + count); +} + +static int hw_mod_tpe_ifr_rcp_mod(struct flow_api_backend_s *be, + enum hw_tpe_e field, uint32_t index, + uint32_t *value, int get) +{ + if (index >= be->tpe.nb_ifr_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 2: + switch (field) { + case HW_TPE_IFR_RCP_EN: + get_set(&be->tpe.v2.ifr_rcp[index].en, value, get); + break; + + case HW_TPE_IFR_RCP_MTU: + get_set(&be->tpe.v2.ifr_rcp[index].mtu, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_tpe_ifr_rcp_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value) +{ + return hw_mod_tpe_ifr_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_tpe_ifr_rcp_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value) +{ + return hw_mod_tpe_ifr_rcp_mod(be, field, index, value, 1); +} + +/* + * INS_RCP + */ + +int hw_mod_tpe_ins_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->tpe.nb_rcp_categories; + if ((unsigned int)(start_idx + count) > be->tpe.nb_rcp_categories) + return error_index_too_large(__func__); + return be->iface->tpe_ins_rcp_flush(be->be_dev, &be->tpe, start_idx, + count); +} + +static int hw_mod_tpe_ins_rcp_mod(struct flow_api_backend_s *be, + enum hw_tpe_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->tpe.nb_rcp_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 1: + case 2: + switch (field) { + case HW_TPE_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->tpe.v1.ins_rcp[index], (uint8_t)*value, + sizeof(struct tpe_v1_ins_v1_rcp_s)); + break; + case HW_TPE_FIND: + rv = find_equal_index(be->tpe.v1.ins_rcp, + sizeof(struct tpe_v1_ins_v1_rcp_s), index, *value, + be->tpe.nb_rcp_categories, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_COMPARE: + rv = do_compare_indexes(be->tpe.v1.ins_rcp, + sizeof(struct tpe_v1_ins_v1_rcp_s), index, *value, + be->tpe.nb_rcp_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_INS_RCP_DYN: + get_set(&be->tpe.v1.ins_rcp[index].dyn, value, get); + break; + case HW_TPE_INS_RCP_OFS: + get_set(&be->tpe.v1.ins_rcp[index].ofs, value, get); + break; + case HW_TPE_INS_RCP_LEN: + get_set(&be->tpe.v1.ins_rcp[index].len, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 1 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_tpe_ins_rcp_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value) +{ + return hw_mod_tpe_ins_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_tpe_ins_rcp_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value) +{ + return hw_mod_tpe_ins_rcp_mod(be, field, index, value, 1); +} + +/* + * RPL_RCP + */ + +int hw_mod_tpe_rpl_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->tpe.nb_rcp_categories; + if ((unsigned int)(start_idx + count) > be->tpe.nb_rcp_categories) + return error_index_too_large(__func__); + return be->iface->tpe_rpl_rcp_flush(be->be_dev, &be->tpe, start_idx, + count); +} + +static int hw_mod_tpe_rpl_rcp_mod(struct flow_api_backend_s *be, + enum hw_tpe_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->tpe.nb_rcp_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 1: + case 2: + switch (field) { + case HW_TPE_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->tpe.v1.rpl_rcp[index], (uint8_t)*value, + sizeof(struct tpe_v1_rpl_v2_rcp_s)); + break; + case HW_TPE_FIND: + rv = find_equal_index(be->tpe.v1.rpl_rcp, + sizeof(struct tpe_v1_rpl_v2_rcp_s), index, *value, + be->tpe.nb_rcp_categories, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_COMPARE: + rv = do_compare_indexes(be->tpe.v1.rpl_rcp, + sizeof(struct tpe_v1_rpl_v2_rcp_s), index, *value, + be->tpe.nb_rcp_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_RPL_RCP_DYN: + get_set(&be->tpe.v1.rpl_rcp[index].dyn, value, get); + break; + case HW_TPE_RPL_RCP_OFS: + get_set(&be->tpe.v1.rpl_rcp[index].ofs, value, get); + break; + case HW_TPE_RPL_RCP_LEN: + get_set(&be->tpe.v1.rpl_rcp[index].len, value, get); + break; + case HW_TPE_RPL_RCP_RPL_PTR: + get_set(&be->tpe.v1.rpl_rcp[index].rpl_ptr, value, get); + break; + case HW_TPE_RPL_RCP_EXT_PRIO: + get_set(&be->tpe.v1.rpl_rcp[index].ext_prio, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 1 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_tpe_rpl_rcp_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value) +{ + return hw_mod_tpe_rpl_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_tpe_rpl_rcp_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value) +{ + return hw_mod_tpe_rpl_rcp_mod(be, field, index, value, 1); +} + +/* + * RPL_EXT + */ + +int hw_mod_tpe_rpl_ext_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->tpe.nb_rpl_ext_categories; + if ((unsigned int)(start_idx + count) > be->tpe.nb_rpl_ext_categories) + return error_index_too_large(__func__); + return be->iface->tpe_rpl_ext_flush(be->be_dev, &be->tpe, start_idx, + count); +} + +static int hw_mod_tpe_rpl_ext_mod(struct flow_api_backend_s *be, + enum hw_tpe_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->tpe.nb_rpl_ext_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 1: + case 2: + switch (field) { + case HW_TPE_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->tpe.v1.rpl_ext[index], (uint8_t)*value, + sizeof(struct tpe_v1_rpl_v2_ext_s)); + break; + case HW_TPE_FIND: + rv = find_equal_index(be->tpe.v1.rpl_ext, + sizeof(struct tpe_v1_rpl_v2_ext_s), index, *value, + be->tpe.nb_rpl_ext_categories, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_COMPARE: + rv = do_compare_indexes(be->tpe.v1.rpl_ext, + sizeof(struct tpe_v1_rpl_v2_ext_s), index, *value, + be->tpe.nb_rpl_ext_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_RPL_EXT_RPL_PTR: + get_set(&be->tpe.v1.rpl_ext[index].rpl_ptr, value, get); + break; + case HW_TPE_RPL_EXT_META_RPL_LEN: + get_set(&be->tpe.v1.rpl_ext[index].meta_rpl_len, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 1 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_tpe_rpl_ext_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value) +{ + return hw_mod_tpe_rpl_ext_mod(be, field, index, &value, 0); +} + +int hw_mod_tpe_rpl_ext_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value) +{ + return hw_mod_tpe_rpl_ext_mod(be, field, index, value, 1); +} + +/* + * RPL_RPL + */ + +int hw_mod_tpe_rpl_rpl_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->tpe.nb_rpl_depth; + if ((unsigned int)(start_idx + count) > be->tpe.nb_rpl_depth) + return error_index_too_large(__func__); + return be->iface->tpe_rpl_rpl_flush(be->be_dev, &be->tpe, start_idx, + count); +} + +static int hw_mod_tpe_rpl_rpl_mod(struct flow_api_backend_s *be, + enum hw_tpe_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->tpe.nb_rpl_depth) + return error_index_too_large(__func__); + switch (_VER_) { + case 1: + case 2: + switch (field) { + case HW_TPE_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->tpe.v1.rpl_rpl[index], (uint8_t)*value, + sizeof(struct tpe_v1_rpl_v2_rpl_s)); + break; + case HW_TPE_FIND: + rv = find_equal_index(be->tpe.v1.rpl_rpl, + sizeof(struct tpe_v1_rpl_v2_rpl_s), index, *value, + be->tpe.nb_rpl_depth, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_COMPARE: + rv = do_compare_indexes(be->tpe.v1.rpl_rpl, + sizeof(struct tpe_v1_rpl_v2_rpl_s), index, *value, + be->tpe.nb_rpl_depth, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_RPL_RPL_VALUE: + if (get) + memcpy(value, be->tpe.v1.rpl_rpl[index].value, + sizeof(uint32_t) * 4); + else + memcpy(be->tpe.v1.rpl_rpl[index].value, value, + sizeof(uint32_t) * 4); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 1 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_tpe_rpl_rpl_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value) +{ + return hw_mod_tpe_rpl_rpl_mod(be, field, index, value, 0); +} + +int hw_mod_tpe_rpl_rpl_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value) +{ + return hw_mod_tpe_rpl_rpl_mod(be, field, index, value, 1); +} + +/* + * CPY_RCP + */ + +int hw_mod_tpe_cpy_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + const uint32_t cpy_size = + be->tpe.nb_cpy_writers * be->tpe.nb_rcp_categories; + if (count == ALL_ENTRIES) + count = cpy_size; + if ((unsigned int)(start_idx + count) > cpy_size) + return error_index_too_large(__func__); + return be->iface->tpe_cpy_rcp_flush(be->be_dev, &be->tpe, start_idx, + count); +} + +static int hw_mod_tpe_cpy_rcp_mod(struct flow_api_backend_s *be, + enum hw_tpe_e field, uint32_t index, + uint32_t *value, int get) +{ + const uint32_t cpy_size = + be->tpe.nb_cpy_writers * be->tpe.nb_rcp_categories; + int rv = 0; + if (index >= cpy_size) + return error_index_too_large(__func__); + switch (_VER_) { + case 1: + case 2: + switch (field) { + case HW_TPE_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->tpe.v1.cpy_rcp[index], (uint8_t)*value, + sizeof(struct tpe_v1_cpy_v1_rcp_s)); + break; + case HW_TPE_FIND: + rv = find_equal_index(be->tpe.v1.cpy_rcp, + sizeof(struct tpe_v1_cpy_v1_rcp_s), index, *value, + cpy_size, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_COMPARE: + rv = do_compare_indexes(be->tpe.v1.cpy_rcp, + sizeof(struct tpe_v1_cpy_v1_rcp_s), index, *value, + cpy_size, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_CPY_RCP_READER_SELECT: + get_set(&be->tpe.v1.cpy_rcp[index].reader_select, value, get); + break; + case HW_TPE_CPY_RCP_DYN: + get_set(&be->tpe.v1.cpy_rcp[index].dyn, value, get); + break; + case HW_TPE_CPY_RCP_OFS: + get_set(&be->tpe.v1.cpy_rcp[index].ofs, value, get); + break; + case HW_TPE_CPY_RCP_LEN: + get_set(&be->tpe.v1.cpy_rcp[index].len, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 1 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_tpe_cpy_rcp_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value) +{ + return hw_mod_tpe_cpy_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_tpe_cpy_rcp_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value) +{ + return hw_mod_tpe_cpy_rcp_mod(be, field, index, value, 1); +} + +/* + * HFU_RCP + */ + +int hw_mod_tpe_hfu_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->tpe.nb_rcp_categories; + if ((unsigned int)(start_idx + count) > be->tpe.nb_rcp_categories) + return error_index_too_large(__func__); + return be->iface->tpe_hfu_rcp_flush(be->be_dev, &be->tpe, start_idx, + count); +} + +static int hw_mod_tpe_hfu_rcp_mod(struct flow_api_backend_s *be, + enum hw_tpe_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->tpe.nb_rcp_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 1: + case 2: + switch (field) { + case HW_TPE_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->tpe.v1.hfu_rcp[index], (uint8_t)*value, + sizeof(struct tpe_v1_hfu_v1_rcp_s)); + break; + case HW_TPE_FIND: + rv = find_equal_index(be->tpe.v1.hfu_rcp, + sizeof(struct tpe_v1_hfu_v1_rcp_s), index, *value, + be->tpe.nb_rcp_categories, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_COMPARE: + rv = do_compare_indexes(be->tpe.v1.hfu_rcp, + sizeof(struct tpe_v1_hfu_v1_rcp_s), index, *value, + be->tpe.nb_rcp_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_HFU_RCP_LEN_A_WR: + get_set(&be->tpe.v1.hfu_rcp[index].len_a_wr, value, get); + break; + case HW_TPE_HFU_RCP_LEN_A_OUTER_L4_LEN: + get_set(&be->tpe.v1.hfu_rcp[index].len_a_outer_l4_len, + value, get); + break; + case HW_TPE_HFU_RCP_LEN_A_POS_DYN: + get_set(&be->tpe.v1.hfu_rcp[index].len_a_pos_dyn, value, get); + break; + case HW_TPE_HFU_RCP_LEN_A_POS_OFS: + get_set(&be->tpe.v1.hfu_rcp[index].len_a_pos_ofs, value, get); + break; + case HW_TPE_HFU_RCP_LEN_A_ADD_DYN: + get_set(&be->tpe.v1.hfu_rcp[index].len_a_add_dyn, value, get); + break; + case HW_TPE_HFU_RCP_LEN_A_ADD_OFS: + get_set(&be->tpe.v1.hfu_rcp[index].len_a_add_ofs, value, get); + break; + case HW_TPE_HFU_RCP_LEN_A_SUB_DYN: + get_set(&be->tpe.v1.hfu_rcp[index].len_a_sub_dyn, value, get); + break; + + case HW_TPE_HFU_RCP_LEN_B_WR: + get_set(&be->tpe.v1.hfu_rcp[index].len_b_wr, value, get); + break; + case HW_TPE_HFU_RCP_LEN_B_POS_DYN: + get_set(&be->tpe.v1.hfu_rcp[index].len_b_pos_dyn, value, get); + break; + case HW_TPE_HFU_RCP_LEN_B_POS_OFS: + get_set(&be->tpe.v1.hfu_rcp[index].len_b_pos_ofs, value, get); + break; + case HW_TPE_HFU_RCP_LEN_B_ADD_DYN: + get_set(&be->tpe.v1.hfu_rcp[index].len_b_add_dyn, value, get); + break; + case HW_TPE_HFU_RCP_LEN_B_ADD_OFS: + get_set(&be->tpe.v1.hfu_rcp[index].len_b_add_ofs, value, get); + break; + case HW_TPE_HFU_RCP_LEN_B_SUB_DYN: + get_set(&be->tpe.v1.hfu_rcp[index].len_b_sub_dyn, value, get); + break; + + case HW_TPE_HFU_RCP_LEN_C_WR: + get_set(&be->tpe.v1.hfu_rcp[index].len_c_wr, value, get); + break; + case HW_TPE_HFU_RCP_LEN_C_POS_DYN: + get_set(&be->tpe.v1.hfu_rcp[index].len_c_pos_dyn, value, get); + break; + case HW_TPE_HFU_RCP_LEN_C_POS_OFS: + get_set(&be->tpe.v1.hfu_rcp[index].len_c_pos_ofs, value, get); + break; + case HW_TPE_HFU_RCP_LEN_C_ADD_DYN: + get_set(&be->tpe.v1.hfu_rcp[index].len_c_add_dyn, value, get); + break; + case HW_TPE_HFU_RCP_LEN_C_ADD_OFS: + get_set(&be->tpe.v1.hfu_rcp[index].len_c_add_ofs, value, get); + break; + case HW_TPE_HFU_RCP_LEN_C_SUB_DYN: + get_set(&be->tpe.v1.hfu_rcp[index].len_c_sub_dyn, value, get); + break; + + case HW_TPE_HFU_RCP_TTL_WR: + get_set(&be->tpe.v1.hfu_rcp[index].ttl_wr, value, get); + break; + case HW_TPE_HFU_RCP_TTL_POS_DYN: + get_set(&be->tpe.v1.hfu_rcp[index].ttl_pos_dyn, value, get); + break; + case HW_TPE_HFU_RCP_TTL_POS_OFS: + get_set(&be->tpe.v1.hfu_rcp[index].ttl_pos_ofs, value, get); + break; + + case HW_TPE_HFU_RCP_CS_INF: + get_set(&be->tpe.v1.hfu_rcp[index].cs_inf, value, get); + break; + case HW_TPE_HFU_RCP_L3_PRT: + get_set(&be->tpe.v1.hfu_rcp[index].l3_prt, value, get); + break; + case HW_TPE_HFU_RCP_L3_FRAG: + get_set(&be->tpe.v1.hfu_rcp[index].l3_frag, value, get); + break; + case HW_TPE_HFU_RCP_TUNNEL: + get_set(&be->tpe.v1.hfu_rcp[index].tunnel, value, get); + break; + case HW_TPE_HFU_RCP_L4_PRT: + get_set(&be->tpe.v1.hfu_rcp[index].l4_prt, value, get); + break; + case HW_TPE_HFU_RCP_OUTER_L3_OFS: + get_set(&be->tpe.v1.hfu_rcp[index].outer_l3_ofs, value, get); + break; + case HW_TPE_HFU_RCP_OUTER_L4_OFS: + get_set(&be->tpe.v1.hfu_rcp[index].outer_l4_ofs, value, get); + break; + case HW_TPE_HFU_RCP_INNER_L3_OFS: + get_set(&be->tpe.v1.hfu_rcp[index].inner_l3_ofs, value, get); + break; + case HW_TPE_HFU_RCP_INNER_L4_OFS: + get_set(&be->tpe.v1.hfu_rcp[index].inner_l4_ofs, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 1 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_tpe_hfu_rcp_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value) +{ + return hw_mod_tpe_hfu_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_tpe_hfu_rcp_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value) +{ + return hw_mod_tpe_hfu_rcp_mod(be, field, index, value, 1); +} + +/* + * CSU_RCP + */ + +int hw_mod_tpe_csu_rcp_flush(struct flow_api_backend_s *be, int start_idx, + int count) +{ + if (count == ALL_ENTRIES) + count = be->tpe.nb_rcp_categories; + if ((unsigned int)(start_idx + count) > be->tpe.nb_rcp_categories) + return error_index_too_large(__func__); + return be->iface->tpe_csu_rcp_flush(be->be_dev, &be->tpe, start_idx, + count); +} + +static int hw_mod_tpe_csu_rcp_mod(struct flow_api_backend_s *be, + enum hw_tpe_e field, uint32_t index, + uint32_t *value, int get) +{ + int rv = 0; + if (index >= be->tpe.nb_rcp_categories) + return error_index_too_large(__func__); + switch (_VER_) { + case 1: + case 2: + switch (field) { + case HW_TPE_PRESET_ALL: + if (get) + return error_unsup_field(__func__); + memset(&be->tpe.v1.csu_rcp[index], (uint8_t)*value, + sizeof(struct tpe_v1_csu_v0_rcp_s)); + break; + case HW_TPE_FIND: + rv = find_equal_index(be->tpe.v1.csu_rcp, + sizeof(struct tpe_v1_csu_v0_rcp_s), index, *value, + be->tpe.nb_rcp_categories, value, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_COMPARE: + rv = do_compare_indexes(be->tpe.v1.csu_rcp, + sizeof(struct tpe_v1_csu_v0_rcp_s), index, *value, + be->tpe.nb_rcp_categories, get, __func__); + if (rv != 0) + return rv; + break; + case HW_TPE_CSU_RCP_OUTER_L3_CMD: + get_set(&be->tpe.v1.csu_rcp[index].ol3_cmd, value, get); + break; + case HW_TPE_CSU_RCP_OUTER_L4_CMD: + get_set(&be->tpe.v1.csu_rcp[index].ol4_cmd, value, get); + break; + case HW_TPE_CSU_RCP_INNER_L3_CMD: + get_set(&be->tpe.v1.csu_rcp[index].il3_cmd, value, get); + break; + case HW_TPE_CSU_RCP_INNER_L4_CMD: + get_set(&be->tpe.v1.csu_rcp[index].il4_cmd, value, get); + break; + + default: + return error_unsup_field(__func__); + } + break; + /* end case 1 */ + default: + return error_unsup_ver(__func__, _MOD_, _VER_); + } + + return 0; +} + +int hw_mod_tpe_csu_rcp_set(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t value) +{ + return hw_mod_tpe_csu_rcp_mod(be, field, index, &value, 0); +} + +int hw_mod_tpe_csu_rcp_get(struct flow_api_backend_s *be, enum hw_tpe_e field, + int index, uint32_t *value) +{ + return hw_mod_tpe_csu_rcp_mod(be, field, index, value, 1); +} diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe_v1.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe_v1.h new file mode 100644 index 0000000000..dacd819659 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe_v1.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_TPE_V1_H_ +#define _HW_MOD_TPE_V1_H_ + +struct tpe_v1_rpp_v0_rcp_s { + uint32_t exp; +}; + +struct tpe_v1_ins_v1_rcp_s { + uint32_t dyn; + uint32_t ofs; + uint32_t len; +}; + +struct tpe_v1_rpl_v2_rcp_s { + uint32_t dyn; + uint32_t ofs; + uint32_t len; + uint32_t rpl_ptr; + uint32_t ext_prio; +}; + +struct tpe_v1_rpl_v2_ext_s { + uint32_t rpl_ptr; + uint32_t meta_rpl_len; /* SW only */ +}; + +struct tpe_v1_rpl_v2_rpl_s { + uint32_t value[4]; +}; + +struct tpe_v1_cpy_v1_rcp_s { + uint32_t reader_select; + uint32_t dyn; + uint32_t ofs; + uint32_t len; +}; + +struct tpe_v1_hfu_v1_rcp_s { + uint32_t len_a_wr; + uint32_t len_a_outer_l4_len; + uint32_t len_a_pos_dyn; + uint32_t len_a_pos_ofs; + uint32_t len_a_add_dyn; + uint32_t len_a_add_ofs; + uint32_t len_a_sub_dyn; + + uint32_t len_b_wr; + uint32_t len_b_pos_dyn; + uint32_t len_b_pos_ofs; + uint32_t len_b_add_dyn; + uint32_t len_b_add_ofs; + uint32_t len_b_sub_dyn; + + uint32_t len_c_wr; + uint32_t len_c_pos_dyn; + uint32_t len_c_pos_ofs; + uint32_t len_c_add_dyn; + uint32_t len_c_add_ofs; + uint32_t len_c_sub_dyn; + + uint32_t ttl_wr; + uint32_t ttl_pos_dyn; + uint32_t ttl_pos_ofs; + + uint32_t cs_inf; + uint32_t l3_prt; + uint32_t l3_frag; + uint32_t tunnel; + uint32_t l4_prt; + uint32_t outer_l3_ofs; + uint32_t outer_l4_ofs; + uint32_t inner_l3_ofs; + uint32_t inner_l4_ofs; +}; + +struct tpe_v1_csu_v0_rcp_s { + uint32_t ol3_cmd; + uint32_t ol4_cmd; + uint32_t il3_cmd; + uint32_t il4_cmd; +}; + +struct hw_mod_tpe_v1_s { + struct tpe_v1_rpp_v0_rcp_s *rpp_rcp; + + struct tpe_v1_ins_v1_rcp_s *ins_rcp; + + struct tpe_v1_rpl_v2_rcp_s *rpl_rcp; + struct tpe_v1_rpl_v2_ext_s *rpl_ext; + struct tpe_v1_rpl_v2_rpl_s *rpl_rpl; + + struct tpe_v1_cpy_v1_rcp_s *cpy_rcp; + + struct tpe_v1_hfu_v1_rcp_s *hfu_rcp; + + struct tpe_v1_csu_v0_rcp_s *csu_rcp; +}; + +#endif /* _HW_MOD_TPE_V1_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe_v2.h b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe_v2.h new file mode 100644 index 0000000000..c56cad8d89 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe_v2.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _HW_MOD_TPE_V2_H_ +#define _HW_MOD_TPE_V2_H_ + +struct tpe_v2_rpp_v1_ifr_rcp_s { + uint32_t en; + uint32_t mtu; +}; + +struct tpe_v2_ifr_v1_rcp_s { + uint32_t en; + uint32_t mtu; +}; + +struct hw_mod_tpe_v2_s { + struct tpe_v1_rpp_v0_rcp_s *rpp_rcp; + + struct tpe_v1_ins_v1_rcp_s *ins_rcp; + + struct tpe_v1_rpl_v2_rcp_s *rpl_rcp; + struct tpe_v1_rpl_v2_ext_s *rpl_ext; + struct tpe_v1_rpl_v2_rpl_s *rpl_rpl; + + struct tpe_v1_cpy_v1_rcp_s *cpy_rcp; + + struct tpe_v1_hfu_v1_rcp_s *hfu_rcp; + + struct tpe_v1_csu_v0_rcp_s *csu_rcp; + + struct tpe_v2_rpp_v1_ifr_rcp_s *rpp_ifr_rcp; + struct tpe_v2_ifr_v1_rcp_s *ifr_rcp; +}; + +#endif /* _HW_MOD_TPE_V2_H_ */ diff --git a/drivers/net/ntnic/nthw/flow_api/stream_binary_flow_api.h b/drivers/net/ntnic/nthw/flow_api/stream_binary_flow_api.h new file mode 100644 index 0000000000..eae8f176a8 --- /dev/null +++ b/drivers/net/ntnic/nthw/flow_api/stream_binary_flow_api.h @@ -0,0 +1,697 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef _STREAM_BINARY_FLOW_API_H_ +#define _STREAM_BINARY_FLOW_API_H_ + +#include /* uint16_t, uint32_t, uint64_t */ +#include /* snprintf */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint16_t be16_t; /* 16-bit big-endian */ +typedef uint32_t be32_t; /* 32-bit big-endian */ +typedef uint64_t be64_t; /* 64-bit big-endian */ + +/* + * Flow frontend for binary programming interface + */ + +#define FLOW_MAX_QUEUES 128 + +#define RAW_ENCAP_DECAP_ELEMS_MAX 16 + +/* + * Partial flow mark and special flow marks + */ +#define FLOW_MARK_LACP 0x7fffffff +#define FLOW_MARK_MAX 0x7ffffffe +/* + * Flow eth dev profile determines how the FPGA module resources are + * managed and what features are available + */ +enum flow_eth_dev_profile { + FLOW_ETH_DEV_PROFILE_VSWITCH = 0, + FLOW_ETH_DEV_PROFILE_INLINE = 1, +}; + +/* + * Flow rule attributes + */ +struct flow_attr { + uint32_t group; /* Priority group. */ + uint32_t priority; /* Rule priority level within group. */ + uint16_t forced_vlan_vid; /* Forced VLAN VID that filter must match. Ignored if 0. */ + uint8_t caller_id; /* Unique ID of caller application. */ +}; + +struct flow_queue_id_s { + int id; + int hw_id; +}; + +/* NT Private rte flow items. */ + +/* NT Private rte flow actions. */ + +enum flow_elem_type { + FLOW_ELEM_TYPE_END, + FLOW_ELEM_TYPE_ANY, + FLOW_ELEM_TYPE_ETH, + FLOW_ELEM_TYPE_VLAN, + FLOW_ELEM_TYPE_IPV4, + FLOW_ELEM_TYPE_IPV6, + FLOW_ELEM_TYPE_SCTP, + FLOW_ELEM_TYPE_TCP, + FLOW_ELEM_TYPE_UDP, + FLOW_ELEM_TYPE_ICMP, + FLOW_ELEM_TYPE_VXLAN, + FLOW_ELEM_TYPE_GTP, + FLOW_ELEM_TYPE_PORT_ID, + FLOW_ELEM_TYPE_TAG, + FLOW_ELEM_TYPE_VOID, + + /* + * Not associated with a RTE_ITEM..., but rather an restoration API device specific + * extension + */ + FLOW_ELEM_TYPE_TUNNEL +}; + +enum flow_action_type { /* conf structure */ + FLOW_ACTION_TYPE_END, /* -none- : End tag for action list */ + FLOW_ACTION_TYPE_POP_VLAN, /* -none- : Pops outer vlan tag */ + FLOW_ACTION_TYPE_PUSH_VLAN, /* struct flow_action_push_vlan : Push VLAN TAG */ + FLOW_ACTION_TYPE_SET_VLAN_VID, /* struct flow_action_set_vlan_vid : Set VLAN VID */ + FLOW_ACTION_TYPE_SET_VLAN_PCP, /* struct flow_action_set_vlan_pcp : Set VLAN PCP */ + /* -none- : Decapsulate outer most VXLAN tunnel from matched flow */ + FLOW_ACTION_TYPE_VXLAN_DECAP, + FLOW_ACTION_TYPE_VXLAN_ENCAP, /* struct flow_action_vxlan_encap */ + FLOW_ACTION_TYPE_DROP, /* -none- : Drop packets of this flow */ + FLOW_ACTION_TYPE_COUNT, /* struct flow_action_count : Used for "query" flow function */ + FLOW_ACTION_TYPE_MARK, /* struct flow_action_mark : Used to tag a flow in HW with a MARK */ + FLOW_ACTION_TYPE_SET_TAG, /* struct flow_action_tag : Used to tag a flow in HW with a TAG */ + /* struct flow_action_port_id : Destination port ID - HW port ID */ + FLOW_ACTION_TYPE_PORT_ID, + FLOW_ACTION_TYPE_RSS, /* struct flow_action_rss : */ + FLOW_ACTION_TYPE_QUEUE, /* struct flow_action_queue : */ + FLOW_ACTION_TYPE_JUMP, /* struct flow_action_jump : */ + /* struct flow_action_meter : Used to set MBR record ids in FLM learn records */ + FLOW_ACTION_TYPE_METER, + FLOW_ACTION_TYPE_RAW_ENCAP, /* struct flow_action_raw_encap : */ + FLOW_ACTION_TYPE_RAW_DECAP, /* struct flow_action_raw_decap : */ + FLOW_ACTION_TYPE_MODIFY_FIELD, /* struct flow_action_modify_field : */ + + /* + * -none- : not associated with a RTE_ACTION..., but rather an restoration API device + * specific extension + */ + FLOW_ACTION_TYPE_TUNNEL_SET +}; + +#pragma pack(1) +struct ether_addr_s { + uint8_t addr_b[6]; +}; + +#pragma pack() + +static inline void flow_ether_format_addr(char *buf, uint16_t size, + const struct ether_addr_s *eth_addr) +{ + snprintf(buf, size, "%02X:%02X:%02X:%02X:%02X:%02X", + eth_addr->addr_b[0], eth_addr->addr_b[1], eth_addr->addr_b[2], + eth_addr->addr_b[3], eth_addr->addr_b[4], eth_addr->addr_b[5]); +} + +/* + * IPv4 Header + */ +#pragma pack(1) +struct ipv4_hdr_s { + uint8_t version_ihl; + uint8_t tos; + be16_t length; + be16_t id; + be16_t frag_offset; + uint8_t ttl; + uint8_t next_proto_id; + be16_t hdr_csum; + be32_t src_ip; + be32_t dst_ip; +}; + +#pragma pack() +/* + * IPv6 Header + */ +#pragma pack(1) +struct ipv6_hdr_s { + be32_t vtc_flow; /* IP version, traffic class & flow label */ + be16_t payload_len; /* IP packet length - includes ip header */ + uint8_t proto; + uint8_t hop_limits; + uint8_t src_addr[16]; + uint8_t dst_addr[16]; +}; + +#pragma pack() + +/* + * SCTP Header + */ +#pragma pack(1) +struct sctp_hdr_s { + be16_t src_port; + be16_t dst_port; + be32_t tag; /* Validation tag */ + be32_t cksum; +}; + +#pragma pack() + +/* + * TCP Header + */ +#pragma pack(1) +struct tcp_hdr_s { + be16_t src_port; + be16_t dst_port; + be32_t sent_seq; + be32_t recv_ack; + uint8_t data_off; + uint8_t tcp_flags; + be16_t rx_win; + be16_t cksum; + be16_t tcp_urp; +}; + +#pragma pack() + +/* + * UDP Header + */ +#pragma pack(1) +struct udp_hdr_s { + be16_t src_port; + be16_t dst_port; + be16_t len; + be16_t cksum; +}; + +#pragma pack() + +/* + * ICMP Header + */ +#pragma pack(1) +struct icmp_hdr_s { + uint8_t type; + uint8_t code; + be16_t cksum; + be16_t ident; + be16_t seq_nb; +}; + +#pragma pack() +/* + * FLOW_ELEM_TYPE_ETH specification + */ +#pragma pack(1) +struct flow_elem_eth { + struct ether_addr_s d_addr; /* DMAC */ + struct ether_addr_s s_addr; /* SMAC */ + be16_t ether_type; /* Frame type */ +}; + +#pragma pack() + +/* + * FLOW_ELEM_TYPE_VLAN specification + */ +#pragma pack(1) +struct flow_elem_vlan { + be16_t tci; /* Tag control information */ + be16_t inner_type; /* Inner EtherType or TPID */ +}; + +#pragma pack() + +/* + * FLOW_ELEM_TYPE_IPV4 specification + */ +struct flow_elem_ipv4 { + struct ipv4_hdr_s hdr; +}; + +/* + * FLOW_ELEM_TYPE_IPV6 specification + */ +struct flow_elem_ipv6 { + struct ipv6_hdr_s hdr; +}; + +/* + * FLOW_ELEM_TYPE_SCTP specification + */ +struct flow_elem_sctp { + struct sctp_hdr_s hdr; +}; + +/* + * FLOW_ELEM_TYPE_TCP specification + */ +struct flow_elem_tcp { + struct tcp_hdr_s hdr; +}; + +/* + * FLOW_ELEM_TYPE_UDP specification + */ +struct flow_elem_udp { + struct udp_hdr_s hdr; +}; + +/* + * FLOW_ELEM_TYPE_ICMP specification + */ +struct flow_elem_icmp { + struct icmp_hdr_s hdr; +}; + +/* + * FLOW_ELEM_TYPE_GTP specification + */ +#pragma pack(1) +struct flow_elem_gtp { + uint8_t v_pt_rsv_flags; + uint8_t msg_type; + be16_t msg_len; + be32_t teid; +}; + +#pragma pack() + +/* + * FLOW_ELEM_TYPE_VXLAN specification (RFC 7348) + */ +#pragma pack(1) +struct flow_elem_vxlan { + uint8_t flags; /* Normally 0x08 (I flag) */ + uint8_t rsvd0[3]; + uint8_t vni[3]; + uint8_t rsvd1; +}; + +#pragma pack() +/* + * FLOW_ELEM_TYPE_PORT_ID specification + */ +struct flow_elem_port_id { + uint32_t id; /* HW port no */ +}; + +/* + * FLOW_ELEM_TYPE_TAG specification + */ +struct flow_elem_tag { + uint32_t data; + uint8_t index; +}; + +/* + * FLOW_ELEM_TYPE_ANY specification + */ +struct flow_elem_any { + uint32_t num; /**< Number of layers covered. */ +}; + +struct flow_elem { + enum flow_elem_type type; /* element type */ + const void *spec; /* Pointer to element specification structure */ + const void *mask; /* Bitmask applied to spec - same type */ +}; + +/* + * FLOW_ACTION_TYPE_RSS + */ +enum flow_hash_function { + FLOW_HASH_FUNCTION_DEFAULT = 0, + FLOW_HASH_FUNCTION_TOEPLITZ, /* Unsupported in current supported FPGA */ + FLOW_HASH_FUNCTION_SIMPLE_XOR /* Simple XOR - not supported */ +}; + +struct flow_action_rss { + enum flow_hash_function func; + uint32_t level; /* only level 0 supported */ + /* Specific RSS hash types (see like DPDK ETH_RSS_*) */ + uint64_t types; + uint32_t key_len; /* Not supported yet - Hash key length in bytes */ + uint32_t queue_num; /* Number of entries in queue */ + const uint8_t *key; /* Not supported yet - Hash key */ + const uint16_t *queue; /* Queue indices to use */ +}; + +/* + * FLOW_ACTION_TYPE_PUSH_VLAN + * Push a new vlan TAG + */ +struct flow_action_push_vlan { + be16_t ethertype; +}; + +/* + * FLOW_ACTION_TYPE_SET_VLAN_VID + */ +struct flow_action_set_vlan_vid { + be16_t vlan_vid; +}; + +/* + * FLOW_ACTION_TYPE_SET_VLAN_PCP + */ +struct flow_action_set_vlan_pcp { + uint8_t vlan_pcp; /* < VLAN priority. */ +}; + +/* + * FLOW_ACTION_TYPE_VXLAN_ENCAP specification + * Valid flow definition: + * + * - ETH / IPV4 / UDP / VXLAN / END + * - ETH / IPV6 / UDP / VXLAN / END + * - ETH / VLAN / IPV4 / UDP / VXLAN / END + * + */ +struct flow_action_vxlan_encap { + /* Encapsulating vxlan tunnel definition */ + struct flow_elem *vxlan_tunnel; +}; + +/* + * FLOW_ACTION_TYPE_COUNT specification + */ +struct flow_action_count { + uint32_t id; /* HW port no */ +}; + +/* + * FLOW_ACTION_TYPE_COUNT specification (query) + */ +struct flow_query_count { + uint32_t reset : 1; + uint32_t hits_set : 1; + uint32_t bytes_set : 1; + + uint32_t tcp_flags : 9; + + uint32_t reserved : 20; + uint64_t hits; + uint64_t bytes; +}; + +/* + * FLOW_ACTION_TYPE_MARK specification + */ +struct flow_action_mark { + uint32_t id; /* mark flow with this ID */ +}; + +/* + * FLOW_ACTION_TYPE_TAG specification + */ +struct flow_action_tag { + uint32_t data; /* tag flow with this value */ + uint32_t mask; /* bit-mask applied to "data" */ + uint8_t index; /* index of tag to set */ +}; + +/* + * FLOW_ACTION_TYPE_PORT_ID specification + */ +struct flow_action_port_id { + uint32_t rte_flags; /* not used but to be binary compatible with rte flow */ + uint32_t id; +}; + +/* + * FLOW_ACTION_TYPE_QUEUE + */ +struct flow_action_queue { + uint16_t index; +}; + +/* + * FLOW_ACTION_TYPE_JUMP + */ +struct flow_action_jump { + uint32_t group; +}; + +/* + * FLOW_ACTION_TYPE_METER + */ +struct flow_action_meter { + uint32_t mtr_id; +}; + +/* + * FLOW_ACTION_TYPE_RAW_ENCAP + */ +struct flow_action_raw_encap { + uint8_t *data; + uint8_t *preserve; + size_t size; + struct flow_elem items[RAW_ENCAP_DECAP_ELEMS_MAX]; + int item_count; +}; + +/* + * FLOW_ACTION_TYPE_RAW_DECAP + */ +struct flow_action_raw_decap { + uint8_t *data; + size_t size; + struct flow_elem items[RAW_ENCAP_DECAP_ELEMS_MAX]; + int item_count; +}; + +/* + * Field IDs for MODIFY_FIELD action. + */ +enum flow_field_id { + FLOW_FIELD_START = 0, /* Start of a packet. */ + FLOW_FIELD_MAC_DST, /* Destination MAC Address. */ + FLOW_FIELD_MAC_SRC, /* Source MAC Address. */ + FLOW_FIELD_VLAN_TYPE, /* 802.1Q Tag Identifier. */ + FLOW_FIELD_VLAN_ID, /* 802.1Q VLAN Identifier. */ + FLOW_FIELD_MAC_TYPE, /* EtherType. */ + FLOW_FIELD_IPV4_DSCP, /* IPv4 DSCP. */ + FLOW_FIELD_IPV4_TTL, /* IPv4 Time To Live. */ + FLOW_FIELD_IPV4_SRC, /* IPv4 Source Address. */ + FLOW_FIELD_IPV4_DST, /* IPv4 Destination Address. */ + FLOW_FIELD_IPV6_DSCP, /* IPv6 DSCP. */ + FLOW_FIELD_IPV6_HOPLIMIT, /* IPv6 Hop Limit. */ + FLOW_FIELD_IPV6_SRC, /* IPv6 Source Address. */ + FLOW_FIELD_IPV6_DST, /* IPv6 Destination Address. */ + FLOW_FIELD_TCP_PORT_SRC, /* TCP Source Port Number. */ + FLOW_FIELD_TCP_PORT_DST, /* TCP Destination Port Number. */ + FLOW_FIELD_TCP_SEQ_NUM, /* TCP Sequence Number. */ + FLOW_FIELD_TCP_ACK_NUM, /* TCP Acknowledgment Number. */ + FLOW_FIELD_TCP_FLAGS, /* TCP Flags. */ + FLOW_FIELD_UDP_PORT_SRC, /* UDP Source Port Number. */ + FLOW_FIELD_UDP_PORT_DST, /* UDP Destination Port Number. */ + FLOW_FIELD_VXLAN_VNI, /* VXLAN Network Identifier. */ + FLOW_FIELD_GENEVE_VNI, /* GENEVE Network Identifier. */ + FLOW_FIELD_GTP_TEID, /* GTP Tunnel Endpoint Identifier. */ + FLOW_FIELD_TAG, /* Tag value. */ + FLOW_FIELD_MARK, /* Mark value. */ + FLOW_FIELD_META, /* Metadata value. */ + FLOW_FIELD_POINTER, /* Memory pointer. */ + FLOW_FIELD_VALUE, /* Immediate value. */ + FLOW_FIELD_IPV4_ECN, /* IPv4 ECN. */ + FLOW_FIELD_IPV6_ECN, /* IPv6 ECN. */ + FLOW_FIELD_GTP_PSC_QFI, /* GTP QFI. */ + FLOW_FIELD_METER_COLOR, /* Meter color marker. */ +}; + +/* + * Field description for MODIFY_FIELD action. + */ +struct flow_action_modify_data { + enum flow_field_id field; /* Field or memory type ID. */ + union { + struct { + /* Encapsulation level or tag index. */ + uint32_t level; + /* Number of bits to skip from a field. */ + uint32_t offset; + }; + /* + * Immediate value for FLOW_FIELD_VALUE, presented in the + * same byte order and length as in relevant rte_flow_item_xxx. + */ + uint8_t value[16]; + /* + * Memory address for FLOW_FIELD_POINTER, memory layout + * should be the same as for relevant field in the + * rte_flow_item_xxx structure. + */ + void *pvalue; + }; +}; + +/* + * Operation types for MODIFY_FIELD action. + */ +enum flow_modify_op { + FLOW_MODIFY_SET = 0, + FLOW_MODIFY_ADD, + FLOW_MODIFY_SUB, +}; + +/* + * FLOW_ACTION_TYPE_MODIFY_FIELD + */ +struct flow_action_modify_field { + enum flow_modify_op operation; + struct flow_action_modify_data dst; + struct flow_action_modify_data src; + uint32_t width; +}; + +struct flow_action { + enum flow_action_type type; + const void *conf; +}; + +enum flow_error_e { FLOW_ERROR_NONE, FLOW_ERROR_SUCCESS, FLOW_ERROR_GENERAL }; + +struct flow_error { + enum flow_error_e type; + const char *message; +}; + +enum flow_lag_cmd { + FLOW_LAG_SET_ENTRY, + FLOW_LAG_SET_ALL, + FLOW_LAG_SET_BALANCE, +}; + +/* + * Tunnel definition for DPDK RTE tunnel helper function support + */ +struct tunnel_cfg_s { + union { + struct { + uint32_t src_ip; /* BE */ + uint32_t dst_ip; /* BE */ + } v4; + struct { + uint8_t src_ip[16]; + uint8_t dst_ip[16]; + } v6; + struct { + uint64_t src_ip[2]; + uint64_t dst_ip[2]; + } v6_long; + }; + int ipversion; + uint16_t s_port; /* BE */ + uint16_t d_port; /* BE */ + int tun_type; +}; + +struct flow_eth_dev; /* port device */ +struct flow_handle; + +/* + * Device Management API + */ +int flow_reset_nic_dev(uint8_t adapter_no); + +struct flow_eth_dev *flow_get_eth_dev(uint8_t adapter_no, uint8_t hw_port_no, + uint32_t port_id, int alloc_queues, + struct flow_queue_id_s queue_ids[], + int *rss_target_id, + enum flow_eth_dev_profile flow_profile, + uint32_t exception_path); + +int flow_eth_dev_add_queue(struct flow_eth_dev *eth_dev, + struct flow_queue_id_s *queue_id); + +int flow_delete_eth_dev(struct flow_eth_dev *eth_dev); + +int flow_get_tunnel_definition(struct tunnel_cfg_s *tun, uint32_t flow_stat_id, + uint8_t vport); + +/* + * NT Flow API + */ +int flow_validate(struct flow_eth_dev *dev, const struct flow_elem item[], + const struct flow_action action[], struct flow_error *error); + +struct flow_handle *flow_create(struct flow_eth_dev *dev, + const struct flow_attr *attr, + const struct flow_elem item[], + const struct flow_action action[], + struct flow_error *error); + +int flow_destroy(struct flow_eth_dev *dev, struct flow_handle *flow, + struct flow_error *error); + +int flow_flush(struct flow_eth_dev *dev, struct flow_error *error); + +int flow_query(struct flow_eth_dev *dev, struct flow_handle *flow, + const struct flow_action *action, void **data, uint32_t *length, + struct flow_error *error); + +/* + * NT Flow FLM Meter API + */ +int flow_mtr_supported(struct flow_eth_dev *dev); + +uint64_t flow_mtr_meter_policy_n_max(void); + +int flow_mtr_set_profile(struct flow_eth_dev *dev, uint32_t profile_id, + uint64_t bucket_rate_a, uint64_t bucket_size_a, + uint64_t bucket_rate_b, uint64_t bucket_size_b); + +int flow_mtr_set_policy(struct flow_eth_dev *dev, uint32_t policy_id, int drop); + +int flow_mtr_create_meter(struct flow_eth_dev *dev, uint32_t mtr_id, + uint32_t profile_id, uint32_t policy_id, + uint64_t stats_mask); + +int flow_mtr_destroy_meter(struct flow_eth_dev *dev, uint32_t mtr_id); + +int flm_mtr_adjust_stats(struct flow_eth_dev *dev, uint32_t mtr_id, + uint32_t adjust_value); + +uint32_t flow_mtr_meters_supported(void); + +uint32_t flm_mtr_update_stats(struct flow_eth_dev *dev); +void flm_mtr_read_stats(struct flow_eth_dev *dev, uint32_t id, + uint64_t *stats_mask, uint64_t *green_pkt, + uint64_t *green_bytes, int clear); + +/* + * Config API + */ +int lag_set_port_group(uint8_t adapter_no, uint32_t port_mask); + +int lag_set_port_block(uint8_t adapter_no, uint32_t port_mask); + +int lag_set_config(uint8_t adapter_no, enum flow_lag_cmd cmd, uint32_t index, + uint32_t value); + +int flow_set_mtu_inline(struct flow_eth_dev *dev, uint32_t port, uint16_t mtu); + +#ifdef __cplusplus +} +#endif + +#endif /* _STREAM_BINARY_FLOW_API_H_ */