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