Commit | Line | Data |
---|---|---|
f96a8a0b CW |
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 | } |