Skip to content

Commit c977ac4

Browse files
committed
Merge branch 'net-flash-modees-firmware' into main
Danielle Ratson says: ==================== Add ability to flash modules' firmware CMIS compliant modules such as QSFP-DD might be running a firmware that can be updated in a vendor-neutral way by exchanging messages between the host and the module as described in section 7.2.2 of revision 4.0 of the CMIS standard. According to the CMIS standard, the firmware update process is done using a CDB commands sequence. CDB (Command Data Block Message Communication) reads and writes are performed on memory map pages 9Fh-AFh according to the CMIS standard, section 8.12 of revision 4.0. Add a pair of new ethtool messages that allow: * User space to trigger firmware update of transceiver modules * The kernel to notify user space about the progress of the process The user interface is designed to be asynchronous in order to avoid RTNL being held for too long and to allow several modules to be updated simultaneously. The interface is designed with CMIS compliant modules in mind, but kept generic enough to accommodate future use cases, if these arise. The kernel interface that will implement the firmware update using CDB command will include 2 layers that will be added under ethtool: * The upper layer that will be triggered from the module layer, is cmis_ fw_update. * The lower one is cmis_cdb. In the future there might be more operations to implement using CDB commands. Therefore, the idea is to keep the cmis_cdb interface clean and the cmis_fw_update specific to the cdb commands handling it. The communication between the kernel and the driver will be done using two ethtool operations that enable reading and writing the transceiver module EEPROM. The operation ethtool_ops::get_module_eeprom_by_page, that is already implemented, will be used for reading from the EEPROM the CDB reply, e.g. reading module setting, state, etc. The operation ethtool_ops::set_module_eeprom_by_page, that is added in the current patchset, will be used for writing to the EEPROM the CDB command such as start firmware image, run firmware image, etc. Therefore in order for a driver to implement module flashing, that driver needs to implement the two functions mentioned above. Patchset overview: Patch #1-#2: Implement the EEPROM writing in mlxsw. Patch #3: Define the interface between the kernel and user space. Patch #4: Add ability to notify the flashing firmware progress. Patch #5: Veto operations during flashing. Patch #6: Add extended compliance codes. Patch #7: Add the cdb layer. Patch #8: Add the fw_update layer. Patch #9: Add ability to flash transceiver modules' firmware. v8: Patch #7: * In the ethtool_cmis_wait_for_cond() evaluate the condition once more to decide if the error code should be -ETIMEDOUT or something else. * s/netdev_err/netdev_err_once. v7: Patch #4: * Return -ENOMEM instead of PTR_ERR(attr) on ethnl_module_fw_flash_ntf_put_err(). Patch #9: * Fix Warning for not unlocking the spin_lock in the error flow on module_flash_fw_work_list_add(). * Avoid the fall-through on ethnl_sock_priv_destroy(). v6: * Squash some of the last patch to patch #5 and patch #9. Patch #3: * Add paragraph in .rst file. Patch #4: * Reserve '1' more place on SKB for NUL terminator in the error message string. * Add more prints on error flow, re-write the printing function and add ethnl_module_fw_flash_ntf_put_err(). * Change the communication method so notification will be sent in unicast instead of multicast. * Add new 'struct ethnl_module_fw_flash_ntf_params' that holds the relevant info for unicast communication and use it to send notification to the specific socket. * s/nla_put_u64_64bit/nla_put_uint/ Patch #7: * In ethtool_cmis_cdb_init(), Use 'const' for the 'params' parameter. Patch #8: * Add a list field to struct ethtool_module_fw_flash for module_fw_flash_work_list that will be presented in the next patch. * Move ethtool_cmis_fw_update() cleaning to a new function that will be represented in the next patch. * Move some of the fields in struct ethtool_module_fw_flash to a separate struct, so ethtool_cmis_fw_update() will get only the relevant parameters for it. * Edit the relevant functions to get the relevant params for them. * s/CMIS_MODULE_READY_MAX_DURATION_USEC/CMIS_MODULE_READY_MAX_DURATION_MSEC Patch #9: * Add a paragraph in the commit message. * Rename labels in module_flash_fw_schedule(). * Add info to genl_sk_priv_*() and implement the relevant callbacks, in order to handle properly a scenario of closing the socket from user space before the work item was ended. * Add a list the holds all the ethtool_module_fw_flash struct that corresponds to the in progress work items. * Add a new enum for the socket types. * Use both above to identify a flashing socket, add it to the list and when closing socket affect only the flashing type. * Create a new function that will get the work item instead of ethtool_cmis_fw_update(). * Edit the relevant functions to get the relevant params for them. * The new function will call the old ethtool_cmis_fw_update(), and do the cleaning, so the existence of the list should be completely isolated in module.c. =================== Signed-off-by: David S. Miller <[email protected]>
2 parents 8fda537 + 32b4c8b commit c977ac4

File tree

22 files changed

+1963
-11
lines changed

22 files changed

+1963
-11
lines changed

Documentation/netlink/specs/ethtool.yaml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ definitions:
2020
name: header-flags
2121
type: flags
2222
entries: [ compact-bitsets, omit-reply, stats ]
23+
-
24+
name: module-fw-flash-status
25+
type: enum
26+
entries: [ started, in_progress, completed, error ]
2327

2428
attribute-sets:
2529
-
@@ -1004,6 +1008,32 @@ attribute-sets:
10041008
-
10051009
name: burst-tmr
10061010
type: u32
1011+
-
1012+
name: module-fw-flash
1013+
attributes:
1014+
-
1015+
name: header
1016+
type: nest
1017+
nested-attributes: header
1018+
-
1019+
name: file-name
1020+
type: string
1021+
-
1022+
name: password
1023+
type: u32
1024+
-
1025+
name: status
1026+
type: u32
1027+
enum: module-fw-flash-status
1028+
-
1029+
name: status-msg
1030+
type: string
1031+
-
1032+
name: done
1033+
type: uint
1034+
-
1035+
name: total
1036+
type: uint
10071037

10081038
operations:
10091039
enum-model: directional
@@ -1764,3 +1794,28 @@ operations:
17641794
name: mm-ntf
17651795
doc: Notification for change in MAC Merge configuration.
17661796
notify: mm-get
1797+
-
1798+
name: module-fw-flash-act
1799+
doc: Flash transceiver module firmware.
1800+
1801+
attribute-set: module-fw-flash
1802+
1803+
do:
1804+
request:
1805+
attributes:
1806+
- header
1807+
- file-name
1808+
- password
1809+
-
1810+
name: module-fw-flash-ntf
1811+
doc: Notification for firmware flashing progress and status.
1812+
1813+
attribute-set: module-fw-flash
1814+
1815+
event:
1816+
attributes:
1817+
- header
1818+
- status
1819+
- status-msg
1820+
- done
1821+
- total

Documentation/networking/ethtool-netlink.rst

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ Userspace to kernel:
228228
``ETHTOOL_MSG_PLCA_GET_STATUS`` get PLCA RS status
229229
``ETHTOOL_MSG_MM_GET`` get MAC merge layer state
230230
``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters
231+
``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` flash transceiver module firmware
231232
===================================== =================================
232233

233234
Kernel to userspace:
@@ -274,6 +275,7 @@ Kernel to userspace:
274275
``ETHTOOL_MSG_PLCA_GET_STATUS_REPLY`` PLCA RS status
275276
``ETHTOOL_MSG_PLCA_NTF`` PLCA RS parameters
276277
``ETHTOOL_MSG_MM_GET_REPLY`` MAC merge layer status
278+
``ETHTOOL_MSG_MODULE_FW_FLASH_NTF`` transceiver module flash updates
277279
======================================== =================================
278280

279281
``GET`` requests are sent by userspace applications to retrieve device
@@ -2041,6 +2043,73 @@ The attributes are propagated to the driver through the following structure:
20412043
.. kernel-doc:: include/linux/ethtool.h
20422044
:identifiers: ethtool_mm_cfg
20432045

2046+
MODULE_FW_FLASH_ACT
2047+
===================
2048+
2049+
Flashes transceiver module firmware.
2050+
2051+
Request contents:
2052+
2053+
======================================= ====== ===========================
2054+
``ETHTOOL_A_MODULE_FW_FLASH_HEADER`` nested request header
2055+
``ETHTOOL_A_MODULE_FW_FLASH_FILE_NAME`` string firmware image file name
2056+
``ETHTOOL_A_MODULE_FW_FLASH_PASSWORD`` u32 transceiver module password
2057+
======================================= ====== ===========================
2058+
2059+
The firmware update process consists of three logical steps:
2060+
2061+
1. Downloading a firmware image to the transceiver module and validating it.
2062+
2. Running the firmware image.
2063+
3. Committing the firmware image so that it is run upon reset.
2064+
2065+
When flash command is given, those three steps are taken in that order.
2066+
2067+
This message merely schedules the update process and returns immediately
2068+
without blocking. The process then runs asynchronously.
2069+
Since it can take several minutes to complete, during the update process
2070+
notifications are emitted from the kernel to user space updating it about
2071+
the status and progress.
2072+
2073+
The ``ETHTOOL_A_MODULE_FW_FLASH_FILE_NAME`` attribute encodes the firmware
2074+
image file name. The firmware image is downloaded to the transceiver module,
2075+
validated, run and committed.
2076+
2077+
The optional ``ETHTOOL_A_MODULE_FW_FLASH_PASSWORD`` attribute encodes a password
2078+
that might be required as part of the transceiver module firmware update
2079+
process.
2080+
2081+
The firmware update process can take several minutes to complete. Therefore,
2082+
during the update process notifications are emitted from the kernel to user
2083+
space updating it about the status and progress.
2084+
2085+
2086+
2087+
Notification contents:
2088+
2089+
+---------------------------------------------------+--------+----------------+
2090+
| ``ETHTOOL_A_MODULE_FW_FLASH_HEADER`` | nested | reply header |
2091+
+---------------------------------------------------+--------+----------------+
2092+
| ``ETHTOOL_A_MODULE_FW_FLASH_STATUS`` | u32 | status |
2093+
+---------------------------------------------------+--------+----------------+
2094+
| ``ETHTOOL_A_MODULE_FW_FLASH_STATUS_MSG`` | string | status message |
2095+
+---------------------------------------------------+--------+----------------+
2096+
| ``ETHTOOL_A_MODULE_FW_FLASH_DONE`` | uint | progress |
2097+
+---------------------------------------------------+--------+----------------+
2098+
| ``ETHTOOL_A_MODULE_FW_FLASH_TOTAL`` | uint | total |
2099+
+---------------------------------------------------+--------+----------------+
2100+
2101+
The ``ETHTOOL_A_MODULE_FW_FLASH_STATUS`` attribute encodes the current status
2102+
of the firmware update process. Possible values are:
2103+
2104+
.. kernel-doc:: include/uapi/linux/ethtool.h
2105+
:identifiers: ethtool_module_fw_flash_status
2106+
2107+
The ``ETHTOOL_A_MODULE_FW_FLASH_STATUS_MSG`` attribute encodes a status message
2108+
string.
2109+
2110+
The ``ETHTOOL_A_MODULE_FW_FLASH_DONE`` and ``ETHTOOL_A_MODULE_FW_FLASH_TOTAL``
2111+
attributes encode the completed and total amount of work, respectively.
2112+
20442113
Request translation
20452114
===================
20462115

@@ -2147,4 +2216,5 @@ are netlink only.
21472216
n/a ``ETHTOOL_MSG_PLCA_GET_STATUS``
21482217
n/a ``ETHTOOL_MSG_MM_GET``
21492218
n/a ``ETHTOOL_MSG_MM_SET``
2219+
n/a ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT``
21502220
=================================== =====================================

drivers/net/ethernet/mellanox/mlxsw/core_env.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,63 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core,
513513
}
514514
EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page);
515515

516+
int
517+
mlxsw_env_set_module_eeprom_by_page(struct mlxsw_core *mlxsw_core,
518+
u8 slot_index, u8 module,
519+
const struct ethtool_module_eeprom *page,
520+
struct netlink_ext_ack *extack)
521+
{
522+
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
523+
u32 bytes_written = 0;
524+
u16 device_addr;
525+
int err;
526+
527+
if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) {
528+
NL_SET_ERR_MSG_MOD(extack,
529+
"Cannot write to EEPROM of a module on an inactive line card");
530+
return -EIO;
531+
}
532+
533+
err = mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
534+
if (err) {
535+
NL_SET_ERR_MSG_MOD(extack, "EEPROM is not equipped on port module type");
536+
return err;
537+
}
538+
539+
device_addr = page->offset;
540+
541+
while (bytes_written < page->length) {
542+
char mcia_pl[MLXSW_REG_MCIA_LEN];
543+
char eeprom_tmp[128] = {};
544+
u8 size;
545+
546+
size = min_t(u8, page->length - bytes_written,
547+
mlxsw_env->max_eeprom_len);
548+
549+
mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page->page,
550+
device_addr + bytes_written, size,
551+
page->i2c_address);
552+
mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank);
553+
memcpy(eeprom_tmp, page->data + bytes_written, size);
554+
mlxsw_reg_mcia_eeprom_memcpy_to(mcia_pl, eeprom_tmp);
555+
556+
err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
557+
if (err) {
558+
NL_SET_ERR_MSG_MOD(extack, "Failed to access module's EEPROM");
559+
return err;
560+
}
561+
562+
err = mlxsw_env_mcia_status_process(mcia_pl, extack);
563+
if (err)
564+
return err;
565+
566+
bytes_written += size;
567+
}
568+
569+
return 0;
570+
}
571+
EXPORT_SYMBOL(mlxsw_env_set_module_eeprom_by_page);
572+
516573
static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 slot_index,
517574
u8 module)
518575
{

drivers/net/ethernet/mellanox/mlxsw/core_env.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core,
2828
const struct ethtool_module_eeprom *page,
2929
struct netlink_ext_ack *extack);
3030

31+
int
32+
mlxsw_env_set_module_eeprom_by_page(struct mlxsw_core *mlxsw_core,
33+
u8 slot_index, u8 module,
34+
const struct ethtool_module_eeprom *page,
35+
struct netlink_ext_ack *extack);
36+
3137
int mlxsw_env_reset_module(struct net_device *netdev,
3238
struct mlxsw_core *mlxsw_core, u8 slot_index,
3339
u8 module, u32 *flags);

drivers/net/ethernet/mellanox/mlxsw/minimal.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,20 @@ mlxsw_m_get_module_eeprom_by_page(struct net_device *netdev,
140140
page, extack);
141141
}
142142

143+
static int
144+
mlxsw_m_set_module_eeprom_by_page(struct net_device *netdev,
145+
const struct ethtool_module_eeprom *page,
146+
struct netlink_ext_ack *extack)
147+
{
148+
struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
149+
struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
150+
151+
return mlxsw_env_set_module_eeprom_by_page(core,
152+
mlxsw_m_port->slot_index,
153+
mlxsw_m_port->module,
154+
page, extack);
155+
}
156+
143157
static int mlxsw_m_reset(struct net_device *netdev, u32 *flags)
144158
{
145159
struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
@@ -181,6 +195,7 @@ static const struct ethtool_ops mlxsw_m_port_ethtool_ops = {
181195
.get_module_info = mlxsw_m_get_module_info,
182196
.get_module_eeprom = mlxsw_m_get_module_eeprom,
183197
.get_module_eeprom_by_page = mlxsw_m_get_module_eeprom_by_page,
198+
.set_module_eeprom_by_page = mlxsw_m_set_module_eeprom_by_page,
184199
.reset = mlxsw_m_reset,
185200
.get_module_power_mode = mlxsw_m_get_module_power_mode,
186201
.set_module_power_mode = mlxsw_m_set_module_power_mode,

drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,20 @@ mlxsw_sp_get_module_eeprom_by_page(struct net_device *dev,
10671067
module, page, extack);
10681068
}
10691069

1070+
static int
1071+
mlxsw_sp_set_module_eeprom_by_page(struct net_device *dev,
1072+
const struct ethtool_module_eeprom *page,
1073+
struct netlink_ext_ack *extack)
1074+
{
1075+
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1076+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1077+
u8 slot_index = mlxsw_sp_port->mapping.slot_index;
1078+
u8 module = mlxsw_sp_port->mapping.module;
1079+
1080+
return mlxsw_env_set_module_eeprom_by_page(mlxsw_sp->core, slot_index,
1081+
module, page, extack);
1082+
}
1083+
10701084
static int
10711085
mlxsw_sp_get_ts_info(struct net_device *netdev, struct ethtool_ts_info *info)
10721086
{
@@ -1256,6 +1270,7 @@ const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
12561270
.get_module_info = mlxsw_sp_get_module_info,
12571271
.get_module_eeprom = mlxsw_sp_get_module_eeprom,
12581272
.get_module_eeprom_by_page = mlxsw_sp_get_module_eeprom_by_page,
1273+
.set_module_eeprom_by_page = mlxsw_sp_set_module_eeprom_by_page,
12591274
.get_ts_info = mlxsw_sp_get_ts_info,
12601275
.get_eth_phy_stats = mlxsw_sp_get_eth_phy_stats,
12611276
.get_eth_mac_stats = mlxsw_sp_get_eth_mac_stats,

include/linux/ethtool.h

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -506,17 +506,16 @@ struct ethtool_ts_stats {
506506
#define ETH_MODULE_MAX_I2C_ADDRESS 0x7f
507507

508508
/**
509-
* struct ethtool_module_eeprom - EEPROM dump from specified page
510-
* @offset: Offset within the specified EEPROM page to begin read, in bytes.
511-
* @length: Number of bytes to read.
512-
* @page: Page number to read from.
513-
* @bank: Page bank number to read from, if applicable by EEPROM spec.
509+
* struct ethtool_module_eeprom - plug-in module EEPROM read / write parameters
510+
* @offset: When @offset is 0-127, it is used as an address to the Lower Memory
511+
* (@page must be 0). Otherwise, it is used as an address to the
512+
* Upper Memory.
513+
* @length: Number of bytes to read / write.
514+
* @page: Page number.
515+
* @bank: Bank number, if supported by EEPROM spec.
514516
* @i2c_address: I2C address of a page. Value less than 0x7f expected. Most
515517
* EEPROMs use 0x50 or 0x51.
516518
* @data: Pointer to buffer with EEPROM data of @length size.
517-
*
518-
* This can be used to manage pages during EEPROM dump in ethtool and pass
519-
* required information to the driver.
520519
*/
521520
struct ethtool_module_eeprom {
522521
u32 offset;
@@ -824,6 +823,8 @@ struct ethtool_rxfh_param {
824823
* @get_module_eeprom_by_page: Get a region of plug-in module EEPROM data from
825824
* specified page. Returns a negative error code or the amount of bytes
826825
* read.
826+
* @set_module_eeprom_by_page: Write to a region of plug-in module EEPROM,
827+
* from kernel space only. Returns a negative error code or zero.
827828
* @get_eth_phy_stats: Query some of the IEEE 802.3 PHY statistics.
828829
* @get_eth_mac_stats: Query some of the IEEE 802.3 MAC statistics.
829830
* @get_eth_ctrl_stats: Query some of the IEEE 802.3 MAC Ctrl statistics.
@@ -958,6 +959,9 @@ struct ethtool_ops {
958959
int (*get_module_eeprom_by_page)(struct net_device *dev,
959960
const struct ethtool_module_eeprom *page,
960961
struct netlink_ext_ack *extack);
962+
int (*set_module_eeprom_by_page)(struct net_device *dev,
963+
const struct ethtool_module_eeprom *page,
964+
struct netlink_ext_ack *extack);
961965
void (*get_eth_phy_stats)(struct net_device *dev,
962966
struct ethtool_eth_phy_stats *phy_stats);
963967
void (*get_eth_mac_stats)(struct net_device *dev,

include/linux/netdevice.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1990,6 +1990,8 @@ enum netdev_reg_state {
19901990
*
19911991
* @threaded: napi threaded mode is enabled
19921992
*
1993+
* @module_fw_flash_in_progress: Module firmware flashing is in progress.
1994+
*
19931995
* @net_notifier_list: List of per-net netdev notifier block
19941996
* that follow this device when it is moved
19951997
* to another network namespace.
@@ -2374,7 +2376,7 @@ struct net_device {
23742376
bool proto_down;
23752377
bool threaded;
23762378
unsigned wol_enabled:1;
2377-
2379+
unsigned module_fw_flash_in_progress:1;
23782380
struct list_head net_notifier_list;
23792381

23802382
#if IS_ENABLED(CONFIG_MACSEC)

include/linux/sfp.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,12 @@ enum {
284284
SFF8024_ID_QSFP_8438 = 0x0c,
285285
SFF8024_ID_QSFP_8436_8636 = 0x0d,
286286
SFF8024_ID_QSFP28_8636 = 0x11,
287+
SFF8024_ID_QSFP_DD = 0x18,
288+
SFF8024_ID_OSFP = 0x19,
289+
SFF8024_ID_DSFP = 0x1B,
290+
SFF8024_ID_QSFP_PLUS_CMIS = 0x1E,
291+
SFF8024_ID_SFP_DD_CMIS = 0x1F,
292+
SFF8024_ID_SFP_PLUS_CMIS = 0x20,
287293

288294
SFF8024_ENCODING_UNSPEC = 0x00,
289295
SFF8024_ENCODING_8B10B = 0x01,

0 commit comments

Comments
 (0)