Skip to content

Commit

Permalink
Merge branch 'ethtool-write-firmware'
Browse files Browse the repository at this point in the history
Danielle Ratson says:

====================
ethtool: Add support for writing firmware

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

v5: Resending- no changes.

v4: Resending the right version after wrong v3.
    No changes from v2.

v2:
	* Fix the commit meassges to align the cover letter about the
	  right meaning of LPL and EPL.
	Patch #2:
	* Initialize the variable 'bytes_written' before the first
	  iteration.
====================

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Oct 13, 2024
2 parents eae38f0 + 9a3b0d0 commit 6aac566
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 34 deletions.
16 changes: 11 additions & 5 deletions net/ethtool/cmis.h
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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,
Expand All @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -96,13 +100,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);

Expand Down
94 changes: 81 additions & 13 deletions net/ethtool/cmis_cdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,41 @@
* 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->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_payload_size(read_write_len_ext);
args->msleep_pre_rpl = msleep_pre_rpl;
args->rpl_exp_len = rpl_exp_len;
args->flags = flags;
Expand Down Expand Up @@ -183,7 +199,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);
Expand Down Expand Up @@ -245,8 +261,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) {
Expand Down Expand Up @@ -546,6 +563,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 = 0;
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;
Expand All @@ -567,7 +627,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";
Expand All @@ -589,6 +651,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,
Expand Down
Loading

0 comments on commit 6aac566

Please sign in to comment.