1*61ae650dSJack F Vogel /****************************************************************************** 2*61ae650dSJack F Vogel 3*61ae650dSJack F Vogel Copyright (c) 2013-2014, Intel Corporation 4*61ae650dSJack F Vogel All rights reserved. 5*61ae650dSJack F Vogel 6*61ae650dSJack F Vogel Redistribution and use in source and binary forms, with or without 7*61ae650dSJack F Vogel modification, are permitted provided that the following conditions are met: 8*61ae650dSJack F Vogel 9*61ae650dSJack F Vogel 1. Redistributions of source code must retain the above copyright notice, 10*61ae650dSJack F Vogel this list of conditions and the following disclaimer. 11*61ae650dSJack F Vogel 12*61ae650dSJack F Vogel 2. Redistributions in binary form must reproduce the above copyright 13*61ae650dSJack F Vogel notice, this list of conditions and the following disclaimer in the 14*61ae650dSJack F Vogel documentation and/or other materials provided with the distribution. 15*61ae650dSJack F Vogel 16*61ae650dSJack F Vogel 3. Neither the name of the Intel Corporation nor the names of its 17*61ae650dSJack F Vogel contributors may be used to endorse or promote products derived from 18*61ae650dSJack F Vogel this software without specific prior written permission. 19*61ae650dSJack F Vogel 20*61ae650dSJack F Vogel THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21*61ae650dSJack F Vogel AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22*61ae650dSJack F Vogel IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23*61ae650dSJack F Vogel ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24*61ae650dSJack F Vogel LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25*61ae650dSJack F Vogel CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26*61ae650dSJack F Vogel SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27*61ae650dSJack F Vogel INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28*61ae650dSJack F Vogel CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29*61ae650dSJack F Vogel ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30*61ae650dSJack F Vogel POSSIBILITY OF SUCH DAMAGE. 31*61ae650dSJack F Vogel 32*61ae650dSJack F Vogel ******************************************************************************/ 33*61ae650dSJack F Vogel /*$FreeBSD$*/ 34*61ae650dSJack F Vogel 35*61ae650dSJack F Vogel #include "i40e_prototype.h" 36*61ae650dSJack F Vogel 37*61ae650dSJack F Vogel /** 38*61ae650dSJack F Vogel * i40e_init_nvm_ops - Initialize NVM function pointers 39*61ae650dSJack F Vogel * @hw: pointer to the HW structure 40*61ae650dSJack F Vogel * 41*61ae650dSJack F Vogel * Setup the function pointers and the NVM info structure. Should be called 42*61ae650dSJack F Vogel * once per NVM initialization, e.g. inside the i40e_init_shared_code(). 43*61ae650dSJack F Vogel * Please notice that the NVM term is used here (& in all methods covered 44*61ae650dSJack F Vogel * in this file) as an equivalent of the FLASH part mapped into the SR. 45*61ae650dSJack F Vogel * We are accessing FLASH always thru the Shadow RAM. 46*61ae650dSJack F Vogel **/ 47*61ae650dSJack F Vogel enum i40e_status_code i40e_init_nvm(struct i40e_hw *hw) 48*61ae650dSJack F Vogel { 49*61ae650dSJack F Vogel struct i40e_nvm_info *nvm = &hw->nvm; 50*61ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 51*61ae650dSJack F Vogel u32 fla, gens; 52*61ae650dSJack F Vogel u8 sr_size; 53*61ae650dSJack F Vogel 54*61ae650dSJack F Vogel DEBUGFUNC("i40e_init_nvm"); 55*61ae650dSJack F Vogel 56*61ae650dSJack F Vogel /* The SR size is stored regardless of the nvm programming mode 57*61ae650dSJack F Vogel * as the blank mode may be used in the factory line. 58*61ae650dSJack F Vogel */ 59*61ae650dSJack F Vogel gens = rd32(hw, I40E_GLNVM_GENS); 60*61ae650dSJack F Vogel sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >> 61*61ae650dSJack F Vogel I40E_GLNVM_GENS_SR_SIZE_SHIFT); 62*61ae650dSJack F Vogel /* Switching to words (sr_size contains power of 2KB) */ 63*61ae650dSJack F Vogel nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB; 64*61ae650dSJack F Vogel 65*61ae650dSJack F Vogel /* Check if we are in the normal or blank NVM programming mode */ 66*61ae650dSJack F Vogel fla = rd32(hw, I40E_GLNVM_FLA); 67*61ae650dSJack F Vogel if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */ 68*61ae650dSJack F Vogel /* Max NVM timeout */ 69*61ae650dSJack F Vogel nvm->timeout = I40E_MAX_NVM_TIMEOUT; 70*61ae650dSJack F Vogel nvm->blank_nvm_mode = FALSE; 71*61ae650dSJack F Vogel } else { /* Blank programming mode */ 72*61ae650dSJack F Vogel nvm->blank_nvm_mode = TRUE; 73*61ae650dSJack F Vogel ret_code = I40E_ERR_NVM_BLANK_MODE; 74*61ae650dSJack F Vogel DEBUGOUT("NVM init error: unsupported blank mode.\n"); 75*61ae650dSJack F Vogel } 76*61ae650dSJack F Vogel 77*61ae650dSJack F Vogel return ret_code; 78*61ae650dSJack F Vogel } 79*61ae650dSJack F Vogel 80*61ae650dSJack F Vogel /** 81*61ae650dSJack F Vogel * i40e_acquire_nvm - Generic request for acquiring the NVM ownership 82*61ae650dSJack F Vogel * @hw: pointer to the HW structure 83*61ae650dSJack F Vogel * @access: NVM access type (read or write) 84*61ae650dSJack F Vogel * 85*61ae650dSJack F Vogel * This function will request NVM ownership for reading 86*61ae650dSJack F Vogel * via the proper Admin Command. 87*61ae650dSJack F Vogel **/ 88*61ae650dSJack F Vogel enum i40e_status_code i40e_acquire_nvm(struct i40e_hw *hw, 89*61ae650dSJack F Vogel enum i40e_aq_resource_access_type access) 90*61ae650dSJack F Vogel { 91*61ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 92*61ae650dSJack F Vogel u64 gtime, timeout; 93*61ae650dSJack F Vogel u64 time = 0; 94*61ae650dSJack F Vogel 95*61ae650dSJack F Vogel DEBUGFUNC("i40e_acquire_nvm"); 96*61ae650dSJack F Vogel 97*61ae650dSJack F Vogel if (hw->nvm.blank_nvm_mode) 98*61ae650dSJack F Vogel goto i40e_i40e_acquire_nvm_exit; 99*61ae650dSJack F Vogel 100*61ae650dSJack F Vogel ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access, 101*61ae650dSJack F Vogel 0, &time, NULL); 102*61ae650dSJack F Vogel /* Reading the Global Device Timer */ 103*61ae650dSJack F Vogel gtime = rd32(hw, I40E_GLVFGEN_TIMER); 104*61ae650dSJack F Vogel 105*61ae650dSJack F Vogel /* Store the timeout */ 106*61ae650dSJack F Vogel hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time) + gtime; 107*61ae650dSJack F Vogel 108*61ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) { 109*61ae650dSJack F Vogel /* Set the polling timeout */ 110*61ae650dSJack F Vogel if (time > I40E_MAX_NVM_TIMEOUT) 111*61ae650dSJack F Vogel timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT) 112*61ae650dSJack F Vogel + gtime; 113*61ae650dSJack F Vogel else 114*61ae650dSJack F Vogel timeout = hw->nvm.hw_semaphore_timeout; 115*61ae650dSJack F Vogel /* Poll until the current NVM owner timeouts */ 116*61ae650dSJack F Vogel while (gtime < timeout) { 117*61ae650dSJack F Vogel i40e_msec_delay(10); 118*61ae650dSJack F Vogel ret_code = i40e_aq_request_resource(hw, 119*61ae650dSJack F Vogel I40E_NVM_RESOURCE_ID, 120*61ae650dSJack F Vogel access, 0, &time, 121*61ae650dSJack F Vogel NULL); 122*61ae650dSJack F Vogel if (ret_code == I40E_SUCCESS) { 123*61ae650dSJack F Vogel hw->nvm.hw_semaphore_timeout = 124*61ae650dSJack F Vogel I40E_MS_TO_GTIME(time) + gtime; 125*61ae650dSJack F Vogel break; 126*61ae650dSJack F Vogel } 127*61ae650dSJack F Vogel gtime = rd32(hw, I40E_GLVFGEN_TIMER); 128*61ae650dSJack F Vogel } 129*61ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) { 130*61ae650dSJack F Vogel hw->nvm.hw_semaphore_timeout = 0; 131*61ae650dSJack F Vogel hw->nvm.hw_semaphore_wait = 132*61ae650dSJack F Vogel I40E_MS_TO_GTIME(time) + gtime; 133*61ae650dSJack F Vogel DEBUGOUT1("NVM acquire timed out, wait %llu ms before trying again.\n", 134*61ae650dSJack F Vogel time); 135*61ae650dSJack F Vogel } 136*61ae650dSJack F Vogel } 137*61ae650dSJack F Vogel 138*61ae650dSJack F Vogel i40e_i40e_acquire_nvm_exit: 139*61ae650dSJack F Vogel return ret_code; 140*61ae650dSJack F Vogel } 141*61ae650dSJack F Vogel 142*61ae650dSJack F Vogel /** 143*61ae650dSJack F Vogel * i40e_release_nvm - Generic request for releasing the NVM ownership 144*61ae650dSJack F Vogel * @hw: pointer to the HW structure 145*61ae650dSJack F Vogel * 146*61ae650dSJack F Vogel * This function will release NVM resource via the proper Admin Command. 147*61ae650dSJack F Vogel **/ 148*61ae650dSJack F Vogel void i40e_release_nvm(struct i40e_hw *hw) 149*61ae650dSJack F Vogel { 150*61ae650dSJack F Vogel DEBUGFUNC("i40e_release_nvm"); 151*61ae650dSJack F Vogel 152*61ae650dSJack F Vogel if (!hw->nvm.blank_nvm_mode) 153*61ae650dSJack F Vogel i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL); 154*61ae650dSJack F Vogel } 155*61ae650dSJack F Vogel 156*61ae650dSJack F Vogel /** 157*61ae650dSJack F Vogel * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit 158*61ae650dSJack F Vogel * @hw: pointer to the HW structure 159*61ae650dSJack F Vogel * 160*61ae650dSJack F Vogel * Polls the SRCTL Shadow RAM register done bit. 161*61ae650dSJack F Vogel **/ 162*61ae650dSJack F Vogel static enum i40e_status_code i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw) 163*61ae650dSJack F Vogel { 164*61ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_ERR_TIMEOUT; 165*61ae650dSJack F Vogel u32 srctl, wait_cnt; 166*61ae650dSJack F Vogel 167*61ae650dSJack F Vogel DEBUGFUNC("i40e_poll_sr_srctl_done_bit"); 168*61ae650dSJack F Vogel 169*61ae650dSJack F Vogel /* Poll the I40E_GLNVM_SRCTL until the done bit is set */ 170*61ae650dSJack F Vogel for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) { 171*61ae650dSJack F Vogel srctl = rd32(hw, I40E_GLNVM_SRCTL); 172*61ae650dSJack F Vogel if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) { 173*61ae650dSJack F Vogel ret_code = I40E_SUCCESS; 174*61ae650dSJack F Vogel break; 175*61ae650dSJack F Vogel } 176*61ae650dSJack F Vogel i40e_usec_delay(5); 177*61ae650dSJack F Vogel } 178*61ae650dSJack F Vogel if (ret_code == I40E_ERR_TIMEOUT) 179*61ae650dSJack F Vogel DEBUGOUT("Done bit in GLNVM_SRCTL not set"); 180*61ae650dSJack F Vogel return ret_code; 181*61ae650dSJack F Vogel } 182*61ae650dSJack F Vogel 183*61ae650dSJack F Vogel /** 184*61ae650dSJack F Vogel * i40e_read_nvm_word - Reads Shadow RAM 185*61ae650dSJack F Vogel * @hw: pointer to the HW structure 186*61ae650dSJack F Vogel * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) 187*61ae650dSJack F Vogel * @data: word read from the Shadow RAM 188*61ae650dSJack F Vogel * 189*61ae650dSJack F Vogel * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. 190*61ae650dSJack F Vogel **/ 191*61ae650dSJack F Vogel enum i40e_status_code i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, 192*61ae650dSJack F Vogel u16 *data) 193*61ae650dSJack F Vogel { 194*61ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_ERR_TIMEOUT; 195*61ae650dSJack F Vogel u32 sr_reg; 196*61ae650dSJack F Vogel 197*61ae650dSJack F Vogel DEBUGFUNC("i40e_read_nvm_srctl"); 198*61ae650dSJack F Vogel 199*61ae650dSJack F Vogel if (offset >= hw->nvm.sr_size) { 200*61ae650dSJack F Vogel DEBUGOUT("NVM read error: Offset beyond Shadow RAM limit.\n"); 201*61ae650dSJack F Vogel ret_code = I40E_ERR_PARAM; 202*61ae650dSJack F Vogel goto read_nvm_exit; 203*61ae650dSJack F Vogel } 204*61ae650dSJack F Vogel 205*61ae650dSJack F Vogel /* Poll the done bit first */ 206*61ae650dSJack F Vogel ret_code = i40e_poll_sr_srctl_done_bit(hw); 207*61ae650dSJack F Vogel if (ret_code == I40E_SUCCESS) { 208*61ae650dSJack F Vogel /* Write the address and start reading */ 209*61ae650dSJack F Vogel sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) | 210*61ae650dSJack F Vogel (1 << I40E_GLNVM_SRCTL_START_SHIFT); 211*61ae650dSJack F Vogel wr32(hw, I40E_GLNVM_SRCTL, sr_reg); 212*61ae650dSJack F Vogel 213*61ae650dSJack F Vogel /* Poll I40E_GLNVM_SRCTL until the done bit is set */ 214*61ae650dSJack F Vogel ret_code = i40e_poll_sr_srctl_done_bit(hw); 215*61ae650dSJack F Vogel if (ret_code == I40E_SUCCESS) { 216*61ae650dSJack F Vogel sr_reg = rd32(hw, I40E_GLNVM_SRDATA); 217*61ae650dSJack F Vogel *data = (u16)((sr_reg & 218*61ae650dSJack F Vogel I40E_GLNVM_SRDATA_RDDATA_MASK) 219*61ae650dSJack F Vogel >> I40E_GLNVM_SRDATA_RDDATA_SHIFT); 220*61ae650dSJack F Vogel } 221*61ae650dSJack F Vogel } 222*61ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) 223*61ae650dSJack F Vogel DEBUGOUT1("NVM read error: Couldn't access Shadow RAM address: 0x%x\n", 224*61ae650dSJack F Vogel offset); 225*61ae650dSJack F Vogel 226*61ae650dSJack F Vogel read_nvm_exit: 227*61ae650dSJack F Vogel return ret_code; 228*61ae650dSJack F Vogel } 229*61ae650dSJack F Vogel 230*61ae650dSJack F Vogel /** 231*61ae650dSJack F Vogel * i40e_read_nvm_buffer - Reads Shadow RAM buffer 232*61ae650dSJack F Vogel * @hw: pointer to the HW structure 233*61ae650dSJack F Vogel * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). 234*61ae650dSJack F Vogel * @words: (in) number of words to read; (out) number of words actually read 235*61ae650dSJack F Vogel * @data: words read from the Shadow RAM 236*61ae650dSJack F Vogel * 237*61ae650dSJack F Vogel * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd() 238*61ae650dSJack F Vogel * method. The buffer read is preceded by the NVM ownership take 239*61ae650dSJack F Vogel * and followed by the release. 240*61ae650dSJack F Vogel **/ 241*61ae650dSJack F Vogel enum i40e_status_code i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, 242*61ae650dSJack F Vogel u16 *words, u16 *data) 243*61ae650dSJack F Vogel { 244*61ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 245*61ae650dSJack F Vogel u16 index, word; 246*61ae650dSJack F Vogel 247*61ae650dSJack F Vogel DEBUGFUNC("i40e_read_nvm_buffer"); 248*61ae650dSJack F Vogel 249*61ae650dSJack F Vogel /* Loop thru the selected region */ 250*61ae650dSJack F Vogel for (word = 0; word < *words; word++) { 251*61ae650dSJack F Vogel index = offset + word; 252*61ae650dSJack F Vogel ret_code = i40e_read_nvm_word(hw, index, &data[word]); 253*61ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) 254*61ae650dSJack F Vogel break; 255*61ae650dSJack F Vogel } 256*61ae650dSJack F Vogel 257*61ae650dSJack F Vogel /* Update the number of words read from the Shadow RAM */ 258*61ae650dSJack F Vogel *words = word; 259*61ae650dSJack F Vogel 260*61ae650dSJack F Vogel return ret_code; 261*61ae650dSJack F Vogel } 262*61ae650dSJack F Vogel /** 263*61ae650dSJack F Vogel * i40e_write_nvm_aq - Writes Shadow RAM. 264*61ae650dSJack F Vogel * @hw: pointer to the HW structure. 265*61ae650dSJack F Vogel * @module_pointer: module pointer location in words from the NVM beginning 266*61ae650dSJack F Vogel * @offset: offset in words from module start 267*61ae650dSJack F Vogel * @words: number of words to write 268*61ae650dSJack F Vogel * @data: buffer with words to write to the Shadow RAM 269*61ae650dSJack F Vogel * @last_command: tells the AdminQ that this is the last command 270*61ae650dSJack F Vogel * 271*61ae650dSJack F Vogel * Writes a 16 bit words buffer to the Shadow RAM using the admin command. 272*61ae650dSJack F Vogel **/ 273*61ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer, 274*61ae650dSJack F Vogel u32 offset, u16 words, void *data, 275*61ae650dSJack F Vogel bool last_command) 276*61ae650dSJack F Vogel { 277*61ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_ERR_NVM; 278*61ae650dSJack F Vogel 279*61ae650dSJack F Vogel DEBUGFUNC("i40e_write_nvm_aq"); 280*61ae650dSJack F Vogel 281*61ae650dSJack F Vogel /* Here we are checking the SR limit only for the flat memory model. 282*61ae650dSJack F Vogel * We cannot do it for the module-based model, as we did not acquire 283*61ae650dSJack F Vogel * the NVM resource yet (we cannot get the module pointer value). 284*61ae650dSJack F Vogel * Firmware will check the module-based model. 285*61ae650dSJack F Vogel */ 286*61ae650dSJack F Vogel if ((offset + words) > hw->nvm.sr_size) 287*61ae650dSJack F Vogel DEBUGOUT("NVM write error: offset beyond Shadow RAM limit.\n"); 288*61ae650dSJack F Vogel else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS) 289*61ae650dSJack F Vogel /* We can write only up to 4KB (one sector), in one AQ write */ 290*61ae650dSJack F Vogel DEBUGOUT("NVM write fail error: cannot write more than 4KB in a single write.\n"); 291*61ae650dSJack F Vogel else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS) 292*61ae650dSJack F Vogel != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS)) 293*61ae650dSJack F Vogel /* A single write cannot spread over two sectors */ 294*61ae650dSJack F Vogel DEBUGOUT("NVM write error: cannot spread over two sectors in a single write.\n"); 295*61ae650dSJack F Vogel else 296*61ae650dSJack F Vogel ret_code = i40e_aq_update_nvm(hw, module_pointer, 297*61ae650dSJack F Vogel 2 * offset, /*bytes*/ 298*61ae650dSJack F Vogel 2 * words, /*bytes*/ 299*61ae650dSJack F Vogel data, last_command, NULL); 300*61ae650dSJack F Vogel 301*61ae650dSJack F Vogel return ret_code; 302*61ae650dSJack F Vogel } 303*61ae650dSJack F Vogel 304*61ae650dSJack F Vogel /** 305*61ae650dSJack F Vogel * i40e_write_nvm_word - Writes Shadow RAM word 306*61ae650dSJack F Vogel * @hw: pointer to the HW structure 307*61ae650dSJack F Vogel * @offset: offset of the Shadow RAM word to write 308*61ae650dSJack F Vogel * @data: word to write to the Shadow RAM 309*61ae650dSJack F Vogel * 310*61ae650dSJack F Vogel * Writes a 16 bit word to the SR using the i40e_write_nvm_aq() method. 311*61ae650dSJack F Vogel * NVM ownership have to be acquired and released (on ARQ completion event 312*61ae650dSJack F Vogel * reception) by caller. To commit SR to NVM update checksum function 313*61ae650dSJack F Vogel * should be called. 314*61ae650dSJack F Vogel **/ 315*61ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_word(struct i40e_hw *hw, u32 offset, 316*61ae650dSJack F Vogel void *data) 317*61ae650dSJack F Vogel { 318*61ae650dSJack F Vogel DEBUGFUNC("i40e_write_nvm_word"); 319*61ae650dSJack F Vogel 320*61ae650dSJack F Vogel /* Value 0x00 below means that we treat SR as a flat mem */ 321*61ae650dSJack F Vogel return i40e_write_nvm_aq(hw, 0x00, offset, 1, data, FALSE); 322*61ae650dSJack F Vogel } 323*61ae650dSJack F Vogel 324*61ae650dSJack F Vogel /** 325*61ae650dSJack F Vogel * i40e_write_nvm_buffer - Writes Shadow RAM buffer 326*61ae650dSJack F Vogel * @hw: pointer to the HW structure 327*61ae650dSJack F Vogel * @module_pointer: module pointer location in words from the NVM beginning 328*61ae650dSJack F Vogel * @offset: offset of the Shadow RAM buffer to write 329*61ae650dSJack F Vogel * @words: number of words to write 330*61ae650dSJack F Vogel * @data: words to write to the Shadow RAM 331*61ae650dSJack F Vogel * 332*61ae650dSJack F Vogel * Writes a 16 bit words buffer to the Shadow RAM using the admin command. 333*61ae650dSJack F Vogel * NVM ownership must be acquired before calling this function and released 334*61ae650dSJack F Vogel * on ARQ completion event reception by caller. To commit SR to NVM update 335*61ae650dSJack F Vogel * checksum function should be called. 336*61ae650dSJack F Vogel **/ 337*61ae650dSJack F Vogel enum i40e_status_code i40e_write_nvm_buffer(struct i40e_hw *hw, 338*61ae650dSJack F Vogel u8 module_pointer, u32 offset, 339*61ae650dSJack F Vogel u16 words, void *data) 340*61ae650dSJack F Vogel { 341*61ae650dSJack F Vogel DEBUGFUNC("i40e_write_nvm_buffer"); 342*61ae650dSJack F Vogel 343*61ae650dSJack F Vogel /* Here we will only write one buffer as the size of the modules 344*61ae650dSJack F Vogel * mirrored in the Shadow RAM is always less than 4K. 345*61ae650dSJack F Vogel */ 346*61ae650dSJack F Vogel return i40e_write_nvm_aq(hw, module_pointer, offset, words, 347*61ae650dSJack F Vogel data, FALSE); 348*61ae650dSJack F Vogel } 349*61ae650dSJack F Vogel 350*61ae650dSJack F Vogel /** 351*61ae650dSJack F Vogel * i40e_calc_nvm_checksum - Calculates and returns the checksum 352*61ae650dSJack F Vogel * @hw: pointer to hardware structure 353*61ae650dSJack F Vogel * @checksum: pointer to the checksum 354*61ae650dSJack F Vogel * 355*61ae650dSJack F Vogel * This function calculates SW Checksum that covers the whole 64kB shadow RAM 356*61ae650dSJack F Vogel * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD 357*61ae650dSJack F Vogel * is customer specific and unknown. Therefore, this function skips all maximum 358*61ae650dSJack F Vogel * possible size of VPD (1kB). 359*61ae650dSJack F Vogel **/ 360*61ae650dSJack F Vogel enum i40e_status_code i40e_calc_nvm_checksum(struct i40e_hw *hw, u16 *checksum) 361*61ae650dSJack F Vogel { 362*61ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 363*61ae650dSJack F Vogel u16 pcie_alt_module = 0; 364*61ae650dSJack F Vogel u16 checksum_local = 0; 365*61ae650dSJack F Vogel u16 vpd_module = 0; 366*61ae650dSJack F Vogel u16 word = 0; 367*61ae650dSJack F Vogel u32 i = 0; 368*61ae650dSJack F Vogel 369*61ae650dSJack F Vogel DEBUGFUNC("i40e_calc_nvm_checksum"); 370*61ae650dSJack F Vogel 371*61ae650dSJack F Vogel /* read pointer to VPD area */ 372*61ae650dSJack F Vogel ret_code = i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module); 373*61ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) { 374*61ae650dSJack F Vogel ret_code = I40E_ERR_NVM_CHECKSUM; 375*61ae650dSJack F Vogel goto i40e_calc_nvm_checksum_exit; 376*61ae650dSJack F Vogel } 377*61ae650dSJack F Vogel 378*61ae650dSJack F Vogel /* read pointer to PCIe Alt Auto-load module */ 379*61ae650dSJack F Vogel ret_code = i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR, 380*61ae650dSJack F Vogel &pcie_alt_module); 381*61ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) { 382*61ae650dSJack F Vogel ret_code = I40E_ERR_NVM_CHECKSUM; 383*61ae650dSJack F Vogel goto i40e_calc_nvm_checksum_exit; 384*61ae650dSJack F Vogel } 385*61ae650dSJack F Vogel 386*61ae650dSJack F Vogel /* Calculate SW checksum that covers the whole 64kB shadow RAM 387*61ae650dSJack F Vogel * except the VPD and PCIe ALT Auto-load modules 388*61ae650dSJack F Vogel */ 389*61ae650dSJack F Vogel for (i = 0; i < hw->nvm.sr_size; i++) { 390*61ae650dSJack F Vogel /* Skip Checksum word */ 391*61ae650dSJack F Vogel if (i == I40E_SR_SW_CHECKSUM_WORD) 392*61ae650dSJack F Vogel i++; 393*61ae650dSJack F Vogel /* Skip VPD module (convert byte size to word count) */ 394*61ae650dSJack F Vogel if (i == (u32)vpd_module) { 395*61ae650dSJack F Vogel i += (I40E_SR_VPD_MODULE_MAX_SIZE / 2); 396*61ae650dSJack F Vogel if (i >= hw->nvm.sr_size) 397*61ae650dSJack F Vogel break; 398*61ae650dSJack F Vogel } 399*61ae650dSJack F Vogel /* Skip PCIe ALT module (convert byte size to word count) */ 400*61ae650dSJack F Vogel if (i == (u32)pcie_alt_module) { 401*61ae650dSJack F Vogel i += (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2); 402*61ae650dSJack F Vogel if (i >= hw->nvm.sr_size) 403*61ae650dSJack F Vogel break; 404*61ae650dSJack F Vogel } 405*61ae650dSJack F Vogel 406*61ae650dSJack F Vogel ret_code = i40e_read_nvm_word(hw, (u16)i, &word); 407*61ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) { 408*61ae650dSJack F Vogel ret_code = I40E_ERR_NVM_CHECKSUM; 409*61ae650dSJack F Vogel goto i40e_calc_nvm_checksum_exit; 410*61ae650dSJack F Vogel } 411*61ae650dSJack F Vogel checksum_local += word; 412*61ae650dSJack F Vogel } 413*61ae650dSJack F Vogel 414*61ae650dSJack F Vogel *checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local; 415*61ae650dSJack F Vogel 416*61ae650dSJack F Vogel i40e_calc_nvm_checksum_exit: 417*61ae650dSJack F Vogel return ret_code; 418*61ae650dSJack F Vogel } 419*61ae650dSJack F Vogel 420*61ae650dSJack F Vogel /** 421*61ae650dSJack F Vogel * i40e_update_nvm_checksum - Updates the NVM checksum 422*61ae650dSJack F Vogel * @hw: pointer to hardware structure 423*61ae650dSJack F Vogel * 424*61ae650dSJack F Vogel * NVM ownership must be acquired before calling this function and released 425*61ae650dSJack F Vogel * on ARQ completion event reception by caller. 426*61ae650dSJack F Vogel * This function will commit SR to NVM. 427*61ae650dSJack F Vogel **/ 428*61ae650dSJack F Vogel enum i40e_status_code i40e_update_nvm_checksum(struct i40e_hw *hw) 429*61ae650dSJack F Vogel { 430*61ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 431*61ae650dSJack F Vogel u16 checksum; 432*61ae650dSJack F Vogel 433*61ae650dSJack F Vogel DEBUGFUNC("i40e_update_nvm_checksum"); 434*61ae650dSJack F Vogel 435*61ae650dSJack F Vogel ret_code = i40e_calc_nvm_checksum(hw, &checksum); 436*61ae650dSJack F Vogel if (ret_code == I40E_SUCCESS) 437*61ae650dSJack F Vogel ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD, 438*61ae650dSJack F Vogel 1, &checksum, TRUE); 439*61ae650dSJack F Vogel 440*61ae650dSJack F Vogel return ret_code; 441*61ae650dSJack F Vogel } 442*61ae650dSJack F Vogel 443*61ae650dSJack F Vogel /** 444*61ae650dSJack F Vogel * i40e_validate_nvm_checksum - Validate EEPROM checksum 445*61ae650dSJack F Vogel * @hw: pointer to hardware structure 446*61ae650dSJack F Vogel * @checksum: calculated checksum 447*61ae650dSJack F Vogel * 448*61ae650dSJack F Vogel * Performs checksum calculation and validates the NVM SW checksum. If the 449*61ae650dSJack F Vogel * caller does not need checksum, the value can be NULL. 450*61ae650dSJack F Vogel **/ 451*61ae650dSJack F Vogel enum i40e_status_code i40e_validate_nvm_checksum(struct i40e_hw *hw, 452*61ae650dSJack F Vogel u16 *checksum) 453*61ae650dSJack F Vogel { 454*61ae650dSJack F Vogel enum i40e_status_code ret_code = I40E_SUCCESS; 455*61ae650dSJack F Vogel u16 checksum_sr = 0; 456*61ae650dSJack F Vogel u16 checksum_local = 0; 457*61ae650dSJack F Vogel 458*61ae650dSJack F Vogel DEBUGFUNC("i40e_validate_nvm_checksum"); 459*61ae650dSJack F Vogel 460*61ae650dSJack F Vogel ret_code = i40e_calc_nvm_checksum(hw, &checksum_local); 461*61ae650dSJack F Vogel if (ret_code != I40E_SUCCESS) 462*61ae650dSJack F Vogel goto i40e_validate_nvm_checksum_exit; 463*61ae650dSJack F Vogel 464*61ae650dSJack F Vogel /* Do not use i40e_read_nvm_word() because we do not want to take 465*61ae650dSJack F Vogel * the synchronization semaphores twice here. 466*61ae650dSJack F Vogel */ 467*61ae650dSJack F Vogel i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr); 468*61ae650dSJack F Vogel 469*61ae650dSJack F Vogel /* Verify read checksum from EEPROM is the same as 470*61ae650dSJack F Vogel * calculated checksum 471*61ae650dSJack F Vogel */ 472*61ae650dSJack F Vogel if (checksum_local != checksum_sr) 473*61ae650dSJack F Vogel ret_code = I40E_ERR_NVM_CHECKSUM; 474*61ae650dSJack F Vogel 475*61ae650dSJack F Vogel /* If the user cares, return the calculated checksum */ 476*61ae650dSJack F Vogel if (checksum) 477*61ae650dSJack F Vogel *checksum = checksum_local; 478*61ae650dSJack F Vogel 479*61ae650dSJack F Vogel i40e_validate_nvm_checksum_exit: 480*61ae650dSJack F Vogel return ret_code; 481*61ae650dSJack F Vogel } 482