netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next 0/2] ethtool: Add support for writing firmware
@ 2024-09-06  5:56 Danielle Ratson
  2024-09-06  5:56 ` [PATCH net-next 1/2] net: ethtool: Add new parameters and a function to support EPL Danielle Ratson
  2024-09-06  5:57 ` [PATCH net-next 2/2] net: ethtool: Add support for writing firmware blocks using EPL payload Danielle Ratson
  0 siblings, 2 replies; 7+ messages in thread
From: Danielle Ratson @ 2024-09-06  5:56 UTC (permalink / raw)
  To: netdev
  Cc: davem, edumazet, kuba, pabeni, yuehaibing, linux-kernel, petrm,
	danieller

In the CMIS specification for pluggable modules, LPL (Local Payload) and
EPL (Extended Payload) are two types of data payloads used for managing
various functions and features of the module.

EPL payloads are used for more complex and extensive management functions
that require a larger amount of data, so writing firmware blocks using EPL
is much more efficient.

Currently, only LPL payload is supported for writing firmware blocks to
the module.

Add support for writing firmware block using EPL payload, both to support
modules that support only EPL write mechanism, and to optimize the flashing
process of modules that support LPL and EPL.

Running the flashing command on the same sample module using EPL vs. LPL
showed an improvement of 84%.

Patchset overview:
Patch #1: preparations
Patch #2: Add EPL support

Danielle Ratson (2):
  net: ethtool: Add new parameters and a function to support EPL
  net: ethtool: Add support for writing firmware blocks using EPL
    payload

 net/ethtool/cmis.h           |  16 ++++--
 net/ethtool/cmis_cdb.c       |  94 +++++++++++++++++++++++++-----
 net/ethtool/cmis_fw_update.c | 108 +++++++++++++++++++++++++++++------
 3 files changed, 184 insertions(+), 34 deletions(-)

-- 
2.45.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH net-next 1/2] net: ethtool: Add new parameters and a function to support EPL
  2024-09-06  5:56 [PATCH net-next 0/2] ethtool: Add support for writing firmware Danielle Ratson
@ 2024-09-06  5:56 ` Danielle Ratson
  2024-09-06 15:36   ` Andrew Lunn
  2024-09-06  5:57 ` [PATCH net-next 2/2] net: ethtool: Add support for writing firmware blocks using EPL payload Danielle Ratson
  1 sibling, 1 reply; 7+ messages in thread
From: Danielle Ratson @ 2024-09-06  5:56 UTC (permalink / raw)
  To: netdev
  Cc: davem, edumazet, kuba, pabeni, yuehaibing, linux-kernel, petrm,
	danieller

In the CMIS specification for pluggable modules, LPL (Low-Priority Payload)
and EPL (Extended Payload Length) are two types of data payloads used for
managing various functions and features of the module.

EPL payloads are used for more complex and extensive management
functions that require a larger amount of data, so writing firmware
blocks using EPL is much more efficient.

Currently, only LPL payload is supported for writing firmware blocks to
the module.

Add EPL related parameters to the function ethtool_cmis_cdb_compose_args()
and add a specific function for calculating the maximum allowable length
extension for EPL. Both will be used in the next patch to add support for
writing firmware blocks using EPL.

Signed-off-by: Danielle Ratson <danieller@nvidia.com>
Reviewed-by: Petr Machata <petrm@nvidia.com>
---
 net/ethtool/cmis.h           | 12 +++++++-----
 net/ethtool/cmis_cdb.c       | 32 +++++++++++++++++++++-----------
 net/ethtool/cmis_fw_update.c | 17 ++++++++++-------
 3 files changed, 38 insertions(+), 23 deletions(-)

diff --git a/net/ethtool/cmis.h b/net/ethtool/cmis.h
index 3e7c293af78c..73a5060d0f4c 100644
--- a/net/ethtool/cmis.h
+++ b/net/ethtool/cmis.h
@@ -96,13 +96,15 @@ struct ethtool_cmis_cdb_rpl {
 	u8 payload[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH];
 };
 
-u32 ethtool_cmis_get_max_payload_size(u8 num_of_byte_octs);
+u32 ethtool_cmis_get_max_lpl_size(u8 num_of_byte_octs);
+u32 ethtool_cmis_get_max_epl_size(u8 num_of_byte_octs);
 
 void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args *args,
-				   enum ethtool_cmis_cdb_cmd_id cmd, u8 *pl,
-				   u8 lpl_len, u16 max_duration,
-				   u8 read_write_len_ext, u16 msleep_pre_rpl,
-				   u8 rpl_exp_len, u8 flags);
+				   enum ethtool_cmis_cdb_cmd_id cmd, u8 *lpl,
+				   u8 lpl_len, u8 *epl, u16 epl_len,
+				   u16 max_duration, u8 read_write_len_ext,
+				   u16 msleep_pre_rpl, u8 rpl_exp_len,
+				   u8 flags);
 
 void ethtool_cmis_cdb_check_completion_flag(u8 cmis_rev, u8 *flags);
 
diff --git a/net/ethtool/cmis_cdb.c b/net/ethtool/cmis_cdb.c
index 1bb08783b60d..f599b20479f6 100644
--- a/net/ethtool/cmis_cdb.c
+++ b/net/ethtool/cmis_cdb.c
@@ -11,25 +11,34 @@
  * min(i, 15) byte octets where i specifies the allowable additional number of
  * byte octets in a READ or a WRITE.
  */
-u32 ethtool_cmis_get_max_payload_size(u8 num_of_byte_octs)
+u32 ethtool_cmis_get_max_lpl_size(u8 num_of_byte_octs)
 {
 	return 8 * (1 + min_t(u8, num_of_byte_octs, 15));
 }
 
+/* For accessing the EPL field on page 9Fh, the allowable length extension is
+ * min(i, 255) byte octets where i specifies the allowable additional number of
+ * byte octets in a READ or a WRITE.
+ */
+u32 ethtool_cmis_get_max_epl_size(u8 num_of_byte_octs)
+{
+	return 8 * (1 + min_t(u8, num_of_byte_octs, 255));
+}
+
 void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args *args,
-				   enum ethtool_cmis_cdb_cmd_id cmd, u8 *pl,
-				   u8 lpl_len, u16 max_duration,
-				   u8 read_write_len_ext, u16 msleep_pre_rpl,
-				   u8 rpl_exp_len, u8 flags)
+				   enum ethtool_cmis_cdb_cmd_id cmd, u8 *lpl,
+				   u8 lpl_len, u8 *epl, u16 epl_len,
+				   u16 max_duration, u8 read_write_len_ext,
+				   u16 msleep_pre_rpl, u8 rpl_exp_len, u8 flags)
 {
 	args->req.id = cpu_to_be16(cmd);
 	args->req.lpl_len = lpl_len;
-	if (pl)
-		memcpy(args->req.payload, pl, args->req.lpl_len);
+	if (lpl)
+		memcpy(args->req.payload, lpl, args->req.lpl_len);
 
 	args->max_duration = max_duration;
 	args->read_write_len_ext =
-		ethtool_cmis_get_max_payload_size(read_write_len_ext);
+		ethtool_cmis_get_max_lpl_size(read_write_len_ext);
 	args->msleep_pre_rpl = msleep_pre_rpl;
 	args->rpl_exp_len = rpl_exp_len;
 	args->flags = flags;
@@ -178,7 +187,7 @@ cmis_cdb_validate_password(struct ethtool_cmis_cdb *cdb,
 	}
 
 	ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_QUERY_STATUS,
-				      (u8 *)&qs_pl, sizeof(qs_pl), 0,
+				      (u8 *)&qs_pl, sizeof(qs_pl), NULL, 0, 0,
 				      cdb->read_write_len_ext, 1000,
 				      sizeof(*rpl),
 				      CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
@@ -240,8 +249,9 @@ static int cmis_cdb_module_features_get(struct ethtool_cmis_cdb *cdb,
 	ethtool_cmis_cdb_check_completion_flag(cdb->cmis_rev, &flags);
 	ethtool_cmis_cdb_compose_args(&args,
 				      ETHTOOL_CMIS_CDB_CMD_MODULE_FEATURES,
-				      NULL, 0, 0, cdb->read_write_len_ext,
-				      1000, sizeof(*rpl), flags);
+				      NULL, 0, NULL, 0, 0,
+				      cdb->read_write_len_ext, 1000,
+				      sizeof(*rpl), flags);
 
 	err = ethtool_cmis_cdb_execute_cmd(dev, &args);
 	if (err < 0) {
diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c
index 655ff5224ffa..a514127985d4 100644
--- a/net/ethtool/cmis_fw_update.c
+++ b/net/ethtool/cmis_fw_update.c
@@ -54,7 +54,8 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
 	ethtool_cmis_cdb_check_completion_flag(cdb->cmis_rev, &flags);
 	ethtool_cmis_cdb_compose_args(&args,
 				      ETHTOOL_CMIS_CDB_CMD_FW_MANAGMENT_FEATURES,
-				      NULL, 0, cdb->max_completion_time,
+				      NULL, 0, NULL, 0,
+				      cdb->max_completion_time,
 				      cdb->read_write_len_ext, 1000,
 				      sizeof(*rpl), flags);
 
@@ -122,7 +123,7 @@ cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb,
 
 	ethtool_cmis_cdb_compose_args(&args,
 				      ETHTOOL_CMIS_CDB_CMD_START_FW_DOWNLOAD,
-				      (u8 *)&pl, lpl_len,
+				      (u8 *)&pl, lpl_len, NULL, 0,
 				      fw_mng->max_duration_start,
 				      cdb->read_write_len_ext, 1000, 0,
 				      CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
@@ -158,7 +159,7 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb,
 	int err;
 
 	max_lpl_len = min_t(u32,
-			    ethtool_cmis_get_max_payload_size(cdb->read_write_len_ext),
+			    ethtool_cmis_get_max_lpl_size(cdb->read_write_len_ext),
 			    ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH);
 	max_block_size =
 		max_lpl_len - sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl,
@@ -183,7 +184,7 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb,
 
 		ethtool_cmis_cdb_compose_args(&args,
 					      ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_LPL,
-					      (u8 *)&pl, lpl_len,
+					      (u8 *)&pl, lpl_len, NULL, 0,
 					      fw_mng->max_duration_write,
 					      cdb->read_write_len_ext, 1, 0,
 					      CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
@@ -212,7 +213,8 @@ cmis_fw_update_complete_download(struct ethtool_cmis_cdb *cdb,
 
 	ethtool_cmis_cdb_compose_args(&args,
 				      ETHTOOL_CMIS_CDB_CMD_COMPLETE_FW_DOWNLOAD,
-				      NULL, 0, fw_mng->max_duration_complete,
+				      NULL, 0, NULL, 0,
+				      fw_mng->max_duration_complete,
 				      cdb->read_write_len_ext, 1000, 0,
 				      CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
 
@@ -294,7 +296,7 @@ cmis_fw_update_run_image(struct ethtool_cmis_cdb *cdb, struct net_device *dev,
 	int err;
 
 	ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_RUN_FW_IMAGE,
-				      (u8 *)&pl, sizeof(pl),
+				      (u8 *)&pl, sizeof(pl), NULL, 0,
 				      cdb->max_completion_time,
 				      cdb->read_write_len_ext, 1000, 0,
 				      CDB_F_MODULE_STATE_VALID);
@@ -326,7 +328,8 @@ cmis_fw_update_commit_image(struct ethtool_cmis_cdb *cdb,
 
 	ethtool_cmis_cdb_compose_args(&args,
 				      ETHTOOL_CMIS_CDB_CMD_COMMIT_FW_IMAGE,
-				      NULL, 0, cdb->max_completion_time,
+				      NULL, 0, NULL, 0,
+				      cdb->max_completion_time,
 				      cdb->read_write_len_ext, 1000, 0,
 				      CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
 
-- 
2.45.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 2/2] net: ethtool: Add support for writing firmware blocks using EPL payload
  2024-09-06  5:56 [PATCH net-next 0/2] ethtool: Add support for writing firmware Danielle Ratson
  2024-09-06  5:56 ` [PATCH net-next 1/2] net: ethtool: Add new parameters and a function to support EPL Danielle Ratson
@ 2024-09-06  5:57 ` Danielle Ratson
  2024-09-07 14:10   ` Simon Horman
  1 sibling, 1 reply; 7+ messages in thread
From: Danielle Ratson @ 2024-09-06  5:57 UTC (permalink / raw)
  To: netdev
  Cc: davem, edumazet, kuba, pabeni, yuehaibing, linux-kernel, petrm,
	danieller

In the CMIS specification for pluggable modules, LPL (Low-Priority Payload)
and EPL (Extended Payload Length) are two types of data payloads used for
managing various functions and features of the module.

EPL payloads are used for more complex and extensive management
functions that require a larger amount of data, so writing firmware
blocks using EPL is much more efficient.

Currently, only LPL payload is supported for writing firmware blocks to
the module.

Add support for writing firmware block using EPL payload, both to
support modules that supports only EPL write mechanism, and to optimize
the flashing process of modules that support LPL and EPL.

Signed-off-by: Danielle Ratson <danieller@nvidia.com>
Reviewed-by: Petr Machata <petrm@nvidia.com>
---
 net/ethtool/cmis.h           |  4 ++
 net/ethtool/cmis_cdb.c       | 66 ++++++++++++++++++++++++--
 net/ethtool/cmis_fw_update.c | 91 ++++++++++++++++++++++++++++++++----
 3 files changed, 148 insertions(+), 13 deletions(-)

diff --git a/net/ethtool/cmis.h b/net/ethtool/cmis.h
index 73a5060d0f4c..1e790413db0e 100644
--- a/net/ethtool/cmis.h
+++ b/net/ethtool/cmis.h
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 
 #define ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH		120
+#define ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH		2048
 #define ETHTOOL_CMIS_CDB_CMD_PAGE			0x9F
 #define ETHTOOL_CMIS_CDB_PAGE_I2C_ADDR			0x50
 
@@ -23,6 +24,7 @@ enum ethtool_cmis_cdb_cmd_id {
 	ETHTOOL_CMIS_CDB_CMD_FW_MANAGMENT_FEATURES	= 0x0041,
 	ETHTOOL_CMIS_CDB_CMD_START_FW_DOWNLOAD		= 0x0101,
 	ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_LPL		= 0x0103,
+	ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_EPL		= 0x0104,
 	ETHTOOL_CMIS_CDB_CMD_COMPLETE_FW_DOWNLOAD	= 0x0107,
 	ETHTOOL_CMIS_CDB_CMD_RUN_FW_IMAGE		= 0x0109,
 	ETHTOOL_CMIS_CDB_CMD_COMMIT_FW_IMAGE		= 0x010A,
@@ -38,6 +40,7 @@ enum ethtool_cmis_cdb_cmd_id {
  * @resv1: Added to match the CMIS standard request continuity.
  * @resv2: Added to match the CMIS standard request continuity.
  * @payload: Payload for the CDB commands.
+ * @epl: Extended payload for the CDB commands.
  */
 struct ethtool_cmis_cdb_request {
 	__be16 id;
@@ -49,6 +52,7 @@ struct ethtool_cmis_cdb_request {
 		u8 resv2;
 		u8 payload[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH];
 	);
+	u8 *epl;	/* Everything above this field checksummed. */
 };
 
 #define CDB_F_COMPLETION_VALID		BIT(0)
diff --git a/net/ethtool/cmis_cdb.c b/net/ethtool/cmis_cdb.c
index f599b20479f6..86d93f6c68c2 100644
--- a/net/ethtool/cmis_cdb.c
+++ b/net/ethtool/cmis_cdb.c
@@ -33,12 +33,19 @@ void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args *args,
 {
 	args->req.id = cpu_to_be16(cmd);
 	args->req.lpl_len = lpl_len;
-	if (lpl)
+	if (lpl) {
 		memcpy(args->req.payload, lpl, args->req.lpl_len);
+		args->read_write_len_ext =
+			ethtool_cmis_get_max_lpl_size(read_write_len_ext);
+	}
+	if (epl) {
+		args->req.epl_len = cpu_to_be16(epl_len);
+		args->req.epl = epl;
+		args->read_write_len_ext =
+			ethtool_cmis_get_max_epl_size(read_write_len_ext);
+	}
 
 	args->max_duration = max_duration;
-	args->read_write_len_ext =
-		ethtool_cmis_get_max_lpl_size(read_write_len_ext);
 	args->msleep_pre_rpl = msleep_pre_rpl;
 	args->rpl_exp_len = rpl_exp_len;
 	args->flags = flags;
@@ -548,6 +555,49 @@ __ethtool_cmis_cdb_execute_cmd(struct net_device *dev,
 	return err;
 }
 
+#define CMIS_CDB_EPL_PAGE_START			0xA0
+#define CMIS_CDB_EPL_PAGE_END			0xAF
+#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_START	128
+#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_END	255
+
+static int
+ethtool_cmis_cdb_execute_epl_cmd(struct net_device *dev,
+				 struct ethtool_cmis_cdb_cmd_args *args,
+				 struct ethtool_module_eeprom *page_data)
+{
+	u16 epl_len = be16_to_cpu(args->req.epl_len);
+	u32 bytes_written;
+	u8 page;
+	int err;
+
+	for (page = CMIS_CDB_EPL_PAGE_START;
+	     page <= CMIS_CDB_EPL_PAGE_END && bytes_written < epl_len; page++) {
+		u16 offset = CMIS_CDB_EPL_FW_BLOCK_OFFSET_START;
+
+		while (offset <= CMIS_CDB_EPL_FW_BLOCK_OFFSET_END &&
+		       bytes_written < epl_len) {
+			u32 bytes_left = epl_len - bytes_written;
+			u16 space_left, bytes_to_write;
+
+			space_left = CMIS_CDB_EPL_FW_BLOCK_OFFSET_END - offset + 1;
+			bytes_to_write = min_t(u16, bytes_left,
+					       min_t(u16, space_left,
+						     args->read_write_len_ext));
+
+			err = __ethtool_cmis_cdb_execute_cmd(dev, page_data,
+							     page, offset,
+							     bytes_to_write,
+							     args->req.epl + bytes_written);
+			if (err < 0)
+				return err;
+
+			offset += bytes_to_write;
+			bytes_written += bytes_to_write;
+		}
+	}
+	return 0;
+}
+
 static u8 cmis_cdb_calc_checksum(const void *data, size_t size)
 {
 	const u8 *bytes = (const u8 *)data;
@@ -569,7 +619,9 @@ int ethtool_cmis_cdb_execute_cmd(struct net_device *dev,
 	int err;
 
 	args->req.chk_code =
-		cmis_cdb_calc_checksum(&args->req, sizeof(args->req));
+		cmis_cdb_calc_checksum(&args->req,
+				       offsetof(struct ethtool_cmis_cdb_request,
+						epl));
 
 	if (args->req.lpl_len > args->read_write_len_ext) {
 		args->err_msg = "LPL length is longer than CDB read write length extension allows";
@@ -591,6 +643,12 @@ int ethtool_cmis_cdb_execute_cmd(struct net_device *dev,
 	if (err < 0)
 		return err;
 
+	if (args->req.epl_len) {
+		err = ethtool_cmis_cdb_execute_epl_cmd(dev, args, &page_data);
+		if (err < 0)
+			return err;
+	}
+
 	offset = CMIS_CDB_CMD_ID_OFFSET +
 		offsetof(struct ethtool_cmis_cdb_request, id);
 	err = __ethtool_cmis_cdb_execute_cmd(dev, &page_data,
diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c
index a514127985d4..48aef6220f00 100644
--- a/net/ethtool/cmis_fw_update.c
+++ b/net/ethtool/cmis_fw_update.c
@@ -9,6 +9,7 @@
 
 struct cmis_fw_update_fw_mng_features {
 	u8	start_cmd_payload_size;
+	u8	write_mechanism;
 	u16	max_duration_start;
 	u16	max_duration_write;
 	u16	max_duration_complete;
@@ -36,7 +37,9 @@ struct cmis_cdb_fw_mng_features_rpl {
 };
 
 enum cmis_cdb_fw_write_mechanism {
+	CMIS_CDB_FW_WRITE_MECHANISM_NONE	= 0x00,
 	CMIS_CDB_FW_WRITE_MECHANISM_LPL		= 0x01,
+	CMIS_CDB_FW_WRITE_MECHANISM_EPL		= 0x10,
 	CMIS_CDB_FW_WRITE_MECHANISM_BOTH	= 0x11,
 };
 
@@ -68,10 +71,9 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
 	}
 
 	rpl = (struct cmis_cdb_fw_mng_features_rpl *)args.req.payload;
-	if (!(rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ||
-	      rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_BOTH)) {
+	if (rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_NONE) {
 		ethnl_module_fw_flash_ntf_err(dev, ntf_params,
-					      "Write LPL is not supported",
+					      "CDB write mechanism is not supported",
 					      NULL);
 		return  -EOPNOTSUPP;
 	}
@@ -83,6 +85,10 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
 	 */
 	cdb->read_write_len_ext = rpl->read_write_len_ext;
 	fw_mng->start_cmd_payload_size = rpl->start_cmd_payload_size;
+	fw_mng->write_mechanism =
+		rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ?
+		CMIS_CDB_FW_WRITE_MECHANISM_LPL :
+		CMIS_CDB_FW_WRITE_MECHANISM_EPL;
 	fw_mng->max_duration_start = be16_to_cpu(rpl->max_duration_start);
 	fw_mng->max_duration_write = be16_to_cpu(rpl->max_duration_write);
 	fw_mng->max_duration_complete = be16_to_cpu(rpl->max_duration_complete);
@@ -149,9 +155,9 @@ struct cmis_cdb_write_fw_block_lpl_pl {
 };
 
 static int
-cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb,
-			   struct ethtool_cmis_fw_update_params *fw_update,
-			   struct cmis_fw_update_fw_mng_features *fw_mng)
+cmis_fw_update_write_image_lpl(struct ethtool_cmis_cdb *cdb,
+			       struct ethtool_cmis_fw_update_params *fw_update,
+			       struct cmis_fw_update_fw_mng_features *fw_mng)
 {
 	u8 start = fw_mng->start_cmd_payload_size;
 	u32 offset, max_block_size, max_lpl_len;
@@ -202,6 +208,67 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb,
 	return 0;
 }
 
+struct cmis_cdb_write_fw_block_epl_pl {
+	u8 fw_block[ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH];
+};
+
+static int
+cmis_fw_update_write_image_epl(struct ethtool_cmis_cdb *cdb,
+			       struct ethtool_cmis_fw_update_params *fw_update,
+			       struct cmis_fw_update_fw_mng_features *fw_mng)
+{
+	u8 start = fw_mng->start_cmd_payload_size;
+	u32 image_size = fw_update->fw->size;
+	u32 offset, lpl_len;
+	int err;
+
+	lpl_len = sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl,
+			       block_address);
+
+	for (offset = start; offset < image_size;
+	     offset += ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH) {
+		struct cmis_cdb_write_fw_block_lpl_pl lpl = {
+			.block_address = cpu_to_be32(offset - start),
+		};
+		struct cmis_cdb_write_fw_block_epl_pl *epl;
+		struct ethtool_cmis_cdb_cmd_args args = {};
+		u32 epl_len;
+
+		ethnl_module_fw_flash_ntf_in_progress(fw_update->dev,
+						      &fw_update->ntf_params,
+						      offset - start,
+						      image_size);
+
+		epl_len = min_t(u32, ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH,
+				image_size - offset);
+		epl = kmalloc_array(epl_len, sizeof(u8), GFP_KERNEL);
+		if (!epl)
+			return -ENOMEM;
+
+		memcpy(epl->fw_block, &fw_update->fw->data[offset], epl_len);
+
+		ethtool_cmis_cdb_compose_args(&args,
+					      ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_EPL,
+					      (u8 *)&lpl, lpl_len, (u8 *)epl,
+					      epl_len,
+					      fw_mng->max_duration_write,
+					      cdb->read_write_len_ext, 1, 0,
+					      CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
+
+		err = ethtool_cmis_cdb_execute_cmd(fw_update->dev, &args);
+		kfree(epl);
+		if (err < 0) {
+			ethnl_module_fw_flash_ntf_err(fw_update->dev,
+						      &fw_update->ntf_params,
+						      "Write FW block EPL command failed",
+						      args.err_msg);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
 static int
 cmis_fw_update_complete_download(struct ethtool_cmis_cdb *cdb,
 				 struct net_device *dev,
@@ -238,9 +305,15 @@ cmis_fw_update_download_image(struct ethtool_cmis_cdb *cdb,
 	if (err < 0)
 		return err;
 
-	err = cmis_fw_update_write_image(cdb, fw_update, fw_mng);
-	if (err < 0)
-		return err;
+	if (fw_mng->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL) {
+		err = cmis_fw_update_write_image_lpl(cdb, fw_update, fw_mng);
+		if (err < 0)
+			return err;
+	} else {
+		err = cmis_fw_update_write_image_epl(cdb, fw_update, fw_mng);
+		if (err < 0)
+			return err;
+	}
 
 	err = cmis_fw_update_complete_download(cdb, fw_update->dev, fw_mng,
 					       &fw_update->ntf_params);
-- 
2.45.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH net-next 1/2] net: ethtool: Add new parameters and a function to support EPL
  2024-09-06  5:56 ` [PATCH net-next 1/2] net: ethtool: Add new parameters and a function to support EPL Danielle Ratson
@ 2024-09-06 15:36   ` Andrew Lunn
  2024-09-08 12:33     ` Danielle Ratson
  0 siblings, 1 reply; 7+ messages in thread
From: Andrew Lunn @ 2024-09-06 15:36 UTC (permalink / raw)
  To: Danielle Ratson
  Cc: netdev, davem, edumazet, kuba, pabeni, yuehaibing, linux-kernel,
	petrm

> +/* For accessing the EPL field on page 9Fh, the allowable length extension is
> + * min(i, 255) byte octets where i specifies the allowable additional number of
> + * byte octets in a READ or a WRITE.
> + */
> +u32 ethtool_cmis_get_max_epl_size(u8 num_of_byte_octs)
> +{
> +	return 8 * (1 + min_t(u8, num_of_byte_octs, 255));
> +}

Does this get mapped to a 255 byte I2C bus transfer?

https://elixir.bootlin.com/linux/v6.11-rc6/source/drivers/net/phy/sfp.c#L218

/* SFP_EEPROM_BLOCK_SIZE is the size of data chunk to read the EEPROM
 * at a time. Some SFP modules and also some Linux I2C drivers do not like
 * reads longer than 16 bytes.
 */
#define SFP_EEPROM_BLOCK_SIZE	16

If an SMBUS is being used, rather than I2C, there is a hard limit of
32 bytes in a message transfer.

I've not looked in details at these patches, but maybe you need a
mechanism to ask the hardware or I2C driver what it can actually do?
Is it possible to say LPL is the only choice?

	Andrew

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH net-next 2/2] net: ethtool: Add support for writing firmware blocks using EPL payload
  2024-09-06  5:57 ` [PATCH net-next 2/2] net: ethtool: Add support for writing firmware blocks using EPL payload Danielle Ratson
@ 2024-09-07 14:10   ` Simon Horman
  2024-09-10  8:53     ` Danielle Ratson
  0 siblings, 1 reply; 7+ messages in thread
From: Simon Horman @ 2024-09-07 14:10 UTC (permalink / raw)
  To: Danielle Ratson
  Cc: netdev, davem, edumazet, kuba, pabeni, yuehaibing, linux-kernel,
	petrm

On Fri, Sep 06, 2024 at 08:57:00AM +0300, Danielle Ratson wrote:
> In the CMIS specification for pluggable modules, LPL (Low-Priority Payload)
> and EPL (Extended Payload Length) are two types of data payloads used for
> managing various functions and features of the module.
> 
> EPL payloads are used for more complex and extensive management
> functions that require a larger amount of data, so writing firmware
> blocks using EPL is much more efficient.
> 
> Currently, only LPL payload is supported for writing firmware blocks to
> the module.
> 
> Add support for writing firmware block using EPL payload, both to
> support modules that supports only EPL write mechanism, and to optimize
> the flashing process of modules that support LPL and EPL.
> 
> Signed-off-by: Danielle Ratson <danieller@nvidia.com>
> Reviewed-by: Petr Machata <petrm@nvidia.com>

...

> diff --git a/net/ethtool/cmis_cdb.c b/net/ethtool/cmis_cdb.c

...

> @@ -548,6 +555,49 @@ __ethtool_cmis_cdb_execute_cmd(struct net_device *dev,
>  	return err;
>  }
>  
> +#define CMIS_CDB_EPL_PAGE_START			0xA0
> +#define CMIS_CDB_EPL_PAGE_END			0xAF
> +#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_START	128
> +#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_END	255
> +
> +static int
> +ethtool_cmis_cdb_execute_epl_cmd(struct net_device *dev,
> +				 struct ethtool_cmis_cdb_cmd_args *args,
> +				 struct ethtool_module_eeprom *page_data)
> +{
> +	u16 epl_len = be16_to_cpu(args->req.epl_len);
> +	u32 bytes_written;
> +	u8 page;
> +	int err;

Hi Danielle,

A minor issue from my side:
In the first iteration of the loop below bytes_written is used uninitialised.

Flagged by W=1 builds using clang-18 and gcc-14.

> +
> +	for (page = CMIS_CDB_EPL_PAGE_START;
> +	     page <= CMIS_CDB_EPL_PAGE_END && bytes_written < epl_len; page++) {
> +		u16 offset = CMIS_CDB_EPL_FW_BLOCK_OFFSET_START;
> +
> +		while (offset <= CMIS_CDB_EPL_FW_BLOCK_OFFSET_END &&
> +		       bytes_written < epl_len) {
> +			u32 bytes_left = epl_len - bytes_written;
> +			u16 space_left, bytes_to_write;
> +
> +			space_left = CMIS_CDB_EPL_FW_BLOCK_OFFSET_END - offset + 1;
> +			bytes_to_write = min_t(u16, bytes_left,
> +					       min_t(u16, space_left,
> +						     args->read_write_len_ext));
> +
> +			err = __ethtool_cmis_cdb_execute_cmd(dev, page_data,
> +							     page, offset,
> +							     bytes_to_write,
> +							     args->req.epl + bytes_written);
> +			if (err < 0)
> +				return err;
> +
> +			offset += bytes_to_write;
> +			bytes_written += bytes_to_write;
> +		}
> +	}
> +	return 0;
> +}
> +
>  static u8 cmis_cdb_calc_checksum(const void *data, size_t size)
>  {
>  	const u8 *bytes = (const u8 *)data;

-- 
pw-bot: cr

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: [PATCH net-next 1/2] net: ethtool: Add new parameters and a function to support EPL
  2024-09-06 15:36   ` Andrew Lunn
@ 2024-09-08 12:33     ` Danielle Ratson
  0 siblings, 0 replies; 7+ messages in thread
From: Danielle Ratson @ 2024-09-08 12:33 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: netdev@vger.kernel.org, davem@davemloft.net, edumazet@google.com,
	kuba@kernel.org, pabeni@redhat.com, yuehaibing@huawei.com,
	linux-kernel@vger.kernel.org, Petr Machata

> From: Andrew Lunn <andrew@lunn.ch>
> Sent: Friday, 6 September 2024 18:36
> To: Danielle Ratson <danieller@nvidia.com>
> Cc: netdev@vger.kernel.org; davem@davemloft.net; edumazet@google.com;
> kuba@kernel.org; pabeni@redhat.com; yuehaibing@huawei.com; linux-
> kernel@vger.kernel.org; Petr Machata <petrm@nvidia.com>
> Subject: Re: [PATCH net-next 1/2] net: ethtool: Add new parameters and a
> function to support EPL
> 
> > +/* For accessing the EPL field on page 9Fh, the allowable length
> > +extension is
> > + * min(i, 255) byte octets where i specifies the allowable additional
> > +number of
> > + * byte octets in a READ or a WRITE.
> > + */
> > +u32 ethtool_cmis_get_max_epl_size(u8 num_of_byte_octs) {
> > +	return 8 * (1 + min_t(u8, num_of_byte_octs, 255)); }
> 
> Does this get mapped to a 255 byte I2C bus transfer?
> 
> https://elixir.bootlin.com/linux/v6.11-rc6/source/drivers/net/phy/sfp.c#L218
> 
> /* SFP_EEPROM_BLOCK_SIZE is the size of data chunk to read the EEPROM
>  * at a time. Some SFP modules and also some Linux I2C drivers do not like
>  * reads longer than 16 bytes.
>  */
> #define SFP_EEPROM_BLOCK_SIZE	16
> 
> If an SMBUS is being used, rather than I2C, there is a hard limit of
> 32 bytes in a message transfer.
> 
> I've not looked in details at these patches, but maybe you need a mechanism
> to ask the hardware or I2C driver what it can actually do?
> Is it possible to say LPL is the only choice?
> 
> 	Andrew

Hi Andrew,

Thanks for your reply.

As I wrote in the commit message, the EPL is an extended type of data payload in which you can send the firmware image, for example, in blocks.
The LPL contains ap to 128 bytes, and the EPL up to 2048. The exact allowed extension can be derived from the 'readWriteLengthExt' and the two functions (ethtool_cmis_get_max_lpl/epl_size ()) that calculates the specific value of the module from it.

The obligations on the chunks that are related to the bus type limit, should be referred to in the driver itself. 
The driver should be the responsible for bus that cannot read/write larger chunks and then split it to the supported size chunks accordingly. 

Hope it makes more sense now.

Thanks,
Danielle





^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: [PATCH net-next 2/2] net: ethtool: Add support for writing firmware blocks using EPL payload
  2024-09-07 14:10   ` Simon Horman
@ 2024-09-10  8:53     ` Danielle Ratson
  0 siblings, 0 replies; 7+ messages in thread
From: Danielle Ratson @ 2024-09-10  8:53 UTC (permalink / raw)
  To: Simon Horman
  Cc: netdev@vger.kernel.org, davem@davemloft.net, edumazet@google.com,
	kuba@kernel.org, pabeni@redhat.com, yuehaibing@huawei.com,
	linux-kernel@vger.kernel.org, Petr Machata



> -----Original Message-----
> From: Simon Horman <horms@kernel.org>
> Sent: Saturday, 7 September 2024 17:11
> To: Danielle Ratson <danieller@nvidia.com>
> Cc: netdev@vger.kernel.org; davem@davemloft.net; edumazet@google.com;
> kuba@kernel.org; pabeni@redhat.com; yuehaibing@huawei.com; linux-
> kernel@vger.kernel.org; Petr Machata <petrm@nvidia.com>
> Subject: Re: [PATCH net-next 2/2] net: ethtool: Add support for writing
> firmware blocks using EPL payload
> 
> On Fri, Sep 06, 2024 at 08:57:00AM +0300, Danielle Ratson wrote:
> > In the CMIS specification for pluggable modules, LPL (Low-Priority
> > Payload) and EPL (Extended Payload Length) are two types of data
> > payloads used for managing various functions and features of the module.
> >
> > EPL payloads are used for more complex and extensive management
> > functions that require a larger amount of data, so writing firmware
> > blocks using EPL is much more efficient.
> >
> > Currently, only LPL payload is supported for writing firmware blocks
> > to the module.
> >
> > Add support for writing firmware block using EPL payload, both to
> > support modules that supports only EPL write mechanism, and to
> > optimize the flashing process of modules that support LPL and EPL.
> >
> > Signed-off-by: Danielle Ratson <danieller@nvidia.com>
> > Reviewed-by: Petr Machata <petrm@nvidia.com>
> 
> ...
> 
> > diff --git a/net/ethtool/cmis_cdb.c b/net/ethtool/cmis_cdb.c
> 
> ...
> 
> > @@ -548,6 +555,49 @@ __ethtool_cmis_cdb_execute_cmd(struct
> net_device *dev,
> >  	return err;
> >  }
> >
> > +#define CMIS_CDB_EPL_PAGE_START			0xA0
> > +#define CMIS_CDB_EPL_PAGE_END			0xAF
> > +#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_START	128
> > +#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_END	255
> > +
> > +static int
> > +ethtool_cmis_cdb_execute_epl_cmd(struct net_device *dev,
> > +				 struct ethtool_cmis_cdb_cmd_args *args,
> > +				 struct ethtool_module_eeprom *page_data) {
> > +	u16 epl_len = be16_to_cpu(args->req.epl_len);
> > +	u32 bytes_written;
> > +	u8 page;
> > +	int err;
> 
> Hi Danielle,
> 
> A minor issue from my side:
> In the first iteration of the loop below bytes_written is used uninitialised.
> 
> Flagged by W=1 builds using clang-18 and gcc-14.

Hi, 

Will fix thanks!

Danielle

> 
> > +
> > +	for (page = CMIS_CDB_EPL_PAGE_START;
> > +	     page <= CMIS_CDB_EPL_PAGE_END && bytes_written < epl_len;
> page++) {
> > +		u16 offset = CMIS_CDB_EPL_FW_BLOCK_OFFSET_START;
> > +
> > +		while (offset <= CMIS_CDB_EPL_FW_BLOCK_OFFSET_END &&
> > +		       bytes_written < epl_len) {
> > +			u32 bytes_left = epl_len - bytes_written;
> > +			u16 space_left, bytes_to_write;
> > +
> > +			space_left = CMIS_CDB_EPL_FW_BLOCK_OFFSET_END
> - offset + 1;
> > +			bytes_to_write = min_t(u16, bytes_left,
> > +					       min_t(u16, space_left,
> > +						     args->read_write_len_ext));
> > +
> > +			err = __ethtool_cmis_cdb_execute_cmd(dev,
> page_data,
> > +							     page, offset,
> > +							     bytes_to_write,
> > +							     args->req.epl +
> bytes_written);
> > +			if (err < 0)
> > +				return err;
> > +
> > +			offset += bytes_to_write;
> > +			bytes_written += bytes_to_write;
> > +		}
> > +	}
> > +	return 0;
> > +}
> > +
> >  static u8 cmis_cdb_calc_checksum(const void *data, size_t size)  {
> >  	const u8 *bytes = (const u8 *)data;
> 
> --
> pw-bot: cr

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2024-09-10  8:53 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-06  5:56 [PATCH net-next 0/2] ethtool: Add support for writing firmware Danielle Ratson
2024-09-06  5:56 ` [PATCH net-next 1/2] net: ethtool: Add new parameters and a function to support EPL Danielle Ratson
2024-09-06 15:36   ` Andrew Lunn
2024-09-08 12:33     ` Danielle Ratson
2024-09-06  5:57 ` [PATCH net-next 2/2] net: ethtool: Add support for writing firmware blocks using EPL payload Danielle Ratson
2024-09-07 14:10   ` Simon Horman
2024-09-10  8:53     ` Danielle Ratson

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).