linux/drivers/net/ethernet/intel/i40e/i40e_nvm.c
<<
>>
Prefs
   1/*******************************************************************************
   2 *
   3 * Intel Ethernet Controller XL710 Family Linux Driver
   4 * Copyright(c) 2013 - 2014 Intel Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2, as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 * more details.
  14 *
  15 * You should have received a copy of the GNU General Public License along
  16 * with this program.  If not, see <http://www.gnu.org/licenses/>.
  17 *
  18 * The full GNU General Public License is included in this distribution in
  19 * the file called "COPYING".
  20 *
  21 * Contact Information:
  22 * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
  23 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  24 *
  25 ******************************************************************************/
  26
  27#include "i40e_prototype.h"
  28
  29/**
  30 * i40e_init_nvm_ops - Initialize NVM function pointers
  31 * @hw: pointer to the HW structure
  32 *
  33 * Setup the function pointers and the NVM info structure. Should be called
  34 * once per NVM initialization, e.g. inside the i40e_init_shared_code().
  35 * Please notice that the NVM term is used here (& in all methods covered
  36 * in this file) as an equivalent of the FLASH part mapped into the SR.
  37 * We are accessing FLASH always thru the Shadow RAM.
  38 **/
  39i40e_status i40e_init_nvm(struct i40e_hw *hw)
  40{
  41        struct i40e_nvm_info *nvm = &hw->nvm;
  42        i40e_status ret_code = 0;
  43        u32 fla, gens;
  44        u8 sr_size;
  45
  46        /* The SR size is stored regardless of the nvm programming mode
  47         * as the blank mode may be used in the factory line.
  48         */
  49        gens = rd32(hw, I40E_GLNVM_GENS);
  50        sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >>
  51                           I40E_GLNVM_GENS_SR_SIZE_SHIFT);
  52        /* Switching to words (sr_size contains power of 2KB) */
  53        nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB;
  54
  55        /* Check if we are in the normal or blank NVM programming mode */
  56        fla = rd32(hw, I40E_GLNVM_FLA);
  57        if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */
  58                /* Max NVM timeout */
  59                nvm->timeout = I40E_MAX_NVM_TIMEOUT;
  60                nvm->blank_nvm_mode = false;
  61        } else { /* Blank programming mode */
  62                nvm->blank_nvm_mode = true;
  63                ret_code = I40E_ERR_NVM_BLANK_MODE;
  64                hw_dbg(hw, "NVM init error: unsupported blank mode.\n");
  65        }
  66
  67        return ret_code;
  68}
  69
  70/**
  71 * i40e_acquire_nvm - Generic request for acquiring the NVM ownership
  72 * @hw: pointer to the HW structure
  73 * @access: NVM access type (read or write)
  74 *
  75 * This function will request NVM ownership for reading
  76 * via the proper Admin Command.
  77 **/
  78i40e_status i40e_acquire_nvm(struct i40e_hw *hw,
  79                                       enum i40e_aq_resource_access_type access)
  80{
  81        i40e_status ret_code = 0;
  82        u64 gtime, timeout;
  83        u64 time = 0;
  84
  85        if (hw->nvm.blank_nvm_mode)
  86                goto i40e_i40e_acquire_nvm_exit;
  87
  88        ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access,
  89                                            0, &time, NULL);
  90        /* Reading the Global Device Timer */
  91        gtime = rd32(hw, I40E_GLVFGEN_TIMER);
  92
  93        /* Store the timeout */
  94        hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time) + gtime;
  95
  96        if (ret_code) {
  97                /* Set the polling timeout */
  98                if (time > I40E_MAX_NVM_TIMEOUT)
  99                        timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT)
 100                                  + gtime;
 101                else
 102                        timeout = hw->nvm.hw_semaphore_timeout;
 103                /* Poll until the current NVM owner timeouts */
 104                while (gtime < timeout) {
 105                        usleep_range(10000, 20000);
 106                        ret_code = i40e_aq_request_resource(hw,
 107                                                        I40E_NVM_RESOURCE_ID,
 108                                                        access, 0, &time,
 109                                                        NULL);
 110                        if (!ret_code) {
 111                                hw->nvm.hw_semaphore_timeout =
 112                                                I40E_MS_TO_GTIME(time) + gtime;
 113                                break;
 114                        }
 115                        gtime = rd32(hw, I40E_GLVFGEN_TIMER);
 116                }
 117                if (ret_code) {
 118                        hw->nvm.hw_semaphore_timeout = 0;
 119                        hw->nvm.hw_semaphore_wait =
 120                                                I40E_MS_TO_GTIME(time) + gtime;
 121                        hw_dbg(hw, "NVM acquire timed out, wait %llu ms before trying again.\n",
 122                                  time);
 123                }
 124        }
 125
 126i40e_i40e_acquire_nvm_exit:
 127        return ret_code;
 128}
 129
 130/**
 131 * i40e_release_nvm - Generic request for releasing the NVM ownership
 132 * @hw: pointer to the HW structure
 133 *
 134 * This function will release NVM resource via the proper Admin Command.
 135 **/
 136void i40e_release_nvm(struct i40e_hw *hw)
 137{
 138        if (!hw->nvm.blank_nvm_mode)
 139                i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL);
 140}
 141
 142/**
 143 * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit
 144 * @hw: pointer to the HW structure
 145 *
 146 * Polls the SRCTL Shadow RAM register done bit.
 147 **/
 148static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
 149{
 150        i40e_status ret_code = I40E_ERR_TIMEOUT;
 151        u32 srctl, wait_cnt;
 152
 153        /* Poll the I40E_GLNVM_SRCTL until the done bit is set */
 154        for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) {
 155                srctl = rd32(hw, I40E_GLNVM_SRCTL);
 156                if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) {
 157                        ret_code = 0;
 158                        break;
 159                }
 160                udelay(5);
 161        }
 162        if (ret_code == I40E_ERR_TIMEOUT)
 163                hw_dbg(hw, "Done bit in GLNVM_SRCTL not set\n");
 164        return ret_code;
 165}
 166
 167/**
 168 * i40e_read_nvm_word - Reads Shadow RAM
 169 * @hw: pointer to the HW structure
 170 * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
 171 * @data: word read from the Shadow RAM
 172 *
 173 * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
 174 **/
 175i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
 176                                         u16 *data)
 177{
 178        i40e_status ret_code = I40E_ERR_TIMEOUT;
 179        u32 sr_reg;
 180
 181        if (offset >= hw->nvm.sr_size) {
 182                hw_dbg(hw, "NVM read error: Offset beyond Shadow RAM limit.\n");
 183                ret_code = I40E_ERR_PARAM;
 184                goto read_nvm_exit;
 185        }
 186
 187        /* Poll the done bit first */
 188        ret_code = i40e_poll_sr_srctl_done_bit(hw);
 189        if (!ret_code) {
 190                /* Write the address and start reading */
 191                sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) |
 192                         (1 << I40E_GLNVM_SRCTL_START_SHIFT);
 193                wr32(hw, I40E_GLNVM_SRCTL, sr_reg);
 194
 195                /* Poll I40E_GLNVM_SRCTL until the done bit is set */
 196                ret_code = i40e_poll_sr_srctl_done_bit(hw);
 197                if (!ret_code) {
 198                        sr_reg = rd32(hw, I40E_GLNVM_SRDATA);
 199                        *data = (u16)((sr_reg &
 200                                       I40E_GLNVM_SRDATA_RDDATA_MASK)
 201                                    >> I40E_GLNVM_SRDATA_RDDATA_SHIFT);
 202                }
 203        }
 204        if (ret_code)
 205                hw_dbg(hw, "NVM read error: Couldn't access Shadow RAM address: 0x%x\n",
 206                          offset);
 207
 208read_nvm_exit:
 209        return ret_code;
 210}
 211
 212/**
 213 * i40e_read_nvm_buffer - Reads Shadow RAM buffer
 214 * @hw: pointer to the HW structure
 215 * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
 216 * @words: (in) number of words to read; (out) number of words actually read
 217 * @data: words read from the Shadow RAM
 218 *
 219 * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
 220 * method. The buffer read is preceded by the NVM ownership take
 221 * and followed by the release.
 222 **/
 223i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
 224                                           u16 *words, u16 *data)
 225{
 226        i40e_status ret_code = 0;
 227        u16 index, word;
 228
 229        /* Loop thru the selected region */
 230        for (word = 0; word < *words; word++) {
 231                index = offset + word;
 232                ret_code = i40e_read_nvm_word(hw, index, &data[word]);
 233                if (ret_code)
 234                        break;
 235        }
 236
 237        /* Update the number of words read from the Shadow RAM */
 238        *words = word;
 239
 240        return ret_code;
 241}
 242
 243/**
 244 * i40e_write_nvm_aq - Writes Shadow RAM.
 245 * @hw: pointer to the HW structure.
 246 * @module_pointer: module pointer location in words from the NVM beginning
 247 * @offset: offset in words from module start
 248 * @words: number of words to write
 249 * @data: buffer with words to write to the Shadow RAM
 250 * @last_command: tells the AdminQ that this is the last command
 251 *
 252 * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
 253 **/
 254static i40e_status i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
 255                                     u32 offset, u16 words, void *data,
 256                                     bool last_command)
 257{
 258        i40e_status ret_code = I40E_ERR_NVM;
 259
 260        /* Here we are checking the SR limit only for the flat memory model.
 261         * We cannot do it for the module-based model, as we did not acquire
 262         * the NVM resource yet (we cannot get the module pointer value).
 263         * Firmware will check the module-based model.
 264         */
 265        if ((offset + words) > hw->nvm.sr_size)
 266                hw_dbg(hw, "NVM write error: offset beyond Shadow RAM limit.\n");
 267        else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
 268                /* We can write only up to 4KB (one sector), in one AQ write */
 269                hw_dbg(hw, "NVM write fail error: cannot write more than 4KB in a single write.\n");
 270        else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
 271                 != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
 272                /* A single write cannot spread over two sectors */
 273                hw_dbg(hw, "NVM write error: cannot spread over two sectors in a single write.\n");
 274        else
 275                ret_code = i40e_aq_update_nvm(hw, module_pointer,
 276                                              2 * offset,  /*bytes*/
 277                                              2 * words,   /*bytes*/
 278                                              data, last_command, NULL);
 279
 280        return ret_code;
 281}
 282
 283/**
 284 * i40e_calc_nvm_checksum - Calculates and returns the checksum
 285 * @hw: pointer to hardware structure
 286 * @checksum: pointer to the checksum
 287 *
 288 * This function calculates SW Checksum that covers the whole 64kB shadow RAM
 289 * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
 290 * is customer specific and unknown. Therefore, this function skips all maximum
 291 * possible size of VPD (1kB).
 292 **/
 293static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw,
 294                                                    u16 *checksum)
 295{
 296        i40e_status ret_code = 0;
 297        u16 pcie_alt_module = 0;
 298        u16 checksum_local = 0;
 299        u16 vpd_module = 0;
 300        u16 word = 0;
 301        u32 i = 0;
 302
 303        /* read pointer to VPD area */
 304        ret_code = i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);
 305        if (ret_code) {
 306                ret_code = I40E_ERR_NVM_CHECKSUM;
 307                goto i40e_calc_nvm_checksum_exit;
 308        }
 309
 310        /* read pointer to PCIe Alt Auto-load module */
 311        ret_code = i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
 312                                       &pcie_alt_module);
 313        if (ret_code) {
 314                ret_code = I40E_ERR_NVM_CHECKSUM;
 315                goto i40e_calc_nvm_checksum_exit;
 316        }
 317
 318        /* Calculate SW checksum that covers the whole 64kB shadow RAM
 319         * except the VPD and PCIe ALT Auto-load modules
 320         */
 321        for (i = 0; i < hw->nvm.sr_size; i++) {
 322                /* Skip Checksum word */
 323                if (i == I40E_SR_SW_CHECKSUM_WORD)
 324                        i++;
 325                /* Skip VPD module (convert byte size to word count) */
 326                if (i == (u32)vpd_module) {
 327                        i += (I40E_SR_VPD_MODULE_MAX_SIZE / 2);
 328                        if (i >= hw->nvm.sr_size)
 329                                break;
 330                }
 331                /* Skip PCIe ALT module (convert byte size to word count) */
 332                if (i == (u32)pcie_alt_module) {
 333                        i += (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2);
 334                        if (i >= hw->nvm.sr_size)
 335                                break;
 336                }
 337
 338                ret_code = i40e_read_nvm_word(hw, (u16)i, &word);
 339                if (ret_code) {
 340                        ret_code = I40E_ERR_NVM_CHECKSUM;
 341                        goto i40e_calc_nvm_checksum_exit;
 342                }
 343                checksum_local += word;
 344        }
 345
 346        *checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local;
 347
 348i40e_calc_nvm_checksum_exit:
 349        return ret_code;
 350}
 351
 352/**
 353 * i40e_update_nvm_checksum - Updates the NVM checksum
 354 * @hw: pointer to hardware structure
 355 *
 356 * NVM ownership must be acquired before calling this function and released
 357 * on ARQ completion event reception by caller.
 358 * This function will commit SR to NVM.
 359 **/
 360i40e_status i40e_update_nvm_checksum(struct i40e_hw *hw)
 361{
 362        i40e_status ret_code = 0;
 363        u16 checksum;
 364
 365        ret_code = i40e_calc_nvm_checksum(hw, &checksum);
 366        if (!ret_code)
 367                ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD,
 368                                             1, &checksum, true);
 369
 370        return ret_code;
 371}
 372
 373/**
 374 * i40e_validate_nvm_checksum - Validate EEPROM checksum
 375 * @hw: pointer to hardware structure
 376 * @checksum: calculated checksum
 377 *
 378 * Performs checksum calculation and validates the NVM SW checksum. If the
 379 * caller does not need checksum, the value can be NULL.
 380 **/
 381i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,
 382                                                 u16 *checksum)
 383{
 384        i40e_status ret_code = 0;
 385        u16 checksum_sr = 0;
 386        u16 checksum_local = 0;
 387
 388        ret_code = i40e_calc_nvm_checksum(hw, &checksum_local);
 389        if (ret_code)
 390                goto i40e_validate_nvm_checksum_exit;
 391
 392        /* Do not use i40e_read_nvm_word() because we do not want to take
 393         * the synchronization semaphores twice here.
 394         */
 395        i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);
 396
 397        /* Verify read checksum from EEPROM is the same as
 398         * calculated checksum
 399         */
 400        if (checksum_local != checksum_sr)
 401                ret_code = I40E_ERR_NVM_CHECKSUM;
 402
 403        /* If the user cares, return the calculated checksum */
 404        if (checksum)
 405                *checksum = checksum_local;
 406
 407i40e_validate_nvm_checksum_exit:
 408        return ret_code;
 409}
 410
 411static i40e_status i40e_nvmupd_state_init(struct i40e_hw *hw,
 412                                          struct i40e_nvm_access *cmd,
 413                                          u8 *bytes, int *errno);
 414static i40e_status i40e_nvmupd_state_reading(struct i40e_hw *hw,
 415                                             struct i40e_nvm_access *cmd,
 416                                             u8 *bytes, int *errno);
 417static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw,
 418                                             struct i40e_nvm_access *cmd,
 419                                             u8 *bytes, int *errno);
 420static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
 421                                                struct i40e_nvm_access *cmd,
 422                                                int *errno);
 423static i40e_status i40e_nvmupd_nvm_erase(struct i40e_hw *hw,
 424                                         struct i40e_nvm_access *cmd,
 425                                         int *errno);
 426static i40e_status i40e_nvmupd_nvm_write(struct i40e_hw *hw,
 427                                         struct i40e_nvm_access *cmd,
 428                                         u8 *bytes, int *errno);
 429static i40e_status i40e_nvmupd_nvm_read(struct i40e_hw *hw,
 430                                        struct i40e_nvm_access *cmd,
 431                                        u8 *bytes, int *errno);
 432static inline u8 i40e_nvmupd_get_module(u32 val)
 433{
 434        return (u8)(val & I40E_NVM_MOD_PNT_MASK);
 435}
 436static inline u8 i40e_nvmupd_get_transaction(u32 val)
 437{
 438        return (u8)((val & I40E_NVM_TRANS_MASK) >> I40E_NVM_TRANS_SHIFT);
 439}
 440
 441/**
 442 * i40e_nvmupd_command - Process an NVM update command
 443 * @hw: pointer to hardware structure
 444 * @cmd: pointer to nvm update command
 445 * @bytes: pointer to the data buffer
 446 * @errno: pointer to return error code
 447 *
 448 * Dispatches command depending on what update state is current
 449 **/
 450i40e_status i40e_nvmupd_command(struct i40e_hw *hw,
 451                                struct i40e_nvm_access *cmd,
 452                                u8 *bytes, int *errno)
 453{
 454        i40e_status status;
 455
 456        /* assume success */
 457        *errno = 0;
 458
 459        switch (hw->nvmupd_state) {
 460        case I40E_NVMUPD_STATE_INIT:
 461                status = i40e_nvmupd_state_init(hw, cmd, bytes, errno);
 462                break;
 463
 464        case I40E_NVMUPD_STATE_READING:
 465                status = i40e_nvmupd_state_reading(hw, cmd, bytes, errno);
 466                break;
 467
 468        case I40E_NVMUPD_STATE_WRITING:
 469                status = i40e_nvmupd_state_writing(hw, cmd, bytes, errno);
 470                break;
 471
 472        default:
 473                /* invalid state, should never happen */
 474                status = I40E_NOT_SUPPORTED;
 475                *errno = -ESRCH;
 476                break;
 477        }
 478        return status;
 479}
 480
 481/**
 482 * i40e_nvmupd_state_init - Handle NVM update state Init
 483 * @hw: pointer to hardware structure
 484 * @cmd: pointer to nvm update command buffer
 485 * @bytes: pointer to the data buffer
 486 * @errno: pointer to return error code
 487 *
 488 * Process legitimate commands of the Init state and conditionally set next
 489 * state. Reject all other commands.
 490 **/
 491static i40e_status i40e_nvmupd_state_init(struct i40e_hw *hw,
 492                                          struct i40e_nvm_access *cmd,
 493                                          u8 *bytes, int *errno)
 494{
 495        i40e_status status = 0;
 496        enum i40e_nvmupd_cmd upd_cmd;
 497
 498        upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno);
 499
 500        switch (upd_cmd) {
 501        case I40E_NVMUPD_READ_SA:
 502                status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
 503                if (status) {
 504                        *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
 505                } else {
 506                        status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno);
 507                        i40e_release_nvm(hw);
 508                }
 509                break;
 510
 511        case I40E_NVMUPD_READ_SNT:
 512                status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
 513                if (status) {
 514                        *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
 515                } else {
 516                        status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno);
 517                        hw->nvmupd_state = I40E_NVMUPD_STATE_READING;
 518                }
 519                break;
 520
 521        case I40E_NVMUPD_WRITE_ERA:
 522                status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
 523                if (status) {
 524                        *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
 525                } else {
 526                        status = i40e_nvmupd_nvm_erase(hw, cmd, errno);
 527                        if (status)
 528                                i40e_release_nvm(hw);
 529                        else
 530                                hw->aq.nvm_release_on_done = true;
 531                }
 532                break;
 533
 534        case I40E_NVMUPD_WRITE_SA:
 535                status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
 536                if (status) {
 537                        *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
 538                } else {
 539                        status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
 540                        if (status)
 541                                i40e_release_nvm(hw);
 542                        else
 543                                hw->aq.nvm_release_on_done = true;
 544                }
 545                break;
 546
 547        case I40E_NVMUPD_WRITE_SNT:
 548                status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
 549                if (status) {
 550                        *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
 551                } else {
 552                        status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
 553                        hw->nvmupd_state = I40E_NVMUPD_STATE_WRITING;
 554                }
 555                break;
 556
 557        case I40E_NVMUPD_CSUM_SA:
 558                status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
 559                if (status) {
 560                        *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
 561                } else {
 562                        status = i40e_update_nvm_checksum(hw);
 563                        if (status) {
 564                                *errno = hw->aq.asq_last_status ?
 565                                   i40e_aq_rc_to_posix(hw->aq.asq_last_status) :
 566                                   -EIO;
 567                                i40e_release_nvm(hw);
 568                        } else {
 569                                hw->aq.nvm_release_on_done = true;
 570                        }
 571                }
 572                break;
 573
 574        default:
 575                status = I40E_ERR_NVM;
 576                *errno = -ESRCH;
 577                break;
 578        }
 579        return status;
 580}
 581
 582/**
 583 * i40e_nvmupd_state_reading - Handle NVM update state Reading
 584 * @hw: pointer to hardware structure
 585 * @cmd: pointer to nvm update command buffer
 586 * @bytes: pointer to the data buffer
 587 * @errno: pointer to return error code
 588 *
 589 * NVM ownership is already held.  Process legitimate commands and set any
 590 * change in state; reject all other commands.
 591 **/
 592static i40e_status i40e_nvmupd_state_reading(struct i40e_hw *hw,
 593                                             struct i40e_nvm_access *cmd,
 594                                             u8 *bytes, int *errno)
 595{
 596        i40e_status status;
 597        enum i40e_nvmupd_cmd upd_cmd;
 598
 599        upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno);
 600
 601        switch (upd_cmd) {
 602        case I40E_NVMUPD_READ_SA:
 603        case I40E_NVMUPD_READ_CON:
 604                status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno);
 605                break;
 606
 607        case I40E_NVMUPD_READ_LCB:
 608                status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno);
 609                i40e_release_nvm(hw);
 610                hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
 611                break;
 612
 613        default:
 614                status = I40E_NOT_SUPPORTED;
 615                *errno = -ESRCH;
 616                break;
 617        }
 618        return status;
 619}
 620
 621/**
 622 * i40e_nvmupd_state_writing - Handle NVM update state Writing
 623 * @hw: pointer to hardware structure
 624 * @cmd: pointer to nvm update command buffer
 625 * @bytes: pointer to the data buffer
 626 * @errno: pointer to return error code
 627 *
 628 * NVM ownership is already held.  Process legitimate commands and set any
 629 * change in state; reject all other commands
 630 **/
 631static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw,
 632                                             struct i40e_nvm_access *cmd,
 633                                             u8 *bytes, int *errno)
 634{
 635        i40e_status status;
 636        enum i40e_nvmupd_cmd upd_cmd;
 637
 638        upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno);
 639
 640        switch (upd_cmd) {
 641        case I40E_NVMUPD_WRITE_CON:
 642                status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
 643                break;
 644
 645        case I40E_NVMUPD_WRITE_LCB:
 646                status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
 647                if (!status) {
 648                        hw->aq.nvm_release_on_done = true;
 649                        hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
 650                }
 651                break;
 652
 653        case I40E_NVMUPD_CSUM_CON:
 654                status = i40e_update_nvm_checksum(hw);
 655                if (status)
 656                        *errno = hw->aq.asq_last_status ?
 657                                   i40e_aq_rc_to_posix(hw->aq.asq_last_status) :
 658                                   -EIO;
 659                break;
 660
 661        case I40E_NVMUPD_CSUM_LCB:
 662                status = i40e_update_nvm_checksum(hw);
 663                if (status) {
 664                        *errno = hw->aq.asq_last_status ?
 665                                   i40e_aq_rc_to_posix(hw->aq.asq_last_status) :
 666                                   -EIO;
 667                } else {
 668                        hw->aq.nvm_release_on_done = true;
 669                        hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
 670                }
 671                break;
 672
 673        default:
 674                status = I40E_NOT_SUPPORTED;
 675                *errno = -ESRCH;
 676                break;
 677        }
 678        return status;
 679}
 680
 681/**
 682 * i40e_nvmupd_validate_command - Validate given command
 683 * @hw: pointer to hardware structure
 684 * @cmd: pointer to nvm update command buffer
 685 * @errno: pointer to return error code
 686 *
 687 * Return one of the valid command types or I40E_NVMUPD_INVALID
 688 **/
 689static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
 690                                                 struct i40e_nvm_access *cmd,
 691                                                 int *errno)
 692{
 693        enum i40e_nvmupd_cmd upd_cmd;
 694        u8 transaction, module;
 695
 696        /* anything that doesn't match a recognized case is an error */
 697        upd_cmd = I40E_NVMUPD_INVALID;
 698
 699        transaction = i40e_nvmupd_get_transaction(cmd->config);
 700        module = i40e_nvmupd_get_module(cmd->config);
 701
 702        /* limits on data size */
 703        if ((cmd->data_size < 1) ||
 704            (cmd->data_size > I40E_NVMUPD_MAX_DATA)) {
 705                hw_dbg(hw, "i40e_nvmupd_validate_command data_size %d\n",
 706                       cmd->data_size);
 707                *errno = -EFAULT;
 708                return I40E_NVMUPD_INVALID;
 709        }
 710
 711        switch (cmd->command) {
 712        case I40E_NVM_READ:
 713                switch (transaction) {
 714                case I40E_NVM_CON:
 715                        upd_cmd = I40E_NVMUPD_READ_CON;
 716                        break;
 717                case I40E_NVM_SNT:
 718                        upd_cmd = I40E_NVMUPD_READ_SNT;
 719                        break;
 720                case I40E_NVM_LCB:
 721                        upd_cmd = I40E_NVMUPD_READ_LCB;
 722                        break;
 723                case I40E_NVM_SA:
 724                        upd_cmd = I40E_NVMUPD_READ_SA;
 725                        break;
 726                }
 727                break;
 728
 729        case I40E_NVM_WRITE:
 730                switch (transaction) {
 731                case I40E_NVM_CON:
 732                        upd_cmd = I40E_NVMUPD_WRITE_CON;
 733                        break;
 734                case I40E_NVM_SNT:
 735                        upd_cmd = I40E_NVMUPD_WRITE_SNT;
 736                        break;
 737                case I40E_NVM_LCB:
 738                        upd_cmd = I40E_NVMUPD_WRITE_LCB;
 739                        break;
 740                case I40E_NVM_SA:
 741                        upd_cmd = I40E_NVMUPD_WRITE_SA;
 742                        break;
 743                case I40E_NVM_ERA:
 744                        upd_cmd = I40E_NVMUPD_WRITE_ERA;
 745                        break;
 746                case I40E_NVM_CSUM:
 747                        upd_cmd = I40E_NVMUPD_CSUM_CON;
 748                        break;
 749                case (I40E_NVM_CSUM|I40E_NVM_SA):
 750                        upd_cmd = I40E_NVMUPD_CSUM_SA;
 751                        break;
 752                case (I40E_NVM_CSUM|I40E_NVM_LCB):
 753                        upd_cmd = I40E_NVMUPD_CSUM_LCB;
 754                        break;
 755                }
 756                break;
 757        }
 758
 759        if (upd_cmd == I40E_NVMUPD_INVALID) {
 760                *errno = -EFAULT;
 761                hw_dbg(hw,
 762                       "i40e_nvmupd_validate_command returns %d  errno: %d\n",
 763                       upd_cmd, *errno);
 764        }
 765        return upd_cmd;
 766}
 767
 768/**
 769 * i40e_nvmupd_nvm_read - Read NVM
 770 * @hw: pointer to hardware structure
 771 * @cmd: pointer to nvm update command buffer
 772 * @bytes: pointer to the data buffer
 773 * @errno: pointer to return error code
 774 *
 775 * cmd structure contains identifiers and data buffer
 776 **/
 777static i40e_status i40e_nvmupd_nvm_read(struct i40e_hw *hw,
 778                                        struct i40e_nvm_access *cmd,
 779                                        u8 *bytes, int *errno)
 780{
 781        i40e_status status;
 782        u8 module, transaction;
 783        bool last;
 784
 785        transaction = i40e_nvmupd_get_transaction(cmd->config);
 786        module = i40e_nvmupd_get_module(cmd->config);
 787        last = (transaction == I40E_NVM_LCB) || (transaction == I40E_NVM_SA);
 788        hw_dbg(hw, "i40e_nvmupd_nvm_read mod 0x%x  off 0x%x  len 0x%x\n",
 789               module, cmd->offset, cmd->data_size);
 790
 791        status = i40e_aq_read_nvm(hw, module, cmd->offset, (u16)cmd->data_size,
 792                                  bytes, last, NULL);
 793        hw_dbg(hw, "i40e_nvmupd_nvm_read status %d\n", status);
 794        if (status)
 795                *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
 796
 797        return status;
 798}
 799
 800/**
 801 * i40e_nvmupd_nvm_erase - Erase an NVM module
 802 * @hw: pointer to hardware structure
 803 * @cmd: pointer to nvm update command buffer
 804 * @errno: pointer to return error code
 805 *
 806 * module, offset, data_size and data are in cmd structure
 807 **/
 808static i40e_status i40e_nvmupd_nvm_erase(struct i40e_hw *hw,
 809                                         struct i40e_nvm_access *cmd,
 810                                         int *errno)
 811{
 812        i40e_status status = 0;
 813        u8 module, transaction;
 814        bool last;
 815
 816        transaction = i40e_nvmupd_get_transaction(cmd->config);
 817        module = i40e_nvmupd_get_module(cmd->config);
 818        last = (transaction & I40E_NVM_LCB);
 819        hw_dbg(hw, "i40e_nvmupd_nvm_erase mod 0x%x  off 0x%x  len 0x%x\n",
 820               module, cmd->offset, cmd->data_size);
 821        status = i40e_aq_erase_nvm(hw, module, cmd->offset, (u16)cmd->data_size,
 822                                   last, NULL);
 823        hw_dbg(hw, "i40e_nvmupd_nvm_erase status %d\n", status);
 824        if (status)
 825                *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
 826
 827        return status;
 828}
 829
 830/**
 831 * i40e_nvmupd_nvm_write - Write NVM
 832 * @hw: pointer to hardware structure
 833 * @cmd: pointer to nvm update command buffer
 834 * @bytes: pointer to the data buffer
 835 * @errno: pointer to return error code
 836 *
 837 * module, offset, data_size and data are in cmd structure
 838 **/
 839static i40e_status i40e_nvmupd_nvm_write(struct i40e_hw *hw,
 840                                         struct i40e_nvm_access *cmd,
 841                                         u8 *bytes, int *errno)
 842{
 843        i40e_status status = 0;
 844        u8 module, transaction;
 845        bool last;
 846
 847        transaction = i40e_nvmupd_get_transaction(cmd->config);
 848        module = i40e_nvmupd_get_module(cmd->config);
 849        last = (transaction & I40E_NVM_LCB);
 850        hw_dbg(hw, "i40e_nvmupd_nvm_write mod 0x%x off 0x%x len 0x%x\n",
 851               module, cmd->offset, cmd->data_size);
 852        status = i40e_aq_update_nvm(hw, module, cmd->offset,
 853                                    (u16)cmd->data_size, bytes, last, NULL);
 854        hw_dbg(hw, "i40e_nvmupd_nvm_write status %d\n", status);
 855        if (status)
 856                *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status);
 857
 858        return status;
 859}
 860