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