Skip to content

Commit 9a3b0d0

Browse files
daniellertsdavem330
authored andcommitted
net: ethtool: Add support for writing firmware blocks using EPL payload
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 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> Reviewed-by: Simon Horman <horms@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent edc3445 commit 9a3b0d0

File tree

3 files changed

+148
-13
lines changed

3 files changed

+148
-13
lines changed

net/ethtool/cmis.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* SPDX-License-Identifier: GPL-2.0-only */
22

33
#define ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH 120
4+
#define ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH 2048
45
#define ETHTOOL_CMIS_CDB_CMD_PAGE 0x9F
56
#define ETHTOOL_CMIS_CDB_PAGE_I2C_ADDR 0x50
67

@@ -23,6 +24,7 @@ enum ethtool_cmis_cdb_cmd_id {
2324
ETHTOOL_CMIS_CDB_CMD_FW_MANAGMENT_FEATURES = 0x0041,
2425
ETHTOOL_CMIS_CDB_CMD_START_FW_DOWNLOAD = 0x0101,
2526
ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_LPL = 0x0103,
27+
ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_EPL = 0x0104,
2628
ETHTOOL_CMIS_CDB_CMD_COMPLETE_FW_DOWNLOAD = 0x0107,
2729
ETHTOOL_CMIS_CDB_CMD_RUN_FW_IMAGE = 0x0109,
2830
ETHTOOL_CMIS_CDB_CMD_COMMIT_FW_IMAGE = 0x010A,
@@ -38,6 +40,7 @@ enum ethtool_cmis_cdb_cmd_id {
3840
* @resv1: Added to match the CMIS standard request continuity.
3941
* @resv2: Added to match the CMIS standard request continuity.
4042
* @payload: Payload for the CDB commands.
43+
* @epl: Extended payload for the CDB commands.
4144
*/
4245
struct ethtool_cmis_cdb_request {
4346
__be16 id;
@@ -49,6 +52,7 @@ struct ethtool_cmis_cdb_request {
4952
u8 resv2;
5053
u8 payload[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH];
5154
);
55+
u8 *epl; /* Everything above this field checksummed. */
5256
};
5357

5458
#define CDB_F_COMPLETION_VALID BIT(0)

net/ethtool/cmis_cdb.c

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,19 @@ void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args *args,
3333
{
3434
args->req.id = cpu_to_be16(cmd);
3535
args->req.lpl_len = lpl_len;
36-
if (lpl)
36+
if (lpl) {
3737
memcpy(args->req.payload, lpl, args->req.lpl_len);
38+
args->read_write_len_ext =
39+
ethtool_cmis_get_max_lpl_size(read_write_len_ext);
40+
}
41+
if (epl) {
42+
args->req.epl_len = cpu_to_be16(epl_len);
43+
args->req.epl = epl;
44+
args->read_write_len_ext =
45+
ethtool_cmis_get_max_epl_size(read_write_len_ext);
46+
}
3847

3948
args->max_duration = max_duration;
40-
args->read_write_len_ext =
41-
ethtool_cmis_get_max_lpl_size(read_write_len_ext);
4249
args->msleep_pre_rpl = msleep_pre_rpl;
4350
args->rpl_exp_len = rpl_exp_len;
4451
args->flags = flags;
@@ -556,6 +563,49 @@ __ethtool_cmis_cdb_execute_cmd(struct net_device *dev,
556563
return err;
557564
}
558565

566+
#define CMIS_CDB_EPL_PAGE_START 0xA0
567+
#define CMIS_CDB_EPL_PAGE_END 0xAF
568+
#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_START 128
569+
#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_END 255
570+
571+
static int
572+
ethtool_cmis_cdb_execute_epl_cmd(struct net_device *dev,
573+
struct ethtool_cmis_cdb_cmd_args *args,
574+
struct ethtool_module_eeprom *page_data)
575+
{
576+
u16 epl_len = be16_to_cpu(args->req.epl_len);
577+
u32 bytes_written = 0;
578+
u8 page;
579+
int err;
580+
581+
for (page = CMIS_CDB_EPL_PAGE_START;
582+
page <= CMIS_CDB_EPL_PAGE_END && bytes_written < epl_len; page++) {
583+
u16 offset = CMIS_CDB_EPL_FW_BLOCK_OFFSET_START;
584+
585+
while (offset <= CMIS_CDB_EPL_FW_BLOCK_OFFSET_END &&
586+
bytes_written < epl_len) {
587+
u32 bytes_left = epl_len - bytes_written;
588+
u16 space_left, bytes_to_write;
589+
590+
space_left = CMIS_CDB_EPL_FW_BLOCK_OFFSET_END - offset + 1;
591+
bytes_to_write = min_t(u16, bytes_left,
592+
min_t(u16, space_left,
593+
args->read_write_len_ext));
594+
595+
err = __ethtool_cmis_cdb_execute_cmd(dev, page_data,
596+
page, offset,
597+
bytes_to_write,
598+
args->req.epl + bytes_written);
599+
if (err < 0)
600+
return err;
601+
602+
offset += bytes_to_write;
603+
bytes_written += bytes_to_write;
604+
}
605+
}
606+
return 0;
607+
}
608+
559609
static u8 cmis_cdb_calc_checksum(const void *data, size_t size)
560610
{
561611
const u8 *bytes = (const u8 *)data;
@@ -577,7 +627,9 @@ int ethtool_cmis_cdb_execute_cmd(struct net_device *dev,
577627
int err;
578628

579629
args->req.chk_code =
580-
cmis_cdb_calc_checksum(&args->req, sizeof(args->req));
630+
cmis_cdb_calc_checksum(&args->req,
631+
offsetof(struct ethtool_cmis_cdb_request,
632+
epl));
581633

582634
if (args->req.lpl_len > args->read_write_len_ext) {
583635
args->err_msg = "LPL length is longer than CDB read write length extension allows";
@@ -599,6 +651,12 @@ int ethtool_cmis_cdb_execute_cmd(struct net_device *dev,
599651
if (err < 0)
600652
return err;
601653

654+
if (args->req.epl_len) {
655+
err = ethtool_cmis_cdb_execute_epl_cmd(dev, args, &page_data);
656+
if (err < 0)
657+
return err;
658+
}
659+
602660
offset = CMIS_CDB_CMD_ID_OFFSET +
603661
offsetof(struct ethtool_cmis_cdb_request, id);
604662
err = __ethtool_cmis_cdb_execute_cmd(dev, &page_data,

net/ethtool/cmis_fw_update.c

Lines changed: 82 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
struct cmis_fw_update_fw_mng_features {
1111
u8 start_cmd_payload_size;
12+
u8 write_mechanism;
1213
u16 max_duration_start;
1314
u16 max_duration_write;
1415
u16 max_duration_complete;
@@ -36,7 +37,9 @@ struct cmis_cdb_fw_mng_features_rpl {
3637
};
3738

3839
enum cmis_cdb_fw_write_mechanism {
40+
CMIS_CDB_FW_WRITE_MECHANISM_NONE = 0x00,
3941
CMIS_CDB_FW_WRITE_MECHANISM_LPL = 0x01,
42+
CMIS_CDB_FW_WRITE_MECHANISM_EPL = 0x10,
4043
CMIS_CDB_FW_WRITE_MECHANISM_BOTH = 0x11,
4144
};
4245

@@ -68,10 +71,9 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
6871
}
6972

7073
rpl = (struct cmis_cdb_fw_mng_features_rpl *)args.req.payload;
71-
if (!(rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ||
72-
rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_BOTH)) {
74+
if (rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_NONE) {
7375
ethnl_module_fw_flash_ntf_err(dev, ntf_params,
74-
"Write LPL is not supported",
76+
"CDB write mechanism is not supported",
7577
NULL);
7678
return -EOPNOTSUPP;
7779
}
@@ -83,6 +85,10 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
8385
*/
8486
cdb->read_write_len_ext = rpl->read_write_len_ext;
8587
fw_mng->start_cmd_payload_size = rpl->start_cmd_payload_size;
88+
fw_mng->write_mechanism =
89+
rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ?
90+
CMIS_CDB_FW_WRITE_MECHANISM_LPL :
91+
CMIS_CDB_FW_WRITE_MECHANISM_EPL;
8692
fw_mng->max_duration_start = be16_to_cpu(rpl->max_duration_start);
8793
fw_mng->max_duration_write = be16_to_cpu(rpl->max_duration_write);
8894
fw_mng->max_duration_complete = be16_to_cpu(rpl->max_duration_complete);
@@ -149,9 +155,9 @@ struct cmis_cdb_write_fw_block_lpl_pl {
149155
};
150156

151157
static int
152-
cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb,
153-
struct ethtool_cmis_fw_update_params *fw_update,
154-
struct cmis_fw_update_fw_mng_features *fw_mng)
158+
cmis_fw_update_write_image_lpl(struct ethtool_cmis_cdb *cdb,
159+
struct ethtool_cmis_fw_update_params *fw_update,
160+
struct cmis_fw_update_fw_mng_features *fw_mng)
155161
{
156162
u8 start = fw_mng->start_cmd_payload_size;
157163
u32 offset, max_block_size, max_lpl_len;
@@ -202,6 +208,67 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb,
202208
return 0;
203209
}
204210

211+
struct cmis_cdb_write_fw_block_epl_pl {
212+
u8 fw_block[ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH];
213+
};
214+
215+
static int
216+
cmis_fw_update_write_image_epl(struct ethtool_cmis_cdb *cdb,
217+
struct ethtool_cmis_fw_update_params *fw_update,
218+
struct cmis_fw_update_fw_mng_features *fw_mng)
219+
{
220+
u8 start = fw_mng->start_cmd_payload_size;
221+
u32 image_size = fw_update->fw->size;
222+
u32 offset, lpl_len;
223+
int err;
224+
225+
lpl_len = sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl,
226+
block_address);
227+
228+
for (offset = start; offset < image_size;
229+
offset += ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH) {
230+
struct cmis_cdb_write_fw_block_lpl_pl lpl = {
231+
.block_address = cpu_to_be32(offset - start),
232+
};
233+
struct cmis_cdb_write_fw_block_epl_pl *epl;
234+
struct ethtool_cmis_cdb_cmd_args args = {};
235+
u32 epl_len;
236+
237+
ethnl_module_fw_flash_ntf_in_progress(fw_update->dev,
238+
&fw_update->ntf_params,
239+
offset - start,
240+
image_size);
241+
242+
epl_len = min_t(u32, ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH,
243+
image_size - offset);
244+
epl = kmalloc_array(epl_len, sizeof(u8), GFP_KERNEL);
245+
if (!epl)
246+
return -ENOMEM;
247+
248+
memcpy(epl->fw_block, &fw_update->fw->data[offset], epl_len);
249+
250+
ethtool_cmis_cdb_compose_args(&args,
251+
ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_EPL,
252+
(u8 *)&lpl, lpl_len, (u8 *)epl,
253+
epl_len,
254+
fw_mng->max_duration_write,
255+
cdb->read_write_len_ext, 1, 0,
256+
CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
257+
258+
err = ethtool_cmis_cdb_execute_cmd(fw_update->dev, &args);
259+
kfree(epl);
260+
if (err < 0) {
261+
ethnl_module_fw_flash_ntf_err(fw_update->dev,
262+
&fw_update->ntf_params,
263+
"Write FW block EPL command failed",
264+
args.err_msg);
265+
return err;
266+
}
267+
}
268+
269+
return 0;
270+
}
271+
205272
static int
206273
cmis_fw_update_complete_download(struct ethtool_cmis_cdb *cdb,
207274
struct net_device *dev,
@@ -238,9 +305,15 @@ cmis_fw_update_download_image(struct ethtool_cmis_cdb *cdb,
238305
if (err < 0)
239306
return err;
240307

241-
err = cmis_fw_update_write_image(cdb, fw_update, fw_mng);
242-
if (err < 0)
243-
return err;
308+
if (fw_mng->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL) {
309+
err = cmis_fw_update_write_image_lpl(cdb, fw_update, fw_mng);
310+
if (err < 0)
311+
return err;
312+
} else {
313+
err = cmis_fw_update_write_image_epl(cdb, fw_update, fw_mng);
314+
if (err < 0)
315+
return err;
316+
}
244317

245318
err = cmis_fw_update_complete_download(cdb, fw_update->dev, fw_mng,
246319
&fw_update->ntf_params);

0 commit comments

Comments
 (0)