1 // SPDX-License-Identifier: GPL-2.0-only
3 #include <linux/ethtool.h>
4 #include <linux/jiffies.h>
10 /* For accessing the LPL field on page 9Fh, the allowable length extension is
11 * min(i, 15) byte octets where i specifies the allowable additional number of
12 * byte octets in a READ or a WRITE.
14 u32
ethtool_cmis_get_max_payload_size(u8 num_of_byte_octs
)
16 return 8 * (1 + min_t(u8
, num_of_byte_octs
, 15));
19 void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args
*args
,
20 enum ethtool_cmis_cdb_cmd_id cmd
, u8
*pl
,
21 u8 lpl_len
, u16 max_duration
,
22 u8 read_write_len_ext
, u16 msleep_pre_rpl
,
23 u8 rpl_exp_len
, u8 flags
)
25 args
->req
.id
= cpu_to_be16(cmd
);
26 args
->req
.lpl_len
= lpl_len
;
28 memcpy(args
->req
.payload
, pl
, args
->req
.lpl_len
);
30 args
->max_duration
= max_duration
;
31 args
->read_write_len_ext
=
32 ethtool_cmis_get_max_payload_size(read_write_len_ext
);
33 args
->msleep_pre_rpl
= msleep_pre_rpl
;
34 args
->rpl_exp_len
= rpl_exp_len
;
39 void ethtool_cmis_page_init(struct ethtool_module_eeprom
*page_data
,
40 u8 page
, u32 offset
, u32 length
)
42 page_data
->page
= page
;
43 page_data
->offset
= offset
;
44 page_data
->length
= length
;
45 page_data
->i2c_address
= ETHTOOL_CMIS_CDB_PAGE_I2C_ADDR
;
48 #define CMIS_REVISION_PAGE 0x00
49 #define CMIS_REVISION_OFFSET 0x01
55 static u8
cmis_rev_rpl_major(struct cmis_rev_rpl
*rpl
)
60 static int cmis_rev_major_get(struct net_device
*dev
, u8
*rev_major
)
62 const struct ethtool_ops
*ops
= dev
->ethtool_ops
;
63 struct ethtool_module_eeprom page_data
= {0};
64 struct netlink_ext_ack extack
= {};
65 struct cmis_rev_rpl rpl
= {};
68 ethtool_cmis_page_init(&page_data
, CMIS_REVISION_PAGE
,
69 CMIS_REVISION_OFFSET
, sizeof(rpl
));
70 page_data
.data
= (u8
*)&rpl
;
72 err
= ops
->get_module_eeprom_by_page(dev
, &page_data
, &extack
);
75 netdev_err(dev
, "%s\n", extack
._msg
);
79 *rev_major
= cmis_rev_rpl_major(&rpl
);
84 #define CMIS_CDB_ADVERTISEMENT_PAGE 0x01
85 #define CMIS_CDB_ADVERTISEMENT_OFFSET 0xA3
87 /* Based on section 8.4.11 "CDB Messaging Support Advertisement" in CMIS
88 * standard revision 5.2.
90 struct cmis_cdb_advert_rpl
{
92 u8 read_write_len_ext
;
97 static u8
cmis_cdb_advert_rpl_inst_supported(struct cmis_cdb_advert_rpl
*rpl
)
99 return rpl
->inst_supported
>> 6;
102 static int cmis_cdb_advertisement_get(struct ethtool_cmis_cdb
*cdb
,
103 struct net_device
*dev
,
104 struct ethnl_module_fw_flash_ntf_params
*ntf_params
)
106 const struct ethtool_ops
*ops
= dev
->ethtool_ops
;
107 struct ethtool_module_eeprom page_data
= {};
108 struct cmis_cdb_advert_rpl rpl
= {};
109 struct netlink_ext_ack extack
= {};
112 ethtool_cmis_page_init(&page_data
, CMIS_CDB_ADVERTISEMENT_PAGE
,
113 CMIS_CDB_ADVERTISEMENT_OFFSET
, sizeof(rpl
));
114 page_data
.data
= (u8
*)&rpl
;
116 err
= ops
->get_module_eeprom_by_page(dev
, &page_data
, &extack
);
119 netdev_err(dev
, "%s\n", extack
._msg
);
123 if (!cmis_cdb_advert_rpl_inst_supported(&rpl
)) {
124 ethnl_module_fw_flash_ntf_err(dev
, ntf_params
,
125 "CDB functionality is not supported",
130 cdb
->read_write_len_ext
= rpl
.read_write_len_ext
;
135 #define CMIS_PASSWORD_ENTRY_PAGE 0x00
136 #define CMIS_PASSWORD_ENTRY_OFFSET 0x7A
138 struct cmis_password_entry_pl
{
142 /* See section 9.3.1 "CMD 0000h: Query Status" in CMIS standard revision 5.2.
143 * struct cmis_cdb_query_status_pl and struct cmis_cdb_query_status_rpl are
144 * structured layouts of the flat arrays,
145 * struct ethtool_cmis_cdb_request::payload and
146 * struct ethtool_cmis_cdb_rpl::payload respectively.
148 struct cmis_cdb_query_status_pl
{
152 struct cmis_cdb_query_status_rpl
{
158 cmis_cdb_validate_password(struct ethtool_cmis_cdb
*cdb
,
159 struct net_device
*dev
,
160 const struct ethtool_module_fw_flash_params
*params
,
161 struct ethnl_module_fw_flash_ntf_params
*ntf_params
)
163 const struct ethtool_ops
*ops
= dev
->ethtool_ops
;
164 struct cmis_cdb_query_status_pl qs_pl
= {0};
165 struct ethtool_module_eeprom page_data
= {};
166 struct ethtool_cmis_cdb_cmd_args args
= {};
167 struct cmis_password_entry_pl pe_pl
= {};
168 struct cmis_cdb_query_status_rpl
*rpl
;
169 struct netlink_ext_ack extack
= {};
172 ethtool_cmis_page_init(&page_data
, CMIS_PASSWORD_ENTRY_PAGE
,
173 CMIS_PASSWORD_ENTRY_OFFSET
, sizeof(pe_pl
));
174 page_data
.data
= (u8
*)&pe_pl
;
176 pe_pl
= *((struct cmis_password_entry_pl
*)page_data
.data
);
177 pe_pl
.password
= params
->password
;
178 err
= ops
->set_module_eeprom_by_page(dev
, &page_data
, &extack
);
181 netdev_err(dev
, "%s\n", extack
._msg
);
185 ethtool_cmis_cdb_compose_args(&args
, ETHTOOL_CMIS_CDB_CMD_QUERY_STATUS
,
186 (u8
*)&qs_pl
, sizeof(qs_pl
), 0,
187 cdb
->read_write_len_ext
, 1000,
189 CDB_F_COMPLETION_VALID
| CDB_F_STATUS_VALID
);
191 err
= ethtool_cmis_cdb_execute_cmd(dev
, &args
);
193 ethnl_module_fw_flash_ntf_err(dev
, ntf_params
,
194 "Query Status command failed",
199 rpl
= (struct cmis_cdb_query_status_rpl
*)args
.req
.payload
;
200 if (!rpl
->length
|| !rpl
->status
) {
201 ethnl_module_fw_flash_ntf_err(dev
, ntf_params
,
202 "Password was not accepted",
210 /* Some CDB commands asserts the CDB completion flag only from CMIS
211 * revision 5. Therefore, check the relevant validity flag only when
212 * the revision supports it.
214 void ethtool_cmis_cdb_check_completion_flag(u8 cmis_rev
, u8
*flags
)
216 *flags
|= cmis_rev
>= 5 ? CDB_F_COMPLETION_VALID
: 0;
219 #define CMIS_CDB_MODULE_FEATURES_RESV_DATA 34
221 /* See section 9.4.1 "CMD 0040h: Module Features" in CMIS standard revision 5.2.
222 * struct cmis_cdb_module_features_rpl is structured layout of the flat
223 * array, ethtool_cmis_cdb_rpl::payload.
225 struct cmis_cdb_module_features_rpl
{
226 u8 resv1
[CMIS_CDB_MODULE_FEATURES_RESV_DATA
];
227 __be16 max_completion_time
;
231 cmis_cdb_module_features_completion_time(struct cmis_cdb_module_features_rpl
*rpl
)
233 return be16_to_cpu(rpl
->max_completion_time
);
236 static int cmis_cdb_module_features_get(struct ethtool_cmis_cdb
*cdb
,
237 struct net_device
*dev
,
238 struct ethnl_module_fw_flash_ntf_params
*ntf_params
)
240 struct ethtool_cmis_cdb_cmd_args args
= {};
241 struct cmis_cdb_module_features_rpl
*rpl
;
242 u8 flags
= CDB_F_STATUS_VALID
;
245 ethtool_cmis_cdb_check_completion_flag(cdb
->cmis_rev
, &flags
);
246 ethtool_cmis_cdb_compose_args(&args
,
247 ETHTOOL_CMIS_CDB_CMD_MODULE_FEATURES
,
248 NULL
, 0, 0, cdb
->read_write_len_ext
,
249 1000, sizeof(*rpl
), flags
);
251 err
= ethtool_cmis_cdb_execute_cmd(dev
, &args
);
253 ethnl_module_fw_flash_ntf_err(dev
, ntf_params
,
254 "Module Features command failed",
259 rpl
= (struct cmis_cdb_module_features_rpl
*)args
.req
.payload
;
260 cdb
->max_completion_time
=
261 cmis_cdb_module_features_completion_time(rpl
);
266 struct ethtool_cmis_cdb
*
267 ethtool_cmis_cdb_init(struct net_device
*dev
,
268 const struct ethtool_module_fw_flash_params
*params
,
269 struct ethnl_module_fw_flash_ntf_params
*ntf_params
)
271 struct ethtool_cmis_cdb
*cdb
;
274 cdb
= kzalloc(sizeof(*cdb
), GFP_KERNEL
);
276 return ERR_PTR(-ENOMEM
);
278 err
= cmis_rev_major_get(dev
, &cdb
->cmis_rev
);
282 if (cdb
->cmis_rev
< 4) {
283 ethnl_module_fw_flash_ntf_err(dev
, ntf_params
,
284 "CMIS revision doesn't support module firmware flashing",
290 err
= cmis_cdb_advertisement_get(cdb
, dev
, ntf_params
);
294 if (params
->password_valid
) {
295 err
= cmis_cdb_validate_password(cdb
, dev
, params
, ntf_params
);
300 err
= cmis_cdb_module_features_get(cdb
, dev
, ntf_params
);
307 ethtool_cmis_cdb_fini(cdb
);
311 void ethtool_cmis_cdb_fini(struct ethtool_cmis_cdb
*cdb
)
316 static bool is_completed(u8 data
)
318 return !!(data
& 0x40);
321 #define CMIS_CDB_STATUS_SUCCESS 0x01
323 static bool status_success(u8 data
)
325 return data
== CMIS_CDB_STATUS_SUCCESS
;
328 #define CMIS_CDB_STATUS_FAIL 0x40
330 static bool status_fail(u8 data
)
332 return data
& CMIS_CDB_STATUS_FAIL
;
335 struct cmis_wait_for_cond_rpl
{
340 ethtool_cmis_module_poll(struct net_device
*dev
,
341 struct cmis_wait_for_cond_rpl
*rpl
, u32 offset
,
342 bool (*cond_success
)(u8
), bool (*cond_fail
)(u8
))
344 const struct ethtool_ops
*ops
= dev
->ethtool_ops
;
345 struct ethtool_module_eeprom page_data
= {0};
346 struct netlink_ext_ack extack
= {};
349 ethtool_cmis_page_init(&page_data
, 0, offset
, sizeof(rpl
));
350 page_data
.data
= (u8
*)rpl
;
352 err
= ops
->get_module_eeprom_by_page(dev
, &page_data
, &extack
);
355 netdev_err_once(dev
, "%s\n", extack
._msg
);
359 if ((*cond_success
)(rpl
->state
))
362 if (*cond_fail
&& (*cond_fail
)(rpl
->state
))
368 int ethtool_cmis_wait_for_cond(struct net_device
*dev
, u8 flags
, u8 flag
,
369 u16 max_duration
, u32 offset
,
370 bool (*cond_success
)(u8
), bool (*cond_fail
)(u8
),
373 struct cmis_wait_for_cond_rpl rpl
= {};
380 if (max_duration
== 0)
381 max_duration
= U16_MAX
;
383 end
= jiffies
+ msecs_to_jiffies(max_duration
);
385 err
= ethtool_cmis_module_poll(dev
, &rpl
, offset
, cond_success
,
391 } while (time_before(jiffies
, end
));
393 err
= ethtool_cmis_module_poll(dev
, &rpl
, offset
, cond_success
,
403 #define CMIS_CDB_COMPLETION_FLAG_OFFSET 0x08
405 static int cmis_cdb_wait_for_completion(struct net_device
*dev
,
406 struct ethtool_cmis_cdb_cmd_args
*args
)
411 /* Some vendors demand waiting time before checking completion flag
412 * in some CDB commands.
414 msleep(args
->msleep_pre_rpl
);
416 err
= ethtool_cmis_wait_for_cond(dev
, args
->flags
,
417 CDB_F_COMPLETION_VALID
,
419 CMIS_CDB_COMPLETION_FLAG_OFFSET
,
420 is_completed
, NULL
, &flag
);
422 args
->err_msg
= "Completion Flag did not set on time";
427 #define CMIS_CDB_STATUS_OFFSET 0x25
429 static void cmis_cdb_status_fail_msg_get(u8 status
, char **err_msg
)
433 *err_msg
= "CDB Status is in progress: Busy capturing command";
437 "CDB Status is in progress: Busy checking/validating command";
440 *err_msg
= "CDB Status is in progress: Busy executing";
443 *err_msg
= "CDB status failed: no specific failure";
447 "CDB status failed: Parameter range error or parameter not supported";
450 *err_msg
= "CDB status failed: CdbChkCode error";
453 *err_msg
= "CDB status failed: Password error";
456 *err_msg
= "Unknown failure reason";
460 static int cmis_cdb_wait_for_status(struct net_device
*dev
,
461 struct ethtool_cmis_cdb_cmd_args
*args
)
466 /* Some vendors demand waiting time before checking status in some
469 msleep(args
->msleep_pre_rpl
);
471 err
= ethtool_cmis_wait_for_cond(dev
, args
->flags
, CDB_F_STATUS_VALID
,
473 CMIS_CDB_STATUS_OFFSET
,
474 status_success
, status_fail
, &status
);
475 if (err
< 0 && !args
->err_msg
)
476 cmis_cdb_status_fail_msg_get(status
, &args
->err_msg
);
481 #define CMIS_CDB_REPLY_OFFSET 0x86
483 static int cmis_cdb_process_reply(struct net_device
*dev
,
484 struct ethtool_module_eeprom
*page_data
,
485 struct ethtool_cmis_cdb_cmd_args
*args
)
487 u8 rpl_hdr_len
= sizeof(struct ethtool_cmis_cdb_rpl_hdr
);
488 u8 rpl_exp_len
= args
->rpl_exp_len
+ rpl_hdr_len
;
489 const struct ethtool_ops
*ops
= dev
->ethtool_ops
;
490 struct netlink_ext_ack extack
= {};
491 struct ethtool_cmis_cdb_rpl
*rpl
;
494 if (!args
->rpl_exp_len
)
497 ethtool_cmis_page_init(page_data
, ETHTOOL_CMIS_CDB_CMD_PAGE
,
498 CMIS_CDB_REPLY_OFFSET
, rpl_exp_len
);
499 page_data
->data
= kmalloc(page_data
->length
, GFP_KERNEL
);
500 if (!page_data
->data
)
503 err
= ops
->get_module_eeprom_by_page(dev
, page_data
, &extack
);
506 netdev_err(dev
, "%s\n", extack
._msg
);
510 rpl
= (struct ethtool_cmis_cdb_rpl
*)page_data
->data
;
511 if ((args
->rpl_exp_len
> rpl
->hdr
.rpl_len
+ rpl_hdr_len
) ||
512 !rpl
->hdr
.rpl_chk_code
) {
517 args
->req
.lpl_len
= rpl
->hdr
.rpl_len
;
518 memcpy(args
->req
.payload
, rpl
->payload
, args
->req
.lpl_len
);
521 kfree(page_data
->data
);
526 __ethtool_cmis_cdb_execute_cmd(struct net_device
*dev
,
527 struct ethtool_module_eeprom
*page_data
,
528 u8 page
, u32 offset
, u32 length
, void *data
)
530 const struct ethtool_ops
*ops
= dev
->ethtool_ops
;
531 struct netlink_ext_ack extack
= {};
534 ethtool_cmis_page_init(page_data
, page
, offset
, length
);
535 page_data
->data
= kmemdup(data
, page_data
->length
, GFP_KERNEL
);
536 if (!page_data
->data
)
539 err
= ops
->set_module_eeprom_by_page(dev
, page_data
, &extack
);
542 netdev_err(dev
, "%s\n", extack
._msg
);
545 kfree(page_data
->data
);
549 static u8
cmis_cdb_calc_checksum(const void *data
, size_t size
)
551 const u8
*bytes
= (const u8
*)data
;
554 for (size_t i
= 0; i
< size
; i
++)
555 checksum
+= bytes
[i
];
560 #define CMIS_CDB_CMD_ID_OFFSET 0x80
562 int ethtool_cmis_cdb_execute_cmd(struct net_device
*dev
,
563 struct ethtool_cmis_cdb_cmd_args
*args
)
565 struct ethtool_module_eeprom page_data
= {};
570 cmis_cdb_calc_checksum(&args
->req
, sizeof(args
->req
));
572 if (args
->req
.lpl_len
> args
->read_write_len_ext
) {
573 args
->err_msg
= "LPL length is longer than CDB read write length extension allows";
577 /* According to the CMIS standard, there are two options to trigger the
578 * CDB commands. The default option is triggering the command by writing
579 * the CMDID bytes. Therefore, the command will be split to 2 calls:
580 * First, with everything except the CMDID field and then the CMDID
583 offset
= CMIS_CDB_CMD_ID_OFFSET
+
584 offsetof(struct ethtool_cmis_cdb_request
, body
);
585 err
= __ethtool_cmis_cdb_execute_cmd(dev
, &page_data
,
586 ETHTOOL_CMIS_CDB_CMD_PAGE
, offset
,
587 sizeof(args
->req
.body
),
592 offset
= CMIS_CDB_CMD_ID_OFFSET
+
593 offsetof(struct ethtool_cmis_cdb_request
, id
);
594 err
= __ethtool_cmis_cdb_execute_cmd(dev
, &page_data
,
595 ETHTOOL_CMIS_CDB_CMD_PAGE
, offset
,
596 sizeof(args
->req
.id
),
601 err
= cmis_cdb_wait_for_completion(dev
, args
);
605 err
= cmis_cdb_wait_for_status(dev
, args
);
609 return cmis_cdb_process_reply(dev
, &page_data
, args
);