Commit 4134c846 authored by David S. Miller's avatar David S. Miller

Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/nex

t-queue

Tony Nguyen says:

====================
100GbE Intel Wired LAN Driver Updates 2021-12-15

This series contains updates to ice driver only.

Jake makes changes to flash update. This includes the following:

 * a new shadow-ram region similar to NVM region but for the device shadow
   RAM contents. This is distinct from NVM region because shadow RAM is
   built up during device init and may be different from the raw NVM flash
   data.
 * refactoring of the ice_flash_pldm_image to become the main flash update
   entry point. This is simpler than having both an
   ice_devlink_flash_update and an ice_flash_pldm_image. It will make
   additions like dry-run easier in the future.
 * reducing time to read Option ROM version information.
 * adding support for firmware activation via devlink reload, when
   possible.

The major new work is the reload support, which allows activating firmware
immediately without a reboot when possible. Reload support only supports
firmware activation.

Jesse improves transmit code: utilizing newer netif_tx* API, adding some
prefetch calls, correcting expected conditions when calling ice_vsi_down(),
and utilizing __netdev_tx_sent_queue() call.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 823f7a54 9c99d099
...@@ -26,8 +26,10 @@ The ``ice`` driver reports the following versions ...@@ -26,8 +26,10 @@ The ``ice`` driver reports the following versions
* - ``fw.mgmt`` * - ``fw.mgmt``
- running - running
- 2.1.7 - 2.1.7
- 3-digit version number of the management firmware that controls the - 3-digit version number of the management firmware running on the
PHY, link, etc. Embedded Management Processor of the device. It controls the PHY,
link, access to device resources, etc. Intel documentation refers to
this as the EMP firmware.
* - ``fw.mgmt.api`` * - ``fw.mgmt.api``
- running - running
- 1.5.1 - 1.5.1
...@@ -119,6 +121,24 @@ preserving settings, and thus ``DEVLINK_FLASH_OVERWRITE_IDENTIFIERS`` on its ...@@ -119,6 +121,24 @@ preserving settings, and thus ``DEVLINK_FLASH_OVERWRITE_IDENTIFIERS`` on its
own will be rejected. If no overwrite mask is provided, the firmware will be own will be rejected. If no overwrite mask is provided, the firmware will be
instructed to preserve all settings and identifying fields when updating. instructed to preserve all settings and identifying fields when updating.
Reload
======
The ``ice`` driver supports activating new firmware after a flash update
using ``DEVLINK_CMD_RELOAD`` with the ``DEVLINK_RELOAD_ACTION_FW_ACTIVATE``
action.
.. code:: shell
$ devlink dev reload pci/0000:01:00.0 reload action fw_activate
The new firmware is activated by issuing a device specific Embedded
Management Processor reset which requests the device to reset and reload the
EMP firmware image.
The driver does not currently support reloading the driver via
``DEVLINK_RELOAD_ACTION_DRIVER_REINIT``.
Regions Regions
======= =======
......
...@@ -503,6 +503,7 @@ struct ice_pf { ...@@ -503,6 +503,7 @@ struct ice_pf {
struct pci_dev *pdev; struct pci_dev *pdev;
struct devlink_region *nvm_region; struct devlink_region *nvm_region;
struct devlink_region *sram_region;
struct devlink_region *devcaps_region; struct devlink_region *devcaps_region;
/* devlink port data */ /* devlink port data */
...@@ -552,6 +553,7 @@ struct ice_pf { ...@@ -552,6 +553,7 @@ struct ice_pf {
spinlock_t aq_wait_lock; spinlock_t aq_wait_lock;
struct hlist_head aq_wait_list; struct hlist_head aq_wait_list;
wait_queue_head_t aq_wait_queue; wait_queue_head_t aq_wait_queue;
bool fw_emp_reset_disabled;
wait_queue_head_t reset_wait_queue; wait_queue_head_t reset_wait_queue;
......
...@@ -117,6 +117,8 @@ struct ice_aqc_list_caps_elem { ...@@ -117,6 +117,8 @@ struct ice_aqc_list_caps_elem {
#define ICE_AQC_CAPS_NET_VER 0x004C #define ICE_AQC_CAPS_NET_VER 0x004C
#define ICE_AQC_CAPS_PENDING_NET_VER 0x004D #define ICE_AQC_CAPS_PENDING_NET_VER 0x004D
#define ICE_AQC_CAPS_RDMA 0x0051 #define ICE_AQC_CAPS_RDMA 0x0051
#define ICE_AQC_CAPS_PCIE_RESET_AVOIDANCE 0x0076
#define ICE_AQC_CAPS_POST_UPDATE_RESET_RESTRICT 0x0077
#define ICE_AQC_CAPS_NVM_MGMT 0x0080 #define ICE_AQC_CAPS_NVM_MGMT 0x0080
u8 major_ver; u8 major_ver;
...@@ -1408,6 +1410,11 @@ struct ice_aqc_nvm { ...@@ -1408,6 +1410,11 @@ struct ice_aqc_nvm {
#define ICE_AQC_NVM_REVERT_LAST_ACTIV BIT(6) /* Write Activate only */ #define ICE_AQC_NVM_REVERT_LAST_ACTIV BIT(6) /* Write Activate only */
#define ICE_AQC_NVM_ACTIV_SEL_MASK ICE_M(0x7, 3) #define ICE_AQC_NVM_ACTIV_SEL_MASK ICE_M(0x7, 3)
#define ICE_AQC_NVM_FLASH_ONLY BIT(7) #define ICE_AQC_NVM_FLASH_ONLY BIT(7)
#define ICE_AQC_NVM_RESET_LVL_M ICE_M(0x3, 0) /* Write reply only */
#define ICE_AQC_NVM_POR_FLAG 0
#define ICE_AQC_NVM_PERST_FLAG 1
#define ICE_AQC_NVM_EMPR_FLAG 2
#define ICE_AQC_NVM_EMPR_ENA BIT(0) /* Write Activate reply only */
__le16 module_typeid; __le16 module_typeid;
__le16 length; __le16 length;
#define ICE_AQC_NVM_ERASE_LEN 0xFFFF #define ICE_AQC_NVM_ERASE_LEN 0xFFFF
......
...@@ -2068,6 +2068,18 @@ ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps, ...@@ -2068,6 +2068,18 @@ ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps,
ice_debug(hw, ICE_DBG_INIT, "%s: max_mtu = %d\n", ice_debug(hw, ICE_DBG_INIT, "%s: max_mtu = %d\n",
prefix, caps->max_mtu); prefix, caps->max_mtu);
break; break;
case ICE_AQC_CAPS_PCIE_RESET_AVOIDANCE:
caps->pcie_reset_avoidance = (number > 0);
ice_debug(hw, ICE_DBG_INIT,
"%s: pcie_reset_avoidance = %d\n", prefix,
caps->pcie_reset_avoidance);
break;
case ICE_AQC_CAPS_POST_UPDATE_RESET_RESTRICT:
caps->reset_restrict_support = (number == 1);
ice_debug(hw, ICE_DBG_INIT,
"%s: reset_restrict_support = %d\n", prefix,
caps->reset_restrict_support);
break;
default: default:
/* Not one of the recognized common capabilities */ /* Not one of the recognized common capabilities */
found = false; found = false;
......
...@@ -371,57 +371,105 @@ static int ice_devlink_info_get(struct devlink *devlink, ...@@ -371,57 +371,105 @@ static int ice_devlink_info_get(struct devlink *devlink,
} }
/** /**
* ice_devlink_flash_update - Update firmware stored in flash on the device * ice_devlink_reload_empr_start - Start EMP reset to activate new firmware
* @devlink: pointer to devlink associated with device to update * @devlink: pointer to the devlink instance to reload
* @params: flash update parameters * @netns_change: if true, the network namespace is changing
* @action: the action to perform. Must be DEVLINK_RELOAD_ACTION_FW_ACTIVATE
* @limit: limits on what reload should do, such as not resetting
* @extack: netlink extended ACK structure * @extack: netlink extended ACK structure
* *
* Perform a device flash update. The bulk of the update logic is contained * Allow user to activate new Embedded Management Processor firmware by
* within the ice_flash_pldm_image function. * issuing device specific EMP reset. Called in response to
* a DEVLINK_CMD_RELOAD with the DEVLINK_RELOAD_ACTION_FW_ACTIVATE.
* *
* Returns: zero on success, or an error code on failure. * Note that teardown and rebuild of the driver state happens automatically as
* part of an interrupt and watchdog task. This is because all physical
* functions on the device must be able to reset when an EMP reset occurs from
* any source.
*/ */
static int static int
ice_devlink_flash_update(struct devlink *devlink, ice_devlink_reload_empr_start(struct devlink *devlink, bool netns_change,
struct devlink_flash_update_params *params, enum devlink_reload_action action,
struct netlink_ext_ack *extack) enum devlink_reload_limit limit,
struct netlink_ext_ack *extack)
{ {
struct ice_pf *pf = devlink_priv(devlink); struct ice_pf *pf = devlink_priv(devlink);
struct device *dev = ice_pf_to_dev(pf);
struct ice_hw *hw = &pf->hw; struct ice_hw *hw = &pf->hw;
u8 preservation; u8 pending;
int err; int err;
if (!params->overwrite_mask) { err = ice_get_pending_updates(pf, &pending, extack);
/* preserve all settings and identifiers */ if (err)
preservation = ICE_AQC_NVM_PRESERVE_ALL; return err;
} else if (params->overwrite_mask == DEVLINK_FLASH_OVERWRITE_SETTINGS) {
/* overwrite settings, but preserve the vital device identifiers */ /* pending is a bitmask of which flash banks have a pending update,
preservation = ICE_AQC_NVM_PRESERVE_SELECTED; * including the main NVM bank, the Option ROM bank, and the netlist
} else if (params->overwrite_mask == (DEVLINK_FLASH_OVERWRITE_SETTINGS | * bank. If any of these bits are set, then there is a pending update
DEVLINK_FLASH_OVERWRITE_IDENTIFIERS)) { * waiting to be activated.
/* overwrite both settings and identifiers, preserve nothing */ */
preservation = ICE_AQC_NVM_NO_PRESERVATION; if (!pending) {
} else { NL_SET_ERR_MSG_MOD(extack, "No pending firmware update");
NL_SET_ERR_MSG_MOD(extack, "Requested overwrite mask is not supported"); return -ECANCELED;
return -EOPNOTSUPP;
} }
if (!hw->dev_caps.common_cap.nvm_unified_update) { if (pf->fw_emp_reset_disabled) {
NL_SET_ERR_MSG_MOD(extack, "Current firmware does not support unified update"); NL_SET_ERR_MSG_MOD(extack, "EMP reset is not available. To activate firmware, a reboot or power cycle is needed");
return -EOPNOTSUPP; return -ECANCELED;
} }
err = ice_check_for_pending_update(pf, NULL, extack); dev_dbg(dev, "Issuing device EMP reset to activate firmware\n");
if (err)
err = ice_aq_nvm_update_empr(hw);
if (err) {
dev_err(dev, "Failed to trigger EMP device reset to reload firmware, err %d aq_err %s\n",
err, ice_aq_str(hw->adminq.sq_last_status));
NL_SET_ERR_MSG_MOD(extack, "Failed to trigger EMP device reset to reload firmware");
return err; return err;
}
devlink_flash_update_status_notify(devlink, "Preparing to flash", NULL, 0, 0); return 0;
}
return ice_flash_pldm_image(pf, params->fw, preservation, extack); /**
* ice_devlink_reload_empr_finish - Wait for EMP reset to finish
* @devlink: pointer to the devlink instance reloading
* @action: the action requested
* @limit: limits imposed by userspace, such as not resetting
* @actions_performed: on return, indicate what actions actually performed
* @extack: netlink extended ACK structure
*
* Wait for driver to finish rebuilding after EMP reset is completed. This
* includes time to wait for both the actual device reset as well as the time
* for the driver's rebuild to complete.
*/
static int
ice_devlink_reload_empr_finish(struct devlink *devlink,
enum devlink_reload_action action,
enum devlink_reload_limit limit,
u32 *actions_performed,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
int err;
*actions_performed = BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE);
err = ice_wait_for_reset(pf, 60 * HZ);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Device still resetting after 1 minute");
return err;
}
return 0;
} }
static const struct devlink_ops ice_devlink_ops = { static const struct devlink_ops ice_devlink_ops = {
.supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK, .supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK,
.reload_actions = BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE),
/* The ice driver currently does not support driver reinit */
.reload_down = ice_devlink_reload_empr_start,
.reload_up = ice_devlink_reload_empr_finish,
.eswitch_mode_get = ice_eswitch_mode_get, .eswitch_mode_get = ice_eswitch_mode_get,
.eswitch_mode_set = ice_eswitch_mode_set, .eswitch_mode_set = ice_eswitch_mode_set,
.info_get = ice_devlink_info_get, .info_get = ice_devlink_info_get,
...@@ -582,6 +630,7 @@ void ice_devlink_register(struct ice_pf *pf) ...@@ -582,6 +630,7 @@ void ice_devlink_register(struct ice_pf *pf)
{ {
struct devlink *devlink = priv_to_devlink(pf); struct devlink *devlink = priv_to_devlink(pf);
devlink_set_features(devlink, DEVLINK_F_RELOAD);
devlink_register(devlink); devlink_register(devlink);
} }
...@@ -739,16 +788,20 @@ void ice_devlink_destroy_vf_port(struct ice_vf *vf) ...@@ -739,16 +788,20 @@ void ice_devlink_destroy_vf_port(struct ice_vf *vf)
} }
/** /**
* ice_devlink_nvm_snapshot - Capture a snapshot of the Shadow RAM contents * ice_devlink_nvm_snapshot - Capture a snapshot of the NVM flash contents
* @devlink: the devlink instance * @devlink: the devlink instance
* @ops: the devlink region being snapshotted * @ops: the devlink region being snapshotted
* @extack: extended ACK response structure * @extack: extended ACK response structure
* @data: on exit points to snapshot data buffer * @data: on exit points to snapshot data buffer
* *
* This function is called in response to the DEVLINK_CMD_REGION_TRIGGER for * This function is called in response to the DEVLINK_CMD_REGION_TRIGGER for
* the shadow-ram devlink region. It captures a snapshot of the shadow ram * the nvm-flash devlink region. It captures a snapshot of the full NVM flash
* contents. This snapshot can later be viewed via the devlink-region * contents, including both banks of flash. This snapshot can later be viewed
* interface. * via the devlink-region interface.
*
* It captures the flash using the FLASH_ONLY bit set when reading via
* firmware, so it does not read the current Shadow RAM contents. For that,
* use the shadow-ram region.
* *
* @returns zero on success, and updates the data pointer. Returns a non-zero * @returns zero on success, and updates the data pointer. Returns a non-zero
* error code on failure. * error code on failure.
...@@ -795,6 +848,66 @@ static int ice_devlink_nvm_snapshot(struct devlink *devlink, ...@@ -795,6 +848,66 @@ static int ice_devlink_nvm_snapshot(struct devlink *devlink,
return 0; return 0;
} }
/**
* ice_devlink_sram_snapshot - Capture a snapshot of the Shadow RAM contents
* @devlink: the devlink instance
* @ops: the devlink region being snapshotted
* @extack: extended ACK response structure
* @data: on exit points to snapshot data buffer
*
* This function is called in response to the DEVLINK_CMD_REGION_TRIGGER for
* the shadow-ram devlink region. It captures a snapshot of the shadow ram
* contents. This snapshot can later be viewed via the devlink-region
* interface.
*
* @returns zero on success, and updates the data pointer. Returns a non-zero
* error code on failure.
*/
static int
ice_devlink_sram_snapshot(struct devlink *devlink,
const struct devlink_region_ops __always_unused *ops,
struct netlink_ext_ack *extack, u8 **data)
{
struct ice_pf *pf = devlink_priv(devlink);
struct device *dev = ice_pf_to_dev(pf);
struct ice_hw *hw = &pf->hw;
u8 *sram_data;
u32 sram_size;
int err;
sram_size = hw->flash.sr_words * 2u;
sram_data = vzalloc(sram_size);
if (!sram_data)
return -ENOMEM;
err = ice_acquire_nvm(hw, ICE_RES_READ);
if (err) {
dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
err, hw->adminq.sq_last_status);
NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
vfree(sram_data);
return err;
}
/* Read from the Shadow RAM, rather than directly from NVM */
err = ice_read_flat_nvm(hw, 0, &sram_size, sram_data, true);
if (err) {
dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n",
sram_size, err, hw->adminq.sq_last_status);
NL_SET_ERR_MSG_MOD(extack,
"Failed to read Shadow RAM contents");
ice_release_nvm(hw);
vfree(sram_data);
return err;
}
ice_release_nvm(hw);
*data = sram_data;
return 0;
}
/** /**
* ice_devlink_devcaps_snapshot - Capture snapshot of device capabilities * ice_devlink_devcaps_snapshot - Capture snapshot of device capabilities
* @devlink: the devlink instance * @devlink: the devlink instance
...@@ -845,6 +958,12 @@ static const struct devlink_region_ops ice_nvm_region_ops = { ...@@ -845,6 +958,12 @@ static const struct devlink_region_ops ice_nvm_region_ops = {
.snapshot = ice_devlink_nvm_snapshot, .snapshot = ice_devlink_nvm_snapshot,
}; };
static const struct devlink_region_ops ice_sram_region_ops = {
.name = "shadow-ram",
.destructor = vfree,
.snapshot = ice_devlink_sram_snapshot,
};
static const struct devlink_region_ops ice_devcaps_region_ops = { static const struct devlink_region_ops ice_devcaps_region_ops = {
.name = "device-caps", .name = "device-caps",
.destructor = vfree, .destructor = vfree,
...@@ -862,7 +981,7 @@ void ice_devlink_init_regions(struct ice_pf *pf) ...@@ -862,7 +981,7 @@ void ice_devlink_init_regions(struct ice_pf *pf)
{ {
struct devlink *devlink = priv_to_devlink(pf); struct devlink *devlink = priv_to_devlink(pf);
struct device *dev = ice_pf_to_dev(pf); struct device *dev = ice_pf_to_dev(pf);
u64 nvm_size; u64 nvm_size, sram_size;
nvm_size = pf->hw.flash.flash_size; nvm_size = pf->hw.flash.flash_size;
pf->nvm_region = devlink_region_create(devlink, &ice_nvm_region_ops, 1, pf->nvm_region = devlink_region_create(devlink, &ice_nvm_region_ops, 1,
...@@ -873,6 +992,15 @@ void ice_devlink_init_regions(struct ice_pf *pf) ...@@ -873,6 +992,15 @@ void ice_devlink_init_regions(struct ice_pf *pf)
pf->nvm_region = NULL; pf->nvm_region = NULL;
} }
sram_size = pf->hw.flash.sr_words * 2u;
pf->sram_region = devlink_region_create(devlink, &ice_sram_region_ops,
1, sram_size);
if (IS_ERR(pf->sram_region)) {
dev_err(dev, "failed to create shadow-ram devlink region, err %ld\n",
PTR_ERR(pf->sram_region));
pf->sram_region = NULL;
}
pf->devcaps_region = devlink_region_create(devlink, pf->devcaps_region = devlink_region_create(devlink,
&ice_devcaps_region_ops, 10, &ice_devcaps_region_ops, 10,
ICE_AQ_MAX_BUF_LEN); ICE_AQ_MAX_BUF_LEN);
...@@ -893,6 +1021,10 @@ void ice_devlink_destroy_regions(struct ice_pf *pf) ...@@ -893,6 +1021,10 @@ void ice_devlink_destroy_regions(struct ice_pf *pf)
{ {
if (pf->nvm_region) if (pf->nvm_region)
devlink_region_destroy(pf->nvm_region); devlink_region_destroy(pf->nvm_region);
if (pf->sram_region)
devlink_region_destroy(pf->sram_region);
if (pf->devcaps_region) if (pf->devcaps_region)
devlink_region_destroy(pf->devcaps_region); devlink_region_destroy(pf->devcaps_region);
} }
...@@ -1280,8 +1280,10 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) ...@@ -1280,8 +1280,10 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags)
} }
if (test_bit(ICE_FLAG_LEGACY_RX, change_flags)) { if (test_bit(ICE_FLAG_LEGACY_RX, change_flags)) {
/* down and up VSI so that changes of Rx cfg are reflected. */ /* down and up VSI so that changes of Rx cfg are reflected. */
ice_down(vsi); if (!test_and_set_bit(ICE_VSI_DOWN, vsi->state)) {
ice_up(vsi); ice_down(vsi);
ice_up(vsi);
}
} }
/* don't allow modification of this flag when a single VF is in /* don't allow modification of this flag when a single VF is in
* promiscuous mode because it's not supported * promiscuous mode because it's not supported
......
...@@ -16,6 +16,18 @@ struct ice_fwu_priv { ...@@ -16,6 +16,18 @@ struct ice_fwu_priv {
/* Track which NVM banks to activate at the end of the update */ /* Track which NVM banks to activate at the end of the update */
u8 activate_flags; u8 activate_flags;
/* Track the firmware response of the required reset to complete the
* flash update.
*
* 0 - ICE_AQC_NVM_POR_FLAG - A full power on is required
* 1 - ICE_AQC_NVM_PERST_FLAG - A cold PCIe reset is required
* 2 - ICE_AQC_NVM_EMPR_FLAG - An EMP reset is required
*/
u8 reset_level;
/* Track if EMP reset is available */
u8 emp_reset_available;
}; };
/** /**
...@@ -257,6 +269,7 @@ ice_send_component_table(struct pldmfw *context, struct pldmfw_component *compon ...@@ -257,6 +269,7 @@ ice_send_component_table(struct pldmfw *context, struct pldmfw_component *compon
* @block_size: size of the block to write, up to 4k * @block_size: size of the block to write, up to 4k
* @block: pointer to block of data to write * @block: pointer to block of data to write
* @last_cmd: whether this is the last command * @last_cmd: whether this is the last command
* @reset_level: storage for reset level required
* @extack: netlink extended ACK structure * @extack: netlink extended ACK structure
* *
* Write a block of data to a flash module, and await for the completion * Write a block of data to a flash module, and await for the completion
...@@ -264,12 +277,19 @@ ice_send_component_table(struct pldmfw *context, struct pldmfw_component *compon ...@@ -264,12 +277,19 @@ ice_send_component_table(struct pldmfw *context, struct pldmfw_component *compon
* *
* Note this function assumes the caller has acquired the NVM resource. * Note this function assumes the caller has acquired the NVM resource.
* *
* On successful return, reset level indicates the device reset required to
* complete the update.
*
* 0 - ICE_AQC_NVM_POR_FLAG - A full power on is required
* 1 - ICE_AQC_NVM_PERST_FLAG - A cold PCIe reset is required
* 2 - ICE_AQC_NVM_EMPR_FLAG - An EMP reset is required
*
* Returns: zero on success, or a negative error code on failure. * Returns: zero on success, or a negative error code on failure.
*/ */
static int static int
ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset, ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
u16 block_size, u8 *block, bool last_cmd, u16 block_size, u8 *block, bool last_cmd,
struct netlink_ext_ack *extack) u8 *reset_level, struct netlink_ext_ack *extack)
{ {
u16 completion_module, completion_retval; u16 completion_module, completion_retval;
struct device *dev = ice_pf_to_dev(pf); struct device *dev = ice_pf_to_dev(pf);
...@@ -335,6 +355,24 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset, ...@@ -335,6 +355,24 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
return -EIO; return -EIO;
} }
/* For the last command to write the NVM bank, newer versions of
* firmware indicate the required level of reset to complete
* activation of firmware. If the firmware supports this, cache the
* response for indicating to the user later. Otherwise, assume that
* a full power cycle is required.
*/
if (reset_level && last_cmd && module == ICE_SR_1ST_NVM_BANK_PTR) {
if (hw->dev_caps.common_cap.pcie_reset_avoidance) {
*reset_level = (event.desc.params.nvm.cmd_flags &
ICE_AQC_NVM_RESET_LVL_M);
dev_dbg(dev, "Firmware reported required reset level as %u\n",
*reset_level);
} else {
*reset_level = ICE_AQC_NVM_POR_FLAG;
dev_dbg(dev, "Firmware doesn't support indicating required reset level. Assuming a power cycle is required\n");
}
}
return 0; return 0;
} }
...@@ -345,6 +383,7 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset, ...@@ -345,6 +383,7 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
* @component: the name of the component being updated * @component: the name of the component being updated
* @image: buffer of image data to write to the NVM * @image: buffer of image data to write to the NVM
* @length: length of the buffer * @length: length of the buffer
* @reset_level: storage for reset level required
* @extack: netlink extended ACK structure * @extack: netlink extended ACK structure
* *
* Loop over the data for a given NVM module and program it in 4 Kb * Loop over the data for a given NVM module and program it in 4 Kb
...@@ -357,7 +396,7 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset, ...@@ -357,7 +396,7 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
*/ */
static int static int
ice_write_nvm_module(struct ice_pf *pf, u16 module, const char *component, ice_write_nvm_module(struct ice_pf *pf, u16 module, const char *component,
const u8 *image, u32 length, const u8 *image, u32 length, u8 *reset_level,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct device *dev = ice_pf_to_dev(pf); struct device *dev = ice_pf_to_dev(pf);
...@@ -391,7 +430,8 @@ ice_write_nvm_module(struct ice_pf *pf, u16 module, const char *component, ...@@ -391,7 +430,8 @@ ice_write_nvm_module(struct ice_pf *pf, u16 module, const char *component,
memcpy(block, image + offset, block_size); memcpy(block, image + offset, block_size);
err = ice_write_one_nvm_block(pf, module, offset, block_size, err = ice_write_one_nvm_block(pf, module, offset, block_size,
block, last_cmd, extack); block, last_cmd, reset_level,
extack);
if (err) if (err)
break; break;
...@@ -507,6 +547,7 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component, ...@@ -507,6 +547,7 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component,
* ice_switch_flash_banks - Tell firmware to switch NVM banks * ice_switch_flash_banks - Tell firmware to switch NVM banks
* @pf: Pointer to the PF data structure * @pf: Pointer to the PF data structure
* @activate_flags: flags used for the activation command * @activate_flags: flags used for the activation command
* @emp_reset_available: on return, indicates if EMP reset is available
* @extack: netlink extended ACK structure * @extack: netlink extended ACK structure
* *
* Notify firmware to activate the newly written flash banks, and wait for the * Notify firmware to activate the newly written flash banks, and wait for the
...@@ -514,18 +555,20 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component, ...@@ -514,18 +555,20 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component,
* *
* Returns: zero on success or an error code on failure. * Returns: zero on success or an error code on failure.
*/ */
static int ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags, static int
struct netlink_ext_ack *extack) ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags,
u8 *emp_reset_available, struct netlink_ext_ack *extack)
{ {
struct device *dev = ice_pf_to_dev(pf); struct device *dev = ice_pf_to_dev(pf);
struct ice_rq_event_info event; struct ice_rq_event_info event;
struct ice_hw *hw = &pf->hw; struct ice_hw *hw = &pf->hw;
u16 completion_retval; u16 completion_retval;
u8 response_flags;
int err; int err;
memset(&event, 0, sizeof(event)); memset(&event, 0, sizeof(event));
err = ice_nvm_write_activate(hw, activate_flags); err = ice_nvm_write_activate(hw, activate_flags, &response_flags);
if (err) { if (err) {
dev_err(dev, "Failed to switch active flash banks, err %d aq_err %s\n", dev_err(dev, "Failed to switch active flash banks, err %d aq_err %s\n",
err, ice_aq_str(hw->adminq.sq_last_status)); err, ice_aq_str(hw->adminq.sq_last_status));
...@@ -533,6 +576,22 @@ static int ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags, ...@@ -533,6 +576,22 @@ static int ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags,
return -EIO; return -EIO;
} }
/* Newer versions of firmware have support to indicate whether an EMP
* reset to reload firmware is available. For older firmware, EMP
* reset is always available.
*/
if (emp_reset_available) {
if (hw->dev_caps.common_cap.reset_restrict_support) {
*emp_reset_available = response_flags & ICE_AQC_NVM_EMPR_ENA;
dev_dbg(dev, "Firmware indicated that EMP reset is %s\n",
*emp_reset_available ?
"available" : "not available");
} else {
*emp_reset_available = ICE_AQC_NVM_EMPR_ENA;
dev_dbg(dev, "Firmware does not support restricting EMP reset availability\n");
}
}
err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_write_activate, 30 * HZ, err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_write_activate, 30 * HZ,
&event); &event);
if (err) { if (err) {
...@@ -573,6 +632,7 @@ ice_flash_component(struct pldmfw *context, struct pldmfw_component *component) ...@@ -573,6 +632,7 @@ ice_flash_component(struct pldmfw *context, struct pldmfw_component *component)
struct netlink_ext_ack *extack = priv->extack; struct netlink_ext_ack *extack = priv->extack;
struct ice_pf *pf = priv->pf; struct ice_pf *pf = priv->pf;
const char *name; const char *name;
u8 *reset_level;
u16 module; u16 module;
u8 flag; u8 flag;
int err; int err;
...@@ -581,16 +641,19 @@ ice_flash_component(struct pldmfw *context, struct pldmfw_component *component) ...@@ -581,16 +641,19 @@ ice_flash_component(struct pldmfw *context, struct pldmfw_component *component)
case NVM_COMP_ID_OROM: case NVM_COMP_ID_OROM:
module = ICE_SR_1ST_OROM_BANK_PTR; module = ICE_SR_1ST_OROM_BANK_PTR;
flag = ICE_AQC_NVM_ACTIV_SEL_OROM; flag = ICE_AQC_NVM_ACTIV_SEL_OROM;
reset_level = NULL;
name = "fw.undi"; name = "fw.undi";
break; break;
case NVM_COMP_ID_NVM: case NVM_COMP_ID_NVM:
module = ICE_SR_1ST_NVM_BANK_PTR; module = ICE_SR_1ST_NVM_BANK_PTR;
flag = ICE_AQC_NVM_ACTIV_SEL_NVM; flag = ICE_AQC_NVM_ACTIV_SEL_NVM;
reset_level = &priv->reset_level;
name = "fw.mgmt"; name = "fw.mgmt";
break; break;
case NVM_COMP_ID_NETLIST: case NVM_COMP_ID_NETLIST:
module = ICE_SR_NETLIST_BANK_PTR; module = ICE_SR_NETLIST_BANK_PTR;
flag = ICE_AQC_NVM_ACTIV_SEL_NETLIST; flag = ICE_AQC_NVM_ACTIV_SEL_NETLIST;
reset_level = NULL;
name = "fw.netlist"; name = "fw.netlist";
break; break;
default: default:
...@@ -610,7 +673,8 @@ ice_flash_component(struct pldmfw *context, struct pldmfw_component *component) ...@@ -610,7 +673,8 @@ ice_flash_component(struct pldmfw *context, struct pldmfw_component *component)
return err; return err;
return ice_write_nvm_module(pf, module, name, component->component_data, return ice_write_nvm_module(pf, module, name, component->component_data,
component->component_size, extack); component->component_size, reset_level,
extack);
} }
/** /**
...@@ -628,107 +692,75 @@ static int ice_finalize_update(struct pldmfw *context) ...@@ -628,107 +692,75 @@ static int ice_finalize_update(struct pldmfw *context)
struct ice_fwu_priv *priv = container_of(context, struct ice_fwu_priv, context); struct ice_fwu_priv *priv = container_of(context, struct ice_fwu_priv, context);
struct netlink_ext_ack *extack = priv->extack; struct netlink_ext_ack *extack = priv->extack;
struct ice_pf *pf = priv->pf; struct ice_pf *pf = priv->pf;
struct devlink *devlink;
int err;
/* Finally, notify firmware to activate the written NVM banks */ /* Finally, notify firmware to activate the written NVM banks */
return ice_switch_flash_banks(pf, priv->activate_flags, extack); err = ice_switch_flash_banks(pf, priv->activate_flags,
} &priv->emp_reset_available, extack);
if (err)
return err;
static const struct pldmfw_ops ice_fwu_ops = { devlink = priv_to_devlink(pf);
.match_record = &pldmfw_op_pci_match_record,
.send_package_data = &ice_send_package_data,
.send_component_table = &ice_send_component_table,
.flash_component = &ice_flash_component,
.finalize_update = &ice_finalize_update,
};
/** /* If the required reset is EMPR, but EMPR is disabled, report that
* ice_flash_pldm_image - Write a PLDM-formatted firmware image to the device * a reboot is required instead.
* @pf: private device driver structure */
* @fw: firmware object pointing to the relevant firmware file if (priv->reset_level == ICE_AQC_NVM_EMPR_FLAG &&
* @preservation: preservation level to request from firmware !priv->emp_reset_available) {
* @extack: netlink extended ACK structure dev_dbg(ice_pf_to_dev(pf), "Firmware indicated EMP reset as sufficient, but EMP reset is disabled\n");
* priv->reset_level = ICE_AQC_NVM_PERST_FLAG;
* Parse the data for a given firmware file, verifying that it is a valid PLDM }
* formatted image that matches this device.
*
* Extract the device record Package Data and Component Tables and send them
* to the firmware. Extract and write the flash data for each of the three
* main flash components, "fw.mgmt", "fw.undi", and "fw.netlist". Notify
* firmware once the data is written to the inactive banks.
*
* Returns: zero on success or a negative error code on failure.
*/
int ice_flash_pldm_image(struct ice_pf *pf, const struct firmware *fw,
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;
int err;
switch (preservation) { switch (priv->reset_level) {
case ICE_AQC_NVM_PRESERVE_ALL: case ICE_AQC_NVM_EMPR_FLAG:
case ICE_AQC_NVM_PRESERVE_SELECTED: devlink_flash_update_status_notify(devlink,
case ICE_AQC_NVM_NO_PRESERVATION: "Activate new firmware by devlink reload",
case ICE_AQC_NVM_FACTORY_DEFAULT: NULL, 0, 0);
break;
case ICE_AQC_NVM_PERST_FLAG:
devlink_flash_update_status_notify(devlink,
"Activate new firmware by rebooting the system",
NULL, 0, 0);
break; break;
case ICE_AQC_NVM_POR_FLAG:
default: default:
WARN(1, "Unexpected preservation level request %u", preservation); devlink_flash_update_status_notify(devlink,
return -EINVAL; "Activate new firmware by power cycling the system",
} NULL, 0, 0);
break;
memset(&priv, 0, sizeof(priv));
priv.context.ops = &ice_fwu_ops;
priv.context.dev = dev;
priv.extack = extack;
priv.pf = pf;
priv.activate_flags = preservation;
err = ice_acquire_nvm(hw, ICE_RES_WRITE);
if (err) {
dev_err(dev, "Failed to acquire device flash lock, err %d aq_err %s\n",
err, ice_aq_str(hw->adminq.sq_last_status));
NL_SET_ERR_MSG_MOD(extack, "Failed to acquire device flash lock");
return err;
}
err = pldmfw_flash_image(&priv.context, fw);
if (err == -ENOENT) {
dev_err(dev, "Firmware image has no record matching this device\n");
NL_SET_ERR_MSG_MOD(extack, "Firmware image has no record matching this device");
} else if (err) {
/* Do not set a generic extended ACK message here. A more
* specific message may already have been set by one of our
* ops.
*/
dev_err(dev, "Failed to flash PLDM image, err %d", err);
} }
ice_release_nvm(hw); pf->fw_emp_reset_disabled = !priv->emp_reset_available;
return err; return 0;
} }
static const struct pldmfw_ops ice_fwu_ops = {
.match_record = &pldmfw_op_pci_match_record,
.send_package_data = &ice_send_package_data,
.send_component_table = &ice_send_component_table,
.flash_component = &ice_flash_component,
.finalize_update = &ice_finalize_update,
};
/** /**
* ice_check_for_pending_update - Check for a pending flash update * ice_get_pending_updates - Check if the component has a pending update
* @pf: the PF driver structure * @pf: the PF driver structure
* @component: if not NULL, the name of the component being updated * @pending: on return, bitmap of updates pending
* @extack: Netlink extended ACK structure * @extack: Netlink extended ACK
* *
* Check whether the device already has a pending flash update. If such an * Check if the device has any pending updates on any flash components.
* update is found, cancel it so that the requested update may proceed.
* *
* Returns: zero on success, or a negative error code on failure. * Returns: zero on success, or a negative error code on failure. Updates
* pending with the bitmap of pending updates.
*/ */
int ice_check_for_pending_update(struct ice_pf *pf, const char *component, int ice_get_pending_updates(struct ice_pf *pf, u8 *pending,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct devlink *devlink = priv_to_devlink(pf);
struct device *dev = ice_pf_to_dev(pf); struct device *dev = ice_pf_to_dev(pf);
struct ice_hw_dev_caps *dev_caps; struct ice_hw_dev_caps *dev_caps;
struct ice_hw *hw = &pf->hw; struct ice_hw *hw = &pf->hw;
u8 pending = 0;
int err; int err;
dev_caps = kzalloc(sizeof(*dev_caps), GFP_KERNEL); dev_caps = kzalloc(sizeof(*dev_caps), GFP_KERNEL);
...@@ -747,23 +779,53 @@ int ice_check_for_pending_update(struct ice_pf *pf, const char *component, ...@@ -747,23 +779,53 @@ int ice_check_for_pending_update(struct ice_pf *pf, const char *component,
return err; return err;
} }
*pending = 0;
if (dev_caps->common_cap.nvm_update_pending_nvm) { if (dev_caps->common_cap.nvm_update_pending_nvm) {
dev_info(dev, "The fw.mgmt flash component has a pending update\n"); dev_info(dev, "The fw.mgmt flash component has a pending update\n");
pending |= ICE_AQC_NVM_ACTIV_SEL_NVM; *pending |= ICE_AQC_NVM_ACTIV_SEL_NVM;
} }
if (dev_caps->common_cap.nvm_update_pending_orom) { if (dev_caps->common_cap.nvm_update_pending_orom) {
dev_info(dev, "The fw.undi flash component has a pending update\n"); dev_info(dev, "The fw.undi flash component has a pending update\n");
pending |= ICE_AQC_NVM_ACTIV_SEL_OROM; *pending |= ICE_AQC_NVM_ACTIV_SEL_OROM;
} }
if (dev_caps->common_cap.nvm_update_pending_netlist) { if (dev_caps->common_cap.nvm_update_pending_netlist) {
dev_info(dev, "The fw.netlist flash component has a pending update\n"); dev_info(dev, "The fw.netlist flash component has a pending update\n");
pending |= ICE_AQC_NVM_ACTIV_SEL_NETLIST; *pending |= ICE_AQC_NVM_ACTIV_SEL_NETLIST;
} }
kfree(dev_caps); kfree(dev_caps);
return 0;
}
/**
* ice_cancel_pending_update - Cancel any pending update for a component
* @pf: the PF driver structure
* @component: if not NULL, the name of the component being updated
* @extack: Netlink extended ACK structure
*
* Cancel any pending update for the specified component. If component is
* NULL, all device updates will be canceled.
*
* Returns: zero on success, or a negative error code on failure.
*/
static int
ice_cancel_pending_update(struct ice_pf *pf, const char *component,
struct netlink_ext_ack *extack)
{
struct devlink *devlink = priv_to_devlink(pf);
struct device *dev = ice_pf_to_dev(pf);
struct ice_hw *hw = &pf->hw;
u8 pending;
int err;
err = ice_get_pending_updates(pf, &pending, extack);
if (err)
return err;
/* If the flash_update request is for a specific component, ignore all /* If the flash_update request is for a specific component, ignore all
* of the other components. * of the other components.
*/ */
...@@ -798,7 +860,98 @@ int ice_check_for_pending_update(struct ice_pf *pf, const char *component, ...@@ -798,7 +860,98 @@ int ice_check_for_pending_update(struct ice_pf *pf, const char *component,
} }
pending |= ICE_AQC_NVM_REVERT_LAST_ACTIV; pending |= ICE_AQC_NVM_REVERT_LAST_ACTIV;
err = ice_switch_flash_banks(pf, pending, extack); err = ice_switch_flash_banks(pf, pending, NULL, extack);
ice_release_nvm(hw);
/* Since we've canceled the pending update, we no longer know if EMP
* reset is restricted.
*/
pf->fw_emp_reset_disabled = false;
return err;
}
/**
* ice_devlink_flash_update - Write a firmware image to the device
* @devlink: pointer to devlink associated with the device to update
* @params: devlink flash update parameters
* @extack: netlink extended ACK structure
*
* Parse the data for a given firmware file, verifying that it is a valid PLDM
* formatted image that matches this device.
*
* Extract the device record Package Data and Component Tables and send them
* to the firmware. Extract and write the flash data for each of the three
* main flash components, "fw.mgmt", "fw.undi", and "fw.netlist". Notify
* firmware once the data is written to the inactive banks.
*
* Returns: zero on success or a negative error code on failure.
*/
int 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 = ice_pf_to_dev(pf);
struct ice_hw *hw = &pf->hw;
struct ice_fwu_priv priv;
u8 preservation;
int err;
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;
}
memset(&priv, 0, sizeof(priv));
priv.context.ops = &ice_fwu_ops;
priv.context.dev = dev;
priv.extack = extack;
priv.pf = pf;
priv.activate_flags = preservation;
devlink_flash_update_status_notify(devlink, "Preparing to flash", NULL, 0, 0);
err = ice_cancel_pending_update(pf, NULL, extack);
if (err)
return err;
err = ice_acquire_nvm(hw, ICE_RES_WRITE);
if (err) {
dev_err(dev, "Failed to acquire device flash lock, err %d aq_err %s\n",
err, ice_aq_str(hw->adminq.sq_last_status));
NL_SET_ERR_MSG_MOD(extack, "Failed to acquire device flash lock");
return err;
}
err = pldmfw_flash_image(&priv.context, params->fw);
if (err == -ENOENT) {
dev_err(dev, "Firmware image has no record matching this device\n");
NL_SET_ERR_MSG_MOD(extack, "Firmware image has no record matching this device");
} else if (err) {
/* Do not set a generic extended ACK message here. A more
* specific message may already have been set by one of our
* ops.
*/
dev_err(dev, "Failed to flash PLDM image, err %d", err);
}
ice_release_nvm(hw); ice_release_nvm(hw);
......
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
#ifndef _ICE_FW_UPDATE_H_ #ifndef _ICE_FW_UPDATE_H_
#define _ICE_FW_UPDATE_H_ #define _ICE_FW_UPDATE_H_
int ice_flash_pldm_image(struct ice_pf *pf, const struct firmware *fw, int ice_devlink_flash_update(struct devlink *devlink,
u8 preservation, struct netlink_ext_ack *extack); struct devlink_flash_update_params *params,
int ice_check_for_pending_update(struct ice_pf *pf, const char *component, struct netlink_ext_ack *extack);
struct netlink_ext_ack *extack); int ice_get_pending_updates(struct ice_pf *pf, u8 *pending,
struct netlink_ext_ack *extack);
#endif #endif
...@@ -6229,14 +6229,15 @@ static void ice_napi_disable_all(struct ice_vsi *vsi) ...@@ -6229,14 +6229,15 @@ static void ice_napi_disable_all(struct ice_vsi *vsi)
/** /**
* ice_down - Shutdown the connection * ice_down - Shutdown the connection
* @vsi: The VSI being stopped * @vsi: The VSI being stopped
*
* Caller of this function is expected to set the vsi->state ICE_DOWN bit
*/ */
int ice_down(struct ice_vsi *vsi) int ice_down(struct ice_vsi *vsi)
{ {
int i, tx_err, rx_err, link_err = 0; int i, tx_err, rx_err, link_err = 0;
/* Caller of this function is expected to set the WARN_ON(!test_bit(ICE_VSI_DOWN, vsi->state));
* vsi->state ICE_DOWN bit
*/
if (vsi->netdev && vsi->type == ICE_VSI_PF) { if (vsi->netdev && vsi->type == ICE_VSI_PF) {
netif_carrier_off(vsi->netdev); netif_carrier_off(vsi->netdev);
netif_tx_disable(vsi->netdev); netif_tx_disable(vsi->netdev);
...@@ -6594,6 +6595,14 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) ...@@ -6594,6 +6595,14 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
dev_dbg(dev, "rebuilding PF after reset_type=%d\n", reset_type); dev_dbg(dev, "rebuilding PF after reset_type=%d\n", reset_type);
if (reset_type == ICE_RESET_EMPR) {
/* If an EMP reset has occurred, any previously pending flash
* update will have completed. We no longer know whether or
* not the NVM update EMP reset is restricted.
*/
pf->fw_emp_reset_disabled = false;
}
err = ice_init_all_ctrlq(hw); err = ice_init_all_ctrlq(hw);
if (err) { if (err) {
dev_err(dev, "control queues init failed %d\n", err); dev_err(dev, "control queues init failed %d\n", err);
......
...@@ -615,7 +615,7 @@ static int ...@@ -615,7 +615,7 @@ static int
ice_get_orom_civd_data(struct ice_hw *hw, enum ice_bank_select bank, ice_get_orom_civd_data(struct ice_hw *hw, enum ice_bank_select bank,
struct ice_orom_civd_info *civd) struct ice_orom_civd_info *civd)
{ {
struct ice_orom_civd_info tmp; u8 *orom_data;
int status; int status;
u32 offset; u32 offset;
...@@ -623,36 +623,60 @@ ice_get_orom_civd_data(struct ice_hw *hw, enum ice_bank_select bank, ...@@ -623,36 +623,60 @@ ice_get_orom_civd_data(struct ice_hw *hw, enum ice_bank_select bank,
* The first 4 bytes must contain the ASCII characters "$CIV". * The first 4 bytes must contain the ASCII characters "$CIV".
* A simple modulo 256 sum of all of the bytes of the structure must * A simple modulo 256 sum of all of the bytes of the structure must
* equal 0. * equal 0.
*
* The exact location is unknown and varies between images but is
* usually somewhere in the middle of the bank. We need to scan the
* Option ROM bank to locate it.
*
* It's significantly faster to read the entire Option ROM up front
* using the maximum page size, than to read each possible location
* with a separate firmware command.
*/ */
orom_data = vzalloc(hw->flash.banks.orom_size);
if (!orom_data)
return -ENOMEM;
status = ice_read_flash_module(hw, bank, ICE_SR_1ST_OROM_BANK_PTR, 0,
orom_data, hw->flash.banks.orom_size);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Unable to read Option ROM data\n");
return status;
}
/* Scan the memory buffer to locate the CIVD data section */
for (offset = 0; (offset + 512) <= hw->flash.banks.orom_size; offset += 512) { for (offset = 0; (offset + 512) <= hw->flash.banks.orom_size; offset += 512) {
struct ice_orom_civd_info *tmp;
u8 sum = 0, i; u8 sum = 0, i;
status = ice_read_flash_module(hw, bank, ICE_SR_1ST_OROM_BANK_PTR, tmp = (struct ice_orom_civd_info *)&orom_data[offset];
offset, (u8 *)&tmp, sizeof(tmp));
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Unable to read Option ROM CIVD data\n");
return status;
}
/* Skip forward until we find a matching signature */ /* Skip forward until we find a matching signature */
if (memcmp("$CIV", tmp.signature, sizeof(tmp.signature)) != 0) if (memcmp("$CIV", tmp->signature, sizeof(tmp->signature)) != 0)
continue; continue;
ice_debug(hw, ICE_DBG_NVM, "Found CIVD section at offset %u\n",
offset);
/* Verify that the simple checksum is zero */ /* Verify that the simple checksum is zero */
for (i = 0; i < sizeof(tmp); i++) for (i = 0; i < sizeof(*tmp); i++)
/* cppcheck-suppress objectIndex */ /* cppcheck-suppress objectIndex */
sum += ((u8 *)&tmp)[i]; sum += ((u8 *)tmp)[i];
if (sum) { if (sum) {
ice_debug(hw, ICE_DBG_NVM, "Found CIVD data with invalid checksum of %u\n", ice_debug(hw, ICE_DBG_NVM, "Found CIVD data with invalid checksum of %u\n",
sum); sum);
return -EIO; goto err_invalid_checksum;
} }
*civd = tmp; *civd = *tmp;
vfree(orom_data);
return 0; return 0;
} }
ice_debug(hw, ICE_DBG_NVM, "Unable to locate CIVD data within the Option ROM\n");
err_invalid_checksum:
vfree(orom_data);
return -EIO; return -EIO;
} }
...@@ -1081,22 +1105,35 @@ int ice_nvm_validate_checksum(struct ice_hw *hw) ...@@ -1081,22 +1105,35 @@ int ice_nvm_validate_checksum(struct ice_hw *hw)
/** /**
* ice_nvm_write_activate * ice_nvm_write_activate
* @hw: pointer to the HW struct * @hw: pointer to the HW struct
* @cmd_flags: NVM activate admin command bits (banks to be validated) * @cmd_flags: flags for write activate command
* @response_flags: response indicators from firmware
* *
* Update the control word with the required banks' validity bits * Update the control word with the required banks' validity bits
* and dumps the Shadow RAM to flash (0x0707) * and dumps the Shadow RAM to flash (0x0707)
*
* cmd_flags controls which banks to activate, and the preservation level to
* use when activating the NVM bank.
*
* On successful return of the firmware command, the response_flags variable
* is updated with the flags reported by firmware indicating certain status,
* such as whether EMP reset is enabled.
*/ */
int ice_nvm_write_activate(struct ice_hw *hw, u8 cmd_flags) int ice_nvm_write_activate(struct ice_hw *hw, u8 cmd_flags, u8 *response_flags)
{ {
struct ice_aqc_nvm *cmd; struct ice_aqc_nvm *cmd;
struct ice_aq_desc desc; struct ice_aq_desc desc;
int err;
cmd = &desc.params.nvm; cmd = &desc.params.nvm;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_write_activate); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_write_activate);
cmd->cmd_flags = cmd_flags; cmd->cmd_flags = cmd_flags;
return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); err = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
if (!err && response_flags)
*response_flags = cmd->cmd_flags;
return err;
} }
/** /**
......
...@@ -34,7 +34,7 @@ ice_aq_update_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, ...@@ -34,7 +34,7 @@ ice_aq_update_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset,
int int
ice_aq_erase_nvm(struct ice_hw *hw, u16 module_typeid, struct ice_sq_cd *cd); ice_aq_erase_nvm(struct ice_hw *hw, u16 module_typeid, struct ice_sq_cd *cd);
int ice_nvm_validate_checksum(struct ice_hw *hw); int ice_nvm_validate_checksum(struct ice_hw *hw);
int ice_nvm_write_activate(struct ice_hw *hw, u8 cmd_flags); int ice_nvm_write_activate(struct ice_hw *hw, u8 cmd_flags, u8 *response_flags);
int ice_aq_nvm_update_empr(struct ice_hw *hw); int ice_aq_nvm_update_empr(struct ice_hw *hw);
int int
ice_nvm_set_pkg_data(struct ice_hw *hw, bool del_pkg_data_flag, u8 *data, ice_nvm_set_pkg_data(struct ice_hw *hw, bool del_pkg_data_flag, u8 *data,
......
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
/* The driver transmit and receive code */ /* The driver transmit and receive code */
#include <linux/prefetch.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/netdevice.h>
#include <linux/prefetch.h>
#include <linux/bpf_trace.h> #include <linux/bpf_trace.h>
#include <net/dsfield.h> #include <net/dsfield.h>
#include <net/xdp.h> #include <net/xdp.h>
...@@ -219,6 +220,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget) ...@@ -219,6 +220,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
struct ice_tx_desc *tx_desc; struct ice_tx_desc *tx_desc;
struct ice_tx_buf *tx_buf; struct ice_tx_buf *tx_buf;
/* get the bql data ready */
if (!ice_ring_is_xdp(tx_ring))
netdev_txq_bql_complete_prefetchw(txring_txq(tx_ring));
tx_buf = &tx_ring->tx_buf[i]; tx_buf = &tx_ring->tx_buf[i];
tx_desc = ICE_TX_DESC(tx_ring, i); tx_desc = ICE_TX_DESC(tx_ring, i);
i -= tx_ring->count; i -= tx_ring->count;
...@@ -232,6 +237,9 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget) ...@@ -232,6 +237,9 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
if (!eop_desc) if (!eop_desc)
break; break;
/* follow the guidelines of other drivers */
prefetchw(&tx_buf->skb->users);
smp_rmb(); /* prevent any other reads prior to eop_desc */ smp_rmb(); /* prevent any other reads prior to eop_desc */
ice_trace(clean_tx_irq, tx_ring, tx_desc, tx_buf); ice_trace(clean_tx_irq, tx_ring, tx_desc, tx_buf);
...@@ -304,8 +312,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget) ...@@ -304,8 +312,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
ice_update_tx_ring_stats(tx_ring, total_pkts, total_bytes); ice_update_tx_ring_stats(tx_ring, total_pkts, total_bytes);
netdev_tx_completed_queue(txring_txq(tx_ring), total_pkts, if (ice_ring_is_xdp(tx_ring))
total_bytes); return !!budget;
netdev_tx_completed_queue(txring_txq(tx_ring), total_pkts, total_bytes);
#define TX_WAKE_THRESHOLD ((s16)(DESC_NEEDED * 2)) #define TX_WAKE_THRESHOLD ((s16)(DESC_NEEDED * 2))
if (unlikely(total_pkts && netif_carrier_ok(tx_ring->netdev) && if (unlikely(total_pkts && netif_carrier_ok(tx_ring->netdev) &&
...@@ -314,11 +324,9 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget) ...@@ -314,11 +324,9 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
* sees the new next_to_clean. * sees the new next_to_clean.
*/ */
smp_mb(); smp_mb();
if (__netif_subqueue_stopped(tx_ring->netdev, if (netif_tx_queue_stopped(txring_txq(tx_ring)) &&
tx_ring->q_index) &&
!test_bit(ICE_VSI_DOWN, vsi->state)) { !test_bit(ICE_VSI_DOWN, vsi->state)) {
netif_wake_subqueue(tx_ring->netdev, netif_tx_wake_queue(txring_txq(tx_ring));
tx_ring->q_index);
++tx_ring->tx_stats.restart_q; ++tx_ring->tx_stats.restart_q;
} }
} }
...@@ -1517,7 +1525,7 @@ int ice_napi_poll(struct napi_struct *napi, int budget) ...@@ -1517,7 +1525,7 @@ int ice_napi_poll(struct napi_struct *napi, int budget)
*/ */
static int __ice_maybe_stop_tx(struct ice_tx_ring *tx_ring, unsigned int size) static int __ice_maybe_stop_tx(struct ice_tx_ring *tx_ring, unsigned int size)
{ {
netif_stop_subqueue(tx_ring->netdev, tx_ring->q_index); netif_tx_stop_queue(txring_txq(tx_ring));
/* Memory barrier before checking head and tail */ /* Memory barrier before checking head and tail */
smp_mb(); smp_mb();
...@@ -1525,8 +1533,8 @@ static int __ice_maybe_stop_tx(struct ice_tx_ring *tx_ring, unsigned int size) ...@@ -1525,8 +1533,8 @@ static int __ice_maybe_stop_tx(struct ice_tx_ring *tx_ring, unsigned int size)
if (likely(ICE_DESC_UNUSED(tx_ring) < size)) if (likely(ICE_DESC_UNUSED(tx_ring) < size))
return -EBUSY; return -EBUSY;
/* A reprieve! - use start_subqueue because it doesn't call schedule */ /* A reprieve! - use start_queue because it doesn't call schedule */
netif_start_subqueue(tx_ring->netdev, tx_ring->q_index); netif_tx_start_queue(txring_txq(tx_ring));
++tx_ring->tx_stats.restart_q; ++tx_ring->tx_stats.restart_q;
return 0; return 0;
} }
...@@ -1568,6 +1576,7 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first, ...@@ -1568,6 +1576,7 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first,
struct sk_buff *skb; struct sk_buff *skb;
skb_frag_t *frag; skb_frag_t *frag;
dma_addr_t dma; dma_addr_t dma;
bool kick;
td_tag = off->td_l2tag1; td_tag = off->td_l2tag1;
td_cmd = off->td_cmd; td_cmd = off->td_cmd;
...@@ -1649,9 +1658,6 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first, ...@@ -1649,9 +1658,6 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first,
tx_buf = &tx_ring->tx_buf[i]; tx_buf = &tx_ring->tx_buf[i];
} }
/* record bytecount for BQL */
netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount);
/* record SW timestamp if HW timestamp is not available */ /* record SW timestamp if HW timestamp is not available */
skb_tx_timestamp(first->skb); skb_tx_timestamp(first->skb);
...@@ -1680,7 +1686,10 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first, ...@@ -1680,7 +1686,10 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first,
ice_maybe_stop_tx(tx_ring, DESC_NEEDED); ice_maybe_stop_tx(tx_ring, DESC_NEEDED);
/* notify HW of packet */ /* notify HW of packet */
if (netif_xmit_stopped(txring_txq(tx_ring)) || !netdev_xmit_more()) kick = __netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount,
netdev_xmit_more());
if (kick)
/* notify HW of packet */
writel(i, tx_ring->tail); writel(i, tx_ring->tail);
return; return;
...@@ -2265,6 +2274,9 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) ...@@ -2265,6 +2274,9 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
/* prefetch for bql data which is infrequently used */
netdev_txq_bql_enqueue_prefetchw(txring_txq(tx_ring));
offload.tx_ring = tx_ring; offload.tx_ring = tx_ring;
/* record the location of the first descriptor for this packet */ /* record the location of the first descriptor for this packet */
......
...@@ -278,6 +278,10 @@ struct ice_hw_common_caps { ...@@ -278,6 +278,10 @@ struct ice_hw_common_caps {
#define ICE_NVM_PENDING_NETLIST BIT(2) #define ICE_NVM_PENDING_NETLIST BIT(2)
bool nvm_unified_update; bool nvm_unified_update;
#define ICE_NVM_MGMT_UNIFIED_UPD_SUPPORT BIT(3) #define ICE_NVM_MGMT_UNIFIED_UPD_SUPPORT BIT(3)
/* PCIe reset avoidance */
bool pcie_reset_avoidance;
/* Post update reset restriction */
bool reset_restrict_support;
}; };
/* IEEE 1588 TIME_SYNC specific info */ /* IEEE 1588 TIME_SYNC specific info */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment