From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <dev-bounces@dpdk.org>
Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124])
	by inbox.dpdk.org (Postfix) with ESMTP id 28A6045501;
	Wed, 26 Jun 2024 21:58:16 +0200 (CEST)
Received: from mails.dpdk.org (localhost [127.0.0.1])
	by mails.dpdk.org (Postfix) with ESMTP id CB5C740E0B;
	Wed, 26 Jun 2024 21:56:27 +0200 (CEST)
Received: from egress-ip42a.ess.de.barracuda.com
 (egress-ip42a.ess.de.barracuda.com [18.185.115.201])
 by mails.dpdk.org (Postfix) with ESMTP id 7061640684
 for <dev@dpdk.org>; Wed, 26 Jun 2024 21:56:16 +0200 (CEST)
Received: from EUR05-DB8-obe.outbound.protection.outlook.com
 (mail-db8eur05lp2105.outbound.protection.outlook.com [104.47.17.105]) by
 mx-outbound14-103.eu-central-1a.ess.aws.cudaops.com (version=TLSv1.2
 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO);
 Wed, 26 Jun 2024 19:56:15 +0000
ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;
 b=OzhuM3A2rO1V75ra0IqCQOrPasyYchnBOLIKTr5K6jRmHSuXcM1FYnzZ3XK/weV76ZynqtUmhzFgzsjMRV5HhHtM1N1cuZGvwfR/sIRJwUqK9qUJz1zhrlPcoXtVHctgQ1E9HPe9sSrEu6t4d7hx68p2l9luinm2II/x4f+HAVFm18S9MiFPyeMej7pjhX5em1jj4z8OgM2ah8Wq7dnmCfpqrmHfhncAGjYDRHxMlVQgFtJN/lNZDKJQkM1LUcaZU/a1F6sZk8jLAg7KOJrvytMUvte10wH+vg11e7KR4NLncO5WRF4mbPMXQmx0f8kzbmmhhVuqtb9Qh22Of1+Q3g==
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=p5GBfmRxMlHFxyBInHculfiy+BtWn/4FoI6NHNMbsZQ=;
 b=T59CLxNdtOHj+67kCZsmSOz5XLJvpOaaYlLw+MHuIx2dPs25vuM06oLT0I0vzDdDb0hy/thHmpoVJH1px03btNe9/ijvsHAaQ+n7NAud72+cx8Hh3EcYtDFSumIf/juHjXl4qQcaLZbomvLXYyYQ43vNdSk8KKvzCvNg9wJprmOFPweIPxHR3JdI8gLZwCBQx1FGFwb0C+OudL9nPcEnFPPM/mtDwJNRoYqWCyOYvYI9svkCFpx8I2QAm47tbpC+lQ4VlYUguku2jcvESUGqHyLrWi+Z/8k9gEVWqj2/ojzUcIrd0UHCM76kzd3O5jKilXGwHI61oFaj8gyZcK1X3w==
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=fail (sender ip is
 178.72.21.4) smtp.rcpttodomain=dpdk.org smtp.mailfrom=napatech.com;
 dmarc=fail (p=reject sp=reject pct=100) action=oreject
 header.from=napatech.com; dkim=none (message not signed); arc=none (0)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=napatech.com;
 s=selector1;
 h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;
 bh=p5GBfmRxMlHFxyBInHculfiy+BtWn/4FoI6NHNMbsZQ=;
 b=jPnfc6YXLcsKCJVcD6/3cLjl5nhU+EOUu0NfYa2JQVj24szZqpTRSmNn1w2VS5tUKGNaess3jDkUgHNraqFGquCOK2DrAOzN/pDWk/1skfffEYBi7i7mtbi3w8qKofAyfbnAHv+4N1Nc4wleZmjMudOxwSAW1+1BwkC3nG1uoTA=
Received: from AS4P250CA0020.EURP250.PROD.OUTLOOK.COM (2603:10a6:20b:5e3::9)
 by PA4P190MB1213.EURP190.PROD.OUTLOOK.COM (2603:10a6:102:bc::24) with
 Microsoft SMTP Server (version=TLS1_2,
 cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7698.32; Wed, 26 Jun
 2024 19:56:13 +0000
Received: from AMS0EPF000001AC.eurprd05.prod.outlook.com
 (2603:10a6:20b:5e3:cafe::8d) by AS4P250CA0020.outlook.office365.com
 (2603:10a6:20b:5e3::9) with Microsoft SMTP Server (version=TLS1_2,
 cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7719.25 via Frontend
 Transport; Wed, 26 Jun 2024 19:56:13 +0000
X-MS-Exchange-Authentication-Results: spf=fail (sender IP is 178.72.21.4)
 smtp.mailfrom=napatech.com; dkim=none (message not signed)
 header.d=none;dmarc=fail action=oreject header.from=napatech.com;
Received-SPF: Fail (protection.outlook.com: domain of napatech.com does not
 designate 178.72.21.4 as permitted sender) receiver=protection.outlook.com;
 client-ip=178.72.21.4; helo=localhost.localdomain;
Received: from localhost.localdomain (178.72.21.4) by
 AMS0EPF000001AC.mail.protection.outlook.com (10.167.16.152) with Microsoft
 SMTP Server id 15.20.7677.15 via Frontend Transport; Wed, 26 Jun 2024
 19:56:13 +0000
From: Serhii Iliushyk <sil-plv@napatech.com>
To: dev@dpdk.org
Cc: mko-plv@napatech.com, sil-plv@napatech.com, ckm@napatech.com,
 andrew.rybchenko@oktetlabs.ru, ferruh.yigit@amd.com
Subject: [PATCH v4 19/23] net/ntnic: add QSFP support
Date: Wed, 26 Jun 2024 21:55:29 +0200
Message-ID: <20240626195545.1793419-19-sil-plv@napatech.com>
X-Mailer: git-send-email 2.45.0
In-Reply-To: <20240626195545.1793419-1-sil-plv@napatech.com>
References: <20240530144929.4127931-1-sil-plv@napatech.com>
 <20240626195545.1793419-1-sil-plv@napatech.com>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-EOPAttributedMessage: 0
X-MS-PublicTrafficType: Email
X-MS-TrafficTypeDiagnostic: AMS0EPF000001AC:EE_|PA4P190MB1213:EE_
Content-Type: text/plain
X-MS-Office365-Filtering-Correlation-Id: 82afd7f2-243b-4360-add8-08dc961a088b
X-MS-Exchange-SenderADCheck: 1
X-MS-Exchange-AntiSpam-Relay: 0
X-Microsoft-Antispam: BCL:0;
 ARA:13230038|36860700011|82310400024|376012|1800799022; 
X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?qrH5uEy/JkZXp/1y0SOToxzXLGhSlqIamwXSm6bFxGhiQL5wibo/y2Q9tSv0?=
 =?us-ascii?Q?Pk8QtjNHxw/n7hgM3VuVdB2hAHeGBxaFUC8BKTl1g7W+c4mQ2TbaYzXUb+St?=
 =?us-ascii?Q?iKIXdwy75IwDZSTGHkm+Co/RiOTLDptmKUcKwUuLuomBuhC6ej0vxpopVLPa?=
 =?us-ascii?Q?8j2sfXsac3urXzoiHvlXdiTYMf5c5IrUvaLtSJMn+Y+pxcwhqgUGkeWrLHl6?=
 =?us-ascii?Q?/Bc1Sfc+P5twyNvpYMZkK7oYI5bTiiJ8Q7JVJFnXerjRNszjVI+t10oa6FaH?=
 =?us-ascii?Q?kVCF1r1q4wrQGavcYsXH7GRhS9OHp6KQtgpeegPVEtMgC5TZz/rvXjptQ7GQ?=
 =?us-ascii?Q?Y9LvPnQGPDfYTlJ2EsDppFX9qJahItT0+ecjWgIHmA2RA2jgoj2TpcXz3luN?=
 =?us-ascii?Q?O1nEj9uh5q6imlyDf+Cr+AykZ79R1iDV7A2dMaEmyPDheFE9e9SVnuxfs2LW?=
 =?us-ascii?Q?unZIBp9h7CybHvy//dcpSo7tGEup+l1wSDGHvCwbPNmsv2MsYMn5yYh/3D0d?=
 =?us-ascii?Q?hOYg5MoPqQUy47ae6Qt8LC6SNZjgVI5Pp8U8KJX4vO1H4/0c4zetu38pYo4U?=
 =?us-ascii?Q?miiCLx1HlvcwjSj9a7cMtxi52jF8xHNc8nnqq/zIamc8LjG1E3n+t+Hx8y5g?=
 =?us-ascii?Q?/wT0NARGMmceF42bX9g20tns7KVup7A63OvQXfBW65uz2VmqD18aQnCOszpi?=
 =?us-ascii?Q?1K0EPM88txyaJ8+qD+PiWvKBa04928qlH6LplcQrjV1uaoyv4ujSPz6WKeVB?=
 =?us-ascii?Q?VNxmuEnj8T9sHQwAWhIDQ9g/Gc1f4eTzLiN+FkJFdvcqbxZA9bZPUt2MMeq8?=
 =?us-ascii?Q?DYcz3Px04zuUxYy7GOicoeNmTy4rhpEksaVxWG5tJALgfBdKHeGJw/47KL1p?=
 =?us-ascii?Q?9gZ1la1Rd8sqsSOiJODqMq5Iix7jfdT6sB/7pfKwUnmWlm1ZrE56dwESpwHx?=
 =?us-ascii?Q?0J4JQKODw9ao5Rs4lY+Lvi2qe4rK2ltfpNO4LR5LlFpvW9Qw6x6XRCk12M0o?=
 =?us-ascii?Q?n2e8zqLqT+iKvGim29HcmRRcSqo985BlcCRAbcOlnWYa6HiHum6mQypfX1Qk?=
 =?us-ascii?Q?zv+AD61wcCik+qz3dUeUbv74Vw9e9u9LFy1Y8AwnzgKVJ5PXikh6ekHxPd6x?=
 =?us-ascii?Q?CLeNCos/SWgGPD+oJlSgzSsYswtoodf1RggkWc1WaXBHS5oVswMfGYXIQNRo?=
 =?us-ascii?Q?TbM0rgkuX8H0hMYshQ+nxoE16F3RFgGOJYMGtxWK5Jri0htRSnWgfX5UM88L?=
 =?us-ascii?Q?4ZAVqSKhU6ghDjYY+I3ejm53xKncud1umUExZfIbC4cRw4j479QhjwC5TG6F?=
 =?us-ascii?Q?OpItFHTXqkQ/0TrdITWz0kSDP+OBDHWqcDo3hgm/BwJacUsge2D3tx64enFJ?=
 =?us-ascii?Q?LGMOEj1eREDLNl42DEzYdBuQSBygPQ89crG4Bm8cJMHBlmDtZSWlUI3Pw/Ne?=
 =?us-ascii?Q?obflj0p2NCiG5wYH411KHhdGSutbCEE8?=
X-Forefront-Antispam-Report: CIP:178.72.21.4; CTRY:DK; LANG:en; SCL:1; SRV:;
 IPV:NLI; SFV:NSPM; H:localhost.localdomain; PTR:InfoDomainNonexistent;
 CAT:NONE; SFS:(13230038)(36860700011)(82310400024)(376012)(1800799022);
 DIR:OUT; SFP:1102; 
X-MS-Exchange-AntiSpam-ExternalHop-MessageData-ChunkCount: 1
X-MS-Exchange-AntiSpam-ExternalHop-MessageData-0: Ja4Q/CmYvd1M/+7uqTfj8jB9nCOqyx0hZe64Aj10c8/8tts45lUy4jFEt40u2G+NrSGwvLr4CvM0/HYWuygRZFutmqwJtDrlmgbI+3jJAIEWyWb3zVZ76fUjRKuTeDYpo78Hp3UYRwNGPYghu2cRaak1TF3DvQsi2KrL0DcsW2E42qUIboHMc38WlTVxRbyWe6FX0VNxVN9j1rUApLB/No5A1H/Hf6l8eE8YF5Qt5X+QFt8Y/3J8S3oTTScgK4ZicLVSVUIFlDzF62T4LzcOiNUAK2BpJ0SkFv2dvIJ5334ki4R3UhzTJ45tvsSBLXSa3vWXtn1uFHS8QbMSmh1Os4HfbB0ig/h70AbMrVM4uztdo38khPwHxpWC3C8weBWR+LUzwP1KEv9cvhGDbE9QIjPB7k6k3I2TXhzekPY6+xqbgSjHd0tguzSFFyLjEYGhtpc9/26abIErK3iQFbqU79Opk3SAW+l316r9AGzWr53ayzxbmb4VBGYunkh+SW92ETuHLT75rm65PBAm40Qrgsha1OtRL8nSS1IWu+bifMbL3dEv7tZTXLhqURq/Vz+vjdvb/ebCKQ57Ub74MNYLUuecCdoolRrQRtG5mwSH8g71QszKTj+OjmmuQvs1XjswUwV0jD1gZQf3yPjzUjxyDw==
X-OriginatorOrg: napatech.com
X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Jun 2024 19:56:13.4580 (UTC)
X-MS-Exchange-CrossTenant-Network-Message-Id: 82afd7f2-243b-4360-add8-08dc961a088b
X-MS-Exchange-CrossTenant-Id: c4540d0b-728a-4233-9da5-9ea30c7ec3ed
X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=c4540d0b-728a-4233-9da5-9ea30c7ec3ed; Ip=[178.72.21.4];
 Helo=[localhost.localdomain]
X-MS-Exchange-CrossTenant-AuthSource: AMS0EPF000001AC.eurprd05.prod.outlook.com
X-MS-Exchange-CrossTenant-AuthAs: Anonymous
X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem
X-MS-Exchange-Transport-CrossTenantHeadersStamped: PA4P190MB1213
X-BESS-ID: 1719431775-303687-24099-15040-1
X-BESS-VER: 2019.1_20240620.2317
X-BESS-Apparent-Source-IP: 104.47.17.105
X-BESS-Parts: H4sIAAAAAAACA4uuVkqtKFGyUioBkjpK+cVKVoZmhgaGQGYGUDQlxdDYzMTCMN
 E8LcUgLTkp0STJ3DzZOCUx1dLQzCLRQqk2FgBdoNAkQgAAAA==
X-BESS-Outbound-Spam-Score: 0.50
X-BESS-Outbound-Spam-Report: Code version 3.2,
 rules version 3.2.2.257218 [from 
 cloudscan17-43.eu-central-1b.ess.aws.cudaops.com]
 Rule breakdown below
 pts rule name              description
 ---- ---------------------- --------------------------------
 0.50 BSF_RULE7568M          META: Custom Rule 7568M 
 0.00 BSF_BESS_OUTBOUND      META: BESS Outbound 
X-BESS-Outbound-Spam-Status: SCORE=0.50 using account:ESS113687 scores of
 KILL_LEVEL=7.0 tests=BSF_RULE7568M, BSF_BESS_OUTBOUND
X-BESS-BRTS-Status: 1
X-BeenThere: dev@dpdk.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: DPDK patches and discussions <dev.dpdk.org>
List-Unsubscribe: <https://mails.dpdk.org/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://mails.dpdk.org/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <https://mails.dpdk.org/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=subscribe>
Errors-To: dev-bounces@dpdk.org

Includes support for QSFP and QSFP+.

Signed-off-by: Serhii Iliushyk <sil-plv@napatech.com>
---
 drivers/net/ntnic/include/ntnic_nim.h         |  10 +
 .../link_mgmt/link_100g/nt4ga_link_100g.c     |  12 +-
 drivers/net/ntnic/nim/i2c_nim.c               | 310 +++++++++++++++++-
 drivers/net/ntnic/nim/i2c_nim.h               |  14 +-
 drivers/net/ntnic/nim/nim_defines.h           |   3 +
 drivers/net/ntnic/nim/qsfp_registers.h        |  43 +++
 6 files changed, 389 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/ntnic/nim/qsfp_registers.h

diff --git a/drivers/net/ntnic/include/ntnic_nim.h b/drivers/net/ntnic/include/ntnic_nim.h
index 263875a857..300842b570 100644
--- a/drivers/net/ntnic/include/ntnic_nim.h
+++ b/drivers/net/ntnic/include/ntnic_nim.h
@@ -15,6 +15,8 @@ typedef enum i2c_type {
 enum nt_port_type_e {
 	NT_PORT_TYPE_NOT_AVAILABLE = 0,	/* The NIM/port type is not available (unknown) */
 	NT_PORT_TYPE_NOT_RECOGNISED,	/* The NIM/port type not recognized */
+	NT_PORT_TYPE_QSFP_PLUS_NOT_PRESENT,	/* QSFP type but slot is empty */
+	NT_PORT_TYPE_QSFP_PLUS,	/* QSFP type */
 };
 
 typedef enum nt_port_type_e nt_port_type_t, *nt_port_type_p;
@@ -51,6 +53,14 @@ typedef struct nim_i2c_ctx {
 	bool tx_disable;
 	bool dmi_supp;
 
+	union {
+		struct {
+			bool rx_only;
+			union {
+			} specific_u;
+		} qsfp;
+
+	} specific_u;
 } nim_i2c_ctx_t, *nim_i2c_ctx_p;
 
 struct nim_sensor_group {
diff --git a/drivers/net/ntnic/link_mgmt/link_100g/nt4ga_link_100g.c b/drivers/net/ntnic/link_mgmt/link_100g/nt4ga_link_100g.c
index 4c159431e1..1f4ed62498 100644
--- a/drivers/net/ntnic/link_mgmt/link_100g/nt4ga_link_100g.c
+++ b/drivers/net/ntnic/link_mgmt/link_100g/nt4ga_link_100g.c
@@ -18,6 +18,7 @@ static int _create_nim(adapter_info_t *drv, int port)
 	int res = 0;
 	const uint8_t valid_nim_id = 17U;
 	nim_i2c_ctx_t *nim_ctx;
+	sfp_nim_state_t nim;
 	nt4ga_link_t *link_info = &drv->nt4ga_link;
 
 	assert(port >= 0 && port < NUM_ADAPTER_PORTS_MAX);
@@ -31,11 +32,20 @@ static int _create_nim(adapter_info_t *drv, int port)
 	 */
 	nt_os_wait_usec(1000000);	/* pause 1.0s */
 
-	res = construct_and_preinit_nim(nim_ctx);
+	res = construct_and_preinit_nim(nim_ctx, NULL);
 
 	if (res)
 		return res;
 
+	res = nim_state_build(nim_ctx, &nim);
+
+	if (res)
+		return res;
+
+	NT_LOG(DBG, NTHW, "%s: NIM id = %u (%s), br = %u, vendor = '%s', pn = '%s', sn='%s'\n",
+		drv->mp_port_id_str[port], nim_ctx->nim_id, nim_id_to_text(nim_ctx->nim_id), nim.br,
+		nim_ctx->vendor_name, nim_ctx->prod_no, nim_ctx->serial_no);
+
 	/*
 	 * Does the driver support the NIM module type?
 	 */
diff --git a/drivers/net/ntnic/nim/i2c_nim.c b/drivers/net/ntnic/nim/i2c_nim.c
index 2918eda072..4831078a2c 100644
--- a/drivers/net/ntnic/nim/i2c_nim.c
+++ b/drivers/net/ntnic/nim/i2c_nim.c
@@ -10,6 +10,7 @@
 #include "ntlog.h"
 #include "nt_util.h"
 #include "ntnic_mod_reg.h"
+#include "qsfp_registers.h"
 #include "nim_defines.h"
 
 #define NIM_READ false
@@ -17,6 +18,25 @@
 #define NIM_PAGE_SEL_REGISTER 127
 #define NIM_I2C_0XA0 0xA0	/* Basic I2C address */
 
+
+static bool page_addressing(nt_nim_identifier_t id)
+{
+	switch (id) {
+	case NT_NIM_QSFP:
+	case NT_NIM_QSFP_PLUS:
+		return true;
+
+	default:
+		NT_LOG(DBG, NTNIC, "Unknown NIM identifier %d\n", id);
+		return false;
+	}
+}
+
+static nt_nim_identifier_t translate_nimid(const nim_i2c_ctx_t *ctx)
+{
+	return (nt_nim_identifier_t)ctx->nim_id;
+}
+
 static int nim_read_write_i2c_data(nim_i2c_ctx_p ctx, bool do_write, uint16_t lin_addr,
 	uint8_t i2c_addr, uint8_t a_reg_addr, uint8_t seq_cnt,
 	uint8_t *p_data)
@@ -158,6 +178,13 @@ static int nim_read_write_data_lin(nim_i2c_ctx_p ctx, bool m_page_addressing, ui
 	return 0;
 }
 
+static int read_data_lin(nim_i2c_ctx_p ctx, uint16_t lin_addr, uint16_t length, void *data)
+{
+	/* Wrapper for using Mutex for QSFP TODO */
+	return nim_read_write_data_lin(ctx, page_addressing(ctx->nim_id), lin_addr, length, data,
+			NIM_READ);
+}
+
 static int nim_read_id(nim_i2c_ctx_t *ctx)
 {
 	/* We are only reading the first byte so we don't care about pages here. */
@@ -205,20 +232,301 @@ static int i2c_nim_common_construct(nim_i2c_ctx_p ctx)
 	return 0;
 }
 
+/*
+ * Read vendor information at a certain address. Any trailing whitespace is
+ * removed and a missing string termination in the NIM data is handled.
+ */
+static int nim_read_vendor_info(nim_i2c_ctx_p ctx, uint16_t addr, uint8_t max_len, char *p_data)
+{
+	const bool pg_addr = page_addressing(ctx->nim_id);
+	int i;
+	/* Subtract "1" from max_len that includes a terminating "0" */
+
+	if (nim_read_write_data_lin(ctx, pg_addr, addr, (uint8_t)(max_len - 1), (uint8_t *)p_data,
+			NIM_READ) != 0) {
+		return -1;
+	}
+
+	/* Terminate at first found white space */
+	for (i = 0; i < max_len - 1; i++) {
+		if (*p_data == ' ' || *p_data == '\n' || *p_data == '\t' || *p_data == '\v' ||
+			*p_data == '\f' || *p_data == '\r') {
+			*p_data = '\0';
+			return 0;
+		}
+
+		p_data++;
+	}
+
+	/*
+	 * Add line termination as the very last character, if it was missing in the
+	 * NIM data
+	 */
+	*p_data = '\0';
+	return 0;
+}
+
+static void qsfp_read_vendor_info(nim_i2c_ctx_t *ctx)
+{
+	nim_read_vendor_info(ctx, QSFP_VENDOR_NAME_LIN_ADDR, sizeof(ctx->vendor_name),
+		ctx->vendor_name);
+	nim_read_vendor_info(ctx, QSFP_VENDOR_PN_LIN_ADDR, sizeof(ctx->prod_no), ctx->prod_no);
+	nim_read_vendor_info(ctx, QSFP_VENDOR_SN_LIN_ADDR, sizeof(ctx->serial_no), ctx->serial_no);
+	nim_read_vendor_info(ctx, QSFP_VENDOR_DATE_LIN_ADDR, sizeof(ctx->date), ctx->date);
+	nim_read_vendor_info(ctx, QSFP_VENDOR_REV_LIN_ADDR, (uint8_t)(sizeof(ctx->rev) - 2),
+		ctx->rev);	/*OBS Only two bytes*/
+}
+static int qsfp_nim_state_build(nim_i2c_ctx_t *ctx, sfp_nim_state_t *state)
+{
+	int res = 0;	/* unused due to no readings from HW */
+
+	assert(ctx && state);
+	assert(ctx->nim_id != NT_NIM_UNKNOWN && "Nim is not initialized");
+
+	(void)memset(state, 0, sizeof(*state));
+
+	switch (ctx->nim_id) {
+	case 12U:
+		state->br = 10U;/* QSFP: 4 x 1G = 4G */
+		break;
+
+	case 13U:
+		state->br = 103U;	/* QSFP+: 4 x 10G = 40G */
+		break;
+
+	default:
+		NT_LOG(INF, NIM, "nim_id = %u is not an QSFP/QSFP+ module\n", ctx->nim_id);
+		res = -1;
+	}
+
+	return res;
+}
+
+int nim_state_build(nim_i2c_ctx_t *ctx, sfp_nim_state_t *state)
+{
+	return qsfp_nim_state_build(ctx, state);
+}
+
 const char *nim_id_to_text(uint8_t nim_id)
 {
 	switch (nim_id) {
 	case 0x0:
 		return "UNKNOWN";
 
+	case 0x0C:
+		return "QSFP";
+
+	case 0x0D:
+		return "QSFP+";
+
 	default:
 		return "ILLEGAL!";
 	}
 }
 
-int construct_and_preinit_nim(nim_i2c_ctx_p ctx)
+/*
+ * Disable laser for specific lane or all lanes
+ */
+int nim_qsfp_plus_nim_set_tx_laser_disable(nim_i2c_ctx_p ctx, bool disable, int lane_idx)
+{
+	uint8_t value;
+	uint8_t mask;
+	const bool pg_addr = page_addressing(ctx->nim_id);
+
+	if (lane_idx < 0)	/* If no lane is specified then all lanes */
+		mask = QSFP_SOFT_TX_ALL_DISABLE_BITS;
+
+	else
+		mask = (uint8_t)(1U << lane_idx);
+
+	if (nim_read_write_data_lin(ctx, pg_addr, QSFP_CONTROL_STATUS_LIN_ADDR, sizeof(value),
+			&value, NIM_READ) != 0) {
+		return -1;
+	}
+
+	if (disable)
+		value |= mask;
+
+	else
+		value &= (uint8_t)(~mask);
+
+	if (nim_read_write_data_lin(ctx, pg_addr, QSFP_CONTROL_STATUS_LIN_ADDR, sizeof(value),
+			&value, NIM_WRITE) != 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Import length info in various units from NIM module data and convert to meters
+ */
+static void nim_import_len_info(nim_i2c_ctx_p ctx, uint8_t *p_nim_len_info, uint16_t *p_nim_units)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(ctx->len_info); i++)
+		if (*(p_nim_len_info + i) == 255) {
+			ctx->len_info[i] = 65535;
+
+		} else {
+			uint32_t len = *(p_nim_len_info + i) * *(p_nim_units + i);
+
+			if (len > 65535)
+				ctx->len_info[i] = 65535;
+
+			else
+				ctx->len_info[i] = (uint16_t)len;
+		}
+}
+
+static int qsfpplus_read_basic_data(nim_i2c_ctx_t *ctx)
+{
+	const bool pg_addr = page_addressing(ctx->nim_id);
+	uint8_t options;
+	uint8_t value;
+	uint8_t nim_len_info[5];
+	uint16_t nim_units[5] = { 1000, 2, 1, 1, 1 };	/* QSFP MSA units in meters */
+	const char *yes_no[2] = { "No", "Yes" };
+	(void)yes_no;
+	NT_LOG(DBG, NTNIC, "Instance %d: NIM id: %s (%d)\n", ctx->instance,
+		nim_id_to_text(ctx->nim_id), ctx->nim_id);
+
+	/* Read DMI options */
+	if (nim_read_write_data_lin(ctx, pg_addr, QSFP_DMI_OPTION_LIN_ADDR, sizeof(options),
+			&options, NIM_READ) != 0) {
+		return -1;
+	}
+
+	ctx->avg_pwr = options & QSFP_DMI_AVG_PWR_BIT;
+	NT_LOG(DBG, NTNIC, "Instance %d: NIM options: (DMI: Yes, AvgPwr: %s)\n", ctx->instance,
+		yes_no[ctx->avg_pwr]);
+
+	qsfp_read_vendor_info(ctx);
+	NT_LOG(DBG, PMD,
+		"Instance %d: NIM info: (Vendor: %s, PN: %s, SN: %s, Date: %s, Rev: %s)\n",
+		ctx->instance, ctx->vendor_name, ctx->prod_no, ctx->serial_no, ctx->date, ctx->rev);
+
+	if (nim_read_write_data_lin(ctx, pg_addr, QSFP_SUP_LEN_INFO_LIN_ADDR, sizeof(nim_len_info),
+			nim_len_info, NIM_READ) != 0) {
+		return -1;
+	}
+
+	/*
+	 * Returns supported length information in meters for various fibers as 5 indivi-
+	 * dual values: [SM(9um), EBW(50um), MM(50um), MM(62.5um), Copper]
+	 * If no length information is available for a certain entry, the returned value
+	 * will be zero. This will be the case for SFP modules - EBW entry.
+	 * If the MSBit is set the returned value in the lower 31 bits indicates that the
+	 * supported length is greater than this.
+	 */
+
+	nim_import_len_info(ctx, nim_len_info, nim_units);
+
+	/* Read required power level */
+	if (nim_read_write_data_lin(ctx, pg_addr, QSFP_EXTENDED_IDENTIFIER, sizeof(value), &value,
+			NIM_READ) != 0) {
+		return -1;
+	}
+
+	/*
+	 * Get power class according to SFF-8636 Rev 2.7, Table 6-16, Page 43:
+	 * If power class >= 5 setHighPower must be called for the module to be fully
+	 * functional
+	 */
+	if ((value & QSFP_POWER_CLASS_BITS_5_7) == 0) {
+		/* NIM in power class 1 - 4 */
+		ctx->pwr_level_req = (uint8_t)(((value & QSFP_POWER_CLASS_BITS_1_4) >> 6) + 1);
+
+	} else {
+		/* NIM in power class 5 - 7 */
+		ctx->pwr_level_req = (uint8_t)((value & QSFP_POWER_CLASS_BITS_5_7) + 4);
+	}
+
+	return 0;
+}
+
+static void qsfpplus_find_port_params(nim_i2c_ctx_p ctx)
+{
+	uint8_t device_tech;
+	read_data_lin(ctx, QSFP_TRANSMITTER_TYPE_LIN_ADDR, sizeof(device_tech), &device_tech);
+
+	switch (device_tech & 0xF0) {
+	case 0xA0:	/* Copper cable unequalized */
+		break;
+
+	case 0xC0:	/* Copper cable, near and far end limiting active equalizers */
+	case 0xD0:	/* Copper cable, far end limiting active equalizers */
+	case 0xE0:	/* Copper cable, near end limiting active equalizers */
+		break;
+
+	default:/* Optical */
+		ctx->port_type = NT_PORT_TYPE_QSFP_PLUS;
+		break;
+	}
+}
+
+static void qsfpplus_set_speed_mask(nim_i2c_ctx_p ctx)
+{
+	ctx->speed_mask = (ctx->lane_idx < 0) ? NT_LINK_SPEED_40G : (NT_LINK_SPEED_10G);
+}
+
+static void qsfpplus_construct(nim_i2c_ctx_p ctx, int8_t lane_idx)
+{
+	assert(lane_idx < 4);
+	ctx->lane_idx = lane_idx;
+	ctx->lane_count = 4;
+}
+
+static int qsfpplus_preinit(nim_i2c_ctx_p ctx, int8_t lane_idx)
+{
+	qsfpplus_construct(ctx, lane_idx);
+	int res = qsfpplus_read_basic_data(ctx);
+
+	if (!res) {
+		qsfpplus_find_port_params(ctx);
+
+		/*
+		 * Read if TX_DISABLE has been implemented
+		 * For passive optical modules this is required while it for copper and active
+		 * optical modules is optional. Under all circumstances register 195.4 will
+		 * indicate, if TX_DISABLE has been implemented in register 86.0-3
+		 */
+		uint8_t value;
+		read_data_lin(ctx, QSFP_OPTION3_LIN_ADDR, sizeof(value), &value);
+
+		ctx->tx_disable = (value & QSFP_OPTION3_TX_DISABLE_BIT) != 0;
+
+		if (ctx->tx_disable)
+			ctx->options |= (1 << NIM_OPTION_TX_DISABLE);
+
+		/*
+		 * Previously - considering AFBR-89BRDZ - code tried to establish if a module was
+		 * RxOnly by testing the state of the lasers after reset. Lasers were for this
+		 * module default disabled.
+		 * However that code did not work for GigaLight, GQS-MPO400-SR4C so it was
+		 * decided that this option should not be detected automatically but from PN
+		 */
+		ctx->specific_u.qsfp.rx_only = (ctx->options & (1 << NIM_OPTION_RX_ONLY)) != 0;
+		qsfpplus_set_speed_mask(ctx);
+	}
+
+	return res;
+}
+
+int construct_and_preinit_nim(nim_i2c_ctx_p ctx, void *extra)
 {
 	int res = i2c_nim_common_construct(ctx);
 
+	switch (translate_nimid(ctx)) {
+	case NT_NIM_QSFP_PLUS:
+		qsfpplus_preinit(ctx, extra ? *(int8_t *)extra : (int8_t)-1);
+		break;
+
+	default:
+		res = 1;
+		NT_LOG(ERR, NTHW, "NIM type %s is not supported.\n", nim_id_to_text(ctx->nim_id));
+	}
+
 	return res;
 }
diff --git a/drivers/net/ntnic/nim/i2c_nim.h b/drivers/net/ntnic/nim/i2c_nim.h
index e89ae47835..edb6dcf1b6 100644
--- a/drivers/net/ntnic/nim/i2c_nim.h
+++ b/drivers/net/ntnic/nim/i2c_nim.h
@@ -8,17 +8,29 @@
 
 #include "ntnic_nim.h"
 
+typedef struct sfp_nim_state {
+	uint8_t br;	/* bit rate, units of 100 MBits/sec */
+} sfp_nim_state_t, *sfp_nim_state_p;
+
+/*
+ * Builds an nim state for the port implied by `ctx`, returns zero
+ * if successful, and non-zero otherwise. SFP and QSFP nims are supported
+ */
+int nim_state_build(nim_i2c_ctx_t *ctx, sfp_nim_state_t *state);
+
 /*
  * Returns a type name such as "SFP/SFP+" for a given NIM type identifier,
  * or the string "ILLEGAL!".
  */
 const char *nim_id_to_text(uint8_t nim_id);
 
+int nim_qsfp_plus_nim_set_tx_laser_disable(nim_i2c_ctx_t *ctx, bool disable, int lane_idx);
+
 /*
  * This function tries to classify NIM based on it's ID and some register reads
  * and collects information into ctx structure. The @extra parameter could contain
  * the initialization argument for specific type of NIMS.
  */
-int construct_and_preinit_nim(nim_i2c_ctx_p ctx);
+int construct_and_preinit_nim(nim_i2c_ctx_p ctx, void *extra);
 
 #endif	/* I2C_NIM_H_ */
diff --git a/drivers/net/ntnic/nim/nim_defines.h b/drivers/net/ntnic/nim/nim_defines.h
index 9ba861bb4f..e5a033a3d4 100644
--- a/drivers/net/ntnic/nim/nim_defines.h
+++ b/drivers/net/ntnic/nim/nim_defines.h
@@ -7,6 +7,7 @@
 #define NIM_DEFINES_H_
 
 #define NIM_IDENTIFIER_ADDR 0	/* 1 byte */
+#define QSFP_EXTENDED_IDENTIFIER 129
 
 /* I2C addresses */
 #define NIM_I2C_0XA0 0xA0	/* Basic I2C address */
@@ -23,6 +24,8 @@ typedef enum {
 
 enum nt_nim_identifier_e {
 	NT_NIM_UNKNOWN = 0x00,	/* Nim type is unknown */
+	NT_NIM_QSFP = 0x0C,	/* Nim type = QSFP */
+	NT_NIM_QSFP_PLUS = 0x0D,/* Nim type = QSFP+ */
 };
 typedef enum nt_nim_identifier_e nt_nim_identifier_t;
 
diff --git a/drivers/net/ntnic/nim/qsfp_registers.h b/drivers/net/ntnic/nim/qsfp_registers.h
new file mode 100644
index 0000000000..13172ce30b
--- /dev/null
+++ b/drivers/net/ntnic/nim/qsfp_registers.h
@@ -0,0 +1,43 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _QSFP_REGISTERS_H
+#define _QSFP_REGISTERS_H
+
+/*
+ * QSFP Registers
+ */
+#define QSFP_INT_STATUS_RX_LOS_ADDR 3
+#define QSFP_TEMP_LIN_ADDR 22
+#define QSFP_VOLT_LIN_ADDR 26
+#define QSFP_RX_PWR_LIN_ADDR 34	/* uint16_t [0..3] */
+#define QSFP_TX_BIAS_LIN_ADDR 42/* uint16_t [0..3] */
+#define QSFP_TX_PWR_LIN_ADDR 50	/* uint16_t [0..3] */
+
+#define QSFP_CONTROL_STATUS_LIN_ADDR 86
+#define QSFP_SOFT_TX_ALL_DISABLE_BITS 0x0F
+
+#define QSFP_POWER_CLASS_BITS_1_4 0xC0
+#define QSFP_POWER_CLASS_BITS_5_7 0x03
+
+#define QSFP_SUP_LEN_INFO_LIN_ADDR 142	/* 5bytes */
+#define QSFP_TRANSMITTER_TYPE_LIN_ADDR 147	/* 1byte */
+#define QSFP_VENDOR_NAME_LIN_ADDR 148	/* 16bytes */
+#define QSFP_VENDOR_PN_LIN_ADDR 168	/* 16bytes */
+#define QSFP_VENDOR_SN_LIN_ADDR 196	/* 16bytes */
+#define QSFP_VENDOR_DATE_LIN_ADDR 212	/* 8bytes */
+#define QSFP_VENDOR_REV_LIN_ADDR 184	/* 2bytes */
+
+#define QSFP_SPEC_COMPLIANCE_CODES_ADDR 131	/* 8 bytes */
+#define QSFP_EXT_SPEC_COMPLIANCE_CODES_ADDR 192	/* 1 byte */
+
+#define QSFP_OPTION3_LIN_ADDR 195
+#define QSFP_OPTION3_TX_DISABLE_BIT (1 << 4)
+
+#define QSFP_DMI_OPTION_LIN_ADDR 220
+#define QSFP_DMI_AVG_PWR_BIT (1 << 3)
+
+
+#endif	/* _QSFP_REGISTERS_H */
-- 
2.45.0