Re: [Intel-wired-lan] [PATCH iwl v3] ice: acquire NVM lock around each flash read
Robert Malz via Intel-wired-lan <[email protected]> Tue, 4 Aug 2026 10:37:27 +0200
| Newsgroups | org.osuosl.intel-wired-lan,org.kernel.vger.linux-kernel,org.kernel.vger.netdev |
|---|---|
| Message-ID | <CADcc-bzeA2CeWUttUcPTOhS=4e0k3=NMFS7i4=EgJHe-w=1j4A@mail.gmail.com> |
Hey Marcin, Thanks for the review. Changes applied in v4. I removed ice_read_sr_word_aq instead of ice_read_sr_word as callers already are using ice_read_sr_word. v4 ref: https://lists.osuosl.org/pipermail/intel-wired-lan/Week-of-Mon-2026= 0803/056281.html Thanks, Robert On Mon, Aug 3, 2026 at 12:05=E2=80=AFPM Marcin Szycik <[email protected]> wrote: > > > > On 31/07/2026 13:10, Robert Malz via Intel-wired-lan wrote: > > FW caps the NVM read lock at a maximum of 3000ms regardless of the time= out > > requested via ice_acquire_nvm(). ice_read_flat_nvm() splits a read into > > multiple ice_aq_read_nvm() commands, one per 4KB sector, all issued und= er a > > single lock taken by the caller. Reading a large region can exceed 3000= ms, > > so FW reclaims the lock mid-read and the remaining commands might fail. > > > > Move the lock acquire/release into ice_read_flat_nvm() so it brackets e= ach > > individual ice_aq_read_nvm() command, ensuring the lock is never held > > across more than one FW read. > > > > ice_release_nvm() issues its own AQ command and overwrites > > hw->adminq.sq_last_status, which some callers inspect after a failed re= ad. > > Add an optional read_aq_err output parameter to ice_read_flat_nvm() to > > capture the failing read's AQ error before the release; callers that ne= ed > > it (ice_discover_flash_size() and the ethtool/devlink log paths) use it > > instead of sq_last_status, others pass NULL. > > > > Callers that previously took the lock around ice_read_flat_nvm(), > > ice_read_sr_word() or ice_read_flash_module() now call them without it. > > The now-redundant per-block locking in ice_devlink_nvm_snapshot() is > > dropped. > > > > Fixes: e94509906d6b ("ice: create function to read a section of the NVM= and Shadow RAM") > > Signed-off-by: Robert Malz <[email protected]> > > --- > > v3: > > - Log the failure via ice_debug() when ice_acquire_nvm() fails inside > > ice_read_flat_nvm(), rather than silently aborting the read. > > v2: > > - Replace the save/restore of sq_last_status across ice_release_nvm(), > > which could race with a concurrent AdminQ command, with a new optiona= l > > read_aq_err output parameter. > > - Add missing "Return:" kdoc to ice_read_sr_word(). > > --- > > .../net/ethernet/intel/ice/devlink/devlink.c | 32 ++------ > > drivers/net/ethernet/intel/ice/ice_ethtool.c | 16 +--- > > drivers/net/ethernet/intel/ice/ice_nvm.c | 79 +++++++++++-------- > > drivers/net/ethernet/intel/ice/ice_nvm.h | 2 +- > > 4 files changed, 59 insertions(+), 70 deletions(-) > > > > diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers= /net/ethernet/intel/ice/devlink/devlink.c > > index 22b7d8e6bd9e..5a1ab9654fb8 100644 > > --- a/drivers/net/ethernet/intel/ice/devlink/devlink.c > > +++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c > > @@ -1856,6 +1856,7 @@ static int ice_devlink_nvm_snapshot(struct devlin= k *devlink, > > { > > struct ice_pf *pf =3D devlink_priv(devlink); > > struct device *dev =3D ice_pf_to_dev(pf); > > + enum libie_aq_err read_aq_err =3D LIBIE_AQ_RC_OK; > > RCT > Also scope can be reduced. > > > struct ice_hw *hw =3D &pf->hw; > > bool read_shadow_ram; > > u8 *nvm_data, *tmp, i; > > @@ -1891,26 +1892,16 @@ static int ice_devlink_nvm_snapshot(struct devl= ink *devlink, > > for (i =3D 0; i < num_blks; i++) { > > u32 read_sz =3D min_t(u32, ICE_DEVLINK_READ_BLK_SIZE, lef= t); > > > > - status =3D ice_acquire_nvm(hw, ICE_RES_READ); > > - if (status) { > > - dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_e= rr %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 =3D ice_read_flat_nvm(hw, i * ICE_DEVLINK_READ_BLK= _SIZE, > > - &read_sz, tmp, read_shadow_ram= ); > > + &read_sz, tmp, read_shadow_ram= , > > + &read_aq_err); > > if (status) { > > dev_dbg(dev, "ice_read_flat_nvm failed after read= ing %u bytes, err %d aq_err %d\n", > > - read_sz, status, hw->adminq.sq_last_statu= s); > > + read_sz, status, read_aq_err); > > NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM co= ntents"); > > - ice_release_nvm(hw); > > vfree(nvm_data); > > return -EIO; > > } > > - ice_release_nvm(hw); > > > > tmp +=3D read_sz; > > left -=3D read_sz; > > @@ -1945,6 +1936,7 @@ static int ice_devlink_nvm_read(struct devlink *d= evlink, > > { > > struct ice_pf *pf =3D devlink_priv(devlink); > > struct device *dev =3D ice_pf_to_dev(pf); > > + enum libie_aq_err read_aq_err =3D LIBIE_AQ_RC_OK; > > RCT > > > struct ice_hw *hw =3D &pf->hw; > > bool read_shadow_ram; > > u64 nvm_size; > > ... > > > /** > > - * ice_read_sr_word - Reads Shadow RAM word and acquire NVM if necessa= ry > > + * ice_read_sr_word - Reads Shadow RAM word > > * @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_wor= d_aq. > > + * Reads one 16 bit word from the Shadow RAM using ice_read_sr_word_aq= . > > + * > > + * The NVM lock is acquired and released internally by ice_read_flat_n= vm() > > + * around the FW read, so this function must be called without the loc= k held. > > + * > > + * Return: zero on success, or a negative error code on failure. > > */ > > int ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data) > > { > > - int status; > > - > > - status =3D ice_acquire_nvm(hw, ICE_RES_READ); > > - if (!status) { > > - status =3D ice_read_sr_word_aq(hw, offset, data); > > - ice_release_nvm(hw); > > - } > > - > > - return status; > > + return ice_read_sr_word_aq(hw, offset, data); > > ice_read_sr_word() is now a wrapper - can we remove it and use > ice_read_sr_word_aq() directly? > > > } > > > > /** > > @@ -856,20 +876,18 @@ int ice_get_inactive_netlist_ver(struct ice_hw *h= w, struct ice_netlist_info *net > > static int ice_discover_flash_size(struct ice_hw *hw) > > { > > u32 min_size =3D 0, max_size =3D ICE_AQC_NVM_MAX_OFFSET + 1; > > - int status; > > - > > - status =3D ice_acquire_nvm(hw, ICE_RES_READ); > > - if (status) > > - return status; > > + int status =3D 0; > > > > while ((max_size - min_size) > 1) { > > u32 offset =3D (max_size + min_size) / 2; > > + enum libie_aq_err read_aq_err =3D LIBIE_AQ_RC_OK; > > RCT > > > u32 len =3D 1; > > u8 data; > > ---8<--- > > Thanks, > Marcin