diff options
author | Carolyn Wyborny <carolyn.wyborny@intel.com> | 2012-04-06 19:25:19 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2012-05-12 16:17:13 -0400 |
commit | f96a8a0b78548c0ec06b0b4b438db6ee895d67e9 (patch) | |
tree | b1e6cc64dd55fc46cfb8877aa94db6a7940c1327 /drivers/net/ethernet/intel/igb/e1000_i210.c | |
parent | da02cde1c1ffb798df6159a2252653a9becea51a (diff) |
igb: Add Support for new i210/i211 devices.
This patch adds new initialization functions and device support
for i210 and i211 devices.
Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/igb/e1000_i210.c')
-rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_i210.c | 603 |
1 files changed, 603 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.c b/drivers/net/ethernet/intel/igb/e1000_i210.c new file mode 100644 index 000000000000..77a5f939bc74 --- /dev/null +++ b/drivers/net/ethernet/intel/igb/e1000_i210.c | |||
@@ -0,0 +1,603 @@ | |||
1 | /******************************************************************************* | ||
2 | |||
3 | Intel(R) Gigabit Ethernet Linux driver | ||
4 | Copyright(c) 2007-2012 Intel Corporation. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify it | ||
7 | under the terms and conditions of the GNU General Public License, | ||
8 | version 2, as published by the Free Software Foundation. | ||
9 | |||
10 | This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License along with | ||
16 | this program; if not, write to the Free Software Foundation, Inc., | ||
17 | 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | |||
19 | The full GNU General Public License is included in this distribution in | ||
20 | the file called "COPYING". | ||
21 | |||
22 | Contact Information: | ||
23 | e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||
24 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
25 | |||
26 | ******************************************************************************/ | ||
27 | |||
28 | /* e1000_i210 | ||
29 | * e1000_i211 | ||
30 | */ | ||
31 | |||
32 | #include <linux/types.h> | ||
33 | #include <linux/if_ether.h> | ||
34 | |||
35 | #include "e1000_hw.h" | ||
36 | #include "e1000_i210.h" | ||
37 | |||
38 | static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw); | ||
39 | static void igb_put_hw_semaphore_i210(struct e1000_hw *hw); | ||
40 | static s32 igb_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words, | ||
41 | u16 *data); | ||
42 | static s32 igb_pool_flash_update_done_i210(struct e1000_hw *hw); | ||
43 | |||
44 | /** | ||
45 | * igb_acquire_nvm_i210 - Request for access to EEPROM | ||
46 | * @hw: pointer to the HW structure | ||
47 | * | ||
48 | * Acquire the necessary semaphores for exclusive access to the EEPROM. | ||
49 | * Set the EEPROM access request bit and wait for EEPROM access grant bit. | ||
50 | * Return successful if access grant bit set, else clear the request for | ||
51 | * EEPROM access and return -E1000_ERR_NVM (-1). | ||
52 | **/ | ||
53 | s32 igb_acquire_nvm_i210(struct e1000_hw *hw) | ||
54 | { | ||
55 | return igb_acquire_swfw_sync_i210(hw, E1000_SWFW_EEP_SM); | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * igb_release_nvm_i210 - Release exclusive access to EEPROM | ||
60 | * @hw: pointer to the HW structure | ||
61 | * | ||
62 | * Stop any current commands to the EEPROM and clear the EEPROM request bit, | ||
63 | * then release the semaphores acquired. | ||
64 | **/ | ||
65 | void igb_release_nvm_i210(struct e1000_hw *hw) | ||
66 | { | ||
67 | igb_release_swfw_sync_i210(hw, E1000_SWFW_EEP_SM); | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * igb_acquire_swfw_sync_i210 - Acquire SW/FW semaphore | ||
72 | * @hw: pointer to the HW structure | ||
73 | * @mask: specifies which semaphore to acquire | ||
74 | * | ||
75 | * Acquire the SW/FW semaphore to access the PHY or NVM. The mask | ||
76 | * will also specify which port we're acquiring the lock for. | ||
77 | **/ | ||
78 | s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask) | ||
79 | { | ||
80 | u32 swfw_sync; | ||
81 | u32 swmask = mask; | ||
82 | u32 fwmask = mask << 16; | ||
83 | s32 ret_val = E1000_SUCCESS; | ||
84 | s32 i = 0, timeout = 200; /* FIXME: find real value to use here */ | ||
85 | |||
86 | while (i < timeout) { | ||
87 | if (igb_get_hw_semaphore_i210(hw)) { | ||
88 | ret_val = -E1000_ERR_SWFW_SYNC; | ||
89 | goto out; | ||
90 | } | ||
91 | |||
92 | swfw_sync = rd32(E1000_SW_FW_SYNC); | ||
93 | if (!(swfw_sync & fwmask)) | ||
94 | break; | ||
95 | |||
96 | /* | ||
97 | * Firmware currently using resource (fwmask) | ||
98 | */ | ||
99 | igb_put_hw_semaphore_i210(hw); | ||
100 | mdelay(5); | ||
101 | i++; | ||
102 | } | ||
103 | |||
104 | if (i == timeout) { | ||
105 | hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n"); | ||
106 | ret_val = -E1000_ERR_SWFW_SYNC; | ||
107 | goto out; | ||
108 | } | ||
109 | |||
110 | swfw_sync |= swmask; | ||
111 | wr32(E1000_SW_FW_SYNC, swfw_sync); | ||
112 | |||
113 | igb_put_hw_semaphore_i210(hw); | ||
114 | out: | ||
115 | return ret_val; | ||
116 | } | ||
117 | |||
118 | /** | ||
119 | * igb_release_swfw_sync_i210 - Release SW/FW semaphore | ||
120 | * @hw: pointer to the HW structure | ||
121 | * @mask: specifies which semaphore to acquire | ||
122 | * | ||
123 | * Release the SW/FW semaphore used to access the PHY or NVM. The mask | ||
124 | * will also specify which port we're releasing the lock for. | ||
125 | **/ | ||
126 | void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask) | ||
127 | { | ||
128 | u32 swfw_sync; | ||
129 | |||
130 | while (igb_get_hw_semaphore_i210(hw) != E1000_SUCCESS) | ||
131 | ; /* Empty */ | ||
132 | |||
133 | swfw_sync = rd32(E1000_SW_FW_SYNC); | ||
134 | swfw_sync &= ~mask; | ||
135 | wr32(E1000_SW_FW_SYNC, swfw_sync); | ||
136 | |||
137 | igb_put_hw_semaphore_i210(hw); | ||
138 | } | ||
139 | |||
140 | /** | ||
141 | * igb_get_hw_semaphore_i210 - Acquire hardware semaphore | ||
142 | * @hw: pointer to the HW structure | ||
143 | * | ||
144 | * Acquire the HW semaphore to access the PHY or NVM | ||
145 | **/ | ||
146 | static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw) | ||
147 | { | ||
148 | u32 swsm; | ||
149 | s32 ret_val = E1000_SUCCESS; | ||
150 | s32 timeout = hw->nvm.word_size + 1; | ||
151 | s32 i = 0; | ||
152 | |||
153 | /* Get the FW semaphore. */ | ||
154 | for (i = 0; i < timeout; i++) { | ||
155 | swsm = rd32(E1000_SWSM); | ||
156 | wr32(E1000_SWSM, swsm | E1000_SWSM_SWESMBI); | ||
157 | |||
158 | /* Semaphore acquired if bit latched */ | ||
159 | if (rd32(E1000_SWSM) & E1000_SWSM_SWESMBI) | ||
160 | break; | ||
161 | |||
162 | udelay(50); | ||
163 | } | ||
164 | |||
165 | if (i == timeout) { | ||
166 | /* Release semaphores */ | ||
167 | igb_put_hw_semaphore(hw); | ||
168 | hw_dbg("Driver can't access the NVM\n"); | ||
169 | ret_val = -E1000_ERR_NVM; | ||
170 | goto out; | ||
171 | } | ||
172 | |||
173 | out: | ||
174 | return ret_val; | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * igb_put_hw_semaphore_i210 - Release hardware semaphore | ||
179 | * @hw: pointer to the HW structure | ||
180 | * | ||
181 | * Release hardware semaphore used to access the PHY or NVM | ||
182 | **/ | ||
183 | static void igb_put_hw_semaphore_i210(struct e1000_hw *hw) | ||
184 | { | ||
185 | u32 swsm; | ||
186 | |||
187 | swsm = rd32(E1000_SWSM); | ||
188 | |||
189 | swsm &= ~E1000_SWSM_SWESMBI; | ||
190 | |||
191 | wr32(E1000_SWSM, swsm); | ||
192 | } | ||
193 | |||
194 | /** | ||
195 | * igb_read_nvm_srrd_i210 - Reads Shadow Ram using EERD register | ||
196 | * @hw: pointer to the HW structure | ||
197 | * @offset: offset of word in the Shadow Ram to read | ||
198 | * @words: number of words to read | ||
199 | * @data: word read from the Shadow Ram | ||
200 | * | ||
201 | * Reads a 16 bit word from the Shadow Ram using the EERD register. | ||
202 | * Uses necessary synchronization semaphores. | ||
203 | **/ | ||
204 | s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words, | ||
205 | u16 *data) | ||
206 | { | ||
207 | s32 status = E1000_SUCCESS; | ||
208 | u16 i, count; | ||
209 | |||
210 | /* We cannot hold synchronization semaphores for too long, | ||
211 | * because of forceful takeover procedure. However it is more efficient | ||
212 | * to read in bursts than synchronizing access for each word. */ | ||
213 | for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) { | ||
214 | count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ? | ||
215 | E1000_EERD_EEWR_MAX_COUNT : (words - i); | ||
216 | if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { | ||
217 | status = igb_read_nvm_eerd(hw, offset, count, | ||
218 | data + i); | ||
219 | hw->nvm.ops.release(hw); | ||
220 | } else { | ||
221 | status = E1000_ERR_SWFW_SYNC; | ||
222 | } | ||
223 | |||
224 | if (status != E1000_SUCCESS) | ||
225 | break; | ||
226 | } | ||
227 | |||
228 | return status; | ||
229 | } | ||
230 | |||
231 | /** | ||
232 | * igb_write_nvm_srwr_i210 - Write to Shadow RAM using EEWR | ||
233 | * @hw: pointer to the HW structure | ||
234 | * @offset: offset within the Shadow RAM to be written to | ||
235 | * @words: number of words to write | ||
236 | * @data: 16 bit word(s) to be written to the Shadow RAM | ||
237 | * | ||
238 | * Writes data to Shadow RAM at offset using EEWR register. | ||
239 | * | ||
240 | * If e1000_update_nvm_checksum is not called after this function , the | ||
241 | * data will not be committed to FLASH and also Shadow RAM will most likely | ||
242 | * contain an invalid checksum. | ||
243 | * | ||
244 | * If error code is returned, data and Shadow RAM may be inconsistent - buffer | ||
245 | * partially written. | ||
246 | **/ | ||
247 | s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words, | ||
248 | u16 *data) | ||
249 | { | ||
250 | s32 status = E1000_SUCCESS; | ||
251 | u16 i, count; | ||
252 | |||
253 | /* We cannot hold synchronization semaphores for too long, | ||
254 | * because of forceful takeover procedure. However it is more efficient | ||
255 | * to write in bursts than synchronizing access for each word. */ | ||
256 | for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) { | ||
257 | count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ? | ||
258 | E1000_EERD_EEWR_MAX_COUNT : (words - i); | ||
259 | if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { | ||
260 | status = igb_write_nvm_srwr(hw, offset, count, | ||
261 | data + i); | ||
262 | hw->nvm.ops.release(hw); | ||
263 | } else { | ||
264 | status = E1000_ERR_SWFW_SYNC; | ||
265 | } | ||
266 | |||
267 | if (status != E1000_SUCCESS) | ||
268 | break; | ||
269 | } | ||
270 | |||
271 | return status; | ||
272 | } | ||
273 | |||
274 | /** | ||
275 | * igb_write_nvm_srwr - Write to Shadow Ram using EEWR | ||
276 | * @hw: pointer to the HW structure | ||
277 | * @offset: offset within the Shadow Ram to be written to | ||
278 | * @words: number of words to write | ||
279 | * @data: 16 bit word(s) to be written to the Shadow Ram | ||
280 | * | ||
281 | * Writes data to Shadow Ram at offset using EEWR register. | ||
282 | * | ||
283 | * If igb_update_nvm_checksum is not called after this function , the | ||
284 | * Shadow Ram will most likely contain an invalid checksum. | ||
285 | **/ | ||
286 | static s32 igb_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words, | ||
287 | u16 *data) | ||
288 | { | ||
289 | struct e1000_nvm_info *nvm = &hw->nvm; | ||
290 | u32 i, k, eewr = 0; | ||
291 | u32 attempts = 100000; | ||
292 | s32 ret_val = E1000_SUCCESS; | ||
293 | |||
294 | /* | ||
295 | * A check for invalid values: offset too large, too many words, | ||
296 | * too many words for the offset, and not enough words. | ||
297 | */ | ||
298 | if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || | ||
299 | (words == 0)) { | ||
300 | hw_dbg("nvm parameter(s) out of bounds\n"); | ||
301 | ret_val = -E1000_ERR_NVM; | ||
302 | goto out; | ||
303 | } | ||
304 | |||
305 | for (i = 0; i < words; i++) { | ||
306 | eewr = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) | | ||
307 | (data[i] << E1000_NVM_RW_REG_DATA) | | ||
308 | E1000_NVM_RW_REG_START; | ||
309 | |||
310 | wr32(E1000_SRWR, eewr); | ||
311 | |||
312 | for (k = 0; k < attempts; k++) { | ||
313 | if (E1000_NVM_RW_REG_DONE & | ||
314 | rd32(E1000_SRWR)) { | ||
315 | ret_val = E1000_SUCCESS; | ||
316 | break; | ||
317 | } | ||
318 | udelay(5); | ||
319 | } | ||
320 | |||
321 | if (ret_val != E1000_SUCCESS) { | ||
322 | hw_dbg("Shadow RAM write EEWR timed out\n"); | ||
323 | break; | ||
324 | } | ||
325 | } | ||
326 | |||
327 | out: | ||
328 | return ret_val; | ||
329 | } | ||
330 | |||
331 | /** | ||
332 | * igb_read_nvm_i211 - Read NVM wrapper function for I211 | ||
333 | * @hw: pointer to the HW structure | ||
334 | * @address: the word address (aka eeprom offset) to read | ||
335 | * @data: pointer to the data read | ||
336 | * | ||
337 | * Wrapper function to return data formerly found in the NVM. | ||
338 | **/ | ||
339 | s32 igb_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words, | ||
340 | u16 *data) | ||
341 | { | ||
342 | s32 ret_val = E1000_SUCCESS; | ||
343 | |||
344 | /* Only the MAC addr is required to be present in the iNVM */ | ||
345 | switch (offset) { | ||
346 | case NVM_MAC_ADDR: | ||
347 | ret_val = igb_read_invm_i211(hw, offset, &data[0]); | ||
348 | ret_val |= igb_read_invm_i211(hw, offset+1, &data[1]); | ||
349 | ret_val |= igb_read_invm_i211(hw, offset+2, &data[2]); | ||
350 | if (ret_val != E1000_SUCCESS) | ||
351 | hw_dbg("MAC Addr not found in iNVM\n"); | ||
352 | break; | ||
353 | case NVM_ID_LED_SETTINGS: | ||
354 | case NVM_INIT_CTRL_2: | ||
355 | case NVM_INIT_CTRL_4: | ||
356 | case NVM_LED_1_CFG: | ||
357 | case NVM_LED_0_2_CFG: | ||
358 | igb_read_invm_i211(hw, offset, data); | ||
359 | break; | ||
360 | case NVM_COMPAT: | ||
361 | *data = ID_LED_DEFAULT_I210; | ||
362 | break; | ||
363 | case NVM_SUB_DEV_ID: | ||
364 | *data = hw->subsystem_device_id; | ||
365 | break; | ||
366 | case NVM_SUB_VEN_ID: | ||
367 | *data = hw->subsystem_vendor_id; | ||
368 | break; | ||
369 | case NVM_DEV_ID: | ||
370 | *data = hw->device_id; | ||
371 | break; | ||
372 | case NVM_VEN_ID: | ||
373 | *data = hw->vendor_id; | ||
374 | break; | ||
375 | default: | ||
376 | hw_dbg("NVM word 0x%02x is not mapped.\n", offset); | ||
377 | *data = NVM_RESERVED_WORD; | ||
378 | break; | ||
379 | } | ||
380 | return ret_val; | ||
381 | } | ||
382 | |||
383 | /** | ||
384 | * igb_read_invm_i211 - Reads OTP | ||
385 | * @hw: pointer to the HW structure | ||
386 | * @address: the word address (aka eeprom offset) to read | ||
387 | * @data: pointer to the data read | ||
388 | * | ||
389 | * Reads 16-bit words from the OTP. Return error when the word is not | ||
390 | * stored in OTP. | ||
391 | **/ | ||
392 | s32 igb_read_invm_i211(struct e1000_hw *hw, u16 address, u16 *data) | ||
393 | { | ||
394 | s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND; | ||
395 | u32 invm_dword; | ||
396 | u16 i; | ||
397 | u8 record_type, word_address; | ||
398 | |||
399 | for (i = 0; i < E1000_INVM_SIZE; i++) { | ||
400 | invm_dword = rd32(E1000_INVM_DATA_REG(i)); | ||
401 | /* Get record type */ | ||
402 | record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword); | ||
403 | if (record_type == E1000_INVM_UNINITIALIZED_STRUCTURE) | ||
404 | break; | ||
405 | if (record_type == E1000_INVM_CSR_AUTOLOAD_STRUCTURE) | ||
406 | i += E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS; | ||
407 | if (record_type == E1000_INVM_RSA_KEY_SHA256_STRUCTURE) | ||
408 | i += E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS; | ||
409 | if (record_type == E1000_INVM_WORD_AUTOLOAD_STRUCTURE) { | ||
410 | word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword); | ||
411 | if (word_address == (u8)address) { | ||
412 | *data = INVM_DWORD_TO_WORD_DATA(invm_dword); | ||
413 | hw_dbg("Read INVM Word 0x%02x = %x", | ||
414 | address, *data); | ||
415 | status = E1000_SUCCESS; | ||
416 | break; | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | if (status != E1000_SUCCESS) | ||
421 | hw_dbg("Requested word 0x%02x not found in OTP\n", address); | ||
422 | return status; | ||
423 | } | ||
424 | |||
425 | /** | ||
426 | * igb_validate_nvm_checksum_i210 - Validate EEPROM checksum | ||
427 | * @hw: pointer to the HW structure | ||
428 | * | ||
429 | * Calculates the EEPROM checksum by reading/adding each word of the EEPROM | ||
430 | * and then verifies that the sum of the EEPROM is equal to 0xBABA. | ||
431 | **/ | ||
432 | s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw) | ||
433 | { | ||
434 | s32 status = E1000_SUCCESS; | ||
435 | s32 (*read_op_ptr)(struct e1000_hw *, u16, u16, u16 *); | ||
436 | |||
437 | if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { | ||
438 | |||
439 | /* | ||
440 | * Replace the read function with semaphore grabbing with | ||
441 | * the one that skips this for a while. | ||
442 | * We have semaphore taken already here. | ||
443 | */ | ||
444 | read_op_ptr = hw->nvm.ops.read; | ||
445 | hw->nvm.ops.read = igb_read_nvm_eerd; | ||
446 | |||
447 | status = igb_validate_nvm_checksum(hw); | ||
448 | |||
449 | /* Revert original read operation. */ | ||
450 | hw->nvm.ops.read = read_op_ptr; | ||
451 | |||
452 | hw->nvm.ops.release(hw); | ||
453 | } else { | ||
454 | status = E1000_ERR_SWFW_SYNC; | ||
455 | } | ||
456 | |||
457 | return status; | ||
458 | } | ||
459 | |||
460 | |||
461 | /** | ||
462 | * igb_update_nvm_checksum_i210 - Update EEPROM checksum | ||
463 | * @hw: pointer to the HW structure | ||
464 | * | ||
465 | * Updates the EEPROM checksum by reading/adding each word of the EEPROM | ||
466 | * up to the checksum. Then calculates the EEPROM checksum and writes the | ||
467 | * value to the EEPROM. Next commit EEPROM data onto the Flash. | ||
468 | **/ | ||
469 | s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw) | ||
470 | { | ||
471 | s32 ret_val = E1000_SUCCESS; | ||
472 | u16 checksum = 0; | ||
473 | u16 i, nvm_data; | ||
474 | |||
475 | /* | ||
476 | * Read the first word from the EEPROM. If this times out or fails, do | ||
477 | * not continue or we could be in for a very long wait while every | ||
478 | * EEPROM read fails | ||
479 | */ | ||
480 | ret_val = igb_read_nvm_eerd(hw, 0, 1, &nvm_data); | ||
481 | if (ret_val != E1000_SUCCESS) { | ||
482 | hw_dbg("EEPROM read failed\n"); | ||
483 | goto out; | ||
484 | } | ||
485 | |||
486 | if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { | ||
487 | /* | ||
488 | * Do not use hw->nvm.ops.write, hw->nvm.ops.read | ||
489 | * because we do not want to take the synchronization | ||
490 | * semaphores twice here. | ||
491 | */ | ||
492 | |||
493 | for (i = 0; i < NVM_CHECKSUM_REG; i++) { | ||
494 | ret_val = igb_read_nvm_eerd(hw, i, 1, &nvm_data); | ||
495 | if (ret_val) { | ||
496 | hw->nvm.ops.release(hw); | ||
497 | hw_dbg("NVM Read Error while updating checksum.\n"); | ||
498 | goto out; | ||
499 | } | ||
500 | checksum += nvm_data; | ||
501 | } | ||
502 | checksum = (u16) NVM_SUM - checksum; | ||
503 | ret_val = igb_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1, | ||
504 | &checksum); | ||
505 | if (ret_val != E1000_SUCCESS) { | ||
506 | hw->nvm.ops.release(hw); | ||
507 | hw_dbg("NVM Write Error while updating checksum.\n"); | ||
508 | goto out; | ||
509 | } | ||
510 | |||
511 | hw->nvm.ops.release(hw); | ||
512 | |||
513 | ret_val = igb_update_flash_i210(hw); | ||
514 | } else { | ||
515 | ret_val = -E1000_ERR_SWFW_SYNC; | ||
516 | } | ||
517 | out: | ||
518 | return ret_val; | ||
519 | } | ||
520 | |||
521 | /** | ||
522 | * igb_update_flash_i210 - Commit EEPROM to the flash | ||
523 | * @hw: pointer to the HW structure | ||
524 | * | ||
525 | **/ | ||
526 | s32 igb_update_flash_i210(struct e1000_hw *hw) | ||
527 | { | ||
528 | s32 ret_val = E1000_SUCCESS; | ||
529 | u32 flup; | ||
530 | |||
531 | ret_val = igb_pool_flash_update_done_i210(hw); | ||
532 | if (ret_val == -E1000_ERR_NVM) { | ||
533 | hw_dbg("Flash update time out\n"); | ||
534 | goto out; | ||
535 | } | ||
536 | |||
537 | flup = rd32(E1000_EECD) | E1000_EECD_FLUPD_I210; | ||
538 | wr32(E1000_EECD, flup); | ||
539 | |||
540 | ret_val = igb_pool_flash_update_done_i210(hw); | ||
541 | if (ret_val == E1000_SUCCESS) | ||
542 | hw_dbg("Flash update complete\n"); | ||
543 | else | ||
544 | hw_dbg("Flash update time out\n"); | ||
545 | |||
546 | out: | ||
547 | return ret_val; | ||
548 | } | ||
549 | |||
550 | /** | ||
551 | * igb_pool_flash_update_done_i210 - Pool FLUDONE status. | ||
552 | * @hw: pointer to the HW structure | ||
553 | * | ||
554 | **/ | ||
555 | s32 igb_pool_flash_update_done_i210(struct e1000_hw *hw) | ||
556 | { | ||
557 | s32 ret_val = -E1000_ERR_NVM; | ||
558 | u32 i, reg; | ||
559 | |||
560 | for (i = 0; i < E1000_FLUDONE_ATTEMPTS; i++) { | ||
561 | reg = rd32(E1000_EECD); | ||
562 | if (reg & E1000_EECD_FLUDONE_I210) { | ||
563 | ret_val = E1000_SUCCESS; | ||
564 | break; | ||
565 | } | ||
566 | udelay(5); | ||
567 | } | ||
568 | |||
569 | return ret_val; | ||
570 | } | ||
571 | |||
572 | /** | ||
573 | * igb_valid_led_default_i210 - Verify a valid default LED config | ||
574 | * @hw: pointer to the HW structure | ||
575 | * @data: pointer to the NVM (EEPROM) | ||
576 | * | ||
577 | * Read the EEPROM for the current default LED configuration. If the | ||
578 | * LED configuration is not valid, set to a valid LED configuration. | ||
579 | **/ | ||
580 | s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data) | ||
581 | { | ||
582 | s32 ret_val; | ||
583 | |||
584 | ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); | ||
585 | if (ret_val) { | ||
586 | hw_dbg("NVM Read Error\n"); | ||
587 | goto out; | ||
588 | } | ||
589 | |||
590 | if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) { | ||
591 | switch (hw->phy.media_type) { | ||
592 | case e1000_media_type_internal_serdes: | ||
593 | *data = ID_LED_DEFAULT_I210_SERDES; | ||
594 | break; | ||
595 | case e1000_media_type_copper: | ||
596 | default: | ||
597 | *data = ID_LED_DEFAULT_I210; | ||
598 | break; | ||
599 | } | ||
600 | } | ||
601 | out: | ||
602 | return ret_val; | ||
603 | } | ||