DPDK patches and discussions
 help / color / mirror / Atom feed
From: "Renyong Wan" <wanry@yunsilicon.com>
To: <dev@dpdk.org>
Cc: <thomas@monjalon.net>, <stephen@networkplumber.org>,
	 <qianr@yunsilicon.com>, <nana@yunsilicon.com>,
	<zhangxx@yunsilicon.com>,  <xudw@yunsilicon.com>,
	<jacky@yunsilicon.com>, <weihg@yunsilicon.com>,
	 <zhenghy@yunsilicon.com>
Subject: [PATCH 03/14] net/xsc: support module EEPROM dump
Date: Fri, 29 Aug 2025 16:24:12 +0800	[thread overview]
Message-ID: <20250829082411.24369-4-wanry@yunsilicon.com> (raw)
In-Reply-To: <20250829082406.24369-1-wanry@yunsilicon.com>

Add support for querying and reading the EEPROM of SFP/QSFP modules.

Signed-off-by: Rong Qian <qianr@yunsilicon.com>
Signed-off-by: Renyong Wan <wanry@yunsilicon.com>
---
 doc/guides/nics/features/xsc.ini |   1 +
 drivers/net/xsc/xsc_cmd.h        |  15 +++
 drivers/net/xsc/xsc_dev.c        | 185 +++++++++++++++++++++++++++++++
 drivers/net/xsc/xsc_dev.h        |  63 +++++++++++
 drivers/net/xsc/xsc_ethdev.c     | 107 ++++++++++++++++++
 5 files changed, 371 insertions(+)

diff --git a/doc/guides/nics/features/xsc.ini b/doc/guides/nics/features/xsc.ini
index 3b02289764..46c56fc921 100644
--- a/doc/guides/nics/features/xsc.ini
+++ b/doc/guides/nics/features/xsc.ini
@@ -16,6 +16,7 @@ Inner L4 checksum    = Y
 Basic stats          = Y
 Stats per queue      = Y
 FW version           = Y
+Module EEPROM dump   = Y
 Linux                = Y
 ARMv8                = Y
 x86-64               = Y
diff --git a/drivers/net/xsc/xsc_cmd.h b/drivers/net/xsc/xsc_cmd.h
index 433dcd0afa..82244d4011 100644
--- a/drivers/net/xsc/xsc_cmd.h
+++ b/drivers/net/xsc/xsc_cmd.h
@@ -23,6 +23,7 @@ enum xsc_cmd_opcode {
 	XSC_CMD_OP_RTR2RTS_QP		= 0x504,
 	XSC_CMD_OP_QP_2RST		= 0x50A,
 	XSC_CMD_OP_CREATE_MULTI_QP	= 0x515,
+	XSC_CMD_OP_ACCESS_REG		= 0x805,
 	XSC_CMD_OP_MODIFY_NIC_HCA	= 0x812,
 	XSC_CMD_OP_MODIFY_RAW_QP	= 0x81f,
 	XSC_CMD_OP_EXEC_NP		= 0x900,
@@ -384,4 +385,18 @@ struct xsc_cmd_modify_nic_hca_mbox_out {
 	uint8_t rsvd[4];
 };
 
+struct xsc_cmd_access_reg_mbox_in {
+	struct xsc_cmd_inbox_hdr hdr;
+	uint8_t rsvd0[2];
+	rte_be16_t register_id;
+	rte_be32_t arg;
+	rte_be32_t data[];
+};
+
+struct xsc_cmd_access_reg_mbox_out {
+	struct xsc_cmd_outbox_hdr hdr;
+	uint8_t rsvd[8];
+	rte_be32_t data[];
+};
+
 #endif /* _XSC_CMD_H_ */
diff --git a/drivers/net/xsc/xsc_dev.c b/drivers/net/xsc/xsc_dev.c
index 66f98d2327..2c55306d35 100644
--- a/drivers/net/xsc/xsc_dev.c
+++ b/drivers/net/xsc/xsc_dev.c
@@ -411,3 +411,188 @@ xsc_dev_fw_version_get(struct xsc_dev *xdev, char *fw_version, size_t fw_size)
 
 	return 0;
 }
+
+static int
+xsc_dev_access_reg(struct xsc_dev *xdev, void *data_in, int size_in,
+		   void *data_out, int size_out, uint16_t reg_num)
+{
+	struct xsc_cmd_access_reg_mbox_in *in;
+	struct xsc_cmd_access_reg_mbox_out *out;
+	int ret = -1;
+
+	in = malloc(sizeof(*in) + size_in);
+	if (in == NULL) {
+		rte_errno = ENOMEM;
+		PMD_DRV_LOG(ERR, "Failed to malloc access reg mbox in memory");
+		return -rte_errno;
+	}
+	memset(in, 0, sizeof(*in) + size_in);
+
+	out = malloc(sizeof(*out) + size_out);
+	if (out == NULL) {
+		rte_errno = ENOMEM;
+		PMD_DRV_LOG(ERR, "Failed to malloc access reg mbox out memory");
+		goto alloc_out_fail;
+	}
+	memset(out, 0, sizeof(*out) + size_out);
+
+	memcpy(in->data, data_in, size_in);
+	in->hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_ACCESS_REG);
+	in->arg = 0;
+	in->register_id = rte_cpu_to_be_16(reg_num);
+
+	ret = xsc_dev_mailbox_exec(xdev, in, sizeof(*in) + size_in, out,
+				   sizeof(*out) + size_out);
+	if (ret != 0 || out->hdr.status != 0) {
+		rte_errno = ENOEXEC;
+		PMD_DRV_LOG(ERR, "Failed to access reg");
+		goto exit;
+	}
+
+	memcpy(data_out, out->data, size_out);
+
+exit:
+	free(out);
+
+alloc_out_fail:
+	free(in);
+	return ret;
+}
+
+static int
+xsc_dev_query_mcia(struct xsc_dev *xdev,
+		   struct xsc_module_eeprom_query_params *params,
+		   uint8_t *data)
+{
+	struct xsc_dev_reg_mcia in = { };
+	struct xsc_dev_reg_mcia out = { };
+	int ret;
+	void *ptr;
+	uint16_t size;
+
+	size = RTE_MIN(params->size, XSC_EEPROM_MAX_BYTES);
+	in.i2c_device_address = params->i2c_address;
+	in.module = params->module_number & 0x000000FF;
+	in.device_address = params->offset;
+	in.page_number = params->page;
+	in.size = size;
+
+	ret = xsc_dev_access_reg(xdev, &in, sizeof(in), &out, sizeof(out), XSC_REG_MCIA);
+	if (ret != 0)
+		return ret;
+
+	ptr = out.dword_0;
+	memcpy(data, ptr, size);
+
+	return size;
+}
+
+static void
+xsc_dev_sfp_eeprom_params_set(uint16_t *i2c_addr, uint32_t *page_num, uint16_t *offset)
+{
+	*i2c_addr = XSC_I2C_ADDR_LOW;
+	*page_num = 0;
+
+	if (*offset < XSC_EEPROM_PAGE_LENGTH)
+		return;
+
+	*i2c_addr = XSC_I2C_ADDR_HIGH;
+	*offset -= XSC_EEPROM_PAGE_LENGTH;
+}
+
+static int
+xsc_dev_qsfp_eeprom_page(uint16_t offset)
+{
+	if (offset < XSC_EEPROM_PAGE_LENGTH)
+		/* Addresses between 0-255 - page 00 */
+		return 0;
+
+	/*
+	 * Addresses between 256 - 639 belongs to pages 01, 02 and 03
+	 * For example, offset = 400 belongs to page 02:
+	 * 1 + ((400 - 256)/128) = 2
+	 */
+	return 1 + ((offset - XSC_EEPROM_PAGE_LENGTH) / XSC_EEPROM_HIGH_PAGE_LENGTH);
+}
+
+static int
+xsc_dev_qsfp_eeprom_high_page_offset(int page_num)
+{
+	/* Page 0 always start from low page */
+	if (!page_num)
+		return 0;
+
+	/* High page */
+	return page_num * XSC_EEPROM_HIGH_PAGE_LENGTH;
+}
+
+static void
+xsc_dev_qsfp_eeprom_params_set(uint16_t *i2c_addr, uint32_t *page_num, uint16_t *offset)
+{
+	*i2c_addr = XSC_I2C_ADDR_LOW;
+	*page_num = xsc_dev_qsfp_eeprom_page(*offset);
+	*offset -=  xsc_dev_qsfp_eeprom_high_page_offset(*page_num);
+}
+
+static int
+xsc_dev_query_module_id(struct xsc_dev *xdev, uint32_t module_num, uint8_t *module_id)
+{
+	struct xsc_dev_reg_mcia in = { 0 };
+	struct xsc_dev_reg_mcia out = { 0 };
+	int ret;
+	uint8_t *ptr;
+
+	in.i2c_device_address = XSC_I2C_ADDR_LOW;
+	in.module = module_num & 0x000000FF;
+	in.device_address = 0;
+	in.page_number = 0;
+	in.size = 1;
+
+	ret = xsc_dev_access_reg(xdev, &in, sizeof(in), &out, sizeof(out), XSC_REG_MCIA);
+	if (ret != 0)
+		return ret;
+
+	ptr = out.dword_0;
+	*module_id = ptr[0];
+	return 0;
+}
+
+int
+xsc_dev_query_module_eeprom(struct xsc_dev *xdev, uint16_t offset,
+			    uint16_t size, uint8_t *data)
+{
+	struct xsc_module_eeprom_query_params query = { 0 };
+	uint8_t module_id;
+	int ret;
+
+	query.module_number = xdev->hwinfo.mac_phy_port;
+	ret = xsc_dev_query_module_id(xdev, query.module_number, &module_id);
+	if (ret != 0)
+		return ret;
+
+	switch (module_id) {
+	case XSC_MODULE_ID_SFP:
+		xsc_dev_sfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
+		break;
+	case XSC_MODULE_ID_QSFP:
+	case XSC_MODULE_ID_QSFP_PLUS:
+	case XSC_MODULE_ID_QSFP28:
+	case XSC_MODULE_ID_QSFP_DD:
+	case XSC_MODULE_ID_DSFP:
+	case XSC_MODULE_ID_QSFP_PLUS_CMIS:
+		xsc_dev_qsfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Module ID not recognized: 0x%x", module_id);
+		return -EINVAL;
+	}
+
+	if (offset + size > XSC_EEPROM_PAGE_LENGTH)
+		/* Cross pages read, read until offset 256 in low page */
+		size = XSC_EEPROM_PAGE_LENGTH - offset;
+
+	query.size = size;
+	query.offset = offset;
+
+	return xsc_dev_query_mcia(xdev, &query, data);
+}
diff --git a/drivers/net/xsc/xsc_dev.h b/drivers/net/xsc/xsc_dev.h
index 274d6c6a2e..5cf19aaf3d 100644
--- a/drivers/net/xsc/xsc_dev.h
+++ b/drivers/net/xsc/xsc_dev.h
@@ -28,6 +28,12 @@
 #define XSC_DEV_REPR_ID_INVALID	0x7FFFFFFF
 
 #define XSC_FW_VERS_LEN			64
+#define XSC_DWORD_LEN			0x20
+#define XSC_I2C_ADDR_LOW		0x50
+#define XSC_I2C_ADDR_HIGH		0x51
+#define XSC_EEPROM_PAGE_LENGTH		256
+#define XSC_EEPROM_HIGH_PAGE_LENGTH	128
+#define XSC_EEPROM_MAX_BYTES		32
 
 enum xsc_queue_type {
 	XSC_QUEUE_TYPE_RDMA_RC		= 0,
@@ -41,6 +47,31 @@ enum xsc_queue_type {
 	XSC_QUEUE_TYPE_INVALID		= 0xFF,
 };
 
+enum xsc_reg_type {
+	XSC_REG_PMLP			= 0x0,
+	XSC_REG_PCAP			= 0x5001,
+	XSC_REG_PMTU			= 0x5003,
+	XSC_REG_PTYS			= 0x5004,
+	XSC_REG_PAOS			= 0x5006,
+	XSC_REG_PMAOS			= 0x5012,
+	XSC_REG_PUDE			= 0x5009,
+	XSC_REG_PMPE			= 0x5010,
+	XSC_REG_PELC			= 0x500e,
+	XSC_REG_NODE_DESC		= 0x6001,
+	XSC_REG_HOST_ENDIANNESS		= 0x7004,
+	XSC_REG_MCIA			= 0x9014,
+};
+
+enum xsc_module_id {
+	XSC_MODULE_ID_SFP		= 0x3,
+	XSC_MODULE_ID_QSFP		= 0xC,
+	XSC_MODULE_ID_QSFP_PLUS		= 0xD,
+	XSC_MODULE_ID_QSFP28		= 0x11,
+	XSC_MODULE_ID_QSFP_DD		= 0x18,
+	XSC_MODULE_ID_DSFP		= 0x1B,
+	XSC_MODULE_ID_QSFP_PLUS_CMIS	= 0x1E,
+};
+
 struct xsc_hwinfo {
 	uint32_t pcie_no; /* pcie number , 0 or 1 */
 	uint32_t func_id; /* pf glb func id */
@@ -132,6 +163,36 @@ struct xsc_dev {
 	int ctrl_fd;
 };
 
+struct xsc_module_eeprom_query_params {
+	uint16_t size;
+	uint16_t offset;
+	uint16_t i2c_address;
+	uint32_t page;
+	uint32_t bank;
+	uint32_t module_number;
+};
+
+struct xsc_dev_reg_mcia {
+	uint8_t module;
+	uint8_t status;
+	uint8_t i2c_device_address;
+	uint8_t page_number;
+	uint8_t device_address;
+	uint8_t size;
+	uint8_t dword_0[XSC_DWORD_LEN];
+	uint8_t dword_1[XSC_DWORD_LEN];
+	uint8_t dword_2[XSC_DWORD_LEN];
+	uint8_t dword_3[XSC_DWORD_LEN];
+	uint8_t dword_4[XSC_DWORD_LEN];
+	uint8_t dword_5[XSC_DWORD_LEN];
+	uint8_t dword_6[XSC_DWORD_LEN];
+	uint8_t dword_7[XSC_DWORD_LEN];
+	uint8_t dword_8[XSC_DWORD_LEN];
+	uint8_t dword_9[XSC_DWORD_LEN];
+	uint8_t dword_10[XSC_DWORD_LEN];
+	uint8_t dword_11[XSC_DWORD_LEN];
+};
+
 struct xsc_dev_ops {
 	TAILQ_ENTRY(xsc_dev_ops) entry;
 	enum rte_pci_kernel_driver kdrv;
@@ -184,5 +245,7 @@ int xsc_dev_qp_set_id_get(struct xsc_dev *xdev, int repr_id);
 int xsc_dev_set_mtu(struct xsc_dev *xdev, uint16_t mtu);
 int xsc_dev_get_mac(struct xsc_dev *xdev, uint8_t *mac);
 int xsc_dev_fw_version_get(struct xsc_dev *xdev, char *fw_version, size_t fw_size);
+int xsc_dev_query_module_eeprom(struct xsc_dev *xdev, uint16_t offset,
+				uint16_t size, uint8_t *data);
 
 #endif /* _XSC_DEV_H_ */
diff --git a/drivers/net/xsc/xsc_ethdev.c b/drivers/net/xsc/xsc_ethdev.c
index 9a70be0543..ffcf04a90c 100644
--- a/drivers/net/xsc/xsc_ethdev.c
+++ b/drivers/net/xsc/xsc_ethdev.c
@@ -2,6 +2,7 @@
  * Copyright 2025 Yunsilicon Technology Co., Ltd.
  */
 
+#include <rte_dev_info.h>
 #include <ethdev_pci.h>
 
 #include "xsc_log.h"
@@ -681,6 +682,110 @@ xsc_ethdev_fw_version_get(struct rte_eth_dev *dev, char *fw_version, size_t fw_s
 	return xsc_dev_fw_version_get(priv->xdev, fw_version, fw_size);
 }
 
+static int
+xsc_ethdev_get_module_info(struct rte_eth_dev *dev,
+			   struct rte_eth_dev_module_info *modinfo)
+{
+	int size_read = 0;
+	uint8_t data[4] = { 0 };
+	struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
+
+	size_read = xsc_dev_query_module_eeprom(priv->xdev, 0, 3, data);
+	if (size_read < 3)
+		return -1;
+
+	/* data[0] = identifier byte */
+	switch (data[0]) {
+	case XSC_MODULE_ID_QSFP:
+		modinfo->type       = RTE_ETH_MODULE_SFF_8436;
+		modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8436_MAX_LEN;
+		break;
+	case XSC_MODULE_ID_QSFP_PLUS:
+	case XSC_MODULE_ID_QSFP28:
+		/* data[1] = revision id */
+		if (data[0] == XSC_MODULE_ID_QSFP28 || data[1] >= 0x3) {
+			modinfo->type       = RTE_ETH_MODULE_SFF_8636;
+			modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8636_MAX_LEN;
+		} else {
+			modinfo->type       = RTE_ETH_MODULE_SFF_8436;
+			modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8436_MAX_LEN;
+		}
+		break;
+	case XSC_MODULE_ID_SFP:
+		modinfo->type       = RTE_ETH_MODULE_SFF_8472;
+		modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8472_LEN;
+		break;
+	case XSC_MODULE_ID_QSFP_DD:
+	case XSC_MODULE_ID_DSFP:
+	case XSC_MODULE_ID_QSFP_PLUS_CMIS:
+		modinfo->type       = RTE_ETH_MODULE_SFF_8636;
+		/* Verify if module EEPROM is a flat memory. In case of flat
+		 * memory only page 00h (0-255 bytes) can be read. Otherwise
+		 * upper pages 01h and 02h can also be read. Upper pages 10h
+		 * and 11h are currently not supported by the driver.
+		 */
+		if (data[2] & 0x80)
+			modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8636_LEN;
+		else
+			modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8472_LEN;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Cable type 0x%x not recognized",
+			    data[0]);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+xsc_ethdev_get_module_eeprom(struct rte_eth_dev *dev,
+			     struct rte_dev_eeprom_info *info)
+{
+	uint32_t i = 0;
+	uint8_t *data;
+	int size_read;
+	uint32_t offset = info->offset;
+	struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
+
+	if (info->length == 0) {
+		PMD_DRV_LOG(ERR, "Failed to get module eeprom, eeprom length is 0");
+		rte_errno = EINVAL;
+		return -rte_errno;
+	}
+
+	data = malloc(info->length);
+	if (data == NULL) {
+		PMD_DRV_LOG(ERR, "Failed to get module eeprom, cannot allocate memory");
+		rte_errno = ENOMEM;
+		return -rte_errno;
+	}
+	memset(data, 0, info->length);
+
+	while (i < info->length) {
+		size_read = xsc_dev_query_module_eeprom(priv->xdev, offset,
+							info->length - i, data + i);
+		if (!size_read)
+			/* Done reading */
+			goto exit;
+
+		if (size_read < 0) {
+			PMD_DRV_LOG(ERR, "Failed to get module eeprom, size read=%d",
+				    size_read);
+			goto exit;
+		}
+
+		i += size_read;
+		offset += size_read;
+	}
+
+	memcpy(info->data, data, info->length);
+
+exit:
+	free(data);
+	return 0;
+}
+
 const struct eth_dev_ops xsc_eth_dev_ops = {
 	.dev_configure = xsc_ethdev_configure,
 	.dev_start = xsc_ethdev_start,
@@ -700,6 +805,8 @@ const struct eth_dev_ops xsc_eth_dev_ops = {
 	.rss_hash_update = xsc_ethdev_rss_hash_update,
 	.rss_hash_conf_get = xsc_ethdev_rss_hash_conf_get,
 	.fw_version_get = xsc_ethdev_fw_version_get,
+	.get_module_info = xsc_ethdev_get_module_info,
+	.get_module_eeprom = xsc_ethdev_get_module_eeprom,
 };
 
 static int
-- 
2.25.1

  parent reply	other threads:[~2025-08-29  8:24 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-29  8:24 [PATCH 00/14] net/xsc: PMD updates Renyong Wan
2025-08-29  8:24 ` [PATCH 01/14] net/xsc: add FW version get support Renyong Wan
2025-08-29  8:24 ` [PATCH 02/14] net/xsc: add TSO support Renyong Wan
2025-08-29  8:24 ` Renyong Wan [this message]
2025-08-29  8:24 ` [PATCH 04/14] net/xsc: support promiscuous mode Renyong Wan
2025-08-29  8:24 ` [PATCH 05/14] net/xsc: add link status support Renyong Wan
2025-08-29  8:24 ` [PATCH 06/14] net/xsc: add link status event support Renyong Wan
2025-08-29  8:24 ` [PATCH 07/14] net/xsc: add FEC get and set support Renyong Wan
2025-08-29  8:24 ` [PATCH 08/14] net/xsc: optimize RSS queue creation Renyong Wan
2025-08-29  8:24 ` [PATCH 09/14] net/xsc: optimize QP and CQ memory allocation Renyong Wan
2025-08-29  8:24 ` [PATCH 10/14] net/xsc: optimize Rx path Renyong Wan
2025-08-29  8:24 ` [PATCH 11/14] net/xsc: optimize stop and close Renyong Wan
2025-08-29  8:24 ` [PATCH 12/14] net/xsc: support per port for multi-process Renyong Wan
2025-08-29  8:24 ` [PATCH 13/14] net/xsc: fix uninitialized value Renyong Wan
2025-08-29  8:24 ` [PATCH 14/14] net/xsc: update release notes for xsc PMD Renyong Wan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250829082411.24369-4-wanry@yunsilicon.com \
    --to=wanry@yunsilicon.com \
    --cc=dev@dpdk.org \
    --cc=jacky@yunsilicon.com \
    --cc=nana@yunsilicon.com \
    --cc=qianr@yunsilicon.com \
    --cc=stephen@networkplumber.org \
    --cc=thomas@monjalon.net \
    --cc=weihg@yunsilicon.com \
    --cc=xudw@yunsilicon.com \
    --cc=zhangxx@yunsilicon.com \
    --cc=zhenghy@yunsilicon.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).