From a8ac0bae54aee6e982a8755943c12bd8cb8f2ba1 Mon Sep 17 00:00:00 2001 From: Helin Zhang Date: Thu, 30 Apr 2015 23:03:15 +0800 Subject: [PATCH] i40e/base: update shadow RAM read/write To support different hardware, shadow RAM read should be done via SRCTL register or AQ command, and shadow RAM write should be done via AQ command only. Test report: http://www.dpdk.org/ml/archives/dev/2015-May/017384.html Signed-off-by: Helin Zhang Acked-by: Jijiang Liu Tested-by: Min Cao --- lib/librte_pmd_i40e/i40e/i40e_nvm.c | 196 +++++++++++++++++++++++++++- 1 file changed, 190 insertions(+), 6 deletions(-) diff --git a/lib/librte_pmd_i40e/i40e/i40e_nvm.c b/lib/librte_pmd_i40e/i40e/i40e_nvm.c index 2b7050806f..c63f5bac4d 100644 --- a/lib/librte_pmd_i40e/i40e/i40e_nvm.c +++ b/lib/librte_pmd_i40e/i40e/i40e_nvm.c @@ -33,6 +33,18 @@ POSSIBILITY OF SUCH DAMAGE. #include "i40e_prototype.h" +enum i40e_status_code i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset, + u16 *data); +enum i40e_status_code i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset, + u16 *data); +enum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset, + u16 *words, u16 *data); +enum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset, + u16 *words, u16 *data); +enum i40e_status_code i40e_read_nvm_aq(struct i40e_hw *hw, u8 module_pointer, + u32 offset, u16 words, void *data, + bool last_command); + /** * i40e_init_nvm_ops - Initialize NVM function pointers * @hw: pointer to the HW structure @@ -189,14 +201,30 @@ static enum i40e_status_code i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw) **/ enum i40e_status_code i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, u16 *data) +{ + return i40e_read_nvm_word_srctl(hw, offset, data); +} + +/** + * i40e_read_nvm_word_srctl - Reads Shadow RAM via SRCTL register + * @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. + **/ +enum i40e_status_code i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset, + u16 *data) { enum i40e_status_code ret_code = I40E_ERR_TIMEOUT; u32 sr_reg; - DEBUGFUNC("i40e_read_nvm_srctl"); + DEBUGFUNC("i40e_read_nvm_word_srctl"); if (offset >= hw->nvm.sr_size) { - DEBUGOUT("NVM read error: Offset beyond Shadow RAM limit.\n"); + i40e_debug(hw, I40E_DEBUG_NVM, + "NVM read error: Offset %d beyond Shadow RAM limit %d\n", + offset, hw->nvm.sr_size); ret_code = I40E_ERR_PARAM; goto read_nvm_exit; } @@ -219,13 +247,35 @@ enum i40e_status_code i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, } } if (ret_code != I40E_SUCCESS) - DEBUGOUT1("NVM read error: Couldn't access Shadow RAM address: 0x%x\n", - offset); + i40e_debug(hw, I40E_DEBUG_NVM, + "NVM read error: Couldn't access Shadow RAM address: 0x%x\n", + offset); read_nvm_exit: 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. + **/ +enum i40e_status_code i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset, + u16 *data) +{ + enum i40e_status_code ret_code = I40E_ERR_TIMEOUT; + + DEBUGFUNC("i40e_read_nvm_word_aq"); + + ret_code = i40e_read_nvm_aq(hw, 0x0, offset, 1, data, true); + *data = LE16_TO_CPU(*(__le16 *)data); + + return ret_code; +} + /** * i40e_read_nvm_buffer - Reads Shadow RAM buffer * @hw: pointer to the HW structure @@ -239,16 +289,33 @@ read_nvm_exit: **/ enum i40e_status_code i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, u16 *words, u16 *data) +{ + return i40e_read_nvm_buffer_srctl(hw, offset, words, data); +} + +/** + * i40e_read_nvm_buffer_srctl - Reads Shadow RAM buffer via SRCTL register + * @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. + **/ +enum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset, + u16 *words, u16 *data) { enum i40e_status_code ret_code = I40E_SUCCESS; u16 index, word; - DEBUGFUNC("i40e_read_nvm_buffer"); + DEBUGFUNC("i40e_read_nvm_buffer_srctl"); /* Loop thru the selected region */ for (word = 0; word < *words; word++) { index = offset + word; - ret_code = i40e_read_nvm_word(hw, index, &data[word]); + ret_code = i40e_read_nvm_word_srctl(hw, index, &data[word]); if (ret_code != I40E_SUCCESS) break; } @@ -258,6 +325,114 @@ enum i40e_status_code i40e_read_nvm_buffer(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. + **/ +enum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset, + u16 *words, u16 *data) +{ + enum i40e_status_code ret_code; + u16 read_size = *words; + bool last_cmd = false; + u16 words_read = 0; + u16 i = 0; + + DEBUGFUNC("i40e_read_nvm_buffer_aq"); + + 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 != I40E_SUCCESS) + 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_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. + **/ +enum i40e_status_code i40e_read_nvm_aq(struct i40e_hw *hw, u8 module_pointer, + u32 offset, u16 words, void *data, + bool last_command) +{ + enum i40e_status_code ret_code = I40E_ERR_NVM; + + DEBUGFUNC("i40e_read_nvm_aq"); + + /* 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, NULL); + + return ret_code; +} + /** * i40e_write_nvm_aq - Writes Shadow RAM. * @hw: pointer to the HW structure. @@ -316,6 +491,8 @@ enum i40e_status_code i40e_write_nvm_word(struct i40e_hw *hw, u32 offset, { DEBUGFUNC("i40e_write_nvm_word"); + *((__le16 *)data) = CPU_TO_LE16(*((u16 *)data)); + /* Value 0x00 below means that we treat SR as a flat mem */ return i40e_write_nvm_aq(hw, 0x00, offset, 1, data, false); } @@ -337,8 +514,15 @@ enum i40e_status_code i40e_write_nvm_buffer(struct i40e_hw *hw, u8 module_pointer, u32 offset, u16 words, void *data) { + __le16 *le_word_ptr = (__le16 *)data; + u16 *word_ptr = (u16 *)data; + u32 i = 0; + DEBUGFUNC("i40e_write_nvm_buffer"); + for (i = 0; i < words; i++) + le_word_ptr[i] = CPU_TO_LE16(word_ptr[i]); + /* Here we will only write one buffer as the size of the modules * mirrored in the Shadow RAM is always less than 4K. */ -- 2.20.1