|
|
@@ -211,6 +211,74 @@ read_nvm_exit:
|
|
|
return ret_code;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * i40e_read_nvm_aq - Read Shadow RAM.
|
|
|
+ * @hw: pointer to the HW structure.
|
|
|
+ * @module_pointer: module pointer location in words from the NVM beginning
|
|
|
+ * @offset: offset in words from module start
|
|
|
+ * @words: number of words to write
|
|
|
+ * @data: buffer with words to write to the Shadow RAM
|
|
|
+ * @last_command: tells the AdminQ that this is the last command
|
|
|
+ *
|
|
|
+ * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
|
|
|
+ **/
|
|
|
+static i40e_status i40e_read_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
|
|
|
+ u32 offset, u16 words, void *data,
|
|
|
+ bool last_command)
|
|
|
+{
|
|
|
+ i40e_status ret_code = I40E_ERR_NVM;
|
|
|
+ struct i40e_asq_cmd_details cmd_details;
|
|
|
+
|
|
|
+ memset(&cmd_details, 0, sizeof(cmd_details));
|
|
|
+
|
|
|
+ /* Here we are checking the SR limit only for the flat memory model.
|
|
|
+ * We cannot do it for the module-based model, as we did not acquire
|
|
|
+ * the NVM resource yet (we cannot get the module pointer value).
|
|
|
+ * Firmware will check the module-based model.
|
|
|
+ */
|
|
|
+ if ((offset + words) > hw->nvm.sr_size)
|
|
|
+ i40e_debug(hw, I40E_DEBUG_NVM,
|
|
|
+ "NVM write error: offset %d beyond Shadow RAM limit %d\n",
|
|
|
+ (offset + words), hw->nvm.sr_size);
|
|
|
+ else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
|
|
|
+ /* We can write only up to 4KB (one sector), in one AQ write */
|
|
|
+ i40e_debug(hw, I40E_DEBUG_NVM,
|
|
|
+ "NVM write fail error: tried to write %d words, limit is %d.\n",
|
|
|
+ words, I40E_SR_SECTOR_SIZE_IN_WORDS);
|
|
|
+ else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
|
|
|
+ != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
|
|
|
+ /* A single write cannot spread over two sectors */
|
|
|
+ i40e_debug(hw, I40E_DEBUG_NVM,
|
|
|
+ "NVM write error: cannot spread over two sectors in a single write offset=%d words=%d\n",
|
|
|
+ offset, words);
|
|
|
+ else
|
|
|
+ ret_code = i40e_aq_read_nvm(hw, module_pointer,
|
|
|
+ 2 * offset, /*bytes*/
|
|
|
+ 2 * words, /*bytes*/
|
|
|
+ data, last_command, &cmd_details);
|
|
|
+
|
|
|
+ return ret_code;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * i40e_read_nvm_word_aq - Reads Shadow RAM via AQ
|
|
|
+ * @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.
|
|
|
+ **/
|
|
|
+static i40e_status i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,
|
|
|
+ u16 *data)
|
|
|
+{
|
|
|
+ i40e_status ret_code = I40E_ERR_TIMEOUT;
|
|
|
+
|
|
|
+ ret_code = i40e_read_nvm_aq(hw, 0x0, offset, 1, data, true);
|
|
|
+ *data = le16_to_cpu(*(__le16 *)data);
|
|
|
+
|
|
|
+ return ret_code;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* i40e_read_nvm_word - Reads Shadow RAM
|
|
|
* @hw: pointer to the HW structure
|
|
|
@@ -222,6 +290,8 @@ read_nvm_exit:
|
|
|
i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
|
|
|
u16 *data)
|
|
|
{
|
|
|
+ if (hw->mac.type == I40E_MAC_X722)
|
|
|
+ return i40e_read_nvm_word_aq(hw, offset, data);
|
|
|
return i40e_read_nvm_word_srctl(hw, offset, data);
|
|
|
}
|
|
|
|
|
|
@@ -256,6 +326,63 @@ static i40e_status i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset,
|
|
|
return ret_code;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * i40e_read_nvm_buffer_aq - Reads Shadow RAM buffer via AQ
|
|
|
+ * @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_aq()
|
|
|
+ * method. The buffer read is preceded by the NVM ownership take
|
|
|
+ * and followed by the release.
|
|
|
+ **/
|
|
|
+static i40e_status i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset,
|
|
|
+ u16 *words, u16 *data)
|
|
|
+{
|
|
|
+ i40e_status ret_code;
|
|
|
+ u16 read_size = *words;
|
|
|
+ bool last_cmd = false;
|
|
|
+ u16 words_read = 0;
|
|
|
+ u16 i = 0;
|
|
|
+
|
|
|
+ do {
|
|
|
+ /* Calculate number of bytes we should read in this step.
|
|
|
+ * FVL AQ do not allow to read more than one page at a time or
|
|
|
+ * to cross page boundaries.
|
|
|
+ */
|
|
|
+ if (offset % I40E_SR_SECTOR_SIZE_IN_WORDS)
|
|
|
+ read_size = min(*words,
|
|
|
+ (u16)(I40E_SR_SECTOR_SIZE_IN_WORDS -
|
|
|
+ (offset % I40E_SR_SECTOR_SIZE_IN_WORDS)));
|
|
|
+ else
|
|
|
+ read_size = min((*words - words_read),
|
|
|
+ I40E_SR_SECTOR_SIZE_IN_WORDS);
|
|
|
+
|
|
|
+ /* Check if this is last command, if so set proper flag */
|
|
|
+ if ((words_read + read_size) >= *words)
|
|
|
+ last_cmd = true;
|
|
|
+
|
|
|
+ ret_code = i40e_read_nvm_aq(hw, 0x0, offset, read_size,
|
|
|
+ data + words_read, last_cmd);
|
|
|
+ if (ret_code)
|
|
|
+ goto read_nvm_buffer_aq_exit;
|
|
|
+
|
|
|
+ /* Increment counter for words already read and move offset to
|
|
|
+ * new read location
|
|
|
+ */
|
|
|
+ words_read += read_size;
|
|
|
+ offset += read_size;
|
|
|
+ } while (words_read < *words);
|
|
|
+
|
|
|
+ for (i = 0; i < *words; i++)
|
|
|
+ data[i] = le16_to_cpu(((__le16 *)data)[i]);
|
|
|
+
|
|
|
+read_nvm_buffer_aq_exit:
|
|
|
+ *words = words_read;
|
|
|
+ return ret_code;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* i40e_read_nvm_buffer - Reads Shadow RAM buffer
|
|
|
* @hw: pointer to the HW structure
|
|
|
@@ -270,6 +397,8 @@ static i40e_status i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset,
|
|
|
i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
|
|
|
u16 *words, u16 *data)
|
|
|
{
|
|
|
+ if (hw->mac.type == I40E_MAC_X722)
|
|
|
+ return i40e_read_nvm_buffer_aq(hw, offset, words, data);
|
|
|
return i40e_read_nvm_buffer_srctl(hw, offset, words, data);
|
|
|
}
|
|
|
|