diff options
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_devlink.c')
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_devlink.c | 59 | 
1 files changed, 40 insertions, 19 deletions
| diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.c b/drivers/net/ethernet/intel/ice/ice_devlink.c index 3991d62473bf..3337314a7b35 100644 --- a/drivers/net/ethernet/intel/ice/ice_devlink.c +++ b/drivers/net/ethernet/intel/ice/ice_devlink.c @@ -814,6 +814,8 @@ void ice_devlink_destroy_vf_port(struct ice_vf *vf)  	devlink_port_unregister(devlink_port);  } +#define ICE_DEVLINK_READ_BLK_SIZE (1024 * 1024) +  /**   * ice_devlink_nvm_snapshot - Capture a snapshot of the NVM flash contents   * @devlink: the devlink instance @@ -840,8 +842,9 @@ static int ice_devlink_nvm_snapshot(struct devlink *devlink,  	struct ice_pf *pf = devlink_priv(devlink);  	struct device *dev = ice_pf_to_dev(pf);  	struct ice_hw *hw = &pf->hw; -	void *nvm_data; -	u32 nvm_size; +	u8 *nvm_data, *tmp, i; +	u32 nvm_size, left; +	s8 num_blks;  	int status;  	nvm_size = hw->flash.flash_size; @@ -849,26 +852,44 @@ static int ice_devlink_nvm_snapshot(struct devlink *devlink,  	if (!nvm_data)  		return -ENOMEM; -	status = ice_acquire_nvm(hw, ICE_RES_READ); -	if (status) { -		dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n", -			status, hw->adminq.sq_last_status); -		NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore"); -		vfree(nvm_data); -		return status; -	} -	status = ice_read_flat_nvm(hw, 0, &nvm_size, nvm_data, false); -	if (status) { -		dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n", -			nvm_size, status, hw->adminq.sq_last_status); -		NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents"); +	num_blks = DIV_ROUND_UP(nvm_size, ICE_DEVLINK_READ_BLK_SIZE); +	tmp = nvm_data; +	left = nvm_size; + +	/* Some systems take longer to read the NVM than others which causes the +	 * FW to reclaim the NVM lock before the entire NVM has been read. Fix +	 * this by breaking the reads of the NVM into smaller chunks that will +	 * probably not take as long. This has some overhead since we are +	 * increasing the number of AQ commands, but it should always work +	 */ +	for (i = 0; i < num_blks; i++) { +		u32 read_sz = min_t(u32, ICE_DEVLINK_READ_BLK_SIZE, left); + +		status = ice_acquire_nvm(hw, ICE_RES_READ); +		if (status) { +			dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n", +				status, hw->adminq.sq_last_status); +			NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore"); +			vfree(nvm_data); +			return -EIO; +		} + +		status = ice_read_flat_nvm(hw, i * ICE_DEVLINK_READ_BLK_SIZE, +					   &read_sz, tmp, false); +		if (status) { +			dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n", +				read_sz, status, hw->adminq.sq_last_status); +			NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents"); +			ice_release_nvm(hw); +			vfree(nvm_data); +			return -EIO; +		}  		ice_release_nvm(hw); -		vfree(nvm_data); -		return status; -	} -	ice_release_nvm(hw); +		tmp += read_sz; +		left -= read_sz; +	}  	*data = nvm_data; |