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