* @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 GLNVM_SRCTL register.
+ * Reads one 16 bit word from the Shadow RAM using the AdminQ
  **/
 static i40e_status i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,
                                         u16 *data)
 }
 
 /**
- * i40e_read_nvm_word - Reads Shadow RAM
+ * __i40e_read_nvm_word - Reads nvm word, assumes called does the locking
  * @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 GLNVM_SRCTL register.
+ * Reads one 16 bit word from the Shadow RAM.
+ *
+ * Do not use this function except in cases where the nvm lock is already
+ * taken via i40e_acquire_nvm().
+ **/
+static i40e_status __i40e_read_nvm_word(struct i40e_hw *hw,
+                                       u16 offset, u16 *data)
+{
+       i40e_status ret_code = 0;
+
+       if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)
+               ret_code = i40e_read_nvm_word_aq(hw, offset, data);
+       else
+               ret_code = i40e_read_nvm_word_srctl(hw, offset, data);
+       return ret_code;
+}
+
+/**
+ * i40e_read_nvm_word - Reads nvm word and acquire lock 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.
  **/
 i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
                               u16 *data)
 {
-       enum i40e_status_code ret_code = 0;
+       i40e_status ret_code = 0;
 
        ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
-       if (!ret_code) {
-               if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) {
-                       ret_code = i40e_read_nvm_word_aq(hw, offset, data);
-               } else {
-                       ret_code = i40e_read_nvm_word_srctl(hw, offset, data);
-               }
-               i40e_release_nvm(hw);
-       }
+       if (ret_code)
+               return ret_code;
+
+       ret_code = __i40e_read_nvm_word(hw, offset, data);
+
+       i40e_release_nvm(hw);
+
        return ret_code;
 }
 
 }
 
 /**
- * i40e_read_nvm_buffer - Reads Shadow RAM buffer
+ * __i40e_read_nvm_buffer - Reads nvm buffer, caller must acquire lock
  * @hw: pointer to the HW structure
  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
  * @words: (in) number of words to read; (out) number of words actually read
  * @data: words read from the Shadow RAM
  *
  * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
- * method. The buffer read is preceded by the NVM ownership take
- * and followed by the release.
+ * method.
  **/
-i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
-                                u16 *words, u16 *data)
+static i40e_status __i40e_read_nvm_buffer(struct i40e_hw *hw,
+                                         u16 offset, u16 *words,
+                                         u16 *data)
 {
-       enum i40e_status_code ret_code = 0;
+       i40e_status ret_code = 0;
 
-       if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) {
-               ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
-               if (!ret_code) {
-                       ret_code = i40e_read_nvm_buffer_aq(hw, offset, words,
-                                                          data);
-                       i40e_release_nvm(hw);
-               }
-       } else {
+       if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)
+               ret_code = i40e_read_nvm_buffer_aq(hw, offset, words, data);
+       else
                ret_code = i40e_read_nvm_buffer_srctl(hw, offset, words, data);
-       }
        return ret_code;
 }
 
        data = (u16 *)vmem.va;
 
        /* read pointer to VPD area */
-       ret_code = i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);
+       ret_code = __i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);
        if (ret_code) {
                ret_code = I40E_ERR_NVM_CHECKSUM;
                goto i40e_calc_nvm_checksum_exit;
        }
 
        /* read pointer to PCIe Alt Auto-load module */
-       ret_code = i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
-                                     &pcie_alt_module);
+       ret_code = __i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
+                                       &pcie_alt_module);
        if (ret_code) {
                ret_code = I40E_ERR_NVM_CHECKSUM;
                goto i40e_calc_nvm_checksum_exit;
                if ((i % I40E_SR_SECTOR_SIZE_IN_WORDS) == 0) {
                        u16 words = I40E_SR_SECTOR_SIZE_IN_WORDS;
 
-                       ret_code = i40e_read_nvm_buffer(hw, i, &words, data);
+                       ret_code = __i40e_read_nvm_buffer(hw, i, &words, data);
                        if (ret_code) {
                                ret_code = I40E_ERR_NVM_CHECKSUM;
                                goto i40e_calc_nvm_checksum_exit;
        u16 checksum_sr = 0;
        u16 checksum_local = 0;
 
+       /* We must acquire the NVM lock in order to correctly synchronize the
+        * NVM accesses across multiple PFs. Without doing so it is possible
+        * for one of the PFs to read invalid data potentially indicating that
+        * the checksum is invalid.
+        */
+       ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+       if (ret_code)
+               return ret_code;
        ret_code = i40e_calc_nvm_checksum(hw, &checksum_local);
+       __i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);
+       i40e_release_nvm(hw);
        if (ret_code)
-               goto i40e_validate_nvm_checksum_exit;
-
-       /* Do not use i40e_read_nvm_word() because we do not want to take
-        * the synchronization semaphores twice here.
-        */
-       i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);
+               return ret_code;
 
        /* Verify read checksum from EEPROM is the same as
         * calculated checksum
        if (checksum)
                *checksum = checksum_local;
 
-i40e_validate_nvm_checksum_exit:
        return ret_code;
 }
 
                break;
 
        case I40E_NVMUPD_CSUM_CON:
+               /* Assumes the caller has acquired the nvm */
                status = i40e_update_nvm_checksum(hw);
                if (status) {
                        *perrno = hw->aq.asq_last_status ?
                break;
 
        case I40E_NVMUPD_CSUM_LCB:
+               /* Assumes the caller has acquired the nvm */
                status = i40e_update_nvm_checksum(hw);
                if (status) {
                        *perrno = hw->aq.asq_last_status ?