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