|
@@ -266,7 +266,7 @@ static i40e_status i40e_read_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
|
|
|
* @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)
|
|
@@ -280,27 +280,49 @@ static i40e_status i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 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;
|
|
|
}
|
|
|
|
|
@@ -393,31 +415,25 @@ read_nvm_buffer_aq_exit:
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 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;
|
|
|
}
|
|
|
|
|
@@ -499,15 +515,15 @@ static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw,
|
|
|
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;
|
|
@@ -521,7 +537,7 @@ static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw,
|
|
|
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;
|
|
@@ -593,14 +609,19 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,
|
|
|
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
|
|
@@ -612,7 +633,6 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,
|
|
|
if (checksum)
|
|
|
*checksum = checksum_local;
|
|
|
|
|
|
-i40e_validate_nvm_checksum_exit:
|
|
|
return ret_code;
|
|
|
}
|
|
|
|
|
@@ -997,6 +1017,7 @@ retry:
|
|
|
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 ?
|
|
@@ -1011,6 +1032,7 @@ retry:
|
|
|
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 ?
|