linux/drivers/net/ethernet/intel/igc/igc_nvm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (c)  2018 Intel Corporation */
   3
   4#include "igc_mac.h"
   5#include "igc_nvm.h"
   6
   7/**
   8 * igc_poll_eerd_eewr_done - Poll for EEPROM read/write completion
   9 * @hw: pointer to the HW structure
  10 * @ee_reg: EEPROM flag for polling
  11 *
  12 * Polls the EEPROM status bit for either read or write completion based
  13 * upon the value of 'ee_reg'.
  14 */
  15static s32 igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg)
  16{
  17        s32 ret_val = -IGC_ERR_NVM;
  18        u32 attempts = 100000;
  19        u32 i, reg = 0;
  20
  21        for (i = 0; i < attempts; i++) {
  22                if (ee_reg == IGC_NVM_POLL_READ)
  23                        reg = rd32(IGC_EERD);
  24                else
  25                        reg = rd32(IGC_EEWR);
  26
  27                if (reg & IGC_NVM_RW_REG_DONE) {
  28                        ret_val = 0;
  29                        break;
  30                }
  31
  32                udelay(5);
  33        }
  34
  35        return ret_val;
  36}
  37
  38/**
  39 * igc_acquire_nvm - Generic request for access to EEPROM
  40 * @hw: pointer to the HW structure
  41 *
  42 * Set the EEPROM access request bit and wait for EEPROM access grant bit.
  43 * Return successful if access grant bit set, else clear the request for
  44 * EEPROM access and return -IGC_ERR_NVM (-1).
  45 */
  46s32 igc_acquire_nvm(struct igc_hw *hw)
  47{
  48        s32 timeout = IGC_NVM_GRANT_ATTEMPTS;
  49        u32 eecd = rd32(IGC_EECD);
  50        s32 ret_val = 0;
  51
  52        wr32(IGC_EECD, eecd | IGC_EECD_REQ);
  53        eecd = rd32(IGC_EECD);
  54
  55        while (timeout) {
  56                if (eecd & IGC_EECD_GNT)
  57                        break;
  58                udelay(5);
  59                eecd = rd32(IGC_EECD);
  60                timeout--;
  61        }
  62
  63        if (!timeout) {
  64                eecd &= ~IGC_EECD_REQ;
  65                wr32(IGC_EECD, eecd);
  66                hw_dbg("Could not acquire NVM grant\n");
  67                ret_val = -IGC_ERR_NVM;
  68        }
  69
  70        return ret_val;
  71}
  72
  73/**
  74 * igc_release_nvm - Release exclusive access to EEPROM
  75 * @hw: pointer to the HW structure
  76 *
  77 * Stop any current commands to the EEPROM and clear the EEPROM request bit.
  78 */
  79void igc_release_nvm(struct igc_hw *hw)
  80{
  81        u32 eecd;
  82
  83        eecd = rd32(IGC_EECD);
  84        eecd &= ~IGC_EECD_REQ;
  85        wr32(IGC_EECD, eecd);
  86}
  87
  88/**
  89 * igc_read_nvm_eerd - Reads EEPROM using EERD register
  90 * @hw: pointer to the HW structure
  91 * @offset: offset of word in the EEPROM to read
  92 * @words: number of words to read
  93 * @data: word read from the EEPROM
  94 *
  95 * Reads a 16 bit word from the EEPROM using the EERD register.
  96 */
  97s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data)
  98{
  99        struct igc_nvm_info *nvm = &hw->nvm;
 100        u32 i, eerd = 0;
 101        s32 ret_val = 0;
 102
 103        /* A check for invalid values:  offset too large, too many words,
 104         * and not enough words.
 105         */
 106        if (offset >= nvm->word_size || (words > (nvm->word_size - offset)) ||
 107            words == 0) {
 108                hw_dbg("nvm parameter(s) out of bounds\n");
 109                ret_val = -IGC_ERR_NVM;
 110                goto out;
 111        }
 112
 113        for (i = 0; i < words; i++) {
 114                eerd = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) +
 115                        IGC_NVM_RW_REG_START;
 116
 117                wr32(IGC_EERD, eerd);
 118                ret_val = igc_poll_eerd_eewr_done(hw, IGC_NVM_POLL_READ);
 119                if (ret_val)
 120                        break;
 121
 122                data[i] = (rd32(IGC_EERD) >> IGC_NVM_RW_REG_DATA);
 123        }
 124
 125out:
 126        return ret_val;
 127}
 128
 129/**
 130 * igc_read_mac_addr - Read device MAC address
 131 * @hw: pointer to the HW structure
 132 */
 133s32 igc_read_mac_addr(struct igc_hw *hw)
 134{
 135        u32 rar_high;
 136        u32 rar_low;
 137        u16 i;
 138
 139        rar_high = rd32(IGC_RAH(0));
 140        rar_low = rd32(IGC_RAL(0));
 141
 142        for (i = 0; i < IGC_RAL_MAC_ADDR_LEN; i++)
 143                hw->mac.perm_addr[i] = (u8)(rar_low >> (i * 8));
 144
 145        for (i = 0; i < IGC_RAH_MAC_ADDR_LEN; i++)
 146                hw->mac.perm_addr[i + 4] = (u8)(rar_high >> (i * 8));
 147
 148        for (i = 0; i < ETH_ALEN; i++)
 149                hw->mac.addr[i] = hw->mac.perm_addr[i];
 150
 151        return 0;
 152}
 153
 154/**
 155 * igc_validate_nvm_checksum - Validate EEPROM checksum
 156 * @hw: pointer to the HW structure
 157 *
 158 * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
 159 * and then verifies that the sum of the EEPROM is equal to 0xBABA.
 160 */
 161s32 igc_validate_nvm_checksum(struct igc_hw *hw)
 162{
 163        u16 checksum = 0;
 164        u16 i, nvm_data;
 165        s32 ret_val = 0;
 166
 167        for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
 168                ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
 169                if (ret_val) {
 170                        hw_dbg("NVM Read Error\n");
 171                        goto out;
 172                }
 173                checksum += nvm_data;
 174        }
 175
 176        if (checksum != (u16)NVM_SUM) {
 177                hw_dbg("NVM Checksum Invalid\n");
 178                ret_val = -IGC_ERR_NVM;
 179                goto out;
 180        }
 181
 182out:
 183        return ret_val;
 184}
 185
 186/**
 187 * igc_update_nvm_checksum - Update EEPROM checksum
 188 * @hw: pointer to the HW structure
 189 *
 190 * Updates the EEPROM checksum by reading/adding each word of the EEPROM
 191 * up to the checksum.  Then calculates the EEPROM checksum and writes the
 192 * value to the EEPROM.
 193 */
 194s32 igc_update_nvm_checksum(struct igc_hw *hw)
 195{
 196        u16 checksum = 0;
 197        u16 i, nvm_data;
 198        s32  ret_val;
 199
 200        for (i = 0; i < NVM_CHECKSUM_REG; i++) {
 201                ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
 202                if (ret_val) {
 203                        hw_dbg("NVM Read Error while updating checksum.\n");
 204                        goto out;
 205                }
 206                checksum += nvm_data;
 207        }
 208        checksum = (u16)NVM_SUM - checksum;
 209        ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
 210        if (ret_val)
 211                hw_dbg("NVM Write Error while updating checksum.\n");
 212
 213out:
 214        return ret_val;
 215}
 216