1 /*-
2 * Copyright 2021 Intel Corp
3 * Copyright 2021 Rubicon Communications, LLC (Netgate)
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <sys/cdefs.h>
8 __FBSDID("$FreeBSD$");
9
10 #include "igc_api.h"
11
12 static s32 igc_init_nvm_params_i225(struct igc_hw *hw);
13 static s32 igc_init_mac_params_i225(struct igc_hw *hw);
14 static s32 igc_init_phy_params_i225(struct igc_hw *hw);
15 static s32 igc_reset_hw_i225(struct igc_hw *hw);
16 static s32 igc_acquire_nvm_i225(struct igc_hw *hw);
17 static void igc_release_nvm_i225(struct igc_hw *hw);
18 static s32 igc_get_hw_semaphore_i225(struct igc_hw *hw);
19 static s32 __igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words,
20 u16 *data);
21 static s32 igc_pool_flash_update_done_i225(struct igc_hw *hw);
22
23 /**
24 * igc_init_nvm_params_i225 - Init NVM func ptrs.
25 * @hw: pointer to the HW structure
26 **/
igc_init_nvm_params_i225(struct igc_hw * hw)27 static s32 igc_init_nvm_params_i225(struct igc_hw *hw)
28 {
29 struct igc_nvm_info *nvm = &hw->nvm;
30 u32 eecd = IGC_READ_REG(hw, IGC_EECD);
31 u16 size;
32
33 DEBUGFUNC("igc_init_nvm_params_i225");
34
35 size = (u16)((eecd & IGC_EECD_SIZE_EX_MASK) >>
36 IGC_EECD_SIZE_EX_SHIFT);
37 /*
38 * Added to a constant, "size" becomes the left-shift value
39 * for setting word_size.
40 */
41 size += NVM_WORD_SIZE_BASE_SHIFT;
42
43 /* Just in case size is out of range, cap it to the largest
44 * EEPROM size supported
45 */
46 if (size > 15)
47 size = 15;
48
49 nvm->word_size = 1 << size;
50 nvm->opcode_bits = 8;
51 nvm->delay_usec = 1;
52 nvm->type = igc_nvm_eeprom_spi;
53
54
55 nvm->page_size = eecd & IGC_EECD_ADDR_BITS ? 32 : 8;
56 nvm->address_bits = eecd & IGC_EECD_ADDR_BITS ?
57 16 : 8;
58
59 if (nvm->word_size == (1 << 15))
60 nvm->page_size = 128;
61
62 nvm->ops.acquire = igc_acquire_nvm_i225;
63 nvm->ops.release = igc_release_nvm_i225;
64 if (igc_get_flash_presence_i225(hw)) {
65 hw->nvm.type = igc_nvm_flash_hw;
66 nvm->ops.read = igc_read_nvm_srrd_i225;
67 nvm->ops.write = igc_write_nvm_srwr_i225;
68 nvm->ops.validate = igc_validate_nvm_checksum_i225;
69 nvm->ops.update = igc_update_nvm_checksum_i225;
70 } else {
71 hw->nvm.type = igc_nvm_invm;
72 nvm->ops.write = igc_null_write_nvm;
73 nvm->ops.validate = igc_null_ops_generic;
74 nvm->ops.update = igc_null_ops_generic;
75 }
76
77 return IGC_SUCCESS;
78 }
79
80 /**
81 * igc_init_mac_params_i225 - Init MAC func ptrs.
82 * @hw: pointer to the HW structure
83 **/
igc_init_mac_params_i225(struct igc_hw * hw)84 static s32 igc_init_mac_params_i225(struct igc_hw *hw)
85 {
86 struct igc_mac_info *mac = &hw->mac;
87 struct igc_dev_spec_i225 *dev_spec = &hw->dev_spec._i225;
88
89 DEBUGFUNC("igc_init_mac_params_i225");
90
91 /* Initialize function pointer */
92 igc_init_mac_ops_generic(hw);
93
94 /* Set media type */
95 hw->phy.media_type = igc_media_type_copper;
96 /* Set mta register count */
97 mac->mta_reg_count = 128;
98 /* Set rar entry count */
99 mac->rar_entry_count = IGC_RAR_ENTRIES_BASE;
100
101 /* reset */
102 mac->ops.reset_hw = igc_reset_hw_i225;
103 /* hw initialization */
104 mac->ops.init_hw = igc_init_hw_i225;
105 /* link setup */
106 mac->ops.setup_link = igc_setup_link_generic;
107 /* check for link */
108 mac->ops.check_for_link = igc_check_for_link_i225;
109 /* link info */
110 mac->ops.get_link_up_info = igc_get_speed_and_duplex_copper_generic;
111 /* acquire SW_FW sync */
112 mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225;
113 /* release SW_FW sync */
114 mac->ops.release_swfw_sync = igc_release_swfw_sync_i225;
115
116 /* Allow a single clear of the SW semaphore on I225 */
117 dev_spec->clear_semaphore_once = true;
118 mac->ops.setup_physical_interface = igc_setup_copper_link_i225;
119
120 /* Set if part includes ASF firmware */
121 mac->asf_firmware_present = true;
122
123 /* multicast address update */
124 mac->ops.update_mc_addr_list = igc_update_mc_addr_list_generic;
125
126 mac->ops.write_vfta = igc_write_vfta_generic;
127
128 return IGC_SUCCESS;
129 }
130
131 /**
132 * igc_init_phy_params_i225 - Init PHY func ptrs.
133 * @hw: pointer to the HW structure
134 **/
igc_init_phy_params_i225(struct igc_hw * hw)135 static s32 igc_init_phy_params_i225(struct igc_hw *hw)
136 {
137 struct igc_phy_info *phy = &hw->phy;
138 s32 ret_val = IGC_SUCCESS;
139
140 DEBUGFUNC("igc_init_phy_params_i225");
141
142
143 if (hw->phy.media_type != igc_media_type_copper) {
144 phy->type = igc_phy_none;
145 goto out;
146 }
147
148 phy->ops.power_up = igc_power_up_phy_copper;
149 phy->ops.power_down = igc_power_down_phy_copper_base;
150
151 phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT_2500;
152
153 phy->reset_delay_us = 100;
154
155 phy->ops.acquire = igc_acquire_phy_base;
156 phy->ops.check_reset_block = igc_check_reset_block_generic;
157 phy->ops.release = igc_release_phy_base;
158 phy->ops.reset = igc_phy_hw_reset_generic;
159 phy->ops.read_reg = igc_read_phy_reg_gpy;
160 phy->ops.write_reg = igc_write_phy_reg_gpy;
161
162 /* Make sure the PHY is in a good state. Several people have reported
163 * firmware leaving the PHY's page select register set to something
164 * other than the default of zero, which causes the PHY ID read to
165 * access something other than the intended register.
166 */
167 ret_val = hw->phy.ops.reset(hw);
168 if (ret_val)
169 goto out;
170
171 ret_val = igc_get_phy_id(hw);
172 /* Verify phy id and set remaining function pointers */
173 switch (phy->id) {
174 case I225_I_PHY_ID:
175 phy->type = igc_phy_i225;
176 phy->ops.set_d0_lplu_state = igc_set_d0_lplu_state_i225;
177 phy->ops.set_d3_lplu_state = igc_set_d3_lplu_state_i225;
178 /* TODO - complete with GPY PHY information */
179 break;
180 default:
181 ret_val = -IGC_ERR_PHY;
182 goto out;
183 }
184
185 out:
186 return ret_val;
187 }
188
189 /**
190 * igc_reset_hw_i225 - Reset hardware
191 * @hw: pointer to the HW structure
192 *
193 * This resets the hardware into a known state.
194 **/
igc_reset_hw_i225(struct igc_hw * hw)195 static s32 igc_reset_hw_i225(struct igc_hw *hw)
196 {
197 u32 ctrl;
198 s32 ret_val;
199
200 DEBUGFUNC("igc_reset_hw_i225");
201
202 /*
203 * Prevent the PCI-E bus from sticking if there is no TLP connection
204 * on the last TLP read/write transaction when MAC is reset.
205 */
206 ret_val = igc_disable_pcie_master_generic(hw);
207 if (ret_val)
208 DEBUGOUT("PCI-E Master disable polling has failed.\n");
209
210 DEBUGOUT("Masking off all interrupts\n");
211 IGC_WRITE_REG(hw, IGC_IMC, 0xffffffff);
212
213 IGC_WRITE_REG(hw, IGC_RCTL, 0);
214 IGC_WRITE_REG(hw, IGC_TCTL, IGC_TCTL_PSP);
215 IGC_WRITE_FLUSH(hw);
216
217 msec_delay(10);
218
219 ctrl = IGC_READ_REG(hw, IGC_CTRL);
220
221 DEBUGOUT("Issuing a global reset to MAC\n");
222 IGC_WRITE_REG(hw, IGC_CTRL, ctrl | IGC_CTRL_DEV_RST);
223
224 ret_val = igc_get_auto_rd_done_generic(hw);
225 if (ret_val) {
226 /*
227 * When auto config read does not complete, do not
228 * return with an error. This can happen in situations
229 * where there is no eeprom and prevents getting link.
230 */
231 DEBUGOUT("Auto Read Done did not complete\n");
232 }
233
234 /* Clear any pending interrupt events. */
235 IGC_WRITE_REG(hw, IGC_IMC, 0xffffffff);
236 IGC_READ_REG(hw, IGC_ICR);
237
238 /* Install any alternate MAC address into RAR0 */
239 ret_val = igc_check_alt_mac_addr_generic(hw);
240
241 return ret_val;
242 }
243
244 /* igc_acquire_nvm_i225 - Request for access to EEPROM
245 * @hw: pointer to the HW structure
246 *
247 * Acquire the necessary semaphores for exclusive access to the EEPROM.
248 * Set the EEPROM access request bit and wait for EEPROM access grant bit.
249 * Return successful if access grant bit set, else clear the request for
250 * EEPROM access and return -IGC_ERR_NVM (-1).
251 */
igc_acquire_nvm_i225(struct igc_hw * hw)252 static s32 igc_acquire_nvm_i225(struct igc_hw *hw)
253 {
254 s32 ret_val;
255
256 DEBUGFUNC("igc_acquire_nvm_i225");
257
258 ret_val = igc_acquire_swfw_sync_i225(hw, IGC_SWFW_EEP_SM);
259
260 return ret_val;
261 }
262
263 /* igc_release_nvm_i225 - Release exclusive access to EEPROM
264 * @hw: pointer to the HW structure
265 *
266 * Stop any current commands to the EEPROM and clear the EEPROM request bit,
267 * then release the semaphores acquired.
268 */
igc_release_nvm_i225(struct igc_hw * hw)269 static void igc_release_nvm_i225(struct igc_hw *hw)
270 {
271 DEBUGFUNC("igc_release_nvm_i225");
272
273 igc_release_swfw_sync_i225(hw, IGC_SWFW_EEP_SM);
274 }
275
276 /* igc_acquire_swfw_sync_i225 - Acquire SW/FW semaphore
277 * @hw: pointer to the HW structure
278 * @mask: specifies which semaphore to acquire
279 *
280 * Acquire the SW/FW semaphore to access the PHY or NVM. The mask
281 * will also specify which port we're acquiring the lock for.
282 */
igc_acquire_swfw_sync_i225(struct igc_hw * hw,u16 mask)283 s32 igc_acquire_swfw_sync_i225(struct igc_hw *hw, u16 mask)
284 {
285 u32 swfw_sync;
286 u32 swmask = mask;
287 u32 fwmask = mask << 16;
288 s32 ret_val = IGC_SUCCESS;
289 s32 i = 0, timeout = 200; /* FIXME: find real value to use here */
290
291 DEBUGFUNC("igc_acquire_swfw_sync_i225");
292
293 while (i < timeout) {
294 if (igc_get_hw_semaphore_i225(hw)) {
295 ret_val = -IGC_ERR_SWFW_SYNC;
296 goto out;
297 }
298
299 swfw_sync = IGC_READ_REG(hw, IGC_SW_FW_SYNC);
300 if (!(swfw_sync & (fwmask | swmask)))
301 break;
302
303 /* Firmware currently using resource (fwmask)
304 * or other software thread using resource (swmask)
305 */
306 igc_put_hw_semaphore_generic(hw);
307 msec_delay_irq(5);
308 i++;
309 }
310
311 if (i == timeout) {
312 DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
313 ret_val = -IGC_ERR_SWFW_SYNC;
314 goto out;
315 }
316
317 swfw_sync |= swmask;
318 IGC_WRITE_REG(hw, IGC_SW_FW_SYNC, swfw_sync);
319
320 igc_put_hw_semaphore_generic(hw);
321
322 out:
323 return ret_val;
324 }
325
326 /* igc_release_swfw_sync_i225 - Release SW/FW semaphore
327 * @hw: pointer to the HW structure
328 * @mask: specifies which semaphore to acquire
329 *
330 * Release the SW/FW semaphore used to access the PHY or NVM. The mask
331 * will also specify which port we're releasing the lock for.
332 */
igc_release_swfw_sync_i225(struct igc_hw * hw,u16 mask)333 void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask)
334 {
335 u32 swfw_sync;
336
337 DEBUGFUNC("igc_release_swfw_sync_i225");
338
339 while (igc_get_hw_semaphore_i225(hw) != IGC_SUCCESS)
340 ; /* Empty */
341
342 swfw_sync = IGC_READ_REG(hw, IGC_SW_FW_SYNC);
343 swfw_sync &= ~mask;
344 IGC_WRITE_REG(hw, IGC_SW_FW_SYNC, swfw_sync);
345
346 igc_put_hw_semaphore_generic(hw);
347 }
348
349 /*
350 * igc_setup_copper_link_i225 - Configure copper link settings
351 * @hw: pointer to the HW structure
352 *
353 * Configures the link for auto-neg or forced speed and duplex. Then we check
354 * for link, once link is established calls to configure collision distance
355 * and flow control are called.
356 */
igc_setup_copper_link_i225(struct igc_hw * hw)357 s32 igc_setup_copper_link_i225(struct igc_hw *hw)
358 {
359 u32 phpm_reg;
360 s32 ret_val;
361 u32 ctrl;
362
363 DEBUGFUNC("igc_setup_copper_link_i225");
364
365 ctrl = IGC_READ_REG(hw, IGC_CTRL);
366 ctrl |= IGC_CTRL_SLU;
367 ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX);
368 IGC_WRITE_REG(hw, IGC_CTRL, ctrl);
369
370 phpm_reg = IGC_READ_REG(hw, IGC_I225_PHPM);
371 phpm_reg &= ~IGC_I225_PHPM_GO_LINKD;
372 IGC_WRITE_REG(hw, IGC_I225_PHPM, phpm_reg);
373
374 ret_val = igc_setup_copper_link_generic(hw);
375
376 return ret_val;
377 }
378
379 /* igc_get_hw_semaphore_i225 - Acquire hardware semaphore
380 * @hw: pointer to the HW structure
381 *
382 * Acquire the HW semaphore to access the PHY or NVM
383 */
igc_get_hw_semaphore_i225(struct igc_hw * hw)384 static s32 igc_get_hw_semaphore_i225(struct igc_hw *hw)
385 {
386 u32 swsm;
387 s32 timeout = hw->nvm.word_size + 1;
388 s32 i = 0;
389
390 DEBUGFUNC("igc_get_hw_semaphore_i225");
391
392 /* Get the SW semaphore */
393 while (i < timeout) {
394 swsm = IGC_READ_REG(hw, IGC_SWSM);
395 if (!(swsm & IGC_SWSM_SMBI))
396 break;
397
398 usec_delay(50);
399 i++;
400 }
401
402 if (i == timeout) {
403 /* In rare circumstances, the SW semaphore may already be held
404 * unintentionally. Clear the semaphore once before giving up.
405 */
406 if (hw->dev_spec._i225.clear_semaphore_once) {
407 hw->dev_spec._i225.clear_semaphore_once = false;
408 igc_put_hw_semaphore_generic(hw);
409 for (i = 0; i < timeout; i++) {
410 swsm = IGC_READ_REG(hw, IGC_SWSM);
411 if (!(swsm & IGC_SWSM_SMBI))
412 break;
413
414 usec_delay(50);
415 }
416 }
417
418 /* If we do not have the semaphore here, we have to give up. */
419 if (i == timeout) {
420 DEBUGOUT("Driver can't access device -\n");
421 DEBUGOUT("SMBI bit is set.\n");
422 return -IGC_ERR_NVM;
423 }
424 }
425
426 /* Get the FW semaphore. */
427 for (i = 0; i < timeout; i++) {
428 swsm = IGC_READ_REG(hw, IGC_SWSM);
429 IGC_WRITE_REG(hw, IGC_SWSM, swsm | IGC_SWSM_SWESMBI);
430
431 /* Semaphore acquired if bit latched */
432 if (IGC_READ_REG(hw, IGC_SWSM) & IGC_SWSM_SWESMBI)
433 break;
434
435 usec_delay(50);
436 }
437
438 if (i == timeout) {
439 /* Release semaphores */
440 igc_put_hw_semaphore_generic(hw);
441 DEBUGOUT("Driver can't access the NVM\n");
442 return -IGC_ERR_NVM;
443 }
444
445 return IGC_SUCCESS;
446 }
447
448 /* igc_read_nvm_srrd_i225 - Reads Shadow Ram using EERD register
449 * @hw: pointer to the HW structure
450 * @offset: offset of word in the Shadow Ram to read
451 * @words: number of words to read
452 * @data: word read from the Shadow Ram
453 *
454 * Reads a 16 bit word from the Shadow Ram using the EERD register.
455 * Uses necessary synchronization semaphores.
456 */
igc_read_nvm_srrd_i225(struct igc_hw * hw,u16 offset,u16 words,u16 * data)457 s32 igc_read_nvm_srrd_i225(struct igc_hw *hw, u16 offset, u16 words,
458 u16 *data)
459 {
460 s32 status = IGC_SUCCESS;
461 u16 i, count;
462
463 DEBUGFUNC("igc_read_nvm_srrd_i225");
464
465 /* We cannot hold synchronization semaphores for too long,
466 * because of forceful takeover procedure. However it is more efficient
467 * to read in bursts than synchronizing access for each word.
468 */
469 for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {
470 count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?
471 IGC_EERD_EEWR_MAX_COUNT : (words - i);
472 if (hw->nvm.ops.acquire(hw) == IGC_SUCCESS) {
473 status = igc_read_nvm_eerd(hw, offset, count,
474 data + i);
475 hw->nvm.ops.release(hw);
476 } else {
477 status = IGC_ERR_SWFW_SYNC;
478 }
479
480 if (status != IGC_SUCCESS)
481 break;
482 }
483
484 return status;
485 }
486
487 /* igc_write_nvm_srwr_i225 - Write to Shadow RAM using EEWR
488 * @hw: pointer to the HW structure
489 * @offset: offset within the Shadow RAM to be written to
490 * @words: number of words to write
491 * @data: 16 bit word(s) to be written to the Shadow RAM
492 *
493 * Writes data to Shadow RAM at offset using EEWR register.
494 *
495 * If igc_update_nvm_checksum is not called after this function , the
496 * data will not be committed to FLASH and also Shadow RAM will most likely
497 * contain an invalid checksum.
498 *
499 * If error code is returned, data and Shadow RAM may be inconsistent - buffer
500 * partially written.
501 */
igc_write_nvm_srwr_i225(struct igc_hw * hw,u16 offset,u16 words,u16 * data)502 s32 igc_write_nvm_srwr_i225(struct igc_hw *hw, u16 offset, u16 words,
503 u16 *data)
504 {
505 s32 status = IGC_SUCCESS;
506 u16 i, count;
507
508 DEBUGFUNC("igc_write_nvm_srwr_i225");
509
510 /* We cannot hold synchronization semaphores for too long,
511 * because of forceful takeover procedure. However it is more efficient
512 * to write in bursts than synchronizing access for each word.
513 */
514 for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {
515 count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?
516 IGC_EERD_EEWR_MAX_COUNT : (words - i);
517 if (hw->nvm.ops.acquire(hw) == IGC_SUCCESS) {
518 status = __igc_write_nvm_srwr(hw, offset, count,
519 data + i);
520 hw->nvm.ops.release(hw);
521 } else {
522 status = IGC_ERR_SWFW_SYNC;
523 }
524
525 if (status != IGC_SUCCESS)
526 break;
527 }
528
529 return status;
530 }
531
532 /* __igc_write_nvm_srwr - Write to Shadow Ram using EEWR
533 * @hw: pointer to the HW structure
534 * @offset: offset within the Shadow Ram to be written to
535 * @words: number of words to write
536 * @data: 16 bit word(s) to be written to the Shadow Ram
537 *
538 * Writes data to Shadow Ram at offset using EEWR register.
539 *
540 * If igc_update_nvm_checksum is not called after this function , the
541 * Shadow Ram will most likely contain an invalid checksum.
542 */
__igc_write_nvm_srwr(struct igc_hw * hw,u16 offset,u16 words,u16 * data)543 static s32 __igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words,
544 u16 *data)
545 {
546 struct igc_nvm_info *nvm = &hw->nvm;
547 u32 i, k, eewr = 0;
548 u32 attempts = 100000;
549 s32 ret_val = IGC_SUCCESS;
550
551 DEBUGFUNC("__igc_write_nvm_srwr");
552
553 /* A check for invalid values: offset too large, too many words,
554 * too many words for the offset, and not enough words.
555 */
556 if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
557 (words == 0)) {
558 DEBUGOUT("nvm parameter(s) out of bounds\n");
559 ret_val = -IGC_ERR_NVM;
560 goto out;
561 }
562
563 for (i = 0; i < words; i++) {
564 eewr = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) |
565 (data[i] << IGC_NVM_RW_REG_DATA) |
566 IGC_NVM_RW_REG_START;
567
568 IGC_WRITE_REG(hw, IGC_SRWR, eewr);
569
570 for (k = 0; k < attempts; k++) {
571 if (IGC_NVM_RW_REG_DONE &
572 IGC_READ_REG(hw, IGC_SRWR)) {
573 ret_val = IGC_SUCCESS;
574 break;
575 }
576 usec_delay(5);
577 }
578
579 if (ret_val != IGC_SUCCESS) {
580 DEBUGOUT("Shadow RAM write EEWR timed out\n");
581 break;
582 }
583 }
584
585 out:
586 return ret_val;
587 }
588
589 /* igc_validate_nvm_checksum_i225 - Validate EEPROM checksum
590 * @hw: pointer to the HW structure
591 *
592 * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
593 * and then verifies that the sum of the EEPROM is equal to 0xBABA.
594 */
igc_validate_nvm_checksum_i225(struct igc_hw * hw)595 s32 igc_validate_nvm_checksum_i225(struct igc_hw *hw)
596 {
597 s32 status = IGC_SUCCESS;
598 s32 (*read_op_ptr)(struct igc_hw *, u16, u16, u16 *);
599
600 DEBUGFUNC("igc_validate_nvm_checksum_i225");
601
602 if (hw->nvm.ops.acquire(hw) == IGC_SUCCESS) {
603 /* Replace the read function with semaphore grabbing with
604 * the one that skips this for a while.
605 * We have semaphore taken already here.
606 */
607 read_op_ptr = hw->nvm.ops.read;
608 hw->nvm.ops.read = igc_read_nvm_eerd;
609
610 status = igc_validate_nvm_checksum_generic(hw);
611
612 /* Revert original read operation. */
613 hw->nvm.ops.read = read_op_ptr;
614
615 hw->nvm.ops.release(hw);
616 } else {
617 status = IGC_ERR_SWFW_SYNC;
618 }
619
620 return status;
621 }
622
623 /* igc_update_nvm_checksum_i225 - Update EEPROM checksum
624 * @hw: pointer to the HW structure
625 *
626 * Updates the EEPROM checksum by reading/adding each word of the EEPROM
627 * up to the checksum. Then calculates the EEPROM checksum and writes the
628 * value to the EEPROM. Next commit EEPROM data onto the Flash.
629 */
igc_update_nvm_checksum_i225(struct igc_hw * hw)630 s32 igc_update_nvm_checksum_i225(struct igc_hw *hw)
631 {
632 s32 ret_val;
633 u16 checksum = 0;
634 u16 i, nvm_data;
635
636 DEBUGFUNC("igc_update_nvm_checksum_i225");
637
638 /* Read the first word from the EEPROM. If this times out or fails, do
639 * not continue or we could be in for a very long wait while every
640 * EEPROM read fails
641 */
642 ret_val = igc_read_nvm_eerd(hw, 0, 1, &nvm_data);
643 if (ret_val != IGC_SUCCESS) {
644 DEBUGOUT("EEPROM read failed\n");
645 goto out;
646 }
647
648 if (hw->nvm.ops.acquire(hw) == IGC_SUCCESS) {
649 /* Do not use hw->nvm.ops.write, hw->nvm.ops.read
650 * because we do not want to take the synchronization
651 * semaphores twice here.
652 */
653
654 for (i = 0; i < NVM_CHECKSUM_REG; i++) {
655 ret_val = igc_read_nvm_eerd(hw, i, 1, &nvm_data);
656 if (ret_val) {
657 hw->nvm.ops.release(hw);
658 DEBUGOUT("NVM Read Error while updating\n");
659 DEBUGOUT("checksum.\n");
660 goto out;
661 }
662 checksum += nvm_data;
663 }
664 checksum = (u16)NVM_SUM - checksum;
665 ret_val = __igc_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1,
666 &checksum);
667 if (ret_val != IGC_SUCCESS) {
668 hw->nvm.ops.release(hw);
669 DEBUGOUT("NVM Write Error while updating checksum.\n");
670 goto out;
671 }
672
673 hw->nvm.ops.release(hw);
674
675 ret_val = igc_update_flash_i225(hw);
676 } else {
677 ret_val = IGC_ERR_SWFW_SYNC;
678 }
679 out:
680 return ret_val;
681 }
682
683 /* igc_get_flash_presence_i225 - Check if flash device is detected.
684 * @hw: pointer to the HW structure
685 */
igc_get_flash_presence_i225(struct igc_hw * hw)686 bool igc_get_flash_presence_i225(struct igc_hw *hw)
687 {
688 u32 eec = 0;
689 bool ret_val = false;
690
691 DEBUGFUNC("igc_get_flash_presence_i225");
692
693 eec = IGC_READ_REG(hw, IGC_EECD);
694
695 if (eec & IGC_EECD_FLASH_DETECTED_I225)
696 ret_val = true;
697
698 return ret_val;
699 }
700
701 /* igc_set_flsw_flash_burst_counter_i225 - sets FLSW NVM Burst
702 * Counter in FLSWCNT register.
703 *
704 * @hw: pointer to the HW structure
705 * @burst_counter: size in bytes of the Flash burst to read or write
706 */
igc_set_flsw_flash_burst_counter_i225(struct igc_hw * hw,u32 burst_counter)707 s32 igc_set_flsw_flash_burst_counter_i225(struct igc_hw *hw,
708 u32 burst_counter)
709 {
710 s32 ret_val = IGC_SUCCESS;
711
712 DEBUGFUNC("igc_set_flsw_flash_burst_counter_i225");
713
714 /* Validate input data */
715 if (burst_counter < IGC_I225_SHADOW_RAM_SIZE) {
716 /* Write FLSWCNT - burst counter */
717 IGC_WRITE_REG(hw, IGC_I225_FLSWCNT, burst_counter);
718 } else {
719 ret_val = IGC_ERR_INVALID_ARGUMENT;
720 }
721
722 return ret_val;
723 }
724
725 /* igc_write_erase_flash_command_i225 - write/erase to a sector
726 * region on a given address.
727 *
728 * @hw: pointer to the HW structure
729 * @opcode: opcode to be used for the write command
730 * @address: the offset to write into the FLASH image
731 */
igc_write_erase_flash_command_i225(struct igc_hw * hw,u32 opcode,u32 address)732 s32 igc_write_erase_flash_command_i225(struct igc_hw *hw, u32 opcode,
733 u32 address)
734 {
735 u32 flswctl = 0;
736 s32 timeout = IGC_NVM_GRANT_ATTEMPTS;
737 s32 ret_val = IGC_SUCCESS;
738
739 DEBUGFUNC("igc_write_erase_flash_command_i225");
740
741 flswctl = IGC_READ_REG(hw, IGC_I225_FLSWCTL);
742 /* Polling done bit on FLSWCTL register */
743 while (timeout) {
744 if (flswctl & IGC_FLSWCTL_DONE)
745 break;
746 usec_delay(5);
747 flswctl = IGC_READ_REG(hw, IGC_I225_FLSWCTL);
748 timeout--;
749 }
750
751 if (!timeout) {
752 DEBUGOUT("Flash transaction was not done\n");
753 return -IGC_ERR_NVM;
754 }
755
756 /* Build and issue command on FLSWCTL register */
757 flswctl = address | opcode;
758 IGC_WRITE_REG(hw, IGC_I225_FLSWCTL, flswctl);
759
760 /* Check if issued command is valid on FLSWCTL register */
761 flswctl = IGC_READ_REG(hw, IGC_I225_FLSWCTL);
762 if (!(flswctl & IGC_FLSWCTL_CMDV)) {
763 DEBUGOUT("Write flash command failed\n");
764 ret_val = IGC_ERR_INVALID_ARGUMENT;
765 }
766
767 return ret_val;
768 }
769
770 /* igc_update_flash_i225 - Commit EEPROM to the flash
771 * if fw_valid_bit is set, FW is active. setting FLUPD bit in EEC
772 * register makes the FW load the internal shadow RAM into the flash.
773 * Otherwise, fw_valid_bit is 0. if FL_SECU.block_prtotected_sw = 0
774 * then FW is not active so the SW is responsible shadow RAM dump.
775 *
776 * @hw: pointer to the HW structure
777 */
igc_update_flash_i225(struct igc_hw * hw)778 s32 igc_update_flash_i225(struct igc_hw *hw)
779 {
780 u16 current_offset_data = 0;
781 u32 block_sw_protect = 1;
782 u16 base_address = 0x0;
783 u32 i, fw_valid_bit;
784 u16 current_offset;
785 s32 ret_val = 0;
786 u32 flup;
787
788 DEBUGFUNC("igc_update_flash_i225");
789
790 block_sw_protect = IGC_READ_REG(hw, IGC_I225_FLSECU) &
791 IGC_FLSECU_BLK_SW_ACCESS_I225;
792 fw_valid_bit = IGC_READ_REG(hw, IGC_FWSM) &
793 IGC_FWSM_FW_VALID_I225;
794 if (fw_valid_bit) {
795 ret_val = igc_pool_flash_update_done_i225(hw);
796 if (ret_val == -IGC_ERR_NVM) {
797 DEBUGOUT("Flash update time out\n");
798 goto out;
799 }
800
801 flup = IGC_READ_REG(hw, IGC_EECD) | IGC_EECD_FLUPD_I225;
802 IGC_WRITE_REG(hw, IGC_EECD, flup);
803
804 ret_val = igc_pool_flash_update_done_i225(hw);
805 if (ret_val == IGC_SUCCESS)
806 DEBUGOUT("Flash update complete\n");
807 else
808 DEBUGOUT("Flash update time out\n");
809 } else if (!block_sw_protect) {
810 /* FW is not active and security protection is disabled.
811 * therefore, SW is in charge of shadow RAM dump.
812 * Check which sector is valid. if sector 0 is valid,
813 * base address remains 0x0. otherwise, sector 1 is
814 * valid and it's base address is 0x1000
815 */
816 if (IGC_READ_REG(hw, IGC_EECD) & IGC_EECD_SEC1VAL_I225)
817 base_address = 0x1000;
818
819 /* Valid sector erase */
820 ret_val = igc_write_erase_flash_command_i225(hw,
821 IGC_I225_ERASE_CMD_OPCODE,
822 base_address);
823 if (!ret_val) {
824 DEBUGOUT("Sector erase failed\n");
825 goto out;
826 }
827
828 current_offset = base_address;
829
830 /* Write */
831 for (i = 0; i < IGC_I225_SHADOW_RAM_SIZE / 2; i++) {
832 /* Set burst write length */
833 ret_val = igc_set_flsw_flash_burst_counter_i225(hw,
834 0x2);
835 if (ret_val != IGC_SUCCESS)
836 break;
837
838 /* Set address and opcode */
839 ret_val = igc_write_erase_flash_command_i225(hw,
840 IGC_I225_WRITE_CMD_OPCODE,
841 2 * current_offset);
842 if (ret_val != IGC_SUCCESS)
843 break;
844
845 ret_val = igc_read_nvm_eerd(hw, current_offset,
846 1, ¤t_offset_data);
847 if (ret_val) {
848 DEBUGOUT("Failed to read from EEPROM\n");
849 goto out;
850 }
851
852 /* Write CurrentOffseData to FLSWDATA register */
853 IGC_WRITE_REG(hw, IGC_I225_FLSWDATA,
854 current_offset_data);
855 current_offset++;
856
857 /* Wait till operation has finished */
858 ret_val = igc_poll_eerd_eewr_done(hw,
859 IGC_NVM_POLL_READ);
860 if (ret_val)
861 break;
862
863 usec_delay(1000);
864 }
865 }
866 out:
867 return ret_val;
868 }
869
870 /* igc_pool_flash_update_done_i225 - Pool FLUDONE status.
871 * @hw: pointer to the HW structure
872 */
igc_pool_flash_update_done_i225(struct igc_hw * hw)873 s32 igc_pool_flash_update_done_i225(struct igc_hw *hw)
874 {
875 s32 ret_val = -IGC_ERR_NVM;
876 u32 i, reg;
877
878 DEBUGFUNC("igc_pool_flash_update_done_i225");
879
880 for (i = 0; i < IGC_FLUDONE_ATTEMPTS; i++) {
881 reg = IGC_READ_REG(hw, IGC_EECD);
882 if (reg & IGC_EECD_FLUDONE_I225) {
883 ret_val = IGC_SUCCESS;
884 break;
885 }
886 usec_delay(5);
887 }
888
889 return ret_val;
890 }
891
892 /* igc_set_ltr_i225 - Set Latency Tolerance Reporting thresholds.
893 * @hw: pointer to the HW structure
894 * @link: bool indicating link status
895 *
896 * Set the LTR thresholds based on the link speed (Mbps), EEE, and DMAC
897 * settings, otherwise specify that there is no LTR requirement.
898 */
igc_set_ltr_i225(struct igc_hw * hw,bool link)899 static s32 igc_set_ltr_i225(struct igc_hw *hw, bool link)
900 {
901 u16 speed, duplex;
902 u32 tw_system, ltrc, ltrv, ltr_min, ltr_max, scale_min, scale_max;
903 s32 size;
904
905 DEBUGFUNC("igc_set_ltr_i225");
906
907 /* If we do not have link, LTR thresholds are zero. */
908 if (link) {
909 hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
910
911 /* Check if using copper interface with EEE enabled or if the
912 * link speed is 10 Mbps.
913 */
914 if ((hw->phy.media_type == igc_media_type_copper) &&
915 !(hw->dev_spec._i225.eee_disable) &&
916 (speed != SPEED_10)) {
917 /* EEE enabled, so send LTRMAX threshold. */
918 ltrc = IGC_READ_REG(hw, IGC_LTRC) |
919 IGC_LTRC_EEEMS_EN;
920 IGC_WRITE_REG(hw, IGC_LTRC, ltrc);
921
922 /* Calculate tw_system (nsec). */
923 if (speed == SPEED_100) {
924 tw_system = ((IGC_READ_REG(hw, IGC_EEE_SU) &
925 IGC_TW_SYSTEM_100_MASK) >>
926 IGC_TW_SYSTEM_100_SHIFT) * 500;
927 } else {
928 tw_system = (IGC_READ_REG(hw, IGC_EEE_SU) &
929 IGC_TW_SYSTEM_1000_MASK) * 500;
930 }
931 } else {
932 tw_system = 0;
933 }
934
935 /* Get the Rx packet buffer size. */
936 size = IGC_READ_REG(hw, IGC_RXPBS) &
937 IGC_RXPBS_SIZE_I225_MASK;
938
939 /* Calculations vary based on DMAC settings. */
940 if (IGC_READ_REG(hw, IGC_DMACR) & IGC_DMACR_DMAC_EN) {
941 size -= (IGC_READ_REG(hw, IGC_DMACR) &
942 IGC_DMACR_DMACTHR_MASK) >>
943 IGC_DMACR_DMACTHR_SHIFT;
944 /* Convert size to bits. */
945 size *= 1024 * 8;
946 } else {
947 /* Convert size to bytes, subtract the MTU, and then
948 * convert the size to bits.
949 */
950 size *= 1024;
951 size -= hw->dev_spec._i225.mtu;
952 size *= 8;
953 }
954
955 if (size < 0) {
956 DEBUGOUT1("Invalid effective Rx buffer size %d\n",
957 size);
958 return -IGC_ERR_CONFIG;
959 }
960
961 /* Calculate the thresholds. Since speed is in Mbps, simplify
962 * the calculation by multiplying size/speed by 1000 for result
963 * to be in nsec before dividing by the scale in nsec. Set the
964 * scale such that the LTR threshold fits in the register.
965 */
966 ltr_min = (1000 * size) / speed;
967 ltr_max = ltr_min + tw_system;
968 scale_min = (ltr_min / 1024) < 1024 ? IGC_LTRMINV_SCALE_1024 :
969 IGC_LTRMINV_SCALE_32768;
970 scale_max = (ltr_max / 1024) < 1024 ? IGC_LTRMAXV_SCALE_1024 :
971 IGC_LTRMAXV_SCALE_32768;
972 ltr_min /= scale_min == IGC_LTRMINV_SCALE_1024 ? 1024 : 32768;
973 ltr_max /= scale_max == IGC_LTRMAXV_SCALE_1024 ? 1024 : 32768;
974
975 /* Only write the LTR thresholds if they differ from before. */
976 ltrv = IGC_READ_REG(hw, IGC_LTRMINV);
977 if (ltr_min != (ltrv & IGC_LTRMINV_LTRV_MASK)) {
978 ltrv = IGC_LTRMINV_LSNP_REQ | ltr_min |
979 (scale_min << IGC_LTRMINV_SCALE_SHIFT);
980 IGC_WRITE_REG(hw, IGC_LTRMINV, ltrv);
981 }
982
983 ltrv = IGC_READ_REG(hw, IGC_LTRMAXV);
984 if (ltr_max != (ltrv & IGC_LTRMAXV_LTRV_MASK)) {
985 ltrv = IGC_LTRMAXV_LSNP_REQ | ltr_max |
986 (scale_min << IGC_LTRMAXV_SCALE_SHIFT);
987 IGC_WRITE_REG(hw, IGC_LTRMAXV, ltrv);
988 }
989 }
990
991 return IGC_SUCCESS;
992 }
993
994 /* igc_check_for_link_i225 - Check for link
995 * @hw: pointer to the HW structure
996 *
997 * Checks to see of the link status of the hardware has changed. If a
998 * change in link status has been detected, then we read the PHY registers
999 * to get the current speed/duplex if link exists.
1000 */
igc_check_for_link_i225(struct igc_hw * hw)1001 s32 igc_check_for_link_i225(struct igc_hw *hw)
1002 {
1003 struct igc_mac_info *mac = &hw->mac;
1004 s32 ret_val;
1005 bool link = false;
1006
1007 DEBUGFUNC("igc_check_for_link_i225");
1008
1009 /* We only want to go out to the PHY registers to see if
1010 * Auto-Neg has completed and/or if our link status has
1011 * changed. The get_link_status flag is set upon receiving
1012 * a Link Status Change or Rx Sequence Error interrupt.
1013 */
1014 if (!mac->get_link_status) {
1015 ret_val = IGC_SUCCESS;
1016 goto out;
1017 }
1018
1019 /* First we want to see if the MII Status Register reports
1020 * link. If so, then we want to get the current speed/duplex
1021 * of the PHY.
1022 */
1023 ret_val = igc_phy_has_link_generic(hw, 1, 0, &link);
1024 if (ret_val)
1025 goto out;
1026
1027 if (!link)
1028 goto out; /* No link detected */
1029
1030 /* First we want to see if the MII Status Register reports
1031 * link. If so, then we want to get the current speed/duplex
1032 * of the PHY.
1033 */
1034 ret_val = igc_phy_has_link_generic(hw, 1, 0, &link);
1035 if (ret_val)
1036 goto out;
1037
1038 if (!link)
1039 goto out; /* No link detected */
1040
1041 mac->get_link_status = false;
1042
1043 /* Check if there was DownShift, must be checked
1044 * immediately after link-up
1045 */
1046 igc_check_downshift_generic(hw);
1047
1048 /* If we are forcing speed/duplex, then we simply return since
1049 * we have already determined whether we have link or not.
1050 */
1051 if (!mac->autoneg)
1052 goto out;
1053
1054 /* Auto-Neg is enabled. Auto Speed Detection takes care
1055 * of MAC speed/duplex configuration. So we only need to
1056 * configure Collision Distance in the MAC.
1057 */
1058 mac->ops.config_collision_dist(hw);
1059
1060 /* Configure Flow Control now that Auto-Neg has completed.
1061 * First, we need to restore the desired flow control
1062 * settings because we may have had to re-autoneg with a
1063 * different link partner.
1064 */
1065 ret_val = igc_config_fc_after_link_up_generic(hw);
1066 if (ret_val)
1067 DEBUGOUT("Error configuring flow control\n");
1068 out:
1069 /* Now that we are aware of our link settings, we can set the LTR
1070 * thresholds.
1071 */
1072 ret_val = igc_set_ltr_i225(hw, link);
1073
1074 return ret_val;
1075 }
1076
1077 /* igc_init_function_pointers_i225 - Init func ptrs.
1078 * @hw: pointer to the HW structure
1079 *
1080 * Called to initialize all function pointers and parameters.
1081 */
igc_init_function_pointers_i225(struct igc_hw * hw)1082 void igc_init_function_pointers_i225(struct igc_hw *hw)
1083 {
1084 igc_init_mac_ops_generic(hw);
1085 igc_init_phy_ops_generic(hw);
1086 igc_init_nvm_ops_generic(hw);
1087 hw->mac.ops.init_params = igc_init_mac_params_i225;
1088 hw->nvm.ops.init_params = igc_init_nvm_params_i225;
1089 hw->phy.ops.init_params = igc_init_phy_params_i225;
1090 }
1091
1092 /* igc_init_hw_i225 - Init hw for I225
1093 * @hw: pointer to the HW structure
1094 *
1095 * Called to initialize hw for i225 hw family.
1096 */
igc_init_hw_i225(struct igc_hw * hw)1097 s32 igc_init_hw_i225(struct igc_hw *hw)
1098 {
1099 s32 ret_val;
1100
1101 DEBUGFUNC("igc_init_hw_i225");
1102
1103 ret_val = igc_init_hw_base(hw);
1104 return ret_val;
1105 }
1106
1107 /*
1108 * igc_set_d0_lplu_state_i225 - Set Low-Power-Link-Up (LPLU) D0 state
1109 * @hw: pointer to the HW structure
1110 * @active: true to enable LPLU, false to disable
1111 *
1112 * Note: since I225 does not actually support LPLU, this function
1113 * simply enables/disables 1G and 2.5G speeds in D0.
1114 */
igc_set_d0_lplu_state_i225(struct igc_hw * hw,bool active)1115 s32 igc_set_d0_lplu_state_i225(struct igc_hw *hw, bool active)
1116 {
1117 u32 data;
1118
1119 DEBUGFUNC("igc_set_d0_lplu_state_i225");
1120
1121 data = IGC_READ_REG(hw, IGC_I225_PHPM);
1122
1123 if (active) {
1124 data |= IGC_I225_PHPM_DIS_1000;
1125 data |= IGC_I225_PHPM_DIS_2500;
1126 } else {
1127 data &= ~IGC_I225_PHPM_DIS_1000;
1128 data &= ~IGC_I225_PHPM_DIS_2500;
1129 }
1130
1131 IGC_WRITE_REG(hw, IGC_I225_PHPM, data);
1132 return IGC_SUCCESS;
1133 }
1134
1135 /*
1136 * igc_set_d3_lplu_state_i225 - Set Low-Power-Link-Up (LPLU) D3 state
1137 * @hw: pointer to the HW structure
1138 * @active: true to enable LPLU, false to disable
1139 *
1140 * Note: since I225 does not actually support LPLU, this function
1141 * simply enables/disables 100M, 1G and 2.5G speeds in D3.
1142 */
igc_set_d3_lplu_state_i225(struct igc_hw * hw,bool active)1143 s32 igc_set_d3_lplu_state_i225(struct igc_hw *hw, bool active)
1144 {
1145 u32 data;
1146
1147 DEBUGFUNC("igc_set_d3_lplu_state_i225");
1148
1149 data = IGC_READ_REG(hw, IGC_I225_PHPM);
1150
1151 if (active) {
1152 data |= IGC_I225_PHPM_DIS_100_D3;
1153 data |= IGC_I225_PHPM_DIS_1000_D3;
1154 data |= IGC_I225_PHPM_DIS_2500_D3;
1155 } else {
1156 data &= ~IGC_I225_PHPM_DIS_100_D3;
1157 data &= ~IGC_I225_PHPM_DIS_1000_D3;
1158 data &= ~IGC_I225_PHPM_DIS_2500_D3;
1159 }
1160
1161 IGC_WRITE_REG(hw, IGC_I225_PHPM, data);
1162 return IGC_SUCCESS;
1163 }
1164
1165 /**
1166 * igc_set_eee_i225 - Enable/disable EEE support
1167 * @hw: pointer to the HW structure
1168 * @adv2p5G: boolean flag enabling 2.5G EEE advertisement
1169 * @adv1G: boolean flag enabling 1G EEE advertisement
1170 * @adv100M: boolean flag enabling 100M EEE advertisement
1171 *
1172 * Enable/disable EEE based on setting in dev_spec structure.
1173 *
1174 **/
igc_set_eee_i225(struct igc_hw * hw,bool adv2p5G,bool adv1G,bool adv100M)1175 s32 igc_set_eee_i225(struct igc_hw *hw, bool adv2p5G, bool adv1G,
1176 bool adv100M)
1177 {
1178 u32 ipcnfg, eeer;
1179
1180 DEBUGFUNC("igc_set_eee_i225");
1181
1182 if (hw->mac.type != igc_i225 ||
1183 hw->phy.media_type != igc_media_type_copper)
1184 goto out;
1185 ipcnfg = IGC_READ_REG(hw, IGC_IPCNFG);
1186 eeer = IGC_READ_REG(hw, IGC_EEER);
1187
1188 /* enable or disable per user setting */
1189 if (!(hw->dev_spec._i225.eee_disable)) {
1190 u32 eee_su = IGC_READ_REG(hw, IGC_EEE_SU);
1191
1192 if (adv100M)
1193 ipcnfg |= IGC_IPCNFG_EEE_100M_AN;
1194 else
1195 ipcnfg &= ~IGC_IPCNFG_EEE_100M_AN;
1196
1197 if (adv1G)
1198 ipcnfg |= IGC_IPCNFG_EEE_1G_AN;
1199 else
1200 ipcnfg &= ~IGC_IPCNFG_EEE_1G_AN;
1201
1202 if (adv2p5G)
1203 ipcnfg |= IGC_IPCNFG_EEE_2_5G_AN;
1204 else
1205 ipcnfg &= ~IGC_IPCNFG_EEE_2_5G_AN;
1206
1207 eeer |= (IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN |
1208 IGC_EEER_LPI_FC);
1209
1210 /* This bit should not be set in normal operation. */
1211 if (eee_su & IGC_EEE_SU_LPI_CLK_STP)
1212 DEBUGOUT("LPI Clock Stop Bit should not be set!\n");
1213 } else {
1214 ipcnfg &= ~(IGC_IPCNFG_EEE_2_5G_AN | IGC_IPCNFG_EEE_1G_AN |
1215 IGC_IPCNFG_EEE_100M_AN);
1216 eeer &= ~(IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN |
1217 IGC_EEER_LPI_FC);
1218 }
1219 IGC_WRITE_REG(hw, IGC_IPCNFG, ipcnfg);
1220 IGC_WRITE_REG(hw, IGC_EEER, eeer);
1221 IGC_READ_REG(hw, IGC_IPCNFG);
1222 IGC_READ_REG(hw, IGC_EEER);
1223 out:
1224
1225 return IGC_SUCCESS;
1226 }
1227
1228