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