Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue
Jeff Kirsher says: ==================== 100GbE Intel Wired LAN Driver Updates 2020-03-21 Implement basic support for the devlink interface in the ice driver. Additionally pave some necessary changes for adding a devlink region that exposes the NVM contents. This series first contains 5 patches for enabling and implementing full NVM read access via the ETHTOOL_GEEPROM interface. This includes some cleanup of endian-types, a new function for reading from the NVM and Shadow RAM as a flat addressable space, a function to calculate the available flash size during load, and a change to how some of the NVM version fields are stored in the ice_nvm_info structure. Following this is 3 patches for implementing devlink support. First, one patch which implements the basic framework and introduces the ice_devlink.c file. Second, a patch to implement basic .info_get support. Finally, a patch which reads the device PBA identifier and reports it as the `board.id` value in the .info_get response. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
adbea1a5f5
@ -98,3 +98,8 @@ fw.roce
|
||||
|
||||
RoCE firmware version which is responsible for handling roce
|
||||
management.
|
||||
|
||||
fw.bundle_id
|
||||
------------
|
||||
|
||||
Unique identifier of the entire firmware bundle.
|
||||
|
71
Documentation/networking/devlink/ice.rst
Normal file
71
Documentation/networking/devlink/ice.rst
Normal file
@ -0,0 +1,71 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
===================
|
||||
ice devlink support
|
||||
===================
|
||||
|
||||
This document describes the devlink features implemented by the ``ice``
|
||||
device driver.
|
||||
|
||||
Info versions
|
||||
=============
|
||||
|
||||
The ``ice`` driver reports the following versions
|
||||
|
||||
.. list-table:: devlink info versions implemented
|
||||
:widths: 5 5 5 90
|
||||
|
||||
* - Name
|
||||
- Type
|
||||
- Example
|
||||
- Description
|
||||
* - ``board.id``
|
||||
- fixed
|
||||
- K65390-000
|
||||
- The Product Board Assembly (PBA) identifier of the board.
|
||||
* - ``fw.mgmt``
|
||||
- running
|
||||
- 2.1.7
|
||||
- 3-digit version number of the management firmware that controls the
|
||||
PHY, link, etc.
|
||||
* - ``fw.mgmt.api``
|
||||
- running
|
||||
- 1.5
|
||||
- 2-digit version number of the API exported over the AdminQ by the
|
||||
management firmware. Used by the driver to identify what commands
|
||||
are supported.
|
||||
* - ``fw.mgmt.build``
|
||||
- running
|
||||
- 0x305d955f
|
||||
- Unique identifier of the source for the management firmware.
|
||||
* - ``fw.undi``
|
||||
- running
|
||||
- 1.2581.0
|
||||
- Version of the Option ROM containing the UEFI driver. The version is
|
||||
reported in ``major.minor.patch`` format. The major version is
|
||||
incremented whenever a major breaking change occurs, or when the
|
||||
minor version would overflow. The minor version is incremented for
|
||||
non-breaking changes and reset to 1 when the major version is
|
||||
incremented. The patch version is normally 0 but is incremented when
|
||||
a fix is delivered as a patch against an older base Option ROM.
|
||||
* - ``fw.psid.api``
|
||||
- running
|
||||
- 0.80
|
||||
- Version defining the format of the flash contents.
|
||||
* - ``fw.bundle_id``
|
||||
- running
|
||||
- 0x80002ec0
|
||||
- Unique identifier of the firmware image file that was loaded onto
|
||||
the device. Also referred to as the EETRACK identifier of the NVM.
|
||||
* - ``fw.app.name``
|
||||
- running
|
||||
- ICE OS Default Package
|
||||
- The name of the DDP package that is active in the device. The DDP
|
||||
package is loaded by the driver during initialization. Each varation
|
||||
of DDP package shall have a unique name.
|
||||
* - ``fw.app``
|
||||
- running
|
||||
- 1.3.1.0
|
||||
- The version of the DDP package that is active in the device. Note
|
||||
that both the name (as reported by ``fw.app.name``) and version are
|
||||
required to uniquely identify the package.
|
@ -32,6 +32,7 @@ parameters, info versions, and other features it supports.
|
||||
|
||||
bnxt
|
||||
ionic
|
||||
ice
|
||||
mlx4
|
||||
mlx5
|
||||
mlxsw
|
||||
|
@ -294,6 +294,7 @@ config ICE
|
||||
tristate "Intel(R) Ethernet Connection E800 Series Support"
|
||||
default n
|
||||
depends on PCI_MSI
|
||||
select NET_DEVLINK
|
||||
---help---
|
||||
This driver supports Intel(R) Ethernet Connection E800 Series of
|
||||
devices. For more information on how to identify your adapter, go
|
||||
|
@ -19,6 +19,7 @@ ice-y := ice_main.o \
|
||||
ice_txrx.o \
|
||||
ice_flex_pipe.o \
|
||||
ice_flow.o \
|
||||
ice_devlink.o \
|
||||
ice_ethtool.o
|
||||
ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o ice_sriov.o
|
||||
ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/avf/virtchnl.h>
|
||||
#include <net/devlink.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/xdp_sock.h>
|
||||
#include "ice_devids.h"
|
||||
@ -347,6 +348,9 @@ enum ice_pf_flags {
|
||||
struct ice_pf {
|
||||
struct pci_dev *pdev;
|
||||
|
||||
/* devlink port data */
|
||||
struct devlink_port devlink_port;
|
||||
|
||||
/* OS reserved IRQ details */
|
||||
struct msix_entry *msix_entries;
|
||||
struct ice_res_tracker *irq_tracker;
|
||||
|
@ -1232,6 +1232,7 @@ struct ice_aqc_sff_eeprom {
|
||||
* NVM Update commands (indirect 0x0703)
|
||||
*/
|
||||
struct ice_aqc_nvm {
|
||||
#define ICE_AQC_NVM_MAX_OFFSET 0xFFFFFF
|
||||
__le16 offset_low;
|
||||
u8 offset_high;
|
||||
u8 cmd_flags;
|
||||
@ -1250,6 +1251,8 @@ struct ice_aqc_nvm {
|
||||
__le32 addr_low;
|
||||
};
|
||||
|
||||
#define ICE_AQC_NVM_START_POINT 0
|
||||
|
||||
/* NVM Checksum Command (direct, 0x0706) */
|
||||
struct ice_aqc_nvm_checksum {
|
||||
u8 flags;
|
||||
@ -1764,6 +1767,7 @@ enum ice_aq_err {
|
||||
ICE_AQ_RC_ENOMEM = 9, /* Out of memory */
|
||||
ICE_AQ_RC_EBUSY = 12, /* Device or resource busy */
|
||||
ICE_AQ_RC_EEXIST = 13, /* Object already exists */
|
||||
ICE_AQ_RC_EINVAL = 14, /* Invalid argument */
|
||||
ICE_AQ_RC_ENOSPC = 16, /* No space left or allocation failure */
|
||||
ICE_AQ_RC_ENOSYS = 17, /* Function not implemented */
|
||||
ICE_AQ_RC_ENOSEC = 24, /* Missing security manifest */
|
||||
|
@ -614,29 +614,6 @@ static void ice_get_itr_intrl_gran(struct ice_hw *hw)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_get_nvm_version - get cached NVM version data
|
||||
* @hw: pointer to the hardware structure
|
||||
* @oem_ver: 8 bit NVM version
|
||||
* @oem_build: 16 bit NVM build number
|
||||
* @oem_patch: 8 NVM patch number
|
||||
* @ver_hi: high 8 bits of the NVM version
|
||||
* @ver_lo: low 8 bits of the NVM version
|
||||
*/
|
||||
void
|
||||
ice_get_nvm_version(struct ice_hw *hw, u8 *oem_ver, u16 *oem_build,
|
||||
u8 *oem_patch, u8 *ver_hi, u8 *ver_lo)
|
||||
{
|
||||
struct ice_nvm_info *nvm = &hw->nvm;
|
||||
|
||||
*oem_ver = (u8)((nvm->oem_ver & ICE_OEM_VER_MASK) >> ICE_OEM_VER_SHIFT);
|
||||
*oem_patch = (u8)(nvm->oem_ver & ICE_OEM_VER_PATCH_MASK);
|
||||
*oem_build = (u16)((nvm->oem_ver & ICE_OEM_VER_BUILD_MASK) >>
|
||||
ICE_OEM_VER_BUILD_SHIFT);
|
||||
*ver_hi = (nvm->ver & ICE_NVM_VER_HI_MASK) >> ICE_NVM_VER_HI_SHIFT;
|
||||
*ver_lo = (nvm->ver & ICE_NVM_VER_LO_MASK) >> ICE_NVM_VER_LO_SHIFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_init_hw - main hardware initialization routine
|
||||
* @hw: pointer to the hardware structure
|
||||
@ -957,72 +934,6 @@ enum ice_status ice_reset(struct ice_hw *hw, enum ice_reset_req req)
|
||||
return ice_check_reset(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_get_pfa_module_tlv - Reads sub module TLV from NVM PFA
|
||||
* @hw: pointer to hardware structure
|
||||
* @module_tlv: pointer to module TLV to return
|
||||
* @module_tlv_len: pointer to module TLV length to return
|
||||
* @module_type: module type requested
|
||||
*
|
||||
* Finds the requested sub module TLV type from the Preserved Field
|
||||
* Area (PFA) and returns the TLV pointer and length. The caller can
|
||||
* use these to read the variable length TLV value.
|
||||
*/
|
||||
enum ice_status
|
||||
ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
|
||||
u16 module_type)
|
||||
{
|
||||
enum ice_status status;
|
||||
u16 pfa_len, pfa_ptr;
|
||||
u16 next_tlv;
|
||||
|
||||
status = ice_read_sr_word(hw, ICE_SR_PFA_PTR, &pfa_ptr);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Preserved Field Array pointer.\n");
|
||||
return status;
|
||||
}
|
||||
status = ice_read_sr_word(hw, pfa_ptr, &pfa_len);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read PFA length.\n");
|
||||
return status;
|
||||
}
|
||||
/* Starting with first TLV after PFA length, iterate through the list
|
||||
* of TLVs to find the requested one.
|
||||
*/
|
||||
next_tlv = pfa_ptr + 1;
|
||||
while (next_tlv < pfa_ptr + pfa_len) {
|
||||
u16 tlv_sub_module_type;
|
||||
u16 tlv_len;
|
||||
|
||||
/* Read TLV type */
|
||||
status = ice_read_sr_word(hw, next_tlv, &tlv_sub_module_type);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read TLV type.\n");
|
||||
break;
|
||||
}
|
||||
/* Read TLV length */
|
||||
status = ice_read_sr_word(hw, next_tlv + 1, &tlv_len);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read TLV length.\n");
|
||||
break;
|
||||
}
|
||||
if (tlv_sub_module_type == module_type) {
|
||||
if (tlv_len) {
|
||||
*module_tlv = next_tlv;
|
||||
*module_tlv_len = tlv_len;
|
||||
return 0;
|
||||
}
|
||||
return ICE_ERR_INVAL_SIZE;
|
||||
}
|
||||
/* Check next TLV, i.e. current TLV pointer + length + 2 words
|
||||
* (for current TLV's type and length)
|
||||
*/
|
||||
next_tlv = next_tlv + tlv_len + 2;
|
||||
}
|
||||
/* Module does not exist */
|
||||
return ICE_ERR_DOES_NOT_EXIST;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_copy_rxq_ctx_to_hw
|
||||
* @hw: pointer to the hardware structure
|
||||
|
@ -15,9 +15,6 @@ enum ice_status ice_nvm_validate_checksum(struct ice_hw *hw);
|
||||
|
||||
enum ice_status ice_init_hw(struct ice_hw *hw);
|
||||
void ice_deinit_hw(struct ice_hw *hw);
|
||||
enum ice_status
|
||||
ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
|
||||
u16 module_type);
|
||||
enum ice_status ice_check_reset(struct ice_hw *hw);
|
||||
enum ice_status ice_reset(struct ice_hw *hw, enum ice_reset_req req);
|
||||
enum ice_status ice_create_all_ctrlq(struct ice_hw *hw);
|
||||
@ -38,9 +35,6 @@ enum ice_status
|
||||
ice_alloc_hw_res(struct ice_hw *hw, u16 type, u16 num, bool btm, u16 *res);
|
||||
enum ice_status
|
||||
ice_free_hw_res(struct ice_hw *hw, u16 type, u16 num, u16 *res);
|
||||
enum ice_status ice_init_nvm(struct ice_hw *hw);
|
||||
enum ice_status
|
||||
ice_read_sr_buf(struct ice_hw *hw, u16 offset, u16 *words, u16 *data);
|
||||
enum ice_status
|
||||
ice_aq_alloc_free_res(struct ice_hw *hw, u16 num_entries,
|
||||
struct ice_aqc_alloc_free_res_elem *buf, u16 buf_size,
|
||||
@ -153,9 +147,6 @@ ice_stat_update40(struct ice_hw *hw, u32 reg, bool prev_stat_loaded,
|
||||
void
|
||||
ice_stat_update32(struct ice_hw *hw, u32 reg, bool prev_stat_loaded,
|
||||
u64 *prev_stat, u64 *cur_stat);
|
||||
void
|
||||
ice_get_nvm_version(struct ice_hw *hw, u8 *oem_ver, u16 *oem_build,
|
||||
u8 *oem_patch, u8 *ver_hi, u8 *ver_lo);
|
||||
enum ice_status
|
||||
ice_sched_query_elem(struct ice_hw *hw, u32 node_teid,
|
||||
struct ice_aqc_get_elem *buf);
|
||||
|
320
drivers/net/ethernet/intel/ice/ice_devlink.c
Normal file
320
drivers/net/ethernet/intel/ice/ice_devlink.c
Normal file
@ -0,0 +1,320 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2020, Intel Corporation. */
|
||||
|
||||
#include "ice.h"
|
||||
#include "ice_lib.h"
|
||||
#include "ice_devlink.h"
|
||||
|
||||
static int ice_info_get_dsn(struct ice_pf *pf, char *buf, size_t len)
|
||||
{
|
||||
u8 dsn[8];
|
||||
|
||||
/* Copy the DSN into an array in Big Endian format */
|
||||
put_unaligned_be64(pci_get_dsn(pf->pdev), dsn);
|
||||
|
||||
snprintf(buf, len, "%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
|
||||
dsn[0], dsn[1], dsn[2], dsn[3],
|
||||
dsn[4], dsn[5], dsn[6], dsn[7]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ice_info_pba(struct ice_pf *pf, char *buf, size_t len)
|
||||
{
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
enum ice_status status;
|
||||
|
||||
status = ice_read_pba_string(hw, (u8 *)buf, len);
|
||||
if (status)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ice_info_fw_mgmt(struct ice_pf *pf, char *buf, size_t len)
|
||||
{
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
|
||||
snprintf(buf, len, "%u.%u.%u", hw->fw_maj_ver, hw->fw_min_ver,
|
||||
hw->fw_patch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ice_info_fw_api(struct ice_pf *pf, char *buf, size_t len)
|
||||
{
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
|
||||
snprintf(buf, len, "%u.%u", hw->api_maj_ver, hw->api_min_ver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ice_info_fw_build(struct ice_pf *pf, char *buf, size_t len)
|
||||
{
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
|
||||
snprintf(buf, len, "0x%08x", hw->fw_build);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ice_info_orom_ver(struct ice_pf *pf, char *buf, size_t len)
|
||||
{
|
||||
struct ice_orom_info *orom = &pf->hw.nvm.orom;
|
||||
|
||||
snprintf(buf, len, "%u.%u.%u", orom->major, orom->build, orom->patch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ice_info_nvm_ver(struct ice_pf *pf, char *buf, size_t len)
|
||||
{
|
||||
struct ice_nvm_info *nvm = &pf->hw.nvm;
|
||||
|
||||
snprintf(buf, len, "%x.%02x", nvm->major_ver, nvm->minor_ver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ice_info_eetrack(struct ice_pf *pf, char *buf, size_t len)
|
||||
{
|
||||
struct ice_nvm_info *nvm = &pf->hw.nvm;
|
||||
|
||||
snprintf(buf, len, "0x%08x", nvm->eetrack);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ice_info_ddp_pkg_name(struct ice_pf *pf, char *buf, size_t len)
|
||||
{
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
|
||||
snprintf(buf, len, "%s", hw->active_pkg_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ice_info_ddp_pkg_version(struct ice_pf *pf, char *buf, size_t len)
|
||||
{
|
||||
struct ice_pkg_ver *pkg = &pf->hw.active_pkg_ver;
|
||||
|
||||
snprintf(buf, len, "%u.%u.%u.%u", pkg->major, pkg->minor, pkg->update,
|
||||
pkg->draft);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define fixed(key, getter) { ICE_VERSION_FIXED, key, getter }
|
||||
#define running(key, getter) { ICE_VERSION_RUNNING, key, getter }
|
||||
|
||||
enum ice_version_type {
|
||||
ICE_VERSION_FIXED,
|
||||
ICE_VERSION_RUNNING,
|
||||
ICE_VERSION_STORED,
|
||||
};
|
||||
|
||||
static const struct ice_devlink_version {
|
||||
enum ice_version_type type;
|
||||
const char *key;
|
||||
int (*getter)(struct ice_pf *pf, char *buf, size_t len);
|
||||
} ice_devlink_versions[] = {
|
||||
fixed(DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, ice_info_pba),
|
||||
running(DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, ice_info_fw_mgmt),
|
||||
running("fw.mgmt.api", ice_info_fw_api),
|
||||
running("fw.mgmt.build", ice_info_fw_build),
|
||||
running(DEVLINK_INFO_VERSION_GENERIC_FW_UNDI, ice_info_orom_ver),
|
||||
running("fw.psid.api", ice_info_nvm_ver),
|
||||
running(DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID, ice_info_eetrack),
|
||||
running("fw.app.name", ice_info_ddp_pkg_name),
|
||||
running(DEVLINK_INFO_VERSION_GENERIC_FW_APP, ice_info_ddp_pkg_version),
|
||||
};
|
||||
|
||||
/**
|
||||
* ice_devlink_info_get - .info_get devlink handler
|
||||
* @devlink: devlink instance structure
|
||||
* @req: the devlink info request
|
||||
* @extack: extended netdev ack structure
|
||||
*
|
||||
* Callback for the devlink .info_get operation. Reports information about the
|
||||
* device.
|
||||
*
|
||||
* Return: zero on success or an error code on failure.
|
||||
*/
|
||||
static int ice_devlink_info_get(struct devlink *devlink,
|
||||
struct devlink_info_req *req,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ice_pf *pf = devlink_priv(devlink);
|
||||
char buf[100];
|
||||
size_t i;
|
||||
int err;
|
||||
|
||||
err = devlink_info_driver_name_put(req, KBUILD_MODNAME);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unable to set driver name");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ice_info_get_dsn(pf, buf, sizeof(buf));
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unable to obtain serial number");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = devlink_info_serial_number_put(req, buf);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unable to set serial number");
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ice_devlink_versions); i++) {
|
||||
enum ice_version_type type = ice_devlink_versions[i].type;
|
||||
const char *key = ice_devlink_versions[i].key;
|
||||
|
||||
err = ice_devlink_versions[i].getter(pf, buf, sizeof(buf));
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unable to obtain version info");
|
||||
return err;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case ICE_VERSION_FIXED:
|
||||
err = devlink_info_version_fixed_put(req, key, buf);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unable to set fixed version");
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
case ICE_VERSION_RUNNING:
|
||||
err = devlink_info_version_running_put(req, key, buf);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unable to set running version");
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
case ICE_VERSION_STORED:
|
||||
err = devlink_info_version_stored_put(req, key, buf);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unable to set stored version");
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct devlink_ops ice_devlink_ops = {
|
||||
.info_get = ice_devlink_info_get,
|
||||
};
|
||||
|
||||
static void ice_devlink_free(void *devlink_ptr)
|
||||
{
|
||||
devlink_free((struct devlink *)devlink_ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_allocate_pf - Allocate devlink and return PF structure pointer
|
||||
* @dev: the device to allocate for
|
||||
*
|
||||
* Allocate a devlink instance for this device and return the private area as
|
||||
* the PF structure. The devlink memory is kept track of through devres by
|
||||
* adding an action to remove it when unwinding.
|
||||
*/
|
||||
struct ice_pf *ice_allocate_pf(struct device *dev)
|
||||
{
|
||||
struct devlink *devlink;
|
||||
|
||||
devlink = devlink_alloc(&ice_devlink_ops, sizeof(struct ice_pf));
|
||||
if (!devlink)
|
||||
return NULL;
|
||||
|
||||
/* Add an action to teardown the devlink when unwinding the driver */
|
||||
if (devm_add_action(dev, ice_devlink_free, devlink)) {
|
||||
devlink_free(devlink);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return devlink_priv(devlink);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_register - Register devlink interface for this PF
|
||||
* @pf: the PF to register the devlink for.
|
||||
*
|
||||
* Register the devlink instance associated with this physical function.
|
||||
*
|
||||
* Return: zero on success or an error code on failure.
|
||||
*/
|
||||
int ice_devlink_register(struct ice_pf *pf)
|
||||
{
|
||||
struct devlink *devlink = priv_to_devlink(pf);
|
||||
struct device *dev = ice_pf_to_dev(pf);
|
||||
int err;
|
||||
|
||||
err = devlink_register(devlink, dev);
|
||||
if (err) {
|
||||
dev_err(dev, "devlink registration failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_unregister - Unregister devlink resources for this PF.
|
||||
* @pf: the PF structure to cleanup
|
||||
*
|
||||
* Releases resources used by devlink and cleans up associated memory.
|
||||
*/
|
||||
void ice_devlink_unregister(struct ice_pf *pf)
|
||||
{
|
||||
devlink_unregister(priv_to_devlink(pf));
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_create_port - Create a devlink port for this PF
|
||||
* @pf: the PF to create a port for
|
||||
*
|
||||
* Create and register a devlink_port for this PF. Note that although each
|
||||
* physical function is connected to a separate devlink instance, the port
|
||||
* will still be numbered according to the physical function id.
|
||||
*
|
||||
* Return: zero on success or an error code on failure.
|
||||
*/
|
||||
int ice_devlink_create_port(struct ice_pf *pf)
|
||||
{
|
||||
struct devlink *devlink = priv_to_devlink(pf);
|
||||
struct ice_vsi *vsi = ice_get_main_vsi(pf);
|
||||
struct device *dev = ice_pf_to_dev(pf);
|
||||
int err;
|
||||
|
||||
if (!vsi) {
|
||||
dev_err(dev, "%s: unable to find main VSI\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
devlink_port_attrs_set(&pf->devlink_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
|
||||
pf->hw.pf_id, false, 0, NULL, 0);
|
||||
err = devlink_port_register(devlink, &pf->devlink_port, pf->hw.pf_id);
|
||||
if (err) {
|
||||
dev_err(dev, "devlink_port_register failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_destroy_port - Destroy the devlink_port for this PF
|
||||
* @pf: the PF to cleanup
|
||||
*
|
||||
* Unregisters the devlink_port structure associated with this PF.
|
||||
*/
|
||||
void ice_devlink_destroy_port(struct ice_pf *pf)
|
||||
{
|
||||
devlink_port_type_clear(&pf->devlink_port);
|
||||
devlink_port_unregister(&pf->devlink_port);
|
||||
}
|
14
drivers/net/ethernet/intel/ice/ice_devlink.h
Normal file
14
drivers/net/ethernet/intel/ice/ice_devlink.h
Normal file
@ -0,0 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2019, Intel Corporation. */
|
||||
|
||||
#ifndef _ICE_DEVLINK_H_
|
||||
#define _ICE_DEVLINK_H_
|
||||
|
||||
struct ice_pf *ice_allocate_pf(struct device *dev);
|
||||
|
||||
int ice_devlink_register(struct ice_pf *pf);
|
||||
void ice_devlink_unregister(struct ice_pf *pf);
|
||||
int ice_devlink_create_port(struct ice_pf *pf);
|
||||
void ice_devlink_destroy_port(struct ice_pf *pf);
|
||||
|
||||
#endif /* _ICE_DEVLINK_H_ */
|
@ -167,11 +167,14 @@ static void
|
||||
ice_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
|
||||
{
|
||||
struct ice_netdev_priv *np = netdev_priv(netdev);
|
||||
u8 oem_ver, oem_patch, nvm_ver_hi, nvm_ver_lo;
|
||||
struct ice_vsi *vsi = np->vsi;
|
||||
struct ice_pf *pf = vsi->back;
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
u16 oem_build;
|
||||
struct ice_orom_info *orom;
|
||||
struct ice_nvm_info *nvm;
|
||||
|
||||
nvm = &hw->nvm;
|
||||
orom = &nvm->orom;
|
||||
|
||||
strscpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
|
||||
strscpy(drvinfo->version, ice_drv_ver, sizeof(drvinfo->version));
|
||||
@ -179,11 +182,9 @@ ice_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
|
||||
/* Display NVM version (from which the firmware version can be
|
||||
* determined) which contains more pertinent information.
|
||||
*/
|
||||
ice_get_nvm_version(hw, &oem_ver, &oem_build, &oem_patch,
|
||||
&nvm_ver_hi, &nvm_ver_lo);
|
||||
snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
|
||||
"%x.%02x 0x%x %d.%d.%d", nvm_ver_hi, nvm_ver_lo,
|
||||
hw->nvm.eetrack, oem_ver, oem_build, oem_patch);
|
||||
"%x.%02x 0x%x %d.%d.%d", nvm->major_ver, nvm->minor_ver,
|
||||
nvm->eetrack, orom->major, orom->build, orom->patch);
|
||||
|
||||
strscpy(drvinfo->bus_info, pci_name(pf->pdev),
|
||||
sizeof(drvinfo->bus_info));
|
||||
@ -244,7 +245,7 @@ static int ice_get_eeprom_len(struct net_device *netdev)
|
||||
struct ice_netdev_priv *np = netdev_priv(netdev);
|
||||
struct ice_pf *pf = np->vsi->back;
|
||||
|
||||
return (int)(pf->hw.nvm.sr_words * sizeof(u16));
|
||||
return (int)pf->hw.nvm.flash_size;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -252,39 +253,46 @@ ice_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
|
||||
u8 *bytes)
|
||||
{
|
||||
struct ice_netdev_priv *np = netdev_priv(netdev);
|
||||
u16 first_word, last_word, nwords;
|
||||
struct ice_vsi *vsi = np->vsi;
|
||||
struct ice_pf *pf = vsi->back;
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
enum ice_status status;
|
||||
struct device *dev;
|
||||
int ret = 0;
|
||||
u16 *buf;
|
||||
u8 *buf;
|
||||
|
||||
dev = ice_pf_to_dev(pf);
|
||||
|
||||
eeprom->magic = hw->vendor_id | (hw->device_id << 16);
|
||||
netdev_dbg(netdev, "GEEPROM cmd 0x%08x, offset 0x%08x, len 0x%08x\n",
|
||||
eeprom->cmd, eeprom->offset, eeprom->len);
|
||||
|
||||
first_word = eeprom->offset >> 1;
|
||||
last_word = (eeprom->offset + eeprom->len - 1) >> 1;
|
||||
nwords = last_word - first_word + 1;
|
||||
|
||||
buf = devm_kcalloc(dev, nwords, sizeof(u16), GFP_KERNEL);
|
||||
buf = kzalloc(eeprom->len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
status = ice_read_sr_buf(hw, first_word, &nwords, buf);
|
||||
status = ice_acquire_nvm(hw, ICE_RES_READ);
|
||||
if (status) {
|
||||
dev_err(dev, "ice_read_sr_buf failed, err %d aq_err %d\n",
|
||||
dev_err(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
|
||||
status, hw->adminq.sq_last_status);
|
||||
eeprom->len = sizeof(u16) * nwords;
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(bytes, (u8 *)buf + (eeprom->offset & 1), eeprom->len);
|
||||
status = ice_read_flat_nvm(hw, eeprom->offset, &eeprom->len, buf,
|
||||
false);
|
||||
if (status) {
|
||||
dev_err(dev, "ice_read_flat_nvm failed, err %d aq_err %d\n",
|
||||
status, hw->adminq.sq_last_status);
|
||||
ret = -EIO;
|
||||
goto release;
|
||||
}
|
||||
|
||||
memcpy(bytes, buf, eeprom->len);
|
||||
release:
|
||||
ice_release_nvm(hw);
|
||||
out:
|
||||
devm_kfree(dev, buf);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "ice_lib.h"
|
||||
#include "ice_dcb_lib.h"
|
||||
#include "ice_dcb_nl.h"
|
||||
#include "ice_devlink.h"
|
||||
|
||||
#define DRV_VERSION_MAJOR 0
|
||||
#define DRV_VERSION_MINOR 8
|
||||
@ -2371,10 +2372,16 @@ static int ice_cfg_netdev(struct ice_vsi *vsi)
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
int err;
|
||||
|
||||
err = ice_devlink_create_port(pf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
netdev = alloc_etherdev_mqs(sizeof(*np), vsi->alloc_txq,
|
||||
vsi->alloc_rxq);
|
||||
if (!netdev)
|
||||
return -ENOMEM;
|
||||
if (!netdev) {
|
||||
err = -ENOMEM;
|
||||
goto err_destroy_devlink_port;
|
||||
}
|
||||
|
||||
vsi->netdev = netdev;
|
||||
np = netdev_priv(netdev);
|
||||
@ -2404,7 +2411,9 @@ static int ice_cfg_netdev(struct ice_vsi *vsi)
|
||||
|
||||
err = register_netdev(vsi->netdev);
|
||||
if (err)
|
||||
return err;
|
||||
goto err_destroy_devlink_port;
|
||||
|
||||
devlink_port_type_eth_set(&pf->devlink_port, vsi->netdev);
|
||||
|
||||
netif_carrier_off(vsi->netdev);
|
||||
|
||||
@ -2412,6 +2421,11 @@ static int ice_cfg_netdev(struct ice_vsi *vsi)
|
||||
netif_tx_stop_all_queues(vsi->netdev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_destroy_devlink_port:
|
||||
ice_devlink_destroy_port(pf);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3184,7 +3198,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
|
||||
return err;
|
||||
}
|
||||
|
||||
pf = devm_kzalloc(dev, sizeof(*pf), GFP_KERNEL);
|
||||
pf = ice_allocate_pf(dev);
|
||||
if (!pf)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -3222,6 +3236,12 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
|
||||
|
||||
pf->msg_enable = netif_msg_init(debug, ICE_DFLT_NETIF_M);
|
||||
|
||||
err = ice_devlink_register(pf);
|
||||
if (err) {
|
||||
dev_err(dev, "ice_devlink_register failed: %d\n", err);
|
||||
goto err_exit_unroll;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DYNAMIC_DEBUG
|
||||
if (debug < -1)
|
||||
hw->debug_mask = debug;
|
||||
@ -3354,6 +3374,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
|
||||
return 0;
|
||||
|
||||
err_alloc_sw_unroll:
|
||||
ice_devlink_destroy_port(pf);
|
||||
set_bit(__ICE_SERVICE_DIS, pf->state);
|
||||
set_bit(__ICE_DOWN, pf->state);
|
||||
devm_kfree(dev, pf->first_sw);
|
||||
@ -3366,6 +3387,7 @@ err_init_pf_unroll:
|
||||
ice_deinit_pf(pf);
|
||||
ice_deinit_hw(hw);
|
||||
err_exit_unroll:
|
||||
ice_devlink_unregister(pf);
|
||||
pci_disable_pcie_error_reporting(pdev);
|
||||
return err;
|
||||
}
|
||||
@ -3396,6 +3418,7 @@ static void ice_remove(struct pci_dev *pdev)
|
||||
set_bit(__ICE_DOWN, pf->state);
|
||||
ice_service_task_stop(pf);
|
||||
|
||||
ice_devlink_destroy_port(pf);
|
||||
ice_vsi_release_all(pf);
|
||||
ice_free_irq_msix_misc(pf);
|
||||
ice_for_each_vsi(pf, i) {
|
||||
@ -3405,6 +3428,8 @@ static void ice_remove(struct pci_dev *pdev)
|
||||
}
|
||||
ice_deinit_pf(pf);
|
||||
ice_deinit_hw(&pf->hw);
|
||||
ice_devlink_unregister(pf);
|
||||
|
||||
/* Issue a PFR as part of the prescribed driver unload flow. Do not
|
||||
* do it via ice_schedule_reset() since there is no need to rebuild
|
||||
* and the service task is already stopped.
|
||||
|
@ -11,25 +11,29 @@
|
||||
* @length: length of the section to be read (in bytes from the offset)
|
||||
* @data: command buffer (size [bytes] = length)
|
||||
* @last_command: tells if this is the last command in a series
|
||||
* @read_shadow_ram: tell if this is a shadow RAM read
|
||||
* @cd: pointer to command details structure or NULL
|
||||
*
|
||||
* Read the NVM using the admin queue commands (0x0701)
|
||||
*/
|
||||
static enum ice_status
|
||||
ice_aq_read_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, u16 length,
|
||||
void *data, bool last_command, struct ice_sq_cd *cd)
|
||||
void *data, bool last_command, bool read_shadow_ram,
|
||||
struct ice_sq_cd *cd)
|
||||
{
|
||||
struct ice_aq_desc desc;
|
||||
struct ice_aqc_nvm *cmd;
|
||||
|
||||
cmd = &desc.params.nvm;
|
||||
|
||||
/* In offset the highest byte must be zeroed. */
|
||||
if (offset & 0xFF000000)
|
||||
if (offset > ICE_AQC_NVM_MAX_OFFSET)
|
||||
return ICE_ERR_PARAM;
|
||||
|
||||
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_read);
|
||||
|
||||
if (!read_shadow_ram && module_typeid == ICE_AQC_NVM_START_POINT)
|
||||
cmd->cmd_flags |= ICE_AQC_NVM_FLASH_ONLY;
|
||||
|
||||
/* If this is the last command in a series, set the proper flag. */
|
||||
if (last_command)
|
||||
cmd->cmd_flags |= ICE_AQC_NVM_LAST_CMD;
|
||||
@ -42,65 +46,64 @@ ice_aq_read_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, u16 length,
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_check_sr_access_params - verify params for Shadow RAM R/W operations.
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset in words from module start
|
||||
* @words: number of words to access
|
||||
*/
|
||||
static enum ice_status
|
||||
ice_check_sr_access_params(struct ice_hw *hw, u32 offset, u16 words)
|
||||
{
|
||||
if ((offset + words) > hw->nvm.sr_words) {
|
||||
ice_debug(hw, ICE_DBG_NVM,
|
||||
"NVM error: offset beyond SR lmt.\n");
|
||||
return ICE_ERR_PARAM;
|
||||
}
|
||||
|
||||
if (words > ICE_SR_SECTOR_SIZE_IN_WORDS) {
|
||||
/* We can access only up to 4KB (one sector), in one AQ write */
|
||||
ice_debug(hw, ICE_DBG_NVM,
|
||||
"NVM error: tried to access %d words, limit is %d.\n",
|
||||
words, ICE_SR_SECTOR_SIZE_IN_WORDS);
|
||||
return ICE_ERR_PARAM;
|
||||
}
|
||||
|
||||
if (((offset + (words - 1)) / ICE_SR_SECTOR_SIZE_IN_WORDS) !=
|
||||
(offset / ICE_SR_SECTOR_SIZE_IN_WORDS)) {
|
||||
/* A single access cannot spread over two sectors */
|
||||
ice_debug(hw, ICE_DBG_NVM,
|
||||
"NVM error: cannot spread over two sectors.\n");
|
||||
return ICE_ERR_PARAM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_read_sr_aq - Read Shadow RAM.
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset in words from module start
|
||||
* @words: number of words to read
|
||||
* @data: buffer for words reads from Shadow RAM
|
||||
* @last_command: tells the AdminQ that this is the last command
|
||||
* ice_read_flat_nvm - Read portion of NVM by flat offset
|
||||
* @hw: pointer to the HW struct
|
||||
* @offset: offset from beginning of NVM
|
||||
* @length: (in) number of bytes to read; (out) number of bytes actually read
|
||||
* @data: buffer to return data in (sized to fit the specified length)
|
||||
* @read_shadow_ram: if true, read from shadow RAM instead of NVM
|
||||
*
|
||||
* Reads 16-bit word buffers from the Shadow RAM using the admin command.
|
||||
* Reads a portion of the NVM, as a flat memory space. This function correctly
|
||||
* breaks read requests across Shadow RAM sectors and ensures that no single
|
||||
* read request exceeds the maximum 4Kb read for a single AdminQ command.
|
||||
*
|
||||
* Returns a status code on failure. Note that the data pointer may be
|
||||
* partially updated if some reads succeed before a failure.
|
||||
*/
|
||||
static enum ice_status
|
||||
ice_read_sr_aq(struct ice_hw *hw, u32 offset, u16 words, u16 *data,
|
||||
bool last_command)
|
||||
enum ice_status
|
||||
ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data,
|
||||
bool read_shadow_ram)
|
||||
{
|
||||
enum ice_status status;
|
||||
u32 inlen = *length;
|
||||
u32 bytes_read = 0;
|
||||
bool last_cmd;
|
||||
|
||||
status = ice_check_sr_access_params(hw, offset, words);
|
||||
*length = 0;
|
||||
|
||||
/* values in "offset" and "words" parameters are sized as words
|
||||
* (16 bits) but ice_aq_read_nvm expects these values in bytes.
|
||||
* So do this conversion while calling ice_aq_read_nvm.
|
||||
*/
|
||||
if (!status)
|
||||
status = ice_aq_read_nvm(hw, 0, 2 * offset, 2 * words, data,
|
||||
last_command, NULL);
|
||||
/* Verify the length of the read if this is for the Shadow RAM */
|
||||
if (read_shadow_ram && ((offset + inlen) > (hw->nvm.sr_words * 2u))) {
|
||||
ice_debug(hw, ICE_DBG_NVM,
|
||||
"NVM error: requested offset is beyond Shadow RAM limit\n");
|
||||
return ICE_ERR_PARAM;
|
||||
}
|
||||
|
||||
do {
|
||||
u32 read_size, sector_offset;
|
||||
|
||||
/* ice_aq_read_nvm cannot read more than 4Kb at a time.
|
||||
* Additionally, a read from the Shadow RAM may not cross over
|
||||
* a sector boundary. Conveniently, the sector size is also
|
||||
* 4Kb.
|
||||
*/
|
||||
sector_offset = offset % ICE_AQ_MAX_BUF_LEN;
|
||||
read_size = min_t(u32, ICE_AQ_MAX_BUF_LEN - sector_offset,
|
||||
inlen - bytes_read);
|
||||
|
||||
last_cmd = !(bytes_read + read_size < inlen);
|
||||
|
||||
status = ice_aq_read_nvm(hw, ICE_AQC_NVM_START_POINT,
|
||||
offset, read_size,
|
||||
data + bytes_read, last_cmd,
|
||||
read_shadow_ram, NULL);
|
||||
if (status)
|
||||
break;
|
||||
|
||||
bytes_read += read_size;
|
||||
offset += read_size;
|
||||
} while (!last_cmd);
|
||||
|
||||
*length = bytes_read;
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -110,75 +113,25 @@ ice_read_sr_aq(struct ice_hw *hw, u32 offset, u16 words, u16 *data,
|
||||
* @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
|
||||
* @data: word read from the Shadow RAM
|
||||
*
|
||||
* Reads one 16 bit word from the Shadow RAM using the ice_read_sr_aq method.
|
||||
* Reads one 16 bit word from the Shadow RAM using ice_read_flat_nvm.
|
||||
*/
|
||||
static enum ice_status
|
||||
ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data)
|
||||
{
|
||||
u32 bytes = sizeof(u16);
|
||||
enum ice_status status;
|
||||
__le16 data_local;
|
||||
|
||||
status = ice_read_sr_aq(hw, offset, 1, data, true);
|
||||
if (!status)
|
||||
*data = le16_to_cpu(*(__force __le16 *)data);
|
||||
/* Note that ice_read_flat_nvm takes into account the 4Kb AdminQ and
|
||||
* Shadow RAM sector restrictions necessary when reading from the NVM.
|
||||
*/
|
||||
status = ice_read_flat_nvm(hw, offset * sizeof(u16), &bytes,
|
||||
(u8 *)&data_local, true);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_read_sr_buf_aq - Reads Shadow RAM buf via AQ
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
|
||||
* @words: (in) number of words to read; (out) number of words actually read
|
||||
* @data: words read from the Shadow RAM
|
||||
*
|
||||
* Reads 16 bit words (data buf) from the SR using the ice_read_sr_aq
|
||||
* method. Ownership of the NVM is taken before reading the buffer and later
|
||||
* released.
|
||||
*/
|
||||
static enum ice_status
|
||||
ice_read_sr_buf_aq(struct ice_hw *hw, u16 offset, u16 *words, u16 *data)
|
||||
{
|
||||
enum ice_status status;
|
||||
bool last_cmd = false;
|
||||
u16 words_read = 0;
|
||||
u16 i = 0;
|
||||
|
||||
do {
|
||||
u16 read_size, off_w;
|
||||
|
||||
/* Calculate number of bytes we should read in this step.
|
||||
* It's not allowed to read more than one page at a time or
|
||||
* to cross page boundaries.
|
||||
*/
|
||||
off_w = offset % ICE_SR_SECTOR_SIZE_IN_WORDS;
|
||||
read_size = off_w ?
|
||||
min_t(u16, *words,
|
||||
(ICE_SR_SECTOR_SIZE_IN_WORDS - off_w)) :
|
||||
min_t(u16, (*words - words_read),
|
||||
ICE_SR_SECTOR_SIZE_IN_WORDS);
|
||||
|
||||
/* Check if this is last command, if so set proper flag */
|
||||
if ((words_read + read_size) >= *words)
|
||||
last_cmd = true;
|
||||
|
||||
status = ice_read_sr_aq(hw, offset, read_size,
|
||||
data + words_read, last_cmd);
|
||||
if (status)
|
||||
goto read_nvm_buf_aq_exit;
|
||||
|
||||
/* Increment counter for words already read and move offset to
|
||||
* new read location
|
||||
*/
|
||||
words_read += read_size;
|
||||
offset += read_size;
|
||||
} while (words_read < *words);
|
||||
|
||||
for (i = 0; i < *words; i++)
|
||||
data[i] = le16_to_cpu(((__force __le16 *)data)[i]);
|
||||
|
||||
read_nvm_buf_aq_exit:
|
||||
*words = words_read;
|
||||
return status;
|
||||
*data = le16_to_cpu(data_local);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,7 +141,7 @@ read_nvm_buf_aq_exit:
|
||||
*
|
||||
* This function will request NVM ownership.
|
||||
*/
|
||||
static enum ice_status
|
||||
enum ice_status
|
||||
ice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access)
|
||||
{
|
||||
if (hw->nvm.blank_nvm_mode)
|
||||
@ -203,7 +156,7 @@ ice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access)
|
||||
*
|
||||
* This function will release NVM ownership.
|
||||
*/
|
||||
static void ice_release_nvm(struct ice_hw *hw)
|
||||
void ice_release_nvm(struct ice_hw *hw)
|
||||
{
|
||||
if (hw->nvm.blank_nvm_mode)
|
||||
return;
|
||||
@ -232,6 +185,239 @@ enum ice_status ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data)
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_get_pfa_module_tlv - Reads sub module TLV from NVM PFA
|
||||
* @hw: pointer to hardware structure
|
||||
* @module_tlv: pointer to module TLV to return
|
||||
* @module_tlv_len: pointer to module TLV length to return
|
||||
* @module_type: module type requested
|
||||
*
|
||||
* Finds the requested sub module TLV type from the Preserved Field
|
||||
* Area (PFA) and returns the TLV pointer and length. The caller can
|
||||
* use these to read the variable length TLV value.
|
||||
*/
|
||||
enum ice_status
|
||||
ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
|
||||
u16 module_type)
|
||||
{
|
||||
enum ice_status status;
|
||||
u16 pfa_len, pfa_ptr;
|
||||
u16 next_tlv;
|
||||
|
||||
status = ice_read_sr_word(hw, ICE_SR_PFA_PTR, &pfa_ptr);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Preserved Field Array pointer.\n");
|
||||
return status;
|
||||
}
|
||||
status = ice_read_sr_word(hw, pfa_ptr, &pfa_len);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read PFA length.\n");
|
||||
return status;
|
||||
}
|
||||
/* Starting with first TLV after PFA length, iterate through the list
|
||||
* of TLVs to find the requested one.
|
||||
*/
|
||||
next_tlv = pfa_ptr + 1;
|
||||
while (next_tlv < pfa_ptr + pfa_len) {
|
||||
u16 tlv_sub_module_type;
|
||||
u16 tlv_len;
|
||||
|
||||
/* Read TLV type */
|
||||
status = ice_read_sr_word(hw, next_tlv, &tlv_sub_module_type);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read TLV type.\n");
|
||||
break;
|
||||
}
|
||||
/* Read TLV length */
|
||||
status = ice_read_sr_word(hw, next_tlv + 1, &tlv_len);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read TLV length.\n");
|
||||
break;
|
||||
}
|
||||
if (tlv_sub_module_type == module_type) {
|
||||
if (tlv_len) {
|
||||
*module_tlv = next_tlv;
|
||||
*module_tlv_len = tlv_len;
|
||||
return 0;
|
||||
}
|
||||
return ICE_ERR_INVAL_SIZE;
|
||||
}
|
||||
/* Check next TLV, i.e. current TLV pointer + length + 2 words
|
||||
* (for current TLV's type and length)
|
||||
*/
|
||||
next_tlv = next_tlv + tlv_len + 2;
|
||||
}
|
||||
/* Module does not exist */
|
||||
return ICE_ERR_DOES_NOT_EXIST;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_read_pba_string - Reads part number string from NVM
|
||||
* @hw: pointer to hardware structure
|
||||
* @pba_num: stores the part number string from the NVM
|
||||
* @pba_num_size: part number string buffer length
|
||||
*
|
||||
* Reads the part number string from the NVM.
|
||||
*/
|
||||
enum ice_status
|
||||
ice_read_pba_string(struct ice_hw *hw, u8 *pba_num, u32 pba_num_size)
|
||||
{
|
||||
u16 pba_tlv, pba_tlv_len;
|
||||
enum ice_status status;
|
||||
u16 pba_word, pba_size;
|
||||
u16 i;
|
||||
|
||||
status = ice_get_pfa_module_tlv(hw, &pba_tlv, &pba_tlv_len,
|
||||
ICE_SR_PBA_BLOCK_PTR);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read PBA Block TLV.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
/* pba_size is the next word */
|
||||
status = ice_read_sr_word(hw, (pba_tlv + 2), &pba_size);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read PBA Section size.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (pba_tlv_len < pba_size) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Invalid PBA Block TLV size.\n");
|
||||
return ICE_ERR_INVAL_SIZE;
|
||||
}
|
||||
|
||||
/* Subtract one to get PBA word count (PBA Size word is included in
|
||||
* total size)
|
||||
*/
|
||||
pba_size--;
|
||||
if (pba_num_size < (((u32)pba_size * 2) + 1)) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Buffer too small for PBA data.\n");
|
||||
return ICE_ERR_PARAM;
|
||||
}
|
||||
|
||||
for (i = 0; i < pba_size; i++) {
|
||||
status = ice_read_sr_word(hw, (pba_tlv + 2 + 1) + i, &pba_word);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read PBA Block word %d.\n", i);
|
||||
return status;
|
||||
}
|
||||
|
||||
pba_num[(i * 2)] = (pba_word >> 8) & 0xFF;
|
||||
pba_num[(i * 2) + 1] = pba_word & 0xFF;
|
||||
}
|
||||
pba_num[(pba_size * 2)] = '\0';
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_get_orom_ver_info - Read Option ROM version information
|
||||
* @hw: pointer to the HW struct
|
||||
*
|
||||
* Read the Combo Image version data from the Boot Configuration TLV and fill
|
||||
* in the option ROM version data.
|
||||
*/
|
||||
static enum ice_status ice_get_orom_ver_info(struct ice_hw *hw)
|
||||
{
|
||||
u16 combo_hi, combo_lo, boot_cfg_tlv, boot_cfg_tlv_len;
|
||||
struct ice_orom_info *orom = &hw->nvm.orom;
|
||||
enum ice_status status;
|
||||
u32 combo_ver;
|
||||
|
||||
status = ice_get_pfa_module_tlv(hw, &boot_cfg_tlv, &boot_cfg_tlv_len,
|
||||
ICE_SR_BOOT_CFG_PTR);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT,
|
||||
"Failed to read Boot Configuration Block TLV.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Boot Configuration Block must have length at least 2 words
|
||||
* (Combo Image Version High and Combo Image Version Low)
|
||||
*/
|
||||
if (boot_cfg_tlv_len < 2) {
|
||||
ice_debug(hw, ICE_DBG_INIT,
|
||||
"Invalid Boot Configuration Block TLV size.\n");
|
||||
return ICE_ERR_INVAL_SIZE;
|
||||
}
|
||||
|
||||
status = ice_read_sr_word(hw, (boot_cfg_tlv + ICE_NVM_OROM_VER_OFF),
|
||||
&combo_hi);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read OROM_VER hi.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = ice_read_sr_word(hw, (boot_cfg_tlv + ICE_NVM_OROM_VER_OFF + 1),
|
||||
&combo_lo);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read OROM_VER lo.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
combo_ver = ((u32)combo_hi << 16) | combo_lo;
|
||||
|
||||
orom->major = (u8)((combo_ver & ICE_OROM_VER_MASK) >>
|
||||
ICE_OROM_VER_SHIFT);
|
||||
orom->patch = (u8)(combo_ver & ICE_OROM_VER_PATCH_MASK);
|
||||
orom->build = (u16)((combo_ver & ICE_OROM_VER_BUILD_MASK) >>
|
||||
ICE_OROM_VER_BUILD_SHIFT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_discover_flash_size - Discover the available flash size.
|
||||
* @hw: pointer to the HW struct
|
||||
*
|
||||
* The device flash could be up to 16MB in size. However, it is possible that
|
||||
* the actual size is smaller. Use bisection to determine the accessible size
|
||||
* of flash memory.
|
||||
*/
|
||||
static enum ice_status ice_discover_flash_size(struct ice_hw *hw)
|
||||
{
|
||||
u32 min_size = 0, max_size = ICE_AQC_NVM_MAX_OFFSET + 1;
|
||||
enum ice_status status;
|
||||
|
||||
status = ice_acquire_nvm(hw, ICE_RES_READ);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
while ((max_size - min_size) > 1) {
|
||||
u32 offset = (max_size + min_size) / 2;
|
||||
u32 len = 1;
|
||||
u8 data;
|
||||
|
||||
status = ice_read_flat_nvm(hw, offset, &len, &data, false);
|
||||
if (status == ICE_ERR_AQ_ERROR &&
|
||||
hw->adminq.sq_last_status == ICE_AQ_RC_EINVAL) {
|
||||
ice_debug(hw, ICE_DBG_NVM,
|
||||
"%s: New upper bound of %u bytes\n",
|
||||
__func__, offset);
|
||||
status = 0;
|
||||
max_size = offset;
|
||||
} else if (!status) {
|
||||
ice_debug(hw, ICE_DBG_NVM,
|
||||
"%s: New lower bound of %u bytes\n",
|
||||
__func__, offset);
|
||||
min_size = offset;
|
||||
} else {
|
||||
/* an unexpected error occurred */
|
||||
goto err_read_flat_nvm;
|
||||
}
|
||||
}
|
||||
|
||||
ice_debug(hw, ICE_DBG_NVM,
|
||||
"Predicted flash size is %u bytes\n", max_size);
|
||||
|
||||
hw->nvm.flash_size = max_size;
|
||||
|
||||
err_read_flat_nvm:
|
||||
ice_release_nvm(hw);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_init_nvm - initializes NVM setting
|
||||
* @hw: pointer to the HW struct
|
||||
@ -241,9 +427,8 @@ enum ice_status ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data)
|
||||
*/
|
||||
enum ice_status ice_init_nvm(struct ice_hw *hw)
|
||||
{
|
||||
u16 oem_hi, oem_lo, boot_cfg_tlv, boot_cfg_tlv_len;
|
||||
struct ice_nvm_info *nvm = &hw->nvm;
|
||||
u16 eetrack_lo, eetrack_hi;
|
||||
u16 eetrack_lo, eetrack_hi, ver;
|
||||
enum ice_status status;
|
||||
u32 fla, gens_stat;
|
||||
u8 sr_size;
|
||||
@ -269,12 +454,14 @@ enum ice_status ice_init_nvm(struct ice_hw *hw)
|
||||
return ICE_ERR_NVM_BLANK_MODE;
|
||||
}
|
||||
|
||||
status = ice_read_sr_word(hw, ICE_SR_NVM_DEV_STARTER_VER, &nvm->ver);
|
||||
status = ice_read_sr_word(hw, ICE_SR_NVM_DEV_STARTER_VER, &ver);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT,
|
||||
"Failed to read DEV starter version.\n");
|
||||
return status;
|
||||
}
|
||||
nvm->major_ver = (ver & ICE_NVM_VER_HI_MASK) >> ICE_NVM_VER_HI_SHIFT;
|
||||
nvm->minor_ver = (ver & ICE_NVM_VER_LO_MASK) >> ICE_NVM_VER_LO_SHIFT;
|
||||
|
||||
status = ice_read_sr_word(hw, ICE_SR_NVM_EETRACK_LO, &eetrack_lo);
|
||||
if (status) {
|
||||
@ -289,6 +476,13 @@ enum ice_status ice_init_nvm(struct ice_hw *hw)
|
||||
|
||||
nvm->eetrack = (eetrack_hi << 16) | eetrack_lo;
|
||||
|
||||
status = ice_discover_flash_size(hw);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_NVM,
|
||||
"NVM init error: failed to discover flash size.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
switch (hw->device_id) {
|
||||
/* the following devices do not have boot_cfg_tlv yet */
|
||||
case ICE_DEV_ID_E823C_BACKPLANE:
|
||||
@ -315,67 +509,15 @@ enum ice_status ice_init_nvm(struct ice_hw *hw)
|
||||
break;
|
||||
}
|
||||
|
||||
status = ice_get_pfa_module_tlv(hw, &boot_cfg_tlv, &boot_cfg_tlv_len,
|
||||
ICE_SR_BOOT_CFG_PTR);
|
||||
status = ice_get_orom_ver_info(hw);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT,
|
||||
"Failed to read Boot Configuration Block TLV.\n");
|
||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read Option ROM info.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Boot Configuration Block must have length at least 2 words
|
||||
* (Combo Image Version High and Combo Image Version Low)
|
||||
*/
|
||||
if (boot_cfg_tlv_len < 2) {
|
||||
ice_debug(hw, ICE_DBG_INIT,
|
||||
"Invalid Boot Configuration Block TLV size.\n");
|
||||
return ICE_ERR_INVAL_SIZE;
|
||||
}
|
||||
|
||||
status = ice_read_sr_word(hw, (boot_cfg_tlv + ICE_NVM_OEM_VER_OFF),
|
||||
&oem_hi);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read OEM_VER hi.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = ice_read_sr_word(hw, (boot_cfg_tlv + ICE_NVM_OEM_VER_OFF + 1),
|
||||
&oem_lo);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_INIT, "Failed to read OEM_VER lo.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
nvm->oem_ver = ((u32)oem_hi << 16) | oem_lo;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_read_sr_buf - Reads Shadow RAM buf and acquire lock if necessary
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
|
||||
* @words: (in) number of words to read; (out) number of words actually read
|
||||
* @data: words read from the Shadow RAM
|
||||
*
|
||||
* Reads 16 bit words (data buf) from the SR using the ice_read_nvm_buf_aq
|
||||
* method. The buf read is preceded by the NVM ownership take
|
||||
* and followed by the release.
|
||||
*/
|
||||
enum ice_status
|
||||
ice_read_sr_buf(struct ice_hw *hw, u16 offset, u16 *words, u16 *data)
|
||||
{
|
||||
enum ice_status status;
|
||||
|
||||
status = ice_acquire_nvm(hw, ICE_RES_READ);
|
||||
if (!status) {
|
||||
status = ice_read_sr_buf_aq(hw, offset, words, data);
|
||||
ice_release_nvm(hw);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_nvm_validate_checksum
|
||||
* @hw: pointer to the HW struct
|
||||
|
@ -4,5 +4,17 @@
|
||||
#ifndef _ICE_NVM_H_
|
||||
#define _ICE_NVM_H_
|
||||
|
||||
enum ice_status
|
||||
ice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access);
|
||||
void ice_release_nvm(struct ice_hw *hw);
|
||||
enum ice_status
|
||||
ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data,
|
||||
bool read_shadow_ram);
|
||||
enum ice_status
|
||||
ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
|
||||
u16 module_type);
|
||||
enum ice_status
|
||||
ice_read_pba_string(struct ice_hw *hw, u8 *pba_num, u32 pba_num_size);
|
||||
enum ice_status ice_init_nvm(struct ice_hw *hw);
|
||||
enum ice_status ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data);
|
||||
#endif /* _ICE_NVM_H_ */
|
||||
|
@ -239,12 +239,21 @@ struct ice_fc_info {
|
||||
enum ice_fc_mode req_mode; /* FC mode requested by caller */
|
||||
};
|
||||
|
||||
/* Option ROM version information */
|
||||
struct ice_orom_info {
|
||||
u8 major; /* Major version of OROM */
|
||||
u8 patch; /* Patch version of OROM */
|
||||
u16 build; /* Build version of OROM */
|
||||
};
|
||||
|
||||
/* NVM Information */
|
||||
struct ice_nvm_info {
|
||||
u32 eetrack; /* NVM data version */
|
||||
u32 oem_ver; /* OEM version info */
|
||||
u16 sr_words; /* Shadow RAM size in words */
|
||||
u16 ver; /* NVM package version */
|
||||
struct ice_orom_info orom; /* Option ROM version info */
|
||||
u32 eetrack; /* NVM data version */
|
||||
u16 sr_words; /* Shadow RAM size in words */
|
||||
u32 flash_size; /* Size of available flash in bytes */
|
||||
u8 major_ver; /* major version of NVM package */
|
||||
u8 minor_ver; /* minor version of dev starter */
|
||||
u8 blank_nvm_mode; /* is NVM empty (no FW present) */
|
||||
};
|
||||
|
||||
@ -626,7 +635,8 @@ struct ice_hw_port_stats {
|
||||
|
||||
/* Checksum and Shadow RAM pointers */
|
||||
#define ICE_SR_BOOT_CFG_PTR 0x132
|
||||
#define ICE_NVM_OEM_VER_OFF 0x02
|
||||
#define ICE_NVM_OROM_VER_OFF 0x02
|
||||
#define ICE_SR_PBA_BLOCK_PTR 0x16
|
||||
#define ICE_SR_NVM_DEV_STARTER_VER 0x18
|
||||
#define ICE_SR_NVM_EETRACK_LO 0x2D
|
||||
#define ICE_SR_NVM_EETRACK_HI 0x2E
|
||||
@ -634,12 +644,12 @@ struct ice_hw_port_stats {
|
||||
#define ICE_NVM_VER_LO_MASK (0xff << ICE_NVM_VER_LO_SHIFT)
|
||||
#define ICE_NVM_VER_HI_SHIFT 12
|
||||
#define ICE_NVM_VER_HI_MASK (0xf << ICE_NVM_VER_HI_SHIFT)
|
||||
#define ICE_OEM_VER_PATCH_SHIFT 0
|
||||
#define ICE_OEM_VER_PATCH_MASK (0xff << ICE_OEM_VER_PATCH_SHIFT)
|
||||
#define ICE_OEM_VER_BUILD_SHIFT 8
|
||||
#define ICE_OEM_VER_BUILD_MASK (0xffff << ICE_OEM_VER_BUILD_SHIFT)
|
||||
#define ICE_OEM_VER_SHIFT 24
|
||||
#define ICE_OEM_VER_MASK (0xff << ICE_OEM_VER_SHIFT)
|
||||
#define ICE_OROM_VER_PATCH_SHIFT 0
|
||||
#define ICE_OROM_VER_PATCH_MASK (0xff << ICE_OROM_VER_PATCH_SHIFT)
|
||||
#define ICE_OROM_VER_BUILD_SHIFT 8
|
||||
#define ICE_OROM_VER_BUILD_MASK (0xffff << ICE_OROM_VER_BUILD_SHIFT)
|
||||
#define ICE_OROM_VER_SHIFT 24
|
||||
#define ICE_OROM_VER_MASK (0xff << ICE_OROM_VER_SHIFT)
|
||||
#define ICE_SR_PFA_PTR 0x40
|
||||
#define ICE_SR_SECTOR_SIZE_IN_WORDS 0x800
|
||||
#define ICE_SR_WORDS_IN_1KB 512
|
||||
|
@ -211,7 +211,7 @@ static const struct nfp_devlink_versions {
|
||||
enum nfp_nsp_versions id;
|
||||
const char *key;
|
||||
} nfp_devlink_versions_nsp[] = {
|
||||
{ NFP_VERSIONS_BUNDLE, "fw.bundle_id", },
|
||||
{ NFP_VERSIONS_BUNDLE, DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID, },
|
||||
{ NFP_VERSIONS_BSP, DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, },
|
||||
{ NFP_VERSIONS_CPLD, "fw.cpld", },
|
||||
{ NFP_VERSIONS_APP, DEVLINK_INFO_VERSION_GENERIC_FW_APP, },
|
||||
|
@ -490,6 +490,8 @@ enum devlink_param_generic_id {
|
||||
#define DEVLINK_INFO_VERSION_GENERIC_FW_PSID "fw.psid"
|
||||
/* RoCE FW version */
|
||||
#define DEVLINK_INFO_VERSION_GENERIC_FW_ROCE "fw.roce"
|
||||
/* Firmware bundle identifier */
|
||||
#define DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID "fw.bundle_id"
|
||||
|
||||
struct devlink_region;
|
||||
struct devlink_info_req;
|
||||
|
Loading…
Reference in New Issue
Block a user