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