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
igc_init_nvm_ops_generic(struct igc_hw * hw)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
igc_null_read_nvm(struct igc_hw IGC_UNUSEDARG * hw,uint16_t IGC_UNUSEDARG a,uint16_t IGC_UNUSEDARG b,uint16_t IGC_UNUSEDARG * c)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
igc_null_nvm_generic(struct igc_hw IGC_UNUSEDARG * hw)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
igc_reload_nvm_generic(struct igc_hw * hw)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
igc_null_write_nvm(struct igc_hw IGC_UNUSEDARG * hw,uint16_t IGC_UNUSEDARG a,uint16_t IGC_UNUSEDARG b,uint16_t IGC_UNUSEDARG * c)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
igc_poll_eerd_eewr_done(struct igc_hw * hw,int ee_reg)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
igc_read_nvm_eerd(struct igc_hw * hw,uint16_t offset,uint16_t words,uint16_t * data)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
igc_read_mac_addr_generic(struct igc_hw * hw)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
igc_validate_nvm_checksum_generic(struct igc_hw * hw)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