Skip to content

Commit

Permalink
Merge branch 'devlink-flash-update-overwrite-mask'
Browse files Browse the repository at this point in the history
Jacob Keller says:

====================
devlink flash update overwrite mask

This series introduces support for a new attribute to the flash update
command: DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK.

This attribute is a bitfield which allows userspace to specify what set of
subfields to overwrite when performing a flash update for a device.

The intention is to support the ability to control the behavior of
overwriting the configuration and identifying fields in the Intel ice device
flash update process. This is necessary  as the firmware layout for the ice
device includes some settings and configuration within the same flash
section as the main firmware binary.

This series, and the accompanying iproute2 series, introduce support for the
attribute. Once applied, the overwrite support can be be invoked via
devlink:

  # overwrite settings
  devlink dev flash pci/0000:af:00.0 file firmware.bin overwrite settings

  # overwrite identifiers and settings
  devlink dev flash pci/0000:af:00.0 file firmware.bin overwrite settings overwrite identifiers

To aid in the safe addition of new parameters, first some refactoring is
done to the .flash_update function: its parameters are converted from a
series of function arguments into a structure. This makes it easier to add
the new parameter without changing the signature of the .flash_update
handler in the future. Additionally, a "supported_flash_update_params" field
is added to devlink_ops. This field is similar to the ethtool
"supported_coalesc_params" field. The devlink core will now check that the
DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT bit is set before forwarding the
component attribute. Similarly, the new overwrite attribute will also
require a supported bit.

Doing these refactors will aid in adding any other attributes in the future,
and creates a good pattern for other interfaces to use in the future. By
requiring drivers to opt-in, we reduce the risk of accidentally breaking
drivers when ever we add an additional parameter. We also reduce boiler
plate code in drivers which do not support the parameters.

Changes since v9:
* rebased to current net-next, no other changes

Changes since v7
* resend, hopefully avoiding the SMTP server issues I experienced on Friday

Changes since v6
* Rebased to current net-next to resolve conflicts
* Added changes to the ionic driver that recently merged flash update support
* Fixed the changes for mlxsw to apply to core instead of spectrum.c after
  the recent refactor.
* Picked up the review tags from Jakub

Changes since v5
* Fix *all* of the BIT usage to use _BITUL() (thanks Jakub!)

Changes since v4
* Renamed nla_overwrite to nla_overwrite_mask at Jiri's suggestion
* Added "by this device" to the netlink error messages for unsupported
  attributes
* Removed use of BIT() in the uapi header
* Fixed the commit message for the netdevsim patch
* Picked up Jakub's reviewed
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Sep 26, 2020
2 parents 6fba737 + 50db1bc commit cb9e4a7
Show file tree
Hide file tree
Showing 17 changed files with 247 additions and 73 deletions.
28 changes: 28 additions & 0 deletions Documentation/networking/devlink/devlink-flash.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,34 @@ Note that the file name is a path relative to the firmware loading path
(usually ``/lib/firmware/``). Drivers may send status updates to inform
user space about the progress of the update operation.

Overwrite Mask
==============

The ``devlink-flash`` command allows optionally specifying a mask indicating
how the device should handle subsections of flash components when updating.
This mask indicates the set of sections which are allowed to be overwritten.

.. list-table:: List of overwrite mask bits
:widths: 5 95

* - Name
- Description
* - ``DEVLINK_FLASH_OVERWRITE_SETTINGS``
- Indicates that the device should overwrite settings in the components
being updated with the settings found in the provided image.
* - ``DEVLINK_FLASH_OVERWRITE_IDENTIFIERS``
- Indicates that the device should overwrite identifiers in the
components being updated with the identifiers found in the provided
image. This includes MAC addresses, serial IDs, and similar device
identifiers.

Multiple overwrite bits may be combined and requested together. If no bits
are provided, it is expected that the device only update firmware binaries
in the components being updated. Settings and identifiers are expected to be
preserved across the update. A device may not support every combination and
the driver for such a device must reject any combination which cannot be
faithfully implemented.

Firmware Loading
================

Expand Down
31 changes: 31 additions & 0 deletions Documentation/networking/devlink/ice.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,37 @@ The ``ice`` driver reports the following versions
- 0xee16ced7
- The first 4 bytes of the hash of the netlist module contents.

Flash Update
============

The ``ice`` driver implements support for flash update using the
``devlink-flash`` interface. It supports updating the device flash using a
combined flash image that contains the ``fw.mgmt``, ``fw.undi``, and
``fw.netlist`` components.

.. list-table:: List of supported overwrite modes
:widths: 5 95

* - Bits
- Behavior
* - ``DEVLINK_FLASH_OVERWRITE_SETTINGS``
- Do not preserve settings stored in the flash components being
updated. This includes overwriting the port configuration that
determines the number of physical functions the device will
initialize with.
* - ``DEVLINK_FLASH_OVERWRITE_SETTINGS`` and ``DEVLINK_FLASH_OVERWRITE_IDENTIFIERS``
- Do not preserve either settings or identifiers. Overwrite everything
in the flash with the contents from the provided image, without
performing any preservation. This includes overwriting device
identifying fields such as the MAC address, VPD area, and device
serial number. It is expected that this combination be used with an
image customized for the specific device.

The ice hardware does not support overwriting only identifiers while
preserving settings, and thus ``DEVLINK_FLASH_OVERWRITE_IDENTIFIERS`` on its
own will be rejected. If no overwrite mask is provided, the firmware will be
instructed to preserve all settings and identifying fields when updating.

Regions
=======

Expand Down
19 changes: 7 additions & 12 deletions drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,26 @@
#include "bnxt_ethtool.h"

static int
bnxt_dl_flash_update(struct devlink *dl, const char *filename,
const char *region, struct netlink_ext_ack *extack)
bnxt_dl_flash_update(struct devlink *dl,
struct devlink_flash_update_params *params,
struct netlink_ext_ack *extack)
{
struct bnxt *bp = bnxt_get_bp_from_dl(dl);
int rc;

if (region)
return -EOPNOTSUPP;

if (!BNXT_PF(bp)) {
NL_SET_ERR_MSG_MOD(extack,
"flash update not supported from a VF");
return -EPERM;
}

devlink_flash_update_begin_notify(dl);
devlink_flash_update_status_notify(dl, "Preparing to flash", region, 0,
0);
rc = bnxt_flash_package_from_file(bp->dev, filename, 0);
devlink_flash_update_status_notify(dl, "Preparing to flash", NULL, 0, 0);
rc = bnxt_flash_package_from_file(bp->dev, params->file_name, 0);
if (!rc)
devlink_flash_update_status_notify(dl, "Flashing done", region,
0, 0);
devlink_flash_update_status_notify(dl, "Flashing done", NULL, 0, 0);
else
devlink_flash_update_status_notify(dl, "Flashing failed",
region, 0, 0);
devlink_flash_update_status_notify(dl, "Flashing failed", NULL, 0, 0);
devlink_flash_update_end_notify(dl);
return rc;
}
Expand Down
8 changes: 2 additions & 6 deletions drivers/net/ethernet/huawei/hinic/hinic_devlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,18 +281,14 @@ static int hinic_firmware_update(struct hinic_devlink_priv *priv,
}

static int hinic_devlink_flash_update(struct devlink *devlink,
const char *file_name,
const char *component,
struct devlink_flash_update_params *params,
struct netlink_ext_ack *extack)
{
struct hinic_devlink_priv *priv = devlink_priv(devlink);
const struct firmware *fw;
int err;

if (component)
return -EOPNOTSUPP;

err = request_firmware_direct(&fw, file_name,
err = request_firmware_direct(&fw, params->file_name,
&priv->hwdev->hwif->pdev->dev);
if (err)
return err;
Expand Down
34 changes: 23 additions & 11 deletions drivers/net/ethernet/intel/ice/ice_devlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,7 @@ static int ice_devlink_info_get(struct devlink *devlink,
/**
* ice_devlink_flash_update - Update firmware stored in flash on the device
* @devlink: pointer to devlink associated with device to update
* @path: the path of the firmware file to use via request_firmware
* @component: name of the component to update, or NULL
* @params: flash update parameters
* @extack: netlink extended ACK structure
*
* Perform a device flash update. The bulk of the update logic is contained
Expand All @@ -243,38 +242,50 @@ static int ice_devlink_info_get(struct devlink *devlink,
* Returns: zero on success, or an error code on failure.
*/
static int
ice_devlink_flash_update(struct devlink *devlink, const char *path,
const char *component, struct netlink_ext_ack *extack)
ice_devlink_flash_update(struct devlink *devlink,
struct devlink_flash_update_params *params,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
struct device *dev = &pf->pdev->dev;
struct ice_hw *hw = &pf->hw;
const struct firmware *fw;
u8 preservation;
int err;

/* individual component update is not yet supported */
if (component)
if (!params->overwrite_mask) {
/* preserve all settings and identifiers */
preservation = ICE_AQC_NVM_PRESERVE_ALL;
} else if (params->overwrite_mask == DEVLINK_FLASH_OVERWRITE_SETTINGS) {
/* overwrite settings, but preserve the vital device identifiers */
preservation = ICE_AQC_NVM_PRESERVE_SELECTED;
} else if (params->overwrite_mask == (DEVLINK_FLASH_OVERWRITE_SETTINGS |
DEVLINK_FLASH_OVERWRITE_IDENTIFIERS)) {
/* overwrite both settings and identifiers, preserve nothing */
preservation = ICE_AQC_NVM_NO_PRESERVATION;
} else {
NL_SET_ERR_MSG_MOD(extack, "Requested overwrite mask is not supported");
return -EOPNOTSUPP;
}

if (!hw->dev_caps.common_cap.nvm_unified_update) {
NL_SET_ERR_MSG_MOD(extack, "Current firmware does not support unified update");
return -EOPNOTSUPP;
}

err = ice_check_for_pending_update(pf, component, extack);
err = ice_check_for_pending_update(pf, NULL, extack);
if (err)
return err;

err = request_firmware(&fw, path, dev);
err = request_firmware(&fw, params->file_name, dev);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Unable to read file from disk");
return err;
}

devlink_flash_update_begin_notify(devlink);
devlink_flash_update_status_notify(devlink, "Preparing to flash",
component, 0, 0);
err = ice_flash_pldm_image(pf, fw, extack);
devlink_flash_update_status_notify(devlink, "Preparing to flash", NULL, 0, 0);
err = ice_flash_pldm_image(pf, fw, preservation, extack);
devlink_flash_update_end_notify(devlink);

release_firmware(fw);
Expand All @@ -283,6 +294,7 @@ ice_devlink_flash_update(struct devlink *devlink, const char *path,
}

static const struct devlink_ops ice_devlink_ops = {
.supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK,
.info_get = ice_devlink_info_get,
.flash_update = ice_devlink_flash_update,
};
Expand Down
16 changes: 14 additions & 2 deletions drivers/net/ethernet/intel/ice/ice_fw_update.c
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ static const struct pldmfw_ops ice_fwu_ops = {
* ice_flash_pldm_image - Write a PLDM-formatted firmware image to the device
* @pf: private device driver structure
* @fw: firmware object pointing to the relevant firmware file
* @preservation: preservation level to request from firmware
* @extack: netlink extended ACK structure
*
* Parse the data for a given firmware file, verifying that it is a valid PLDM
Expand All @@ -638,21 +639,32 @@ static const struct pldmfw_ops ice_fwu_ops = {
* Returns: zero on success or a negative error code on failure.
*/
int ice_flash_pldm_image(struct ice_pf *pf, const struct firmware *fw,
struct netlink_ext_ack *extack)
u8 preservation, struct netlink_ext_ack *extack)
{
struct device *dev = ice_pf_to_dev(pf);
struct ice_hw *hw = &pf->hw;
struct ice_fwu_priv priv;
enum ice_status status;
int err;

switch (preservation) {
case ICE_AQC_NVM_PRESERVE_ALL:
case ICE_AQC_NVM_PRESERVE_SELECTED:
case ICE_AQC_NVM_NO_PRESERVATION:
case ICE_AQC_NVM_FACTORY_DEFAULT:
break;
default:
WARN(1, "Unexpected preservation level request %u", preservation);
return -EINVAL;
}

memset(&priv, 0, sizeof(priv));

priv.context.ops = &ice_fwu_ops;
priv.context.dev = dev;
priv.extack = extack;
priv.pf = pf;
priv.activate_flags = ICE_AQC_NVM_PRESERVE_ALL;
priv.activate_flags = preservation;

status = ice_acquire_nvm(hw, ICE_RES_WRITE);
if (status) {
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/intel/ice/ice_fw_update.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#define _ICE_FW_UPDATE_H_

int ice_flash_pldm_image(struct ice_pf *pf, const struct firmware *fw,
struct netlink_ext_ack *extack);
u8 preservation, struct netlink_ext_ack *extack);
int ice_check_for_pending_update(struct ice_pf *pf, const char *component,
struct netlink_ext_ack *extack);

Expand Down
8 changes: 2 additions & 6 deletions drivers/net/ethernet/mellanox/mlx5/core/devlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,14 @@
#include "eswitch.h"

static int mlx5_devlink_flash_update(struct devlink *devlink,
const char *file_name,
const char *component,
struct devlink_flash_update_params *params,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
const struct firmware *fw;
int err;

if (component)
return -EOPNOTSUPP;

err = request_firmware_direct(&fw, file_name, &dev->pdev->dev);
err = request_firmware_direct(&fw, params->file_name, &dev->pdev->dev);
if (err)
return err;

Expand Down
12 changes: 4 additions & 8 deletions drivers/net/ethernet/mellanox/mlxsw/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1102,16 +1102,13 @@ static int mlxsw_core_fw_rev_validate(struct mlxsw_core *mlxsw_core,
}

static int mlxsw_core_fw_flash_update(struct mlxsw_core *mlxsw_core,
const char *file_name, const char *component,
struct devlink_flash_update_params *params,
struct netlink_ext_ack *extack)
{
const struct firmware *firmware;
int err;

if (component)
return -EOPNOTSUPP;

err = request_firmware_direct(&firmware, file_name, mlxsw_core->bus_info->dev);
err = request_firmware_direct(&firmware, params->file_name, mlxsw_core->bus_info->dev);
if (err)
return err;
err = mlxsw_core_fw_flash(mlxsw_core, firmware, extack);
Expand Down Expand Up @@ -1434,13 +1431,12 @@ mlxsw_devlink_core_bus_device_reload_up(struct devlink *devlink,
}

static int mlxsw_devlink_flash_update(struct devlink *devlink,
const char *file_name,
const char *component,
struct devlink_flash_update_params *params,
struct netlink_ext_ack *extack)
{
struct mlxsw_core *mlxsw_core = devlink_priv(devlink);

return mlxsw_core_fw_flash_update(mlxsw_core, file_name, component, extack);
return mlxsw_core_fw_flash_update(mlxsw_core, params, extack);
}

static int mlxsw_devlink_trap_init(struct devlink *devlink,
Expand Down
9 changes: 4 additions & 5 deletions drivers/net/ethernet/netronome/nfp/nfp_devlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,12 +329,11 @@ nfp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
}

static int
nfp_devlink_flash_update(struct devlink *devlink, const char *path,
const char *component, struct netlink_ext_ack *extack)
nfp_devlink_flash_update(struct devlink *devlink,
struct devlink_flash_update_params *params,
struct netlink_ext_ack *extack)
{
if (component)
return -EOPNOTSUPP;
return nfp_flash_update_common(devlink_priv(devlink), path, extack);
return nfp_flash_update_common(devlink_priv(devlink), params->file_name, extack);
}

const struct devlink_ops nfp_devlink_ops = {
Expand Down
8 changes: 2 additions & 6 deletions drivers/net/ethernet/pensando/ionic/ionic_devlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@
#include "ionic_devlink.h"

static int ionic_dl_flash_update(struct devlink *dl,
const char *fwname,
const char *component,
struct devlink_flash_update_params *params,
struct netlink_ext_ack *extack)
{
struct ionic *ionic = devlink_priv(dl);

if (component)
return -EOPNOTSUPP;

return ionic_firmware_update(ionic->lif, fwname, extack);
return ionic_firmware_update(ionic->lif, params->file_name, extack);
}

static int ionic_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
Expand Down
Loading

0 comments on commit cb9e4a7

Please sign in to comment.