When the admin queue command to read NVM returns EBUSY, the driver
currently treats it as a fatal error and aborts the entire read
operation. This can cause spurious NVM read failures during periods of
high firmware activity.

Add retry logic to ice_read_flat_nvm() that handles EBUSY responses
from the admin queue. When an EBUSY error is encountered, release the
NVM resource lock, wait for ICE_SQ_SEND_DELAY_TIME_MS, re-acquire it,
and retry the failed read. The retry is attempted up to
ICE_SQ_SEND_MAX_EXECUTE times before giving up.

Code was extracted from OOT ice driver 1.15.4 release. Additional
change was made to reset last_cmd in case of retry to make sure that
all commands are retried properly.

Fixes: e94509906d6b ("ice: create function to read a section of the NVM and 
Shadow RAM")
Signed-off-by: Robert Malz <[email protected]>
---
 drivers/net/ethernet/intel/ice/ice_nvm.c | 25 +++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c 
b/drivers/net/ethernet/intel/ice/ice_nvm.c
index 7e187a804dfa..cbe21ef9d18e 100644
--- a/drivers/net/ethernet/intel/ice/ice_nvm.c
+++ b/drivers/net/ethernet/intel/ice/ice_nvm.c
@@ -67,6 +67,7 @@ ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, 
u8 *data,
 {
        u32 inlen = *length;
        u32 bytes_read = 0;
+       int retry_cnt = 0;
        bool last_cmd;
        int status;
 
@@ -96,11 +97,25 @@ ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 
*length, u8 *data,
                                         offset, read_size,
                                         data + bytes_read, last_cmd,
                                         read_shadow_ram, NULL);
-               if (status)
-                       break;
-
-               bytes_read += read_size;
-               offset += read_size;
+               if (status) {
+                       if (hw->adminq.sq_last_status != ICE_AQ_RC_EBUSY ||
+                           retry_cnt > ICE_SQ_SEND_MAX_EXECUTE)
+                               break;
+                       ice_debug(hw, ICE_DBG_NVM,
+                                 "NVM read EBUSY error, retry %d\n",
+                                 retry_cnt + 1);
+                       last_cmd = false;
+                       ice_release_nvm(hw);
+                       msleep(ICE_SQ_SEND_DELAY_TIME_MS);
+                       status = ice_acquire_nvm(hw, ICE_RES_READ);
+                       if (status)
+                               break;
+                       retry_cnt++;
+               } else {
+                       bytes_read += read_size;
+                       offset += read_size;
+                       retry_cnt = 0;
+               }
        } while (!last_cmd);
 
        *length = bytes_read;
-- 
2.34.1

Reply via email to