diff mbox series

[03/15] ice: Start hardware initialization

Message ID 20180309172136.9073-4-anirudh.venkataramanan@intel.com
State Changes Requested
Headers show
Series Add ice driver | expand

Commit Message

Anirudh Venkataramanan March 9, 2018, 5:21 p.m. UTC
This patch implements multiple pieces of the initialization flow
as follows:

1) A reset is issued to ensure a clean device state, followed
   by initialization of admin queue interface.

2) Once the admin queue interface is up, clear the PF config
   and transition the device to non-PXE mode.

3) Get the NVM configuration stored in the device's non-volatile
   memory (NVM) using ice_init_nvm.

Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>
---
 drivers/net/ethernet/intel/ice/Makefile         |   3 +-
 drivers/net/ethernet/intel/ice/ice.h            |   2 +
 drivers/net/ethernet/intel/ice/ice_adminq_cmd.h |  79 +++++
 drivers/net/ethernet/intel/ice/ice_common.c     | 410 ++++++++++++++++++++++++
 drivers/net/ethernet/intel/ice/ice_common.h     |  11 +
 drivers/net/ethernet/intel/ice/ice_controlq.h   |   3 +
 drivers/net/ethernet/intel/ice/ice_hw_autogen.h |  30 ++
 drivers/net/ethernet/intel/ice/ice_main.c       |  31 ++
 drivers/net/ethernet/intel/ice/ice_nvm.c        | 245 ++++++++++++++
 drivers/net/ethernet/intel/ice/ice_osdep.h      |   1 +
 drivers/net/ethernet/intel/ice/ice_status.h     |   5 +
 drivers/net/ethernet/intel/ice/ice_type.h       |  49 +++
 12 files changed, 868 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/intel/ice/ice_nvm.c

Comments

Shannon Nelson March 13, 2018, 2:05 a.m. UTC | #1
On 3/9/2018 9:21 AM, Anirudh Venkataramanan wrote:
> This patch implements multiple pieces of the initialization flow
> as follows:
> 
> 1) A reset is issued to ensure a clean device state, followed
>     by initialization of admin queue interface.
> 
> 2) Once the admin queue interface is up, clear the PF config
>     and transition the device to non-PXE mode.
> 
> 3) Get the NVM configuration stored in the device's non-volatile
>     memory (NVM) using ice_init_nvm.
> 
> Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>
> ---
>   drivers/net/ethernet/intel/ice/Makefile         |   3 +-
>   drivers/net/ethernet/intel/ice/ice.h            |   2 +
>   drivers/net/ethernet/intel/ice/ice_adminq_cmd.h |  79 +++++
>   drivers/net/ethernet/intel/ice/ice_common.c     | 410 ++++++++++++++++++++++++
>   drivers/net/ethernet/intel/ice/ice_common.h     |  11 +
>   drivers/net/ethernet/intel/ice/ice_controlq.h   |   3 +
>   drivers/net/ethernet/intel/ice/ice_hw_autogen.h |  30 ++
>   drivers/net/ethernet/intel/ice/ice_main.c       |  31 ++
>   drivers/net/ethernet/intel/ice/ice_nvm.c        | 245 ++++++++++++++
>   drivers/net/ethernet/intel/ice/ice_osdep.h      |   1 +
>   drivers/net/ethernet/intel/ice/ice_status.h     |   5 +
>   drivers/net/ethernet/intel/ice/ice_type.h       |  49 +++
>   12 files changed, 868 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/net/ethernet/intel/ice/ice_nvm.c
> 
> diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile
> index eebf619e84a8..373d481dbb25 100644
> --- a/drivers/net/ethernet/intel/ice/Makefile
> +++ b/drivers/net/ethernet/intel/ice/Makefile
> @@ -26,4 +26,5 @@ obj-$(CONFIG_ICE) += ice.o
>   
>   ice-y := ice_main.o	\
>   	 ice_controlq.o	\
> -	 ice_common.o
> +	 ice_common.o	\
> +	 ice_nvm.o
> diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
> index ea2fb63bb095..ab2800c31906 100644
> --- a/drivers/net/ethernet/intel/ice/ice.h
> +++ b/drivers/net/ethernet/intel/ice/ice.h
> @@ -30,8 +30,10 @@
>   #include <linux/bitmap.h>
>   #include "ice_devids.h"
>   #include "ice_type.h"
> +#include "ice_common.h"
>   
>   #define ICE_BAR0		0
> +#define ICE_AQ_LEN		64
>   
>   #define ICE_DFLT_NETIF_M (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
>   
> diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> index 885fa3c6fec4..05b22a1ffd70 100644
> --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> @@ -50,6 +50,67 @@ struct ice_aqc_q_shutdown {
>   	u8 reserved[12];
>   };
>   
> +/* Request resource ownership (direct 0x0008)
> + * Release resource ownership (direct 0x0009)
> + */
> +struct ice_aqc_req_res {
> +	__le16 res_id;
> +#define ICE_AQC_RES_ID_NVM		1
> +#define ICE_AQC_RES_ID_SDP		2
> +#define ICE_AQC_RES_ID_CHNG_LOCK	3
> +#define ICE_AQC_RES_ID_GLBL_LOCK	4
> +	__le16 access_type;
> +#define ICE_AQC_RES_ACCESS_READ		1
> +#define ICE_AQC_RES_ACCESS_WRITE	2
> +
> +	/* Upon successful completion, FW writes this value and driver is
> +	 * expected to release resource before timeout. This value is provided
> +	 * in milliseconds.
> +	 */
> +	__le32 timeout;
> +#define ICE_AQ_RES_NVM_READ_DFLT_TIMEOUT_MS	3000
> +#define ICE_AQ_RES_NVM_WRITE_DFLT_TIMEOUT_MS	180000
> +#define ICE_AQ_RES_CHNG_LOCK_DFLT_TIMEOUT_MS	1000
> +#define ICE_AQ_RES_GLBL_LOCK_DFLT_TIMEOUT_MS	3000
> +	/* For SDP: pin id of the SDP */
> +	__le32 res_number;
> +	/* Status is only used for ICE_AQC_RES_ID_GLBL_LOCK */
> +	__le16 status;
> +#define ICE_AQ_RES_GLBL_SUCCESS		0
> +#define ICE_AQ_RES_GLBL_IN_PROG		1
> +#define ICE_AQ_RES_GLBL_DONE		2
> +	u8 reserved[2];

Since these structs all become part of the descriptor's param union, 
perhaps adding reserved space to the end is not necessary.

> +};
> +
> +/* Clear PXE Command and response (direct 0x0110) */
> +struct ice_aqc_clear_pxe {
> +	u8 rx_cnt;
> +#define ICE_AQC_CLEAR_PXE_RX_CNT		0x2
> +	u8 reserved[15];
> +};
> +
> +/* NVM Read command (indirect 0x0701)
> + * NVM Erase commands (direct 0x0702)
> + * NVM Update commands (indirect 0x0703)
> + */
> +struct ice_aqc_nvm {
> +	u8	cmd_flags;
> +#define ICE_AQC_NVM_LAST_CMD		BIT(0)
> +#define ICE_AQC_NVM_PCIR_REQ		BIT(0)	/* Used by NVM Update reply */
> +#define ICE_AQC_NVM_PRESERVATION_S	1
> +#define ICE_AQC_NVM_PRESERVATION_M	(3 << CSR_AQ_NVM_PRESERVATION_S)
> +#define ICE_AQC_NVM_NO_PRESERVATION	(0 << CSR_AQ_NVM_PRESERVATION_S)
> +#define ICE_AQC_NVM_PRESERVE_ALL	BIT(1)
> +#define ICE_AQC_NVM_PRESERVE_SELECTED	(3 << CSR_AQ_NVM_PRESERVATION_S)
> +#define ICE_AQC_NVM_FLASH_ONLY		BIT(7)
> +	u8	module_typeid;
> +	__le16	length;
> +#define ICE_AQC_NVM_ERASE_LEN	0xFFFF
> +	__le32	offset;
> +	__le32	addr_high;
> +	__le32	addr_low;
> +};
> +
>   /**
>    * struct ice_aq_desc - Admin Queue (AQ) descriptor
>    * @flags: ICE_AQ_FLAG_* flags
> @@ -79,6 +140,9 @@ struct ice_aq_desc {
>   		struct ice_aqc_generic generic;
>   		struct ice_aqc_get_ver get_ver;
>   		struct ice_aqc_q_shutdown q_shutdown;
> +		struct ice_aqc_req_res res_owner;
> +		struct ice_aqc_clear_pxe clear_pxe;
> +		struct ice_aqc_nvm nvm;
>   	} params;
>   };
>   
> @@ -96,6 +160,8 @@ struct ice_aq_desc {
>   /* error codes */
>   enum ice_aq_err {
>   	ICE_AQ_RC_OK		= 0,  /* success */
> +	ICE_AQ_RC_EBUSY		= 12, /* Device or resource busy */
> +	ICE_AQ_RC_EEXIST	= 13, /* object already exists */

Are we eventually going to get an ENOTTY error value?  :-)

>   };
>   
>   /* Admin Queue command opcodes */
> @@ -103,6 +169,19 @@ enum ice_adminq_opc {
>   	/* AQ commands */
>   	ice_aqc_opc_get_ver				= 0x0001,
>   	ice_aqc_opc_q_shutdown				= 0x0003,
> +
> +	/* resource ownership */
> +	ice_aqc_opc_req_res				= 0x0008,
> +	ice_aqc_opc_release_res				= 0x0009,
> +
> +	/* PXE */
> +	ice_aqc_opc_clear_pxe_mode			= 0x0110,
> +
> +	ice_aqc_opc_clear_pf_cfg			= 0x02A4,
> +
> +	/* NVM commands */
> +	ice_aqc_opc_nvm_read				= 0x0701,
> +
>   };
>   
>   #endif /* _ICE_ADMINQ_CMD_H_ */
> diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
> index d980f0518744..eb3e06488705 100644
> --- a/drivers/net/ethernet/intel/ice/ice_common.c
> +++ b/drivers/net/ethernet/intel/ice/ice_common.c
> @@ -18,6 +18,224 @@
>   #include "ice_common.h"
>   #include "ice_adminq_cmd.h"
>   
> +#define ICE_PF_RESET_WAIT_COUNT	200
> +
> +/**
> + * ice_set_mac_type - Sets MAC type
> + * @hw: pointer to the HW structure
> + *
> + * This function sets the MAC type of the adapter based on the
> + * vendor ID and device ID stored in the hw structure.
> + */
> +static enum ice_status ice_set_mac_type(struct ice_hw *hw)
> +{
> +	if (hw->vendor_id != PCI_VENDOR_ID_INTEL)
> +		return ICE_ERR_DEVICE_NOT_SUPPORTED;
> +
> +	hw->mac_type = ICE_MAC_GENERIC;
> +	return 0;
> +}
> +
> +/**
> + * ice_clear_pf_cfg - Clear PF configuration
> + * @hw: pointer to the hardware structure
> + */
> +enum ice_status ice_clear_pf_cfg(struct ice_hw *hw)
> +{
> +	struct ice_aq_desc desc;
> +
> +	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_clear_pf_cfg);
> +
> +	return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
> +}
> +
> +/**
> + * ice_init_hw - main hardware initialization routine
> + * @hw: pointer to the hardware structure
> + */
> +enum ice_status ice_init_hw(struct ice_hw *hw)
> +{
> +	enum ice_status status;
> +
> +	/* Set MAC type based on DeviceID */
> +	status = ice_set_mac_type(hw);
> +	if (status)
> +		return status;
> +
> +	hw->pf_id = (u8)(rd32(hw, PF_FUNC_RID) &
> +			 PF_FUNC_RID_FUNC_NUM_M) >>
> +		PF_FUNC_RID_FUNC_NUM_S;
> +
> +	status = ice_reset(hw, ICE_RESET_PFR);
> +	if (status)
> +		return status;
> +
> +	status = ice_init_all_ctrlq(hw);
> +	if (status)
> +		goto err_unroll_cqinit;
> +
> +	status = ice_clear_pf_cfg(hw);
> +	if (status)
> +		goto err_unroll_cqinit;
> +
> +	ice_clear_pxe_mode(hw);
> +
> +	status = ice_init_nvm(hw);
> +	if (status)
> +		goto err_unroll_cqinit;
> +
> +	return 0;
> +
> +err_unroll_cqinit:
> +	ice_shutdown_all_ctrlq(hw);
> +	return status;
> +}
> +
> +/**
> + * ice_deinit_hw - unroll initialization operations done by ice_init_hw
> + * @hw: pointer to the hardware structure
> + */
> +void ice_deinit_hw(struct ice_hw *hw)
> +{
> +	ice_shutdown_all_ctrlq(hw);
> +}
> +
> +/**
> + * ice_check_reset - Check to see if a global reset is complete
> + * @hw: pointer to the hardware structure
> + */
> +enum ice_status ice_check_reset(struct ice_hw *hw)
> +{
> +	u32 cnt, reg = 0, grst_delay;
> +
> +	/* Poll for Device Active state in case a recent CORER, GLOBR,
> +	 * or EMPR has occurred. The grst delay value is in 100ms units.
> +	 * Add 1sec for outstanding AQ commands that can take a long time.
> +	 */
> +	grst_delay = ((rd32(hw, GLGEN_RSTCTL) & GLGEN_RSTCTL_GRSTDEL_M) >>
> +		      GLGEN_RSTCTL_GRSTDEL_S) + 10;

Will this be long enough for any longer-running async completion 
commands, maybe for NVM?  Or will that matter?

> +
> +	for (cnt = 0; cnt < grst_delay; cnt++) {
> +		mdelay(100);
> +		reg = rd32(hw, GLGEN_RSTAT);
> +		if (!(reg & GLGEN_RSTAT_DEVSTATE_M))
> +			break;
> +	}
> +
> +	if (cnt == grst_delay) {
> +		ice_debug(hw, ICE_DBG_INIT,
> +			  "Global reset polling failed to complete.\n");
> +		return ICE_ERR_RESET_FAILED;
> +	}
> +
> +#define ICE_RESET_DONE_MASK	(GLNVM_ULD_CORER_DONE_M | \
> +				 GLNVM_ULD_GLOBR_DONE_M)
> +
> +	/* Device is Active; check Global Reset processes are done */
> +	for (cnt = 0; cnt < ICE_PF_RESET_WAIT_COUNT; cnt++) {
> +		reg = rd32(hw, GLNVM_ULD) & ICE_RESET_DONE_MASK;
> +		if (reg == ICE_RESET_DONE_MASK) {
> +			ice_debug(hw, ICE_DBG_INIT,
> +				  "Global reset processes done. %d\n", cnt);
> +			break;
> +		}
> +		mdelay(10);
> +	}
> +
> +	if (cnt == ICE_PF_RESET_WAIT_COUNT) {
> +		ice_debug(hw, ICE_DBG_INIT,
> +			  "Wait for Reset Done timed out. GLNVM_ULD = 0x%x\n",
> +			  reg);
> +		return ICE_ERR_RESET_FAILED;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * ice_pf_reset - Reset the PF
> + * @hw: pointer to the hardware structure
> + *
> + * If a global reset has been triggered, this function checks
> + * for its completion and then issues the PF reset
> + */
> +static enum ice_status ice_pf_reset(struct ice_hw *hw)
> +{
> +	u32 cnt, reg;
> +
> +	/* If at function entry a global reset was already in progress, i.e.
> +	 * state is not 'device active' or any of the reset done bits are not
> +	 * set in GLNVM_ULD, there is no need for a PF Reset; poll until the
> +	 * global reset is done.
> +	 */
> +	if ((rd32(hw, GLGEN_RSTAT) & GLGEN_RSTAT_DEVSTATE_M) ||
> +	    (rd32(hw, GLNVM_ULD) & ICE_RESET_DONE_MASK) ^ ICE_RESET_DONE_MASK) {
> +		/* poll on global reset currently in progress until done */
> +		if (ice_check_reset(hw))
> +			return ICE_ERR_RESET_FAILED;
> +
> +		return 0;
> +	}
> +
> +	/* Reset the PF */
> +	reg = rd32(hw, PFGEN_CTRL);
> +
> +	wr32(hw, PFGEN_CTRL, (reg | PFGEN_CTRL_PFSWR_M));
> +
> +	for (cnt = 0; cnt < ICE_PF_RESET_WAIT_COUNT; cnt++) {
> +		reg = rd32(hw, PFGEN_CTRL);
> +		if (!(reg & PFGEN_CTRL_PFSWR_M))
> +			break;
> +
> +		mdelay(1);
> +	}
> +
> +	if (cnt == ICE_PF_RESET_WAIT_COUNT) {
> +		ice_debug(hw, ICE_DBG_INIT,
> +			  "PF reset polling failed to complete.\n");
> +		return ICE_ERR_RESET_FAILED;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * ice_reset - Perform different types of reset
> + * @hw: pointer to the hardware structure
> + * @req: reset request
> + *
> + * This function triggers a reset as specified by the req parameter.
> + *
> + * Note:
> + * If anything other than a PF reset is triggered, PXE mode is restored.
> + * This has to be cleared using ice_clear_pxe_mode again, once the AQ
> + * interface has been restored in the rebuild flow.
> + */
> +enum ice_status ice_reset(struct ice_hw *hw, enum ice_reset_req req)
> +{
> +	u32 val = 0;
> +
> +	switch (req) {
> +	case ICE_RESET_PFR:
> +		return ice_pf_reset(hw);
> +	case ICE_RESET_CORER:
> +		ice_debug(hw, ICE_DBG_INIT, "CoreR requested\n");
> +		val = GLGEN_RTRIG_CORER_M;
> +		break;
> +	case ICE_RESET_GLOBR:
> +		ice_debug(hw, ICE_DBG_INIT, "GlobalR requested\n");
> +		val = GLGEN_RTRIG_GLOBR_M;
> +		break;
> +	}
> +
> +	val |= rd32(hw, GLGEN_RTRIG);
> +	wr32(hw, GLGEN_RTRIG, val);
> +	ice_flush(hw);
> +
> +	/* wait for the FW to be ready */
> +	return ice_check_reset(hw);
> +}
> +
>   /**
>    * ice_debug_cq
>    * @hw: pointer to the hardware structure
> @@ -142,3 +360,195 @@ enum ice_status ice_aq_q_shutdown(struct ice_hw *hw, bool unloading)
>   
>   	return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
>   }
> +
> +/**
> + * ice_aq_req_res
> + * @hw: pointer to the hw struct
> + * @res: resource id
> + * @access: access type
> + * @sdp_number: resource number
> + * @timeout: the maximum time in ms that the driver may hold the resource
> + * @cd: pointer to command details structure or NULL
> + *
> + * requests common resource using the admin queue commands (0x0008)
> + */
> +static enum ice_status
> +ice_aq_req_res(struct ice_hw *hw, enum ice_aq_res_ids res,
> +	       enum ice_aq_res_access_type access, u8 sdp_number, u32 *timeout,
> +	       struct ice_sq_cd *cd)
> +{
> +	struct ice_aqc_req_res *cmd_resp;
> +	struct ice_aq_desc desc;
> +	enum ice_status status;
> +
> +	cmd_resp = &desc.params.res_owner;
> +
> +	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_req_res);
> +
> +	cmd_resp->res_id = cpu_to_le16(res);
> +	cmd_resp->access_type = cpu_to_le16(access);
> +	cmd_resp->res_number = cpu_to_le32(sdp_number);
> +
> +	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
> +	/* The completion specifies the maximum time in ms that the driver
> +	 * may hold the resource in the Timeout field.
> +	 * If the resource is held by someone else, the command completes with
> +	 * busy return value and the timeout field indicates the maximum time
> +	 * the current owner of the resource has to free it.
> +	 */
> +	if (!status || hw->adminq.sq_last_status == ICE_AQ_RC_EBUSY)
> +		*timeout = le32_to_cpu(cmd_resp->timeout);
> +
> +	return status;
> +}
> +
> +/**
> + * ice_aq_release_res
> + * @hw: pointer to the hw struct
> + * @res: resource id
> + * @sdp_number: resource number
> + * @cd: pointer to command details structure or NULL
> + *
> + * release common resource using the admin queue commands (0x0009)
> + */
> +static enum ice_status
> +ice_aq_release_res(struct ice_hw *hw, enum ice_aq_res_ids res, u8 sdp_number,
> +		   struct ice_sq_cd *cd)
> +{
> +	struct ice_aqc_req_res *cmd;
> +	struct ice_aq_desc desc;
> +
> +	cmd = &desc.params.res_owner;
> +
> +	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_release_res);
> +
> +	cmd->res_id = cpu_to_le16(res);
> +	cmd->res_number = cpu_to_le32(sdp_number);
> +
> +	return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
> +}
> +
> +/**
> + * ice_acquire_res
> + * @hw: pointer to the HW structure
> + * @res: resource id
> + * @access: access type (read or write)
> + *
> + * This function will attempt to acquire the ownership of a resource.
> + */
> +enum ice_status
> +ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,
> +		enum ice_aq_res_access_type access)
> +{
> +#define ICE_RES_POLLING_DELAY_MS	10
> +	u32 delay = ICE_RES_POLLING_DELAY_MS;
> +	enum ice_status status;
> +	u32 time_left = 0;
> +	u32 timeout;
> +
> +	status = ice_aq_req_res(hw, res, access, 0, &time_left, NULL);
> +
> +	/* An admin queue return code of ICE_AQ_RC_EEXIST means that another
> +	 * driver has previously acquired the resource and performed any
> +	 * necessary updates; in this case the caller does not obtain the
> +	 * resource and has no further work to do.
> +	 */
> +	if (hw->adminq.sq_last_status == ICE_AQ_RC_EEXIST) {
> +		status = ICE_ERR_AQ_NO_WORK;
> +		goto ice_acquire_res_exit;
> +	}
> +
> +	if (status)
> +		ice_debug(hw, ICE_DBG_RES,
> +			  "resource %d acquire type %d failed.\n", res, access);
> +
> +	/* If necessary, poll until the current lock owner timeouts */
> +	timeout = time_left;
> +	while (status && timeout && time_left) {
> +		mdelay(delay);
> +		timeout = (timeout > delay) ? timeout - delay : 0;
> +		status = ice_aq_req_res(hw, res, access, 0, &time_left, NULL);
> +
> +		if (hw->adminq.sq_last_status == ICE_AQ_RC_EEXIST) {
> +			/* lock free, but no work to do */
> +			status = ICE_ERR_AQ_NO_WORK;
> +			break;
> +		}
> +
> +		if (!status)
> +			/* lock acquired */
> +			break;
> +	}
> +	if (status && status != ICE_ERR_AQ_NO_WORK)
> +		ice_debug(hw, ICE_DBG_RES, "resource acquire timed out.\n");
> +
> +ice_acquire_res_exit:
> +	if (status == ICE_ERR_AQ_NO_WORK) {
> +		if (access == ICE_RES_WRITE)
> +			ice_debug(hw, ICE_DBG_RES,
> +				  "resource indicates no work to do.\n");
> +		else
> +			ice_debug(hw, ICE_DBG_RES,
> +				  "Warning: ICE_ERR_AQ_NO_WORK not expected\n");
> +	}
> +	return status;
> +}
> +
> +/**
> + * ice_release_res
> + * @hw: pointer to the HW structure
> + * @res: resource id
> + *
> + * This function will release a resource using the proper Admin Command.
> + */
> +void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res)
> +{
> +	enum ice_status status;
> +	u32 total_delay = 0;
> +
> +	status = ice_aq_release_res(hw, res, 0, NULL);
> +
> +	/* there are some rare cases when trying to release the resource
> +	 * results in an admin Q timeout, so handle them correctly
> +	 */
> +	while ((status == ICE_ERR_AQ_TIMEOUT) &&
> +	       (total_delay < hw->adminq.sq_cmd_timeout)) {
> +		mdelay(1);
> +		status = ice_aq_release_res(hw, res, 0, NULL);
> +		total_delay++;
> +	}
> +}
> +
> +/**
> + * ice_aq_clear_pxe_mode
> + * @hw: pointer to the hw struct
> + *
> + * Tell the firmware that the driver is taking over from PXE (0x0110).
> + */
> +static enum ice_status ice_aq_clear_pxe_mode(struct ice_hw *hw)
> +{
> +	struct ice_aq_desc desc;
> +	enum ice_status status;
> +
> +	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_clear_pxe_mode);
> +	desc.params.clear_pxe.rx_cnt = ICE_AQC_CLEAR_PXE_RX_CNT;
> +
> +	status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
> +
> +	wr32(hw, GLLAN_RCTL_0, 0x1);

So you can do this write regardless of the send_cmd() status?

> +
> +	return status;
> +}
> +
> +/**
> + * ice_clear_pxe_mode - clear pxe operations mode
> + * @hw: pointer to the hw struct
> + *
> + * Make sure all PXE mode settings are cleared, including things
> + * like descriptor fetch/write-back mode.
> + */
> +void ice_clear_pxe_mode(struct ice_hw *hw)
> +{
> +	if (ice_check_sq_alive(hw, &hw->adminq))
> +		ice_aq_clear_pxe_mode(hw);
> +}
> diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
> index 1e3caecc38c6..0876fd98090a 100644
> --- a/drivers/net/ethernet/intel/ice/ice_common.h
> +++ b/drivers/net/ethernet/intel/ice/ice_common.h
> @@ -23,12 +23,22 @@
>   
>   void ice_debug_cq(struct ice_hw *hw, u32 mask, void *desc, void *buf,
>   		  u16 buf_len);
> +enum ice_status ice_init_hw(struct ice_hw *hw);
> +void ice_deinit_hw(struct ice_hw *hw);
> +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_init_all_ctrlq(struct ice_hw *hw);
>   void ice_shutdown_all_ctrlq(struct ice_hw *hw);
>   enum ice_status
> +ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,
> +		enum ice_aq_res_access_type access);
> +void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res);
> +enum ice_status ice_init_nvm(struct ice_hw *hw);
> +enum ice_status
>   ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq,
>   		struct ice_aq_desc *desc, void *buf, u16 buf_size,
>   		struct ice_sq_cd *cd);
> +void ice_clear_pxe_mode(struct ice_hw *hw);
>   bool ice_check_sq_alive(struct ice_hw *hw, struct ice_ctl_q_info *cq);
>   enum ice_status ice_aq_q_shutdown(struct ice_hw *hw, bool unloading);
>   void ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16 opcode);
> @@ -36,4 +46,5 @@ enum ice_status
>   ice_aq_send_cmd(struct ice_hw *hw, struct ice_aq_desc *desc,
>   		void *buf, u16 buf_size, struct ice_sq_cd *cd);
>   enum ice_status ice_aq_get_fw_ver(struct ice_hw *hw, struct ice_sq_cd *cd);
> +enum ice_status ice_clear_pf_cfg(struct ice_hw *hw);
>   #endif /* _ICE_COMMON_H_ */
> diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h
> index 143578d02aec..835c035419a3 100644
> --- a/drivers/net/ethernet/intel/ice/ice_controlq.h
> +++ b/drivers/net/ethernet/intel/ice/ice_controlq.h
> @@ -20,6 +20,9 @@
>   
>   #include "ice_adminq_cmd.h"
>   
> +/* Maximum buffer lengths for all control queue types */
> +#define ICE_AQ_MAX_BUF_LEN 4096
> +
>   #define ICE_CTL_Q_DESC(R, i) \
>   	(&(((struct ice_aq_desc *)((R).desc_buf.va))[i]))
>   
> diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
> index 3d6bb273e4c8..e258a12099b8 100644
> --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
> +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
> @@ -42,5 +42,35 @@
>   #define PF_FW_ATQLEN_ATQENABLE_S	31
>   #define PF_FW_ATQLEN_ATQENABLE_M	BIT(PF_FW_ATQLEN_ATQENABLE_S)
>   #define PF_FW_ATQT			0x00080400
> +#define GLGEN_RSTAT			0x000B8188
> +#define GLGEN_RSTAT_DEVSTATE_S		0
> +#define GLGEN_RSTAT_DEVSTATE_M		ICE_M(0x3, GLGEN_RSTAT_DEVSTATE_S)
> +#define GLGEN_RSTCTL			0x000B8180
> +#define GLGEN_RSTCTL_GRSTDEL_S		0
> +#define GLGEN_RSTCTL_GRSTDEL_M		ICE_M(0x3F, GLGEN_RSTCTL_GRSTDEL_S)
> +#define GLGEN_RTRIG			0x000B8190
> +#define GLGEN_RTRIG_CORER_S		0
> +#define GLGEN_RTRIG_CORER_M		BIT(GLGEN_RTRIG_CORER_S)
> +#define GLGEN_RTRIG_GLOBR_S		1
> +#define GLGEN_RTRIG_GLOBR_M		BIT(GLGEN_RTRIG_GLOBR_S)
> +#define GLGEN_STAT			0x000B612C
> +#define PFGEN_CTRL			0x00091000
> +#define PFGEN_CTRL_PFSWR_S		0
> +#define PFGEN_CTRL_PFSWR_M		BIT(PFGEN_CTRL_PFSWR_S)
> +#define GLLAN_RCTL_0			0x002941F8
> +#define GLNVM_FLA			0x000B6108
> +#define GLNVM_FLA_LOCKED_S		6
> +#define GLNVM_FLA_LOCKED_M		BIT(GLNVM_FLA_LOCKED_S)
> +#define GLNVM_GENS			0x000B6100
> +#define GLNVM_GENS_SR_SIZE_S		5
> +#define GLNVM_GENS_SR_SIZE_M		ICE_M(0x7, GLNVM_GENS_SR_SIZE_S)
> +#define GLNVM_ULD			0x000B6008
> +#define GLNVM_ULD_CORER_DONE_S		3
> +#define GLNVM_ULD_CORER_DONE_M		BIT(GLNVM_ULD_CORER_DONE_S)
> +#define GLNVM_ULD_GLOBR_DONE_S		4
> +#define GLNVM_ULD_GLOBR_DONE_M		BIT(GLNVM_ULD_GLOBR_DONE_S)
> +#define PF_FUNC_RID			0x0009E880
> +#define PF_FUNC_RID_FUNC_NUM_S		0
> +#define PF_FUNC_RID_FUNC_NUM_M		ICE_M(0x7, PF_FUNC_RID_FUNC_NUM_S)
>   
>   #endif /* _ICE_HW_AUTOGEN_H_ */
> diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
> index 408ae90d6562..2ee4a0547ba3 100644
> --- a/drivers/net/ethernet/intel/ice/ice_main.c
> +++ b/drivers/net/ethernet/intel/ice/ice_main.c
> @@ -40,6 +40,18 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all), hw debug_mask (0x8XXXX
>   MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
>   #endif /* !CONFIG_DYNAMIC_DEBUG */
>   
> +/**
> + * ice_set_ctrlq_len - helper function to set controlq length
> + * @hw: pointer to the hw instance
> + */
> +static void ice_set_ctrlq_len(struct ice_hw *hw)
> +{
> +	hw->adminq.num_rq_entries = ICE_AQ_LEN;
> +	hw->adminq.num_sq_entries = ICE_AQ_LEN;
> +	hw->adminq.rq_buf_size = ICE_AQ_MAX_BUF_LEN;
> +	hw->adminq.sq_buf_size = ICE_AQ_MAX_BUF_LEN;
> +}
> +
>   /**
>    * ice_probe - Device initialization routine
>    * @pdev: PCI device information struct
> @@ -95,6 +107,8 @@ static int ice_probe(struct pci_dev *pdev,
>   	hw->subsystem_device_id = pdev->subsystem_device;
>   	hw->bus.device = PCI_SLOT(pdev->devfn);
>   	hw->bus.func = PCI_FUNC(pdev->devfn);
> +	ice_set_ctrlq_len(hw);
> +
>   	pf->msg_enable = netif_msg_init(debug, ICE_DFLT_NETIF_M);
>   
>   #ifndef CONFIG_DYNAMIC_DEBUG
> @@ -102,7 +116,22 @@ static int ice_probe(struct pci_dev *pdev,
>   		hw->debug_mask = debug;
>   #endif
>   
> +	err = ice_init_hw(hw);
> +	if (err) {
> +		dev_err(&pdev->dev, "ice_init_hw failed: %d\n", err);
> +		err = -EIO;
> +		goto err_exit_unroll;
> +	}
> +
> +	dev_info(&pdev->dev, "firmware %d.%d.%05d api %d.%d\n",
> +		 hw->fw_maj_ver, hw->fw_min_ver, hw->fw_build,
> +		 hw->api_maj_ver, hw->api_min_ver);
> +
>   	return 0;
> +
> +err_exit_unroll:
> +	pci_disable_pcie_error_reporting(pdev);
> +	return err;
>   }
>   
>   /**
> @@ -117,6 +146,8 @@ static void ice_remove(struct pci_dev *pdev)
>   		return;
>   
>   	set_bit(__ICE_DOWN, pf->state);
> +
> +	ice_deinit_hw(&pf->hw);
>   	pci_disable_pcie_error_reporting(pdev);
>   }
>   
> diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c
> new file mode 100644
> index 000000000000..565910f01290
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ice/ice_nvm.c
> @@ -0,0 +1,245 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Intel(R) Ethernet Connection E800 Series Linux Driver
> + * Copyright (c) 2018, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * The full GNU General Public License is included in this distribution in
> + * the file called "COPYING".
> + */
> +
> +#include "ice_common.h"
> +
> +/**
> + * ice_aq_read_nvm
> + * @hw: pointer to the hw struct
> + * @module_typeid: module pointer location in words from the NVM beginning
> + * @offset: byte offset from the module beginning
> + * @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
> + * @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, u8 module_typeid, u32 offset, u16 length,
> +		void *data, bool last_command, 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)
> +		return ICE_ERR_PARAM;
> +
> +	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_read);
> +
> +	/* If this is the last command in a series, set the proper flag. */
> +	if (last_command)
> +		cmd->cmd_flags |= ICE_AQC_NVM_LAST_CMD;
> +	cmd->module_typeid = module_typeid;
> +	cmd->offset = cpu_to_le32(offset);
> +	cmd->length = cpu_to_le16(length);
> +
> +	return ice_aq_send_cmd(hw, &desc, data, length, cd);
> +}
> +
> +/**
> + * 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
> + *
> + * Reads 16-bit word buffers from the Shadow RAM using the admin command.
> + */
> +static enum ice_status
> +ice_read_sr_aq(struct ice_hw *hw, u32 offset, u16 words, u16 *data,
> +	       bool last_command)
> +{
> +	enum ice_status status;
> +
> +	status = ice_check_sr_access_params(hw, offset, words);
> +	if (!status)
> +		status = ice_aq_read_nvm(hw, 0, 2 * offset, 2 * words, data,

Why the doubling of offset and words?  If this is some general 
adjustment made for the AQ interface, it should be made in 
ice_aq_read_nvm().  If not, then some explanation is needed here.

sln
Anirudh Venkataramanan March 14, 2018, 10:05 p.m. UTC | #2
On Mon, 2018-03-12 at 19:05 -0700, Shannon Nelson wrote:
> On 3/9/2018 9:21 AM, Anirudh Venkataramanan wrote:
> > This patch implements multiple pieces of the initialization flow
> > as follows:
> > 
> > 1) A reset is issued to ensure a clean device state, followed
> >     by initialization of admin queue interface.
> > 
> > 2) Once the admin queue interface is up, clear the PF config
> >     and transition the device to non-PXE mode.
> > 
> > 3) Get the NVM configuration stored in the device's non-volatile
> >     memory (NVM) using ice_init_nvm.
> > 
> > Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel
> > .com>
> > ---
> >   drivers/net/ethernet/intel/ice/Makefile         |   3 +-
> >   drivers/net/ethernet/intel/ice/ice.h            |   2 +
> >   drivers/net/ethernet/intel/ice/ice_adminq_cmd.h |  79 +++++
> >   drivers/net/ethernet/intel/ice/ice_common.c     | 410
> > ++++++++++++++++++++++++
> >   drivers/net/ethernet/intel/ice/ice_common.h     |  11 +
> >   drivers/net/ethernet/intel/ice/ice_controlq.h   |   3 +
> >   drivers/net/ethernet/intel/ice/ice_hw_autogen.h |  30 ++
> >   drivers/net/ethernet/intel/ice/ice_main.c       |  31 ++
> >   drivers/net/ethernet/intel/ice/ice_nvm.c        | 245
> > ++++++++++++++
> >   drivers/net/ethernet/intel/ice/ice_osdep.h      |   1 +
> >   drivers/net/ethernet/intel/ice/ice_status.h     |   5 +
> >   drivers/net/ethernet/intel/ice/ice_type.h       |  49 +++
> >   12 files changed, 868 insertions(+), 1 deletion(-)
> >   create mode 100644 drivers/net/ethernet/intel/ice/ice_nvm.c
> > 
> > diff --git a/drivers/net/ethernet/intel/ice/Makefile
> > b/drivers/net/ethernet/intel/ice/Makefile
> > index eebf619e84a8..373d481dbb25 100644
> > --- a/drivers/net/ethernet/intel/ice/Makefile
> > +++ b/drivers/net/ethernet/intel/ice/Makefile
> > @@ -26,4 +26,5 @@ obj-$(CONFIG_ICE) += ice.o
> >   
> >   ice-y := ice_main.o	\
> >   	 ice_controlq.o	\
> > -	 ice_common.o
> > +	 ice_common.o	\
> > +	 ice_nvm.o
> > diff --git a/drivers/net/ethernet/intel/ice/ice.h
> > b/drivers/net/ethernet/intel/ice/ice.h
> > index ea2fb63bb095..ab2800c31906 100644
> > --- a/drivers/net/ethernet/intel/ice/ice.h
> > +++ b/drivers/net/ethernet/intel/ice/ice.h
> > @@ -30,8 +30,10 @@
> >   #include <linux/bitmap.h>
> >   #include "ice_devids.h"
> >   #include "ice_type.h"
> > +#include "ice_common.h"
> >   
> >   #define ICE_BAR0		0
> > +#define ICE_AQ_LEN		64
> >   
> >   #define ICE_DFLT_NETIF_M (NETIF_MSG_DRV | NETIF_MSG_PROBE |
> > NETIF_MSG_LINK)
> >   
> > diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> > b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> > index 885fa3c6fec4..05b22a1ffd70 100644
> > --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> > +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> > @@ -50,6 +50,67 @@ struct ice_aqc_q_shutdown {
> >   	u8 reserved[12];
> >   };
> >   
> > +/* Request resource ownership (direct 0x0008)
> > + * Release resource ownership (direct 0x0009)
> > + */
> > +struct ice_aqc_req_res {
> > +	__le16 res_id;
> > +#define ICE_AQC_RES_ID_NVM		1
> > +#define ICE_AQC_RES_ID_SDP		2
> > +#define ICE_AQC_RES_ID_CHNG_LOCK	3
> > +#define ICE_AQC_RES_ID_GLBL_LOCK	4
> > +	__le16 access_type;
> > +#define ICE_AQC_RES_ACCESS_READ		1
> > +#define ICE_AQC_RES_ACCESS_WRITE	2
> > +
> > +	/* Upon successful completion, FW writes this value and
> > driver is
> > +	 * expected to release resource before timeout. This value
> > is provided
> > +	 * in milliseconds.
> > +	 */
> > +	__le32 timeout;
> > +#define ICE_AQ_RES_NVM_READ_DFLT_TIMEOUT_MS	3000
> > +#define ICE_AQ_RES_NVM_WRITE_DFLT_TIMEOUT_MS	180000
> > +#define ICE_AQ_RES_CHNG_LOCK_DFLT_TIMEOUT_MS	1000
> > +#define ICE_AQ_RES_GLBL_LOCK_DFLT_TIMEOUT_MS	3000
> > +	/* For SDP: pin id of the SDP */
> > +	__le32 res_number;
> > +	/* Status is only used for ICE_AQC_RES_ID_GLBL_LOCK */
> > +	__le16 status;
> > +#define ICE_AQ_RES_GLBL_SUCCESS		0
> > +#define ICE_AQ_RES_GLBL_IN_PROG		1
> > +#define ICE_AQ_RES_GLBL_DONE		2
> > +	u8 reserved[2];
> 
> Since these structs all become part of the descriptor's param union, 
> perhaps adding reserved space to the end is not necessary.
> 
> > +};
> > +
> > +/* Clear PXE Command and response (direct 0x0110) */
> > +struct ice_aqc_clear_pxe {
> > +	u8 rx_cnt;
> > +#define ICE_AQC_CLEAR_PXE_RX_CNT		0x2
> > +	u8 reserved[15];
> > +};
> > +
> > +/* NVM Read command (indirect 0x0701)
> > + * NVM Erase commands (direct 0x0702)
> > + * NVM Update commands (indirect 0x0703)
> > + */
> > +struct ice_aqc_nvm {
> > +	u8	cmd_flags;
> > +#define ICE_AQC_NVM_LAST_CMD		BIT(0)
> > +#define ICE_AQC_NVM_PCIR_REQ		BIT(0)	/* Used
> > by NVM Update reply */
> > +#define ICE_AQC_NVM_PRESERVATION_S	1
> > +#define ICE_AQC_NVM_PRESERVATION_M	(3 <<
> > CSR_AQ_NVM_PRESERVATION_S)
> > +#define ICE_AQC_NVM_NO_PRESERVATION	(0 <<
> > CSR_AQ_NVM_PRESERVATION_S)
> > +#define ICE_AQC_NVM_PRESERVE_ALL	BIT(1)
> > +#define ICE_AQC_NVM_PRESERVE_SELECTED	(3 <<
> > CSR_AQ_NVM_PRESERVATION_S)
> > +#define ICE_AQC_NVM_FLASH_ONLY		BIT(7)
> > +	u8	module_typeid;
> > +	__le16	length;
> > +#define ICE_AQC_NVM_ERASE_LEN	0xFFFF
> > +	__le32	offset;
> > +	__le32	addr_high;
> > +	__le32	addr_low;
> > +};
> > +
> >   /**
> >    * struct ice_aq_desc - Admin Queue (AQ) descriptor
> >    * @flags: ICE_AQ_FLAG_* flags
> > @@ -79,6 +140,9 @@ struct ice_aq_desc {
> >   		struct ice_aqc_generic generic;
> >   		struct ice_aqc_get_ver get_ver;
> >   		struct ice_aqc_q_shutdown q_shutdown;
> > +		struct ice_aqc_req_res res_owner;
> > +		struct ice_aqc_clear_pxe clear_pxe;
> > +		struct ice_aqc_nvm nvm;
> >   	} params;
> >   };
> >   
> > @@ -96,6 +160,8 @@ struct ice_aq_desc {
> >   /* error codes */
> >   enum ice_aq_err {
> >   	ICE_AQ_RC_OK		= 0,  /* success */
> > +	ICE_AQ_RC_EBUSY		= 12, /* Device or resource
> > busy */
> > +	ICE_AQ_RC_EEXIST	= 13, /* object already exists */
> 
> Are we eventually going to get an ENOTTY error value?  :-)
> 
> >   };
> >   
> >   /* Admin Queue command opcodes */
> > @@ -103,6 +169,19 @@ enum ice_adminq_opc {
> >   	/* AQ commands */
> >   	ice_aqc_opc_get_ver				=
> > 0x0001,
> >   	ice_aqc_opc_q_shutdown				=
> > 0x0003,
> > +
> > +	/* resource ownership */
> > +	ice_aqc_opc_req_res				=
> > 0x0008,
> > +	ice_aqc_opc_release_res				=
> > 0x0009,
> > +
> > +	/* PXE */
> > +	ice_aqc_opc_clear_pxe_mode			=
> > 0x0110,
> > +
> > +	ice_aqc_opc_clear_pf_cfg			= 0x02A4,
> > +
> > +	/* NVM commands */
> > +	ice_aqc_opc_nvm_read				=
> > 0x0701,
> > +
> >   };
> >   
> >   #endif /* _ICE_ADMINQ_CMD_H_ */
> > diff --git a/drivers/net/ethernet/intel/ice/ice_common.c
> > b/drivers/net/ethernet/intel/ice/ice_common.c
> > index d980f0518744..eb3e06488705 100644
> > --- a/drivers/net/ethernet/intel/ice/ice_common.c
> > +++ b/drivers/net/ethernet/intel/ice/ice_common.c
> > @@ -18,6 +18,224 @@
> >   #include "ice_common.h"
> >   #include "ice_adminq_cmd.h"
> >   
> > +#define ICE_PF_RESET_WAIT_COUNT	200
> > +
> > +/**
> > + * ice_set_mac_type - Sets MAC type
> > + * @hw: pointer to the HW structure
> > + *
> > + * This function sets the MAC type of the adapter based on the
> > + * vendor ID and device ID stored in the hw structure.
> > + */
> > +static enum ice_status ice_set_mac_type(struct ice_hw *hw)
> > +{
> > +	if (hw->vendor_id != PCI_VENDOR_ID_INTEL)
> > +		return ICE_ERR_DEVICE_NOT_SUPPORTED;
> > +
> > +	hw->mac_type = ICE_MAC_GENERIC;
> > +	return 0;
> > +}
> > +
> > +/**
> > + * ice_clear_pf_cfg - Clear PF configuration
> > + * @hw: pointer to the hardware structure
> > + */
> > +enum ice_status ice_clear_pf_cfg(struct ice_hw *hw)
> > +{
> > +	struct ice_aq_desc desc;
> > +
> > +	ice_fill_dflt_direct_cmd_desc(&desc,
> > ice_aqc_opc_clear_pf_cfg);
> > +
> > +	return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
> > +}
> > +
> > +/**
> > + * ice_init_hw - main hardware initialization routine
> > + * @hw: pointer to the hardware structure
> > + */
> > +enum ice_status ice_init_hw(struct ice_hw *hw)
> > +{
> > +	enum ice_status status;
> > +
> > +	/* Set MAC type based on DeviceID */
> > +	status = ice_set_mac_type(hw);
> > +	if (status)
> > +		return status;
> > +
> > +	hw->pf_id = (u8)(rd32(hw, PF_FUNC_RID) &
> > +			 PF_FUNC_RID_FUNC_NUM_M) >>
> > +		PF_FUNC_RID_FUNC_NUM_S;
> > +
> > +	status = ice_reset(hw, ICE_RESET_PFR);
> > +	if (status)
> > +		return status;
> > +
> > +	status = ice_init_all_ctrlq(hw);
> > +	if (status)
> > +		goto err_unroll_cqinit;
> > +
> > +	status = ice_clear_pf_cfg(hw);
> > +	if (status)
> > +		goto err_unroll_cqinit;
> > +
> > +	ice_clear_pxe_mode(hw);
> > +
> > +	status = ice_init_nvm(hw);
> > +	if (status)
> > +		goto err_unroll_cqinit;
> > +
> > +	return 0;
> > +
> > +err_unroll_cqinit:
> > +	ice_shutdown_all_ctrlq(hw);
> > +	return status;
> > +}
> > +
> > +/**
> > + * ice_deinit_hw - unroll initialization operations done by
> > ice_init_hw
> > + * @hw: pointer to the hardware structure
> > + */
> > +void ice_deinit_hw(struct ice_hw *hw)
> > +{
> > +	ice_shutdown_all_ctrlq(hw);
> > +}
> > +
> > +/**
> > + * ice_check_reset - Check to see if a global reset is complete
> > + * @hw: pointer to the hardware structure
> > + */
> > +enum ice_status ice_check_reset(struct ice_hw *hw)
> > +{
> > +	u32 cnt, reg = 0, grst_delay;
> > +
> > +	/* Poll for Device Active state in case a recent CORER,
> > GLOBR,
> > +	 * or EMPR has occurred. The grst delay value is in 100ms
> > units.
> > +	 * Add 1sec for outstanding AQ commands that can take a
> > long time.
> > +	 */
> > +	grst_delay = ((rd32(hw, GLGEN_RSTCTL) &
> > GLGEN_RSTCTL_GRSTDEL_M) >>
> > +		      GLGEN_RSTCTL_GRSTDEL_S) + 10;
> 
> Will this be long enough for any longer-running async completion 
> commands, maybe for NVM?  Or will that matter?
> 
> > +
> > +	for (cnt = 0; cnt < grst_delay; cnt++) {
> > +		mdelay(100);
> > +		reg = rd32(hw, GLGEN_RSTAT);
> > +		if (!(reg & GLGEN_RSTAT_DEVSTATE_M))
> > +			break;
> > +	}
> > +
> > +	if (cnt == grst_delay) {
> > +		ice_debug(hw, ICE_DBG_INIT,
> > +			  "Global reset polling failed to
> > complete.\n");
> > +		return ICE_ERR_RESET_FAILED;
> > +	}
> > +
> > +#define ICE_RESET_DONE_MASK	(GLNVM_ULD_CORER_DONE_M | \
> > +				 GLNVM_ULD_GLOBR_DONE_M)
> > +
> > +	/* Device is Active; check Global Reset processes are done
> > */
> > +	for (cnt = 0; cnt < ICE_PF_RESET_WAIT_COUNT; cnt++) {
> > +		reg = rd32(hw, GLNVM_ULD) & ICE_RESET_DONE_MASK;
> > +		if (reg == ICE_RESET_DONE_MASK) {
> > +			ice_debug(hw, ICE_DBG_INIT,
> > +				  "Global reset processes done.
> > %d\n", cnt);
> > +			break;
> > +		}
> > +		mdelay(10);
> > +	}
> > +
> > +	if (cnt == ICE_PF_RESET_WAIT_COUNT) {
> > +		ice_debug(hw, ICE_DBG_INIT,
> > +			  "Wait for Reset Done timed out.
> > GLNVM_ULD = 0x%x\n",
> > +			  reg);
> > +		return ICE_ERR_RESET_FAILED;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * ice_pf_reset - Reset the PF
> > + * @hw: pointer to the hardware structure
> > + *
> > + * If a global reset has been triggered, this function checks
> > + * for its completion and then issues the PF reset
> > + */
> > +static enum ice_status ice_pf_reset(struct ice_hw *hw)
> > +{
> > +	u32 cnt, reg;
> > +
> > +	/* If at function entry a global reset was already in
> > progress, i.e.
> > +	 * state is not 'device active' or any of the reset done
> > bits are not
> > +	 * set in GLNVM_ULD, there is no need for a PF Reset; poll
> > until the
> > +	 * global reset is done.
> > +	 */
> > +	if ((rd32(hw, GLGEN_RSTAT) & GLGEN_RSTAT_DEVSTATE_M) ||
> > +	    (rd32(hw, GLNVM_ULD) & ICE_RESET_DONE_MASK) ^
> > ICE_RESET_DONE_MASK) {
> > +		/* poll on global reset currently in progress
> > until done */
> > +		if (ice_check_reset(hw))
> > +			return ICE_ERR_RESET_FAILED;
> > +
> > +		return 0;
> > +	}
> > +
> > +	/* Reset the PF */
> > +	reg = rd32(hw, PFGEN_CTRL);
> > +
> > +	wr32(hw, PFGEN_CTRL, (reg | PFGEN_CTRL_PFSWR_M));
> > +
> > +	for (cnt = 0; cnt < ICE_PF_RESET_WAIT_COUNT; cnt++) {
> > +		reg = rd32(hw, PFGEN_CTRL);
> > +		if (!(reg & PFGEN_CTRL_PFSWR_M))
> > +			break;
> > +
> > +		mdelay(1);
> > +	}
> > +
> > +	if (cnt == ICE_PF_RESET_WAIT_COUNT) {
> > +		ice_debug(hw, ICE_DBG_INIT,
> > +			  "PF reset polling failed to
> > complete.\n");
> > +		return ICE_ERR_RESET_FAILED;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * ice_reset - Perform different types of reset
> > + * @hw: pointer to the hardware structure
> > + * @req: reset request
> > + *
> > + * This function triggers a reset as specified by the req
> > parameter.
> > + *
> > + * Note:
> > + * If anything other than a PF reset is triggered, PXE mode is
> > restored.
> > + * This has to be cleared using ice_clear_pxe_mode again, once the
> > AQ
> > + * interface has been restored in the rebuild flow.
> > + */
> > +enum ice_status ice_reset(struct ice_hw *hw, enum ice_reset_req
> > req)
> > +{
> > +	u32 val = 0;
> > +
> > +	switch (req) {
> > +	case ICE_RESET_PFR:
> > +		return ice_pf_reset(hw);
> > +	case ICE_RESET_CORER:
> > +		ice_debug(hw, ICE_DBG_INIT, "CoreR requested\n");
> > +		val = GLGEN_RTRIG_CORER_M;
> > +		break;
> > +	case ICE_RESET_GLOBR:
> > +		ice_debug(hw, ICE_DBG_INIT, "GlobalR
> > requested\n");
> > +		val = GLGEN_RTRIG_GLOBR_M;
> > +		break;
> > +	}
> > +
> > +	val |= rd32(hw, GLGEN_RTRIG);
> > +	wr32(hw, GLGEN_RTRIG, val);
> > +	ice_flush(hw);
> > +
> > +	/* wait for the FW to be ready */
> > +	return ice_check_reset(hw);
> > +}
> > +
> >   /**
> >    * ice_debug_cq
> >    * @hw: pointer to the hardware structure
> > @@ -142,3 +360,195 @@ enum ice_status ice_aq_q_shutdown(struct
> > ice_hw *hw, bool unloading)
> >   
> >   	return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
> >   }
> > +
> > +/**
> > + * ice_aq_req_res
> > + * @hw: pointer to the hw struct
> > + * @res: resource id
> > + * @access: access type
> > + * @sdp_number: resource number
> > + * @timeout: the maximum time in ms that the driver may hold the
> > resource
> > + * @cd: pointer to command details structure or NULL
> > + *
> > + * requests common resource using the admin queue commands
> > (0x0008)
> > + */
> > +static enum ice_status
> > +ice_aq_req_res(struct ice_hw *hw, enum ice_aq_res_ids res,
> > +	       enum ice_aq_res_access_type access, u8 sdp_number,
> > u32 *timeout,
> > +	       struct ice_sq_cd *cd)
> > +{
> > +	struct ice_aqc_req_res *cmd_resp;
> > +	struct ice_aq_desc desc;
> > +	enum ice_status status;
> > +
> > +	cmd_resp = &desc.params.res_owner;
> > +
> > +	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_req_res);
> > +
> > +	cmd_resp->res_id = cpu_to_le16(res);
> > +	cmd_resp->access_type = cpu_to_le16(access);
> > +	cmd_resp->res_number = cpu_to_le32(sdp_number);
> > +
> > +	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
> > +	/* The completion specifies the maximum time in ms that
> > the driver
> > +	 * may hold the resource in the Timeout field.
> > +	 * If the resource is held by someone else, the command
> > completes with
> > +	 * busy return value and the timeout field indicates the
> > maximum time
> > +	 * the current owner of the resource has to free it.
> > +	 */
> > +	if (!status || hw->adminq.sq_last_status ==
> > ICE_AQ_RC_EBUSY)
> > +		*timeout = le32_to_cpu(cmd_resp->timeout);
> > +
> > +	return status;
> > +}
> > +
> > +/**
> > + * ice_aq_release_res
> > + * @hw: pointer to the hw struct
> > + * @res: resource id
> > + * @sdp_number: resource number
> > + * @cd: pointer to command details structure or NULL
> > + *
> > + * release common resource using the admin queue commands (0x0009)
> > + */
> > +static enum ice_status
> > +ice_aq_release_res(struct ice_hw *hw, enum ice_aq_res_ids res, u8
> > sdp_number,
> > +		   struct ice_sq_cd *cd)
> > +{
> > +	struct ice_aqc_req_res *cmd;
> > +	struct ice_aq_desc desc;
> > +
> > +	cmd = &desc.params.res_owner;
> > +
> > +	ice_fill_dflt_direct_cmd_desc(&desc,
> > ice_aqc_opc_release_res);
> > +
> > +	cmd->res_id = cpu_to_le16(res);
> > +	cmd->res_number = cpu_to_le32(sdp_number);
> > +
> > +	return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
> > +}
> > +
> > +/**
> > + * ice_acquire_res
> > + * @hw: pointer to the HW structure
> > + * @res: resource id
> > + * @access: access type (read or write)
> > + *
> > + * This function will attempt to acquire the ownership of a
> > resource.
> > + */
> > +enum ice_status
> > +ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,
> > +		enum ice_aq_res_access_type access)
> > +{
> > +#define ICE_RES_POLLING_DELAY_MS	10
> > +	u32 delay = ICE_RES_POLLING_DELAY_MS;
> > +	enum ice_status status;
> > +	u32 time_left = 0;
> > +	u32 timeout;
> > +
> > +	status = ice_aq_req_res(hw, res, access, 0, &time_left,
> > NULL);
> > +
> > +	/* An admin queue return code of ICE_AQ_RC_EEXIST means
> > that another
> > +	 * driver has previously acquired the resource and
> > performed any
> > +	 * necessary updates; in this case the caller does not
> > obtain the
> > +	 * resource and has no further work to do.
> > +	 */
> > +	if (hw->adminq.sq_last_status == ICE_AQ_RC_EEXIST) {
> > +		status = ICE_ERR_AQ_NO_WORK;
> > +		goto ice_acquire_res_exit;
> > +	}
> > +
> > +	if (status)
> > +		ice_debug(hw, ICE_DBG_RES,
> > +			  "resource %d acquire type %d failed.\n",
> > res, access);
> > +
> > +	/* If necessary, poll until the current lock owner
> > timeouts */
> > +	timeout = time_left;
> > +	while (status && timeout && time_left) {
> > +		mdelay(delay);
> > +		timeout = (timeout > delay) ? timeout - delay : 0;
> > +		status = ice_aq_req_res(hw, res, access, 0,
> > &time_left, NULL);
> > +
> > +		if (hw->adminq.sq_last_status == ICE_AQ_RC_EEXIST)
> > {
> > +			/* lock free, but no work to do */
> > +			status = ICE_ERR_AQ_NO_WORK;
> > +			break;
> > +		}
> > +
> > +		if (!status)
> > +			/* lock acquired */
> > +			break;
> > +	}
> > +	if (status && status != ICE_ERR_AQ_NO_WORK)
> > +		ice_debug(hw, ICE_DBG_RES, "resource acquire timed
> > out.\n");
> > +
> > +ice_acquire_res_exit:
> > +	if (status == ICE_ERR_AQ_NO_WORK) {
> > +		if (access == ICE_RES_WRITE)
> > +			ice_debug(hw, ICE_DBG_RES,
> > +				  "resource indicates no work to
> > do.\n");
> > +		else
> > +			ice_debug(hw, ICE_DBG_RES,
> > +				  "Warning: ICE_ERR_AQ_NO_WORK not
> > expected\n");
> > +	}
> > +	return status;
> > +}
> > +
> > +/**
> > + * ice_release_res
> > + * @hw: pointer to the HW structure
> > + * @res: resource id
> > + *
> > + * This function will release a resource using the proper Admin
> > Command.
> > + */
> > +void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res)
> > +{
> > +	enum ice_status status;
> > +	u32 total_delay = 0;
> > +
> > +	status = ice_aq_release_res(hw, res, 0, NULL);
> > +
> > +	/* there are some rare cases when trying to release the
> > resource
> > +	 * results in an admin Q timeout, so handle them correctly
> > +	 */
> > +	while ((status == ICE_ERR_AQ_TIMEOUT) &&
> > +	       (total_delay < hw->adminq.sq_cmd_timeout)) {
> > +		mdelay(1);
> > +		status = ice_aq_release_res(hw, res, 0, NULL);
> > +		total_delay++;
> > +	}
> > +}
> > +
> > +/**
> > + * ice_aq_clear_pxe_mode
> > + * @hw: pointer to the hw struct
> > + *
> > + * Tell the firmware that the driver is taking over from PXE
> > (0x0110).
> > + */
> > +static enum ice_status ice_aq_clear_pxe_mode(struct ice_hw *hw)
> > +{
> > +	struct ice_aq_desc desc;
> > +	enum ice_status status;
> > +
> > +	ice_fill_dflt_direct_cmd_desc(&desc,
> > ice_aqc_opc_clear_pxe_mode);
> > +	desc.params.clear_pxe.rx_cnt = ICE_AQC_CLEAR_PXE_RX_CNT;
> > +
> > +	status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
> > +
> > +	wr32(hw, GLLAN_RCTL_0, 0x1);
> 
> So you can do this write regardless of the send_cmd() status?
> 
> > +
> > +	return status;
> > +}
> > +
> > +/**
> > + * ice_clear_pxe_mode - clear pxe operations mode
> > + * @hw: pointer to the hw struct
> > + *
> > + * Make sure all PXE mode settings are cleared, including things
> > + * like descriptor fetch/write-back mode.
> > + */
> > +void ice_clear_pxe_mode(struct ice_hw *hw)
> > +{
> > +	if (ice_check_sq_alive(hw, &hw->adminq))
> > +		ice_aq_clear_pxe_mode(hw);
> > +}
> > diff --git a/drivers/net/ethernet/intel/ice/ice_common.h
> > b/drivers/net/ethernet/intel/ice/ice_common.h
> > index 1e3caecc38c6..0876fd98090a 100644
> > --- a/drivers/net/ethernet/intel/ice/ice_common.h
> > +++ b/drivers/net/ethernet/intel/ice/ice_common.h
> > @@ -23,12 +23,22 @@
> >   
> >   void ice_debug_cq(struct ice_hw *hw, u32 mask, void *desc, void
> > *buf,
> >   		  u16 buf_len);
> > +enum ice_status ice_init_hw(struct ice_hw *hw);
> > +void ice_deinit_hw(struct ice_hw *hw);
> > +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_init_all_ctrlq(struct ice_hw *hw);
> >   void ice_shutdown_all_ctrlq(struct ice_hw *hw);
> >   enum ice_status
> > +ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,
> > +		enum ice_aq_res_access_type access);
> > +void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res);
> > +enum ice_status ice_init_nvm(struct ice_hw *hw);
> > +enum ice_status
> >   ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq,
> >   		struct ice_aq_desc *desc, void *buf, u16
> > buf_size,
> >   		struct ice_sq_cd *cd);
> > +void ice_clear_pxe_mode(struct ice_hw *hw);
> >   bool ice_check_sq_alive(struct ice_hw *hw, struct ice_ctl_q_info
> > *cq);
> >   enum ice_status ice_aq_q_shutdown(struct ice_hw *hw, bool
> > unloading);
> >   void ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16
> > opcode);
> > @@ -36,4 +46,5 @@ enum ice_status
> >   ice_aq_send_cmd(struct ice_hw *hw, struct ice_aq_desc *desc,
> >   		void *buf, u16 buf_size, struct ice_sq_cd *cd);
> >   enum ice_status ice_aq_get_fw_ver(struct ice_hw *hw, struct
> > ice_sq_cd *cd);
> > +enum ice_status ice_clear_pf_cfg(struct ice_hw *hw);
> >   #endif /* _ICE_COMMON_H_ */
> > diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h
> > b/drivers/net/ethernet/intel/ice/ice_controlq.h
> > index 143578d02aec..835c035419a3 100644
> > --- a/drivers/net/ethernet/intel/ice/ice_controlq.h
> > +++ b/drivers/net/ethernet/intel/ice/ice_controlq.h
> > @@ -20,6 +20,9 @@
> >   
> >   #include "ice_adminq_cmd.h"
> >   
> > +/* Maximum buffer lengths for all control queue types */
> > +#define ICE_AQ_MAX_BUF_LEN 4096
> > +
> >   #define ICE_CTL_Q_DESC(R, i) \
> >   	(&(((struct ice_aq_desc *)((R).desc_buf.va))[i]))
> >   
> > diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
> > b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
> > index 3d6bb273e4c8..e258a12099b8 100644
> > --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
> > +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
> > @@ -42,5 +42,35 @@
> >   #define PF_FW_ATQLEN_ATQENABLE_S	31
> >   #define PF_FW_ATQLEN_ATQENABLE_M	BIT(PF_FW_ATQLEN_ATQENABL
> > E_S)
> >   #define PF_FW_ATQT			0x00080400
> > +#define GLGEN_RSTAT			0x000B8188
> > +#define GLGEN_RSTAT_DEVSTATE_S		0
> > +#define GLGEN_RSTAT_DEVSTATE_M		ICE_M(0x3,
> > GLGEN_RSTAT_DEVSTATE_S)
> > +#define GLGEN_RSTCTL			0x000B8180
> > +#define GLGEN_RSTCTL_GRSTDEL_S		0
> > +#define GLGEN_RSTCTL_GRSTDEL_M		ICE_M(0x3F,
> > GLGEN_RSTCTL_GRSTDEL_S)
> > +#define GLGEN_RTRIG			0x000B8190
> > +#define GLGEN_RTRIG_CORER_S		0
> > +#define GLGEN_RTRIG_CORER_M		BIT(GLGEN_RTRIG_CORER_S
> > )
> > +#define GLGEN_RTRIG_GLOBR_S		1
> > +#define GLGEN_RTRIG_GLOBR_M		BIT(GLGEN_RTRIG_GLOBR_S
> > )
> > +#define GLGEN_STAT			0x000B612C
> > +#define PFGEN_CTRL			0x00091000
> > +#define PFGEN_CTRL_PFSWR_S		0
> > +#define PFGEN_CTRL_PFSWR_M		BIT(PFGEN_CTRL_PFSWR_S)
> > +#define GLLAN_RCTL_0			0x002941F8
> > +#define GLNVM_FLA			0x000B6108
> > +#define GLNVM_FLA_LOCKED_S		6
> > +#define GLNVM_FLA_LOCKED_M		BIT(GLNVM_FLA_LOCKED_S)
> > +#define GLNVM_GENS			0x000B6100
> > +#define GLNVM_GENS_SR_SIZE_S		5
> > +#define GLNVM_GENS_SR_SIZE_M		ICE_M(0x7,
> > GLNVM_GENS_SR_SIZE_S)
> > +#define GLNVM_ULD			0x000B6008
> > +#define GLNVM_ULD_CORER_DONE_S		3
> > +#define GLNVM_ULD_CORER_DONE_M		BIT(GLNVM_ULD_CORER_
> > DONE_S)
> > +#define GLNVM_ULD_GLOBR_DONE_S		4
> > +#define GLNVM_ULD_GLOBR_DONE_M		BIT(GLNVM_ULD_GLOBR_
> > DONE_S)
> > +#define PF_FUNC_RID			0x0009E880
> > +#define PF_FUNC_RID_FUNC_NUM_S		0
> > +#define PF_FUNC_RID_FUNC_NUM_M		ICE_M(0x7,
> > PF_FUNC_RID_FUNC_NUM_S)
> >   
> >   #endif /* _ICE_HW_AUTOGEN_H_ */
> > diff --git a/drivers/net/ethernet/intel/ice/ice_main.c
> > b/drivers/net/ethernet/intel/ice/ice_main.c
> > index 408ae90d6562..2ee4a0547ba3 100644
> > --- a/drivers/net/ethernet/intel/ice/ice_main.c
> > +++ b/drivers/net/ethernet/intel/ice/ice_main.c
> > @@ -40,6 +40,18 @@ MODULE_PARM_DESC(debug, "netif level
> > (0=none,...,16=all), hw debug_mask (0x8XXXX
> >   MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
> >   #endif /* !CONFIG_DYNAMIC_DEBUG */
> >   
> > +/**
> > + * ice_set_ctrlq_len - helper function to set controlq length
> > + * @hw: pointer to the hw instance
> > + */
> > +static void ice_set_ctrlq_len(struct ice_hw *hw)
> > +{
> > +	hw->adminq.num_rq_entries = ICE_AQ_LEN;
> > +	hw->adminq.num_sq_entries = ICE_AQ_LEN;
> > +	hw->adminq.rq_buf_size = ICE_AQ_MAX_BUF_LEN;
> > +	hw->adminq.sq_buf_size = ICE_AQ_MAX_BUF_LEN;
> > +}
> > +
> >   /**
> >    * ice_probe - Device initialization routine
> >    * @pdev: PCI device information struct
> > @@ -95,6 +107,8 @@ static int ice_probe(struct pci_dev *pdev,
> >   	hw->subsystem_device_id = pdev->subsystem_device;
> >   	hw->bus.device = PCI_SLOT(pdev->devfn);
> >   	hw->bus.func = PCI_FUNC(pdev->devfn);
> > +	ice_set_ctrlq_len(hw);
> > +
> >   	pf->msg_enable = netif_msg_init(debug, ICE_DFLT_NETIF_M);
> >   
> >   #ifndef CONFIG_DYNAMIC_DEBUG
> > @@ -102,7 +116,22 @@ static int ice_probe(struct pci_dev *pdev,
> >   		hw->debug_mask = debug;
> >   #endif
> >   
> > +	err = ice_init_hw(hw);
> > +	if (err) {
> > +		dev_err(&pdev->dev, "ice_init_hw failed: %d\n",
> > err);
> > +		err = -EIO;
> > +		goto err_exit_unroll;
> > +	}
> > +
> > +	dev_info(&pdev->dev, "firmware %d.%d.%05d api %d.%d\n",
> > +		 hw->fw_maj_ver, hw->fw_min_ver, hw->fw_build,
> > +		 hw->api_maj_ver, hw->api_min_ver);
> > +
> >   	return 0;
> > +
> > +err_exit_unroll:
> > +	pci_disable_pcie_error_reporting(pdev);
> > +	return err;
> >   }
> >   
> >   /**
> > @@ -117,6 +146,8 @@ static void ice_remove(struct pci_dev *pdev)
> >   		return;
> >   
> >   	set_bit(__ICE_DOWN, pf->state);
> > +
> > +	ice_deinit_hw(&pf->hw);
> >   	pci_disable_pcie_error_reporting(pdev);
> >   }
> >   
> > diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c
> > b/drivers/net/ethernet/intel/ice/ice_nvm.c
> > new file mode 100644
> > index 000000000000..565910f01290
> > --- /dev/null
> > +++ b/drivers/net/ethernet/intel/ice/ice_nvm.c
> > @@ -0,0 +1,245 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/* Intel(R) Ethernet Connection E800 Series Linux Driver
> > + * Copyright (c) 2018, Intel Corporation.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > modify it
> > + * under the terms and conditions of the GNU General Public
> > License,
> > + * version 2, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but
> > WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of
> > MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> > License for
> > + * more details.
> > + *
> > + * The full GNU General Public License is included in this
> > distribution in
> > + * the file called "COPYING".
> > + */
> > +
> > +#include "ice_common.h"
> > +
> > +/**
> > + * ice_aq_read_nvm
> > + * @hw: pointer to the hw struct
> > + * @module_typeid: module pointer location in words from the NVM
> > beginning
> > + * @offset: byte offset from the module beginning
> > + * @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
> > + * @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, u8 module_typeid, u32 offset,
> > u16 length,
> > +		void *data, bool last_command, 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)
> > +		return ICE_ERR_PARAM;
> > +
> > +	ice_fill_dflt_direct_cmd_desc(&desc,
> > ice_aqc_opc_nvm_read);
> > +
> > +	/* If this is the last command in a series, set the proper
> > flag. */
> > +	if (last_command)
> > +		cmd->cmd_flags |= ICE_AQC_NVM_LAST_CMD;
> > +	cmd->module_typeid = module_typeid;
> > +	cmd->offset = cpu_to_le32(offset);
> > +	cmd->length = cpu_to_le16(length);
> > +
> > +	return ice_aq_send_cmd(hw, &desc, data, length, cd);
> > +}
> > +
> > +/**
> > + * 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
> > + *
> > + * Reads 16-bit word buffers from the Shadow RAM using the admin
> > command.
> > + */
> > +static enum ice_status
> > +ice_read_sr_aq(struct ice_hw *hw, u32 offset, u16 words, u16
> > *data,
> > +	       bool last_command)
> > +{
> > +	enum ice_status status;
> > +
> > +	status = ice_check_sr_access_params(hw, offset, words);
> > +	if (!status)
> > +		status = ice_aq_read_nvm(hw, 0, 2 * offset, 2 *
> > words, data,
> 
> Why the doubling of offset and words?  If this is some general 
> adjustment made for the AQ interface, it should be made in 
> ice_aq_read_nvm().  If not, then some explanation is needed here.

ice_read_sr_aq expects a word offset and size in words. The
ice_aq_read_nvm interface expects offset and size in bytes. The
doubling is a conversion from word offset/size to byte offset/size. 

> 
> sln
>
Shannon Nelson March 15, 2018, 5 p.m. UTC | #3
On 3/14/2018 3:05 PM, Venkataramanan, Anirudh wrote:
> On Mon, 2018-03-12 at 19:05 -0700, Shannon Nelson wrote:
>> On 3/9/2018 9:21 AM, Anirudh Venkataramanan wrote:


>>> +
>>> +/**
>>> + * 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
>>> + *
>>> + * Reads 16-bit word buffers from the Shadow RAM using the admin
>>> command.
>>> + */
>>> +static enum ice_status
>>> +ice_read_sr_aq(struct ice_hw *hw, u32 offset, u16 words, u16
>>> *data,
>>> +	       bool last_command)
>>> +{
>>> +	enum ice_status status;
>>> +
>>> +	status = ice_check_sr_access_params(hw, offset, words);
>>> +	if (!status)
>>> +		status = ice_aq_read_nvm(hw, 0, 2 * offset, 2 *
>>> words, data,
>>
>> Why the doubling of offset and words?  If this is some general
>> adjustment made for the AQ interface, it should be made in
>> ice_aq_read_nvm().  If not, then some explanation is needed here.
> 
> ice_read_sr_aq expects a word offset and size in words. The
> ice_aq_read_nvm interface expects offset and size in bytes. The
> doubling is a conversion from word offset/size to byte offset/size.

In that case, this might be a good place for a small comment for readers 
like me who don't have the spec available.

sln
Anirudh Venkataramanan March 15, 2018, 6:27 p.m. UTC | #4
On Thu, 2018-03-15 at 10:00 -0700, Shannon Nelson wrote:
> On 3/14/2018 3:05 PM, Venkataramanan, Anirudh wrote:
> > On Mon, 2018-03-12 at 19:05 -0700, Shannon Nelson wrote:
> > > On 3/9/2018 9:21 AM, Anirudh Venkataramanan wrote:
> 
> 
> > > > +
> > > > +/**
> > > > + * 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
> > > > + *
> > > > + * Reads 16-bit word buffers from the Shadow RAM using the
> > > > admin
> > > > command.
> > > > + */
> > > > +static enum ice_status
> > > > +ice_read_sr_aq(struct ice_hw *hw, u32 offset, u16 words, u16
> > > > *data,
> > > > +	       bool last_command)
> > > > +{
> > > > +	enum ice_status status;
> > > > +
> > > > +	status = ice_check_sr_access_params(hw, offset,
> > > > words);
> > > > +	if (!status)
> > > > +		status = ice_aq_read_nvm(hw, 0, 2 * offset, 2
> > > > *
> > > > words, data,
> > > 
> > > Why the doubling of offset and words?  If this is some general
> > > adjustment made for the AQ interface, it should be made in
> > > ice_aq_read_nvm().  If not, then some explanation is needed here.
> > 
> > ice_read_sr_aq expects a word offset and size in words. The
> > ice_aq_read_nvm interface expects offset and size in bytes. The
> > doubling is a conversion from word offset/size to byte offset/size.
> 
> In that case, this might be a good place for a small comment for
> readers 
> like me who don't have the spec available.

Sure thing! :-)

> 
> sln
>
diff mbox series

Patch

diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile
index eebf619e84a8..373d481dbb25 100644
--- a/drivers/net/ethernet/intel/ice/Makefile
+++ b/drivers/net/ethernet/intel/ice/Makefile
@@ -26,4 +26,5 @@  obj-$(CONFIG_ICE) += ice.o
 
 ice-y := ice_main.o	\
 	 ice_controlq.o	\
-	 ice_common.o
+	 ice_common.o	\
+	 ice_nvm.o
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index ea2fb63bb095..ab2800c31906 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -30,8 +30,10 @@ 
 #include <linux/bitmap.h>
 #include "ice_devids.h"
 #include "ice_type.h"
+#include "ice_common.h"
 
 #define ICE_BAR0		0
+#define ICE_AQ_LEN		64
 
 #define ICE_DFLT_NETIF_M (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
 
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index 885fa3c6fec4..05b22a1ffd70 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -50,6 +50,67 @@  struct ice_aqc_q_shutdown {
 	u8 reserved[12];
 };
 
+/* Request resource ownership (direct 0x0008)
+ * Release resource ownership (direct 0x0009)
+ */
+struct ice_aqc_req_res {
+	__le16 res_id;
+#define ICE_AQC_RES_ID_NVM		1
+#define ICE_AQC_RES_ID_SDP		2
+#define ICE_AQC_RES_ID_CHNG_LOCK	3
+#define ICE_AQC_RES_ID_GLBL_LOCK	4
+	__le16 access_type;
+#define ICE_AQC_RES_ACCESS_READ		1
+#define ICE_AQC_RES_ACCESS_WRITE	2
+
+	/* Upon successful completion, FW writes this value and driver is
+	 * expected to release resource before timeout. This value is provided
+	 * in milliseconds.
+	 */
+	__le32 timeout;
+#define ICE_AQ_RES_NVM_READ_DFLT_TIMEOUT_MS	3000
+#define ICE_AQ_RES_NVM_WRITE_DFLT_TIMEOUT_MS	180000
+#define ICE_AQ_RES_CHNG_LOCK_DFLT_TIMEOUT_MS	1000
+#define ICE_AQ_RES_GLBL_LOCK_DFLT_TIMEOUT_MS	3000
+	/* For SDP: pin id of the SDP */
+	__le32 res_number;
+	/* Status is only used for ICE_AQC_RES_ID_GLBL_LOCK */
+	__le16 status;
+#define ICE_AQ_RES_GLBL_SUCCESS		0
+#define ICE_AQ_RES_GLBL_IN_PROG		1
+#define ICE_AQ_RES_GLBL_DONE		2
+	u8 reserved[2];
+};
+
+/* Clear PXE Command and response (direct 0x0110) */
+struct ice_aqc_clear_pxe {
+	u8 rx_cnt;
+#define ICE_AQC_CLEAR_PXE_RX_CNT		0x2
+	u8 reserved[15];
+};
+
+/* NVM Read command (indirect 0x0701)
+ * NVM Erase commands (direct 0x0702)
+ * NVM Update commands (indirect 0x0703)
+ */
+struct ice_aqc_nvm {
+	u8	cmd_flags;
+#define ICE_AQC_NVM_LAST_CMD		BIT(0)
+#define ICE_AQC_NVM_PCIR_REQ		BIT(0)	/* Used by NVM Update reply */
+#define ICE_AQC_NVM_PRESERVATION_S	1
+#define ICE_AQC_NVM_PRESERVATION_M	(3 << CSR_AQ_NVM_PRESERVATION_S)
+#define ICE_AQC_NVM_NO_PRESERVATION	(0 << CSR_AQ_NVM_PRESERVATION_S)
+#define ICE_AQC_NVM_PRESERVE_ALL	BIT(1)
+#define ICE_AQC_NVM_PRESERVE_SELECTED	(3 << CSR_AQ_NVM_PRESERVATION_S)
+#define ICE_AQC_NVM_FLASH_ONLY		BIT(7)
+	u8	module_typeid;
+	__le16	length;
+#define ICE_AQC_NVM_ERASE_LEN	0xFFFF
+	__le32	offset;
+	__le32	addr_high;
+	__le32	addr_low;
+};
+
 /**
  * struct ice_aq_desc - Admin Queue (AQ) descriptor
  * @flags: ICE_AQ_FLAG_* flags
@@ -79,6 +140,9 @@  struct ice_aq_desc {
 		struct ice_aqc_generic generic;
 		struct ice_aqc_get_ver get_ver;
 		struct ice_aqc_q_shutdown q_shutdown;
+		struct ice_aqc_req_res res_owner;
+		struct ice_aqc_clear_pxe clear_pxe;
+		struct ice_aqc_nvm nvm;
 	} params;
 };
 
@@ -96,6 +160,8 @@  struct ice_aq_desc {
 /* error codes */
 enum ice_aq_err {
 	ICE_AQ_RC_OK		= 0,  /* success */
+	ICE_AQ_RC_EBUSY		= 12, /* Device or resource busy */
+	ICE_AQ_RC_EEXIST	= 13, /* object already exists */
 };
 
 /* Admin Queue command opcodes */
@@ -103,6 +169,19 @@  enum ice_adminq_opc {
 	/* AQ commands */
 	ice_aqc_opc_get_ver				= 0x0001,
 	ice_aqc_opc_q_shutdown				= 0x0003,
+
+	/* resource ownership */
+	ice_aqc_opc_req_res				= 0x0008,
+	ice_aqc_opc_release_res				= 0x0009,
+
+	/* PXE */
+	ice_aqc_opc_clear_pxe_mode			= 0x0110,
+
+	ice_aqc_opc_clear_pf_cfg			= 0x02A4,
+
+	/* NVM commands */
+	ice_aqc_opc_nvm_read				= 0x0701,
+
 };
 
 #endif /* _ICE_ADMINQ_CMD_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index d980f0518744..eb3e06488705 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -18,6 +18,224 @@ 
 #include "ice_common.h"
 #include "ice_adminq_cmd.h"
 
+#define ICE_PF_RESET_WAIT_COUNT	200
+
+/**
+ * ice_set_mac_type - Sets MAC type
+ * @hw: pointer to the HW structure
+ *
+ * This function sets the MAC type of the adapter based on the
+ * vendor ID and device ID stored in the hw structure.
+ */
+static enum ice_status ice_set_mac_type(struct ice_hw *hw)
+{
+	if (hw->vendor_id != PCI_VENDOR_ID_INTEL)
+		return ICE_ERR_DEVICE_NOT_SUPPORTED;
+
+	hw->mac_type = ICE_MAC_GENERIC;
+	return 0;
+}
+
+/**
+ * ice_clear_pf_cfg - Clear PF configuration
+ * @hw: pointer to the hardware structure
+ */
+enum ice_status ice_clear_pf_cfg(struct ice_hw *hw)
+{
+	struct ice_aq_desc desc;
+
+	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_clear_pf_cfg);
+
+	return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
+}
+
+/**
+ * ice_init_hw - main hardware initialization routine
+ * @hw: pointer to the hardware structure
+ */
+enum ice_status ice_init_hw(struct ice_hw *hw)
+{
+	enum ice_status status;
+
+	/* Set MAC type based on DeviceID */
+	status = ice_set_mac_type(hw);
+	if (status)
+		return status;
+
+	hw->pf_id = (u8)(rd32(hw, PF_FUNC_RID) &
+			 PF_FUNC_RID_FUNC_NUM_M) >>
+		PF_FUNC_RID_FUNC_NUM_S;
+
+	status = ice_reset(hw, ICE_RESET_PFR);
+	if (status)
+		return status;
+
+	status = ice_init_all_ctrlq(hw);
+	if (status)
+		goto err_unroll_cqinit;
+
+	status = ice_clear_pf_cfg(hw);
+	if (status)
+		goto err_unroll_cqinit;
+
+	ice_clear_pxe_mode(hw);
+
+	status = ice_init_nvm(hw);
+	if (status)
+		goto err_unroll_cqinit;
+
+	return 0;
+
+err_unroll_cqinit:
+	ice_shutdown_all_ctrlq(hw);
+	return status;
+}
+
+/**
+ * ice_deinit_hw - unroll initialization operations done by ice_init_hw
+ * @hw: pointer to the hardware structure
+ */
+void ice_deinit_hw(struct ice_hw *hw)
+{
+	ice_shutdown_all_ctrlq(hw);
+}
+
+/**
+ * ice_check_reset - Check to see if a global reset is complete
+ * @hw: pointer to the hardware structure
+ */
+enum ice_status ice_check_reset(struct ice_hw *hw)
+{
+	u32 cnt, reg = 0, grst_delay;
+
+	/* Poll for Device Active state in case a recent CORER, GLOBR,
+	 * or EMPR has occurred. The grst delay value is in 100ms units.
+	 * Add 1sec for outstanding AQ commands that can take a long time.
+	 */
+	grst_delay = ((rd32(hw, GLGEN_RSTCTL) & GLGEN_RSTCTL_GRSTDEL_M) >>
+		      GLGEN_RSTCTL_GRSTDEL_S) + 10;
+
+	for (cnt = 0; cnt < grst_delay; cnt++) {
+		mdelay(100);
+		reg = rd32(hw, GLGEN_RSTAT);
+		if (!(reg & GLGEN_RSTAT_DEVSTATE_M))
+			break;
+	}
+
+	if (cnt == grst_delay) {
+		ice_debug(hw, ICE_DBG_INIT,
+			  "Global reset polling failed to complete.\n");
+		return ICE_ERR_RESET_FAILED;
+	}
+
+#define ICE_RESET_DONE_MASK	(GLNVM_ULD_CORER_DONE_M | \
+				 GLNVM_ULD_GLOBR_DONE_M)
+
+	/* Device is Active; check Global Reset processes are done */
+	for (cnt = 0; cnt < ICE_PF_RESET_WAIT_COUNT; cnt++) {
+		reg = rd32(hw, GLNVM_ULD) & ICE_RESET_DONE_MASK;
+		if (reg == ICE_RESET_DONE_MASK) {
+			ice_debug(hw, ICE_DBG_INIT,
+				  "Global reset processes done. %d\n", cnt);
+			break;
+		}
+		mdelay(10);
+	}
+
+	if (cnt == ICE_PF_RESET_WAIT_COUNT) {
+		ice_debug(hw, ICE_DBG_INIT,
+			  "Wait for Reset Done timed out. GLNVM_ULD = 0x%x\n",
+			  reg);
+		return ICE_ERR_RESET_FAILED;
+	}
+
+	return 0;
+}
+
+/**
+ * ice_pf_reset - Reset the PF
+ * @hw: pointer to the hardware structure
+ *
+ * If a global reset has been triggered, this function checks
+ * for its completion and then issues the PF reset
+ */
+static enum ice_status ice_pf_reset(struct ice_hw *hw)
+{
+	u32 cnt, reg;
+
+	/* If at function entry a global reset was already in progress, i.e.
+	 * state is not 'device active' or any of the reset done bits are not
+	 * set in GLNVM_ULD, there is no need for a PF Reset; poll until the
+	 * global reset is done.
+	 */
+	if ((rd32(hw, GLGEN_RSTAT) & GLGEN_RSTAT_DEVSTATE_M) ||
+	    (rd32(hw, GLNVM_ULD) & ICE_RESET_DONE_MASK) ^ ICE_RESET_DONE_MASK) {
+		/* poll on global reset currently in progress until done */
+		if (ice_check_reset(hw))
+			return ICE_ERR_RESET_FAILED;
+
+		return 0;
+	}
+
+	/* Reset the PF */
+	reg = rd32(hw, PFGEN_CTRL);
+
+	wr32(hw, PFGEN_CTRL, (reg | PFGEN_CTRL_PFSWR_M));
+
+	for (cnt = 0; cnt < ICE_PF_RESET_WAIT_COUNT; cnt++) {
+		reg = rd32(hw, PFGEN_CTRL);
+		if (!(reg & PFGEN_CTRL_PFSWR_M))
+			break;
+
+		mdelay(1);
+	}
+
+	if (cnt == ICE_PF_RESET_WAIT_COUNT) {
+		ice_debug(hw, ICE_DBG_INIT,
+			  "PF reset polling failed to complete.\n");
+		return ICE_ERR_RESET_FAILED;
+	}
+
+	return 0;
+}
+
+/**
+ * ice_reset - Perform different types of reset
+ * @hw: pointer to the hardware structure
+ * @req: reset request
+ *
+ * This function triggers a reset as specified by the req parameter.
+ *
+ * Note:
+ * If anything other than a PF reset is triggered, PXE mode is restored.
+ * This has to be cleared using ice_clear_pxe_mode again, once the AQ
+ * interface has been restored in the rebuild flow.
+ */
+enum ice_status ice_reset(struct ice_hw *hw, enum ice_reset_req req)
+{
+	u32 val = 0;
+
+	switch (req) {
+	case ICE_RESET_PFR:
+		return ice_pf_reset(hw);
+	case ICE_RESET_CORER:
+		ice_debug(hw, ICE_DBG_INIT, "CoreR requested\n");
+		val = GLGEN_RTRIG_CORER_M;
+		break;
+	case ICE_RESET_GLOBR:
+		ice_debug(hw, ICE_DBG_INIT, "GlobalR requested\n");
+		val = GLGEN_RTRIG_GLOBR_M;
+		break;
+	}
+
+	val |= rd32(hw, GLGEN_RTRIG);
+	wr32(hw, GLGEN_RTRIG, val);
+	ice_flush(hw);
+
+	/* wait for the FW to be ready */
+	return ice_check_reset(hw);
+}
+
 /**
  * ice_debug_cq
  * @hw: pointer to the hardware structure
@@ -142,3 +360,195 @@  enum ice_status ice_aq_q_shutdown(struct ice_hw *hw, bool unloading)
 
 	return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
 }
+
+/**
+ * ice_aq_req_res
+ * @hw: pointer to the hw struct
+ * @res: resource id
+ * @access: access type
+ * @sdp_number: resource number
+ * @timeout: the maximum time in ms that the driver may hold the resource
+ * @cd: pointer to command details structure or NULL
+ *
+ * requests common resource using the admin queue commands (0x0008)
+ */
+static enum ice_status
+ice_aq_req_res(struct ice_hw *hw, enum ice_aq_res_ids res,
+	       enum ice_aq_res_access_type access, u8 sdp_number, u32 *timeout,
+	       struct ice_sq_cd *cd)
+{
+	struct ice_aqc_req_res *cmd_resp;
+	struct ice_aq_desc desc;
+	enum ice_status status;
+
+	cmd_resp = &desc.params.res_owner;
+
+	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_req_res);
+
+	cmd_resp->res_id = cpu_to_le16(res);
+	cmd_resp->access_type = cpu_to_le16(access);
+	cmd_resp->res_number = cpu_to_le32(sdp_number);
+
+	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
+	/* The completion specifies the maximum time in ms that the driver
+	 * may hold the resource in the Timeout field.
+	 * If the resource is held by someone else, the command completes with
+	 * busy return value and the timeout field indicates the maximum time
+	 * the current owner of the resource has to free it.
+	 */
+	if (!status || hw->adminq.sq_last_status == ICE_AQ_RC_EBUSY)
+		*timeout = le32_to_cpu(cmd_resp->timeout);
+
+	return status;
+}
+
+/**
+ * ice_aq_release_res
+ * @hw: pointer to the hw struct
+ * @res: resource id
+ * @sdp_number: resource number
+ * @cd: pointer to command details structure or NULL
+ *
+ * release common resource using the admin queue commands (0x0009)
+ */
+static enum ice_status
+ice_aq_release_res(struct ice_hw *hw, enum ice_aq_res_ids res, u8 sdp_number,
+		   struct ice_sq_cd *cd)
+{
+	struct ice_aqc_req_res *cmd;
+	struct ice_aq_desc desc;
+
+	cmd = &desc.params.res_owner;
+
+	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_release_res);
+
+	cmd->res_id = cpu_to_le16(res);
+	cmd->res_number = cpu_to_le32(sdp_number);
+
+	return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
+}
+
+/**
+ * ice_acquire_res
+ * @hw: pointer to the HW structure
+ * @res: resource id
+ * @access: access type (read or write)
+ *
+ * This function will attempt to acquire the ownership of a resource.
+ */
+enum ice_status
+ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,
+		enum ice_aq_res_access_type access)
+{
+#define ICE_RES_POLLING_DELAY_MS	10
+	u32 delay = ICE_RES_POLLING_DELAY_MS;
+	enum ice_status status;
+	u32 time_left = 0;
+	u32 timeout;
+
+	status = ice_aq_req_res(hw, res, access, 0, &time_left, NULL);
+
+	/* An admin queue return code of ICE_AQ_RC_EEXIST means that another
+	 * driver has previously acquired the resource and performed any
+	 * necessary updates; in this case the caller does not obtain the
+	 * resource and has no further work to do.
+	 */
+	if (hw->adminq.sq_last_status == ICE_AQ_RC_EEXIST) {
+		status = ICE_ERR_AQ_NO_WORK;
+		goto ice_acquire_res_exit;
+	}
+
+	if (status)
+		ice_debug(hw, ICE_DBG_RES,
+			  "resource %d acquire type %d failed.\n", res, access);
+
+	/* If necessary, poll until the current lock owner timeouts */
+	timeout = time_left;
+	while (status && timeout && time_left) {
+		mdelay(delay);
+		timeout = (timeout > delay) ? timeout - delay : 0;
+		status = ice_aq_req_res(hw, res, access, 0, &time_left, NULL);
+
+		if (hw->adminq.sq_last_status == ICE_AQ_RC_EEXIST) {
+			/* lock free, but no work to do */
+			status = ICE_ERR_AQ_NO_WORK;
+			break;
+		}
+
+		if (!status)
+			/* lock acquired */
+			break;
+	}
+	if (status && status != ICE_ERR_AQ_NO_WORK)
+		ice_debug(hw, ICE_DBG_RES, "resource acquire timed out.\n");
+
+ice_acquire_res_exit:
+	if (status == ICE_ERR_AQ_NO_WORK) {
+		if (access == ICE_RES_WRITE)
+			ice_debug(hw, ICE_DBG_RES,
+				  "resource indicates no work to do.\n");
+		else
+			ice_debug(hw, ICE_DBG_RES,
+				  "Warning: ICE_ERR_AQ_NO_WORK not expected\n");
+	}
+	return status;
+}
+
+/**
+ * ice_release_res
+ * @hw: pointer to the HW structure
+ * @res: resource id
+ *
+ * This function will release a resource using the proper Admin Command.
+ */
+void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res)
+{
+	enum ice_status status;
+	u32 total_delay = 0;
+
+	status = ice_aq_release_res(hw, res, 0, NULL);
+
+	/* there are some rare cases when trying to release the resource
+	 * results in an admin Q timeout, so handle them correctly
+	 */
+	while ((status == ICE_ERR_AQ_TIMEOUT) &&
+	       (total_delay < hw->adminq.sq_cmd_timeout)) {
+		mdelay(1);
+		status = ice_aq_release_res(hw, res, 0, NULL);
+		total_delay++;
+	}
+}
+
+/**
+ * ice_aq_clear_pxe_mode
+ * @hw: pointer to the hw struct
+ *
+ * Tell the firmware that the driver is taking over from PXE (0x0110).
+ */
+static enum ice_status ice_aq_clear_pxe_mode(struct ice_hw *hw)
+{
+	struct ice_aq_desc desc;
+	enum ice_status status;
+
+	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_clear_pxe_mode);
+	desc.params.clear_pxe.rx_cnt = ICE_AQC_CLEAR_PXE_RX_CNT;
+
+	status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
+
+	wr32(hw, GLLAN_RCTL_0, 0x1);
+
+	return status;
+}
+
+/**
+ * ice_clear_pxe_mode - clear pxe operations mode
+ * @hw: pointer to the hw struct
+ *
+ * Make sure all PXE mode settings are cleared, including things
+ * like descriptor fetch/write-back mode.
+ */
+void ice_clear_pxe_mode(struct ice_hw *hw)
+{
+	if (ice_check_sq_alive(hw, &hw->adminq))
+		ice_aq_clear_pxe_mode(hw);
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index 1e3caecc38c6..0876fd98090a 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -23,12 +23,22 @@ 
 
 void ice_debug_cq(struct ice_hw *hw, u32 mask, void *desc, void *buf,
 		  u16 buf_len);
+enum ice_status ice_init_hw(struct ice_hw *hw);
+void ice_deinit_hw(struct ice_hw *hw);
+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_init_all_ctrlq(struct ice_hw *hw);
 void ice_shutdown_all_ctrlq(struct ice_hw *hw);
 enum ice_status
+ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,
+		enum ice_aq_res_access_type access);
+void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res);
+enum ice_status ice_init_nvm(struct ice_hw *hw);
+enum ice_status
 ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq,
 		struct ice_aq_desc *desc, void *buf, u16 buf_size,
 		struct ice_sq_cd *cd);
+void ice_clear_pxe_mode(struct ice_hw *hw);
 bool ice_check_sq_alive(struct ice_hw *hw, struct ice_ctl_q_info *cq);
 enum ice_status ice_aq_q_shutdown(struct ice_hw *hw, bool unloading);
 void ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16 opcode);
@@ -36,4 +46,5 @@  enum ice_status
 ice_aq_send_cmd(struct ice_hw *hw, struct ice_aq_desc *desc,
 		void *buf, u16 buf_size, struct ice_sq_cd *cd);
 enum ice_status ice_aq_get_fw_ver(struct ice_hw *hw, struct ice_sq_cd *cd);
+enum ice_status ice_clear_pf_cfg(struct ice_hw *hw);
 #endif /* _ICE_COMMON_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h
index 143578d02aec..835c035419a3 100644
--- a/drivers/net/ethernet/intel/ice/ice_controlq.h
+++ b/drivers/net/ethernet/intel/ice/ice_controlq.h
@@ -20,6 +20,9 @@ 
 
 #include "ice_adminq_cmd.h"
 
+/* Maximum buffer lengths for all control queue types */
+#define ICE_AQ_MAX_BUF_LEN 4096
+
 #define ICE_CTL_Q_DESC(R, i) \
 	(&(((struct ice_aq_desc *)((R).desc_buf.va))[i]))
 
diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
index 3d6bb273e4c8..e258a12099b8 100644
--- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
+++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
@@ -42,5 +42,35 @@ 
 #define PF_FW_ATQLEN_ATQENABLE_S	31
 #define PF_FW_ATQLEN_ATQENABLE_M	BIT(PF_FW_ATQLEN_ATQENABLE_S)
 #define PF_FW_ATQT			0x00080400
+#define GLGEN_RSTAT			0x000B8188
+#define GLGEN_RSTAT_DEVSTATE_S		0
+#define GLGEN_RSTAT_DEVSTATE_M		ICE_M(0x3, GLGEN_RSTAT_DEVSTATE_S)
+#define GLGEN_RSTCTL			0x000B8180
+#define GLGEN_RSTCTL_GRSTDEL_S		0
+#define GLGEN_RSTCTL_GRSTDEL_M		ICE_M(0x3F, GLGEN_RSTCTL_GRSTDEL_S)
+#define GLGEN_RTRIG			0x000B8190
+#define GLGEN_RTRIG_CORER_S		0
+#define GLGEN_RTRIG_CORER_M		BIT(GLGEN_RTRIG_CORER_S)
+#define GLGEN_RTRIG_GLOBR_S		1
+#define GLGEN_RTRIG_GLOBR_M		BIT(GLGEN_RTRIG_GLOBR_S)
+#define GLGEN_STAT			0x000B612C
+#define PFGEN_CTRL			0x00091000
+#define PFGEN_CTRL_PFSWR_S		0
+#define PFGEN_CTRL_PFSWR_M		BIT(PFGEN_CTRL_PFSWR_S)
+#define GLLAN_RCTL_0			0x002941F8
+#define GLNVM_FLA			0x000B6108
+#define GLNVM_FLA_LOCKED_S		6
+#define GLNVM_FLA_LOCKED_M		BIT(GLNVM_FLA_LOCKED_S)
+#define GLNVM_GENS			0x000B6100
+#define GLNVM_GENS_SR_SIZE_S		5
+#define GLNVM_GENS_SR_SIZE_M		ICE_M(0x7, GLNVM_GENS_SR_SIZE_S)
+#define GLNVM_ULD			0x000B6008
+#define GLNVM_ULD_CORER_DONE_S		3
+#define GLNVM_ULD_CORER_DONE_M		BIT(GLNVM_ULD_CORER_DONE_S)
+#define GLNVM_ULD_GLOBR_DONE_S		4
+#define GLNVM_ULD_GLOBR_DONE_M		BIT(GLNVM_ULD_GLOBR_DONE_S)
+#define PF_FUNC_RID			0x0009E880
+#define PF_FUNC_RID_FUNC_NUM_S		0
+#define PF_FUNC_RID_FUNC_NUM_M		ICE_M(0x7, PF_FUNC_RID_FUNC_NUM_S)
 
 #endif /* _ICE_HW_AUTOGEN_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 408ae90d6562..2ee4a0547ba3 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -40,6 +40,18 @@  MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all), hw debug_mask (0x8XXXX
 MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
 #endif /* !CONFIG_DYNAMIC_DEBUG */
 
+/**
+ * ice_set_ctrlq_len - helper function to set controlq length
+ * @hw: pointer to the hw instance
+ */
+static void ice_set_ctrlq_len(struct ice_hw *hw)
+{
+	hw->adminq.num_rq_entries = ICE_AQ_LEN;
+	hw->adminq.num_sq_entries = ICE_AQ_LEN;
+	hw->adminq.rq_buf_size = ICE_AQ_MAX_BUF_LEN;
+	hw->adminq.sq_buf_size = ICE_AQ_MAX_BUF_LEN;
+}
+
 /**
  * ice_probe - Device initialization routine
  * @pdev: PCI device information struct
@@ -95,6 +107,8 @@  static int ice_probe(struct pci_dev *pdev,
 	hw->subsystem_device_id = pdev->subsystem_device;
 	hw->bus.device = PCI_SLOT(pdev->devfn);
 	hw->bus.func = PCI_FUNC(pdev->devfn);
+	ice_set_ctrlq_len(hw);
+
 	pf->msg_enable = netif_msg_init(debug, ICE_DFLT_NETIF_M);
 
 #ifndef CONFIG_DYNAMIC_DEBUG
@@ -102,7 +116,22 @@  static int ice_probe(struct pci_dev *pdev,
 		hw->debug_mask = debug;
 #endif
 
+	err = ice_init_hw(hw);
+	if (err) {
+		dev_err(&pdev->dev, "ice_init_hw failed: %d\n", err);
+		err = -EIO;
+		goto err_exit_unroll;
+	}
+
+	dev_info(&pdev->dev, "firmware %d.%d.%05d api %d.%d\n",
+		 hw->fw_maj_ver, hw->fw_min_ver, hw->fw_build,
+		 hw->api_maj_ver, hw->api_min_ver);
+
 	return 0;
+
+err_exit_unroll:
+	pci_disable_pcie_error_reporting(pdev);
+	return err;
 }
 
 /**
@@ -117,6 +146,8 @@  static void ice_remove(struct pci_dev *pdev)
 		return;
 
 	set_bit(__ICE_DOWN, pf->state);
+
+	ice_deinit_hw(&pf->hw);
 	pci_disable_pcie_error_reporting(pdev);
 }
 
diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c
new file mode 100644
index 000000000000..565910f01290
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_nvm.c
@@ -0,0 +1,245 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/* Intel(R) Ethernet Connection E800 Series Linux Driver
+ * Copyright (c) 2018, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ */
+
+#include "ice_common.h"
+
+/**
+ * ice_aq_read_nvm
+ * @hw: pointer to the hw struct
+ * @module_typeid: module pointer location in words from the NVM beginning
+ * @offset: byte offset from the module beginning
+ * @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
+ * @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, u8 module_typeid, u32 offset, u16 length,
+		void *data, bool last_command, 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)
+		return ICE_ERR_PARAM;
+
+	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_read);
+
+	/* If this is the last command in a series, set the proper flag. */
+	if (last_command)
+		cmd->cmd_flags |= ICE_AQC_NVM_LAST_CMD;
+	cmd->module_typeid = module_typeid;
+	cmd->offset = cpu_to_le32(offset);
+	cmd->length = cpu_to_le16(length);
+
+	return ice_aq_send_cmd(hw, &desc, data, length, cd);
+}
+
+/**
+ * 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
+ *
+ * Reads 16-bit word buffers from the Shadow RAM using the admin command.
+ */
+static enum ice_status
+ice_read_sr_aq(struct ice_hw *hw, u32 offset, u16 words, u16 *data,
+	       bool last_command)
+{
+	enum ice_status status;
+
+	status = ice_check_sr_access_params(hw, offset, words);
+	if (!status)
+		status = ice_aq_read_nvm(hw, 0, 2 * offset, 2 * words, data,
+					 last_command, NULL);
+
+	return status;
+}
+
+/**
+ * ice_read_sr_word_aq - Reads Shadow RAM via AQ
+ * @hw: pointer to the HW structure
+ * @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.
+ */
+static enum ice_status
+ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data)
+{
+	enum ice_status status;
+
+	status = ice_read_sr_aq(hw, offset, 1, data, true);
+	if (!status)
+		*data = le16_to_cpu(*(__le16 *)data);
+
+	return status;
+}
+
+/**
+ * ice_acquire_nvm - Generic request for acquiring the NVM ownership
+ * @hw: pointer to the HW structure
+ * @access: NVM access type (read or write)
+ *
+ * This function will request NVM ownership.
+ */
+static enum
+ice_status ice_acquire_nvm(struct ice_hw *hw,
+			   enum ice_aq_res_access_type access)
+{
+	if (hw->nvm.blank_nvm_mode)
+		return 0;
+
+	return ice_acquire_res(hw, ICE_NVM_RES_ID, access);
+}
+
+/**
+ * ice_release_nvm - Generic request for releasing the NVM ownership
+ * @hw: pointer to the HW structure
+ *
+ * This function will release NVM ownership.
+ */
+static void ice_release_nvm(struct ice_hw *hw)
+{
+	if (hw->nvm.blank_nvm_mode)
+		return;
+
+	ice_release_res(hw, ICE_NVM_RES_ID);
+}
+
+/**
+ * ice_read_sr_word - Reads Shadow RAM word and acquire NVM if necessary
+ * @hw: pointer to the HW structure
+ * @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_word_aq.
+ */
+static enum ice_status
+ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data)
+{
+	enum ice_status status;
+
+	status = ice_acquire_nvm(hw, ICE_RES_READ);
+	if (!status) {
+		status = ice_read_sr_word_aq(hw, offset, data);
+		ice_release_nvm(hw);
+	}
+
+	return status;
+}
+
+/**
+ * ice_init_nvm - initializes NVM setting
+ * @hw: pointer to the hw struct
+ *
+ * This function reads and populates NVM settings such as Shadow RAM size,
+ * max_timeout, and blank_nvm_mode
+ */
+enum ice_status ice_init_nvm(struct ice_hw *hw)
+{
+	struct ice_nvm_info *nvm = &hw->nvm;
+	u16 eetrack_lo, eetrack_hi;
+	enum ice_status status = 0;
+	u32 fla, gens_stat;
+	u8 sr_size;
+
+	/* The SR size is stored regardless of the nvm programming mode
+	 * as the blank mode may be used in the factory line.
+	 */
+	gens_stat = rd32(hw, GLNVM_GENS);
+	sr_size = (gens_stat & GLNVM_GENS_SR_SIZE_M) >> GLNVM_GENS_SR_SIZE_S;
+
+	/* Switching to words (sr_size contains power of 2) */
+	nvm->sr_words = BIT(sr_size) * ICE_SR_WORDS_IN_1KB;
+
+	/* Check if we are in the normal or blank NVM programming mode */
+	fla = rd32(hw, GLNVM_FLA);
+	if (fla & GLNVM_FLA_LOCKED_M) { /* Normal programming mode */
+		nvm->blank_nvm_mode = false;
+	} else { /* Blank programming mode */
+		nvm->blank_nvm_mode = true;
+		status = ICE_ERR_NVM_BLANK_MODE;
+		ice_debug(hw, ICE_DBG_NVM,
+			  "NVM init error: unsupported blank mode.\n");
+		return status;
+	}
+
+	status = ice_read_sr_word(hw, ICE_SR_NVM_DEV_STARTER_VER, &hw->nvm.ver);
+	if (status) {
+		ice_debug(hw, ICE_DBG_INIT,
+			  "Failed to read DEV starter version.\n");
+		return status;
+	}
+
+	status = ice_read_sr_word(hw, ICE_SR_NVM_EETRACK_LO, &eetrack_lo);
+	if (status) {
+		ice_debug(hw, ICE_DBG_INIT, "Failed to read EETRACK lo.\n");
+		return status;
+	}
+	status = ice_read_sr_word(hw, ICE_SR_NVM_EETRACK_HI, &eetrack_hi);
+	if (status) {
+		ice_debug(hw, ICE_DBG_INIT, "Failed to read EETRACK hi.\n");
+		return status;
+	}
+
+	hw->nvm.eetrack = (eetrack_hi << 16) | eetrack_lo;
+
+	return status;
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_osdep.h b/drivers/net/ethernet/intel/ice/ice_osdep.h
index fc6576a3a9d1..d7af84c714c1 100644
--- a/drivers/net/ethernet/intel/ice/ice_osdep.h
+++ b/drivers/net/ethernet/intel/ice/ice_osdep.h
@@ -29,6 +29,7 @@ 
 #define wr64(a, reg, value)	writeq((value), ((a)->hw_addr + (reg)))
 #define rd64(a, reg)		readq((a)->hw_addr + (reg))
 
+#define ice_flush(a)		rd32((a), GLGEN_STAT)
 #define ICE_M(m, s)		((m) << (s))
 
 struct ice_dma_mem {
diff --git a/drivers/net/ethernet/intel/ice/ice_status.h b/drivers/net/ethernet/intel/ice/ice_status.h
index 940d6f57adcf..1fb6eb8301cf 100644
--- a/drivers/net/ethernet/intel/ice/ice_status.h
+++ b/drivers/net/ethernet/intel/ice/ice_status.h
@@ -23,12 +23,17 @@  enum ice_status {
 	ICE_ERR_PARAM				= -1,
 	ICE_ERR_NOT_READY			= -3,
 	ICE_ERR_INVAL_SIZE			= -6,
+	ICE_ERR_DEVICE_NOT_SUPPORTED		= -8,
+	ICE_ERR_RESET_FAILED			= -9,
 	ICE_ERR_FW_API_VER			= -10,
 	ICE_ERR_NO_MEMORY			= -11,
 	ICE_ERR_CFG				= -12,
+	ICE_ERR_OUT_OF_RANGE			= -13,
+	ICE_ERR_NVM_BLANK_MODE			= -53,
 	ICE_ERR_AQ_ERROR			= -100,
 	ICE_ERR_AQ_TIMEOUT			= -101,
 	ICE_ERR_AQ_FULL				= -102,
+	ICE_ERR_AQ_NO_WORK			= -103,
 	ICE_ERR_AQ_EMPTY			= -104,
 };
 
diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h
index cfa98e55a33a..e40fab48cf7f 100644
--- a/drivers/net/ethernet/intel/ice/ice_type.h
+++ b/drivers/net/ethernet/intel/ice/ice_type.h
@@ -24,20 +24,58 @@ 
 #include "ice_controlq.h"
 
 /* debug masks - set these bits in hw->debug_mask to control output */
+#define ICE_DBG_INIT		BIT_ULL(1)
+#define ICE_DBG_NVM		BIT_ULL(7)
+#define ICE_DBG_RES		BIT_ULL(17)
 #define ICE_DBG_AQ_MSG		BIT_ULL(24)
 #define ICE_DBG_AQ_CMD		BIT_ULL(27)
 
+enum ice_aq_res_ids {
+	ICE_NVM_RES_ID = 1,
+	ICE_SPD_RES_ID,
+	ICE_GLOBAL_CFG_LOCK_RES_ID,
+	ICE_CHANGE_LOCK_RES_ID
+};
+
+enum ice_aq_res_access_type {
+	ICE_RES_READ = 1,
+	ICE_RES_WRITE
+};
+
+/* Various MAC types */
+enum ice_mac_type {
+	ICE_MAC_UNKNOWN = 0,
+	ICE_MAC_GENERIC,
+};
+
+/* Various RESET request, These are not tied with HW reset types */
+enum ice_reset_req {
+	ICE_RESET_PFR	= 0,
+	ICE_RESET_CORER	= 1,
+	ICE_RESET_GLOBR	= 2,
+};
+
 /* Bus parameters */
 struct ice_bus_info {
 	u16 device;
 	u8 func;
 };
 
+/* 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 */
+	bool blank_nvm_mode;      /* is NVM empty (no FW present) */
+};
+
 /* Port hardware description */
 struct ice_hw {
 	u8 __iomem *hw_addr;
 	void *back;
 	u64 debug_mask;		/* bitmap for debug mask */
+	enum ice_mac_type mac_type;
 
 	/* pci info */
 	u16 device_id;
@@ -46,7 +84,11 @@  struct ice_hw {
 	u16 subsystem_vendor_id;
 	u8 revision_id;
 
+	u8 pf_id;		/* device profile info */
+
 	struct ice_bus_info bus;
+	struct ice_nvm_info nvm;
+
 	/* Control Queue info */
 	struct ice_ctl_q_info adminq;
 
@@ -61,4 +103,11 @@  struct ice_hw {
 	u32 fw_build;		/* firmware build number */
 };
 
+/* Checksum and Shadow RAM pointers */
+#define ICE_SR_NVM_DEV_STARTER_VER	0x18
+#define ICE_SR_NVM_EETRACK_LO		0x2D
+#define ICE_SR_NVM_EETRACK_HI		0x2E
+#define ICE_SR_SECTOR_SIZE_IN_WORDS	0x800
+#define ICE_SR_WORDS_IN_1KB		512
+
 #endif /* _ICE_TYPE_H_ */