Skip to content

Commit d69ea41

Browse files
jacob-kellerdavem330
authored andcommitted
ice: implement device flash update via devlink
Use the newly added pldmfw library to implement device flash update for the Intel ice networking device driver. This support uses the devlink flash update interface. The main parts of the flash include the Option ROM, the netlist module, and the main NVM data. The PLDM firmware file contains modules for each of these components. Using the pldmfw library, the provided firmware file will be scanned for the three major components, "fw.undi" for the Option ROM, "fw.mgmt" for the main NVM module containing the primary device firmware, and "fw.netlist" containing the netlist module. The flash is separated into two banks, the active bank containing the running firmware, and the inactive bank which we use for update. Each module is updated in a staged process. First, the inactive bank is erased, preparing the device for update. Second, the contents of the component are copied to the inactive portion of the flash. After all components are updated, the driver signals the device to switch the active bank during the next EMP reset (which would usually occur during the next reboot). Although the firmware AdminQ interface does report an immediate status for each command, the NVM erase and NVM write commands receive status asynchronously. The driver must not continue writing until previous erase and write commands have finished. The real status of the NVM commands is returned over the receive AdminQ. Implement a simple interface that uses a wait queue so that the main update thread can sleep until the completion status is reported by firmware. For erasing the inactive banks, this can take quite a while in practice. To help visualize the process to the devlink application and other applications based on the devlink netlink interface, status is reported via the devlink_flash_update_status_notify. While we do report status after each 4k block when writing, there is no real status we can report during erasing. We simply must wait for the complete module erasure to finish. With this implementation, basic flash update for the ice hardware is supported. Signed-off-by: Jacob Keller <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2ab560a commit d69ea41

File tree

9 files changed

+1007
-1
lines changed

9 files changed

+1007
-1
lines changed

drivers/net/ethernet/intel/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ config ICE
295295
default n
296296
depends on PCI_MSI
297297
select NET_DEVLINK
298+
select PLDMFW
298299
help
299300
This driver supports Intel(R) Ethernet Connection E800 Series of
300301
devices. For more information on how to identify your adapter, go

drivers/net/ethernet/intel/ice/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ ice-y := ice_main.o \
2323
ice_flex_pipe.o \
2424
ice_flow.o \
2525
ice_devlink.o \
26+
ice_fw_update.o \
2627
ice_ethtool.o
2728
ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o ice_sriov.o
2829
ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o

drivers/net/ethernet/intel/ice/ice.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/dma-mapping.h>
2020
#include <linux/pci.h>
2121
#include <linux/workqueue.h>
22+
#include <linux/wait.h>
2223
#include <linux/aer.h>
2324
#include <linux/interrupt.h>
2425
#include <linux/ethtool.h>
@@ -412,6 +413,12 @@ struct ice_pf {
412413
struct mutex sw_mutex; /* lock for protecting VSI alloc flow */
413414
struct mutex tc_mutex; /* lock to protect TC changes */
414415
u32 msg_enable;
416+
417+
/* spinlock to protect the AdminQ wait list */
418+
spinlock_t aq_wait_lock;
419+
struct hlist_head aq_wait_list;
420+
wait_queue_head_t aq_wait_queue;
421+
415422
u32 hw_csum_rx_error;
416423
u16 oicr_idx; /* Other interrupt cause MSIX vector index */
417424
u16 num_avail_sw_msix; /* remaining MSIX SW vectors left unclaimed */
@@ -593,6 +600,8 @@ void ice_fdir_release_flows(struct ice_hw *hw);
593600
void ice_fdir_replay_flows(struct ice_hw *hw);
594601
void ice_fdir_replay_fltrs(struct ice_pf *pf);
595602
int ice_fdir_create_dflt_rules(struct ice_pf *pf);
603+
int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout,
604+
struct ice_rq_event_info *event);
596605
int ice_open(struct net_device *netdev);
597606
int ice_stop(struct net_device *netdev);
598607
void ice_service_task_schedule(struct ice_pf *pf);

drivers/net/ethernet/intel/ice/ice_common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2223,7 +2223,7 @@ ice_aq_list_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count,
22232223
* Read the device capabilities and extract them into the dev_caps structure
22242224
* for later use.
22252225
*/
2226-
static enum ice_status
2226+
enum ice_status
22272227
ice_discover_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_caps)
22282228
{
22292229
enum ice_status status;

drivers/net/ethernet/intel/ice/ice_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
8888
enum ice_status
8989
ice_aq_list_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count,
9090
enum ice_adminq_opc opc, struct ice_sq_cd *cd);
91+
enum ice_status
92+
ice_discover_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_caps);
9193
void
9294
ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high,
9395
u16 link_speeds_bitmap);

drivers/net/ethernet/intel/ice/ice_devlink.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "ice.h"
55
#include "ice_lib.h"
66
#include "ice_devlink.h"
7+
#include "ice_fw_update.h"
78

89
static int ice_info_get_dsn(struct ice_pf *pf, char *buf, size_t len)
910
{
@@ -229,8 +230,61 @@ static int ice_devlink_info_get(struct devlink *devlink,
229230
return 0;
230231
}
231232

233+
/**
234+
* ice_devlink_flash_update - Update firmware stored in flash on the device
235+
* @devlink: pointer to devlink associated with device to update
236+
* @path: the path of the firmware file to use via request_firmware
237+
* @component: name of the component to update, or NULL
238+
* @extack: netlink extended ACK structure
239+
*
240+
* Perform a device flash update. The bulk of the update logic is contained
241+
* within the ice_flash_pldm_image function.
242+
*
243+
* Returns: zero on success, or an error code on failure.
244+
*/
245+
static int
246+
ice_devlink_flash_update(struct devlink *devlink, const char *path,
247+
const char *component, struct netlink_ext_ack *extack)
248+
{
249+
struct ice_pf *pf = devlink_priv(devlink);
250+
struct device *dev = &pf->pdev->dev;
251+
struct ice_hw *hw = &pf->hw;
252+
const struct firmware *fw;
253+
int err;
254+
255+
/* individual component update is not yet supported */
256+
if (component)
257+
return -EOPNOTSUPP;
258+
259+
if (!hw->dev_caps.common_cap.nvm_unified_update) {
260+
NL_SET_ERR_MSG_MOD(extack, "Current firmware does not support unified update");
261+
return -EOPNOTSUPP;
262+
}
263+
264+
err = ice_check_for_pending_update(pf, component, extack);
265+
if (err)
266+
return err;
267+
268+
err = request_firmware(&fw, path, dev);
269+
if (err) {
270+
NL_SET_ERR_MSG_MOD(extack, "Unable to read file from disk");
271+
return err;
272+
}
273+
274+
devlink_flash_update_begin_notify(devlink);
275+
devlink_flash_update_status_notify(devlink, "Preparing to flash",
276+
component, 0, 0);
277+
err = ice_flash_pldm_image(pf, fw, extack);
278+
devlink_flash_update_end_notify(devlink);
279+
280+
release_firmware(fw);
281+
282+
return err;
283+
}
284+
232285
static const struct devlink_ops ice_devlink_ops = {
233286
.info_get = ice_devlink_info_get,
287+
.flash_update = ice_devlink_flash_update,
234288
};
235289

236290
static void ice_devlink_free(void *devlink_ptr)

0 commit comments

Comments
 (0)