1 1.2 rin /* $NetBSD: igc_nvm.c,v 1.2 2023/10/04 07:35:27 rin Exp $ */ 2 1.1 rin /* $OpenBSD: igc_nvm.c,v 1.1 2021/10/31 14:52:57 patrick Exp $ */ 3 1.1 rin /*- 4 1.1 rin * Copyright 2021 Intel Corp 5 1.1 rin * Copyright 2021 Rubicon Communications, LLC (Netgate) 6 1.1 rin * SPDX-License-Identifier: BSD-3-Clause 7 1.1 rin */ 8 1.1 rin 9 1.2 rin #include <sys/cdefs.h> 10 1.2 rin __KERNEL_RCSID(0, "$NetBSD: igc_nvm.c,v 1.2 2023/10/04 07:35:27 rin Exp $"); 11 1.2 rin 12 1.2 rin #include <dev/pci/igc/igc_api.h> 13 1.1 rin 14 1.1 rin /** 15 1.1 rin * igc_init_nvm_ops_generic - Initialize NVM function pointers 16 1.1 rin * @hw: pointer to the HW structure 17 1.1 rin * 18 1.1 rin * Setups up the function pointers to no-op functions 19 1.1 rin **/ 20 1.1 rin void 21 1.1 rin igc_init_nvm_ops_generic(struct igc_hw *hw) 22 1.1 rin { 23 1.1 rin struct igc_nvm_info *nvm = &hw->nvm; 24 1.1 rin DEBUGFUNC("igc_init_nvm_ops_generic"); 25 1.1 rin 26 1.1 rin /* Initialize function pointers */ 27 1.1 rin nvm->ops.init_params = igc_null_ops_generic; 28 1.1 rin nvm->ops.acquire = igc_null_ops_generic; 29 1.1 rin nvm->ops.read = igc_null_read_nvm; 30 1.1 rin nvm->ops.release = igc_null_nvm_generic; 31 1.1 rin nvm->ops.reload = igc_reload_nvm_generic; 32 1.1 rin nvm->ops.update = igc_null_ops_generic; 33 1.1 rin nvm->ops.validate = igc_null_ops_generic; 34 1.1 rin nvm->ops.write = igc_null_write_nvm; 35 1.1 rin } 36 1.1 rin 37 1.1 rin /** 38 1.1 rin * igc_null_nvm_read - No-op function, return 0 39 1.1 rin * @hw: pointer to the HW structure 40 1.1 rin * @a: dummy variable 41 1.1 rin * @b: dummy variable 42 1.1 rin * @c: dummy variable 43 1.1 rin **/ 44 1.1 rin int 45 1.1 rin igc_null_read_nvm(struct igc_hw IGC_UNUSEDARG *hw, uint16_t IGC_UNUSEDARG a, 46 1.1 rin uint16_t IGC_UNUSEDARG b, uint16_t IGC_UNUSEDARG *c) 47 1.1 rin { 48 1.1 rin DEBUGFUNC("igc_null_read_nvm"); 49 1.1 rin return IGC_SUCCESS; 50 1.1 rin } 51 1.1 rin 52 1.1 rin /** 53 1.1 rin * igc_null_nvm_generic - No-op function, return void 54 1.1 rin * @hw: pointer to the HW structure 55 1.1 rin **/ 56 1.1 rin void 57 1.1 rin igc_null_nvm_generic(struct igc_hw IGC_UNUSEDARG *hw) 58 1.1 rin { 59 1.1 rin DEBUGFUNC("igc_null_nvm_generic"); 60 1.1 rin return; 61 1.1 rin } 62 1.1 rin 63 1.1 rin /** 64 1.1 rin * igc_reload_nvm_generic - Reloads EEPROM 65 1.1 rin * @hw: pointer to the HW structure 66 1.1 rin * 67 1.1 rin * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the 68 1.1 rin * extended control register. 69 1.1 rin **/ 70 1.1 rin void 71 1.1 rin igc_reload_nvm_generic(struct igc_hw *hw) 72 1.1 rin { 73 1.1 rin uint32_t ctrl_ext; 74 1.1 rin 75 1.1 rin DEBUGFUNC("igc_reload_nvm_generic"); 76 1.1 rin 77 1.1 rin DELAY(10); 78 1.1 rin ctrl_ext = IGC_READ_REG(hw, IGC_CTRL_EXT); 79 1.1 rin ctrl_ext |= IGC_CTRL_EXT_EE_RST; 80 1.1 rin IGC_WRITE_REG(hw, IGC_CTRL_EXT, ctrl_ext); 81 1.1 rin IGC_WRITE_FLUSH(hw); 82 1.1 rin } 83 1.1 rin 84 1.1 rin /** 85 1.1 rin * igc_null_write_nvm - No-op function, return 0 86 1.1 rin * @hw: pointer to the HW structure 87 1.1 rin * @a: dummy variable 88 1.1 rin * @b: dummy variable 89 1.1 rin * @c: dummy variable 90 1.1 rin **/ 91 1.1 rin int 92 1.1 rin igc_null_write_nvm(struct igc_hw IGC_UNUSEDARG *hw, uint16_t IGC_UNUSEDARG a, 93 1.1 rin uint16_t IGC_UNUSEDARG b, uint16_t IGC_UNUSEDARG *c) 94 1.1 rin { 95 1.1 rin DEBUGFUNC("igc_null_write_nvm"); 96 1.1 rin return IGC_SUCCESS; 97 1.1 rin } 98 1.1 rin 99 1.1 rin /** 100 1.1 rin * igc_poll_eerd_eewr_done - Poll for EEPROM read/write completion 101 1.1 rin * @hw: pointer to the HW structure 102 1.1 rin * @ee_reg: EEPROM flag for polling 103 1.1 rin * 104 1.1 rin * Polls the EEPROM status bit for either read or write completion based 105 1.1 rin * upon the value of 'ee_reg'. 106 1.1 rin **/ 107 1.1 rin int 108 1.1 rin igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg) 109 1.1 rin { 110 1.1 rin uint32_t attempts = 100000; 111 1.1 rin uint32_t i, reg = 0; 112 1.1 rin 113 1.1 rin DEBUGFUNC("igc_poll_eerd_eewr_done"); 114 1.1 rin 115 1.1 rin for (i = 0; i < attempts; i++) { 116 1.1 rin if (ee_reg == IGC_NVM_POLL_READ) 117 1.1 rin reg = IGC_READ_REG(hw, IGC_EERD); 118 1.1 rin else 119 1.1 rin reg = IGC_READ_REG(hw, IGC_EEWR); 120 1.1 rin 121 1.1 rin if (reg & IGC_NVM_RW_REG_DONE) 122 1.1 rin return IGC_SUCCESS; 123 1.1 rin 124 1.1 rin DELAY(5); 125 1.1 rin } 126 1.1 rin 127 1.1 rin return -IGC_ERR_NVM; 128 1.1 rin } 129 1.1 rin 130 1.1 rin /** 131 1.1 rin * igc_read_nvm_eerd - Reads EEPROM using EERD register 132 1.1 rin * @hw: pointer to the HW structure 133 1.1 rin * @offset: offset of word in the EEPROM to read 134 1.1 rin * @words: number of words to read 135 1.1 rin * @data: word read from the EEPROM 136 1.1 rin * 137 1.1 rin * Reads a 16 bit word from the EEPROM using the EERD register. 138 1.1 rin **/ 139 1.1 rin int 140 1.1 rin igc_read_nvm_eerd(struct igc_hw *hw, uint16_t offset, uint16_t words, 141 1.1 rin uint16_t *data) 142 1.1 rin { 143 1.1 rin struct igc_nvm_info *nvm = &hw->nvm; 144 1.1 rin uint32_t i, eerd = 0; 145 1.1 rin int ret_val = IGC_SUCCESS; 146 1.1 rin 147 1.1 rin DEBUGFUNC("igc_read_nvm_eerd"); 148 1.1 rin 149 1.1 rin /* A check for invalid values: offset too large, too many words, 150 1.1 rin * too many words for the offset, and not enough words. 151 1.1 rin */ 152 1.1 rin if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || 153 1.1 rin (words == 0)) { 154 1.1 rin DEBUGOUT("nvm parameter(s) out of bounds\n"); 155 1.1 rin return -IGC_ERR_NVM; 156 1.1 rin } 157 1.1 rin 158 1.1 rin for (i = 0; i < words; i++) { 159 1.1 rin eerd = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) + 160 1.1 rin IGC_NVM_RW_REG_START; 161 1.1 rin 162 1.1 rin IGC_WRITE_REG(hw, IGC_EERD, eerd); 163 1.1 rin ret_val = igc_poll_eerd_eewr_done(hw, IGC_NVM_POLL_READ); 164 1.1 rin if (ret_val) 165 1.1 rin break; 166 1.1 rin 167 1.1 rin data[i] = (IGC_READ_REG(hw, IGC_EERD) >> IGC_NVM_RW_REG_DATA); 168 1.1 rin } 169 1.1 rin 170 1.1 rin if (ret_val) 171 1.1 rin DEBUGOUT1("NVM read error: %d\n", ret_val); 172 1.1 rin 173 1.1 rin return ret_val; 174 1.1 rin } 175 1.1 rin 176 1.1 rin /** 177 1.1 rin * igc_read_mac_addr_generic - Read device MAC address 178 1.1 rin * @hw: pointer to the HW structure 179 1.1 rin * 180 1.1 rin * Reads the device MAC address from the EEPROM and stores the value. 181 1.1 rin * Since devices with two ports use the same EEPROM, we increment the 182 1.1 rin * last bit in the MAC address for the second port. 183 1.1 rin **/ 184 1.1 rin int 185 1.1 rin igc_read_mac_addr_generic(struct igc_hw *hw) 186 1.1 rin { 187 1.1 rin uint32_t rar_high, rar_low; 188 1.1 rin uint16_t i; 189 1.1 rin 190 1.1 rin rar_high = IGC_READ_REG(hw, IGC_RAH(0)); 191 1.1 rin rar_low = IGC_READ_REG(hw, IGC_RAL(0)); 192 1.1 rin 193 1.1 rin for (i = 0; i < IGC_RAL_MAC_ADDR_LEN; i++) 194 1.1 rin hw->mac.perm_addr[i] = (uint8_t)(rar_low >> (i * 8)); 195 1.1 rin 196 1.1 rin for (i = 0; i < IGC_RAH_MAC_ADDR_LEN; i++) 197 1.1 rin hw->mac.perm_addr[i+4] = (uint8_t)(rar_high >> (i * 8)); 198 1.1 rin 199 1.1 rin for (i = 0; i < ETHER_ADDR_LEN; i++) 200 1.1 rin hw->mac.addr[i] = hw->mac.perm_addr[i]; 201 1.1 rin 202 1.1 rin return IGC_SUCCESS; 203 1.1 rin } 204 1.1 rin 205 1.1 rin /** 206 1.1 rin * igc_validate_nvm_checksum_generic - Validate EEPROM checksum 207 1.1 rin * @hw: pointer to the HW structure 208 1.1 rin * 209 1.1 rin * Calculates the EEPROM checksum by reading/adding each word of the EEPROM 210 1.1 rin * and then verifies that the sum of the EEPROM is equal to 0xBABA. 211 1.1 rin **/ 212 1.1 rin int 213 1.1 rin igc_validate_nvm_checksum_generic(struct igc_hw *hw) 214 1.1 rin { 215 1.1 rin uint16_t checksum = 0; 216 1.1 rin uint16_t i, nvm_data; 217 1.1 rin int ret_val; 218 1.1 rin 219 1.1 rin DEBUGFUNC("igc_validate_nvm_checksum_generic"); 220 1.1 rin 221 1.1 rin for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { 222 1.1 rin ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); 223 1.1 rin if (ret_val) { 224 1.1 rin DEBUGOUT("NVM Read Error\n"); 225 1.1 rin return ret_val; 226 1.1 rin } 227 1.1 rin checksum += nvm_data; 228 1.1 rin } 229 1.1 rin 230 1.1 rin if (checksum != (uint16_t) NVM_SUM) { 231 1.1 rin DEBUGOUT("NVM Checksum Invalid\n"); 232 1.1 rin return -IGC_ERR_NVM; 233 1.1 rin } 234 1.1 rin 235 1.1 rin return IGC_SUCCESS; 236 1.1 rin } 237