xref: /freebsd/sys/dev/e1000/e1000_ich8lan.c (revision c80429cedb277ccc9626c28a7cf8fafc5a265ff6)
18cfa0ad2SJack F Vogel /******************************************************************************
28cfa0ad2SJack F Vogel 
37c669ab6SSean Bruno   Copyright (c) 2001-2015, Intel Corporation
48cfa0ad2SJack F Vogel   All rights reserved.
58cfa0ad2SJack F Vogel 
68cfa0ad2SJack F Vogel   Redistribution and use in source and binary forms, with or without
78cfa0ad2SJack F Vogel   modification, are permitted provided that the following conditions are met:
88cfa0ad2SJack F Vogel 
98cfa0ad2SJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
108cfa0ad2SJack F Vogel       this list of conditions and the following disclaimer.
118cfa0ad2SJack F Vogel 
128cfa0ad2SJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
138cfa0ad2SJack F Vogel       notice, this list of conditions and the following disclaimer in the
148cfa0ad2SJack F Vogel       documentation and/or other materials provided with the distribution.
158cfa0ad2SJack F Vogel 
168cfa0ad2SJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
178cfa0ad2SJack F Vogel       contributors may be used to endorse or promote products derived from
188cfa0ad2SJack F Vogel       this software without specific prior written permission.
198cfa0ad2SJack F Vogel 
208cfa0ad2SJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
218cfa0ad2SJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
228cfa0ad2SJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
238cfa0ad2SJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
248cfa0ad2SJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
258cfa0ad2SJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
268cfa0ad2SJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
278cfa0ad2SJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
288cfa0ad2SJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
298cfa0ad2SJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
308cfa0ad2SJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
318cfa0ad2SJack F Vogel 
328cfa0ad2SJack F Vogel ******************************************************************************/
338cfa0ad2SJack F Vogel /*$FreeBSD$*/
348cfa0ad2SJack F Vogel 
356ab6bfe3SJack F Vogel /* 82562G 10/100 Network Connection
36daf9197cSJack F Vogel  * 82562G-2 10/100 Network Connection
37daf9197cSJack F Vogel  * 82562GT 10/100 Network Connection
38daf9197cSJack F Vogel  * 82562GT-2 10/100 Network Connection
39daf9197cSJack F Vogel  * 82562V 10/100 Network Connection
40daf9197cSJack F Vogel  * 82562V-2 10/100 Network Connection
41daf9197cSJack F Vogel  * 82566DC-2 Gigabit Network Connection
42daf9197cSJack F Vogel  * 82566DC Gigabit Network Connection
43daf9197cSJack F Vogel  * 82566DM-2 Gigabit Network Connection
44daf9197cSJack F Vogel  * 82566DM Gigabit Network Connection
45daf9197cSJack F Vogel  * 82566MC Gigabit Network Connection
46daf9197cSJack F Vogel  * 82566MM Gigabit Network Connection
47daf9197cSJack F Vogel  * 82567LM Gigabit Network Connection
48daf9197cSJack F Vogel  * 82567LF Gigabit Network Connection
49daf9197cSJack F Vogel  * 82567V Gigabit Network Connection
50daf9197cSJack F Vogel  * 82567LM-2 Gigabit Network Connection
51daf9197cSJack F Vogel  * 82567LF-2 Gigabit Network Connection
52daf9197cSJack F Vogel  * 82567V-2 Gigabit Network Connection
53daf9197cSJack F Vogel  * 82567LF-3 Gigabit Network Connection
54daf9197cSJack F Vogel  * 82567LM-3 Gigabit Network Connection
55daf9197cSJack F Vogel  * 82567LM-4 Gigabit Network Connection
569d81738fSJack F Vogel  * 82577LM Gigabit Network Connection
579d81738fSJack F Vogel  * 82577LC Gigabit Network Connection
589d81738fSJack F Vogel  * 82578DM Gigabit Network Connection
599d81738fSJack F Vogel  * 82578DC Gigabit Network Connection
607d9119bdSJack F Vogel  * 82579LM Gigabit Network Connection
617d9119bdSJack F Vogel  * 82579V Gigabit Network Connection
627609433eSJack F Vogel  * Ethernet Connection I217-LM
637609433eSJack F Vogel  * Ethernet Connection I217-V
647609433eSJack F Vogel  * Ethernet Connection I218-V
657609433eSJack F Vogel  * Ethernet Connection I218-LM
668cc64f1eSJack F Vogel  * Ethernet Connection (2) I218-LM
678cc64f1eSJack F Vogel  * Ethernet Connection (2) I218-V
688cc64f1eSJack F Vogel  * Ethernet Connection (3) I218-LM
698cc64f1eSJack F Vogel  * Ethernet Connection (3) I218-V
708cfa0ad2SJack F Vogel  */
718cfa0ad2SJack F Vogel 
728cfa0ad2SJack F Vogel #include "e1000_api.h"
738cfa0ad2SJack F Vogel 
748cfa0ad2SJack F Vogel static s32  e1000_acquire_swflag_ich8lan(struct e1000_hw *hw);
758cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw);
764edd8523SJack F Vogel static s32  e1000_acquire_nvm_ich8lan(struct e1000_hw *hw);
774edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw);
788cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
797d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
808cc64f1eSJack F Vogel static int  e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index);
818cc64f1eSJack F Vogel static int  e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index);
827609433eSJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw);
83730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw,
84730d3130SJack F Vogel 					      u8 *mc_addr_list,
85730d3130SJack F Vogel 					      u32 mc_addr_count);
868cfa0ad2SJack F Vogel static s32  e1000_check_reset_block_ich8lan(struct e1000_hw *hw);
878cfa0ad2SJack F Vogel static s32  e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw);
884edd8523SJack F Vogel static s32  e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active);
898cfa0ad2SJack F Vogel static s32  e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
908cfa0ad2SJack F Vogel 					    bool active);
918cfa0ad2SJack F Vogel static s32  e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
928cfa0ad2SJack F Vogel 					    bool active);
938cfa0ad2SJack F Vogel static s32  e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
948cfa0ad2SJack F Vogel 				   u16 words, u16 *data);
95*c80429ceSEric Joyner static s32  e1000_read_nvm_spt(struct e1000_hw *hw, u16 offset, u16 words,
96*c80429ceSEric Joyner 			       u16 *data);
978cfa0ad2SJack F Vogel static s32  e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
988cfa0ad2SJack F Vogel 				    u16 words, u16 *data);
998cfa0ad2SJack F Vogel static s32  e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw);
1008cfa0ad2SJack F Vogel static s32  e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
101*c80429ceSEric Joyner static s32  e1000_update_nvm_checksum_spt(struct e1000_hw *hw);
1028cfa0ad2SJack F Vogel static s32  e1000_valid_led_default_ich8lan(struct e1000_hw *hw,
1038cfa0ad2SJack F Vogel 					    u16 *data);
1049d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw);
1058cfa0ad2SJack F Vogel static s32  e1000_get_bus_info_ich8lan(struct e1000_hw *hw);
1068cfa0ad2SJack F Vogel static s32  e1000_reset_hw_ich8lan(struct e1000_hw *hw);
1078cfa0ad2SJack F Vogel static s32  e1000_init_hw_ich8lan(struct e1000_hw *hw);
1088cfa0ad2SJack F Vogel static s32  e1000_setup_link_ich8lan(struct e1000_hw *hw);
1098cfa0ad2SJack F Vogel static s32  e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
1106ab6bfe3SJack F Vogel static s32  e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw);
1118cfa0ad2SJack F Vogel static s32  e1000_get_link_up_info_ich8lan(struct e1000_hw *hw,
1128cfa0ad2SJack F Vogel 					   u16 *speed, u16 *duplex);
1138cfa0ad2SJack F Vogel static s32  e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
1148cfa0ad2SJack F Vogel static s32  e1000_led_on_ich8lan(struct e1000_hw *hw);
1158cfa0ad2SJack F Vogel static s32  e1000_led_off_ich8lan(struct e1000_hw *hw);
1164edd8523SJack F Vogel static s32  e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
1179d81738fSJack F Vogel static s32  e1000_setup_led_pchlan(struct e1000_hw *hw);
1189d81738fSJack F Vogel static s32  e1000_cleanup_led_pchlan(struct e1000_hw *hw);
1199d81738fSJack F Vogel static s32  e1000_led_on_pchlan(struct e1000_hw *hw);
1209d81738fSJack F Vogel static s32  e1000_led_off_pchlan(struct e1000_hw *hw);
1218cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
1228cfa0ad2SJack F Vogel static s32  e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
1238cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
1248cfa0ad2SJack F Vogel static s32  e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
1258cfa0ad2SJack F Vogel static s32  e1000_read_flash_byte_ich8lan(struct e1000_hw *hw,
1268cfa0ad2SJack F Vogel 					  u32 offset, u8 *data);
1278cfa0ad2SJack F Vogel static s32  e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
1288cfa0ad2SJack F Vogel 					  u8 size, u16 *data);
129*c80429ceSEric Joyner static s32  e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
130*c80429ceSEric Joyner 					    u32 *data);
131*c80429ceSEric Joyner static s32  e1000_read_flash_dword_ich8lan(struct e1000_hw *hw,
132*c80429ceSEric Joyner 					   u32 offset, u32 *data);
133*c80429ceSEric Joyner static s32  e1000_write_flash_data32_ich8lan(struct e1000_hw *hw,
134*c80429ceSEric Joyner 					     u32 offset, u32 data);
135*c80429ceSEric Joyner static s32  e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw,
136*c80429ceSEric Joyner 						  u32 offset, u32 dword);
1378cfa0ad2SJack F Vogel static s32  e1000_read_flash_word_ich8lan(struct e1000_hw *hw,
1388cfa0ad2SJack F Vogel 					  u32 offset, u16 *data);
1398cfa0ad2SJack F Vogel static s32  e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
1408cfa0ad2SJack F Vogel 						 u32 offset, u8 byte);
1418cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
1428cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
1434edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw);
144a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
1457d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw);
1467d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate);
147e373323fSSean Bruno static s32 e1000_set_obff_timer_pch_lpt(struct e1000_hw *hw, u32 itr);
1488cfa0ad2SJack F Vogel 
1498cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
1508cfa0ad2SJack F Vogel /* Offset 04h HSFSTS */
1518cfa0ad2SJack F Vogel union ich8_hws_flash_status {
1528cfa0ad2SJack F Vogel 	struct ich8_hsfsts {
1538cfa0ad2SJack F Vogel 		u16 flcdone:1; /* bit 0 Flash Cycle Done */
1548cfa0ad2SJack F Vogel 		u16 flcerr:1; /* bit 1 Flash Cycle Error */
1558cfa0ad2SJack F Vogel 		u16 dael:1; /* bit 2 Direct Access error Log */
1568cfa0ad2SJack F Vogel 		u16 berasesz:2; /* bit 4:3 Sector Erase Size */
1578cfa0ad2SJack F Vogel 		u16 flcinprog:1; /* bit 5 flash cycle in Progress */
1588cfa0ad2SJack F Vogel 		u16 reserved1:2; /* bit 13:6 Reserved */
1598cfa0ad2SJack F Vogel 		u16 reserved2:6; /* bit 13:6 Reserved */
1608cfa0ad2SJack F Vogel 		u16 fldesvalid:1; /* bit 14 Flash Descriptor Valid */
1618cfa0ad2SJack F Vogel 		u16 flockdn:1; /* bit 15 Flash Config Lock-Down */
1628cfa0ad2SJack F Vogel 	} hsf_status;
1638cfa0ad2SJack F Vogel 	u16 regval;
1648cfa0ad2SJack F Vogel };
1658cfa0ad2SJack F Vogel 
1668cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
1678cfa0ad2SJack F Vogel /* Offset 06h FLCTL */
1688cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl {
1698cfa0ad2SJack F Vogel 	struct ich8_hsflctl {
1708cfa0ad2SJack F Vogel 		u16 flcgo:1;   /* 0 Flash Cycle Go */
1718cfa0ad2SJack F Vogel 		u16 flcycle:2;   /* 2:1 Flash Cycle */
1728cfa0ad2SJack F Vogel 		u16 reserved:5;   /* 7:3 Reserved  */
1738cfa0ad2SJack F Vogel 		u16 fldbcount:2;   /* 9:8 Flash Data Byte Count */
1748cfa0ad2SJack F Vogel 		u16 flockdn:6;   /* 15:10 Reserved */
1758cfa0ad2SJack F Vogel 	} hsf_ctrl;
1768cfa0ad2SJack F Vogel 	u16 regval;
1778cfa0ad2SJack F Vogel };
1788cfa0ad2SJack F Vogel 
1798cfa0ad2SJack F Vogel /* ICH Flash Region Access Permissions */
1808cfa0ad2SJack F Vogel union ich8_hws_flash_regacc {
1818cfa0ad2SJack F Vogel 	struct ich8_flracc {
1828cfa0ad2SJack F Vogel 		u32 grra:8; /* 0:7 GbE region Read Access */
1838cfa0ad2SJack F Vogel 		u32 grwa:8; /* 8:15 GbE region Write Access */
1848cfa0ad2SJack F Vogel 		u32 gmrag:8; /* 23:16 GbE Master Read Access Grant */
1858cfa0ad2SJack F Vogel 		u32 gmwag:8; /* 31:24 GbE Master Write Access Grant */
1868cfa0ad2SJack F Vogel 	} hsf_flregacc;
1878cfa0ad2SJack F Vogel 	u16 regval;
1888cfa0ad2SJack F Vogel };
1898cfa0ad2SJack F Vogel 
1906ab6bfe3SJack F Vogel /**
1916ab6bfe3SJack F Vogel  *  e1000_phy_is_accessible_pchlan - Check if able to access PHY registers
1926ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
1936ab6bfe3SJack F Vogel  *
1946ab6bfe3SJack F Vogel  *  Test access to the PHY registers by reading the PHY ID registers.  If
1956ab6bfe3SJack F Vogel  *  the PHY ID is already known (e.g. resume path) compare it with known ID,
1966ab6bfe3SJack F Vogel  *  otherwise assume the read PHY ID is correct if it is valid.
1976ab6bfe3SJack F Vogel  *
1986ab6bfe3SJack F Vogel  *  Assumes the sw/fw/hw semaphore is already acquired.
1996ab6bfe3SJack F Vogel  **/
2006ab6bfe3SJack F Vogel static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
2014dab5c37SJack F Vogel {
2026ab6bfe3SJack F Vogel 	u16 phy_reg = 0;
2036ab6bfe3SJack F Vogel 	u32 phy_id = 0;
2047609433eSJack F Vogel 	s32 ret_val = 0;
2056ab6bfe3SJack F Vogel 	u16 retry_count;
2067609433eSJack F Vogel 	u32 mac_reg = 0;
2074dab5c37SJack F Vogel 
2086ab6bfe3SJack F Vogel 	for (retry_count = 0; retry_count < 2; retry_count++) {
2096ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID1, &phy_reg);
2106ab6bfe3SJack F Vogel 		if (ret_val || (phy_reg == 0xFFFF))
2116ab6bfe3SJack F Vogel 			continue;
2126ab6bfe3SJack F Vogel 		phy_id = (u32)(phy_reg << 16);
2134dab5c37SJack F Vogel 
2146ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID2, &phy_reg);
2156ab6bfe3SJack F Vogel 		if (ret_val || (phy_reg == 0xFFFF)) {
2166ab6bfe3SJack F Vogel 			phy_id = 0;
2176ab6bfe3SJack F Vogel 			continue;
2186ab6bfe3SJack F Vogel 		}
2196ab6bfe3SJack F Vogel 		phy_id |= (u32)(phy_reg & PHY_REVISION_MASK);
2206ab6bfe3SJack F Vogel 		break;
2216ab6bfe3SJack F Vogel 	}
2226ab6bfe3SJack F Vogel 
2236ab6bfe3SJack F Vogel 	if (hw->phy.id) {
2246ab6bfe3SJack F Vogel 		if  (hw->phy.id == phy_id)
2257609433eSJack F Vogel 			goto out;
2266ab6bfe3SJack F Vogel 	} else if (phy_id) {
2276ab6bfe3SJack F Vogel 		hw->phy.id = phy_id;
2286ab6bfe3SJack F Vogel 		hw->phy.revision = (u32)(phy_reg & ~PHY_REVISION_MASK);
2297609433eSJack F Vogel 		goto out;
2306ab6bfe3SJack F Vogel 	}
2316ab6bfe3SJack F Vogel 
2326ab6bfe3SJack F Vogel 	/* In case the PHY needs to be in mdio slow mode,
2336ab6bfe3SJack F Vogel 	 * set slow mode and try to get the PHY id again.
2346ab6bfe3SJack F Vogel 	 */
2357609433eSJack F Vogel 	if (hw->mac.type < e1000_pch_lpt) {
2366ab6bfe3SJack F Vogel 		hw->phy.ops.release(hw);
2376ab6bfe3SJack F Vogel 		ret_val = e1000_set_mdio_slow_mode_hv(hw);
2386ab6bfe3SJack F Vogel 		if (!ret_val)
2396ab6bfe3SJack F Vogel 			ret_val = e1000_get_phy_id(hw);
2406ab6bfe3SJack F Vogel 		hw->phy.ops.acquire(hw);
2417609433eSJack F Vogel 	}
2426ab6bfe3SJack F Vogel 
2437609433eSJack F Vogel 	if (ret_val)
2447609433eSJack F Vogel 		return FALSE;
2457609433eSJack F Vogel out:
246*c80429ceSEric Joyner 	if ((hw->mac.type == e1000_pch_lpt) ||
247*c80429ceSEric Joyner 	    (hw->mac.type == e1000_pch_spt)) {
248*c80429ceSEric Joyner 		/* Only unforce SMBus if ME is not active */
249*c80429ceSEric Joyner 		if (!(E1000_READ_REG(hw, E1000_FWSM) &
250*c80429ceSEric Joyner 		    E1000_ICH_FWSM_FW_VALID)) {
2517609433eSJack F Vogel 			/* Unforce SMBus mode in PHY */
2527609433eSJack F Vogel 			hw->phy.ops.read_reg_locked(hw, CV_SMB_CTRL, &phy_reg);
2537609433eSJack F Vogel 			phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
2547609433eSJack F Vogel 			hw->phy.ops.write_reg_locked(hw, CV_SMB_CTRL, phy_reg);
2557609433eSJack F Vogel 
2567609433eSJack F Vogel 			/* Unforce SMBus mode in MAC */
2577609433eSJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
2587609433eSJack F Vogel 			mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
2597609433eSJack F Vogel 			E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
2607609433eSJack F Vogel 		}
261*c80429ceSEric Joyner 	}
2627609433eSJack F Vogel 
2637609433eSJack F Vogel 	return TRUE;
2647609433eSJack F Vogel }
2657609433eSJack F Vogel 
2667609433eSJack F Vogel /**
2677609433eSJack F Vogel  *  e1000_toggle_lanphypc_pch_lpt - toggle the LANPHYPC pin value
2687609433eSJack F Vogel  *  @hw: pointer to the HW structure
2697609433eSJack F Vogel  *
2707609433eSJack F Vogel  *  Toggling the LANPHYPC pin value fully power-cycles the PHY and is
2717609433eSJack F Vogel  *  used to reset the PHY to a quiescent state when necessary.
2727609433eSJack F Vogel  **/
2738cc64f1eSJack F Vogel static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw)
2747609433eSJack F Vogel {
2757609433eSJack F Vogel 	u32 mac_reg;
2767609433eSJack F Vogel 
2777609433eSJack F Vogel 	DEBUGFUNC("e1000_toggle_lanphypc_pch_lpt");
2787609433eSJack F Vogel 
2797609433eSJack F Vogel 	/* Set Phy Config Counter to 50msec */
2807609433eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM3);
2817609433eSJack F Vogel 	mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
2827609433eSJack F Vogel 	mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
2837609433eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_FEXTNVM3, mac_reg);
2847609433eSJack F Vogel 
2857609433eSJack F Vogel 	/* Toggle LANPHYPC Value bit */
2867609433eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_CTRL);
2877609433eSJack F Vogel 	mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
2887609433eSJack F Vogel 	mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
2897609433eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, mac_reg);
2907609433eSJack F Vogel 	E1000_WRITE_FLUSH(hw);
2917609433eSJack F Vogel 	usec_delay(10);
2927609433eSJack F Vogel 	mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
2937609433eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, mac_reg);
2947609433eSJack F Vogel 	E1000_WRITE_FLUSH(hw);
2957609433eSJack F Vogel 
2967609433eSJack F Vogel 	if (hw->mac.type < e1000_pch_lpt) {
2977609433eSJack F Vogel 		msec_delay(50);
2987609433eSJack F Vogel 	} else {
2997609433eSJack F Vogel 		u16 count = 20;
3007609433eSJack F Vogel 
3017609433eSJack F Vogel 		do {
3027609433eSJack F Vogel 			msec_delay(5);
3037609433eSJack F Vogel 		} while (!(E1000_READ_REG(hw, E1000_CTRL_EXT) &
3047609433eSJack F Vogel 			   E1000_CTRL_EXT_LPCD) && count--);
3057609433eSJack F Vogel 
3067609433eSJack F Vogel 		msec_delay(30);
3077609433eSJack F Vogel 	}
3086ab6bfe3SJack F Vogel }
3096ab6bfe3SJack F Vogel 
3106ab6bfe3SJack F Vogel /**
3116ab6bfe3SJack F Vogel  *  e1000_init_phy_workarounds_pchlan - PHY initialization workarounds
3126ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
3136ab6bfe3SJack F Vogel  *
3146ab6bfe3SJack F Vogel  *  Workarounds/flow necessary for PHY initialization during driver load
3156ab6bfe3SJack F Vogel  *  and resume paths.
3166ab6bfe3SJack F Vogel  **/
3176ab6bfe3SJack F Vogel static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
3186ab6bfe3SJack F Vogel {
3196ab6bfe3SJack F Vogel 	u32 mac_reg, fwsm = E1000_READ_REG(hw, E1000_FWSM);
3206ab6bfe3SJack F Vogel 	s32 ret_val;
3216ab6bfe3SJack F Vogel 
3226ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_init_phy_workarounds_pchlan");
3236ab6bfe3SJack F Vogel 
3246ab6bfe3SJack F Vogel 	/* Gate automatic PHY configuration by hardware on managed and
3256ab6bfe3SJack F Vogel 	 * non-managed 82579 and newer adapters.
3266ab6bfe3SJack F Vogel 	 */
3276ab6bfe3SJack F Vogel 	e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
3286ab6bfe3SJack F Vogel 
3298cc64f1eSJack F Vogel 	/* It is not possible to be certain of the current state of ULP
3308cc64f1eSJack F Vogel 	 * so forcibly disable it.
3318cc64f1eSJack F Vogel 	 */
3328cc64f1eSJack F Vogel 	hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_unknown;
3338cc64f1eSJack F Vogel 	e1000_disable_ulp_lpt_lp(hw, TRUE);
3348cc64f1eSJack F Vogel 
3356ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
3366ab6bfe3SJack F Vogel 	if (ret_val) {
3376ab6bfe3SJack F Vogel 		DEBUGOUT("Failed to initialize PHY flow\n");
3386ab6bfe3SJack F Vogel 		goto out;
3396ab6bfe3SJack F Vogel 	}
3406ab6bfe3SJack F Vogel 
3416ab6bfe3SJack F Vogel 	/* The MAC-PHY interconnect may be in SMBus mode.  If the PHY is
3426ab6bfe3SJack F Vogel 	 * inaccessible and resetting the PHY is not blocked, toggle the
3436ab6bfe3SJack F Vogel 	 * LANPHYPC Value bit to force the interconnect to PCIe mode.
3446ab6bfe3SJack F Vogel 	 */
3456ab6bfe3SJack F Vogel 	switch (hw->mac.type) {
3466ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
347*c80429ceSEric Joyner 	case e1000_pch_spt:
3486ab6bfe3SJack F Vogel 		if (e1000_phy_is_accessible_pchlan(hw))
3496ab6bfe3SJack F Vogel 			break;
3506ab6bfe3SJack F Vogel 
3516ab6bfe3SJack F Vogel 		/* Before toggling LANPHYPC, see if PHY is accessible by
3526ab6bfe3SJack F Vogel 		 * forcing MAC to SMBus mode first.
3536ab6bfe3SJack F Vogel 		 */
3546ab6bfe3SJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
3556ab6bfe3SJack F Vogel 		mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
3566ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
3576ab6bfe3SJack F Vogel 
3587609433eSJack F Vogel 		/* Wait 50 milliseconds for MAC to finish any retries
3597609433eSJack F Vogel 		 * that it might be trying to perform from previous
3607609433eSJack F Vogel 		 * attempts to acknowledge any phy read requests.
3617609433eSJack F Vogel 		 */
3627609433eSJack F Vogel 		 msec_delay(50);
3637609433eSJack F Vogel 
3646ab6bfe3SJack F Vogel 		/* fall-through */
3656ab6bfe3SJack F Vogel 	case e1000_pch2lan:
3667609433eSJack F Vogel 		if (e1000_phy_is_accessible_pchlan(hw))
3676ab6bfe3SJack F Vogel 			break;
3686ab6bfe3SJack F Vogel 
3696ab6bfe3SJack F Vogel 		/* fall-through */
3706ab6bfe3SJack F Vogel 	case e1000_pchlan:
3716ab6bfe3SJack F Vogel 		if ((hw->mac.type == e1000_pchlan) &&
3726ab6bfe3SJack F Vogel 		    (fwsm & E1000_ICH_FWSM_FW_VALID))
3736ab6bfe3SJack F Vogel 			break;
3746ab6bfe3SJack F Vogel 
3756ab6bfe3SJack F Vogel 		if (hw->phy.ops.check_reset_block(hw)) {
3766ab6bfe3SJack F Vogel 			DEBUGOUT("Required LANPHYPC toggle blocked by ME\n");
3777609433eSJack F Vogel 			ret_val = -E1000_ERR_PHY;
3786ab6bfe3SJack F Vogel 			break;
3796ab6bfe3SJack F Vogel 		}
3806ab6bfe3SJack F Vogel 
3817609433eSJack F Vogel 		/* Toggle LANPHYPC Value bit */
3827609433eSJack F Vogel 		e1000_toggle_lanphypc_pch_lpt(hw);
3837609433eSJack F Vogel 		if (hw->mac.type >= e1000_pch_lpt) {
3847609433eSJack F Vogel 			if (e1000_phy_is_accessible_pchlan(hw))
3857609433eSJack F Vogel 				break;
3866ab6bfe3SJack F Vogel 
3876ab6bfe3SJack F Vogel 			/* Toggling LANPHYPC brings the PHY out of SMBus mode
3887609433eSJack F Vogel 			 * so ensure that the MAC is also out of SMBus mode
3896ab6bfe3SJack F Vogel 			 */
3906ab6bfe3SJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
3916ab6bfe3SJack F Vogel 			mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
3926ab6bfe3SJack F Vogel 			E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
3936ab6bfe3SJack F Vogel 
3947609433eSJack F Vogel 			if (e1000_phy_is_accessible_pchlan(hw))
3957609433eSJack F Vogel 				break;
3967609433eSJack F Vogel 
3977609433eSJack F Vogel 			ret_val = -E1000_ERR_PHY;
3986ab6bfe3SJack F Vogel 		}
3996ab6bfe3SJack F Vogel 		break;
4006ab6bfe3SJack F Vogel 	default:
4016ab6bfe3SJack F Vogel 		break;
4026ab6bfe3SJack F Vogel 	}
4036ab6bfe3SJack F Vogel 
4046ab6bfe3SJack F Vogel 	hw->phy.ops.release(hw);
4057609433eSJack F Vogel 	if (!ret_val) {
4067609433eSJack F Vogel 
4077609433eSJack F Vogel 		/* Check to see if able to reset PHY.  Print error if not */
4087609433eSJack F Vogel 		if (hw->phy.ops.check_reset_block(hw)) {
4097609433eSJack F Vogel 			ERROR_REPORT("Reset blocked by ME\n");
4107609433eSJack F Vogel 			goto out;
4117609433eSJack F Vogel 		}
4126ab6bfe3SJack F Vogel 
4136ab6bfe3SJack F Vogel 		/* Reset the PHY before any access to it.  Doing so, ensures
4146ab6bfe3SJack F Vogel 		 * that the PHY is in a known good state before we read/write
4156ab6bfe3SJack F Vogel 		 * PHY registers.  The generic reset is sufficient here,
4166ab6bfe3SJack F Vogel 		 * because we haven't determined the PHY type yet.
4176ab6bfe3SJack F Vogel 		 */
4186ab6bfe3SJack F Vogel 		ret_val = e1000_phy_hw_reset_generic(hw);
4197609433eSJack F Vogel 		if (ret_val)
4207609433eSJack F Vogel 			goto out;
4217609433eSJack F Vogel 
4227609433eSJack F Vogel 		/* On a successful reset, possibly need to wait for the PHY
4237609433eSJack F Vogel 		 * to quiesce to an accessible state before returning control
4247609433eSJack F Vogel 		 * to the calling function.  If the PHY does not quiesce, then
4257609433eSJack F Vogel 		 * return E1000E_BLK_PHY_RESET, as this is the condition that
4267609433eSJack F Vogel 		 *  the PHY is in.
4277609433eSJack F Vogel 		 */
4287609433eSJack F Vogel 		ret_val = hw->phy.ops.check_reset_block(hw);
4297609433eSJack F Vogel 		if (ret_val)
4307609433eSJack F Vogel 			ERROR_REPORT("ME blocked access to PHY after reset\n");
4317609433eSJack F Vogel 	}
4326ab6bfe3SJack F Vogel 
4336ab6bfe3SJack F Vogel out:
4346ab6bfe3SJack F Vogel 	/* Ungate automatic PHY configuration on non-managed 82579 */
4356ab6bfe3SJack F Vogel 	if ((hw->mac.type == e1000_pch2lan) &&
4366ab6bfe3SJack F Vogel 	    !(fwsm & E1000_ICH_FWSM_FW_VALID)) {
4376ab6bfe3SJack F Vogel 		msec_delay(10);
4386ab6bfe3SJack F Vogel 		e1000_gate_hw_phy_config_ich8lan(hw, FALSE);
4396ab6bfe3SJack F Vogel 	}
4406ab6bfe3SJack F Vogel 
4416ab6bfe3SJack F Vogel 	return ret_val;
4424dab5c37SJack F Vogel }
4434dab5c37SJack F Vogel 
4448cfa0ad2SJack F Vogel /**
4459d81738fSJack F Vogel  *  e1000_init_phy_params_pchlan - Initialize PHY function pointers
4469d81738fSJack F Vogel  *  @hw: pointer to the HW structure
4479d81738fSJack F Vogel  *
4489d81738fSJack F Vogel  *  Initialize family-specific PHY parameters and function pointers.
4499d81738fSJack F Vogel  **/
4509d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
4519d81738fSJack F Vogel {
4529d81738fSJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
4536ab6bfe3SJack F Vogel 	s32 ret_val;
4549d81738fSJack F Vogel 
4559d81738fSJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_pchlan");
4569d81738fSJack F Vogel 
4579d81738fSJack F Vogel 	phy->addr		= 1;
4589d81738fSJack F Vogel 	phy->reset_delay_us	= 100;
4599d81738fSJack F Vogel 
4609d81738fSJack F Vogel 	phy->ops.acquire	= e1000_acquire_swflag_ich8lan;
4619d81738fSJack F Vogel 	phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
4629d81738fSJack F Vogel 	phy->ops.get_cfg_done	= e1000_get_cfg_done_ich8lan;
4634dab5c37SJack F Vogel 	phy->ops.set_page	= e1000_set_page_igp;
4649d81738fSJack F Vogel 	phy->ops.read_reg	= e1000_read_phy_reg_hv;
4654edd8523SJack F Vogel 	phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked;
4664dab5c37SJack F Vogel 	phy->ops.read_reg_page	= e1000_read_phy_reg_page_hv;
4679d81738fSJack F Vogel 	phy->ops.release	= e1000_release_swflag_ich8lan;
4689d81738fSJack F Vogel 	phy->ops.reset		= e1000_phy_hw_reset_ich8lan;
4694edd8523SJack F Vogel 	phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan;
4704edd8523SJack F Vogel 	phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan;
4719d81738fSJack F Vogel 	phy->ops.write_reg	= e1000_write_phy_reg_hv;
4724edd8523SJack F Vogel 	phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked;
4734dab5c37SJack F Vogel 	phy->ops.write_reg_page	= e1000_write_phy_reg_page_hv;
4749d81738fSJack F Vogel 	phy->ops.power_up	= e1000_power_up_phy_copper;
4759d81738fSJack F Vogel 	phy->ops.power_down	= e1000_power_down_phy_copper_ich8lan;
4769d81738fSJack F Vogel 	phy->autoneg_mask	= AUTONEG_ADVERTISE_SPEED_DEFAULT;
4779d81738fSJack F Vogel 
4789d81738fSJack F Vogel 	phy->id = e1000_phy_unknown;
4796ab6bfe3SJack F Vogel 
4806ab6bfe3SJack F Vogel 	ret_val = e1000_init_phy_workarounds_pchlan(hw);
4816ab6bfe3SJack F Vogel 	if (ret_val)
4826ab6bfe3SJack F Vogel 		return ret_val;
4836ab6bfe3SJack F Vogel 
4846ab6bfe3SJack F Vogel 	if (phy->id == e1000_phy_unknown)
4857d9119bdSJack F Vogel 		switch (hw->mac.type) {
4867d9119bdSJack F Vogel 		default:
487a69ed8dfSJack F Vogel 			ret_val = e1000_get_phy_id(hw);
488a69ed8dfSJack F Vogel 			if (ret_val)
4896ab6bfe3SJack F Vogel 				return ret_val;
4907d9119bdSJack F Vogel 			if ((phy->id != 0) && (phy->id != PHY_REVISION_MASK))
4917d9119bdSJack F Vogel 				break;
4927d9119bdSJack F Vogel 			/* fall-through */
4937d9119bdSJack F Vogel 		case e1000_pch2lan:
4946ab6bfe3SJack F Vogel 		case e1000_pch_lpt:
495*c80429ceSEric Joyner 		case e1000_pch_spt:
4966ab6bfe3SJack F Vogel 			/* In case the PHY needs to be in mdio slow mode,
497a69ed8dfSJack F Vogel 			 * set slow mode and try to get the PHY id again.
498a69ed8dfSJack F Vogel 			 */
499a69ed8dfSJack F Vogel 			ret_val = e1000_set_mdio_slow_mode_hv(hw);
500a69ed8dfSJack F Vogel 			if (ret_val)
5016ab6bfe3SJack F Vogel 				return ret_val;
502a69ed8dfSJack F Vogel 			ret_val = e1000_get_phy_id(hw);
503a69ed8dfSJack F Vogel 			if (ret_val)
5046ab6bfe3SJack F Vogel 				return ret_val;
5057d9119bdSJack F Vogel 			break;
506a69ed8dfSJack F Vogel 		}
5079d81738fSJack F Vogel 	phy->type = e1000_get_phy_type_from_id(phy->id);
5089d81738fSJack F Vogel 
5094edd8523SJack F Vogel 	switch (phy->type) {
5104edd8523SJack F Vogel 	case e1000_phy_82577:
5117d9119bdSJack F Vogel 	case e1000_phy_82579:
5126ab6bfe3SJack F Vogel 	case e1000_phy_i217:
5139d81738fSJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_82577;
5149d81738fSJack F Vogel 		phy->ops.force_speed_duplex =
5159d81738fSJack F Vogel 			e1000_phy_force_speed_duplex_82577;
5169d81738fSJack F Vogel 		phy->ops.get_cable_length = e1000_get_cable_length_82577;
5179d81738fSJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_82577;
5189d81738fSJack F Vogel 		phy->ops.commit = e1000_phy_sw_reset_generic;
5198ec87fc5SJack F Vogel 		break;
5204edd8523SJack F Vogel 	case e1000_phy_82578:
5214edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_m88;
5224edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
5234edd8523SJack F Vogel 		phy->ops.get_cable_length = e1000_get_cable_length_m88;
5244edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_m88;
5254edd8523SJack F Vogel 		break;
5264edd8523SJack F Vogel 	default:
5274edd8523SJack F Vogel 		ret_val = -E1000_ERR_PHY;
5284edd8523SJack F Vogel 		break;
5299d81738fSJack F Vogel 	}
5309d81738fSJack F Vogel 
5319d81738fSJack F Vogel 	return ret_val;
5329d81738fSJack F Vogel }
5339d81738fSJack F Vogel 
5349d81738fSJack F Vogel /**
5358cfa0ad2SJack F Vogel  *  e1000_init_phy_params_ich8lan - Initialize PHY function pointers
5368cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5378cfa0ad2SJack F Vogel  *
5388cfa0ad2SJack F Vogel  *  Initialize family-specific PHY parameters and function pointers.
5398cfa0ad2SJack F Vogel  **/
5408cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
5418cfa0ad2SJack F Vogel {
5428cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
5436ab6bfe3SJack F Vogel 	s32 ret_val;
5448cfa0ad2SJack F Vogel 	u16 i = 0;
5458cfa0ad2SJack F Vogel 
5468cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_ich8lan");
5478cfa0ad2SJack F Vogel 
5488cfa0ad2SJack F Vogel 	phy->addr		= 1;
5498cfa0ad2SJack F Vogel 	phy->reset_delay_us	= 100;
5508cfa0ad2SJack F Vogel 
5518cfa0ad2SJack F Vogel 	phy->ops.acquire	= e1000_acquire_swflag_ich8lan;
5528cfa0ad2SJack F Vogel 	phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
5538cfa0ad2SJack F Vogel 	phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
5548cfa0ad2SJack F Vogel 	phy->ops.get_cfg_done	= e1000_get_cfg_done_ich8lan;
5558cfa0ad2SJack F Vogel 	phy->ops.read_reg	= e1000_read_phy_reg_igp;
5568cfa0ad2SJack F Vogel 	phy->ops.release	= e1000_release_swflag_ich8lan;
5578cfa0ad2SJack F Vogel 	phy->ops.reset		= e1000_phy_hw_reset_ich8lan;
5588cfa0ad2SJack F Vogel 	phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan;
5598cfa0ad2SJack F Vogel 	phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan;
5608cfa0ad2SJack F Vogel 	phy->ops.write_reg	= e1000_write_phy_reg_igp;
5618cfa0ad2SJack F Vogel 	phy->ops.power_up	= e1000_power_up_phy_copper;
5628cfa0ad2SJack F Vogel 	phy->ops.power_down	= e1000_power_down_phy_copper_ich8lan;
5638cfa0ad2SJack F Vogel 
5646ab6bfe3SJack F Vogel 	/* We may need to do this twice - once for IGP and if that fails,
5658cfa0ad2SJack F Vogel 	 * we'll set BM func pointers and try again
5668cfa0ad2SJack F Vogel 	 */
5678cfa0ad2SJack F Vogel 	ret_val = e1000_determine_phy_address(hw);
5688cfa0ad2SJack F Vogel 	if (ret_val) {
5698cfa0ad2SJack F Vogel 		phy->ops.write_reg = e1000_write_phy_reg_bm;
5708cfa0ad2SJack F Vogel 		phy->ops.read_reg  = e1000_read_phy_reg_bm;
5718cfa0ad2SJack F Vogel 		ret_val = e1000_determine_phy_address(hw);
5728cfa0ad2SJack F Vogel 		if (ret_val) {
573d035aa2dSJack F Vogel 			DEBUGOUT("Cannot determine PHY addr. Erroring out\n");
5746ab6bfe3SJack F Vogel 			return ret_val;
5758cfa0ad2SJack F Vogel 		}
5768cfa0ad2SJack F Vogel 	}
5778cfa0ad2SJack F Vogel 
5788cfa0ad2SJack F Vogel 	phy->id = 0;
5798cfa0ad2SJack F Vogel 	while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) &&
5808cfa0ad2SJack F Vogel 	       (i++ < 100)) {
5818cfa0ad2SJack F Vogel 		msec_delay(1);
5828cfa0ad2SJack F Vogel 		ret_val = e1000_get_phy_id(hw);
5838cfa0ad2SJack F Vogel 		if (ret_val)
5846ab6bfe3SJack F Vogel 			return ret_val;
5858cfa0ad2SJack F Vogel 	}
5868cfa0ad2SJack F Vogel 
5878cfa0ad2SJack F Vogel 	/* Verify phy id */
5888cfa0ad2SJack F Vogel 	switch (phy->id) {
5898cfa0ad2SJack F Vogel 	case IGP03E1000_E_PHY_ID:
5908cfa0ad2SJack F Vogel 		phy->type = e1000_phy_igp_3;
5918cfa0ad2SJack F Vogel 		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
5924edd8523SJack F Vogel 		phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked;
5934edd8523SJack F Vogel 		phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked;
5944edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_igp;
5954edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_igp;
5964edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
5978cfa0ad2SJack F Vogel 		break;
5988cfa0ad2SJack F Vogel 	case IFE_E_PHY_ID:
5998cfa0ad2SJack F Vogel 	case IFE_PLUS_E_PHY_ID:
6008cfa0ad2SJack F Vogel 	case IFE_C_E_PHY_ID:
6018cfa0ad2SJack F Vogel 		phy->type = e1000_phy_ife;
6028cfa0ad2SJack F Vogel 		phy->autoneg_mask = E1000_ALL_NOT_GIG;
6034edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_ife;
6044edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_ife;
6054edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife;
6068cfa0ad2SJack F Vogel 		break;
6078cfa0ad2SJack F Vogel 	case BME1000_E_PHY_ID:
6088cfa0ad2SJack F Vogel 		phy->type = e1000_phy_bm;
6098cfa0ad2SJack F Vogel 		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
6108cfa0ad2SJack F Vogel 		phy->ops.read_reg = e1000_read_phy_reg_bm;
6118cfa0ad2SJack F Vogel 		phy->ops.write_reg = e1000_write_phy_reg_bm;
6128cfa0ad2SJack F Vogel 		phy->ops.commit = e1000_phy_sw_reset_generic;
6134edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_m88;
6144edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_m88;
6154edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
6168cfa0ad2SJack F Vogel 		break;
6178cfa0ad2SJack F Vogel 	default:
6186ab6bfe3SJack F Vogel 		return -E1000_ERR_PHY;
6196ab6bfe3SJack F Vogel 		break;
6208cfa0ad2SJack F Vogel 	}
6218cfa0ad2SJack F Vogel 
6226ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
6238cfa0ad2SJack F Vogel }
6248cfa0ad2SJack F Vogel 
6258cfa0ad2SJack F Vogel /**
6268cfa0ad2SJack F Vogel  *  e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
6278cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
6288cfa0ad2SJack F Vogel  *
6298cfa0ad2SJack F Vogel  *  Initialize family-specific NVM parameters and function
6308cfa0ad2SJack F Vogel  *  pointers.
6318cfa0ad2SJack F Vogel  **/
6328cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
6338cfa0ad2SJack F Vogel {
6348cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
635daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
6368cfa0ad2SJack F Vogel 	u32 gfpreg, sector_base_addr, sector_end_addr;
6378cfa0ad2SJack F Vogel 	u16 i;
638*c80429ceSEric Joyner 	u32 nvm_size;
6398cfa0ad2SJack F Vogel 
6408cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_nvm_params_ich8lan");
6418cfa0ad2SJack F Vogel 
6428cc64f1eSJack F Vogel 	nvm->type = e1000_nvm_flash_sw;
643*c80429ceSEric Joyner 
644*c80429ceSEric Joyner 	if (hw->mac.type == e1000_pch_spt) {
645*c80429ceSEric Joyner 		/* in SPT, gfpreg doesn't exist. NVM size is taken from the
646*c80429ceSEric Joyner 		 * STRAP register. This is because in SPT the GbE Flash region
647*c80429ceSEric Joyner 		 * is no longer accessed through the flash registers. Instead,
648*c80429ceSEric Joyner 		 * the mechanism has changed, and the Flash region access
649*c80429ceSEric Joyner 		 * registers are now implemented in GbE memory space.
650*c80429ceSEric Joyner 		 */
651*c80429ceSEric Joyner 		nvm->flash_base_addr = 0;
652*c80429ceSEric Joyner 		nvm_size =
653*c80429ceSEric Joyner 		    (((E1000_READ_REG(hw, E1000_STRAP) >> 1) & 0x1F) + 1)
654*c80429ceSEric Joyner 		    * NVM_SIZE_MULTIPLIER;
655*c80429ceSEric Joyner 		nvm->flash_bank_size = nvm_size / 2;
656*c80429ceSEric Joyner 		/* Adjust to word count */
657*c80429ceSEric Joyner 		nvm->flash_bank_size /= sizeof(u16);
658*c80429ceSEric Joyner 		/* Set the base address for flash register access */
659*c80429ceSEric Joyner 		hw->flash_address = hw->hw_addr + E1000_FLASH_BASE_ADDR;
660*c80429ceSEric Joyner 	} else {
661*c80429ceSEric Joyner 		/* Can't read flash registers if register set isn't mapped. */
6628cfa0ad2SJack F Vogel 		if (!hw->flash_address) {
6638cfa0ad2SJack F Vogel 			DEBUGOUT("ERROR: Flash registers not mapped\n");
6646ab6bfe3SJack F Vogel 			return -E1000_ERR_CONFIG;
6658cfa0ad2SJack F Vogel 		}
6668cfa0ad2SJack F Vogel 
6678cfa0ad2SJack F Vogel 		gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG);
6688cfa0ad2SJack F Vogel 
6696ab6bfe3SJack F Vogel 		/* sector_X_addr is a "sector"-aligned address (4096 bytes)
6708cfa0ad2SJack F Vogel 		 * Add 1 to sector_end_addr since this sector is included in
6718cfa0ad2SJack F Vogel 		 * the overall size.
6728cfa0ad2SJack F Vogel 		 */
6738cfa0ad2SJack F Vogel 		sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
6748cfa0ad2SJack F Vogel 		sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
6758cfa0ad2SJack F Vogel 
6768cfa0ad2SJack F Vogel 		/* flash_base_addr is byte-aligned */
677*c80429ceSEric Joyner 		nvm->flash_base_addr = sector_base_addr
678*c80429ceSEric Joyner 				       << FLASH_SECTOR_ADDR_SHIFT;
6798cfa0ad2SJack F Vogel 
6806ab6bfe3SJack F Vogel 		/* find total size of the NVM, then cut in half since the total
6818cfa0ad2SJack F Vogel 		 * size represents two separate NVM banks.
6828cfa0ad2SJack F Vogel 		 */
6837609433eSJack F Vogel 		nvm->flash_bank_size = ((sector_end_addr - sector_base_addr)
6847609433eSJack F Vogel 					<< FLASH_SECTOR_ADDR_SHIFT);
6858cfa0ad2SJack F Vogel 		nvm->flash_bank_size /= 2;
6868cfa0ad2SJack F Vogel 		/* Adjust to word count */
6878cfa0ad2SJack F Vogel 		nvm->flash_bank_size /= sizeof(u16);
688*c80429ceSEric Joyner 	}
6898cfa0ad2SJack F Vogel 
6908cfa0ad2SJack F Vogel 	nvm->word_size = E1000_SHADOW_RAM_WORDS;
6918cfa0ad2SJack F Vogel 
6928cfa0ad2SJack F Vogel 	/* Clear shadow ram */
6938cfa0ad2SJack F Vogel 	for (i = 0; i < nvm->word_size; i++) {
6948cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].modified = FALSE;
6958cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].value    = 0xFFFF;
6968cfa0ad2SJack F Vogel 	}
6978cfa0ad2SJack F Vogel 
6984edd8523SJack F Vogel 	E1000_MUTEX_INIT(&dev_spec->nvm_mutex);
6994edd8523SJack F Vogel 	E1000_MUTEX_INIT(&dev_spec->swflag_mutex);
7004edd8523SJack F Vogel 
7018cfa0ad2SJack F Vogel 	/* Function Pointers */
7024edd8523SJack F Vogel 	nvm->ops.acquire	= e1000_acquire_nvm_ich8lan;
7034edd8523SJack F Vogel 	nvm->ops.release	= e1000_release_nvm_ich8lan;
704*c80429ceSEric Joyner 	if (hw->mac.type == e1000_pch_spt) {
705*c80429ceSEric Joyner 		nvm->ops.read	= e1000_read_nvm_spt;
706*c80429ceSEric Joyner 		nvm->ops.update	= e1000_update_nvm_checksum_spt;
707*c80429ceSEric Joyner 	} else {
7088cfa0ad2SJack F Vogel 		nvm->ops.read	= e1000_read_nvm_ich8lan;
7098cfa0ad2SJack F Vogel 		nvm->ops.update	= e1000_update_nvm_checksum_ich8lan;
710*c80429ceSEric Joyner 	}
7118cfa0ad2SJack F Vogel 	nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan;
7128cfa0ad2SJack F Vogel 	nvm->ops.validate	= e1000_validate_nvm_checksum_ich8lan;
7138cfa0ad2SJack F Vogel 	nvm->ops.write		= e1000_write_nvm_ich8lan;
7148cfa0ad2SJack F Vogel 
7156ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
7168cfa0ad2SJack F Vogel }
7178cfa0ad2SJack F Vogel 
7188cfa0ad2SJack F Vogel /**
7198cfa0ad2SJack F Vogel  *  e1000_init_mac_params_ich8lan - Initialize MAC function pointers
7208cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
7218cfa0ad2SJack F Vogel  *
7228cfa0ad2SJack F Vogel  *  Initialize family-specific MAC parameters and function
7238cfa0ad2SJack F Vogel  *  pointers.
7248cfa0ad2SJack F Vogel  **/
7258cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
7268cfa0ad2SJack F Vogel {
7278cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
7288cfa0ad2SJack F Vogel 
7298cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_mac_params_ich8lan");
7308cfa0ad2SJack F Vogel 
7318cfa0ad2SJack F Vogel 	/* Set media type function pointer */
7328cfa0ad2SJack F Vogel 	hw->phy.media_type = e1000_media_type_copper;
7338cfa0ad2SJack F Vogel 
7348cfa0ad2SJack F Vogel 	/* Set mta register count */
7358cfa0ad2SJack F Vogel 	mac->mta_reg_count = 32;
7368cfa0ad2SJack F Vogel 	/* Set rar entry count */
7378cfa0ad2SJack F Vogel 	mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
7388cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
7398cfa0ad2SJack F Vogel 		mac->rar_entry_count--;
7408cfa0ad2SJack F Vogel 	/* Set if part includes ASF firmware */
7418cfa0ad2SJack F Vogel 	mac->asf_firmware_present = TRUE;
7428ec87fc5SJack F Vogel 	/* FWSM register */
7438ec87fc5SJack F Vogel 	mac->has_fwsm = TRUE;
7448ec87fc5SJack F Vogel 	/* ARC subsystem not supported */
7458ec87fc5SJack F Vogel 	mac->arc_subsystem_valid = FALSE;
7464edd8523SJack F Vogel 	/* Adaptive IFS supported */
7474edd8523SJack F Vogel 	mac->adaptive_ifs = TRUE;
7488cfa0ad2SJack F Vogel 
7498cfa0ad2SJack F Vogel 	/* Function pointers */
7508cfa0ad2SJack F Vogel 
7518cfa0ad2SJack F Vogel 	/* bus type/speed/width */
7528cfa0ad2SJack F Vogel 	mac->ops.get_bus_info = e1000_get_bus_info_ich8lan;
753daf9197cSJack F Vogel 	/* function id */
754daf9197cSJack F Vogel 	mac->ops.set_lan_id = e1000_set_lan_id_single_port;
7558cfa0ad2SJack F Vogel 	/* reset */
7568cfa0ad2SJack F Vogel 	mac->ops.reset_hw = e1000_reset_hw_ich8lan;
7578cfa0ad2SJack F Vogel 	/* hw initialization */
7588cfa0ad2SJack F Vogel 	mac->ops.init_hw = e1000_init_hw_ich8lan;
7598cfa0ad2SJack F Vogel 	/* link setup */
7608cfa0ad2SJack F Vogel 	mac->ops.setup_link = e1000_setup_link_ich8lan;
7618cfa0ad2SJack F Vogel 	/* physical interface setup */
7628cfa0ad2SJack F Vogel 	mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan;
7638cfa0ad2SJack F Vogel 	/* check for link */
7644edd8523SJack F Vogel 	mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan;
7658cfa0ad2SJack F Vogel 	/* link info */
7668cfa0ad2SJack F Vogel 	mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan;
7678cfa0ad2SJack F Vogel 	/* multicast address update */
7688cfa0ad2SJack F Vogel 	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
769d035aa2dSJack F Vogel 	/* clear hardware counters */
770d035aa2dSJack F Vogel 	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan;
771d035aa2dSJack F Vogel 
7726ab6bfe3SJack F Vogel 	/* LED and other operations */
773d035aa2dSJack F Vogel 	switch (mac->type) {
774d035aa2dSJack F Vogel 	case e1000_ich8lan:
775d035aa2dSJack F Vogel 	case e1000_ich9lan:
776d035aa2dSJack F Vogel 	case e1000_ich10lan:
7777d9119bdSJack F Vogel 		/* check management mode */
7787d9119bdSJack F Vogel 		mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
779d035aa2dSJack F Vogel 		/* ID LED init */
780d035aa2dSJack F Vogel 		mac->ops.id_led_init = e1000_id_led_init_generic;
7818cfa0ad2SJack F Vogel 		/* blink LED */
7828cfa0ad2SJack F Vogel 		mac->ops.blink_led = e1000_blink_led_generic;
7838cfa0ad2SJack F Vogel 		/* setup LED */
7848cfa0ad2SJack F Vogel 		mac->ops.setup_led = e1000_setup_led_generic;
7858cfa0ad2SJack F Vogel 		/* cleanup LED */
7868cfa0ad2SJack F Vogel 		mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
7878cfa0ad2SJack F Vogel 		/* turn on/off LED */
7888cfa0ad2SJack F Vogel 		mac->ops.led_on = e1000_led_on_ich8lan;
7898cfa0ad2SJack F Vogel 		mac->ops.led_off = e1000_led_off_ich8lan;
790d035aa2dSJack F Vogel 		break;
7917d9119bdSJack F Vogel 	case e1000_pch2lan:
7927d9119bdSJack F Vogel 		mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES;
7937d9119bdSJack F Vogel 		mac->ops.rar_set = e1000_rar_set_pch2lan;
7946ab6bfe3SJack F Vogel 		/* fall-through */
7956ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
796*c80429ceSEric Joyner 	case e1000_pch_spt:
797730d3130SJack F Vogel 		/* multicast address update for pch2 */
798730d3130SJack F Vogel 		mac->ops.update_mc_addr_list =
799730d3130SJack F Vogel 			e1000_update_mc_addr_list_pch2lan;
800*c80429ceSEric Joyner 		/* fall-through */
8019d81738fSJack F Vogel 	case e1000_pchlan:
8027d9119bdSJack F Vogel 		/* check management mode */
8037d9119bdSJack F Vogel 		mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
8049d81738fSJack F Vogel 		/* ID LED init */
8059d81738fSJack F Vogel 		mac->ops.id_led_init = e1000_id_led_init_pchlan;
8069d81738fSJack F Vogel 		/* setup LED */
8079d81738fSJack F Vogel 		mac->ops.setup_led = e1000_setup_led_pchlan;
8089d81738fSJack F Vogel 		/* cleanup LED */
8099d81738fSJack F Vogel 		mac->ops.cleanup_led = e1000_cleanup_led_pchlan;
8109d81738fSJack F Vogel 		/* turn on/off LED */
8119d81738fSJack F Vogel 		mac->ops.led_on = e1000_led_on_pchlan;
8129d81738fSJack F Vogel 		mac->ops.led_off = e1000_led_off_pchlan;
8139d81738fSJack F Vogel 		break;
814d035aa2dSJack F Vogel 	default:
815d035aa2dSJack F Vogel 		break;
816d035aa2dSJack F Vogel 	}
8178cfa0ad2SJack F Vogel 
818*c80429ceSEric Joyner 	if ((mac->type == e1000_pch_lpt) ||
819*c80429ceSEric Joyner 	    (mac->type == e1000_pch_spt)) {
8206ab6bfe3SJack F Vogel 		mac->rar_entry_count = E1000_PCH_LPT_RAR_ENTRIES;
8216ab6bfe3SJack F Vogel 		mac->ops.rar_set = e1000_rar_set_pch_lpt;
8226ab6bfe3SJack F Vogel 		mac->ops.setup_physical_interface = e1000_setup_copper_link_pch_lpt;
823e373323fSSean Bruno 		mac->ops.set_obff_timer = e1000_set_obff_timer_pch_lpt;
8244dab5c37SJack F Vogel 	}
8254dab5c37SJack F Vogel 
8268cfa0ad2SJack F Vogel 	/* Enable PCS Lock-loss workaround for ICH8 */
8278cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
8288cfa0ad2SJack F Vogel 		e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE);
8298cfa0ad2SJack F Vogel 
830daf9197cSJack F Vogel 	return E1000_SUCCESS;
8318cfa0ad2SJack F Vogel }
8328cfa0ad2SJack F Vogel 
8338cfa0ad2SJack F Vogel /**
8346ab6bfe3SJack F Vogel  *  __e1000_access_emi_reg_locked - Read/write EMI register
8356ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
8366ab6bfe3SJack F Vogel  *  @addr: EMI address to program
8376ab6bfe3SJack F Vogel  *  @data: pointer to value to read/write from/to the EMI address
8386ab6bfe3SJack F Vogel  *  @read: boolean flag to indicate read or write
8396ab6bfe3SJack F Vogel  *
8406ab6bfe3SJack F Vogel  *  This helper function assumes the SW/FW/HW Semaphore is already acquired.
8416ab6bfe3SJack F Vogel  **/
8426ab6bfe3SJack F Vogel static s32 __e1000_access_emi_reg_locked(struct e1000_hw *hw, u16 address,
8436ab6bfe3SJack F Vogel 					 u16 *data, bool read)
8446ab6bfe3SJack F Vogel {
8456ab6bfe3SJack F Vogel 	s32 ret_val;
8466ab6bfe3SJack F Vogel 
8476ab6bfe3SJack F Vogel 	DEBUGFUNC("__e1000_access_emi_reg_locked");
8486ab6bfe3SJack F Vogel 
8496ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR, address);
8506ab6bfe3SJack F Vogel 	if (ret_val)
8516ab6bfe3SJack F Vogel 		return ret_val;
8526ab6bfe3SJack F Vogel 
8536ab6bfe3SJack F Vogel 	if (read)
8546ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.read_reg_locked(hw, I82579_EMI_DATA,
8556ab6bfe3SJack F Vogel 						      data);
8566ab6bfe3SJack F Vogel 	else
8576ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_DATA,
8586ab6bfe3SJack F Vogel 						       *data);
8596ab6bfe3SJack F Vogel 
8606ab6bfe3SJack F Vogel 	return ret_val;
8616ab6bfe3SJack F Vogel }
8626ab6bfe3SJack F Vogel 
8636ab6bfe3SJack F Vogel /**
8646ab6bfe3SJack F Vogel  *  e1000_read_emi_reg_locked - Read Extended Management Interface register
8656ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
8666ab6bfe3SJack F Vogel  *  @addr: EMI address to program
8676ab6bfe3SJack F Vogel  *  @data: value to be read from the EMI address
8686ab6bfe3SJack F Vogel  *
8696ab6bfe3SJack F Vogel  *  Assumes the SW/FW/HW Semaphore is already acquired.
8706ab6bfe3SJack F Vogel  **/
8716ab6bfe3SJack F Vogel s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data)
8726ab6bfe3SJack F Vogel {
8736ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_read_emi_reg_locked");
8746ab6bfe3SJack F Vogel 
8756ab6bfe3SJack F Vogel 	return __e1000_access_emi_reg_locked(hw, addr, data, TRUE);
8766ab6bfe3SJack F Vogel }
8776ab6bfe3SJack F Vogel 
8786ab6bfe3SJack F Vogel /**
8796ab6bfe3SJack F Vogel  *  e1000_write_emi_reg_locked - Write Extended Management Interface register
8806ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
8816ab6bfe3SJack F Vogel  *  @addr: EMI address to program
8826ab6bfe3SJack F Vogel  *  @data: value to be written to the EMI address
8836ab6bfe3SJack F Vogel  *
8846ab6bfe3SJack F Vogel  *  Assumes the SW/FW/HW Semaphore is already acquired.
8856ab6bfe3SJack F Vogel  **/
8867609433eSJack F Vogel s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
8876ab6bfe3SJack F Vogel {
8886ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_read_emi_reg_locked");
8896ab6bfe3SJack F Vogel 
8906ab6bfe3SJack F Vogel 	return __e1000_access_emi_reg_locked(hw, addr, &data, FALSE);
8916ab6bfe3SJack F Vogel }
8926ab6bfe3SJack F Vogel 
8936ab6bfe3SJack F Vogel /**
8947d9119bdSJack F Vogel  *  e1000_set_eee_pchlan - Enable/disable EEE support
8957d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
8967d9119bdSJack F Vogel  *
8976ab6bfe3SJack F Vogel  *  Enable/disable EEE based on setting in dev_spec structure, the duplex of
8986ab6bfe3SJack F Vogel  *  the link and the EEE capabilities of the link partner.  The LPI Control
8996ab6bfe3SJack F Vogel  *  register bits will remain set only if/when link is up.
9007609433eSJack F Vogel  *
9017609433eSJack F Vogel  *  EEE LPI must not be asserted earlier than one second after link is up.
9027609433eSJack F Vogel  *  On 82579, EEE LPI should not be enabled until such time otherwise there
9037609433eSJack F Vogel  *  can be link issues with some switches.  Other devices can have EEE LPI
9047609433eSJack F Vogel  *  enabled immediately upon link up since they have a timer in hardware which
9057609433eSJack F Vogel  *  prevents LPI from being asserted too early.
9067d9119bdSJack F Vogel  **/
9077609433eSJack F Vogel s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
9087d9119bdSJack F Vogel {
9094dab5c37SJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
9106ab6bfe3SJack F Vogel 	s32 ret_val;
9117609433eSJack F Vogel 	u16 lpa, pcs_status, adv, adv_addr, lpi_ctrl, data;
9127d9119bdSJack F Vogel 
9137d9119bdSJack F Vogel 	DEBUGFUNC("e1000_set_eee_pchlan");
9147d9119bdSJack F Vogel 
9157609433eSJack F Vogel 	switch (hw->phy.type) {
9167609433eSJack F Vogel 	case e1000_phy_82579:
9177609433eSJack F Vogel 		lpa = I82579_EEE_LP_ABILITY;
9187609433eSJack F Vogel 		pcs_status = I82579_EEE_PCS_STATUS;
9197609433eSJack F Vogel 		adv_addr = I82579_EEE_ADVERTISEMENT;
9207609433eSJack F Vogel 		break;
9217609433eSJack F Vogel 	case e1000_phy_i217:
9227609433eSJack F Vogel 		lpa = I217_EEE_LP_ABILITY;
9237609433eSJack F Vogel 		pcs_status = I217_EEE_PCS_STATUS;
9247609433eSJack F Vogel 		adv_addr = I217_EEE_ADVERTISEMENT;
9257609433eSJack F Vogel 		break;
9267609433eSJack F Vogel 	default:
9276ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
9287609433eSJack F Vogel 	}
9297d9119bdSJack F Vogel 
9306ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
9317d9119bdSJack F Vogel 	if (ret_val)
9327d9119bdSJack F Vogel 		return ret_val;
9336ab6bfe3SJack F Vogel 
9346ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw, I82579_LPI_CTRL, &lpi_ctrl);
9356ab6bfe3SJack F Vogel 	if (ret_val)
9366ab6bfe3SJack F Vogel 		goto release;
9376ab6bfe3SJack F Vogel 
9386ab6bfe3SJack F Vogel 	/* Clear bits that enable EEE in various speeds */
9396ab6bfe3SJack F Vogel 	lpi_ctrl &= ~I82579_LPI_CTRL_ENABLE_MASK;
9406ab6bfe3SJack F Vogel 
9416ab6bfe3SJack F Vogel 	/* Enable EEE if not disabled by user */
9426ab6bfe3SJack F Vogel 	if (!dev_spec->eee_disable) {
9436ab6bfe3SJack F Vogel 		/* Save off link partner's EEE ability */
9446ab6bfe3SJack F Vogel 		ret_val = e1000_read_emi_reg_locked(hw, lpa,
9456ab6bfe3SJack F Vogel 						    &dev_spec->eee_lp_ability);
9466ab6bfe3SJack F Vogel 		if (ret_val)
9476ab6bfe3SJack F Vogel 			goto release;
9486ab6bfe3SJack F Vogel 
9497609433eSJack F Vogel 		/* Read EEE advertisement */
9507609433eSJack F Vogel 		ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &adv);
9517609433eSJack F Vogel 		if (ret_val)
9527609433eSJack F Vogel 			goto release;
9537609433eSJack F Vogel 
9546ab6bfe3SJack F Vogel 		/* Enable EEE only for speeds in which the link partner is
9557609433eSJack F Vogel 		 * EEE capable and for which we advertise EEE.
9566ab6bfe3SJack F Vogel 		 */
9577609433eSJack F Vogel 		if (adv & dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED)
9586ab6bfe3SJack F Vogel 			lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE;
9596ab6bfe3SJack F Vogel 
9607609433eSJack F Vogel 		if (adv & dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) {
9616ab6bfe3SJack F Vogel 			hw->phy.ops.read_reg_locked(hw, PHY_LP_ABILITY, &data);
9626ab6bfe3SJack F Vogel 			if (data & NWAY_LPAR_100TX_FD_CAPS)
9636ab6bfe3SJack F Vogel 				lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE;
9646ab6bfe3SJack F Vogel 			else
9656ab6bfe3SJack F Vogel 				/* EEE is not supported in 100Half, so ignore
9666ab6bfe3SJack F Vogel 				 * partner's EEE in 100 ability if full-duplex
9676ab6bfe3SJack F Vogel 				 * is not advertised.
9686ab6bfe3SJack F Vogel 				 */
9696ab6bfe3SJack F Vogel 				dev_spec->eee_lp_ability &=
9706ab6bfe3SJack F Vogel 				    ~I82579_EEE_100_SUPPORTED;
9716ab6bfe3SJack F Vogel 		}
9727609433eSJack F Vogel 	}
9736ab6bfe3SJack F Vogel 
9748cc64f1eSJack F Vogel 	if (hw->phy.type == e1000_phy_82579) {
9758cc64f1eSJack F Vogel 		ret_val = e1000_read_emi_reg_locked(hw, I82579_LPI_PLL_SHUT,
9768cc64f1eSJack F Vogel 						    &data);
9778cc64f1eSJack F Vogel 		if (ret_val)
9788cc64f1eSJack F Vogel 			goto release;
9798cc64f1eSJack F Vogel 
9808cc64f1eSJack F Vogel 		data &= ~I82579_LPI_100_PLL_SHUT;
9818cc64f1eSJack F Vogel 		ret_val = e1000_write_emi_reg_locked(hw, I82579_LPI_PLL_SHUT,
9828cc64f1eSJack F Vogel 						     data);
9838cc64f1eSJack F Vogel 	}
9848cc64f1eSJack F Vogel 
9856ab6bfe3SJack F Vogel 	/* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */
9866ab6bfe3SJack F Vogel 	ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data);
9876ab6bfe3SJack F Vogel 	if (ret_val)
9886ab6bfe3SJack F Vogel 		goto release;
9896ab6bfe3SJack F Vogel 
9906ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, I82579_LPI_CTRL, lpi_ctrl);
9916ab6bfe3SJack F Vogel release:
9926ab6bfe3SJack F Vogel 	hw->phy.ops.release(hw);
9936ab6bfe3SJack F Vogel 
9946ab6bfe3SJack F Vogel 	return ret_val;
9956ab6bfe3SJack F Vogel }
9966ab6bfe3SJack F Vogel 
9976ab6bfe3SJack F Vogel /**
9986ab6bfe3SJack F Vogel  *  e1000_k1_workaround_lpt_lp - K1 workaround on Lynxpoint-LP
9996ab6bfe3SJack F Vogel  *  @hw:   pointer to the HW structure
10006ab6bfe3SJack F Vogel  *  @link: link up bool flag
10016ab6bfe3SJack F Vogel  *
10026ab6bfe3SJack F Vogel  *  When K1 is enabled for 1Gbps, the MAC can miss 2 DMA completion indications
10036ab6bfe3SJack F Vogel  *  preventing further DMA write requests.  Workaround the issue by disabling
10046ab6bfe3SJack F Vogel  *  the de-assertion of the clock request when in 1Gpbs mode.
10057609433eSJack F Vogel  *  Also, set appropriate Tx re-transmission timeouts for 10 and 100Half link
10067609433eSJack F Vogel  *  speeds in order to avoid Tx hangs.
10076ab6bfe3SJack F Vogel  **/
10086ab6bfe3SJack F Vogel static s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link)
10096ab6bfe3SJack F Vogel {
10106ab6bfe3SJack F Vogel 	u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6);
10117609433eSJack F Vogel 	u32 status = E1000_READ_REG(hw, E1000_STATUS);
10126ab6bfe3SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
10137609433eSJack F Vogel 	u16 reg;
10146ab6bfe3SJack F Vogel 
10157609433eSJack F Vogel 	if (link && (status & E1000_STATUS_SPEED_1000)) {
10166ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
10176ab6bfe3SJack F Vogel 		if (ret_val)
10186ab6bfe3SJack F Vogel 			return ret_val;
10196ab6bfe3SJack F Vogel 
10206ab6bfe3SJack F Vogel 		ret_val =
10216ab6bfe3SJack F Vogel 		    e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
10227609433eSJack F Vogel 					       &reg);
10236ab6bfe3SJack F Vogel 		if (ret_val)
10246ab6bfe3SJack F Vogel 			goto release;
10256ab6bfe3SJack F Vogel 
10266ab6bfe3SJack F Vogel 		ret_val =
10276ab6bfe3SJack F Vogel 		    e1000_write_kmrn_reg_locked(hw,
10286ab6bfe3SJack F Vogel 						E1000_KMRNCTRLSTA_K1_CONFIG,
10297609433eSJack F Vogel 						reg &
10306ab6bfe3SJack F Vogel 						~E1000_KMRNCTRLSTA_K1_ENABLE);
10316ab6bfe3SJack F Vogel 		if (ret_val)
10326ab6bfe3SJack F Vogel 			goto release;
10336ab6bfe3SJack F Vogel 
10346ab6bfe3SJack F Vogel 		usec_delay(10);
10356ab6bfe3SJack F Vogel 
10366ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_FEXTNVM6,
10376ab6bfe3SJack F Vogel 				fextnvm6 | E1000_FEXTNVM6_REQ_PLL_CLK);
10386ab6bfe3SJack F Vogel 
10396ab6bfe3SJack F Vogel 		ret_val =
10406ab6bfe3SJack F Vogel 		    e1000_write_kmrn_reg_locked(hw,
10416ab6bfe3SJack F Vogel 						E1000_KMRNCTRLSTA_K1_CONFIG,
10427609433eSJack F Vogel 						reg);
10436ab6bfe3SJack F Vogel release:
10446ab6bfe3SJack F Vogel 		hw->phy.ops.release(hw);
10456ab6bfe3SJack F Vogel 	} else {
10466ab6bfe3SJack F Vogel 		/* clear FEXTNVM6 bit 8 on link down or 10/100 */
10477609433eSJack F Vogel 		fextnvm6 &= ~E1000_FEXTNVM6_REQ_PLL_CLK;
10487609433eSJack F Vogel 
1049*c80429ceSEric Joyner 		if ((hw->phy.revision > 5) || !link ||
1050*c80429ceSEric Joyner 		    ((status & E1000_STATUS_SPEED_100) &&
10517609433eSJack F Vogel 		     (status & E1000_STATUS_FD)))
10527609433eSJack F Vogel 			goto update_fextnvm6;
10537609433eSJack F Vogel 
10547609433eSJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, I217_INBAND_CTRL, &reg);
10557609433eSJack F Vogel 		if (ret_val)
10567609433eSJack F Vogel 			return ret_val;
10577609433eSJack F Vogel 
10587609433eSJack F Vogel 		/* Clear link status transmit timeout */
10597609433eSJack F Vogel 		reg &= ~I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_MASK;
10607609433eSJack F Vogel 
10617609433eSJack F Vogel 		if (status & E1000_STATUS_SPEED_100) {
10627609433eSJack F Vogel 			/* Set inband Tx timeout to 5x10us for 100Half */
10637609433eSJack F Vogel 			reg |= 5 << I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT;
10647609433eSJack F Vogel 
10657609433eSJack F Vogel 			/* Do not extend the K1 entry latency for 100Half */
10667609433eSJack F Vogel 			fextnvm6 &= ~E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION;
10677609433eSJack F Vogel 		} else {
10687609433eSJack F Vogel 			/* Set inband Tx timeout to 50x10us for 10Full/Half */
10697609433eSJack F Vogel 			reg |= 50 <<
10707609433eSJack F Vogel 			       I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT;
10717609433eSJack F Vogel 
10727609433eSJack F Vogel 			/* Extend the K1 entry latency for 10 Mbps */
10737609433eSJack F Vogel 			fextnvm6 |= E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION;
10747609433eSJack F Vogel 		}
10757609433eSJack F Vogel 
10767609433eSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, I217_INBAND_CTRL, reg);
10777609433eSJack F Vogel 		if (ret_val)
10787609433eSJack F Vogel 			return ret_val;
10797609433eSJack F Vogel 
10807609433eSJack F Vogel update_fextnvm6:
10817609433eSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FEXTNVM6, fextnvm6);
10826ab6bfe3SJack F Vogel 	}
10836ab6bfe3SJack F Vogel 
10846ab6bfe3SJack F Vogel 	return ret_val;
10856ab6bfe3SJack F Vogel }
10866ab6bfe3SJack F Vogel 
1087e373323fSSean Bruno static u64 e1000_ltr2ns(u16 ltr)
1088e373323fSSean Bruno {
1089e373323fSSean Bruno 	u32 value, scale;
1090e373323fSSean Bruno 
1091e373323fSSean Bruno 	/* Determine the latency in nsec based on the LTR value & scale */
1092e373323fSSean Bruno 	value = ltr & E1000_LTRV_VALUE_MASK;
1093e373323fSSean Bruno 	scale = (ltr & E1000_LTRV_SCALE_MASK) >> E1000_LTRV_SCALE_SHIFT;
1094e373323fSSean Bruno 
1095e373323fSSean Bruno 	return value * (1 << (scale * E1000_LTRV_SCALE_FACTOR));
1096e373323fSSean Bruno }
1097e373323fSSean Bruno 
1098e373323fSSean Bruno /**
1099e373323fSSean Bruno  *  e1000_platform_pm_pch_lpt - Set platform power management values
1100e373323fSSean Bruno  *  @hw: pointer to the HW structure
1101e373323fSSean Bruno  *  @link: bool indicating link status
1102e373323fSSean Bruno  *
1103e373323fSSean Bruno  *  Set the Latency Tolerance Reporting (LTR) values for the "PCIe-like"
1104e373323fSSean Bruno  *  GbE MAC in the Lynx Point PCH based on Rx buffer size and link speed
1105e373323fSSean Bruno  *  when link is up (which must not exceed the maximum latency supported
1106e373323fSSean Bruno  *  by the platform), otherwise specify there is no LTR requirement.
1107e373323fSSean Bruno  *  Unlike TRUE-PCIe devices which set the LTR maximum snoop/no-snoop
1108e373323fSSean Bruno  *  latencies in the LTR Extended Capability Structure in the PCIe Extended
1109e373323fSSean Bruno  *  Capability register set, on this device LTR is set by writing the
1110e373323fSSean Bruno  *  equivalent snoop/no-snoop latencies in the LTRV register in the MAC and
1111e373323fSSean Bruno  *  set the SEND bit to send an Intel On-chip System Fabric sideband (IOSF-SB)
1112e373323fSSean Bruno  *  message to the PMC.
1113e373323fSSean Bruno  *
1114e373323fSSean Bruno  *  Use the LTR value to calculate the Optimized Buffer Flush/Fill (OBFF)
1115e373323fSSean Bruno  *  high-water mark.
1116e373323fSSean Bruno  **/
1117e373323fSSean Bruno static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link)
1118e373323fSSean Bruno {
1119e373323fSSean Bruno 	u32 reg = link << (E1000_LTRV_REQ_SHIFT + E1000_LTRV_NOSNOOP_SHIFT) |
1120e373323fSSean Bruno 		  link << E1000_LTRV_REQ_SHIFT | E1000_LTRV_SEND;
1121e373323fSSean Bruno 	u16 lat_enc = 0;	/* latency encoded */
1122e373323fSSean Bruno 	s32 obff_hwm = 0;
1123e373323fSSean Bruno 
1124e373323fSSean Bruno 	DEBUGFUNC("e1000_platform_pm_pch_lpt");
1125e373323fSSean Bruno 
1126e373323fSSean Bruno 	if (link) {
1127e373323fSSean Bruno 		u16 speed, duplex, scale = 0;
1128e373323fSSean Bruno 		u16 max_snoop, max_nosnoop;
1129e373323fSSean Bruno 		u16 max_ltr_enc;	/* max LTR latency encoded */
1130e373323fSSean Bruno 		s64 lat_ns;
1131e373323fSSean Bruno 		s64 value;
1132e373323fSSean Bruno 		u32 rxa;
1133e373323fSSean Bruno 
1134e373323fSSean Bruno 		if (!hw->mac.max_frame_size) {
1135e373323fSSean Bruno 			DEBUGOUT("max_frame_size not set.\n");
1136e373323fSSean Bruno 			return -E1000_ERR_CONFIG;
1137e373323fSSean Bruno 		}
1138e373323fSSean Bruno 
1139e373323fSSean Bruno 		hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
1140e373323fSSean Bruno 		if (!speed) {
1141e373323fSSean Bruno 			DEBUGOUT("Speed not set.\n");
1142e373323fSSean Bruno 			return -E1000_ERR_CONFIG;
1143e373323fSSean Bruno 		}
1144e373323fSSean Bruno 
1145e373323fSSean Bruno 		/* Rx Packet Buffer Allocation size (KB) */
1146e373323fSSean Bruno 		rxa = E1000_READ_REG(hw, E1000_PBA) & E1000_PBA_RXA_MASK;
1147e373323fSSean Bruno 
1148e373323fSSean Bruno 		/* Determine the maximum latency tolerated by the device.
1149e373323fSSean Bruno 		 *
1150e373323fSSean Bruno 		 * Per the PCIe spec, the tolerated latencies are encoded as
1151e373323fSSean Bruno 		 * a 3-bit encoded scale (only 0-5 are valid) multiplied by
1152e373323fSSean Bruno 		 * a 10-bit value (0-1023) to provide a range from 1 ns to
1153e373323fSSean Bruno 		 * 2^25*(2^10-1) ns.  The scale is encoded as 0=2^0ns,
1154e373323fSSean Bruno 		 * 1=2^5ns, 2=2^10ns,...5=2^25ns.
1155e373323fSSean Bruno 		 */
1156e373323fSSean Bruno 		lat_ns = ((s64)rxa * 1024 -
1157e373323fSSean Bruno 			  (2 * (s64)hw->mac.max_frame_size)) * 8 * 1000;
1158e373323fSSean Bruno 		if (lat_ns < 0)
1159e373323fSSean Bruno 			lat_ns = 0;
1160e373323fSSean Bruno 		else
1161e373323fSSean Bruno 			lat_ns /= speed;
1162e373323fSSean Bruno 		value = lat_ns;
1163e373323fSSean Bruno 
1164e373323fSSean Bruno 		while (value > E1000_LTRV_VALUE_MASK) {
1165e373323fSSean Bruno 			scale++;
1166e373323fSSean Bruno 			value = E1000_DIVIDE_ROUND_UP(value, (1 << 5));
1167e373323fSSean Bruno 		}
1168e373323fSSean Bruno 		if (scale > E1000_LTRV_SCALE_MAX) {
1169e373323fSSean Bruno 			DEBUGOUT1("Invalid LTR latency scale %d\n", scale);
1170e373323fSSean Bruno 			return -E1000_ERR_CONFIG;
1171e373323fSSean Bruno 		}
1172e373323fSSean Bruno 		lat_enc = (u16)((scale << E1000_LTRV_SCALE_SHIFT) | value);
1173e373323fSSean Bruno 
1174e373323fSSean Bruno 		/* Determine the maximum latency tolerated by the platform */
1175e373323fSSean Bruno 		e1000_read_pci_cfg(hw, E1000_PCI_LTR_CAP_LPT, &max_snoop);
1176e373323fSSean Bruno 		e1000_read_pci_cfg(hw, E1000_PCI_LTR_CAP_LPT + 2, &max_nosnoop);
1177e373323fSSean Bruno 		max_ltr_enc = E1000_MAX(max_snoop, max_nosnoop);
1178e373323fSSean Bruno 
1179e373323fSSean Bruno 		if (lat_enc > max_ltr_enc) {
1180e373323fSSean Bruno 			lat_enc = max_ltr_enc;
1181e373323fSSean Bruno 			lat_ns = e1000_ltr2ns(max_ltr_enc);
1182e373323fSSean Bruno 		}
1183e373323fSSean Bruno 
1184e373323fSSean Bruno 		if (lat_ns) {
1185e373323fSSean Bruno 			lat_ns *= speed * 1000;
1186e373323fSSean Bruno 			lat_ns /= 8;
1187e373323fSSean Bruno 			lat_ns /= 1000000000;
1188e373323fSSean Bruno 			obff_hwm = (s32)(rxa - lat_ns);
1189e373323fSSean Bruno 		}
1190e373323fSSean Bruno 		if ((obff_hwm < 0) || (obff_hwm > E1000_SVT_OFF_HWM_MASK)) {
1191e373323fSSean Bruno 			DEBUGOUT1("Invalid high water mark %d\n", obff_hwm);
1192e373323fSSean Bruno 			return -E1000_ERR_CONFIG;
1193e373323fSSean Bruno 		}
1194e373323fSSean Bruno 	}
1195e373323fSSean Bruno 
1196e373323fSSean Bruno 	/* Set Snoop and No-Snoop latencies the same */
1197e373323fSSean Bruno 	reg |= lat_enc | (lat_enc << E1000_LTRV_NOSNOOP_SHIFT);
1198e373323fSSean Bruno 	E1000_WRITE_REG(hw, E1000_LTRV, reg);
1199e373323fSSean Bruno 
1200e373323fSSean Bruno 	/* Set OBFF high water mark */
1201e373323fSSean Bruno 	reg = E1000_READ_REG(hw, E1000_SVT) & ~E1000_SVT_OFF_HWM_MASK;
1202e373323fSSean Bruno 	reg |= obff_hwm;
1203e373323fSSean Bruno 	E1000_WRITE_REG(hw, E1000_SVT, reg);
1204e373323fSSean Bruno 
1205e373323fSSean Bruno 	/* Enable OBFF */
1206e373323fSSean Bruno 	reg = E1000_READ_REG(hw, E1000_SVCR);
1207e373323fSSean Bruno 	reg |= E1000_SVCR_OFF_EN;
1208e373323fSSean Bruno 	/* Always unblock interrupts to the CPU even when the system is
1209e373323fSSean Bruno 	 * in OBFF mode. This ensures that small round-robin traffic
1210e373323fSSean Bruno 	 * (like ping) does not get dropped or experience long latency.
1211e373323fSSean Bruno 	 */
1212e373323fSSean Bruno 	reg |= E1000_SVCR_OFF_MASKINT;
1213e373323fSSean Bruno 	E1000_WRITE_REG(hw, E1000_SVCR, reg);
1214e373323fSSean Bruno 
1215e373323fSSean Bruno 	return E1000_SUCCESS;
1216e373323fSSean Bruno }
1217e373323fSSean Bruno 
1218e373323fSSean Bruno /**
1219e373323fSSean Bruno  *  e1000_set_obff_timer_pch_lpt - Update Optimized Buffer Flush/Fill timer
1220e373323fSSean Bruno  *  @hw: pointer to the HW structure
1221e373323fSSean Bruno  *  @itr: interrupt throttling rate
1222e373323fSSean Bruno  *
1223e373323fSSean Bruno  *  Configure OBFF with the updated interrupt rate.
1224e373323fSSean Bruno  **/
1225e373323fSSean Bruno static s32 e1000_set_obff_timer_pch_lpt(struct e1000_hw *hw, u32 itr)
1226e373323fSSean Bruno {
1227e373323fSSean Bruno 	u32 svcr;
1228e373323fSSean Bruno 	s32 timer;
1229e373323fSSean Bruno 
1230e373323fSSean Bruno 	DEBUGFUNC("e1000_set_obff_timer_pch_lpt");
1231e373323fSSean Bruno 
1232e373323fSSean Bruno 	/* Convert ITR value into microseconds for OBFF timer */
1233e373323fSSean Bruno 	timer = itr & E1000_ITR_MASK;
1234e373323fSSean Bruno 	timer = (timer * E1000_ITR_MULT) / 1000;
1235e373323fSSean Bruno 
1236e373323fSSean Bruno 	if ((timer < 0) || (timer > E1000_ITR_MASK)) {
1237e373323fSSean Bruno 		DEBUGOUT1("Invalid OBFF timer %d\n", timer);
1238e373323fSSean Bruno 		return -E1000_ERR_CONFIG;
1239e373323fSSean Bruno 	}
1240e373323fSSean Bruno 
1241e373323fSSean Bruno 	svcr = E1000_READ_REG(hw, E1000_SVCR);
1242e373323fSSean Bruno 	svcr &= ~E1000_SVCR_OFF_TIMER_MASK;
1243e373323fSSean Bruno 	svcr |= timer << E1000_SVCR_OFF_TIMER_SHIFT;
1244e373323fSSean Bruno 	E1000_WRITE_REG(hw, E1000_SVCR, svcr);
1245e373323fSSean Bruno 
1246e373323fSSean Bruno 	return E1000_SUCCESS;
1247e373323fSSean Bruno }
1248e373323fSSean Bruno 
12497d9119bdSJack F Vogel /**
12508cc64f1eSJack F Vogel  *  e1000_enable_ulp_lpt_lp - configure Ultra Low Power mode for LynxPoint-LP
12518cc64f1eSJack F Vogel  *  @hw: pointer to the HW structure
12528cc64f1eSJack F Vogel  *  @to_sx: boolean indicating a system power state transition to Sx
12538cc64f1eSJack F Vogel  *
12548cc64f1eSJack F Vogel  *  When link is down, configure ULP mode to significantly reduce the power
12558cc64f1eSJack F Vogel  *  to the PHY.  If on a Manageability Engine (ME) enabled system, tell the
12568cc64f1eSJack F Vogel  *  ME firmware to start the ULP configuration.  If not on an ME enabled
12578cc64f1eSJack F Vogel  *  system, configure the ULP mode by software.
12588cc64f1eSJack F Vogel  */
12598cc64f1eSJack F Vogel s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
12608cc64f1eSJack F Vogel {
12618cc64f1eSJack F Vogel 	u32 mac_reg;
12628cc64f1eSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
12638cc64f1eSJack F Vogel 	u16 phy_reg;
1264*c80429ceSEric Joyner 	u16 oem_reg = 0;
12658cc64f1eSJack F Vogel 
12668cc64f1eSJack F Vogel 	if ((hw->mac.type < e1000_pch_lpt) ||
12678cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) ||
12688cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V) ||
12698cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_LM2) ||
12708cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_V2) ||
12718cc64f1eSJack F Vogel 	    (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_on))
12728cc64f1eSJack F Vogel 		return 0;
12738cc64f1eSJack F Vogel 
12748cc64f1eSJack F Vogel 	if (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID) {
12758cc64f1eSJack F Vogel 		/* Request ME configure ULP mode in the PHY */
12768cc64f1eSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_H2ME);
12778cc64f1eSJack F Vogel 		mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS;
12788cc64f1eSJack F Vogel 		E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
12798cc64f1eSJack F Vogel 
12808cc64f1eSJack F Vogel 		goto out;
12818cc64f1eSJack F Vogel 	}
12828cc64f1eSJack F Vogel 
12838cc64f1eSJack F Vogel 	if (!to_sx) {
12848cc64f1eSJack F Vogel 		int i = 0;
12858cc64f1eSJack F Vogel 
12868cc64f1eSJack F Vogel 		/* Poll up to 5 seconds for Cable Disconnected indication */
12878cc64f1eSJack F Vogel 		while (!(E1000_READ_REG(hw, E1000_FEXT) &
12888cc64f1eSJack F Vogel 			 E1000_FEXT_PHY_CABLE_DISCONNECTED)) {
12898cc64f1eSJack F Vogel 			/* Bail if link is re-acquired */
12908cc64f1eSJack F Vogel 			if (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)
12918cc64f1eSJack F Vogel 				return -E1000_ERR_PHY;
12928cc64f1eSJack F Vogel 
12938cc64f1eSJack F Vogel 			if (i++ == 100)
12948cc64f1eSJack F Vogel 				break;
12958cc64f1eSJack F Vogel 
12968cc64f1eSJack F Vogel 			msec_delay(50);
12978cc64f1eSJack F Vogel 		}
12988cc64f1eSJack F Vogel 		DEBUGOUT2("CABLE_DISCONNECTED %s set after %dmsec\n",
12998cc64f1eSJack F Vogel 			 (E1000_READ_REG(hw, E1000_FEXT) &
13008cc64f1eSJack F Vogel 			  E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not",
13018cc64f1eSJack F Vogel 			 i * 50);
13028cc64f1eSJack F Vogel 	}
13038cc64f1eSJack F Vogel 
13048cc64f1eSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
13058cc64f1eSJack F Vogel 	if (ret_val)
13068cc64f1eSJack F Vogel 		goto out;
13078cc64f1eSJack F Vogel 
13088cc64f1eSJack F Vogel 	/* Force SMBus mode in PHY */
13098cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
13108cc64f1eSJack F Vogel 	if (ret_val)
13118cc64f1eSJack F Vogel 		goto release;
13128cc64f1eSJack F Vogel 	phy_reg |= CV_SMB_CTRL_FORCE_SMBUS;
13138cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
13148cc64f1eSJack F Vogel 
13158cc64f1eSJack F Vogel 	/* Force SMBus mode in MAC */
13168cc64f1eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
13178cc64f1eSJack F Vogel 	mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
13188cc64f1eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
13198cc64f1eSJack F Vogel 
1320*c80429ceSEric Joyner 	/* Si workaround for ULP entry flow on i127/rev6 h/w.  Enable
1321*c80429ceSEric Joyner 	 * LPLU and disable Gig speed when entering ULP
1322*c80429ceSEric Joyner 	 */
1323*c80429ceSEric Joyner 	if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6)) {
1324*c80429ceSEric Joyner 		ret_val = e1000_read_phy_reg_hv_locked(hw, HV_OEM_BITS,
1325*c80429ceSEric Joyner 						       &oem_reg);
1326*c80429ceSEric Joyner 		if (ret_val)
1327*c80429ceSEric Joyner 			goto release;
1328*c80429ceSEric Joyner 
1329*c80429ceSEric Joyner 		phy_reg = oem_reg;
1330*c80429ceSEric Joyner 		phy_reg |= HV_OEM_BITS_LPLU | HV_OEM_BITS_GBE_DIS;
1331*c80429ceSEric Joyner 
1332*c80429ceSEric Joyner 		ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS,
1333*c80429ceSEric Joyner 							phy_reg);
1334*c80429ceSEric Joyner 
1335*c80429ceSEric Joyner 		if (ret_val)
1336*c80429ceSEric Joyner 			goto release;
1337*c80429ceSEric Joyner 	}
1338*c80429ceSEric Joyner 
13398cc64f1eSJack F Vogel 	/* Set Inband ULP Exit, Reset to SMBus mode and
13408cc64f1eSJack F Vogel 	 * Disable SMBus Release on PERST# in PHY
13418cc64f1eSJack F Vogel 	 */
13428cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
13438cc64f1eSJack F Vogel 	if (ret_val)
13448cc64f1eSJack F Vogel 		goto release;
13458cc64f1eSJack F Vogel 	phy_reg |= (I218_ULP_CONFIG1_RESET_TO_SMBUS |
13468cc64f1eSJack F Vogel 		    I218_ULP_CONFIG1_DISABLE_SMB_PERST);
13478cc64f1eSJack F Vogel 	if (to_sx) {
13488cc64f1eSJack F Vogel 		if (E1000_READ_REG(hw, E1000_WUFC) & E1000_WUFC_LNKC)
13498cc64f1eSJack F Vogel 			phy_reg |= I218_ULP_CONFIG1_WOL_HOST;
1350*c80429ceSEric Joyner 		else
1351*c80429ceSEric Joyner 			phy_reg &= ~I218_ULP_CONFIG1_WOL_HOST;
13528cc64f1eSJack F Vogel 
13538cc64f1eSJack F Vogel 		phy_reg |= I218_ULP_CONFIG1_STICKY_ULP;
1354*c80429ceSEric Joyner 		phy_reg &= ~I218_ULP_CONFIG1_INBAND_EXIT;
13558cc64f1eSJack F Vogel 	} else {
13568cc64f1eSJack F Vogel 		phy_reg |= I218_ULP_CONFIG1_INBAND_EXIT;
1357*c80429ceSEric Joyner 		phy_reg &= ~I218_ULP_CONFIG1_STICKY_ULP;
1358*c80429ceSEric Joyner 		phy_reg &= ~I218_ULP_CONFIG1_WOL_HOST;
13598cc64f1eSJack F Vogel 	}
13608cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
13618cc64f1eSJack F Vogel 
13628cc64f1eSJack F Vogel 	/* Set Disable SMBus Release on PERST# in MAC */
13638cc64f1eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM7);
13648cc64f1eSJack F Vogel 	mac_reg |= E1000_FEXTNVM7_DISABLE_SMB_PERST;
13658cc64f1eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_FEXTNVM7, mac_reg);
13668cc64f1eSJack F Vogel 
13678cc64f1eSJack F Vogel 	/* Commit ULP changes in PHY by starting auto ULP configuration */
13688cc64f1eSJack F Vogel 	phy_reg |= I218_ULP_CONFIG1_START;
13698cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
1370*c80429ceSEric Joyner 
1371*c80429ceSEric Joyner 	if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6) &&
1372*c80429ceSEric Joyner 	    to_sx && (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
1373*c80429ceSEric Joyner 		ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS,
1374*c80429ceSEric Joyner 							oem_reg);
1375*c80429ceSEric Joyner 		if (ret_val)
1376*c80429ceSEric Joyner 			goto release;
1377*c80429ceSEric Joyner 	}
1378*c80429ceSEric Joyner 
13798cc64f1eSJack F Vogel release:
13808cc64f1eSJack F Vogel 	hw->phy.ops.release(hw);
13818cc64f1eSJack F Vogel out:
13828cc64f1eSJack F Vogel 	if (ret_val)
13838cc64f1eSJack F Vogel 		DEBUGOUT1("Error in ULP enable flow: %d\n", ret_val);
13848cc64f1eSJack F Vogel 	else
13858cc64f1eSJack F Vogel 		hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_on;
13868cc64f1eSJack F Vogel 
13878cc64f1eSJack F Vogel 	return ret_val;
13888cc64f1eSJack F Vogel }
13898cc64f1eSJack F Vogel 
13908cc64f1eSJack F Vogel /**
13918cc64f1eSJack F Vogel  *  e1000_disable_ulp_lpt_lp - unconfigure Ultra Low Power mode for LynxPoint-LP
13928cc64f1eSJack F Vogel  *  @hw: pointer to the HW structure
13938cc64f1eSJack F Vogel  *  @force: boolean indicating whether or not to force disabling ULP
13948cc64f1eSJack F Vogel  *
13958cc64f1eSJack F Vogel  *  Un-configure ULP mode when link is up, the system is transitioned from
13968cc64f1eSJack F Vogel  *  Sx or the driver is unloaded.  If on a Manageability Engine (ME) enabled
13978cc64f1eSJack F Vogel  *  system, poll for an indication from ME that ULP has been un-configured.
13988cc64f1eSJack F Vogel  *  If not on an ME enabled system, un-configure the ULP mode by software.
13998cc64f1eSJack F Vogel  *
14008cc64f1eSJack F Vogel  *  During nominal operation, this function is called when link is acquired
14018cc64f1eSJack F Vogel  *  to disable ULP mode (force=FALSE); otherwise, for example when unloading
14028cc64f1eSJack F Vogel  *  the driver or during Sx->S0 transitions, this is called with force=TRUE
14038cc64f1eSJack F Vogel  *  to forcibly disable ULP.
14048cc64f1eSJack F Vogel  */
14058cc64f1eSJack F Vogel s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
14068cc64f1eSJack F Vogel {
14078cc64f1eSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
14088cc64f1eSJack F Vogel 	u32 mac_reg;
14098cc64f1eSJack F Vogel 	u16 phy_reg;
14108cc64f1eSJack F Vogel 	int i = 0;
14118cc64f1eSJack F Vogel 
14128cc64f1eSJack F Vogel 	if ((hw->mac.type < e1000_pch_lpt) ||
14138cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) ||
14148cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V) ||
14158cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_LM2) ||
14168cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_V2) ||
14178cc64f1eSJack F Vogel 	    (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_off))
14188cc64f1eSJack F Vogel 		return 0;
14198cc64f1eSJack F Vogel 
14208cc64f1eSJack F Vogel 	if (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID) {
14218cc64f1eSJack F Vogel 		if (force) {
14228cc64f1eSJack F Vogel 			/* Request ME un-configure ULP mode in the PHY */
14238cc64f1eSJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_H2ME);
14248cc64f1eSJack F Vogel 			mac_reg &= ~E1000_H2ME_ULP;
14258cc64f1eSJack F Vogel 			mac_reg |= E1000_H2ME_ENFORCE_SETTINGS;
14268cc64f1eSJack F Vogel 			E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
14278cc64f1eSJack F Vogel 		}
14288cc64f1eSJack F Vogel 
1429*c80429ceSEric Joyner 		/* Poll up to 300msec for ME to clear ULP_CFG_DONE. */
14308cc64f1eSJack F Vogel 		while (E1000_READ_REG(hw, E1000_FWSM) &
14318cc64f1eSJack F Vogel 		       E1000_FWSM_ULP_CFG_DONE) {
1432*c80429ceSEric Joyner 			if (i++ == 30) {
14338cc64f1eSJack F Vogel 				ret_val = -E1000_ERR_PHY;
14348cc64f1eSJack F Vogel 				goto out;
14358cc64f1eSJack F Vogel 			}
14368cc64f1eSJack F Vogel 
14378cc64f1eSJack F Vogel 			msec_delay(10);
14388cc64f1eSJack F Vogel 		}
14398cc64f1eSJack F Vogel 		DEBUGOUT1("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10);
14408cc64f1eSJack F Vogel 
14418cc64f1eSJack F Vogel 		if (force) {
14428cc64f1eSJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_H2ME);
14438cc64f1eSJack F Vogel 			mac_reg &= ~E1000_H2ME_ENFORCE_SETTINGS;
14448cc64f1eSJack F Vogel 			E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
14458cc64f1eSJack F Vogel 		} else {
14468cc64f1eSJack F Vogel 			/* Clear H2ME.ULP after ME ULP configuration */
14478cc64f1eSJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_H2ME);
14488cc64f1eSJack F Vogel 			mac_reg &= ~E1000_H2ME_ULP;
14498cc64f1eSJack F Vogel 			E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
14508cc64f1eSJack F Vogel 		}
14518cc64f1eSJack F Vogel 
14528cc64f1eSJack F Vogel 		goto out;
14538cc64f1eSJack F Vogel 	}
14548cc64f1eSJack F Vogel 
14558cc64f1eSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
14568cc64f1eSJack F Vogel 	if (ret_val)
14578cc64f1eSJack F Vogel 		goto out;
14588cc64f1eSJack F Vogel 
14598cc64f1eSJack F Vogel 	if (force)
14608cc64f1eSJack F Vogel 		/* Toggle LANPHYPC Value bit */
14618cc64f1eSJack F Vogel 		e1000_toggle_lanphypc_pch_lpt(hw);
14628cc64f1eSJack F Vogel 
14638cc64f1eSJack F Vogel 	/* Unforce SMBus mode in PHY */
14648cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
14658cc64f1eSJack F Vogel 	if (ret_val) {
14668cc64f1eSJack F Vogel 		/* The MAC might be in PCIe mode, so temporarily force to
14678cc64f1eSJack F Vogel 		 * SMBus mode in order to access the PHY.
14688cc64f1eSJack F Vogel 		 */
14698cc64f1eSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
14708cc64f1eSJack F Vogel 		mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
14718cc64f1eSJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
14728cc64f1eSJack F Vogel 
14738cc64f1eSJack F Vogel 		msec_delay(50);
14748cc64f1eSJack F Vogel 
14758cc64f1eSJack F Vogel 		ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL,
14768cc64f1eSJack F Vogel 						       &phy_reg);
14778cc64f1eSJack F Vogel 		if (ret_val)
14788cc64f1eSJack F Vogel 			goto release;
14798cc64f1eSJack F Vogel 	}
14808cc64f1eSJack F Vogel 	phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
14818cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
14828cc64f1eSJack F Vogel 
14838cc64f1eSJack F Vogel 	/* Unforce SMBus mode in MAC */
14848cc64f1eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
14858cc64f1eSJack F Vogel 	mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
14868cc64f1eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
14878cc64f1eSJack F Vogel 
14888cc64f1eSJack F Vogel 	/* When ULP mode was previously entered, K1 was disabled by the
14898cc64f1eSJack F Vogel 	 * hardware.  Re-Enable K1 in the PHY when exiting ULP.
14908cc64f1eSJack F Vogel 	 */
14918cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, HV_PM_CTRL, &phy_reg);
14928cc64f1eSJack F Vogel 	if (ret_val)
14938cc64f1eSJack F Vogel 		goto release;
14948cc64f1eSJack F Vogel 	phy_reg |= HV_PM_CTRL_K1_ENABLE;
14958cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, HV_PM_CTRL, phy_reg);
14968cc64f1eSJack F Vogel 
14978cc64f1eSJack F Vogel 	/* Clear ULP enabled configuration */
14988cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
14998cc64f1eSJack F Vogel 	if (ret_val)
15008cc64f1eSJack F Vogel 		goto release;
15018cc64f1eSJack F Vogel 		phy_reg &= ~(I218_ULP_CONFIG1_IND |
15028cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_STICKY_ULP |
15038cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_RESET_TO_SMBUS |
15048cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_WOL_HOST |
15058cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_INBAND_EXIT |
1506*c80429ceSEric Joyner 			     I218_ULP_CONFIG1_EN_ULP_LANPHYPC |
1507*c80429ceSEric Joyner 			     I218_ULP_CONFIG1_DIS_CLR_STICKY_ON_PERST |
15088cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_DISABLE_SMB_PERST);
15098cc64f1eSJack F Vogel 		e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
15108cc64f1eSJack F Vogel 
15118cc64f1eSJack F Vogel 		/* Commit ULP changes by starting auto ULP configuration */
15128cc64f1eSJack F Vogel 		phy_reg |= I218_ULP_CONFIG1_START;
15138cc64f1eSJack F Vogel 		e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
15148cc64f1eSJack F Vogel 
15158cc64f1eSJack F Vogel 		/* Clear Disable SMBus Release on PERST# in MAC */
15168cc64f1eSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM7);
15178cc64f1eSJack F Vogel 		mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST;
15188cc64f1eSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FEXTNVM7, mac_reg);
15198cc64f1eSJack F Vogel 
15208cc64f1eSJack F Vogel release:
15218cc64f1eSJack F Vogel 	hw->phy.ops.release(hw);
15228cc64f1eSJack F Vogel 	if (force) {
15238cc64f1eSJack F Vogel 		hw->phy.ops.reset(hw);
15248cc64f1eSJack F Vogel 		msec_delay(50);
15258cc64f1eSJack F Vogel 	}
15268cc64f1eSJack F Vogel out:
15278cc64f1eSJack F Vogel 	if (ret_val)
15288cc64f1eSJack F Vogel 		DEBUGOUT1("Error in ULP disable flow: %d\n", ret_val);
15298cc64f1eSJack F Vogel 	else
15308cc64f1eSJack F Vogel 		hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_off;
15318cc64f1eSJack F Vogel 
15328cc64f1eSJack F Vogel 	return ret_val;
15338cc64f1eSJack F Vogel }
15348cc64f1eSJack F Vogel 
15358cc64f1eSJack F Vogel /**
15364edd8523SJack F Vogel  *  e1000_check_for_copper_link_ich8lan - Check for link (Copper)
15374edd8523SJack F Vogel  *  @hw: pointer to the HW structure
15384edd8523SJack F Vogel  *
15394edd8523SJack F Vogel  *  Checks to see of the link status of the hardware has changed.  If a
15404edd8523SJack F Vogel  *  change in link status has been detected, then we read the PHY registers
15414edd8523SJack F Vogel  *  to get the current speed/duplex if link exists.
15424edd8523SJack F Vogel  **/
15434edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
15444edd8523SJack F Vogel {
15454edd8523SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
1546*c80429ceSEric Joyner 	s32 ret_val, tipg_reg = 0;
1547*c80429ceSEric Joyner 	u16 emi_addr, emi_val = 0;
15484edd8523SJack F Vogel 	bool link;
15494dab5c37SJack F Vogel 	u16 phy_reg;
15504edd8523SJack F Vogel 
15514edd8523SJack F Vogel 	DEBUGFUNC("e1000_check_for_copper_link_ich8lan");
15524edd8523SJack F Vogel 
15536ab6bfe3SJack F Vogel 	/* We only want to go out to the PHY registers to see if Auto-Neg
15544edd8523SJack F Vogel 	 * has completed and/or if our link status has changed.  The
15554edd8523SJack F Vogel 	 * get_link_status flag is set upon receiving a Link Status
15564edd8523SJack F Vogel 	 * Change or Rx Sequence Error interrupt.
15574edd8523SJack F Vogel 	 */
15586ab6bfe3SJack F Vogel 	if (!mac->get_link_status)
15596ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
15604edd8523SJack F Vogel 
15616ab6bfe3SJack F Vogel 		/* First we want to see if the MII Status Register reports
15624edd8523SJack F Vogel 		 * link.  If so, then we want to get the current speed/duplex
15634edd8523SJack F Vogel 		 * of the PHY.
15644edd8523SJack F Vogel 		 */
15654edd8523SJack F Vogel 		ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
15664edd8523SJack F Vogel 		if (ret_val)
15676ab6bfe3SJack F Vogel 			return ret_val;
15684edd8523SJack F Vogel 
15694edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan) {
15704edd8523SJack F Vogel 		ret_val = e1000_k1_gig_workaround_hv(hw, link);
15714edd8523SJack F Vogel 		if (ret_val)
15726ab6bfe3SJack F Vogel 			return ret_val;
15734edd8523SJack F Vogel 	}
15744edd8523SJack F Vogel 
15758cc64f1eSJack F Vogel 	/* When connected at 10Mbps half-duplex, some parts are excessively
15766ab6bfe3SJack F Vogel 	 * aggressive resulting in many collisions. To avoid this, increase
15776ab6bfe3SJack F Vogel 	 * the IPG and reduce Rx latency in the PHY.
15786ab6bfe3SJack F Vogel 	 */
15798cc64f1eSJack F Vogel 	if (((hw->mac.type == e1000_pch2lan) ||
1580*c80429ceSEric Joyner 	     (hw->mac.type == e1000_pch_lpt) ||
1581*c80429ceSEric Joyner 	     (hw->mac.type == e1000_pch_spt)) && link) {
1582*c80429ceSEric Joyner 		u16 speed, duplex;
15838cc64f1eSJack F Vogel 
1584*c80429ceSEric Joyner 		e1000_get_speed_and_duplex_copper_generic(hw, &speed, &duplex);
1585*c80429ceSEric Joyner 		tipg_reg = E1000_READ_REG(hw, E1000_TIPG);
1586*c80429ceSEric Joyner 		tipg_reg &= ~E1000_TIPG_IPGT_MASK;
15876ab6bfe3SJack F Vogel 
1588*c80429ceSEric Joyner 		if (duplex == HALF_DUPLEX && speed == SPEED_10) {
1589*c80429ceSEric Joyner 			tipg_reg |= 0xFF;
15906ab6bfe3SJack F Vogel 			/* Reduce Rx latency in analog PHY */
1591*c80429ceSEric Joyner 			emi_val = 0;
1592*c80429ceSEric Joyner 		} else if (hw->mac.type == e1000_pch_spt &&
1593*c80429ceSEric Joyner 			   duplex == FULL_DUPLEX && speed != SPEED_1000) {
1594*c80429ceSEric Joyner 			tipg_reg |= 0xC;
1595*c80429ceSEric Joyner 			emi_val = 1;
1596*c80429ceSEric Joyner 		} else {
1597*c80429ceSEric Joyner 			/* Roll back the default values */
1598*c80429ceSEric Joyner 			tipg_reg |= 0x08;
1599*c80429ceSEric Joyner 			emi_val = 1;
1600*c80429ceSEric Joyner 		}
1601*c80429ceSEric Joyner 
1602*c80429ceSEric Joyner 		E1000_WRITE_REG(hw, E1000_TIPG, tipg_reg);
1603*c80429ceSEric Joyner 
16046ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
16056ab6bfe3SJack F Vogel 		if (ret_val)
16066ab6bfe3SJack F Vogel 			return ret_val;
16076ab6bfe3SJack F Vogel 
16088cc64f1eSJack F Vogel 		if (hw->mac.type == e1000_pch2lan)
16098cc64f1eSJack F Vogel 			emi_addr = I82579_RX_CONFIG;
16108cc64f1eSJack F Vogel 		else
16118cc64f1eSJack F Vogel 			emi_addr = I217_RX_CONFIG;
1612*c80429ceSEric Joyner 		ret_val = e1000_write_emi_reg_locked(hw, emi_addr, emi_val);
16136ab6bfe3SJack F Vogel 
1614*c80429ceSEric Joyner 		if (hw->mac.type == e1000_pch_lpt ||
1615*c80429ceSEric Joyner 		    hw->mac.type == e1000_pch_spt) {
1616*c80429ceSEric Joyner 			u16 phy_reg;
1617*c80429ceSEric Joyner 
1618*c80429ceSEric Joyner 			hw->phy.ops.read_reg_locked(hw, I217_PLL_CLOCK_GATE_REG,
1619*c80429ceSEric Joyner 						    &phy_reg);
1620*c80429ceSEric Joyner 			phy_reg &= ~I217_PLL_CLOCK_GATE_MASK;
1621*c80429ceSEric Joyner 			if (speed == SPEED_100 || speed == SPEED_10)
1622*c80429ceSEric Joyner 				phy_reg |= 0x3E8;
1623*c80429ceSEric Joyner 			else
1624*c80429ceSEric Joyner 				phy_reg |= 0xFA;
1625*c80429ceSEric Joyner 			hw->phy.ops.write_reg_locked(hw,
1626*c80429ceSEric Joyner 						     I217_PLL_CLOCK_GATE_REG,
1627*c80429ceSEric Joyner 						     phy_reg);
1628*c80429ceSEric Joyner 		}
16296ab6bfe3SJack F Vogel 		hw->phy.ops.release(hw);
16306ab6bfe3SJack F Vogel 
16316ab6bfe3SJack F Vogel 		if (ret_val)
16326ab6bfe3SJack F Vogel 			return ret_val;
1633*c80429ceSEric Joyner 
1634*c80429ceSEric Joyner 		if (hw->mac.type == e1000_pch_spt) {
1635*c80429ceSEric Joyner 			u16 data;
1636*c80429ceSEric Joyner 			u16 ptr_gap;
1637*c80429ceSEric Joyner 
1638*c80429ceSEric Joyner 			if (speed == SPEED_1000) {
1639*c80429ceSEric Joyner 				ret_val = hw->phy.ops.acquire(hw);
1640*c80429ceSEric Joyner 				if (ret_val)
1641*c80429ceSEric Joyner 					return ret_val;
1642*c80429ceSEric Joyner 
1643*c80429ceSEric Joyner 				ret_val = hw->phy.ops.read_reg_locked(hw,
1644*c80429ceSEric Joyner 							      PHY_REG(776, 20),
1645*c80429ceSEric Joyner 							      &data);
1646*c80429ceSEric Joyner 				if (ret_val) {
1647*c80429ceSEric Joyner 					hw->phy.ops.release(hw);
1648*c80429ceSEric Joyner 					return ret_val;
16496ab6bfe3SJack F Vogel 				}
1650*c80429ceSEric Joyner 
1651*c80429ceSEric Joyner 				ptr_gap = (data & (0x3FF << 2)) >> 2;
1652*c80429ceSEric Joyner 				if (ptr_gap < 0x18) {
1653*c80429ceSEric Joyner 					data &= ~(0x3FF << 2);
1654*c80429ceSEric Joyner 					data |= (0x18 << 2);
1655*c80429ceSEric Joyner 					ret_val =
1656*c80429ceSEric Joyner 						hw->phy.ops.write_reg_locked(hw,
1657*c80429ceSEric Joyner 							PHY_REG(776, 20), data);
1658*c80429ceSEric Joyner 				}
1659*c80429ceSEric Joyner 				hw->phy.ops.release(hw);
1660*c80429ceSEric Joyner 				if (ret_val)
1661*c80429ceSEric Joyner 					return ret_val;
1662*c80429ceSEric Joyner 			} else {
1663*c80429ceSEric Joyner 				ret_val = hw->phy.ops.acquire(hw);
1664*c80429ceSEric Joyner 				if (ret_val)
1665*c80429ceSEric Joyner 					return ret_val;
1666*c80429ceSEric Joyner 
1667*c80429ceSEric Joyner 				ret_val = hw->phy.ops.write_reg_locked(hw,
1668*c80429ceSEric Joyner 							     PHY_REG(776, 20),
1669*c80429ceSEric Joyner 							     0xC023);
1670*c80429ceSEric Joyner 				hw->phy.ops.release(hw);
1671*c80429ceSEric Joyner 				if (ret_val)
1672*c80429ceSEric Joyner 					return ret_val;
1673*c80429ceSEric Joyner 
1674*c80429ceSEric Joyner 			}
1675*c80429ceSEric Joyner 		}
1676*c80429ceSEric Joyner 	}
1677*c80429ceSEric Joyner 
1678*c80429ceSEric Joyner 	/* I217 Packet Loss issue:
1679*c80429ceSEric Joyner 	 * ensure that FEXTNVM4 Beacon Duration is set correctly
1680*c80429ceSEric Joyner 	 * on power up.
1681*c80429ceSEric Joyner 	 * Set the Beacon Duration for I217 to 8 usec
1682*c80429ceSEric Joyner 	 */
1683*c80429ceSEric Joyner 	if ((hw->mac.type == e1000_pch_lpt) ||
1684*c80429ceSEric Joyner 	    (hw->mac.type == e1000_pch_spt)) {
1685*c80429ceSEric Joyner 		u32 mac_reg;
1686*c80429ceSEric Joyner 
1687*c80429ceSEric Joyner 		mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4);
1688*c80429ceSEric Joyner 		mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
1689*c80429ceSEric Joyner 		mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
1690*c80429ceSEric Joyner 		E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg);
16916ab6bfe3SJack F Vogel 	}
16926ab6bfe3SJack F Vogel 
16936ab6bfe3SJack F Vogel 	/* Work-around I218 hang issue */
16946ab6bfe3SJack F Vogel 	if ((hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
16958cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) ||
16968cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_LM3) ||
16978cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_V3)) {
16986ab6bfe3SJack F Vogel 		ret_val = e1000_k1_workaround_lpt_lp(hw, link);
16996ab6bfe3SJack F Vogel 		if (ret_val)
17006ab6bfe3SJack F Vogel 			return ret_val;
17016ab6bfe3SJack F Vogel 	}
1702*c80429ceSEric Joyner 	if ((hw->mac.type == e1000_pch_lpt) ||
1703*c80429ceSEric Joyner 	    (hw->mac.type == e1000_pch_spt)) {
1704e373323fSSean Bruno 		/* Set platform power management values for
1705e373323fSSean Bruno 		 * Latency Tolerance Reporting (LTR)
1706e373323fSSean Bruno 		 * Optimized Buffer Flush/Fill (OBFF)
1707e373323fSSean Bruno 		 */
1708e373323fSSean Bruno 		ret_val = e1000_platform_pm_pch_lpt(hw, link);
1709e373323fSSean Bruno 		if (ret_val)
1710e373323fSSean Bruno 			return ret_val;
1711e373323fSSean Bruno 	}
1712e373323fSSean Bruno 
17136ab6bfe3SJack F Vogel 	/* Clear link partner's EEE ability */
17146ab6bfe3SJack F Vogel 	hw->dev_spec.ich8lan.eee_lp_ability = 0;
17156ab6bfe3SJack F Vogel 
1716*c80429ceSEric Joyner 	/* FEXTNVM6 K1-off workaround */
1717*c80429ceSEric Joyner 	if (hw->mac.type == e1000_pch_spt) {
1718*c80429ceSEric Joyner 		u32 pcieanacfg = E1000_READ_REG(hw, E1000_PCIEANACFG);
1719*c80429ceSEric Joyner 		u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6);
1720*c80429ceSEric Joyner 
1721*c80429ceSEric Joyner 		if (pcieanacfg & E1000_FEXTNVM6_K1_OFF_ENABLE)
1722*c80429ceSEric Joyner 			fextnvm6 |= E1000_FEXTNVM6_K1_OFF_ENABLE;
1723*c80429ceSEric Joyner 		else
1724*c80429ceSEric Joyner 			fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE;
1725*c80429ceSEric Joyner 
1726*c80429ceSEric Joyner 		E1000_WRITE_REG(hw, E1000_FEXTNVM6, fextnvm6);
1727*c80429ceSEric Joyner 	}
1728*c80429ceSEric Joyner 
17294edd8523SJack F Vogel 	if (!link)
17306ab6bfe3SJack F Vogel 		return E1000_SUCCESS; /* No link detected */
17314edd8523SJack F Vogel 
17324edd8523SJack F Vogel 	mac->get_link_status = FALSE;
17334edd8523SJack F Vogel 
17344dab5c37SJack F Vogel 	switch (hw->mac.type) {
17354dab5c37SJack F Vogel 	case e1000_pch2lan:
17364dab5c37SJack F Vogel 		ret_val = e1000_k1_workaround_lv(hw);
17374dab5c37SJack F Vogel 		if (ret_val)
17386ab6bfe3SJack F Vogel 			return ret_val;
17394dab5c37SJack F Vogel 		/* fall-thru */
17404dab5c37SJack F Vogel 	case e1000_pchlan:
17414edd8523SJack F Vogel 		if (hw->phy.type == e1000_phy_82578) {
17424edd8523SJack F Vogel 			ret_val = e1000_link_stall_workaround_hv(hw);
17434edd8523SJack F Vogel 			if (ret_val)
17446ab6bfe3SJack F Vogel 				return ret_val;
17454edd8523SJack F Vogel 		}
17464edd8523SJack F Vogel 
17476ab6bfe3SJack F Vogel 		/* Workaround for PCHx parts in half-duplex:
17484dab5c37SJack F Vogel 		 * Set the number of preambles removed from the packet
17494dab5c37SJack F Vogel 		 * when it is passed from the PHY to the MAC to prevent
17504dab5c37SJack F Vogel 		 * the MAC from misinterpreting the packet type.
17514dab5c37SJack F Vogel 		 */
17524dab5c37SJack F Vogel 		hw->phy.ops.read_reg(hw, HV_KMRN_FIFO_CTRLSTA, &phy_reg);
17534dab5c37SJack F Vogel 		phy_reg &= ~HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK;
17544dab5c37SJack F Vogel 
17554dab5c37SJack F Vogel 		if ((E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_FD) !=
17564dab5c37SJack F Vogel 		    E1000_STATUS_FD)
17574dab5c37SJack F Vogel 			phy_reg |= (1 << HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT);
17584dab5c37SJack F Vogel 
17594dab5c37SJack F Vogel 		hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA, phy_reg);
17604dab5c37SJack F Vogel 		break;
17614dab5c37SJack F Vogel 	default:
17624dab5c37SJack F Vogel 		break;
17637d9119bdSJack F Vogel 	}
17647d9119bdSJack F Vogel 
17656ab6bfe3SJack F Vogel 	/* Check if there was DownShift, must be checked
17664edd8523SJack F Vogel 	 * immediately after link-up
17674edd8523SJack F Vogel 	 */
17684edd8523SJack F Vogel 	e1000_check_downshift_generic(hw);
17694edd8523SJack F Vogel 
17707d9119bdSJack F Vogel 	/* Enable/Disable EEE after link up */
17717609433eSJack F Vogel 	if (hw->phy.type > e1000_phy_82579) {
17727d9119bdSJack F Vogel 		ret_val = e1000_set_eee_pchlan(hw);
17737d9119bdSJack F Vogel 		if (ret_val)
17746ab6bfe3SJack F Vogel 			return ret_val;
17757609433eSJack F Vogel 	}
17767d9119bdSJack F Vogel 
17776ab6bfe3SJack F Vogel 	/* If we are forcing speed/duplex, then we simply return since
17784edd8523SJack F Vogel 	 * we have already determined whether we have link or not.
17794edd8523SJack F Vogel 	 */
17806ab6bfe3SJack F Vogel 	if (!mac->autoneg)
17816ab6bfe3SJack F Vogel 		return -E1000_ERR_CONFIG;
17824edd8523SJack F Vogel 
17836ab6bfe3SJack F Vogel 	/* Auto-Neg is enabled.  Auto Speed Detection takes care
17844edd8523SJack F Vogel 	 * of MAC speed/duplex configuration.  So we only need to
17854edd8523SJack F Vogel 	 * configure Collision Distance in the MAC.
17864edd8523SJack F Vogel 	 */
17876ab6bfe3SJack F Vogel 	mac->ops.config_collision_dist(hw);
17884edd8523SJack F Vogel 
17896ab6bfe3SJack F Vogel 	/* Configure Flow Control now that Auto-Neg has completed.
17904edd8523SJack F Vogel 	 * First, we need to restore the desired flow control
17914edd8523SJack F Vogel 	 * settings because we may have had to re-autoneg with a
17924edd8523SJack F Vogel 	 * different link partner.
17934edd8523SJack F Vogel 	 */
17944edd8523SJack F Vogel 	ret_val = e1000_config_fc_after_link_up_generic(hw);
17954edd8523SJack F Vogel 	if (ret_val)
17964edd8523SJack F Vogel 		DEBUGOUT("Error configuring flow control\n");
17974edd8523SJack F Vogel 
17984edd8523SJack F Vogel 	return ret_val;
17994edd8523SJack F Vogel }
18004edd8523SJack F Vogel 
18014edd8523SJack F Vogel /**
18028cfa0ad2SJack F Vogel  *  e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers
18038cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
18048cfa0ad2SJack F Vogel  *
18058cfa0ad2SJack F Vogel  *  Initialize family-specific function pointers for PHY, MAC, and NVM.
18068cfa0ad2SJack F Vogel  **/
18078cfa0ad2SJack F Vogel void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw)
18088cfa0ad2SJack F Vogel {
18098cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_function_pointers_ich8lan");
18108cfa0ad2SJack F Vogel 
18118cfa0ad2SJack F Vogel 	hw->mac.ops.init_params = e1000_init_mac_params_ich8lan;
18128cfa0ad2SJack F Vogel 	hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan;
18139d81738fSJack F Vogel 	switch (hw->mac.type) {
18149d81738fSJack F Vogel 	case e1000_ich8lan:
18159d81738fSJack F Vogel 	case e1000_ich9lan:
18169d81738fSJack F Vogel 	case e1000_ich10lan:
18178cfa0ad2SJack F Vogel 		hw->phy.ops.init_params = e1000_init_phy_params_ich8lan;
18189d81738fSJack F Vogel 		break;
18199d81738fSJack F Vogel 	case e1000_pchlan:
18207d9119bdSJack F Vogel 	case e1000_pch2lan:
18216ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
1822*c80429ceSEric Joyner 	case e1000_pch_spt:
18239d81738fSJack F Vogel 		hw->phy.ops.init_params = e1000_init_phy_params_pchlan;
18249d81738fSJack F Vogel 		break;
18259d81738fSJack F Vogel 	default:
18269d81738fSJack F Vogel 		break;
18279d81738fSJack F Vogel 	}
18288cfa0ad2SJack F Vogel }
18298cfa0ad2SJack F Vogel 
18308cfa0ad2SJack F Vogel /**
18314edd8523SJack F Vogel  *  e1000_acquire_nvm_ich8lan - Acquire NVM mutex
18324edd8523SJack F Vogel  *  @hw: pointer to the HW structure
18334edd8523SJack F Vogel  *
18344edd8523SJack F Vogel  *  Acquires the mutex for performing NVM operations.
18354edd8523SJack F Vogel  **/
18364edd8523SJack F Vogel static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
18374edd8523SJack F Vogel {
18384edd8523SJack F Vogel 	DEBUGFUNC("e1000_acquire_nvm_ich8lan");
18394edd8523SJack F Vogel 
18404edd8523SJack F Vogel 	E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.nvm_mutex);
18414edd8523SJack F Vogel 
18424edd8523SJack F Vogel 	return E1000_SUCCESS;
18434edd8523SJack F Vogel }
18444edd8523SJack F Vogel 
18454edd8523SJack F Vogel /**
18464edd8523SJack F Vogel  *  e1000_release_nvm_ich8lan - Release NVM mutex
18474edd8523SJack F Vogel  *  @hw: pointer to the HW structure
18484edd8523SJack F Vogel  *
18494edd8523SJack F Vogel  *  Releases the mutex used while performing NVM operations.
18504edd8523SJack F Vogel  **/
18514edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
18524edd8523SJack F Vogel {
18534edd8523SJack F Vogel 	DEBUGFUNC("e1000_release_nvm_ich8lan");
18544edd8523SJack F Vogel 
18554edd8523SJack F Vogel 	E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.nvm_mutex);
18564edd8523SJack F Vogel 
18574edd8523SJack F Vogel 	return;
18584edd8523SJack F Vogel }
18594edd8523SJack F Vogel 
18604edd8523SJack F Vogel /**
18618cfa0ad2SJack F Vogel  *  e1000_acquire_swflag_ich8lan - Acquire software control flag
18628cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
18638cfa0ad2SJack F Vogel  *
18644edd8523SJack F Vogel  *  Acquires the software control flag for performing PHY and select
18654edd8523SJack F Vogel  *  MAC CSR accesses.
18668cfa0ad2SJack F Vogel  **/
18678cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
18688cfa0ad2SJack F Vogel {
18698cfa0ad2SJack F Vogel 	u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
18708cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
18718cfa0ad2SJack F Vogel 
18728cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_acquire_swflag_ich8lan");
18738cfa0ad2SJack F Vogel 
18744edd8523SJack F Vogel 	E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.swflag_mutex);
18754edd8523SJack F Vogel 
18768cfa0ad2SJack F Vogel 	while (timeout) {
18778cfa0ad2SJack F Vogel 		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
18784edd8523SJack F Vogel 		if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG))
18798cfa0ad2SJack F Vogel 			break;
18804edd8523SJack F Vogel 
18818cfa0ad2SJack F Vogel 		msec_delay_irq(1);
18828cfa0ad2SJack F Vogel 		timeout--;
18838cfa0ad2SJack F Vogel 	}
18848cfa0ad2SJack F Vogel 
18858cfa0ad2SJack F Vogel 	if (!timeout) {
18864dab5c37SJack F Vogel 		DEBUGOUT("SW has already locked the resource.\n");
18874edd8523SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
18884edd8523SJack F Vogel 		goto out;
18894edd8523SJack F Vogel 	}
18904edd8523SJack F Vogel 
18914edd8523SJack F Vogel 	timeout = SW_FLAG_TIMEOUT;
18924edd8523SJack F Vogel 
18934edd8523SJack F Vogel 	extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
18944edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
18954edd8523SJack F Vogel 
18964edd8523SJack F Vogel 	while (timeout) {
18974edd8523SJack F Vogel 		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
18984edd8523SJack F Vogel 		if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
18994edd8523SJack F Vogel 			break;
19004edd8523SJack F Vogel 
19014edd8523SJack F Vogel 		msec_delay_irq(1);
19024edd8523SJack F Vogel 		timeout--;
19034edd8523SJack F Vogel 	}
19044edd8523SJack F Vogel 
19054edd8523SJack F Vogel 	if (!timeout) {
19064dab5c37SJack F Vogel 		DEBUGOUT2("Failed to acquire the semaphore, FW or HW has it: FWSM=0x%8.8x EXTCNF_CTRL=0x%8.8x)\n",
19074dab5c37SJack F Vogel 			  E1000_READ_REG(hw, E1000_FWSM), extcnf_ctrl);
19088cfa0ad2SJack F Vogel 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
19098cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
19108cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
19118cfa0ad2SJack F Vogel 		goto out;
19128cfa0ad2SJack F Vogel 	}
19138cfa0ad2SJack F Vogel 
19148cfa0ad2SJack F Vogel out:
19154edd8523SJack F Vogel 	if (ret_val)
19164edd8523SJack F Vogel 		E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
19174edd8523SJack F Vogel 
19188cfa0ad2SJack F Vogel 	return ret_val;
19198cfa0ad2SJack F Vogel }
19208cfa0ad2SJack F Vogel 
19218cfa0ad2SJack F Vogel /**
19228cfa0ad2SJack F Vogel  *  e1000_release_swflag_ich8lan - Release software control flag
19238cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
19248cfa0ad2SJack F Vogel  *
19254edd8523SJack F Vogel  *  Releases the software control flag for performing PHY and select
19264edd8523SJack F Vogel  *  MAC CSR accesses.
19278cfa0ad2SJack F Vogel  **/
19288cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
19298cfa0ad2SJack F Vogel {
19308cfa0ad2SJack F Vogel 	u32 extcnf_ctrl;
19318cfa0ad2SJack F Vogel 
19328cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_release_swflag_ich8lan");
19338cfa0ad2SJack F Vogel 
19348cfa0ad2SJack F Vogel 	extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
1935730d3130SJack F Vogel 
1936730d3130SJack F Vogel 	if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) {
19378cfa0ad2SJack F Vogel 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
19388cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
1939730d3130SJack F Vogel 	} else {
1940730d3130SJack F Vogel 		DEBUGOUT("Semaphore unexpectedly released by sw/fw/hw\n");
1941730d3130SJack F Vogel 	}
19428cfa0ad2SJack F Vogel 
19434edd8523SJack F Vogel 	E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
19444edd8523SJack F Vogel 
19458cfa0ad2SJack F Vogel 	return;
19468cfa0ad2SJack F Vogel }
19478cfa0ad2SJack F Vogel 
19488cfa0ad2SJack F Vogel /**
19498cfa0ad2SJack F Vogel  *  e1000_check_mng_mode_ich8lan - Checks management mode
19508cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
19518cfa0ad2SJack F Vogel  *
19527d9119bdSJack F Vogel  *  This checks if the adapter has any manageability enabled.
19538cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by read/write
19548cfa0ad2SJack F Vogel  *  routines for the PHY and NVM parts.
19558cfa0ad2SJack F Vogel  **/
19568cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
19578cfa0ad2SJack F Vogel {
19588cfa0ad2SJack F Vogel 	u32 fwsm;
19598cfa0ad2SJack F Vogel 
19608cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_mng_mode_ich8lan");
19618cfa0ad2SJack F Vogel 
19628cfa0ad2SJack F Vogel 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
19638cfa0ad2SJack F Vogel 
19648cc64f1eSJack F Vogel 	return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
19657d9119bdSJack F Vogel 	       ((fwsm & E1000_FWSM_MODE_MASK) ==
19668cc64f1eSJack F Vogel 		(E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
19677d9119bdSJack F Vogel }
19687d9119bdSJack F Vogel 
19697d9119bdSJack F Vogel /**
19707d9119bdSJack F Vogel  *  e1000_check_mng_mode_pchlan - Checks management mode
19717d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
19727d9119bdSJack F Vogel  *
19737d9119bdSJack F Vogel  *  This checks if the adapter has iAMT enabled.
19747d9119bdSJack F Vogel  *  This is a function pointer entry point only called by read/write
19757d9119bdSJack F Vogel  *  routines for the PHY and NVM parts.
19767d9119bdSJack F Vogel  **/
19777d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw)
19787d9119bdSJack F Vogel {
19797d9119bdSJack F Vogel 	u32 fwsm;
19807d9119bdSJack F Vogel 
19817d9119bdSJack F Vogel 	DEBUGFUNC("e1000_check_mng_mode_pchlan");
19827d9119bdSJack F Vogel 
19837d9119bdSJack F Vogel 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
19847d9119bdSJack F Vogel 
19857d9119bdSJack F Vogel 	return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
19867d9119bdSJack F Vogel 	       (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
19877d9119bdSJack F Vogel }
19887d9119bdSJack F Vogel 
19897d9119bdSJack F Vogel /**
19907d9119bdSJack F Vogel  *  e1000_rar_set_pch2lan - Set receive address register
19917d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
19927d9119bdSJack F Vogel  *  @addr: pointer to the receive address
19937d9119bdSJack F Vogel  *  @index: receive address array register
19947d9119bdSJack F Vogel  *
19957d9119bdSJack F Vogel  *  Sets the receive address array register at index to the address passed
19967d9119bdSJack F Vogel  *  in by addr.  For 82579, RAR[0] is the base address register that is to
19977d9119bdSJack F Vogel  *  contain the MAC address but RAR[1-6] are reserved for manageability (ME).
19987d9119bdSJack F Vogel  *  Use SHRA[0-3] in place of those reserved for ME.
19997d9119bdSJack F Vogel  **/
20008cc64f1eSJack F Vogel static int e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index)
20017d9119bdSJack F Vogel {
20027d9119bdSJack F Vogel 	u32 rar_low, rar_high;
20037d9119bdSJack F Vogel 
20047d9119bdSJack F Vogel 	DEBUGFUNC("e1000_rar_set_pch2lan");
20057d9119bdSJack F Vogel 
20066ab6bfe3SJack F Vogel 	/* HW expects these in little endian so we reverse the byte order
20077d9119bdSJack F Vogel 	 * from network order (big endian) to little endian
20087d9119bdSJack F Vogel 	 */
20097d9119bdSJack F Vogel 	rar_low = ((u32) addr[0] |
20107d9119bdSJack F Vogel 		   ((u32) addr[1] << 8) |
20117d9119bdSJack F Vogel 		   ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
20127d9119bdSJack F Vogel 
20137d9119bdSJack F Vogel 	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
20147d9119bdSJack F Vogel 
20157d9119bdSJack F Vogel 	/* If MAC address zero, no need to set the AV bit */
20167d9119bdSJack F Vogel 	if (rar_low || rar_high)
20177d9119bdSJack F Vogel 		rar_high |= E1000_RAH_AV;
20187d9119bdSJack F Vogel 
20197d9119bdSJack F Vogel 	if (index == 0) {
20207d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
20217d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
20227d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
20237d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
20248cc64f1eSJack F Vogel 		return E1000_SUCCESS;
20257d9119bdSJack F Vogel 	}
20267d9119bdSJack F Vogel 
20277609433eSJack F Vogel 	/* RAR[1-6] are owned by manageability.  Skip those and program the
20287609433eSJack F Vogel 	 * next address into the SHRA register array.
20297609433eSJack F Vogel 	 */
20308cc64f1eSJack F Vogel 	if (index < (u32) (hw->mac.rar_entry_count)) {
20316ab6bfe3SJack F Vogel 		s32 ret_val;
20326ab6bfe3SJack F Vogel 
20336ab6bfe3SJack F Vogel 		ret_val = e1000_acquire_swflag_ich8lan(hw);
20346ab6bfe3SJack F Vogel 		if (ret_val)
20356ab6bfe3SJack F Vogel 			goto out;
20366ab6bfe3SJack F Vogel 
20377d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_SHRAL(index - 1), rar_low);
20387d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
20397d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_SHRAH(index - 1), rar_high);
20407d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
20417d9119bdSJack F Vogel 
20426ab6bfe3SJack F Vogel 		e1000_release_swflag_ich8lan(hw);
20436ab6bfe3SJack F Vogel 
20447d9119bdSJack F Vogel 		/* verify the register updates */
20457d9119bdSJack F Vogel 		if ((E1000_READ_REG(hw, E1000_SHRAL(index - 1)) == rar_low) &&
20467d9119bdSJack F Vogel 		    (E1000_READ_REG(hw, E1000_SHRAH(index - 1)) == rar_high))
20478cc64f1eSJack F Vogel 			return E1000_SUCCESS;
20487d9119bdSJack F Vogel 
20497d9119bdSJack F Vogel 		DEBUGOUT2("SHRA[%d] might be locked by ME - FWSM=0x%8.8x\n",
20507d9119bdSJack F Vogel 			 (index - 1), E1000_READ_REG(hw, E1000_FWSM));
20517d9119bdSJack F Vogel 	}
20527d9119bdSJack F Vogel 
20536ab6bfe3SJack F Vogel out:
20546ab6bfe3SJack F Vogel 	DEBUGOUT1("Failed to write receive address at index %d\n", index);
20558cc64f1eSJack F Vogel 	return -E1000_ERR_CONFIG;
20566ab6bfe3SJack F Vogel }
20576ab6bfe3SJack F Vogel 
20586ab6bfe3SJack F Vogel /**
20596ab6bfe3SJack F Vogel  *  e1000_rar_set_pch_lpt - Set receive address registers
20606ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
20616ab6bfe3SJack F Vogel  *  @addr: pointer to the receive address
20626ab6bfe3SJack F Vogel  *  @index: receive address array register
20636ab6bfe3SJack F Vogel  *
20646ab6bfe3SJack F Vogel  *  Sets the receive address register array at index to the address passed
20656ab6bfe3SJack F Vogel  *  in by addr. For LPT, RAR[0] is the base address register that is to
20666ab6bfe3SJack F Vogel  *  contain the MAC address. SHRA[0-10] are the shared receive address
20676ab6bfe3SJack F Vogel  *  registers that are shared between the Host and manageability engine (ME).
20686ab6bfe3SJack F Vogel  **/
20698cc64f1eSJack F Vogel static int e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index)
20706ab6bfe3SJack F Vogel {
20716ab6bfe3SJack F Vogel 	u32 rar_low, rar_high;
20726ab6bfe3SJack F Vogel 	u32 wlock_mac;
20736ab6bfe3SJack F Vogel 
20746ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_rar_set_pch_lpt");
20756ab6bfe3SJack F Vogel 
20766ab6bfe3SJack F Vogel 	/* HW expects these in little endian so we reverse the byte order
20776ab6bfe3SJack F Vogel 	 * from network order (big endian) to little endian
20786ab6bfe3SJack F Vogel 	 */
20796ab6bfe3SJack F Vogel 	rar_low = ((u32) addr[0] | ((u32) addr[1] << 8) |
20806ab6bfe3SJack F Vogel 		   ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
20816ab6bfe3SJack F Vogel 
20826ab6bfe3SJack F Vogel 	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
20836ab6bfe3SJack F Vogel 
20846ab6bfe3SJack F Vogel 	/* If MAC address zero, no need to set the AV bit */
20856ab6bfe3SJack F Vogel 	if (rar_low || rar_high)
20866ab6bfe3SJack F Vogel 		rar_high |= E1000_RAH_AV;
20876ab6bfe3SJack F Vogel 
20886ab6bfe3SJack F Vogel 	if (index == 0) {
20896ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
20906ab6bfe3SJack F Vogel 		E1000_WRITE_FLUSH(hw);
20916ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
20926ab6bfe3SJack F Vogel 		E1000_WRITE_FLUSH(hw);
20938cc64f1eSJack F Vogel 		return E1000_SUCCESS;
20946ab6bfe3SJack F Vogel 	}
20956ab6bfe3SJack F Vogel 
20966ab6bfe3SJack F Vogel 	/* The manageability engine (ME) can lock certain SHRAR registers that
20976ab6bfe3SJack F Vogel 	 * it is using - those registers are unavailable for use.
20986ab6bfe3SJack F Vogel 	 */
20996ab6bfe3SJack F Vogel 	if (index < hw->mac.rar_entry_count) {
21006ab6bfe3SJack F Vogel 		wlock_mac = E1000_READ_REG(hw, E1000_FWSM) &
21016ab6bfe3SJack F Vogel 			    E1000_FWSM_WLOCK_MAC_MASK;
21026ab6bfe3SJack F Vogel 		wlock_mac >>= E1000_FWSM_WLOCK_MAC_SHIFT;
21036ab6bfe3SJack F Vogel 
21046ab6bfe3SJack F Vogel 		/* Check if all SHRAR registers are locked */
21056ab6bfe3SJack F Vogel 		if (wlock_mac == 1)
21066ab6bfe3SJack F Vogel 			goto out;
21076ab6bfe3SJack F Vogel 
21086ab6bfe3SJack F Vogel 		if ((wlock_mac == 0) || (index <= wlock_mac)) {
21096ab6bfe3SJack F Vogel 			s32 ret_val;
21106ab6bfe3SJack F Vogel 
21116ab6bfe3SJack F Vogel 			ret_val = e1000_acquire_swflag_ich8lan(hw);
21126ab6bfe3SJack F Vogel 
21136ab6bfe3SJack F Vogel 			if (ret_val)
21146ab6bfe3SJack F Vogel 				goto out;
21156ab6bfe3SJack F Vogel 
21166ab6bfe3SJack F Vogel 			E1000_WRITE_REG(hw, E1000_SHRAL_PCH_LPT(index - 1),
21176ab6bfe3SJack F Vogel 					rar_low);
21186ab6bfe3SJack F Vogel 			E1000_WRITE_FLUSH(hw);
21196ab6bfe3SJack F Vogel 			E1000_WRITE_REG(hw, E1000_SHRAH_PCH_LPT(index - 1),
21206ab6bfe3SJack F Vogel 					rar_high);
21216ab6bfe3SJack F Vogel 			E1000_WRITE_FLUSH(hw);
21226ab6bfe3SJack F Vogel 
21236ab6bfe3SJack F Vogel 			e1000_release_swflag_ich8lan(hw);
21246ab6bfe3SJack F Vogel 
21256ab6bfe3SJack F Vogel 			/* verify the register updates */
21266ab6bfe3SJack F Vogel 			if ((E1000_READ_REG(hw, E1000_SHRAL_PCH_LPT(index - 1)) == rar_low) &&
21276ab6bfe3SJack F Vogel 			    (E1000_READ_REG(hw, E1000_SHRAH_PCH_LPT(index - 1)) == rar_high))
21288cc64f1eSJack F Vogel 				return E1000_SUCCESS;
21296ab6bfe3SJack F Vogel 		}
21306ab6bfe3SJack F Vogel 	}
21316ab6bfe3SJack F Vogel 
21326ab6bfe3SJack F Vogel out:
21337d9119bdSJack F Vogel 	DEBUGOUT1("Failed to write receive address at index %d\n", index);
21348cc64f1eSJack F Vogel 	return -E1000_ERR_CONFIG;
21358cfa0ad2SJack F Vogel }
21368cfa0ad2SJack F Vogel 
21378cfa0ad2SJack F Vogel /**
2138730d3130SJack F Vogel  *  e1000_update_mc_addr_list_pch2lan - Update Multicast addresses
2139730d3130SJack F Vogel  *  @hw: pointer to the HW structure
2140730d3130SJack F Vogel  *  @mc_addr_list: array of multicast addresses to program
2141730d3130SJack F Vogel  *  @mc_addr_count: number of multicast addresses to program
2142730d3130SJack F Vogel  *
2143730d3130SJack F Vogel  *  Updates entire Multicast Table Array of the PCH2 MAC and PHY.
2144730d3130SJack F Vogel  *  The caller must have a packed mc_addr_list of multicast addresses.
2145730d3130SJack F Vogel  **/
2146730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw,
2147730d3130SJack F Vogel 					      u8 *mc_addr_list,
2148730d3130SJack F Vogel 					      u32 mc_addr_count)
2149730d3130SJack F Vogel {
21504dab5c37SJack F Vogel 	u16 phy_reg = 0;
2151730d3130SJack F Vogel 	int i;
21524dab5c37SJack F Vogel 	s32 ret_val;
2153730d3130SJack F Vogel 
2154730d3130SJack F Vogel 	DEBUGFUNC("e1000_update_mc_addr_list_pch2lan");
2155730d3130SJack F Vogel 
2156730d3130SJack F Vogel 	e1000_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count);
2157730d3130SJack F Vogel 
21584dab5c37SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
21594dab5c37SJack F Vogel 	if (ret_val)
21604dab5c37SJack F Vogel 		return;
21614dab5c37SJack F Vogel 
21624dab5c37SJack F Vogel 	ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg);
21634dab5c37SJack F Vogel 	if (ret_val)
21644dab5c37SJack F Vogel 		goto release;
21654dab5c37SJack F Vogel 
2166730d3130SJack F Vogel 	for (i = 0; i < hw->mac.mta_reg_count; i++) {
21674dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_MTA(i),
21684dab5c37SJack F Vogel 					   (u16)(hw->mac.mta_shadow[i] &
21694dab5c37SJack F Vogel 						 0xFFFF));
21704dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, (BM_MTA(i) + 1),
2171730d3130SJack F Vogel 					   (u16)((hw->mac.mta_shadow[i] >> 16) &
2172730d3130SJack F Vogel 						 0xFFFF));
2173730d3130SJack F Vogel 	}
21744dab5c37SJack F Vogel 
21754dab5c37SJack F Vogel 	e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg);
21764dab5c37SJack F Vogel 
21774dab5c37SJack F Vogel release:
21784dab5c37SJack F Vogel 	hw->phy.ops.release(hw);
2179730d3130SJack F Vogel }
2180730d3130SJack F Vogel 
2181730d3130SJack F Vogel /**
21828cfa0ad2SJack F Vogel  *  e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
21838cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
21848cfa0ad2SJack F Vogel  *
21858cfa0ad2SJack F Vogel  *  Checks if firmware is blocking the reset of the PHY.
21868cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
21878cfa0ad2SJack F Vogel  *  reset routines.
21888cfa0ad2SJack F Vogel  **/
21898cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
21908cfa0ad2SJack F Vogel {
21918cfa0ad2SJack F Vogel 	u32 fwsm;
21927609433eSJack F Vogel 	bool blocked = FALSE;
21937609433eSJack F Vogel 	int i = 0;
21948cfa0ad2SJack F Vogel 
21958cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_reset_block_ich8lan");
21968cfa0ad2SJack F Vogel 
21977609433eSJack F Vogel 	do {
21988cfa0ad2SJack F Vogel 		fwsm = E1000_READ_REG(hw, E1000_FWSM);
21997609433eSJack F Vogel 		if (!(fwsm & E1000_ICH_FWSM_RSPCIPHY)) {
22007609433eSJack F Vogel 			blocked = TRUE;
22017609433eSJack F Vogel 			msec_delay(10);
22027609433eSJack F Vogel 			continue;
22037609433eSJack F Vogel 		}
22047609433eSJack F Vogel 		blocked = FALSE;
2205*c80429ceSEric Joyner 	} while (blocked && (i++ < 30));
22067609433eSJack F Vogel 	return blocked ? E1000_BLK_PHY_RESET : E1000_SUCCESS;
22078cfa0ad2SJack F Vogel }
22088cfa0ad2SJack F Vogel 
22098cfa0ad2SJack F Vogel /**
22107d9119bdSJack F Vogel  *  e1000_write_smbus_addr - Write SMBus address to PHY needed during Sx states
22117d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
22127d9119bdSJack F Vogel  *
22137d9119bdSJack F Vogel  *  Assumes semaphore already acquired.
22147d9119bdSJack F Vogel  *
22157d9119bdSJack F Vogel  **/
22167d9119bdSJack F Vogel static s32 e1000_write_smbus_addr(struct e1000_hw *hw)
22177d9119bdSJack F Vogel {
22187d9119bdSJack F Vogel 	u16 phy_data;
22197d9119bdSJack F Vogel 	u32 strap = E1000_READ_REG(hw, E1000_STRAP);
22206ab6bfe3SJack F Vogel 	u32 freq = (strap & E1000_STRAP_SMT_FREQ_MASK) >>
22216ab6bfe3SJack F Vogel 		E1000_STRAP_SMT_FREQ_SHIFT;
22226ab6bfe3SJack F Vogel 	s32 ret_val;
22237d9119bdSJack F Vogel 
22247d9119bdSJack F Vogel 	strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
22257d9119bdSJack F Vogel 
22267d9119bdSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, HV_SMB_ADDR, &phy_data);
22277d9119bdSJack F Vogel 	if (ret_val)
22286ab6bfe3SJack F Vogel 		return ret_val;
22297d9119bdSJack F Vogel 
22307d9119bdSJack F Vogel 	phy_data &= ~HV_SMB_ADDR_MASK;
22317d9119bdSJack F Vogel 	phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT);
22327d9119bdSJack F Vogel 	phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
22337d9119bdSJack F Vogel 
22346ab6bfe3SJack F Vogel 	if (hw->phy.type == e1000_phy_i217) {
22356ab6bfe3SJack F Vogel 		/* Restore SMBus frequency */
22366ab6bfe3SJack F Vogel 		if (freq--) {
22376ab6bfe3SJack F Vogel 			phy_data &= ~HV_SMB_ADDR_FREQ_MASK;
22386ab6bfe3SJack F Vogel 			phy_data |= (freq & (1 << 0)) <<
22396ab6bfe3SJack F Vogel 				HV_SMB_ADDR_FREQ_LOW_SHIFT;
22406ab6bfe3SJack F Vogel 			phy_data |= (freq & (1 << 1)) <<
22416ab6bfe3SJack F Vogel 				(HV_SMB_ADDR_FREQ_HIGH_SHIFT - 1);
22426ab6bfe3SJack F Vogel 		} else {
22436ab6bfe3SJack F Vogel 			DEBUGOUT("Unsupported SMB frequency in PHY\n");
22446ab6bfe3SJack F Vogel 		}
22456ab6bfe3SJack F Vogel 	}
22466ab6bfe3SJack F Vogel 
22476ab6bfe3SJack F Vogel 	return e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data);
22487d9119bdSJack F Vogel }
22497d9119bdSJack F Vogel 
22507d9119bdSJack F Vogel /**
22514edd8523SJack F Vogel  *  e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration
22524edd8523SJack F Vogel  *  @hw:   pointer to the HW structure
22534edd8523SJack F Vogel  *
22544edd8523SJack F Vogel  *  SW should configure the LCD from the NVM extended configuration region
22554edd8523SJack F Vogel  *  as a workaround for certain parts.
22564edd8523SJack F Vogel  **/
22574edd8523SJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
22584edd8523SJack F Vogel {
22594edd8523SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
22604edd8523SJack F Vogel 	u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
2261a69ed8dfSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
22624edd8523SJack F Vogel 	u16 word_addr, reg_data, reg_addr, phy_page = 0;
22634edd8523SJack F Vogel 
22647d9119bdSJack F Vogel 	DEBUGFUNC("e1000_sw_lcd_config_ich8lan");
22654edd8523SJack F Vogel 
22666ab6bfe3SJack F Vogel 	/* Initialize the PHY from the NVM on ICH platforms.  This
22674edd8523SJack F Vogel 	 * is needed due to an issue where the NVM configuration is
22684edd8523SJack F Vogel 	 * not properly autoloaded after power transitions.
22694edd8523SJack F Vogel 	 * Therefore, after each PHY reset, we will load the
22704edd8523SJack F Vogel 	 * configuration data out of the NVM manually.
22714edd8523SJack F Vogel 	 */
22727d9119bdSJack F Vogel 	switch (hw->mac.type) {
22737d9119bdSJack F Vogel 	case e1000_ich8lan:
22747d9119bdSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
22757d9119bdSJack F Vogel 			return ret_val;
22767d9119bdSJack F Vogel 
22777d9119bdSJack F Vogel 		if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_AMT) ||
22787d9119bdSJack F Vogel 		    (hw->device_id == E1000_DEV_ID_ICH8_IGP_C)) {
22794edd8523SJack F Vogel 			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
22807d9119bdSJack F Vogel 			break;
22817d9119bdSJack F Vogel 		}
22827d9119bdSJack F Vogel 		/* Fall-thru */
22837d9119bdSJack F Vogel 	case e1000_pchlan:
22847d9119bdSJack F Vogel 	case e1000_pch2lan:
22856ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
2286*c80429ceSEric Joyner 	case e1000_pch_spt:
22877d9119bdSJack F Vogel 		sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
22887d9119bdSJack F Vogel 		break;
22897d9119bdSJack F Vogel 	default:
22907d9119bdSJack F Vogel 		return ret_val;
22917d9119bdSJack F Vogel 	}
22927d9119bdSJack F Vogel 
22937d9119bdSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
22947d9119bdSJack F Vogel 	if (ret_val)
22957d9119bdSJack F Vogel 		return ret_val;
22964edd8523SJack F Vogel 
22974edd8523SJack F Vogel 	data = E1000_READ_REG(hw, E1000_FEXTNVM);
22984edd8523SJack F Vogel 	if (!(data & sw_cfg_mask))
22996ab6bfe3SJack F Vogel 		goto release;
23004edd8523SJack F Vogel 
23016ab6bfe3SJack F Vogel 	/* Make sure HW does not configure LCD from PHY
23024edd8523SJack F Vogel 	 * extended configuration before SW configuration
23034edd8523SJack F Vogel 	 */
23044edd8523SJack F Vogel 	data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
23056ab6bfe3SJack F Vogel 	if ((hw->mac.type < e1000_pch2lan) &&
23066ab6bfe3SJack F Vogel 	    (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE))
23076ab6bfe3SJack F Vogel 			goto release;
23084edd8523SJack F Vogel 
23094edd8523SJack F Vogel 	cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE);
23104edd8523SJack F Vogel 	cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
23114edd8523SJack F Vogel 	cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
23124edd8523SJack F Vogel 	if (!cnf_size)
23136ab6bfe3SJack F Vogel 		goto release;
23144edd8523SJack F Vogel 
23154edd8523SJack F Vogel 	cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
23164edd8523SJack F Vogel 	cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
23174edd8523SJack F Vogel 
23186ab6bfe3SJack F Vogel 	if (((hw->mac.type == e1000_pchlan) &&
23196ab6bfe3SJack F Vogel 	     !(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)) ||
23206ab6bfe3SJack F Vogel 	    (hw->mac.type > e1000_pchlan)) {
23216ab6bfe3SJack F Vogel 		/* HW configures the SMBus address and LEDs when the
23224edd8523SJack F Vogel 		 * OEM and LCD Write Enable bits are set in the NVM.
23234edd8523SJack F Vogel 		 * When both NVM bits are cleared, SW will configure
23244edd8523SJack F Vogel 		 * them instead.
23254edd8523SJack F Vogel 		 */
23267d9119bdSJack F Vogel 		ret_val = e1000_write_smbus_addr(hw);
23274edd8523SJack F Vogel 		if (ret_val)
23286ab6bfe3SJack F Vogel 			goto release;
23294edd8523SJack F Vogel 
23304edd8523SJack F Vogel 		data = E1000_READ_REG(hw, E1000_LEDCTL);
2331a69ed8dfSJack F Vogel 		ret_val = e1000_write_phy_reg_hv_locked(hw, HV_LED_CONFIG,
23324edd8523SJack F Vogel 							(u16)data);
23334edd8523SJack F Vogel 		if (ret_val)
23346ab6bfe3SJack F Vogel 			goto release;
23354edd8523SJack F Vogel 	}
23364edd8523SJack F Vogel 
23374edd8523SJack F Vogel 	/* Configure LCD from extended configuration region. */
23384edd8523SJack F Vogel 
23394edd8523SJack F Vogel 	/* cnf_base_addr is in DWORD */
23404edd8523SJack F Vogel 	word_addr = (u16)(cnf_base_addr << 1);
23414edd8523SJack F Vogel 
23424edd8523SJack F Vogel 	for (i = 0; i < cnf_size; i++) {
23434edd8523SJack F Vogel 		ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1,
23444edd8523SJack F Vogel 					   &reg_data);
23454edd8523SJack F Vogel 		if (ret_val)
23466ab6bfe3SJack F Vogel 			goto release;
23474edd8523SJack F Vogel 
23484edd8523SJack F Vogel 		ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1),
23494edd8523SJack F Vogel 					   1, &reg_addr);
23504edd8523SJack F Vogel 		if (ret_val)
23516ab6bfe3SJack F Vogel 			goto release;
23524edd8523SJack F Vogel 
23534edd8523SJack F Vogel 		/* Save off the PHY page for future writes. */
23544edd8523SJack F Vogel 		if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
23554edd8523SJack F Vogel 			phy_page = reg_data;
23564edd8523SJack F Vogel 			continue;
23574edd8523SJack F Vogel 		}
23584edd8523SJack F Vogel 
23594edd8523SJack F Vogel 		reg_addr &= PHY_REG_MASK;
23604edd8523SJack F Vogel 		reg_addr |= phy_page;
23614edd8523SJack F Vogel 
23624edd8523SJack F Vogel 		ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr,
23634edd8523SJack F Vogel 						    reg_data);
23644edd8523SJack F Vogel 		if (ret_val)
23656ab6bfe3SJack F Vogel 			goto release;
23664edd8523SJack F Vogel 	}
23674edd8523SJack F Vogel 
23686ab6bfe3SJack F Vogel release:
23694edd8523SJack F Vogel 	hw->phy.ops.release(hw);
23704edd8523SJack F Vogel 	return ret_val;
23714edd8523SJack F Vogel }
23724edd8523SJack F Vogel 
23734edd8523SJack F Vogel /**
23744edd8523SJack F Vogel  *  e1000_k1_gig_workaround_hv - K1 Si workaround
23754edd8523SJack F Vogel  *  @hw:   pointer to the HW structure
23764edd8523SJack F Vogel  *  @link: link up bool flag
23774edd8523SJack F Vogel  *
23784edd8523SJack F Vogel  *  If K1 is enabled for 1Gbps, the MAC might stall when transitioning
23794edd8523SJack F Vogel  *  from a lower speed.  This workaround disables K1 whenever link is at 1Gig
23804edd8523SJack F Vogel  *  If link is down, the function will restore the default K1 setting located
23814edd8523SJack F Vogel  *  in the NVM.
23824edd8523SJack F Vogel  **/
23834edd8523SJack F Vogel static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
23844edd8523SJack F Vogel {
23854edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
23864edd8523SJack F Vogel 	u16 status_reg = 0;
23874edd8523SJack F Vogel 	bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled;
23884edd8523SJack F Vogel 
23894edd8523SJack F Vogel 	DEBUGFUNC("e1000_k1_gig_workaround_hv");
23904edd8523SJack F Vogel 
23914edd8523SJack F Vogel 	if (hw->mac.type != e1000_pchlan)
23926ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
23934edd8523SJack F Vogel 
23944edd8523SJack F Vogel 	/* Wrap the whole flow with the sw flag */
23954edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
23964edd8523SJack F Vogel 	if (ret_val)
23976ab6bfe3SJack F Vogel 		return ret_val;
23984edd8523SJack F Vogel 
23994edd8523SJack F Vogel 	/* Disable K1 when link is 1Gbps, otherwise use the NVM setting */
24004edd8523SJack F Vogel 	if (link) {
24014edd8523SJack F Vogel 		if (hw->phy.type == e1000_phy_82578) {
24024edd8523SJack F Vogel 			ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS,
24034edd8523SJack F Vogel 							      &status_reg);
24044edd8523SJack F Vogel 			if (ret_val)
24054edd8523SJack F Vogel 				goto release;
24064edd8523SJack F Vogel 
24077609433eSJack F Vogel 			status_reg &= (BM_CS_STATUS_LINK_UP |
24084edd8523SJack F Vogel 				       BM_CS_STATUS_RESOLVED |
24097609433eSJack F Vogel 				       BM_CS_STATUS_SPEED_MASK);
24104edd8523SJack F Vogel 
24114edd8523SJack F Vogel 			if (status_reg == (BM_CS_STATUS_LINK_UP |
24124edd8523SJack F Vogel 					   BM_CS_STATUS_RESOLVED |
24134edd8523SJack F Vogel 					   BM_CS_STATUS_SPEED_1000))
24144edd8523SJack F Vogel 				k1_enable = FALSE;
24154edd8523SJack F Vogel 		}
24164edd8523SJack F Vogel 
24174edd8523SJack F Vogel 		if (hw->phy.type == e1000_phy_82577) {
24184edd8523SJack F Vogel 			ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS,
24194edd8523SJack F Vogel 							      &status_reg);
24204edd8523SJack F Vogel 			if (ret_val)
24214edd8523SJack F Vogel 				goto release;
24224edd8523SJack F Vogel 
24237609433eSJack F Vogel 			status_reg &= (HV_M_STATUS_LINK_UP |
24244edd8523SJack F Vogel 				       HV_M_STATUS_AUTONEG_COMPLETE |
24257609433eSJack F Vogel 				       HV_M_STATUS_SPEED_MASK);
24264edd8523SJack F Vogel 
24274edd8523SJack F Vogel 			if (status_reg == (HV_M_STATUS_LINK_UP |
24284edd8523SJack F Vogel 					   HV_M_STATUS_AUTONEG_COMPLETE |
24294edd8523SJack F Vogel 					   HV_M_STATUS_SPEED_1000))
24304edd8523SJack F Vogel 				k1_enable = FALSE;
24314edd8523SJack F Vogel 		}
24324edd8523SJack F Vogel 
24334edd8523SJack F Vogel 		/* Link stall fix for link up */
24344edd8523SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
24354edd8523SJack F Vogel 						       0x0100);
24364edd8523SJack F Vogel 		if (ret_val)
24374edd8523SJack F Vogel 			goto release;
24384edd8523SJack F Vogel 
24394edd8523SJack F Vogel 	} else {
24404edd8523SJack F Vogel 		/* Link stall fix for link down */
24414edd8523SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
24424edd8523SJack F Vogel 						       0x4100);
24434edd8523SJack F Vogel 		if (ret_val)
24444edd8523SJack F Vogel 			goto release;
24454edd8523SJack F Vogel 	}
24464edd8523SJack F Vogel 
24474edd8523SJack F Vogel 	ret_val = e1000_configure_k1_ich8lan(hw, k1_enable);
24484edd8523SJack F Vogel 
24494edd8523SJack F Vogel release:
24504edd8523SJack F Vogel 	hw->phy.ops.release(hw);
24516ab6bfe3SJack F Vogel 
24524edd8523SJack F Vogel 	return ret_val;
24534edd8523SJack F Vogel }
24544edd8523SJack F Vogel 
24554edd8523SJack F Vogel /**
24564edd8523SJack F Vogel  *  e1000_configure_k1_ich8lan - Configure K1 power state
24574edd8523SJack F Vogel  *  @hw: pointer to the HW structure
24584edd8523SJack F Vogel  *  @enable: K1 state to configure
24594edd8523SJack F Vogel  *
24604edd8523SJack F Vogel  *  Configure the K1 power state based on the provided parameter.
24614edd8523SJack F Vogel  *  Assumes semaphore already acquired.
24624edd8523SJack F Vogel  *
24634edd8523SJack F Vogel  *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
24644edd8523SJack F Vogel  **/
24654edd8523SJack F Vogel s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
24664edd8523SJack F Vogel {
24676ab6bfe3SJack F Vogel 	s32 ret_val;
24684edd8523SJack F Vogel 	u32 ctrl_reg = 0;
24694edd8523SJack F Vogel 	u32 ctrl_ext = 0;
24704edd8523SJack F Vogel 	u32 reg = 0;
24714edd8523SJack F Vogel 	u16 kmrn_reg = 0;
24724edd8523SJack F Vogel 
24737d9119bdSJack F Vogel 	DEBUGFUNC("e1000_configure_k1_ich8lan");
24747d9119bdSJack F Vogel 
24754dab5c37SJack F Vogel 	ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
24764edd8523SJack F Vogel 					     &kmrn_reg);
24774edd8523SJack F Vogel 	if (ret_val)
24786ab6bfe3SJack F Vogel 		return ret_val;
24794edd8523SJack F Vogel 
24804edd8523SJack F Vogel 	if (k1_enable)
24814edd8523SJack F Vogel 		kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE;
24824edd8523SJack F Vogel 	else
24834edd8523SJack F Vogel 		kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE;
24844edd8523SJack F Vogel 
24854dab5c37SJack F Vogel 	ret_val = e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
24864edd8523SJack F Vogel 					      kmrn_reg);
24874edd8523SJack F Vogel 	if (ret_val)
24886ab6bfe3SJack F Vogel 		return ret_val;
24894edd8523SJack F Vogel 
24904edd8523SJack F Vogel 	usec_delay(20);
24914edd8523SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
24924edd8523SJack F Vogel 	ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
24934edd8523SJack F Vogel 
24944edd8523SJack F Vogel 	reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
24954edd8523SJack F Vogel 	reg |= E1000_CTRL_FRCSPD;
24964edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, reg);
24974edd8523SJack F Vogel 
24984edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
24994dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
25004edd8523SJack F Vogel 	usec_delay(20);
25014edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
25024edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
25034dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
25044edd8523SJack F Vogel 	usec_delay(20);
25054edd8523SJack F Vogel 
25066ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
25074edd8523SJack F Vogel }
25084edd8523SJack F Vogel 
25094edd8523SJack F Vogel /**
25104edd8523SJack F Vogel  *  e1000_oem_bits_config_ich8lan - SW-based LCD Configuration
25114edd8523SJack F Vogel  *  @hw:       pointer to the HW structure
25124edd8523SJack F Vogel  *  @d0_state: boolean if entering d0 or d3 device state
25134edd8523SJack F Vogel  *
25144edd8523SJack F Vogel  *  SW will configure Gbe Disable and LPLU based on the NVM. The four bits are
25154edd8523SJack F Vogel  *  collectively called OEM bits.  The OEM Write Enable bit and SW Config bit
25164edd8523SJack F Vogel  *  in NVM determines whether HW should configure LPLU and Gbe Disable.
25174edd8523SJack F Vogel  **/
25184dab5c37SJack F Vogel static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
25194edd8523SJack F Vogel {
25204edd8523SJack F Vogel 	s32 ret_val = 0;
25214edd8523SJack F Vogel 	u32 mac_reg;
25224edd8523SJack F Vogel 	u16 oem_reg;
25234edd8523SJack F Vogel 
25247d9119bdSJack F Vogel 	DEBUGFUNC("e1000_oem_bits_config_ich8lan");
25257d9119bdSJack F Vogel 
25266ab6bfe3SJack F Vogel 	if (hw->mac.type < e1000_pchlan)
25274edd8523SJack F Vogel 		return ret_val;
25284edd8523SJack F Vogel 
25294edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
25304edd8523SJack F Vogel 	if (ret_val)
25314edd8523SJack F Vogel 		return ret_val;
25324edd8523SJack F Vogel 
25336ab6bfe3SJack F Vogel 	if (hw->mac.type == e1000_pchlan) {
25344edd8523SJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
25354edd8523SJack F Vogel 		if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
25366ab6bfe3SJack F Vogel 			goto release;
25377d9119bdSJack F Vogel 	}
25384edd8523SJack F Vogel 
25394edd8523SJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM);
25404edd8523SJack F Vogel 	if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
25416ab6bfe3SJack F Vogel 		goto release;
25424edd8523SJack F Vogel 
25434edd8523SJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
25444edd8523SJack F Vogel 
25454edd8523SJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg);
25464edd8523SJack F Vogel 	if (ret_val)
25476ab6bfe3SJack F Vogel 		goto release;
25484edd8523SJack F Vogel 
25494edd8523SJack F Vogel 	oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU);
25504edd8523SJack F Vogel 
25514edd8523SJack F Vogel 	if (d0_state) {
25524edd8523SJack F Vogel 		if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE)
25534edd8523SJack F Vogel 			oem_reg |= HV_OEM_BITS_GBE_DIS;
25544edd8523SJack F Vogel 
25554edd8523SJack F Vogel 		if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
25564edd8523SJack F Vogel 			oem_reg |= HV_OEM_BITS_LPLU;
25574dab5c37SJack F Vogel 	} else {
25584dab5c37SJack F Vogel 		if (mac_reg & (E1000_PHY_CTRL_GBE_DISABLE |
25594dab5c37SJack F Vogel 		    E1000_PHY_CTRL_NOND0A_GBE_DISABLE))
25604dab5c37SJack F Vogel 			oem_reg |= HV_OEM_BITS_GBE_DIS;
25614dab5c37SJack F Vogel 
25624dab5c37SJack F Vogel 		if (mac_reg & (E1000_PHY_CTRL_D0A_LPLU |
25634dab5c37SJack F Vogel 		    E1000_PHY_CTRL_NOND0A_LPLU))
25644dab5c37SJack F Vogel 			oem_reg |= HV_OEM_BITS_LPLU;
25654dab5c37SJack F Vogel 	}
25664dab5c37SJack F Vogel 
25676ab6bfe3SJack F Vogel 	/* Set Restart auto-neg to activate the bits */
25686ab6bfe3SJack F Vogel 	if ((d0_state || (hw->mac.type != e1000_pchlan)) &&
25696ab6bfe3SJack F Vogel 	    !hw->phy.ops.check_reset_block(hw))
25706ab6bfe3SJack F Vogel 		oem_reg |= HV_OEM_BITS_RESTART_AN;
25716ab6bfe3SJack F Vogel 
25724edd8523SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg);
25734edd8523SJack F Vogel 
25746ab6bfe3SJack F Vogel release:
25754edd8523SJack F Vogel 	hw->phy.ops.release(hw);
25764edd8523SJack F Vogel 
25774edd8523SJack F Vogel 	return ret_val;
25784edd8523SJack F Vogel }
25794edd8523SJack F Vogel 
25804edd8523SJack F Vogel 
25814edd8523SJack F Vogel /**
2582a69ed8dfSJack F Vogel  *  e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode
2583a69ed8dfSJack F Vogel  *  @hw:   pointer to the HW structure
2584a69ed8dfSJack F Vogel  **/
2585a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw)
2586a69ed8dfSJack F Vogel {
2587a69ed8dfSJack F Vogel 	s32 ret_val;
2588a69ed8dfSJack F Vogel 	u16 data;
2589a69ed8dfSJack F Vogel 
25907d9119bdSJack F Vogel 	DEBUGFUNC("e1000_set_mdio_slow_mode_hv");
25917d9119bdSJack F Vogel 
2592a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, HV_KMRN_MODE_CTRL, &data);
2593a69ed8dfSJack F Vogel 	if (ret_val)
2594a69ed8dfSJack F Vogel 		return ret_val;
2595a69ed8dfSJack F Vogel 
2596a69ed8dfSJack F Vogel 	data |= HV_KMRN_MDIO_SLOW;
2597a69ed8dfSJack F Vogel 
2598a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_MODE_CTRL, data);
2599a69ed8dfSJack F Vogel 
2600a69ed8dfSJack F Vogel 	return ret_val;
2601a69ed8dfSJack F Vogel }
2602a69ed8dfSJack F Vogel 
2603a69ed8dfSJack F Vogel /**
26049d81738fSJack F Vogel  *  e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
26059d81738fSJack F Vogel  *  done after every PHY reset.
26069d81738fSJack F Vogel  **/
26079d81738fSJack F Vogel static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
26089d81738fSJack F Vogel {
26099d81738fSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
2610a69ed8dfSJack F Vogel 	u16 phy_data;
26119d81738fSJack F Vogel 
26127d9119bdSJack F Vogel 	DEBUGFUNC("e1000_hv_phy_workarounds_ich8lan");
26137d9119bdSJack F Vogel 
26149d81738fSJack F Vogel 	if (hw->mac.type != e1000_pchlan)
26156ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
26169d81738fSJack F Vogel 
2617a69ed8dfSJack F Vogel 	/* Set MDIO slow mode before any other MDIO access */
2618a69ed8dfSJack F Vogel 	if (hw->phy.type == e1000_phy_82577) {
2619a69ed8dfSJack F Vogel 		ret_val = e1000_set_mdio_slow_mode_hv(hw);
2620a69ed8dfSJack F Vogel 		if (ret_val)
26216ab6bfe3SJack F Vogel 			return ret_val;
2622a69ed8dfSJack F Vogel 	}
2623a69ed8dfSJack F Vogel 
26249d81738fSJack F Vogel 	if (((hw->phy.type == e1000_phy_82577) &&
26259d81738fSJack F Vogel 	     ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
26269d81738fSJack F Vogel 	    ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
26279d81738fSJack F Vogel 		/* Disable generation of early preamble */
26289d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
26299d81738fSJack F Vogel 		if (ret_val)
26306ab6bfe3SJack F Vogel 			return ret_val;
26319d81738fSJack F Vogel 
26329d81738fSJack F Vogel 		/* Preamble tuning for SSC */
26334dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA,
26344dab5c37SJack F Vogel 						0xA204);
26359d81738fSJack F Vogel 		if (ret_val)
26366ab6bfe3SJack F Vogel 			return ret_val;
26379d81738fSJack F Vogel 	}
26389d81738fSJack F Vogel 
26399d81738fSJack F Vogel 	if (hw->phy.type == e1000_phy_82578) {
26406ab6bfe3SJack F Vogel 		/* Return registers to default by doing a soft reset then
26419d81738fSJack F Vogel 		 * writing 0x3140 to the control register.
26429d81738fSJack F Vogel 		 */
26439d81738fSJack F Vogel 		if (hw->phy.revision < 2) {
26449d81738fSJack F Vogel 			e1000_phy_sw_reset_generic(hw);
26459d81738fSJack F Vogel 			ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL,
26469d81738fSJack F Vogel 							0x3140);
26479d81738fSJack F Vogel 		}
26489d81738fSJack F Vogel 	}
26499d81738fSJack F Vogel 
26509d81738fSJack F Vogel 	/* Select page 0 */
26519d81738fSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
26529d81738fSJack F Vogel 	if (ret_val)
26536ab6bfe3SJack F Vogel 		return ret_val;
26544edd8523SJack F Vogel 
26559d81738fSJack F Vogel 	hw->phy.addr = 1;
26564edd8523SJack F Vogel 	ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
2657a69ed8dfSJack F Vogel 	hw->phy.ops.release(hw);
26584edd8523SJack F Vogel 	if (ret_val)
26596ab6bfe3SJack F Vogel 		return ret_val;
26609d81738fSJack F Vogel 
26616ab6bfe3SJack F Vogel 	/* Configure the K1 Si workaround during phy reset assuming there is
26624edd8523SJack F Vogel 	 * link so that it disables K1 if link is in 1Gbps.
26634edd8523SJack F Vogel 	 */
26644edd8523SJack F Vogel 	ret_val = e1000_k1_gig_workaround_hv(hw, TRUE);
2665a69ed8dfSJack F Vogel 	if (ret_val)
26666ab6bfe3SJack F Vogel 		return ret_val;
26674edd8523SJack F Vogel 
2668a69ed8dfSJack F Vogel 	/* Workaround for link disconnects on a busy hub in half duplex */
2669a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
2670a69ed8dfSJack F Vogel 	if (ret_val)
26716ab6bfe3SJack F Vogel 		return ret_val;
26724dab5c37SJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw, BM_PORT_GEN_CFG, &phy_data);
2673a69ed8dfSJack F Vogel 	if (ret_val)
2674a69ed8dfSJack F Vogel 		goto release;
26754dab5c37SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, BM_PORT_GEN_CFG,
2676a69ed8dfSJack F Vogel 					       phy_data & 0x00FF);
26776ab6bfe3SJack F Vogel 	if (ret_val)
26786ab6bfe3SJack F Vogel 		goto release;
26796ab6bfe3SJack F Vogel 
26806ab6bfe3SJack F Vogel 	/* set MSE higher to enable link to stay up when noise is high */
26816ab6bfe3SJack F Vogel 	ret_val = e1000_write_emi_reg_locked(hw, I82577_MSE_THRESHOLD, 0x0034);
2682a69ed8dfSJack F Vogel release:
2683a69ed8dfSJack F Vogel 	hw->phy.ops.release(hw);
26846ab6bfe3SJack F Vogel 
26859d81738fSJack F Vogel 	return ret_val;
26869d81738fSJack F Vogel }
26879d81738fSJack F Vogel 
26889d81738fSJack F Vogel /**
26897d9119bdSJack F Vogel  *  e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY
26907d9119bdSJack F Vogel  *  @hw:   pointer to the HW structure
26917d9119bdSJack F Vogel  **/
26927d9119bdSJack F Vogel void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
26937d9119bdSJack F Vogel {
26947d9119bdSJack F Vogel 	u32 mac_reg;
26954dab5c37SJack F Vogel 	u16 i, phy_reg = 0;
26964dab5c37SJack F Vogel 	s32 ret_val;
26977d9119bdSJack F Vogel 
26987d9119bdSJack F Vogel 	DEBUGFUNC("e1000_copy_rx_addrs_to_phy_ich8lan");
26997d9119bdSJack F Vogel 
27004dab5c37SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
27014dab5c37SJack F Vogel 	if (ret_val)
27024dab5c37SJack F Vogel 		return;
27034dab5c37SJack F Vogel 	ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg);
27044dab5c37SJack F Vogel 	if (ret_val)
27054dab5c37SJack F Vogel 		goto release;
27064dab5c37SJack F Vogel 
27077609433eSJack F Vogel 	/* Copy both RAL/H (rar_entry_count) and SHRAL/H to PHY */
27087609433eSJack F Vogel 	for (i = 0; i < (hw->mac.rar_entry_count); i++) {
27097d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RAL(i));
27104dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_L(i),
27114dab5c37SJack F Vogel 					   (u16)(mac_reg & 0xFFFF));
27124dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_M(i),
27134dab5c37SJack F Vogel 					   (u16)((mac_reg >> 16) & 0xFFFF));
27144dab5c37SJack F Vogel 
27157d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RAH(i));
27164dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_H(i),
27174dab5c37SJack F Vogel 					   (u16)(mac_reg & 0xFFFF));
27184dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_CTRL(i),
27194dab5c37SJack F Vogel 					   (u16)((mac_reg & E1000_RAH_AV)
27204dab5c37SJack F Vogel 						 >> 16));
27217d9119bdSJack F Vogel 	}
27224dab5c37SJack F Vogel 
27234dab5c37SJack F Vogel 	e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg);
27244dab5c37SJack F Vogel 
27254dab5c37SJack F Vogel release:
27264dab5c37SJack F Vogel 	hw->phy.ops.release(hw);
27277d9119bdSJack F Vogel }
27287d9119bdSJack F Vogel 
27297d9119bdSJack F Vogel static u32 e1000_calc_rx_da_crc(u8 mac[])
27307d9119bdSJack F Vogel {
27317d9119bdSJack F Vogel 	u32 poly = 0xEDB88320;	/* Polynomial for 802.3 CRC calculation */
27327d9119bdSJack F Vogel 	u32 i, j, mask, crc;
27337d9119bdSJack F Vogel 
27347d9119bdSJack F Vogel 	DEBUGFUNC("e1000_calc_rx_da_crc");
27357d9119bdSJack F Vogel 
27367d9119bdSJack F Vogel 	crc = 0xffffffff;
27377d9119bdSJack F Vogel 	for (i = 0; i < 6; i++) {
27387d9119bdSJack F Vogel 		crc = crc ^ mac[i];
27397d9119bdSJack F Vogel 		for (j = 8; j > 0; j--) {
27407d9119bdSJack F Vogel 			mask = (crc & 1) * (-1);
27417d9119bdSJack F Vogel 			crc = (crc >> 1) ^ (poly & mask);
27427d9119bdSJack F Vogel 		}
27437d9119bdSJack F Vogel 	}
27447d9119bdSJack F Vogel 	return ~crc;
27457d9119bdSJack F Vogel }
27467d9119bdSJack F Vogel 
27477d9119bdSJack F Vogel /**
27487d9119bdSJack F Vogel  *  e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation
27497d9119bdSJack F Vogel  *  with 82579 PHY
27507d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
27517d9119bdSJack F Vogel  *  @enable: flag to enable/disable workaround when enabling/disabling jumbos
27527d9119bdSJack F Vogel  **/
27537d9119bdSJack F Vogel s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
27547d9119bdSJack F Vogel {
27557d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
27567d9119bdSJack F Vogel 	u16 phy_reg, data;
27577d9119bdSJack F Vogel 	u32 mac_reg;
27587d9119bdSJack F Vogel 	u16 i;
27597d9119bdSJack F Vogel 
27607d9119bdSJack F Vogel 	DEBUGFUNC("e1000_lv_jumbo_workaround_ich8lan");
27617d9119bdSJack F Vogel 
27626ab6bfe3SJack F Vogel 	if (hw->mac.type < e1000_pch2lan)
27636ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
27647d9119bdSJack F Vogel 
27657d9119bdSJack F Vogel 	/* disable Rx path while enabling/disabling workaround */
27667d9119bdSJack F Vogel 	hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg);
27674dab5c37SJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20),
27684dab5c37SJack F Vogel 					phy_reg | (1 << 14));
27697d9119bdSJack F Vogel 	if (ret_val)
27706ab6bfe3SJack F Vogel 		return ret_val;
27717d9119bdSJack F Vogel 
27727d9119bdSJack F Vogel 	if (enable) {
27737609433eSJack F Vogel 		/* Write Rx addresses (rar_entry_count for RAL/H, and
27747d9119bdSJack F Vogel 		 * SHRAL/H) and initial CRC values to the MAC
27757d9119bdSJack F Vogel 		 */
27767609433eSJack F Vogel 		for (i = 0; i < hw->mac.rar_entry_count; i++) {
27777d9119bdSJack F Vogel 			u8 mac_addr[ETH_ADDR_LEN] = {0};
27787d9119bdSJack F Vogel 			u32 addr_high, addr_low;
27797d9119bdSJack F Vogel 
27807d9119bdSJack F Vogel 			addr_high = E1000_READ_REG(hw, E1000_RAH(i));
27817d9119bdSJack F Vogel 			if (!(addr_high & E1000_RAH_AV))
27827d9119bdSJack F Vogel 				continue;
27837d9119bdSJack F Vogel 			addr_low = E1000_READ_REG(hw, E1000_RAL(i));
27847d9119bdSJack F Vogel 			mac_addr[0] = (addr_low & 0xFF);
27857d9119bdSJack F Vogel 			mac_addr[1] = ((addr_low >> 8) & 0xFF);
27867d9119bdSJack F Vogel 			mac_addr[2] = ((addr_low >> 16) & 0xFF);
27877d9119bdSJack F Vogel 			mac_addr[3] = ((addr_low >> 24) & 0xFF);
27887d9119bdSJack F Vogel 			mac_addr[4] = (addr_high & 0xFF);
27897d9119bdSJack F Vogel 			mac_addr[5] = ((addr_high >> 8) & 0xFF);
27907d9119bdSJack F Vogel 
27917d9119bdSJack F Vogel 			E1000_WRITE_REG(hw, E1000_PCH_RAICC(i),
27927d9119bdSJack F Vogel 					e1000_calc_rx_da_crc(mac_addr));
27937d9119bdSJack F Vogel 		}
27947d9119bdSJack F Vogel 
27957d9119bdSJack F Vogel 		/* Write Rx addresses to the PHY */
27967d9119bdSJack F Vogel 		e1000_copy_rx_addrs_to_phy_ich8lan(hw);
27977d9119bdSJack F Vogel 
27987d9119bdSJack F Vogel 		/* Enable jumbo frame workaround in the MAC */
27997d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
28007d9119bdSJack F Vogel 		mac_reg &= ~(1 << 14);
28017d9119bdSJack F Vogel 		mac_reg |= (7 << 15);
28027d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
28037d9119bdSJack F Vogel 
28047d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RCTL);
28057d9119bdSJack F Vogel 		mac_reg |= E1000_RCTL_SECRC;
28067d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
28077d9119bdSJack F Vogel 
28087d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
28097d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
28107d9119bdSJack F Vogel 						&data);
28117d9119bdSJack F Vogel 		if (ret_val)
28126ab6bfe3SJack F Vogel 			return ret_val;
28137d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
28147d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
28157d9119bdSJack F Vogel 						data | (1 << 0));
28167d9119bdSJack F Vogel 		if (ret_val)
28176ab6bfe3SJack F Vogel 			return ret_val;
28187d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
28197d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
28207d9119bdSJack F Vogel 						&data);
28217d9119bdSJack F Vogel 		if (ret_val)
28226ab6bfe3SJack F Vogel 			return ret_val;
28237d9119bdSJack F Vogel 		data &= ~(0xF << 8);
28247d9119bdSJack F Vogel 		data |= (0xB << 8);
28257d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
28267d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
28277d9119bdSJack F Vogel 						data);
28287d9119bdSJack F Vogel 		if (ret_val)
28296ab6bfe3SJack F Vogel 			return ret_val;
28307d9119bdSJack F Vogel 
28317d9119bdSJack F Vogel 		/* Enable jumbo frame workaround in the PHY */
28327d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
28337d9119bdSJack F Vogel 		data &= ~(0x7F << 5);
28347d9119bdSJack F Vogel 		data |= (0x37 << 5);
28357d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
28367d9119bdSJack F Vogel 		if (ret_val)
28376ab6bfe3SJack F Vogel 			return ret_val;
28387d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
28397d9119bdSJack F Vogel 		data &= ~(1 << 13);
28407d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
28417d9119bdSJack F Vogel 		if (ret_val)
28426ab6bfe3SJack F Vogel 			return ret_val;
28437d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
28447d9119bdSJack F Vogel 		data &= ~(0x3FF << 2);
28458cc64f1eSJack F Vogel 		data |= (E1000_TX_PTR_GAP << 2);
28467d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
28477d9119bdSJack F Vogel 		if (ret_val)
28486ab6bfe3SJack F Vogel 			return ret_val;
28494dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0xF100);
28507d9119bdSJack F Vogel 		if (ret_val)
28516ab6bfe3SJack F Vogel 			return ret_val;
28527d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
28534dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data |
28544dab5c37SJack F Vogel 						(1 << 10));
28557d9119bdSJack F Vogel 		if (ret_val)
28566ab6bfe3SJack F Vogel 			return ret_val;
28577d9119bdSJack F Vogel 	} else {
28587d9119bdSJack F Vogel 		/* Write MAC register values back to h/w defaults */
28597d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
28607d9119bdSJack F Vogel 		mac_reg &= ~(0xF << 14);
28617d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
28627d9119bdSJack F Vogel 
28637d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RCTL);
28647d9119bdSJack F Vogel 		mac_reg &= ~E1000_RCTL_SECRC;
28657d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
28667d9119bdSJack F Vogel 
28677d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
28687d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
28697d9119bdSJack F Vogel 						&data);
28707d9119bdSJack F Vogel 		if (ret_val)
28716ab6bfe3SJack F Vogel 			return ret_val;
28727d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
28737d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
28747d9119bdSJack F Vogel 						data & ~(1 << 0));
28757d9119bdSJack F Vogel 		if (ret_val)
28766ab6bfe3SJack F Vogel 			return ret_val;
28777d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
28787d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
28797d9119bdSJack F Vogel 						&data);
28807d9119bdSJack F Vogel 		if (ret_val)
28816ab6bfe3SJack F Vogel 			return ret_val;
28827d9119bdSJack F Vogel 		data &= ~(0xF << 8);
28837d9119bdSJack F Vogel 		data |= (0xB << 8);
28847d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
28857d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
28867d9119bdSJack F Vogel 						data);
28877d9119bdSJack F Vogel 		if (ret_val)
28886ab6bfe3SJack F Vogel 			return ret_val;
28897d9119bdSJack F Vogel 
28907d9119bdSJack F Vogel 		/* Write PHY register values back to h/w defaults */
28917d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
28927d9119bdSJack F Vogel 		data &= ~(0x7F << 5);
28937d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
28947d9119bdSJack F Vogel 		if (ret_val)
28956ab6bfe3SJack F Vogel 			return ret_val;
28967d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
28977d9119bdSJack F Vogel 		data |= (1 << 13);
28987d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
28997d9119bdSJack F Vogel 		if (ret_val)
29006ab6bfe3SJack F Vogel 			return ret_val;
29017d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
29027d9119bdSJack F Vogel 		data &= ~(0x3FF << 2);
29037d9119bdSJack F Vogel 		data |= (0x8 << 2);
29047d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
29057d9119bdSJack F Vogel 		if (ret_val)
29066ab6bfe3SJack F Vogel 			return ret_val;
29077d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0x7E00);
29087d9119bdSJack F Vogel 		if (ret_val)
29096ab6bfe3SJack F Vogel 			return ret_val;
29107d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
29114dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data &
29124dab5c37SJack F Vogel 						~(1 << 10));
29137d9119bdSJack F Vogel 		if (ret_val)
29146ab6bfe3SJack F Vogel 			return ret_val;
29157d9119bdSJack F Vogel 	}
29167d9119bdSJack F Vogel 
29177d9119bdSJack F Vogel 	/* re-enable Rx path after enabling/disabling workaround */
29186ab6bfe3SJack F Vogel 	return hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg &
29194dab5c37SJack F Vogel 				     ~(1 << 14));
29207d9119bdSJack F Vogel }
29217d9119bdSJack F Vogel 
29227d9119bdSJack F Vogel /**
29237d9119bdSJack F Vogel  *  e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be
29247d9119bdSJack F Vogel  *  done after every PHY reset.
29257d9119bdSJack F Vogel  **/
29267d9119bdSJack F Vogel static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw)
29277d9119bdSJack F Vogel {
29287d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
29297d9119bdSJack F Vogel 
29307d9119bdSJack F Vogel 	DEBUGFUNC("e1000_lv_phy_workarounds_ich8lan");
29317d9119bdSJack F Vogel 
29327d9119bdSJack F Vogel 	if (hw->mac.type != e1000_pch2lan)
29336ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
29347d9119bdSJack F Vogel 
29357d9119bdSJack F Vogel 	/* Set MDIO slow mode before any other MDIO access */
29367d9119bdSJack F Vogel 	ret_val = e1000_set_mdio_slow_mode_hv(hw);
29376ab6bfe3SJack F Vogel 	if (ret_val)
29386ab6bfe3SJack F Vogel 		return ret_val;
29397d9119bdSJack F Vogel 
29404dab5c37SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
29414dab5c37SJack F Vogel 	if (ret_val)
29426ab6bfe3SJack F Vogel 		return ret_val;
29434dab5c37SJack F Vogel 	/* set MSE higher to enable link to stay up when noise is high */
29446ab6bfe3SJack F Vogel 	ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_THRESHOLD, 0x0034);
29454dab5c37SJack F Vogel 	if (ret_val)
29464dab5c37SJack F Vogel 		goto release;
29474dab5c37SJack F Vogel 	/* drop link after 5 times MSE threshold was reached */
29486ab6bfe3SJack F Vogel 	ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_LINK_DOWN, 0x0005);
29494dab5c37SJack F Vogel release:
29504dab5c37SJack F Vogel 	hw->phy.ops.release(hw);
29514dab5c37SJack F Vogel 
29527d9119bdSJack F Vogel 	return ret_val;
29537d9119bdSJack F Vogel }
29547d9119bdSJack F Vogel 
29557d9119bdSJack F Vogel /**
29567d9119bdSJack F Vogel  *  e1000_k1_gig_workaround_lv - K1 Si workaround
29577d9119bdSJack F Vogel  *  @hw:   pointer to the HW structure
29587d9119bdSJack F Vogel  *
29598cc64f1eSJack F Vogel  *  Workaround to set the K1 beacon duration for 82579 parts in 10Mbps
29608cc64f1eSJack F Vogel  *  Disable K1 for 1000 and 100 speeds
29617d9119bdSJack F Vogel  **/
29627d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw)
29637d9119bdSJack F Vogel {
29647d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
29657d9119bdSJack F Vogel 	u16 status_reg = 0;
29667d9119bdSJack F Vogel 
29677d9119bdSJack F Vogel 	DEBUGFUNC("e1000_k1_workaround_lv");
29687d9119bdSJack F Vogel 
29697d9119bdSJack F Vogel 	if (hw->mac.type != e1000_pch2lan)
29706ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
29717d9119bdSJack F Vogel 
29728cc64f1eSJack F Vogel 	/* Set K1 beacon duration based on 10Mbs speed */
29737d9119bdSJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, HV_M_STATUS, &status_reg);
29747d9119bdSJack F Vogel 	if (ret_val)
29756ab6bfe3SJack F Vogel 		return ret_val;
29767d9119bdSJack F Vogel 
29777d9119bdSJack F Vogel 	if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE))
29787d9119bdSJack F Vogel 	    == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) {
29798cc64f1eSJack F Vogel 		if (status_reg &
29808cc64f1eSJack F Vogel 		    (HV_M_STATUS_SPEED_1000 | HV_M_STATUS_SPEED_100)) {
29816ab6bfe3SJack F Vogel 			u16 pm_phy_reg;
29826ab6bfe3SJack F Vogel 
29838cc64f1eSJack F Vogel 			/* LV 1G/100 Packet drop issue wa  */
29846ab6bfe3SJack F Vogel 			ret_val = hw->phy.ops.read_reg(hw, HV_PM_CTRL,
29856ab6bfe3SJack F Vogel 						       &pm_phy_reg);
29866ab6bfe3SJack F Vogel 			if (ret_val)
29876ab6bfe3SJack F Vogel 				return ret_val;
29888cc64f1eSJack F Vogel 			pm_phy_reg &= ~HV_PM_CTRL_K1_ENABLE;
29896ab6bfe3SJack F Vogel 			ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL,
29906ab6bfe3SJack F Vogel 							pm_phy_reg);
29916ab6bfe3SJack F Vogel 			if (ret_val)
29926ab6bfe3SJack F Vogel 				return ret_val;
29934dab5c37SJack F Vogel 		} else {
29948cc64f1eSJack F Vogel 			u32 mac_reg;
29958cc64f1eSJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4);
29968cc64f1eSJack F Vogel 			mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
29974dab5c37SJack F Vogel 			mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
29987d9119bdSJack F Vogel 			E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg);
29998cc64f1eSJack F Vogel 		}
30007d9119bdSJack F Vogel 	}
30017d9119bdSJack F Vogel 
30027d9119bdSJack F Vogel 	return ret_val;
30037d9119bdSJack F Vogel }
30047d9119bdSJack F Vogel 
30057d9119bdSJack F Vogel /**
30067d9119bdSJack F Vogel  *  e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware
30077d9119bdSJack F Vogel  *  @hw:   pointer to the HW structure
3008730d3130SJack F Vogel  *  @gate: boolean set to TRUE to gate, FALSE to ungate
30097d9119bdSJack F Vogel  *
30107d9119bdSJack F Vogel  *  Gate/ungate the automatic PHY configuration via hardware; perform
30117d9119bdSJack F Vogel  *  the configuration via software instead.
30127d9119bdSJack F Vogel  **/
30137d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate)
30147d9119bdSJack F Vogel {
30157d9119bdSJack F Vogel 	u32 extcnf_ctrl;
30167d9119bdSJack F Vogel 
30177d9119bdSJack F Vogel 	DEBUGFUNC("e1000_gate_hw_phy_config_ich8lan");
30187d9119bdSJack F Vogel 
30196ab6bfe3SJack F Vogel 	if (hw->mac.type < e1000_pch2lan)
30207d9119bdSJack F Vogel 		return;
30217d9119bdSJack F Vogel 
30227d9119bdSJack F Vogel 	extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
30237d9119bdSJack F Vogel 
30247d9119bdSJack F Vogel 	if (gate)
30257d9119bdSJack F Vogel 		extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
30267d9119bdSJack F Vogel 	else
30277d9119bdSJack F Vogel 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG;
30287d9119bdSJack F Vogel 
30297d9119bdSJack F Vogel 	E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
30307d9119bdSJack F Vogel }
30317d9119bdSJack F Vogel 
30327d9119bdSJack F Vogel /**
30339d81738fSJack F Vogel  *  e1000_lan_init_done_ich8lan - Check for PHY config completion
30348cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
30358cfa0ad2SJack F Vogel  *
30369d81738fSJack F Vogel  *  Check the appropriate indication the MAC has finished configuring the
30379d81738fSJack F Vogel  *  PHY after a software reset.
30388cfa0ad2SJack F Vogel  **/
30399d81738fSJack F Vogel static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw)
30408cfa0ad2SJack F Vogel {
30419d81738fSJack F Vogel 	u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT;
30428cfa0ad2SJack F Vogel 
30439d81738fSJack F Vogel 	DEBUGFUNC("e1000_lan_init_done_ich8lan");
30448cfa0ad2SJack F Vogel 
30459d81738fSJack F Vogel 	/* Wait for basic configuration completes before proceeding */
30469d81738fSJack F Vogel 	do {
30479d81738fSJack F Vogel 		data = E1000_READ_REG(hw, E1000_STATUS);
30489d81738fSJack F Vogel 		data &= E1000_STATUS_LAN_INIT_DONE;
30499d81738fSJack F Vogel 		usec_delay(100);
30509d81738fSJack F Vogel 	} while ((!data) && --loop);
30518cfa0ad2SJack F Vogel 
30526ab6bfe3SJack F Vogel 	/* If basic configuration is incomplete before the above loop
30539d81738fSJack F Vogel 	 * count reaches 0, loading the configuration from NVM will
30549d81738fSJack F Vogel 	 * leave the PHY in a bad state possibly resulting in no link.
30559d81738fSJack F Vogel 	 */
30569d81738fSJack F Vogel 	if (loop == 0)
30579d81738fSJack F Vogel 		DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n");
30588cfa0ad2SJack F Vogel 
30599d81738fSJack F Vogel 	/* Clear the Init Done bit for the next init event */
30609d81738fSJack F Vogel 	data = E1000_READ_REG(hw, E1000_STATUS);
30619d81738fSJack F Vogel 	data &= ~E1000_STATUS_LAN_INIT_DONE;
30629d81738fSJack F Vogel 	E1000_WRITE_REG(hw, E1000_STATUS, data);
30638cfa0ad2SJack F Vogel }
30648cfa0ad2SJack F Vogel 
30658cfa0ad2SJack F Vogel /**
30667d9119bdSJack F Vogel  *  e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset
30677d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
30687d9119bdSJack F Vogel  **/
30697d9119bdSJack F Vogel static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
30707d9119bdSJack F Vogel {
30717d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
30727d9119bdSJack F Vogel 	u16 reg;
30737d9119bdSJack F Vogel 
30747d9119bdSJack F Vogel 	DEBUGFUNC("e1000_post_phy_reset_ich8lan");
30757d9119bdSJack F Vogel 
30767d9119bdSJack F Vogel 	if (hw->phy.ops.check_reset_block(hw))
30776ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
30787d9119bdSJack F Vogel 
30797d9119bdSJack F Vogel 	/* Allow time for h/w to get to quiescent state after reset */
30807d9119bdSJack F Vogel 	msec_delay(10);
30817d9119bdSJack F Vogel 
30827d9119bdSJack F Vogel 	/* Perform any necessary post-reset workarounds */
30837d9119bdSJack F Vogel 	switch (hw->mac.type) {
30847d9119bdSJack F Vogel 	case e1000_pchlan:
30857d9119bdSJack F Vogel 		ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
30867d9119bdSJack F Vogel 		if (ret_val)
30876ab6bfe3SJack F Vogel 			return ret_val;
30887d9119bdSJack F Vogel 		break;
30897d9119bdSJack F Vogel 	case e1000_pch2lan:
30907d9119bdSJack F Vogel 		ret_val = e1000_lv_phy_workarounds_ich8lan(hw);
30917d9119bdSJack F Vogel 		if (ret_val)
30926ab6bfe3SJack F Vogel 			return ret_val;
30937d9119bdSJack F Vogel 		break;
30947d9119bdSJack F Vogel 	default:
30957d9119bdSJack F Vogel 		break;
30967d9119bdSJack F Vogel 	}
30977d9119bdSJack F Vogel 
30984dab5c37SJack F Vogel 	/* Clear the host wakeup bit after lcd reset */
30994dab5c37SJack F Vogel 	if (hw->mac.type >= e1000_pchlan) {
31004dab5c37SJack F Vogel 		hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, &reg);
31014dab5c37SJack F Vogel 		reg &= ~BM_WUC_HOST_WU_BIT;
31024dab5c37SJack F Vogel 		hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, reg);
31037d9119bdSJack F Vogel 	}
31047d9119bdSJack F Vogel 
31057d9119bdSJack F Vogel 	/* Configure the LCD with the extended configuration region in NVM */
31067d9119bdSJack F Vogel 	ret_val = e1000_sw_lcd_config_ich8lan(hw);
31077d9119bdSJack F Vogel 	if (ret_val)
31086ab6bfe3SJack F Vogel 		return ret_val;
31097d9119bdSJack F Vogel 
31107d9119bdSJack F Vogel 	/* Configure the LCD with the OEM bits in NVM */
31117d9119bdSJack F Vogel 	ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE);
31127d9119bdSJack F Vogel 
3113730d3130SJack F Vogel 	if (hw->mac.type == e1000_pch2lan) {
31147d9119bdSJack F Vogel 		/* Ungate automatic PHY configuration on non-managed 82579 */
3115730d3130SJack F Vogel 		if (!(E1000_READ_REG(hw, E1000_FWSM) &
3116730d3130SJack F Vogel 		    E1000_ICH_FWSM_FW_VALID)) {
31177d9119bdSJack F Vogel 			msec_delay(10);
31187d9119bdSJack F Vogel 			e1000_gate_hw_phy_config_ich8lan(hw, FALSE);
31197d9119bdSJack F Vogel 		}
31207d9119bdSJack F Vogel 
3121730d3130SJack F Vogel 		/* Set EEE LPI Update Timer to 200usec */
3122730d3130SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
3123730d3130SJack F Vogel 		if (ret_val)
31246ab6bfe3SJack F Vogel 			return ret_val;
31256ab6bfe3SJack F Vogel 		ret_val = e1000_write_emi_reg_locked(hw,
31266ab6bfe3SJack F Vogel 						     I82579_LPI_UPDATE_TIMER,
3127730d3130SJack F Vogel 						     0x1387);
3128730d3130SJack F Vogel 		hw->phy.ops.release(hw);
3129730d3130SJack F Vogel 	}
3130730d3130SJack F Vogel 
31317d9119bdSJack F Vogel 	return ret_val;
31327d9119bdSJack F Vogel }
31337d9119bdSJack F Vogel 
31347d9119bdSJack F Vogel /**
31358cfa0ad2SJack F Vogel  *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
31368cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
31378cfa0ad2SJack F Vogel  *
31388cfa0ad2SJack F Vogel  *  Resets the PHY
31398cfa0ad2SJack F Vogel  *  This is a function pointer entry point called by drivers
31408cfa0ad2SJack F Vogel  *  or other shared routines.
31418cfa0ad2SJack F Vogel  **/
31428cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
31438cfa0ad2SJack F Vogel {
31444edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
31458cfa0ad2SJack F Vogel 
31468cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
31478cfa0ad2SJack F Vogel 
31487d9119bdSJack F Vogel 	/* Gate automatic PHY configuration by hardware on non-managed 82579 */
31497d9119bdSJack F Vogel 	if ((hw->mac.type == e1000_pch2lan) &&
31507d9119bdSJack F Vogel 	    !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
31517d9119bdSJack F Vogel 		e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
31527d9119bdSJack F Vogel 
31538cfa0ad2SJack F Vogel 	ret_val = e1000_phy_hw_reset_generic(hw);
31548cfa0ad2SJack F Vogel 	if (ret_val)
31558cfa0ad2SJack F Vogel 		return ret_val;
31566ab6bfe3SJack F Vogel 
31576ab6bfe3SJack F Vogel 	return e1000_post_phy_reset_ich8lan(hw);
31588cfa0ad2SJack F Vogel }
31598cfa0ad2SJack F Vogel 
31608cfa0ad2SJack F Vogel /**
31614edd8523SJack F Vogel  *  e1000_set_lplu_state_pchlan - Set Low Power Link Up state
31628cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
31634edd8523SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
31648cfa0ad2SJack F Vogel  *
31654edd8523SJack F Vogel  *  Sets the LPLU state according to the active flag.  For PCH, if OEM write
31664edd8523SJack F Vogel  *  bit are disabled in the NVM, writing the LPLU bits in the MAC will not set
31674edd8523SJack F Vogel  *  the phy speed. This function will manually set the LPLU bit and restart
31684edd8523SJack F Vogel  *  auto-neg as hw would do. D3 and D0 LPLU will call the same function
31694edd8523SJack F Vogel  *  since it configures the same bit.
31708cfa0ad2SJack F Vogel  **/
31714edd8523SJack F Vogel static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
31728cfa0ad2SJack F Vogel {
31736ab6bfe3SJack F Vogel 	s32 ret_val;
31744edd8523SJack F Vogel 	u16 oem_reg;
31758cfa0ad2SJack F Vogel 
31764edd8523SJack F Vogel 	DEBUGFUNC("e1000_set_lplu_state_pchlan");
31774edd8523SJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg);
31788cfa0ad2SJack F Vogel 	if (ret_val)
31796ab6bfe3SJack F Vogel 		return ret_val;
31808cfa0ad2SJack F Vogel 
31814edd8523SJack F Vogel 	if (active)
31824edd8523SJack F Vogel 		oem_reg |= HV_OEM_BITS_LPLU;
31834edd8523SJack F Vogel 	else
31844edd8523SJack F Vogel 		oem_reg &= ~HV_OEM_BITS_LPLU;
31858cfa0ad2SJack F Vogel 
31864dab5c37SJack F Vogel 	if (!hw->phy.ops.check_reset_block(hw))
31874edd8523SJack F Vogel 		oem_reg |= HV_OEM_BITS_RESTART_AN;
31884dab5c37SJack F Vogel 
31896ab6bfe3SJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg);
31908cfa0ad2SJack F Vogel }
31918cfa0ad2SJack F Vogel 
31928cfa0ad2SJack F Vogel /**
31938cfa0ad2SJack F Vogel  *  e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
31948cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
31958cfa0ad2SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
31968cfa0ad2SJack F Vogel  *
31978cfa0ad2SJack F Vogel  *  Sets the LPLU D0 state according to the active flag.  When
31988cfa0ad2SJack F Vogel  *  activating LPLU this function also disables smart speed
31998cfa0ad2SJack F Vogel  *  and vice versa.  LPLU will not be activated unless the
32008cfa0ad2SJack F Vogel  *  device autonegotiation advertisement meets standards of
32018cfa0ad2SJack F Vogel  *  either 10 or 10/100 or 10/100/1000 at all duplexes.
32028cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
32038cfa0ad2SJack F Vogel  *  PHY setup routines.
32048cfa0ad2SJack F Vogel  **/
3205daf9197cSJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
32068cfa0ad2SJack F Vogel {
32078cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
32088cfa0ad2SJack F Vogel 	u32 phy_ctrl;
32098cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
32108cfa0ad2SJack F Vogel 	u16 data;
32118cfa0ad2SJack F Vogel 
32128cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan");
32138cfa0ad2SJack F Vogel 
32148cfa0ad2SJack F Vogel 	if (phy->type == e1000_phy_ife)
32156ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
32168cfa0ad2SJack F Vogel 
32178cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
32188cfa0ad2SJack F Vogel 
32198cfa0ad2SJack F Vogel 	if (active) {
32208cfa0ad2SJack F Vogel 		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
32218cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
32228cfa0ad2SJack F Vogel 
32239d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
32246ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
32259d81738fSJack F Vogel 
32266ab6bfe3SJack F Vogel 		/* Call gig speed drop workaround on LPLU before accessing
32278cfa0ad2SJack F Vogel 		 * any PHY registers
32288cfa0ad2SJack F Vogel 		 */
32299d81738fSJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
32308cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
32318cfa0ad2SJack F Vogel 
32328cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
32338cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw,
32348cfa0ad2SJack F Vogel 					    IGP01E1000_PHY_PORT_CONFIG,
32358cfa0ad2SJack F Vogel 					    &data);
32366ab6bfe3SJack F Vogel 		if (ret_val)
32376ab6bfe3SJack F Vogel 			return ret_val;
32388cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
32398cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
32408cfa0ad2SJack F Vogel 					     IGP01E1000_PHY_PORT_CONFIG,
32418cfa0ad2SJack F Vogel 					     data);
32428cfa0ad2SJack F Vogel 		if (ret_val)
32436ab6bfe3SJack F Vogel 			return ret_val;
32448cfa0ad2SJack F Vogel 	} else {
32458cfa0ad2SJack F Vogel 		phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
32468cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
32478cfa0ad2SJack F Vogel 
32489d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
32496ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
32509d81738fSJack F Vogel 
32516ab6bfe3SJack F Vogel 		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
32528cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
32538cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
32548cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
32558cfa0ad2SJack F Vogel 		 */
32568cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
32578cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
32588cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
32598cfa0ad2SJack F Vogel 						    &data);
32608cfa0ad2SJack F Vogel 			if (ret_val)
32616ab6bfe3SJack F Vogel 				return ret_val;
32628cfa0ad2SJack F Vogel 
32638cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
32648cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
32658cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
32668cfa0ad2SJack F Vogel 						     data);
32678cfa0ad2SJack F Vogel 			if (ret_val)
32686ab6bfe3SJack F Vogel 				return ret_val;
32698cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
32708cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
32718cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
32728cfa0ad2SJack F Vogel 						    &data);
32738cfa0ad2SJack F Vogel 			if (ret_val)
32746ab6bfe3SJack F Vogel 				return ret_val;
32758cfa0ad2SJack F Vogel 
32768cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
32778cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
32788cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
32798cfa0ad2SJack F Vogel 						     data);
32808cfa0ad2SJack F Vogel 			if (ret_val)
32816ab6bfe3SJack F Vogel 				return ret_val;
32828cfa0ad2SJack F Vogel 		}
32838cfa0ad2SJack F Vogel 	}
32848cfa0ad2SJack F Vogel 
32856ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
32868cfa0ad2SJack F Vogel }
32878cfa0ad2SJack F Vogel 
32888cfa0ad2SJack F Vogel /**
32898cfa0ad2SJack F Vogel  *  e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
32908cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
32918cfa0ad2SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
32928cfa0ad2SJack F Vogel  *
32938cfa0ad2SJack F Vogel  *  Sets the LPLU D3 state according to the active flag.  When
32948cfa0ad2SJack F Vogel  *  activating LPLU this function also disables smart speed
32958cfa0ad2SJack F Vogel  *  and vice versa.  LPLU will not be activated unless the
32968cfa0ad2SJack F Vogel  *  device autonegotiation advertisement meets standards of
32978cfa0ad2SJack F Vogel  *  either 10 or 10/100 or 10/100/1000 at all duplexes.
32988cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
32998cfa0ad2SJack F Vogel  *  PHY setup routines.
33008cfa0ad2SJack F Vogel  **/
3301daf9197cSJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
33028cfa0ad2SJack F Vogel {
33038cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
33048cfa0ad2SJack F Vogel 	u32 phy_ctrl;
33058cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
33068cfa0ad2SJack F Vogel 	u16 data;
33078cfa0ad2SJack F Vogel 
33088cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan");
33098cfa0ad2SJack F Vogel 
33108cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
33118cfa0ad2SJack F Vogel 
33128cfa0ad2SJack F Vogel 	if (!active) {
33138cfa0ad2SJack F Vogel 		phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
33148cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
33159d81738fSJack F Vogel 
33169d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
33176ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
33189d81738fSJack F Vogel 
33196ab6bfe3SJack F Vogel 		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
33208cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
33218cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
33228cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
33238cfa0ad2SJack F Vogel 		 */
33248cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
33258cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
33268cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
33278cfa0ad2SJack F Vogel 						    &data);
33288cfa0ad2SJack F Vogel 			if (ret_val)
33296ab6bfe3SJack F Vogel 				return ret_val;
33308cfa0ad2SJack F Vogel 
33318cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
33328cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
33338cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
33348cfa0ad2SJack F Vogel 						     data);
33358cfa0ad2SJack F Vogel 			if (ret_val)
33366ab6bfe3SJack F Vogel 				return ret_val;
33378cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
33388cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
33398cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
33408cfa0ad2SJack F Vogel 						    &data);
33418cfa0ad2SJack F Vogel 			if (ret_val)
33426ab6bfe3SJack F Vogel 				return ret_val;
33438cfa0ad2SJack F Vogel 
33448cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
33458cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
33468cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
33478cfa0ad2SJack F Vogel 						     data);
33488cfa0ad2SJack F Vogel 			if (ret_val)
33496ab6bfe3SJack F Vogel 				return ret_val;
33508cfa0ad2SJack F Vogel 		}
33518cfa0ad2SJack F Vogel 	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
33528cfa0ad2SJack F Vogel 		   (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
33538cfa0ad2SJack F Vogel 		   (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
33548cfa0ad2SJack F Vogel 		phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
33558cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
33568cfa0ad2SJack F Vogel 
33579d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
33586ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
33599d81738fSJack F Vogel 
33606ab6bfe3SJack F Vogel 		/* Call gig speed drop workaround on LPLU before accessing
33618cfa0ad2SJack F Vogel 		 * any PHY registers
33628cfa0ad2SJack F Vogel 		 */
33639d81738fSJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
33648cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
33658cfa0ad2SJack F Vogel 
33668cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
33678cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw,
33688cfa0ad2SJack F Vogel 					    IGP01E1000_PHY_PORT_CONFIG,
33698cfa0ad2SJack F Vogel 					    &data);
33708cfa0ad2SJack F Vogel 		if (ret_val)
33716ab6bfe3SJack F Vogel 			return ret_val;
33728cfa0ad2SJack F Vogel 
33738cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
33748cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
33758cfa0ad2SJack F Vogel 					     IGP01E1000_PHY_PORT_CONFIG,
33768cfa0ad2SJack F Vogel 					     data);
33778cfa0ad2SJack F Vogel 	}
33788cfa0ad2SJack F Vogel 
33798cfa0ad2SJack F Vogel 	return ret_val;
33808cfa0ad2SJack F Vogel }
33818cfa0ad2SJack F Vogel 
33828cfa0ad2SJack F Vogel /**
33838cfa0ad2SJack F Vogel  *  e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
33848cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
33858cfa0ad2SJack F Vogel  *  @bank:  pointer to the variable that returns the active bank
33868cfa0ad2SJack F Vogel  *
33878cfa0ad2SJack F Vogel  *  Reads signature byte from the NVM using the flash access registers.
3388d035aa2dSJack F Vogel  *  Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
33898cfa0ad2SJack F Vogel  **/
33908cfa0ad2SJack F Vogel static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
33918cfa0ad2SJack F Vogel {
3392d035aa2dSJack F Vogel 	u32 eecd;
33938cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
33948cfa0ad2SJack F Vogel 	u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
33958cfa0ad2SJack F Vogel 	u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
3396*c80429ceSEric Joyner 	u32 nvm_dword = 0;
3397d035aa2dSJack F Vogel 	u8 sig_byte = 0;
33986ab6bfe3SJack F Vogel 	s32 ret_val;
33998cfa0ad2SJack F Vogel 
34007d9119bdSJack F Vogel 	DEBUGFUNC("e1000_valid_nvm_bank_detect_ich8lan");
34017d9119bdSJack F Vogel 
3402d035aa2dSJack F Vogel 	switch (hw->mac.type) {
3403*c80429ceSEric Joyner 	case e1000_pch_spt:
3404*c80429ceSEric Joyner 		bank1_offset = nvm->flash_bank_size;
3405*c80429ceSEric Joyner 		act_offset = E1000_ICH_NVM_SIG_WORD;
3406*c80429ceSEric Joyner 
3407*c80429ceSEric Joyner 		/* set bank to 0 in case flash read fails */
3408*c80429ceSEric Joyner 		*bank = 0;
3409*c80429ceSEric Joyner 
3410*c80429ceSEric Joyner 		/* Check bank 0 */
3411*c80429ceSEric Joyner 		ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset,
3412*c80429ceSEric Joyner 							 &nvm_dword);
3413*c80429ceSEric Joyner 		if (ret_val)
3414*c80429ceSEric Joyner 			return ret_val;
3415*c80429ceSEric Joyner 		sig_byte = (u8)((nvm_dword & 0xFF00) >> 8);
3416*c80429ceSEric Joyner 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
3417*c80429ceSEric Joyner 		    E1000_ICH_NVM_SIG_VALUE) {
3418*c80429ceSEric Joyner 			*bank = 0;
3419*c80429ceSEric Joyner 			return E1000_SUCCESS;
3420*c80429ceSEric Joyner 		}
3421*c80429ceSEric Joyner 
3422*c80429ceSEric Joyner 		/* Check bank 1 */
3423*c80429ceSEric Joyner 		ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset +
3424*c80429ceSEric Joyner 							 bank1_offset,
3425*c80429ceSEric Joyner 							 &nvm_dword);
3426*c80429ceSEric Joyner 		if (ret_val)
3427*c80429ceSEric Joyner 			return ret_val;
3428*c80429ceSEric Joyner 		sig_byte = (u8)((nvm_dword & 0xFF00) >> 8);
3429*c80429ceSEric Joyner 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
3430*c80429ceSEric Joyner 		    E1000_ICH_NVM_SIG_VALUE) {
3431*c80429ceSEric Joyner 			*bank = 1;
3432*c80429ceSEric Joyner 			return E1000_SUCCESS;
3433*c80429ceSEric Joyner 		}
3434*c80429ceSEric Joyner 
3435*c80429ceSEric Joyner 		DEBUGOUT("ERROR: No valid NVM bank present\n");
3436*c80429ceSEric Joyner 		return -E1000_ERR_NVM;
3437d035aa2dSJack F Vogel 	case e1000_ich8lan:
3438d035aa2dSJack F Vogel 	case e1000_ich9lan:
3439d035aa2dSJack F Vogel 		eecd = E1000_READ_REG(hw, E1000_EECD);
3440d035aa2dSJack F Vogel 		if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
3441d035aa2dSJack F Vogel 		    E1000_EECD_SEC1VAL_VALID_MASK) {
3442d035aa2dSJack F Vogel 			if (eecd & E1000_EECD_SEC1VAL)
34438cfa0ad2SJack F Vogel 				*bank = 1;
34448cfa0ad2SJack F Vogel 			else
34458cfa0ad2SJack F Vogel 				*bank = 0;
3446d035aa2dSJack F Vogel 
34476ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
3448d035aa2dSJack F Vogel 		}
34494dab5c37SJack F Vogel 		DEBUGOUT("Unable to determine valid NVM bank via EEC - reading flash signature\n");
3450d035aa2dSJack F Vogel 		/* fall-thru */
3451d035aa2dSJack F Vogel 	default:
3452d035aa2dSJack F Vogel 		/* set bank to 0 in case flash read fails */
34538cfa0ad2SJack F Vogel 		*bank = 0;
34548cfa0ad2SJack F Vogel 
3455d035aa2dSJack F Vogel 		/* Check bank 0 */
3456d035aa2dSJack F Vogel 		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
3457d035aa2dSJack F Vogel 							&sig_byte);
3458d035aa2dSJack F Vogel 		if (ret_val)
34596ab6bfe3SJack F Vogel 			return ret_val;
3460d035aa2dSJack F Vogel 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
3461d035aa2dSJack F Vogel 		    E1000_ICH_NVM_SIG_VALUE) {
3462d035aa2dSJack F Vogel 			*bank = 0;
34636ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
3464d035aa2dSJack F Vogel 		}
3465d035aa2dSJack F Vogel 
3466d035aa2dSJack F Vogel 		/* Check bank 1 */
3467d035aa2dSJack F Vogel 		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
3468d035aa2dSJack F Vogel 							bank1_offset,
3469d035aa2dSJack F Vogel 							&sig_byte);
3470d035aa2dSJack F Vogel 		if (ret_val)
34716ab6bfe3SJack F Vogel 			return ret_val;
3472d035aa2dSJack F Vogel 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
3473d035aa2dSJack F Vogel 		    E1000_ICH_NVM_SIG_VALUE) {
34748cfa0ad2SJack F Vogel 			*bank = 1;
34756ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
34768cfa0ad2SJack F Vogel 		}
34778cfa0ad2SJack F Vogel 
3478d035aa2dSJack F Vogel 		DEBUGOUT("ERROR: No valid NVM bank present\n");
34796ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
3480d035aa2dSJack F Vogel 	}
34818cfa0ad2SJack F Vogel }
34828cfa0ad2SJack F Vogel 
34838cfa0ad2SJack F Vogel /**
3484*c80429ceSEric Joyner  *  e1000_read_nvm_spt - NVM access for SPT
3485*c80429ceSEric Joyner  *  @hw: pointer to the HW structure
3486*c80429ceSEric Joyner  *  @offset: The offset (in bytes) of the word(s) to read.
3487*c80429ceSEric Joyner  *  @words: Size of data to read in words.
3488*c80429ceSEric Joyner  *  @data: pointer to the word(s) to read at offset.
3489*c80429ceSEric Joyner  *
3490*c80429ceSEric Joyner  *  Reads a word(s) from the NVM
3491*c80429ceSEric Joyner  **/
3492*c80429ceSEric Joyner static s32 e1000_read_nvm_spt(struct e1000_hw *hw, u16 offset, u16 words,
3493*c80429ceSEric Joyner 			      u16 *data)
3494*c80429ceSEric Joyner {
3495*c80429ceSEric Joyner 	struct e1000_nvm_info *nvm = &hw->nvm;
3496*c80429ceSEric Joyner 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
3497*c80429ceSEric Joyner 	u32 act_offset;
3498*c80429ceSEric Joyner 	s32 ret_val = E1000_SUCCESS;
3499*c80429ceSEric Joyner 	u32 bank = 0;
3500*c80429ceSEric Joyner 	u32 dword = 0;
3501*c80429ceSEric Joyner 	u16 offset_to_read;
3502*c80429ceSEric Joyner 	u16 i;
3503*c80429ceSEric Joyner 
3504*c80429ceSEric Joyner 	DEBUGFUNC("e1000_read_nvm_spt");
3505*c80429ceSEric Joyner 
3506*c80429ceSEric Joyner 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
3507*c80429ceSEric Joyner 	    (words == 0)) {
3508*c80429ceSEric Joyner 		DEBUGOUT("nvm parameter(s) out of bounds\n");
3509*c80429ceSEric Joyner 		ret_val = -E1000_ERR_NVM;
3510*c80429ceSEric Joyner 		goto out;
3511*c80429ceSEric Joyner 	}
3512*c80429ceSEric Joyner 
3513*c80429ceSEric Joyner 	nvm->ops.acquire(hw);
3514*c80429ceSEric Joyner 
3515*c80429ceSEric Joyner 	ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
3516*c80429ceSEric Joyner 	if (ret_val != E1000_SUCCESS) {
3517*c80429ceSEric Joyner 		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
3518*c80429ceSEric Joyner 		bank = 0;
3519*c80429ceSEric Joyner 	}
3520*c80429ceSEric Joyner 
3521*c80429ceSEric Joyner 	act_offset = (bank) ? nvm->flash_bank_size : 0;
3522*c80429ceSEric Joyner 	act_offset += offset;
3523*c80429ceSEric Joyner 
3524*c80429ceSEric Joyner 	ret_val = E1000_SUCCESS;
3525*c80429ceSEric Joyner 
3526*c80429ceSEric Joyner 	for (i = 0; i < words; i += 2) {
3527*c80429ceSEric Joyner 		if (words - i == 1) {
3528*c80429ceSEric Joyner 			if (dev_spec->shadow_ram[offset+i].modified) {
3529*c80429ceSEric Joyner 				data[i] = dev_spec->shadow_ram[offset+i].value;
3530*c80429ceSEric Joyner 			} else {
3531*c80429ceSEric Joyner 				offset_to_read = act_offset + i -
3532*c80429ceSEric Joyner 						 ((act_offset + i) % 2);
3533*c80429ceSEric Joyner 				ret_val =
3534*c80429ceSEric Joyner 				   e1000_read_flash_dword_ich8lan(hw,
3535*c80429ceSEric Joyner 								 offset_to_read,
3536*c80429ceSEric Joyner 								 &dword);
3537*c80429ceSEric Joyner 				if (ret_val)
3538*c80429ceSEric Joyner 					break;
3539*c80429ceSEric Joyner 				if ((act_offset + i) % 2 == 0)
3540*c80429ceSEric Joyner 					data[i] = (u16)(dword & 0xFFFF);
3541*c80429ceSEric Joyner 				else
3542*c80429ceSEric Joyner 					data[i] = (u16)((dword >> 16) & 0xFFFF);
3543*c80429ceSEric Joyner 			}
3544*c80429ceSEric Joyner 		} else {
3545*c80429ceSEric Joyner 			offset_to_read = act_offset + i;
3546*c80429ceSEric Joyner 			if (!(dev_spec->shadow_ram[offset+i].modified) ||
3547*c80429ceSEric Joyner 			    !(dev_spec->shadow_ram[offset+i+1].modified)) {
3548*c80429ceSEric Joyner 				ret_val =
3549*c80429ceSEric Joyner 				   e1000_read_flash_dword_ich8lan(hw,
3550*c80429ceSEric Joyner 								 offset_to_read,
3551*c80429ceSEric Joyner 								 &dword);
3552*c80429ceSEric Joyner 				if (ret_val)
3553*c80429ceSEric Joyner 					break;
3554*c80429ceSEric Joyner 			}
3555*c80429ceSEric Joyner 			if (dev_spec->shadow_ram[offset+i].modified)
3556*c80429ceSEric Joyner 				data[i] = dev_spec->shadow_ram[offset+i].value;
3557*c80429ceSEric Joyner 			else
3558*c80429ceSEric Joyner 				data[i] = (u16) (dword & 0xFFFF);
3559*c80429ceSEric Joyner 			if (dev_spec->shadow_ram[offset+i].modified)
3560*c80429ceSEric Joyner 				data[i+1] =
3561*c80429ceSEric Joyner 				   dev_spec->shadow_ram[offset+i+1].value;
3562*c80429ceSEric Joyner 			else
3563*c80429ceSEric Joyner 				data[i+1] = (u16) (dword >> 16 & 0xFFFF);
3564*c80429ceSEric Joyner 		}
3565*c80429ceSEric Joyner 	}
3566*c80429ceSEric Joyner 
3567*c80429ceSEric Joyner 	nvm->ops.release(hw);
3568*c80429ceSEric Joyner 
3569*c80429ceSEric Joyner out:
3570*c80429ceSEric Joyner 	if (ret_val)
3571*c80429ceSEric Joyner 		DEBUGOUT1("NVM read error: %d\n", ret_val);
3572*c80429ceSEric Joyner 
3573*c80429ceSEric Joyner 	return ret_val;
3574*c80429ceSEric Joyner }
3575*c80429ceSEric Joyner 
3576*c80429ceSEric Joyner /**
35778cfa0ad2SJack F Vogel  *  e1000_read_nvm_ich8lan - Read word(s) from the NVM
35788cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
35798cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the word(s) to read.
35808cfa0ad2SJack F Vogel  *  @words: Size of data to read in words
35818cfa0ad2SJack F Vogel  *  @data: Pointer to the word(s) to read at offset.
35828cfa0ad2SJack F Vogel  *
35838cfa0ad2SJack F Vogel  *  Reads a word(s) from the NVM using the flash access registers.
35848cfa0ad2SJack F Vogel  **/
35858cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
35868cfa0ad2SJack F Vogel 				  u16 *data)
35878cfa0ad2SJack F Vogel {
35888cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
3589daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
35908cfa0ad2SJack F Vogel 	u32 act_offset;
35918cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
35928cfa0ad2SJack F Vogel 	u32 bank = 0;
35938cfa0ad2SJack F Vogel 	u16 i, word;
35948cfa0ad2SJack F Vogel 
35958cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_nvm_ich8lan");
35968cfa0ad2SJack F Vogel 
35978cfa0ad2SJack F Vogel 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
35988cfa0ad2SJack F Vogel 	    (words == 0)) {
35998cfa0ad2SJack F Vogel 		DEBUGOUT("nvm parameter(s) out of bounds\n");
36008cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
36018cfa0ad2SJack F Vogel 		goto out;
36028cfa0ad2SJack F Vogel 	}
36038cfa0ad2SJack F Vogel 
36044edd8523SJack F Vogel 	nvm->ops.acquire(hw);
36058cfa0ad2SJack F Vogel 
36068cfa0ad2SJack F Vogel 	ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
36074edd8523SJack F Vogel 	if (ret_val != E1000_SUCCESS) {
36084edd8523SJack F Vogel 		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
36094edd8523SJack F Vogel 		bank = 0;
36104edd8523SJack F Vogel 	}
36118cfa0ad2SJack F Vogel 
36128cfa0ad2SJack F Vogel 	act_offset = (bank) ? nvm->flash_bank_size : 0;
36138cfa0ad2SJack F Vogel 	act_offset += offset;
36148cfa0ad2SJack F Vogel 
36154edd8523SJack F Vogel 	ret_val = E1000_SUCCESS;
36168cfa0ad2SJack F Vogel 	for (i = 0; i < words; i++) {
36174dab5c37SJack F Vogel 		if (dev_spec->shadow_ram[offset+i].modified) {
36188cfa0ad2SJack F Vogel 			data[i] = dev_spec->shadow_ram[offset+i].value;
36198cfa0ad2SJack F Vogel 		} else {
36208cfa0ad2SJack F Vogel 			ret_val = e1000_read_flash_word_ich8lan(hw,
36218cfa0ad2SJack F Vogel 								act_offset + i,
36228cfa0ad2SJack F Vogel 								&word);
36238cfa0ad2SJack F Vogel 			if (ret_val)
36248cfa0ad2SJack F Vogel 				break;
36258cfa0ad2SJack F Vogel 			data[i] = word;
36268cfa0ad2SJack F Vogel 		}
36278cfa0ad2SJack F Vogel 	}
36288cfa0ad2SJack F Vogel 
36298cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
36308cfa0ad2SJack F Vogel 
36318cfa0ad2SJack F Vogel out:
3632d035aa2dSJack F Vogel 	if (ret_val)
3633d035aa2dSJack F Vogel 		DEBUGOUT1("NVM read error: %d\n", ret_val);
3634d035aa2dSJack F Vogel 
36358cfa0ad2SJack F Vogel 	return ret_val;
36368cfa0ad2SJack F Vogel }
36378cfa0ad2SJack F Vogel 
36388cfa0ad2SJack F Vogel /**
36398cfa0ad2SJack F Vogel  *  e1000_flash_cycle_init_ich8lan - Initialize flash
36408cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
36418cfa0ad2SJack F Vogel  *
36428cfa0ad2SJack F Vogel  *  This function does initial flash setup so that a new read/write/erase cycle
36438cfa0ad2SJack F Vogel  *  can be started.
36448cfa0ad2SJack F Vogel  **/
36458cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
36468cfa0ad2SJack F Vogel {
36478cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
36488cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
36498cfa0ad2SJack F Vogel 
36508cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_flash_cycle_init_ich8lan");
36518cfa0ad2SJack F Vogel 
36528cfa0ad2SJack F Vogel 	hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
36538cfa0ad2SJack F Vogel 
36548cfa0ad2SJack F Vogel 	/* Check if the flash descriptor is valid */
36556ab6bfe3SJack F Vogel 	if (!hsfsts.hsf_status.fldesvalid) {
36564dab5c37SJack F Vogel 		DEBUGOUT("Flash descriptor invalid.  SW Sequencing must be used.\n");
36576ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
36588cfa0ad2SJack F Vogel 	}
36598cfa0ad2SJack F Vogel 
36608cfa0ad2SJack F Vogel 	/* Clear FCERR and DAEL in hw status by writing 1 */
36618cfa0ad2SJack F Vogel 	hsfsts.hsf_status.flcerr = 1;
36628cfa0ad2SJack F Vogel 	hsfsts.hsf_status.dael = 1;
3663*c80429ceSEric Joyner 	if (hw->mac.type == e1000_pch_spt)
3664*c80429ceSEric Joyner 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
3665*c80429ceSEric Joyner 				      hsfsts.regval & 0xFFFF);
3666*c80429ceSEric Joyner 	else
36678cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
36688cfa0ad2SJack F Vogel 
36696ab6bfe3SJack F Vogel 	/* Either we should have a hardware SPI cycle in progress
36708cfa0ad2SJack F Vogel 	 * bit to check against, in order to start a new cycle or
36718cfa0ad2SJack F Vogel 	 * FDONE bit should be changed in the hardware so that it
36728cfa0ad2SJack F Vogel 	 * is 1 after hardware reset, which can then be used as an
36738cfa0ad2SJack F Vogel 	 * indication whether a cycle is in progress or has been
36748cfa0ad2SJack F Vogel 	 * completed.
36758cfa0ad2SJack F Vogel 	 */
36768cfa0ad2SJack F Vogel 
36776ab6bfe3SJack F Vogel 	if (!hsfsts.hsf_status.flcinprog) {
36786ab6bfe3SJack F Vogel 		/* There is no cycle running at present,
36798cfa0ad2SJack F Vogel 		 * so we can start a cycle.
36808cfa0ad2SJack F Vogel 		 * Begin by setting Flash Cycle Done.
36818cfa0ad2SJack F Vogel 		 */
36828cfa0ad2SJack F Vogel 		hsfsts.hsf_status.flcdone = 1;
3683*c80429ceSEric Joyner 		if (hw->mac.type == e1000_pch_spt)
3684*c80429ceSEric Joyner 			E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
3685*c80429ceSEric Joyner 					      hsfsts.regval & 0xFFFF);
3686*c80429ceSEric Joyner 		else
3687*c80429ceSEric Joyner 			E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
3688*c80429ceSEric Joyner 						hsfsts.regval);
36898cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
36908cfa0ad2SJack F Vogel 	} else {
3691730d3130SJack F Vogel 		s32 i;
3692730d3130SJack F Vogel 
36936ab6bfe3SJack F Vogel 		/* Otherwise poll for sometime so the current
36948cfa0ad2SJack F Vogel 		 * cycle has a chance to end before giving up.
36958cfa0ad2SJack F Vogel 		 */
36968cfa0ad2SJack F Vogel 		for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
36978cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
36988cfa0ad2SJack F Vogel 							      ICH_FLASH_HSFSTS);
36996ab6bfe3SJack F Vogel 			if (!hsfsts.hsf_status.flcinprog) {
37008cfa0ad2SJack F Vogel 				ret_val = E1000_SUCCESS;
37018cfa0ad2SJack F Vogel 				break;
37028cfa0ad2SJack F Vogel 			}
37038cfa0ad2SJack F Vogel 			usec_delay(1);
37048cfa0ad2SJack F Vogel 		}
37058cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS) {
37066ab6bfe3SJack F Vogel 			/* Successful in waiting for previous cycle to timeout,
37078cfa0ad2SJack F Vogel 			 * now set the Flash Cycle Done.
37088cfa0ad2SJack F Vogel 			 */
37098cfa0ad2SJack F Vogel 			hsfsts.hsf_status.flcdone = 1;
3710*c80429ceSEric Joyner 			if (hw->mac.type == e1000_pch_spt)
3711*c80429ceSEric Joyner 				E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
3712*c80429ceSEric Joyner 						      hsfsts.regval & 0xFFFF);
3713*c80429ceSEric Joyner 			else
3714daf9197cSJack F Vogel 				E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
37158cfa0ad2SJack F Vogel 							hsfsts.regval);
37168cfa0ad2SJack F Vogel 		} else {
37174dab5c37SJack F Vogel 			DEBUGOUT("Flash controller busy, cannot get access\n");
37188cfa0ad2SJack F Vogel 		}
37198cfa0ad2SJack F Vogel 	}
37208cfa0ad2SJack F Vogel 
37218cfa0ad2SJack F Vogel 	return ret_val;
37228cfa0ad2SJack F Vogel }
37238cfa0ad2SJack F Vogel 
37248cfa0ad2SJack F Vogel /**
37258cfa0ad2SJack F Vogel  *  e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
37268cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
37278cfa0ad2SJack F Vogel  *  @timeout: maximum time to wait for completion
37288cfa0ad2SJack F Vogel  *
37298cfa0ad2SJack F Vogel  *  This function starts a flash cycle and waits for its completion.
37308cfa0ad2SJack F Vogel  **/
37318cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
37328cfa0ad2SJack F Vogel {
37338cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
37348cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
37358cfa0ad2SJack F Vogel 	u32 i = 0;
37368cfa0ad2SJack F Vogel 
37378cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_flash_cycle_ich8lan");
37388cfa0ad2SJack F Vogel 
37398cfa0ad2SJack F Vogel 	/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
3740*c80429ceSEric Joyner 	if (hw->mac.type == e1000_pch_spt)
3741*c80429ceSEric Joyner 		hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16;
3742*c80429ceSEric Joyner 	else
37438cfa0ad2SJack F Vogel 		hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
37448cfa0ad2SJack F Vogel 	hsflctl.hsf_ctrl.flcgo = 1;
37458cc64f1eSJack F Vogel 
3746*c80429ceSEric Joyner 	if (hw->mac.type == e1000_pch_spt)
3747*c80429ceSEric Joyner 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
3748*c80429ceSEric Joyner 				      hsflctl.regval << 16);
3749*c80429ceSEric Joyner 	else
37508cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
37518cfa0ad2SJack F Vogel 
37528cfa0ad2SJack F Vogel 	/* wait till FDONE bit is set to 1 */
37538cfa0ad2SJack F Vogel 	do {
37548cfa0ad2SJack F Vogel 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
37556ab6bfe3SJack F Vogel 		if (hsfsts.hsf_status.flcdone)
37568cfa0ad2SJack F Vogel 			break;
37578cfa0ad2SJack F Vogel 		usec_delay(1);
37588cfa0ad2SJack F Vogel 	} while (i++ < timeout);
37598cfa0ad2SJack F Vogel 
37606ab6bfe3SJack F Vogel 	if (hsfsts.hsf_status.flcdone && !hsfsts.hsf_status.flcerr)
37616ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
37628cfa0ad2SJack F Vogel 
37636ab6bfe3SJack F Vogel 	return -E1000_ERR_NVM;
37648cfa0ad2SJack F Vogel }
37658cfa0ad2SJack F Vogel 
37668cfa0ad2SJack F Vogel /**
3767*c80429ceSEric Joyner  *  e1000_read_flash_dword_ich8lan - Read dword from flash
3768*c80429ceSEric Joyner  *  @hw: pointer to the HW structure
3769*c80429ceSEric Joyner  *  @offset: offset to data location
3770*c80429ceSEric Joyner  *  @data: pointer to the location for storing the data
3771*c80429ceSEric Joyner  *
3772*c80429ceSEric Joyner  *  Reads the flash dword at offset into data.  Offset is converted
3773*c80429ceSEric Joyner  *  to bytes before read.
3774*c80429ceSEric Joyner  **/
3775*c80429ceSEric Joyner static s32 e1000_read_flash_dword_ich8lan(struct e1000_hw *hw, u32 offset,
3776*c80429ceSEric Joyner 					  u32 *data)
3777*c80429ceSEric Joyner {
3778*c80429ceSEric Joyner 	DEBUGFUNC("e1000_read_flash_dword_ich8lan");
3779*c80429ceSEric Joyner 
3780*c80429ceSEric Joyner 	if (!data)
3781*c80429ceSEric Joyner 		return -E1000_ERR_NVM;
3782*c80429ceSEric Joyner 
3783*c80429ceSEric Joyner 	/* Must convert word offset into bytes. */
3784*c80429ceSEric Joyner 	offset <<= 1;
3785*c80429ceSEric Joyner 
3786*c80429ceSEric Joyner 	return e1000_read_flash_data32_ich8lan(hw, offset, data);
3787*c80429ceSEric Joyner }
3788*c80429ceSEric Joyner 
3789*c80429ceSEric Joyner /**
37908cfa0ad2SJack F Vogel  *  e1000_read_flash_word_ich8lan - Read word from flash
37918cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
37928cfa0ad2SJack F Vogel  *  @offset: offset to data location
37938cfa0ad2SJack F Vogel  *  @data: pointer to the location for storing the data
37948cfa0ad2SJack F Vogel  *
37958cfa0ad2SJack F Vogel  *  Reads the flash word at offset into data.  Offset is converted
37968cfa0ad2SJack F Vogel  *  to bytes before read.
37978cfa0ad2SJack F Vogel  **/
37988cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
37998cfa0ad2SJack F Vogel 					 u16 *data)
38008cfa0ad2SJack F Vogel {
38018cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_flash_word_ich8lan");
38028cfa0ad2SJack F Vogel 
38036ab6bfe3SJack F Vogel 	if (!data)
38046ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
38058cfa0ad2SJack F Vogel 
38068cfa0ad2SJack F Vogel 	/* Must convert offset into bytes. */
38078cfa0ad2SJack F Vogel 	offset <<= 1;
38088cfa0ad2SJack F Vogel 
38096ab6bfe3SJack F Vogel 	return e1000_read_flash_data_ich8lan(hw, offset, 2, data);
38108cfa0ad2SJack F Vogel }
38118cfa0ad2SJack F Vogel 
38128cfa0ad2SJack F Vogel /**
38138cfa0ad2SJack F Vogel  *  e1000_read_flash_byte_ich8lan - Read byte from flash
38148cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
38158cfa0ad2SJack F Vogel  *  @offset: The offset of the byte to read.
38168cfa0ad2SJack F Vogel  *  @data: Pointer to a byte to store the value read.
38178cfa0ad2SJack F Vogel  *
38188cfa0ad2SJack F Vogel  *  Reads a single byte from the NVM using the flash access registers.
38198cfa0ad2SJack F Vogel  **/
38208cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
38218cfa0ad2SJack F Vogel 					 u8 *data)
38228cfa0ad2SJack F Vogel {
38236ab6bfe3SJack F Vogel 	s32 ret_val;
38248cfa0ad2SJack F Vogel 	u16 word = 0;
38258cfa0ad2SJack F Vogel 
3826*c80429ceSEric Joyner 	/* In SPT, only 32 bits access is supported,
3827*c80429ceSEric Joyner 	 * so this function should not be called.
3828*c80429ceSEric Joyner 	 */
3829*c80429ceSEric Joyner 	if (hw->mac.type == e1000_pch_spt)
3830*c80429ceSEric Joyner 		return -E1000_ERR_NVM;
3831*c80429ceSEric Joyner 	else
38328cfa0ad2SJack F Vogel 		ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
38338cc64f1eSJack F Vogel 
38348cfa0ad2SJack F Vogel 	if (ret_val)
38356ab6bfe3SJack F Vogel 		return ret_val;
38368cfa0ad2SJack F Vogel 
38378cfa0ad2SJack F Vogel 	*data = (u8)word;
38388cfa0ad2SJack F Vogel 
38396ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
38408cfa0ad2SJack F Vogel }
38418cfa0ad2SJack F Vogel 
38428cfa0ad2SJack F Vogel /**
38438cfa0ad2SJack F Vogel  *  e1000_read_flash_data_ich8lan - Read byte or word from NVM
38448cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
38458cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the byte or word to read.
38468cfa0ad2SJack F Vogel  *  @size: Size of data to read, 1=byte 2=word
38478cfa0ad2SJack F Vogel  *  @data: Pointer to the word to store the value read.
38488cfa0ad2SJack F Vogel  *
38498cfa0ad2SJack F Vogel  *  Reads a byte or word from the NVM using the flash access registers.
38508cfa0ad2SJack F Vogel  **/
38518cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
38528cfa0ad2SJack F Vogel 					 u8 size, u16 *data)
38538cfa0ad2SJack F Vogel {
38548cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
38558cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
38568cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
38578cfa0ad2SJack F Vogel 	u32 flash_data = 0;
38588cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
38598cfa0ad2SJack F Vogel 	u8 count = 0;
38608cfa0ad2SJack F Vogel 
38618cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_flash_data_ich8lan");
38628cfa0ad2SJack F Vogel 
38638cfa0ad2SJack F Vogel 	if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
38646ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
38657609433eSJack F Vogel 	flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
38667609433eSJack F Vogel 			     hw->nvm.flash_base_addr);
38678cfa0ad2SJack F Vogel 
38688cfa0ad2SJack F Vogel 	do {
38698cfa0ad2SJack F Vogel 		usec_delay(1);
38708cfa0ad2SJack F Vogel 		/* Steps */
38718cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
38728cfa0ad2SJack F Vogel 		if (ret_val != E1000_SUCCESS)
38738cfa0ad2SJack F Vogel 			break;
38748cfa0ad2SJack F Vogel 		hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
38758cc64f1eSJack F Vogel 
38768cfa0ad2SJack F Vogel 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
38778cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.fldbcount = size - 1;
38788cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
38798cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
38808cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
38818cfa0ad2SJack F Vogel 
38828cc64f1eSJack F Vogel 		ret_val = e1000_flash_cycle_ich8lan(hw,
38838cfa0ad2SJack F Vogel 						ICH_FLASH_READ_COMMAND_TIMEOUT);
38848cfa0ad2SJack F Vogel 
38856ab6bfe3SJack F Vogel 		/* Check if FCERR is set to 1, if set to 1, clear it
38868cfa0ad2SJack F Vogel 		 * and try the whole sequence a few more times, else
38878cfa0ad2SJack F Vogel 		 * read in (shift in) the Flash Data0, the order is
38888cfa0ad2SJack F Vogel 		 * least significant byte first msb to lsb
38898cfa0ad2SJack F Vogel 		 */
38908cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS) {
38918cfa0ad2SJack F Vogel 			flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
3892daf9197cSJack F Vogel 			if (size == 1)
38938cfa0ad2SJack F Vogel 				*data = (u8)(flash_data & 0x000000FF);
3894daf9197cSJack F Vogel 			else if (size == 2)
38958cfa0ad2SJack F Vogel 				*data = (u16)(flash_data & 0x0000FFFF);
38968cfa0ad2SJack F Vogel 			break;
38978cfa0ad2SJack F Vogel 		} else {
38986ab6bfe3SJack F Vogel 			/* If we've gotten here, then things are probably
38998cfa0ad2SJack F Vogel 			 * completely hosed, but if the error condition is
39008cfa0ad2SJack F Vogel 			 * detected, it won't hurt to give it another try...
39018cfa0ad2SJack F Vogel 			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
39028cfa0ad2SJack F Vogel 			 */
39038cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
39048cfa0ad2SJack F Vogel 							      ICH_FLASH_HSFSTS);
39056ab6bfe3SJack F Vogel 			if (hsfsts.hsf_status.flcerr) {
39068cfa0ad2SJack F Vogel 				/* Repeat for some time before giving up. */
39078cfa0ad2SJack F Vogel 				continue;
39086ab6bfe3SJack F Vogel 			} else if (!hsfsts.hsf_status.flcdone) {
39094dab5c37SJack F Vogel 				DEBUGOUT("Timeout error - flash cycle did not complete.\n");
39108cfa0ad2SJack F Vogel 				break;
39118cfa0ad2SJack F Vogel 			}
39128cfa0ad2SJack F Vogel 		}
39138cfa0ad2SJack F Vogel 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
39148cfa0ad2SJack F Vogel 
39158cfa0ad2SJack F Vogel 	return ret_val;
39168cfa0ad2SJack F Vogel }
39178cfa0ad2SJack F Vogel 
3918*c80429ceSEric Joyner /**
3919*c80429ceSEric Joyner  *  e1000_read_flash_data32_ich8lan - Read dword from NVM
3920*c80429ceSEric Joyner  *  @hw: pointer to the HW structure
3921*c80429ceSEric Joyner  *  @offset: The offset (in bytes) of the dword to read.
3922*c80429ceSEric Joyner  *  @data: Pointer to the dword to store the value read.
3923*c80429ceSEric Joyner  *
3924*c80429ceSEric Joyner  *  Reads a byte or word from the NVM using the flash access registers.
3925*c80429ceSEric Joyner  **/
3926*c80429ceSEric Joyner static s32 e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
3927*c80429ceSEric Joyner 					   u32 *data)
3928*c80429ceSEric Joyner {
3929*c80429ceSEric Joyner 	union ich8_hws_flash_status hsfsts;
3930*c80429ceSEric Joyner 	union ich8_hws_flash_ctrl hsflctl;
3931*c80429ceSEric Joyner 	u32 flash_linear_addr;
3932*c80429ceSEric Joyner 	s32 ret_val = -E1000_ERR_NVM;
3933*c80429ceSEric Joyner 	u8 count = 0;
3934*c80429ceSEric Joyner 
3935*c80429ceSEric Joyner 	DEBUGFUNC("e1000_read_flash_data_ich8lan");
3936*c80429ceSEric Joyner 
3937*c80429ceSEric Joyner 		if (offset > ICH_FLASH_LINEAR_ADDR_MASK ||
3938*c80429ceSEric Joyner 		    hw->mac.type != e1000_pch_spt)
3939*c80429ceSEric Joyner 			return -E1000_ERR_NVM;
3940*c80429ceSEric Joyner 	flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
3941*c80429ceSEric Joyner 			     hw->nvm.flash_base_addr);
3942*c80429ceSEric Joyner 
3943*c80429ceSEric Joyner 	do {
3944*c80429ceSEric Joyner 		usec_delay(1);
3945*c80429ceSEric Joyner 		/* Steps */
3946*c80429ceSEric Joyner 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
3947*c80429ceSEric Joyner 		if (ret_val != E1000_SUCCESS)
3948*c80429ceSEric Joyner 			break;
3949*c80429ceSEric Joyner 		/* In SPT, This register is in Lan memory space, not flash.
3950*c80429ceSEric Joyner 		 * Therefore, only 32 bit access is supported
3951*c80429ceSEric Joyner 		 */
3952*c80429ceSEric Joyner 		hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16;
3953*c80429ceSEric Joyner 
3954*c80429ceSEric Joyner 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
3955*c80429ceSEric Joyner 		hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1;
3956*c80429ceSEric Joyner 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
3957*c80429ceSEric Joyner 		/* In SPT, This register is in Lan memory space, not flash.
3958*c80429ceSEric Joyner 		 * Therefore, only 32 bit access is supported
3959*c80429ceSEric Joyner 		 */
3960*c80429ceSEric Joyner 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
3961*c80429ceSEric Joyner 				      (u32)hsflctl.regval << 16);
3962*c80429ceSEric Joyner 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
3963*c80429ceSEric Joyner 
3964*c80429ceSEric Joyner 		ret_val = e1000_flash_cycle_ich8lan(hw,
3965*c80429ceSEric Joyner 						ICH_FLASH_READ_COMMAND_TIMEOUT);
3966*c80429ceSEric Joyner 
3967*c80429ceSEric Joyner 		/* Check if FCERR is set to 1, if set to 1, clear it
3968*c80429ceSEric Joyner 		 * and try the whole sequence a few more times, else
3969*c80429ceSEric Joyner 		 * read in (shift in) the Flash Data0, the order is
3970*c80429ceSEric Joyner 		 * least significant byte first msb to lsb
3971*c80429ceSEric Joyner 		 */
3972*c80429ceSEric Joyner 		if (ret_val == E1000_SUCCESS) {
3973*c80429ceSEric Joyner 			*data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
3974*c80429ceSEric Joyner 			break;
3975*c80429ceSEric Joyner 		} else {
3976*c80429ceSEric Joyner 			/* If we've gotten here, then things are probably
3977*c80429ceSEric Joyner 			 * completely hosed, but if the error condition is
3978*c80429ceSEric Joyner 			 * detected, it won't hurt to give it another try...
3979*c80429ceSEric Joyner 			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
3980*c80429ceSEric Joyner 			 */
3981*c80429ceSEric Joyner 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
3982*c80429ceSEric Joyner 							      ICH_FLASH_HSFSTS);
3983*c80429ceSEric Joyner 			if (hsfsts.hsf_status.flcerr) {
3984*c80429ceSEric Joyner 				/* Repeat for some time before giving up. */
3985*c80429ceSEric Joyner 				continue;
3986*c80429ceSEric Joyner 			} else if (!hsfsts.hsf_status.flcdone) {
3987*c80429ceSEric Joyner 				DEBUGOUT("Timeout error - flash cycle did not complete.\n");
3988*c80429ceSEric Joyner 				break;
3989*c80429ceSEric Joyner 			}
3990*c80429ceSEric Joyner 		}
3991*c80429ceSEric Joyner 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
3992*c80429ceSEric Joyner 
3993*c80429ceSEric Joyner 	return ret_val;
3994*c80429ceSEric Joyner }
39958cc64f1eSJack F Vogel 
39968cfa0ad2SJack F Vogel /**
39978cfa0ad2SJack F Vogel  *  e1000_write_nvm_ich8lan - Write word(s) to the NVM
39988cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
39998cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the word(s) to write.
40008cfa0ad2SJack F Vogel  *  @words: Size of data to write in words
40018cfa0ad2SJack F Vogel  *  @data: Pointer to the word(s) to write at offset.
40028cfa0ad2SJack F Vogel  *
40038cfa0ad2SJack F Vogel  *  Writes a byte or word to the NVM using the flash access registers.
40048cfa0ad2SJack F Vogel  **/
40058cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
40068cfa0ad2SJack F Vogel 				   u16 *data)
40078cfa0ad2SJack F Vogel {
40088cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
4009daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
40108cfa0ad2SJack F Vogel 	u16 i;
40118cfa0ad2SJack F Vogel 
40128cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_nvm_ich8lan");
40138cfa0ad2SJack F Vogel 
40148cfa0ad2SJack F Vogel 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
40158cfa0ad2SJack F Vogel 	    (words == 0)) {
40168cfa0ad2SJack F Vogel 		DEBUGOUT("nvm parameter(s) out of bounds\n");
40176ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
40188cfa0ad2SJack F Vogel 	}
40198cfa0ad2SJack F Vogel 
40204edd8523SJack F Vogel 	nvm->ops.acquire(hw);
40218cfa0ad2SJack F Vogel 
40228cfa0ad2SJack F Vogel 	for (i = 0; i < words; i++) {
40238cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[offset+i].modified = TRUE;
40248cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[offset+i].value = data[i];
40258cfa0ad2SJack F Vogel 	}
40268cfa0ad2SJack F Vogel 
40278cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
40288cfa0ad2SJack F Vogel 
40296ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
40308cfa0ad2SJack F Vogel }
40318cfa0ad2SJack F Vogel 
40328cfa0ad2SJack F Vogel /**
4033*c80429ceSEric Joyner  *  e1000_update_nvm_checksum_spt - Update the checksum for NVM
4034*c80429ceSEric Joyner  *  @hw: pointer to the HW structure
4035*c80429ceSEric Joyner  *
4036*c80429ceSEric Joyner  *  The NVM checksum is updated by calling the generic update_nvm_checksum,
4037*c80429ceSEric Joyner  *  which writes the checksum to the shadow ram.  The changes in the shadow
4038*c80429ceSEric Joyner  *  ram are then committed to the EEPROM by processing each bank at a time
4039*c80429ceSEric Joyner  *  checking for the modified bit and writing only the pending changes.
4040*c80429ceSEric Joyner  *  After a successful commit, the shadow ram is cleared and is ready for
4041*c80429ceSEric Joyner  *  future writes.
4042*c80429ceSEric Joyner  **/
4043*c80429ceSEric Joyner static s32 e1000_update_nvm_checksum_spt(struct e1000_hw *hw)
4044*c80429ceSEric Joyner {
4045*c80429ceSEric Joyner 	struct e1000_nvm_info *nvm = &hw->nvm;
4046*c80429ceSEric Joyner 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
4047*c80429ceSEric Joyner 	u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
4048*c80429ceSEric Joyner 	s32 ret_val;
4049*c80429ceSEric Joyner 	u32 dword = 0;
4050*c80429ceSEric Joyner 
4051*c80429ceSEric Joyner 	DEBUGFUNC("e1000_update_nvm_checksum_spt");
4052*c80429ceSEric Joyner 
4053*c80429ceSEric Joyner 	ret_val = e1000_update_nvm_checksum_generic(hw);
4054*c80429ceSEric Joyner 	if (ret_val)
4055*c80429ceSEric Joyner 		goto out;
4056*c80429ceSEric Joyner 
4057*c80429ceSEric Joyner 	if (nvm->type != e1000_nvm_flash_sw)
4058*c80429ceSEric Joyner 		goto out;
4059*c80429ceSEric Joyner 
4060*c80429ceSEric Joyner 	nvm->ops.acquire(hw);
4061*c80429ceSEric Joyner 
4062*c80429ceSEric Joyner 	/* We're writing to the opposite bank so if we're on bank 1,
4063*c80429ceSEric Joyner 	 * write to bank 0 etc.  We also need to erase the segment that
4064*c80429ceSEric Joyner 	 * is going to be written
4065*c80429ceSEric Joyner 	 */
4066*c80429ceSEric Joyner 	ret_val =  e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
4067*c80429ceSEric Joyner 	if (ret_val != E1000_SUCCESS) {
4068*c80429ceSEric Joyner 		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
4069*c80429ceSEric Joyner 		bank = 0;
4070*c80429ceSEric Joyner 	}
4071*c80429ceSEric Joyner 
4072*c80429ceSEric Joyner 	if (bank == 0) {
4073*c80429ceSEric Joyner 		new_bank_offset = nvm->flash_bank_size;
4074*c80429ceSEric Joyner 		old_bank_offset = 0;
4075*c80429ceSEric Joyner 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
4076*c80429ceSEric Joyner 		if (ret_val)
4077*c80429ceSEric Joyner 			goto release;
4078*c80429ceSEric Joyner 	} else {
4079*c80429ceSEric Joyner 		old_bank_offset = nvm->flash_bank_size;
4080*c80429ceSEric Joyner 		new_bank_offset = 0;
4081*c80429ceSEric Joyner 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
4082*c80429ceSEric Joyner 		if (ret_val)
4083*c80429ceSEric Joyner 			goto release;
4084*c80429ceSEric Joyner 	}
4085*c80429ceSEric Joyner 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i += 2) {
4086*c80429ceSEric Joyner 		/* Determine whether to write the value stored
4087*c80429ceSEric Joyner 		 * in the other NVM bank or a modified value stored
4088*c80429ceSEric Joyner 		 * in the shadow RAM
4089*c80429ceSEric Joyner 		 */
4090*c80429ceSEric Joyner 		ret_val = e1000_read_flash_dword_ich8lan(hw,
4091*c80429ceSEric Joyner 							 i + old_bank_offset,
4092*c80429ceSEric Joyner 							 &dword);
4093*c80429ceSEric Joyner 
4094*c80429ceSEric Joyner 		if (dev_spec->shadow_ram[i].modified) {
4095*c80429ceSEric Joyner 			dword &= 0xffff0000;
4096*c80429ceSEric Joyner 			dword |= (dev_spec->shadow_ram[i].value & 0xffff);
4097*c80429ceSEric Joyner 		}
4098*c80429ceSEric Joyner 		if (dev_spec->shadow_ram[i + 1].modified) {
4099*c80429ceSEric Joyner 			dword &= 0x0000ffff;
4100*c80429ceSEric Joyner 			dword |= ((dev_spec->shadow_ram[i + 1].value & 0xffff)
4101*c80429ceSEric Joyner 				  << 16);
4102*c80429ceSEric Joyner 		}
4103*c80429ceSEric Joyner 		if (ret_val)
4104*c80429ceSEric Joyner 			break;
4105*c80429ceSEric Joyner 
4106*c80429ceSEric Joyner 		/* If the word is 0x13, then make sure the signature bits
4107*c80429ceSEric Joyner 		 * (15:14) are 11b until the commit has completed.
4108*c80429ceSEric Joyner 		 * This will allow us to write 10b which indicates the
4109*c80429ceSEric Joyner 		 * signature is valid.  We want to do this after the write
4110*c80429ceSEric Joyner 		 * has completed so that we don't mark the segment valid
4111*c80429ceSEric Joyner 		 * while the write is still in progress
4112*c80429ceSEric Joyner 		 */
4113*c80429ceSEric Joyner 		if (i == E1000_ICH_NVM_SIG_WORD - 1)
4114*c80429ceSEric Joyner 			dword |= E1000_ICH_NVM_SIG_MASK << 16;
4115*c80429ceSEric Joyner 
4116*c80429ceSEric Joyner 		/* Convert offset to bytes. */
4117*c80429ceSEric Joyner 		act_offset = (i + new_bank_offset) << 1;
4118*c80429ceSEric Joyner 
4119*c80429ceSEric Joyner 		usec_delay(100);
4120*c80429ceSEric Joyner 
4121*c80429ceSEric Joyner 		/* Write the data to the new bank. Offset in words*/
4122*c80429ceSEric Joyner 		act_offset = i + new_bank_offset;
4123*c80429ceSEric Joyner 		ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset,
4124*c80429ceSEric Joyner 								dword);
4125*c80429ceSEric Joyner 		if (ret_val)
4126*c80429ceSEric Joyner 			break;
4127*c80429ceSEric Joyner 	 }
4128*c80429ceSEric Joyner 
4129*c80429ceSEric Joyner 	/* Don't bother writing the segment valid bits if sector
4130*c80429ceSEric Joyner 	 * programming failed.
4131*c80429ceSEric Joyner 	 */
4132*c80429ceSEric Joyner 	if (ret_val) {
4133*c80429ceSEric Joyner 		DEBUGOUT("Flash commit failed.\n");
4134*c80429ceSEric Joyner 		goto release;
4135*c80429ceSEric Joyner 	}
4136*c80429ceSEric Joyner 
4137*c80429ceSEric Joyner 	/* Finally validate the new segment by setting bit 15:14
4138*c80429ceSEric Joyner 	 * to 10b in word 0x13 , this can be done without an
4139*c80429ceSEric Joyner 	 * erase as well since these bits are 11 to start with
4140*c80429ceSEric Joyner 	 * and we need to change bit 14 to 0b
4141*c80429ceSEric Joyner 	 */
4142*c80429ceSEric Joyner 	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
4143*c80429ceSEric Joyner 
4144*c80429ceSEric Joyner 	/*offset in words but we read dword*/
4145*c80429ceSEric Joyner 	--act_offset;
4146*c80429ceSEric Joyner 	ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword);
4147*c80429ceSEric Joyner 
4148*c80429ceSEric Joyner 	if (ret_val)
4149*c80429ceSEric Joyner 		goto release;
4150*c80429ceSEric Joyner 
4151*c80429ceSEric Joyner 	dword &= 0xBFFFFFFF;
4152*c80429ceSEric Joyner 	ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword);
4153*c80429ceSEric Joyner 
4154*c80429ceSEric Joyner 	if (ret_val)
4155*c80429ceSEric Joyner 		goto release;
4156*c80429ceSEric Joyner 
4157*c80429ceSEric Joyner 	/* And invalidate the previously valid segment by setting
4158*c80429ceSEric Joyner 	 * its signature word (0x13) high_byte to 0b. This can be
4159*c80429ceSEric Joyner 	 * done without an erase because flash erase sets all bits
4160*c80429ceSEric Joyner 	 * to 1's. We can write 1's to 0's without an erase
4161*c80429ceSEric Joyner 	 */
4162*c80429ceSEric Joyner 	act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
4163*c80429ceSEric Joyner 
4164*c80429ceSEric Joyner 	/* offset in words but we read dword*/
4165*c80429ceSEric Joyner 	act_offset = old_bank_offset + E1000_ICH_NVM_SIG_WORD - 1;
4166*c80429ceSEric Joyner 	ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword);
4167*c80429ceSEric Joyner 
4168*c80429ceSEric Joyner 	if (ret_val)
4169*c80429ceSEric Joyner 		goto release;
4170*c80429ceSEric Joyner 
4171*c80429ceSEric Joyner 	dword &= 0x00FFFFFF;
4172*c80429ceSEric Joyner 	ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword);
4173*c80429ceSEric Joyner 
4174*c80429ceSEric Joyner 	if (ret_val)
4175*c80429ceSEric Joyner 		goto release;
4176*c80429ceSEric Joyner 
4177*c80429ceSEric Joyner 	/* Great!  Everything worked, we can now clear the cached entries. */
4178*c80429ceSEric Joyner 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
4179*c80429ceSEric Joyner 		dev_spec->shadow_ram[i].modified = FALSE;
4180*c80429ceSEric Joyner 		dev_spec->shadow_ram[i].value = 0xFFFF;
4181*c80429ceSEric Joyner 	}
4182*c80429ceSEric Joyner 
4183*c80429ceSEric Joyner release:
4184*c80429ceSEric Joyner 	nvm->ops.release(hw);
4185*c80429ceSEric Joyner 
4186*c80429ceSEric Joyner 	/* Reload the EEPROM, or else modifications will not appear
4187*c80429ceSEric Joyner 	 * until after the next adapter reset.
4188*c80429ceSEric Joyner 	 */
4189*c80429ceSEric Joyner 	if (!ret_val) {
4190*c80429ceSEric Joyner 		nvm->ops.reload(hw);
4191*c80429ceSEric Joyner 		msec_delay(10);
4192*c80429ceSEric Joyner 	}
4193*c80429ceSEric Joyner 
4194*c80429ceSEric Joyner out:
4195*c80429ceSEric Joyner 	if (ret_val)
4196*c80429ceSEric Joyner 		DEBUGOUT1("NVM update error: %d\n", ret_val);
4197*c80429ceSEric Joyner 
4198*c80429ceSEric Joyner 	return ret_val;
4199*c80429ceSEric Joyner }
4200*c80429ceSEric Joyner 
4201*c80429ceSEric Joyner /**
42028cfa0ad2SJack F Vogel  *  e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
42038cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
42048cfa0ad2SJack F Vogel  *
42058cfa0ad2SJack F Vogel  *  The NVM checksum is updated by calling the generic update_nvm_checksum,
42068cfa0ad2SJack F Vogel  *  which writes the checksum to the shadow ram.  The changes in the shadow
42078cfa0ad2SJack F Vogel  *  ram are then committed to the EEPROM by processing each bank at a time
42088cfa0ad2SJack F Vogel  *  checking for the modified bit and writing only the pending changes.
42098cfa0ad2SJack F Vogel  *  After a successful commit, the shadow ram is cleared and is ready for
42108cfa0ad2SJack F Vogel  *  future writes.
42118cfa0ad2SJack F Vogel  **/
42128cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
42138cfa0ad2SJack F Vogel {
42148cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
4215daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
42168cfa0ad2SJack F Vogel 	u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
42178cfa0ad2SJack F Vogel 	s32 ret_val;
42188cc64f1eSJack F Vogel 	u16 data = 0;
42198cfa0ad2SJack F Vogel 
42208cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_update_nvm_checksum_ich8lan");
42218cfa0ad2SJack F Vogel 
42228cfa0ad2SJack F Vogel 	ret_val = e1000_update_nvm_checksum_generic(hw);
42238cfa0ad2SJack F Vogel 	if (ret_val)
42248cfa0ad2SJack F Vogel 		goto out;
42258cfa0ad2SJack F Vogel 
42268cfa0ad2SJack F Vogel 	if (nvm->type != e1000_nvm_flash_sw)
42278cfa0ad2SJack F Vogel 		goto out;
42288cfa0ad2SJack F Vogel 
42294edd8523SJack F Vogel 	nvm->ops.acquire(hw);
42308cfa0ad2SJack F Vogel 
42316ab6bfe3SJack F Vogel 	/* We're writing to the opposite bank so if we're on bank 1,
42328cfa0ad2SJack F Vogel 	 * write to bank 0 etc.  We also need to erase the segment that
42338cfa0ad2SJack F Vogel 	 * is going to be written
42348cfa0ad2SJack F Vogel 	 */
42358cfa0ad2SJack F Vogel 	ret_val =  e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
4236d035aa2dSJack F Vogel 	if (ret_val != E1000_SUCCESS) {
42374edd8523SJack F Vogel 		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
42384edd8523SJack F Vogel 		bank = 0;
4239d035aa2dSJack F Vogel 	}
42408cfa0ad2SJack F Vogel 
42418cfa0ad2SJack F Vogel 	if (bank == 0) {
42428cfa0ad2SJack F Vogel 		new_bank_offset = nvm->flash_bank_size;
42438cfa0ad2SJack F Vogel 		old_bank_offset = 0;
4244d035aa2dSJack F Vogel 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
4245a69ed8dfSJack F Vogel 		if (ret_val)
4246a69ed8dfSJack F Vogel 			goto release;
42478cfa0ad2SJack F Vogel 	} else {
42488cfa0ad2SJack F Vogel 		old_bank_offset = nvm->flash_bank_size;
42498cfa0ad2SJack F Vogel 		new_bank_offset = 0;
4250d035aa2dSJack F Vogel 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
4251a69ed8dfSJack F Vogel 		if (ret_val)
4252a69ed8dfSJack F Vogel 			goto release;
42538cfa0ad2SJack F Vogel 	}
42548cfa0ad2SJack F Vogel 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
42558cfa0ad2SJack F Vogel 		if (dev_spec->shadow_ram[i].modified) {
42568cfa0ad2SJack F Vogel 			data = dev_spec->shadow_ram[i].value;
42578cfa0ad2SJack F Vogel 		} else {
4258d035aa2dSJack F Vogel 			ret_val = e1000_read_flash_word_ich8lan(hw, i +
4259d035aa2dSJack F Vogel 								old_bank_offset,
42608cfa0ad2SJack F Vogel 								&data);
4261d035aa2dSJack F Vogel 			if (ret_val)
4262d035aa2dSJack F Vogel 				break;
42638cfa0ad2SJack F Vogel 		}
42646ab6bfe3SJack F Vogel 		/* If the word is 0x13, then make sure the signature bits
42658cfa0ad2SJack F Vogel 		 * (15:14) are 11b until the commit has completed.
42668cfa0ad2SJack F Vogel 		 * This will allow us to write 10b which indicates the
42678cfa0ad2SJack F Vogel 		 * signature is valid.  We want to do this after the write
42688cfa0ad2SJack F Vogel 		 * has completed so that we don't mark the segment valid
42698cfa0ad2SJack F Vogel 		 * while the write is still in progress
42708cfa0ad2SJack F Vogel 		 */
42718cfa0ad2SJack F Vogel 		if (i == E1000_ICH_NVM_SIG_WORD)
42728cfa0ad2SJack F Vogel 			data |= E1000_ICH_NVM_SIG_MASK;
42738cfa0ad2SJack F Vogel 
42748cfa0ad2SJack F Vogel 		/* Convert offset to bytes. */
42758cfa0ad2SJack F Vogel 		act_offset = (i + new_bank_offset) << 1;
42768cfa0ad2SJack F Vogel 
42778cfa0ad2SJack F Vogel 		usec_delay(100);
42788cc64f1eSJack F Vogel 
42798cfa0ad2SJack F Vogel 		/* Write the bytes to the new bank. */
42808cfa0ad2SJack F Vogel 		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
42818cfa0ad2SJack F Vogel 							       act_offset,
42828cfa0ad2SJack F Vogel 							       (u8)data);
42838cfa0ad2SJack F Vogel 		if (ret_val)
42848cfa0ad2SJack F Vogel 			break;
42858cfa0ad2SJack F Vogel 
42868cfa0ad2SJack F Vogel 		usec_delay(100);
42878cfa0ad2SJack F Vogel 		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
42888cfa0ad2SJack F Vogel 							  act_offset + 1,
42898cfa0ad2SJack F Vogel 							  (u8)(data >> 8));
42908cfa0ad2SJack F Vogel 		if (ret_val)
42918cfa0ad2SJack F Vogel 			break;
42928cfa0ad2SJack F Vogel 	 }
42938cfa0ad2SJack F Vogel 
42946ab6bfe3SJack F Vogel 	/* Don't bother writing the segment valid bits if sector
42958cfa0ad2SJack F Vogel 	 * programming failed.
42968cfa0ad2SJack F Vogel 	 */
42978cfa0ad2SJack F Vogel 	if (ret_val) {
42988cfa0ad2SJack F Vogel 		DEBUGOUT("Flash commit failed.\n");
4299a69ed8dfSJack F Vogel 		goto release;
43008cfa0ad2SJack F Vogel 	}
43018cfa0ad2SJack F Vogel 
43026ab6bfe3SJack F Vogel 	/* Finally validate the new segment by setting bit 15:14
43038cfa0ad2SJack F Vogel 	 * to 10b in word 0x13 , this can be done without an
43048cfa0ad2SJack F Vogel 	 * erase as well since these bits are 11 to start with
43058cfa0ad2SJack F Vogel 	 * and we need to change bit 14 to 0b
43068cfa0ad2SJack F Vogel 	 */
43078cfa0ad2SJack F Vogel 	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
4308d035aa2dSJack F Vogel 	ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
4309a69ed8dfSJack F Vogel 	if (ret_val)
4310a69ed8dfSJack F Vogel 		goto release;
43114edd8523SJack F Vogel 
43128cfa0ad2SJack F Vogel 	data &= 0xBFFF;
43138cc64f1eSJack F Vogel 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset * 2 + 1,
43148cfa0ad2SJack F Vogel 						       (u8)(data >> 8));
4315a69ed8dfSJack F Vogel 	if (ret_val)
4316a69ed8dfSJack F Vogel 		goto release;
43178cfa0ad2SJack F Vogel 
43186ab6bfe3SJack F Vogel 	/* And invalidate the previously valid segment by setting
43198cfa0ad2SJack F Vogel 	 * its signature word (0x13) high_byte to 0b. This can be
43208cfa0ad2SJack F Vogel 	 * done without an erase because flash erase sets all bits
43218cfa0ad2SJack F Vogel 	 * to 1's. We can write 1's to 0's without an erase
43228cfa0ad2SJack F Vogel 	 */
43238cfa0ad2SJack F Vogel 	act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
43248cc64f1eSJack F Vogel 
43258cfa0ad2SJack F Vogel 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
43268cc64f1eSJack F Vogel 
4327a69ed8dfSJack F Vogel 	if (ret_val)
4328a69ed8dfSJack F Vogel 		goto release;
43298cfa0ad2SJack F Vogel 
43308cfa0ad2SJack F Vogel 	/* Great!  Everything worked, we can now clear the cached entries. */
43318cfa0ad2SJack F Vogel 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
43328cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].modified = FALSE;
43338cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].value = 0xFFFF;
43348cfa0ad2SJack F Vogel 	}
43358cfa0ad2SJack F Vogel 
4336a69ed8dfSJack F Vogel release:
43378cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
43388cfa0ad2SJack F Vogel 
43396ab6bfe3SJack F Vogel 	/* Reload the EEPROM, or else modifications will not appear
43408cfa0ad2SJack F Vogel 	 * until after the next adapter reset.
43418cfa0ad2SJack F Vogel 	 */
4342a69ed8dfSJack F Vogel 	if (!ret_val) {
43438cfa0ad2SJack F Vogel 		nvm->ops.reload(hw);
43448cfa0ad2SJack F Vogel 		msec_delay(10);
4345a69ed8dfSJack F Vogel 	}
43468cfa0ad2SJack F Vogel 
43478cfa0ad2SJack F Vogel out:
4348d035aa2dSJack F Vogel 	if (ret_val)
4349d035aa2dSJack F Vogel 		DEBUGOUT1("NVM update error: %d\n", ret_val);
4350d035aa2dSJack F Vogel 
43518cfa0ad2SJack F Vogel 	return ret_val;
43528cfa0ad2SJack F Vogel }
43538cfa0ad2SJack F Vogel 
43548cfa0ad2SJack F Vogel /**
43558cfa0ad2SJack F Vogel  *  e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
43568cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
43578cfa0ad2SJack F Vogel  *
43588cfa0ad2SJack F Vogel  *  Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
4359daf9197cSJack F Vogel  *  If the bit is 0, that the EEPROM had been modified, but the checksum was not
4360daf9197cSJack F Vogel  *  calculated, in which case we need to calculate the checksum and set bit 6.
43618cfa0ad2SJack F Vogel  **/
43628cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
43638cfa0ad2SJack F Vogel {
43646ab6bfe3SJack F Vogel 	s32 ret_val;
43658cfa0ad2SJack F Vogel 	u16 data;
43666ab6bfe3SJack F Vogel 	u16 word;
43676ab6bfe3SJack F Vogel 	u16 valid_csum_mask;
43688cfa0ad2SJack F Vogel 
43698cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan");
43708cfa0ad2SJack F Vogel 
43716ab6bfe3SJack F Vogel 	/* Read NVM and check Invalid Image CSUM bit.  If this bit is 0,
43726ab6bfe3SJack F Vogel 	 * the checksum needs to be fixed.  This bit is an indication that
43736ab6bfe3SJack F Vogel 	 * the NVM was prepared by OEM software and did not calculate
43746ab6bfe3SJack F Vogel 	 * the checksum...a likely scenario.
43758cfa0ad2SJack F Vogel 	 */
43766ab6bfe3SJack F Vogel 	switch (hw->mac.type) {
43776ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
4378*c80429ceSEric Joyner 	case e1000_pch_spt:
43796ab6bfe3SJack F Vogel 		word = NVM_COMPAT;
43806ab6bfe3SJack F Vogel 		valid_csum_mask = NVM_COMPAT_VALID_CSUM;
43816ab6bfe3SJack F Vogel 		break;
43826ab6bfe3SJack F Vogel 	default:
43836ab6bfe3SJack F Vogel 		word = NVM_FUTURE_INIT_WORD1;
43846ab6bfe3SJack F Vogel 		valid_csum_mask = NVM_FUTURE_INIT_WORD1_VALID_CSUM;
43856ab6bfe3SJack F Vogel 		break;
43868cfa0ad2SJack F Vogel 	}
43878cfa0ad2SJack F Vogel 
43886ab6bfe3SJack F Vogel 	ret_val = hw->nvm.ops.read(hw, word, 1, &data);
43896ab6bfe3SJack F Vogel 	if (ret_val)
43908cfa0ad2SJack F Vogel 		return ret_val;
43916ab6bfe3SJack F Vogel 
43926ab6bfe3SJack F Vogel 	if (!(data & valid_csum_mask)) {
43936ab6bfe3SJack F Vogel 		data |= valid_csum_mask;
43946ab6bfe3SJack F Vogel 		ret_val = hw->nvm.ops.write(hw, word, 1, &data);
43956ab6bfe3SJack F Vogel 		if (ret_val)
43966ab6bfe3SJack F Vogel 			return ret_val;
43976ab6bfe3SJack F Vogel 		ret_val = hw->nvm.ops.update(hw);
43986ab6bfe3SJack F Vogel 		if (ret_val)
43996ab6bfe3SJack F Vogel 			return ret_val;
44006ab6bfe3SJack F Vogel 	}
44016ab6bfe3SJack F Vogel 
44026ab6bfe3SJack F Vogel 	return e1000_validate_nvm_checksum_generic(hw);
44038cfa0ad2SJack F Vogel }
44048cfa0ad2SJack F Vogel 
44058cfa0ad2SJack F Vogel /**
44068cfa0ad2SJack F Vogel  *  e1000_write_flash_data_ich8lan - Writes bytes to the NVM
44078cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
44088cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the byte/word to read.
44098cfa0ad2SJack F Vogel  *  @size: Size of data to read, 1=byte 2=word
44108cfa0ad2SJack F Vogel  *  @data: The byte(s) to write to the NVM.
44118cfa0ad2SJack F Vogel  *
44128cfa0ad2SJack F Vogel  *  Writes one/two bytes to the NVM using the flash access registers.
44138cfa0ad2SJack F Vogel  **/
44148cfa0ad2SJack F Vogel static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
44158cfa0ad2SJack F Vogel 					  u8 size, u16 data)
44168cfa0ad2SJack F Vogel {
44178cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
44188cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
44198cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
44208cfa0ad2SJack F Vogel 	u32 flash_data = 0;
44216ab6bfe3SJack F Vogel 	s32 ret_val;
44228cfa0ad2SJack F Vogel 	u8 count = 0;
44238cfa0ad2SJack F Vogel 
44248cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_ich8_data");
44258cfa0ad2SJack F Vogel 
4426*c80429ceSEric Joyner 	if (hw->mac.type == e1000_pch_spt) {
4427*c80429ceSEric Joyner 		if (size != 4 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
4428*c80429ceSEric Joyner 			return -E1000_ERR_NVM;
4429*c80429ceSEric Joyner 	} else {
44308cc64f1eSJack F Vogel 		if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
44316ab6bfe3SJack F Vogel 			return -E1000_ERR_NVM;
4432*c80429ceSEric Joyner 	}
44338cfa0ad2SJack F Vogel 
44347609433eSJack F Vogel 	flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
44357609433eSJack F Vogel 			     hw->nvm.flash_base_addr);
44368cfa0ad2SJack F Vogel 
44378cfa0ad2SJack F Vogel 	do {
44388cfa0ad2SJack F Vogel 		usec_delay(1);
44398cfa0ad2SJack F Vogel 		/* Steps */
44408cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
44418cfa0ad2SJack F Vogel 		if (ret_val != E1000_SUCCESS)
44428cfa0ad2SJack F Vogel 			break;
4443*c80429ceSEric Joyner 		/* In SPT, This register is in Lan memory space, not
4444*c80429ceSEric Joyner 		 * flash.  Therefore, only 32 bit access is supported
4445*c80429ceSEric Joyner 		 */
4446*c80429ceSEric Joyner 		if (hw->mac.type == e1000_pch_spt)
4447*c80429ceSEric Joyner 			hsflctl.regval =
4448*c80429ceSEric Joyner 			    E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16;
4449*c80429ceSEric Joyner 		else
4450*c80429ceSEric Joyner 			hsflctl.regval =
4451*c80429ceSEric Joyner 			    E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
44528cc64f1eSJack F Vogel 
44538cfa0ad2SJack F Vogel 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
44548cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.fldbcount = size - 1;
44558cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
4456*c80429ceSEric Joyner 		/* In SPT, This register is in Lan memory space,
4457*c80429ceSEric Joyner 		 * not flash.  Therefore, only 32 bit access is
4458*c80429ceSEric Joyner 		 * supported
4459*c80429ceSEric Joyner 		 */
4460*c80429ceSEric Joyner 		if (hw->mac.type == e1000_pch_spt)
4461*c80429ceSEric Joyner 			E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
4462*c80429ceSEric Joyner 					      hsflctl.regval << 16);
4463*c80429ceSEric Joyner 		else
4464*c80429ceSEric Joyner 			E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
4465*c80429ceSEric Joyner 						hsflctl.regval);
44668cfa0ad2SJack F Vogel 
44678cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
44688cfa0ad2SJack F Vogel 
44698cfa0ad2SJack F Vogel 		if (size == 1)
44708cfa0ad2SJack F Vogel 			flash_data = (u32)data & 0x00FF;
44718cfa0ad2SJack F Vogel 		else
44728cfa0ad2SJack F Vogel 			flash_data = (u32)data;
44738cfa0ad2SJack F Vogel 
44748cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data);
44758cfa0ad2SJack F Vogel 
44766ab6bfe3SJack F Vogel 		/* check if FCERR is set to 1 , if set to 1, clear it
44778cfa0ad2SJack F Vogel 		 * and try the whole sequence a few more times else done
44788cfa0ad2SJack F Vogel 		 */
44797609433eSJack F Vogel 		ret_val =
44807609433eSJack F Vogel 		    e1000_flash_cycle_ich8lan(hw,
44818cfa0ad2SJack F Vogel 					      ICH_FLASH_WRITE_COMMAND_TIMEOUT);
4482daf9197cSJack F Vogel 		if (ret_val == E1000_SUCCESS)
44838cfa0ad2SJack F Vogel 			break;
4484daf9197cSJack F Vogel 
44856ab6bfe3SJack F Vogel 		/* If we're here, then things are most likely
44868cfa0ad2SJack F Vogel 		 * completely hosed, but if the error condition
44878cfa0ad2SJack F Vogel 		 * is detected, it won't hurt to give it another
44888cfa0ad2SJack F Vogel 		 * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
44898cfa0ad2SJack F Vogel 		 */
4490daf9197cSJack F Vogel 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
44916ab6bfe3SJack F Vogel 		if (hsfsts.hsf_status.flcerr)
44928cfa0ad2SJack F Vogel 			/* Repeat for some time before giving up. */
44938cfa0ad2SJack F Vogel 			continue;
44946ab6bfe3SJack F Vogel 		if (!hsfsts.hsf_status.flcdone) {
44954dab5c37SJack F Vogel 			DEBUGOUT("Timeout error - flash cycle did not complete.\n");
44968cfa0ad2SJack F Vogel 			break;
44978cfa0ad2SJack F Vogel 		}
44988cfa0ad2SJack F Vogel 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
44998cfa0ad2SJack F Vogel 
45008cfa0ad2SJack F Vogel 	return ret_val;
45018cfa0ad2SJack F Vogel }
45028cfa0ad2SJack F Vogel 
4503*c80429ceSEric Joyner /**
4504*c80429ceSEric Joyner *  e1000_write_flash_data32_ich8lan - Writes 4 bytes to the NVM
4505*c80429ceSEric Joyner *  @hw: pointer to the HW structure
4506*c80429ceSEric Joyner *  @offset: The offset (in bytes) of the dwords to read.
4507*c80429ceSEric Joyner *  @data: The 4 bytes to write to the NVM.
4508*c80429ceSEric Joyner *
4509*c80429ceSEric Joyner *  Writes one/two/four bytes to the NVM using the flash access registers.
4510*c80429ceSEric Joyner **/
4511*c80429ceSEric Joyner static s32 e1000_write_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
4512*c80429ceSEric Joyner 					    u32 data)
4513*c80429ceSEric Joyner {
4514*c80429ceSEric Joyner 	union ich8_hws_flash_status hsfsts;
4515*c80429ceSEric Joyner 	union ich8_hws_flash_ctrl hsflctl;
4516*c80429ceSEric Joyner 	u32 flash_linear_addr;
4517*c80429ceSEric Joyner 	s32 ret_val;
4518*c80429ceSEric Joyner 	u8 count = 0;
4519*c80429ceSEric Joyner 
4520*c80429ceSEric Joyner 	DEBUGFUNC("e1000_write_flash_data32_ich8lan");
4521*c80429ceSEric Joyner 
4522*c80429ceSEric Joyner 	if (hw->mac.type == e1000_pch_spt) {
4523*c80429ceSEric Joyner 		if (offset > ICH_FLASH_LINEAR_ADDR_MASK)
4524*c80429ceSEric Joyner 			return -E1000_ERR_NVM;
4525*c80429ceSEric Joyner 	}
4526*c80429ceSEric Joyner 	flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
4527*c80429ceSEric Joyner 			     hw->nvm.flash_base_addr);
4528*c80429ceSEric Joyner 	do {
4529*c80429ceSEric Joyner 		usec_delay(1);
4530*c80429ceSEric Joyner 		/* Steps */
4531*c80429ceSEric Joyner 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
4532*c80429ceSEric Joyner 		if (ret_val != E1000_SUCCESS)
4533*c80429ceSEric Joyner 			break;
4534*c80429ceSEric Joyner 
4535*c80429ceSEric Joyner 		/* In SPT, This register is in Lan memory space, not
4536*c80429ceSEric Joyner 		 * flash.  Therefore, only 32 bit access is supported
4537*c80429ceSEric Joyner 		 */
4538*c80429ceSEric Joyner 		if (hw->mac.type == e1000_pch_spt)
4539*c80429ceSEric Joyner 			hsflctl.regval = E1000_READ_FLASH_REG(hw,
4540*c80429ceSEric Joyner 							      ICH_FLASH_HSFSTS)
4541*c80429ceSEric Joyner 					 >> 16;
4542*c80429ceSEric Joyner 		else
4543*c80429ceSEric Joyner 			hsflctl.regval = E1000_READ_FLASH_REG16(hw,
4544*c80429ceSEric Joyner 							      ICH_FLASH_HSFCTL);
4545*c80429ceSEric Joyner 
4546*c80429ceSEric Joyner 		hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1;
4547*c80429ceSEric Joyner 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
4548*c80429ceSEric Joyner 
4549*c80429ceSEric Joyner 		/* In SPT, This register is in Lan memory space,
4550*c80429ceSEric Joyner 		 * not flash.  Therefore, only 32 bit access is
4551*c80429ceSEric Joyner 		 * supported
4552*c80429ceSEric Joyner 		 */
4553*c80429ceSEric Joyner 		if (hw->mac.type == e1000_pch_spt)
4554*c80429ceSEric Joyner 			E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
4555*c80429ceSEric Joyner 					      hsflctl.regval << 16);
4556*c80429ceSEric Joyner 		else
4557*c80429ceSEric Joyner 			E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
4558*c80429ceSEric Joyner 						hsflctl.regval);
4559*c80429ceSEric Joyner 
4560*c80429ceSEric Joyner 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
4561*c80429ceSEric Joyner 
4562*c80429ceSEric Joyner 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, data);
4563*c80429ceSEric Joyner 
4564*c80429ceSEric Joyner 		/* check if FCERR is set to 1 , if set to 1, clear it
4565*c80429ceSEric Joyner 		 * and try the whole sequence a few more times else done
4566*c80429ceSEric Joyner 		 */
4567*c80429ceSEric Joyner 		ret_val = e1000_flash_cycle_ich8lan(hw,
4568*c80429ceSEric Joyner 					       ICH_FLASH_WRITE_COMMAND_TIMEOUT);
4569*c80429ceSEric Joyner 
4570*c80429ceSEric Joyner 		if (ret_val == E1000_SUCCESS)
4571*c80429ceSEric Joyner 			break;
4572*c80429ceSEric Joyner 
4573*c80429ceSEric Joyner 		/* If we're here, then things are most likely
4574*c80429ceSEric Joyner 		 * completely hosed, but if the error condition
4575*c80429ceSEric Joyner 		 * is detected, it won't hurt to give it another
4576*c80429ceSEric Joyner 		 * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
4577*c80429ceSEric Joyner 		 */
4578*c80429ceSEric Joyner 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
4579*c80429ceSEric Joyner 
4580*c80429ceSEric Joyner 		if (hsfsts.hsf_status.flcerr)
4581*c80429ceSEric Joyner 			/* Repeat for some time before giving up. */
4582*c80429ceSEric Joyner 			continue;
4583*c80429ceSEric Joyner 		if (!hsfsts.hsf_status.flcdone) {
4584*c80429ceSEric Joyner 			DEBUGOUT("Timeout error - flash cycle did not complete.\n");
4585*c80429ceSEric Joyner 			break;
4586*c80429ceSEric Joyner 		}
4587*c80429ceSEric Joyner 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
4588*c80429ceSEric Joyner 
4589*c80429ceSEric Joyner 	return ret_val;
4590*c80429ceSEric Joyner }
45918cc64f1eSJack F Vogel 
45928cfa0ad2SJack F Vogel /**
45938cfa0ad2SJack F Vogel  *  e1000_write_flash_byte_ich8lan - Write a single byte to NVM
45948cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
45958cfa0ad2SJack F Vogel  *  @offset: The index of the byte to read.
45968cfa0ad2SJack F Vogel  *  @data: The byte to write to the NVM.
45978cfa0ad2SJack F Vogel  *
45988cfa0ad2SJack F Vogel  *  Writes a single byte to the NVM using the flash access registers.
45998cfa0ad2SJack F Vogel  **/
46008cfa0ad2SJack F Vogel static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
46018cfa0ad2SJack F Vogel 					  u8 data)
46028cfa0ad2SJack F Vogel {
46038cfa0ad2SJack F Vogel 	u16 word = (u16)data;
46048cfa0ad2SJack F Vogel 
46058cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_flash_byte_ich8lan");
46068cfa0ad2SJack F Vogel 
46078cfa0ad2SJack F Vogel 	return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
46088cfa0ad2SJack F Vogel }
46098cfa0ad2SJack F Vogel 
4610*c80429ceSEric Joyner /**
4611*c80429ceSEric Joyner *  e1000_retry_write_flash_dword_ich8lan - Writes a dword to NVM
4612*c80429ceSEric Joyner *  @hw: pointer to the HW structure
4613*c80429ceSEric Joyner *  @offset: The offset of the word to write.
4614*c80429ceSEric Joyner *  @dword: The dword to write to the NVM.
4615*c80429ceSEric Joyner *
4616*c80429ceSEric Joyner *  Writes a single dword to the NVM using the flash access registers.
4617*c80429ceSEric Joyner *  Goes through a retry algorithm before giving up.
4618*c80429ceSEric Joyner **/
4619*c80429ceSEric Joyner static s32 e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw,
4620*c80429ceSEric Joyner 						 u32 offset, u32 dword)
4621*c80429ceSEric Joyner {
4622*c80429ceSEric Joyner 	s32 ret_val;
4623*c80429ceSEric Joyner 	u16 program_retries;
46248cc64f1eSJack F Vogel 
4625*c80429ceSEric Joyner 	DEBUGFUNC("e1000_retry_write_flash_dword_ich8lan");
4626*c80429ceSEric Joyner 
4627*c80429ceSEric Joyner 	/* Must convert word offset into bytes. */
4628*c80429ceSEric Joyner 	offset <<= 1;
4629*c80429ceSEric Joyner 
4630*c80429ceSEric Joyner 	ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword);
4631*c80429ceSEric Joyner 
4632*c80429ceSEric Joyner 	if (!ret_val)
4633*c80429ceSEric Joyner 		return ret_val;
4634*c80429ceSEric Joyner 	for (program_retries = 0; program_retries < 100; program_retries++) {
4635*c80429ceSEric Joyner 		DEBUGOUT2("Retrying Byte %8.8X at offset %u\n", dword, offset);
4636*c80429ceSEric Joyner 		usec_delay(100);
4637*c80429ceSEric Joyner 		ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword);
4638*c80429ceSEric Joyner 		if (ret_val == E1000_SUCCESS)
4639*c80429ceSEric Joyner 			break;
4640*c80429ceSEric Joyner 	}
4641*c80429ceSEric Joyner 	if (program_retries == 100)
4642*c80429ceSEric Joyner 		return -E1000_ERR_NVM;
4643*c80429ceSEric Joyner 
4644*c80429ceSEric Joyner 	return E1000_SUCCESS;
4645*c80429ceSEric Joyner }
46468cc64f1eSJack F Vogel 
46478cfa0ad2SJack F Vogel /**
46488cfa0ad2SJack F Vogel  *  e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
46498cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
46508cfa0ad2SJack F Vogel  *  @offset: The offset of the byte to write.
46518cfa0ad2SJack F Vogel  *  @byte: The byte to write to the NVM.
46528cfa0ad2SJack F Vogel  *
46538cfa0ad2SJack F Vogel  *  Writes a single byte to the NVM using the flash access registers.
46548cfa0ad2SJack F Vogel  *  Goes through a retry algorithm before giving up.
46558cfa0ad2SJack F Vogel  **/
46568cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
46578cfa0ad2SJack F Vogel 						u32 offset, u8 byte)
46588cfa0ad2SJack F Vogel {
46598cfa0ad2SJack F Vogel 	s32 ret_val;
46608cfa0ad2SJack F Vogel 	u16 program_retries;
46618cfa0ad2SJack F Vogel 
46628cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan");
46638cfa0ad2SJack F Vogel 
46648cfa0ad2SJack F Vogel 	ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
46656ab6bfe3SJack F Vogel 	if (!ret_val)
46666ab6bfe3SJack F Vogel 		return ret_val;
46678cfa0ad2SJack F Vogel 
46688cfa0ad2SJack F Vogel 	for (program_retries = 0; program_retries < 100; program_retries++) {
46698cfa0ad2SJack F Vogel 		DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset);
46708cfa0ad2SJack F Vogel 		usec_delay(100);
46718cfa0ad2SJack F Vogel 		ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
46728cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS)
46738cfa0ad2SJack F Vogel 			break;
46748cfa0ad2SJack F Vogel 	}
46756ab6bfe3SJack F Vogel 	if (program_retries == 100)
46766ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
46778cfa0ad2SJack F Vogel 
46786ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
46798cfa0ad2SJack F Vogel }
46808cfa0ad2SJack F Vogel 
46818cfa0ad2SJack F Vogel /**
46828cfa0ad2SJack F Vogel  *  e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
46838cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
46848cfa0ad2SJack F Vogel  *  @bank: 0 for first bank, 1 for second bank, etc.
46858cfa0ad2SJack F Vogel  *
46868cfa0ad2SJack F Vogel  *  Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
46878cfa0ad2SJack F Vogel  *  bank N is 4096 * N + flash_reg_addr.
46888cfa0ad2SJack F Vogel  **/
46898cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
46908cfa0ad2SJack F Vogel {
46918cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
46928cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
46938cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
46948cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
46958cfa0ad2SJack F Vogel 	/* bank size is in 16bit words - adjust to bytes */
46968cfa0ad2SJack F Vogel 	u32 flash_bank_size = nvm->flash_bank_size * 2;
46976ab6bfe3SJack F Vogel 	s32 ret_val;
46988cfa0ad2SJack F Vogel 	s32 count = 0;
46998cfa0ad2SJack F Vogel 	s32 j, iteration, sector_size;
47008cfa0ad2SJack F Vogel 
47018cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_erase_flash_bank_ich8lan");
47028cfa0ad2SJack F Vogel 
47038cfa0ad2SJack F Vogel 	hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
47048cfa0ad2SJack F Vogel 
47056ab6bfe3SJack F Vogel 	/* Determine HW Sector size: Read BERASE bits of hw flash status
47068cfa0ad2SJack F Vogel 	 * register
47078cfa0ad2SJack F Vogel 	 * 00: The Hw sector is 256 bytes, hence we need to erase 16
47088cfa0ad2SJack F Vogel 	 *     consecutive sectors.  The start index for the nth Hw sector
47098cfa0ad2SJack F Vogel 	 *     can be calculated as = bank * 4096 + n * 256
47108cfa0ad2SJack F Vogel 	 * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
47118cfa0ad2SJack F Vogel 	 *     The start index for the nth Hw sector can be calculated
47128cfa0ad2SJack F Vogel 	 *     as = bank * 4096
47138cfa0ad2SJack F Vogel 	 * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
47148cfa0ad2SJack F Vogel 	 *     (ich9 only, otherwise error condition)
47158cfa0ad2SJack F Vogel 	 * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
47168cfa0ad2SJack F Vogel 	 */
47178cfa0ad2SJack F Vogel 	switch (hsfsts.hsf_status.berasesz) {
47188cfa0ad2SJack F Vogel 	case 0:
47198cfa0ad2SJack F Vogel 		/* Hw sector size 256 */
47208cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_256;
47218cfa0ad2SJack F Vogel 		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
47228cfa0ad2SJack F Vogel 		break;
47238cfa0ad2SJack F Vogel 	case 1:
47248cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_4K;
47259d81738fSJack F Vogel 		iteration = 1;
47268cfa0ad2SJack F Vogel 		break;
47278cfa0ad2SJack F Vogel 	case 2:
47288cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_8K;
47298bd0025fSJack F Vogel 		iteration = 1;
47308cfa0ad2SJack F Vogel 		break;
47318cfa0ad2SJack F Vogel 	case 3:
47328cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_64K;
47339d81738fSJack F Vogel 		iteration = 1;
47348cfa0ad2SJack F Vogel 		break;
47358cfa0ad2SJack F Vogel 	default:
47366ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
47378cfa0ad2SJack F Vogel 	}
47388cfa0ad2SJack F Vogel 
47398cfa0ad2SJack F Vogel 	/* Start with the base address, then add the sector offset. */
47408cfa0ad2SJack F Vogel 	flash_linear_addr = hw->nvm.flash_base_addr;
47414edd8523SJack F Vogel 	flash_linear_addr += (bank) ? flash_bank_size : 0;
47428cfa0ad2SJack F Vogel 
47438cfa0ad2SJack F Vogel 	for (j = 0; j < iteration; j++) {
47448cfa0ad2SJack F Vogel 		do {
47457609433eSJack F Vogel 			u32 timeout = ICH_FLASH_ERASE_COMMAND_TIMEOUT;
47467609433eSJack F Vogel 
47478cfa0ad2SJack F Vogel 			/* Steps */
47488cfa0ad2SJack F Vogel 			ret_val = e1000_flash_cycle_init_ich8lan(hw);
47498cfa0ad2SJack F Vogel 			if (ret_val)
47506ab6bfe3SJack F Vogel 				return ret_val;
47518cfa0ad2SJack F Vogel 
47526ab6bfe3SJack F Vogel 			/* Write a value 11 (block Erase) in Flash
47538cfa0ad2SJack F Vogel 			 * Cycle field in hw flash control
47548cfa0ad2SJack F Vogel 			 */
4755*c80429ceSEric Joyner 			if (hw->mac.type == e1000_pch_spt)
47568cc64f1eSJack F Vogel 				hsflctl.regval =
4757*c80429ceSEric Joyner 				    E1000_READ_FLASH_REG(hw,
4758*c80429ceSEric Joyner 							 ICH_FLASH_HSFSTS)>>16;
4759*c80429ceSEric Joyner 			else
4760*c80429ceSEric Joyner 				hsflctl.regval =
4761*c80429ceSEric Joyner 				    E1000_READ_FLASH_REG16(hw,
4762*c80429ceSEric Joyner 							   ICH_FLASH_HSFCTL);
47638cc64f1eSJack F Vogel 
47648cfa0ad2SJack F Vogel 			hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
4765*c80429ceSEric Joyner 			if (hw->mac.type == e1000_pch_spt)
4766*c80429ceSEric Joyner 				E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
4767*c80429ceSEric Joyner 						      hsflctl.regval << 16);
4768*c80429ceSEric Joyner 			else
4769daf9197cSJack F Vogel 				E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
47708cfa0ad2SJack F Vogel 							hsflctl.regval);
47718cfa0ad2SJack F Vogel 
47726ab6bfe3SJack F Vogel 			/* Write the last 24 bits of an index within the
47738cfa0ad2SJack F Vogel 			 * block into Flash Linear address field in Flash
47748cfa0ad2SJack F Vogel 			 * Address.
47758cfa0ad2SJack F Vogel 			 */
47768cfa0ad2SJack F Vogel 			flash_linear_addr += (j * sector_size);
4777daf9197cSJack F Vogel 			E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR,
47788cfa0ad2SJack F Vogel 					      flash_linear_addr);
47798cfa0ad2SJack F Vogel 
47807609433eSJack F Vogel 			ret_val = e1000_flash_cycle_ich8lan(hw, timeout);
4781daf9197cSJack F Vogel 			if (ret_val == E1000_SUCCESS)
47828cfa0ad2SJack F Vogel 				break;
4783daf9197cSJack F Vogel 
47846ab6bfe3SJack F Vogel 			/* Check if FCERR is set to 1.  If 1,
47858cfa0ad2SJack F Vogel 			 * clear it and try the whole sequence
47868cfa0ad2SJack F Vogel 			 * a few more times else Done
47878cfa0ad2SJack F Vogel 			 */
47888cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
47898cfa0ad2SJack F Vogel 						      ICH_FLASH_HSFSTS);
47906ab6bfe3SJack F Vogel 			if (hsfsts.hsf_status.flcerr)
4791daf9197cSJack F Vogel 				/* repeat for some time before giving up */
47928cfa0ad2SJack F Vogel 				continue;
47936ab6bfe3SJack F Vogel 			else if (!hsfsts.hsf_status.flcdone)
47946ab6bfe3SJack F Vogel 				return ret_val;
47958cfa0ad2SJack F Vogel 		} while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
47968cfa0ad2SJack F Vogel 	}
47978cfa0ad2SJack F Vogel 
47986ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
47998cfa0ad2SJack F Vogel }
48008cfa0ad2SJack F Vogel 
48018cfa0ad2SJack F Vogel /**
48028cfa0ad2SJack F Vogel  *  e1000_valid_led_default_ich8lan - Set the default LED settings
48038cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
48048cfa0ad2SJack F Vogel  *  @data: Pointer to the LED settings
48058cfa0ad2SJack F Vogel  *
48068cfa0ad2SJack F Vogel  *  Reads the LED default settings from the NVM to data.  If the NVM LED
48078cfa0ad2SJack F Vogel  *  settings is all 0's or F's, set the LED default to a valid LED default
48088cfa0ad2SJack F Vogel  *  setting.
48098cfa0ad2SJack F Vogel  **/
48108cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
48118cfa0ad2SJack F Vogel {
48128cfa0ad2SJack F Vogel 	s32 ret_val;
48138cfa0ad2SJack F Vogel 
48148cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_valid_led_default_ich8lan");
48158cfa0ad2SJack F Vogel 
48168cfa0ad2SJack F Vogel 	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
48178cfa0ad2SJack F Vogel 	if (ret_val) {
48188cfa0ad2SJack F Vogel 		DEBUGOUT("NVM Read Error\n");
48196ab6bfe3SJack F Vogel 		return ret_val;
48208cfa0ad2SJack F Vogel 	}
48218cfa0ad2SJack F Vogel 
48224dab5c37SJack F Vogel 	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
48238cfa0ad2SJack F Vogel 		*data = ID_LED_DEFAULT_ICH8LAN;
48248cfa0ad2SJack F Vogel 
48256ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
48268cfa0ad2SJack F Vogel }
48278cfa0ad2SJack F Vogel 
48288cfa0ad2SJack F Vogel /**
48299d81738fSJack F Vogel  *  e1000_id_led_init_pchlan - store LED configurations
48309d81738fSJack F Vogel  *  @hw: pointer to the HW structure
48319d81738fSJack F Vogel  *
48329d81738fSJack F Vogel  *  PCH does not control LEDs via the LEDCTL register, rather it uses
48339d81738fSJack F Vogel  *  the PHY LED configuration register.
48349d81738fSJack F Vogel  *
48359d81738fSJack F Vogel  *  PCH also does not have an "always on" or "always off" mode which
48369d81738fSJack F Vogel  *  complicates the ID feature.  Instead of using the "on" mode to indicate
48379d81738fSJack F Vogel  *  in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()),
48389d81738fSJack F Vogel  *  use "link_up" mode.  The LEDs will still ID on request if there is no
48399d81738fSJack F Vogel  *  link based on logic in e1000_led_[on|off]_pchlan().
48409d81738fSJack F Vogel  **/
48419d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw)
48429d81738fSJack F Vogel {
48439d81738fSJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
48449d81738fSJack F Vogel 	s32 ret_val;
48459d81738fSJack F Vogel 	const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
48469d81738fSJack F Vogel 	const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
48479d81738fSJack F Vogel 	u16 data, i, temp, shift;
48489d81738fSJack F Vogel 
48499d81738fSJack F Vogel 	DEBUGFUNC("e1000_id_led_init_pchlan");
48509d81738fSJack F Vogel 
48519d81738fSJack F Vogel 	/* Get default ID LED modes */
48529d81738fSJack F Vogel 	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
48539d81738fSJack F Vogel 	if (ret_val)
48546ab6bfe3SJack F Vogel 		return ret_val;
48559d81738fSJack F Vogel 
48569d81738fSJack F Vogel 	mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
48579d81738fSJack F Vogel 	mac->ledctl_mode1 = mac->ledctl_default;
48589d81738fSJack F Vogel 	mac->ledctl_mode2 = mac->ledctl_default;
48599d81738fSJack F Vogel 
48609d81738fSJack F Vogel 	for (i = 0; i < 4; i++) {
48619d81738fSJack F Vogel 		temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
48629d81738fSJack F Vogel 		shift = (i * 5);
48639d81738fSJack F Vogel 		switch (temp) {
48649d81738fSJack F Vogel 		case ID_LED_ON1_DEF2:
48659d81738fSJack F Vogel 		case ID_LED_ON1_ON2:
48669d81738fSJack F Vogel 		case ID_LED_ON1_OFF2:
48679d81738fSJack F Vogel 			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
48689d81738fSJack F Vogel 			mac->ledctl_mode1 |= (ledctl_on << shift);
48699d81738fSJack F Vogel 			break;
48709d81738fSJack F Vogel 		case ID_LED_OFF1_DEF2:
48719d81738fSJack F Vogel 		case ID_LED_OFF1_ON2:
48729d81738fSJack F Vogel 		case ID_LED_OFF1_OFF2:
48739d81738fSJack F Vogel 			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
48749d81738fSJack F Vogel 			mac->ledctl_mode1 |= (ledctl_off << shift);
48759d81738fSJack F Vogel 			break;
48769d81738fSJack F Vogel 		default:
48779d81738fSJack F Vogel 			/* Do nothing */
48789d81738fSJack F Vogel 			break;
48799d81738fSJack F Vogel 		}
48809d81738fSJack F Vogel 		switch (temp) {
48819d81738fSJack F Vogel 		case ID_LED_DEF1_ON2:
48829d81738fSJack F Vogel 		case ID_LED_ON1_ON2:
48839d81738fSJack F Vogel 		case ID_LED_OFF1_ON2:
48849d81738fSJack F Vogel 			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
48859d81738fSJack F Vogel 			mac->ledctl_mode2 |= (ledctl_on << shift);
48869d81738fSJack F Vogel 			break;
48879d81738fSJack F Vogel 		case ID_LED_DEF1_OFF2:
48889d81738fSJack F Vogel 		case ID_LED_ON1_OFF2:
48899d81738fSJack F Vogel 		case ID_LED_OFF1_OFF2:
48909d81738fSJack F Vogel 			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
48919d81738fSJack F Vogel 			mac->ledctl_mode2 |= (ledctl_off << shift);
48929d81738fSJack F Vogel 			break;
48939d81738fSJack F Vogel 		default:
48949d81738fSJack F Vogel 			/* Do nothing */
48959d81738fSJack F Vogel 			break;
48969d81738fSJack F Vogel 		}
48979d81738fSJack F Vogel 	}
48989d81738fSJack F Vogel 
48996ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
49009d81738fSJack F Vogel }
49019d81738fSJack F Vogel 
49029d81738fSJack F Vogel /**
49038cfa0ad2SJack F Vogel  *  e1000_get_bus_info_ich8lan - Get/Set the bus type and width
49048cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
49058cfa0ad2SJack F Vogel  *
49068cfa0ad2SJack F Vogel  *  ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
49076ab6bfe3SJack F Vogel  *  register, so the the bus width is hard coded.
49088cfa0ad2SJack F Vogel  **/
49098cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
49108cfa0ad2SJack F Vogel {
49118cfa0ad2SJack F Vogel 	struct e1000_bus_info *bus = &hw->bus;
49128cfa0ad2SJack F Vogel 	s32 ret_val;
49138cfa0ad2SJack F Vogel 
49148cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_bus_info_ich8lan");
49158cfa0ad2SJack F Vogel 
49168cfa0ad2SJack F Vogel 	ret_val = e1000_get_bus_info_pcie_generic(hw);
49178cfa0ad2SJack F Vogel 
49186ab6bfe3SJack F Vogel 	/* ICH devices are "PCI Express"-ish.  They have
49198cfa0ad2SJack F Vogel 	 * a configuration space, but do not contain
49208cfa0ad2SJack F Vogel 	 * PCI Express Capability registers, so bus width
49218cfa0ad2SJack F Vogel 	 * must be hardcoded.
49228cfa0ad2SJack F Vogel 	 */
49238cfa0ad2SJack F Vogel 	if (bus->width == e1000_bus_width_unknown)
49248cfa0ad2SJack F Vogel 		bus->width = e1000_bus_width_pcie_x1;
49258cfa0ad2SJack F Vogel 
49268cfa0ad2SJack F Vogel 	return ret_val;
49278cfa0ad2SJack F Vogel }
49288cfa0ad2SJack F Vogel 
49298cfa0ad2SJack F Vogel /**
49308cfa0ad2SJack F Vogel  *  e1000_reset_hw_ich8lan - Reset the hardware
49318cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
49328cfa0ad2SJack F Vogel  *
49338cfa0ad2SJack F Vogel  *  Does a full reset of the hardware which includes a reset of the PHY and
49348cfa0ad2SJack F Vogel  *  MAC.
49358cfa0ad2SJack F Vogel  **/
49368cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
49378cfa0ad2SJack F Vogel {
49384edd8523SJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
49396ab6bfe3SJack F Vogel 	u16 kum_cfg;
49406ab6bfe3SJack F Vogel 	u32 ctrl, reg;
49418cfa0ad2SJack F Vogel 	s32 ret_val;
49428cfa0ad2SJack F Vogel 
49438cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_reset_hw_ich8lan");
49448cfa0ad2SJack F Vogel 
49456ab6bfe3SJack F Vogel 	/* Prevent the PCI-E bus from sticking if there is no TLP connection
49468cfa0ad2SJack F Vogel 	 * on the last TLP read/write transaction when MAC is reset.
49478cfa0ad2SJack F Vogel 	 */
49488cfa0ad2SJack F Vogel 	ret_val = e1000_disable_pcie_master_generic(hw);
4949daf9197cSJack F Vogel 	if (ret_val)
49508cfa0ad2SJack F Vogel 		DEBUGOUT("PCI-E Master disable polling has failed.\n");
49518cfa0ad2SJack F Vogel 
49528cfa0ad2SJack F Vogel 	DEBUGOUT("Masking off all interrupts\n");
49538cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
49548cfa0ad2SJack F Vogel 
49556ab6bfe3SJack F Vogel 	/* Disable the Transmit and Receive units.  Then delay to allow
49568cfa0ad2SJack F Vogel 	 * any pending transactions to complete before we hit the MAC
49578cfa0ad2SJack F Vogel 	 * with the global reset.
49588cfa0ad2SJack F Vogel 	 */
49598cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RCTL, 0);
49608cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
49618cfa0ad2SJack F Vogel 	E1000_WRITE_FLUSH(hw);
49628cfa0ad2SJack F Vogel 
49638cfa0ad2SJack F Vogel 	msec_delay(10);
49648cfa0ad2SJack F Vogel 
49658cfa0ad2SJack F Vogel 	/* Workaround for ICH8 bit corruption issue in FIFO memory */
49668cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan) {
49678cfa0ad2SJack F Vogel 		/* Set Tx and Rx buffer allocation to 8k apiece. */
49688cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K);
49698cfa0ad2SJack F Vogel 		/* Set Packet Buffer Size to 16k. */
49708cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K);
49718cfa0ad2SJack F Vogel 	}
49728cfa0ad2SJack F Vogel 
49734edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan) {
49744edd8523SJack F Vogel 		/* Save the NVM K1 bit setting*/
49756ab6bfe3SJack F Vogel 		ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, &kum_cfg);
49764edd8523SJack F Vogel 		if (ret_val)
49774edd8523SJack F Vogel 			return ret_val;
49784edd8523SJack F Vogel 
49796ab6bfe3SJack F Vogel 		if (kum_cfg & E1000_NVM_K1_ENABLE)
49804edd8523SJack F Vogel 			dev_spec->nvm_k1_enabled = TRUE;
49814edd8523SJack F Vogel 		else
49824edd8523SJack F Vogel 			dev_spec->nvm_k1_enabled = FALSE;
49834edd8523SJack F Vogel 	}
49844edd8523SJack F Vogel 
49858cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
49868cfa0ad2SJack F Vogel 
49877d9119bdSJack F Vogel 	if (!hw->phy.ops.check_reset_block(hw)) {
49886ab6bfe3SJack F Vogel 		/* Full-chip reset requires MAC and PHY reset at the same
49898cfa0ad2SJack F Vogel 		 * time to make sure the interface between MAC and the
49908cfa0ad2SJack F Vogel 		 * external PHY is reset.
49918cfa0ad2SJack F Vogel 		 */
49928cfa0ad2SJack F Vogel 		ctrl |= E1000_CTRL_PHY_RST;
49937d9119bdSJack F Vogel 
49946ab6bfe3SJack F Vogel 		/* Gate automatic PHY configuration by hardware on
49957d9119bdSJack F Vogel 		 * non-managed 82579
49967d9119bdSJack F Vogel 		 */
49977d9119bdSJack F Vogel 		if ((hw->mac.type == e1000_pch2lan) &&
49987d9119bdSJack F Vogel 		    !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
49997d9119bdSJack F Vogel 			e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
50008cfa0ad2SJack F Vogel 	}
50018cfa0ad2SJack F Vogel 	ret_val = e1000_acquire_swflag_ich8lan(hw);
5002daf9197cSJack F Vogel 	DEBUGOUT("Issuing a global reset to ich8lan\n");
50038cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST));
50044dab5c37SJack F Vogel 	/* cannot issue a flush here because it hangs the hardware */
50058cfa0ad2SJack F Vogel 	msec_delay(20);
50068cfa0ad2SJack F Vogel 
50076ab6bfe3SJack F Vogel 	/* Set Phy Config Counter to 50msec */
50086ab6bfe3SJack F Vogel 	if (hw->mac.type == e1000_pch2lan) {
50096ab6bfe3SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_FEXTNVM3);
50106ab6bfe3SJack F Vogel 		reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
50116ab6bfe3SJack F Vogel 		reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
50126ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_FEXTNVM3, reg);
50136ab6bfe3SJack F Vogel 	}
50146ab6bfe3SJack F Vogel 
50159d81738fSJack F Vogel 	if (!ret_val)
50164dab5c37SJack F Vogel 		E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
50179d81738fSJack F Vogel 
50187d9119bdSJack F Vogel 	if (ctrl & E1000_CTRL_PHY_RST) {
50199d81738fSJack F Vogel 		ret_val = hw->phy.ops.get_cfg_done(hw);
50204edd8523SJack F Vogel 		if (ret_val)
50216ab6bfe3SJack F Vogel 			return ret_val;
50224edd8523SJack F Vogel 
50237d9119bdSJack F Vogel 		ret_val = e1000_post_phy_reset_ich8lan(hw);
50244edd8523SJack F Vogel 		if (ret_val)
50256ab6bfe3SJack F Vogel 			return ret_val;
50267d9119bdSJack F Vogel 	}
50277d9119bdSJack F Vogel 
50286ab6bfe3SJack F Vogel 	/* For PCH, this write will make sure that any noise
50294edd8523SJack F Vogel 	 * will be detected as a CRC error and be dropped rather than show up
50304edd8523SJack F Vogel 	 * as a bad packet to the DMA engine.
50314edd8523SJack F Vogel 	 */
50324edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan)
50334edd8523SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565);
50348cfa0ad2SJack F Vogel 
50358cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
5036730d3130SJack F Vogel 	E1000_READ_REG(hw, E1000_ICR);
50378cfa0ad2SJack F Vogel 
50386ab6bfe3SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_KABGTXD);
50396ab6bfe3SJack F Vogel 	reg |= E1000_KABGTXD_BGSQLBIAS;
50406ab6bfe3SJack F Vogel 	E1000_WRITE_REG(hw, E1000_KABGTXD, reg);
50418cfa0ad2SJack F Vogel 
50426ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
50438cfa0ad2SJack F Vogel }
50448cfa0ad2SJack F Vogel 
50458cfa0ad2SJack F Vogel /**
50468cfa0ad2SJack F Vogel  *  e1000_init_hw_ich8lan - Initialize the hardware
50478cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
50488cfa0ad2SJack F Vogel  *
50498cfa0ad2SJack F Vogel  *  Prepares the hardware for transmit and receive by doing the following:
50508cfa0ad2SJack F Vogel  *   - initialize hardware bits
50518cfa0ad2SJack F Vogel  *   - initialize LED identification
50528cfa0ad2SJack F Vogel  *   - setup receive address registers
50538cfa0ad2SJack F Vogel  *   - setup flow control
50548cfa0ad2SJack F Vogel  *   - setup transmit descriptors
50558cfa0ad2SJack F Vogel  *   - clear statistics
50568cfa0ad2SJack F Vogel  **/
50578cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
50588cfa0ad2SJack F Vogel {
50598cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
50608cfa0ad2SJack F Vogel 	u32 ctrl_ext, txdctl, snoop;
50618cfa0ad2SJack F Vogel 	s32 ret_val;
50628cfa0ad2SJack F Vogel 	u16 i;
50638cfa0ad2SJack F Vogel 
50648cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_hw_ich8lan");
50658cfa0ad2SJack F Vogel 
50668cfa0ad2SJack F Vogel 	e1000_initialize_hw_bits_ich8lan(hw);
50678cfa0ad2SJack F Vogel 
50688cfa0ad2SJack F Vogel 	/* Initialize identification LED */
5069d035aa2dSJack F Vogel 	ret_val = mac->ops.id_led_init(hw);
50706ab6bfe3SJack F Vogel 	/* An error is not fatal and we should not stop init due to this */
5071d035aa2dSJack F Vogel 	if (ret_val)
5072d035aa2dSJack F Vogel 		DEBUGOUT("Error initializing identification LED\n");
50738cfa0ad2SJack F Vogel 
50748cfa0ad2SJack F Vogel 	/* Setup the receive address. */
50758cfa0ad2SJack F Vogel 	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
50768cfa0ad2SJack F Vogel 
50778cfa0ad2SJack F Vogel 	/* Zero out the Multicast HASH table */
50788cfa0ad2SJack F Vogel 	DEBUGOUT("Zeroing the MTA\n");
50798cfa0ad2SJack F Vogel 	for (i = 0; i < mac->mta_reg_count; i++)
50808cfa0ad2SJack F Vogel 		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
50818cfa0ad2SJack F Vogel 
50826ab6bfe3SJack F Vogel 	/* The 82578 Rx buffer will stall if wakeup is enabled in host and
50834dab5c37SJack F Vogel 	 * the ME.  Disable wakeup by clearing the host wakeup bit.
50849d81738fSJack F Vogel 	 * Reset the phy after disabling host wakeup to reset the Rx buffer.
50859d81738fSJack F Vogel 	 */
50869d81738fSJack F Vogel 	if (hw->phy.type == e1000_phy_82578) {
50874dab5c37SJack F Vogel 		hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, &i);
50884dab5c37SJack F Vogel 		i &= ~BM_WUC_HOST_WU_BIT;
50894dab5c37SJack F Vogel 		hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, i);
50909d81738fSJack F Vogel 		ret_val = e1000_phy_hw_reset_ich8lan(hw);
50919d81738fSJack F Vogel 		if (ret_val)
50929d81738fSJack F Vogel 			return ret_val;
50939d81738fSJack F Vogel 	}
50949d81738fSJack F Vogel 
50958cfa0ad2SJack F Vogel 	/* Setup link and flow control */
50968cfa0ad2SJack F Vogel 	ret_val = mac->ops.setup_link(hw);
50978cfa0ad2SJack F Vogel 
50988cfa0ad2SJack F Vogel 	/* Set the transmit descriptor write-back policy for both queues */
50998cfa0ad2SJack F Vogel 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
51007609433eSJack F Vogel 	txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) |
51017609433eSJack F Vogel 		  E1000_TXDCTL_FULL_TX_DESC_WB);
51027609433eSJack F Vogel 	txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) |
51037609433eSJack F Vogel 		  E1000_TXDCTL_MAX_TX_DESC_PREFETCH);
51048cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
51058cfa0ad2SJack F Vogel 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1));
51067609433eSJack F Vogel 	txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) |
51077609433eSJack F Vogel 		  E1000_TXDCTL_FULL_TX_DESC_WB);
51087609433eSJack F Vogel 	txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) |
51097609433eSJack F Vogel 		  E1000_TXDCTL_MAX_TX_DESC_PREFETCH);
51108cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl);
51118cfa0ad2SJack F Vogel 
51126ab6bfe3SJack F Vogel 	/* ICH8 has opposite polarity of no_snoop bits.
51138cfa0ad2SJack F Vogel 	 * By default, we should use snoop behavior.
51148cfa0ad2SJack F Vogel 	 */
51158cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
51168cfa0ad2SJack F Vogel 		snoop = PCIE_ICH8_SNOOP_ALL;
51178cfa0ad2SJack F Vogel 	else
51188cfa0ad2SJack F Vogel 		snoop = (u32) ~(PCIE_NO_SNOOP_ALL);
51198cfa0ad2SJack F Vogel 	e1000_set_pcie_no_snoop_generic(hw, snoop);
51208cfa0ad2SJack F Vogel 
51218cfa0ad2SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
51228cfa0ad2SJack F Vogel 	ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
51238cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
51248cfa0ad2SJack F Vogel 
51256ab6bfe3SJack F Vogel 	/* Clear all of the statistics registers (clear on read).  It is
51268cfa0ad2SJack F Vogel 	 * important that we do this after we have tried to establish link
51278cfa0ad2SJack F Vogel 	 * because the symbol error count will increment wildly if there
51288cfa0ad2SJack F Vogel 	 * is no link.
51298cfa0ad2SJack F Vogel 	 */
51308cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_ich8lan(hw);
51318cfa0ad2SJack F Vogel 
51328cfa0ad2SJack F Vogel 	return ret_val;
51338cfa0ad2SJack F Vogel }
51346ab6bfe3SJack F Vogel 
51358cfa0ad2SJack F Vogel /**
51368cfa0ad2SJack F Vogel  *  e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
51378cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
51388cfa0ad2SJack F Vogel  *
51398cfa0ad2SJack F Vogel  *  Sets/Clears required hardware bits necessary for correctly setting up the
51408cfa0ad2SJack F Vogel  *  hardware for transmit and receive.
51418cfa0ad2SJack F Vogel  **/
51428cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
51438cfa0ad2SJack F Vogel {
51448cfa0ad2SJack F Vogel 	u32 reg;
51458cfa0ad2SJack F Vogel 
51468cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_initialize_hw_bits_ich8lan");
51478cfa0ad2SJack F Vogel 
51488cfa0ad2SJack F Vogel 	/* Extended Device Control */
51498cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
51508cfa0ad2SJack F Vogel 	reg |= (1 << 22);
51519d81738fSJack F Vogel 	/* Enable PHY low-power state when MAC is at D3 w/o WoL */
51529d81738fSJack F Vogel 	if (hw->mac.type >= e1000_pchlan)
51539d81738fSJack F Vogel 		reg |= E1000_CTRL_EXT_PHYPDEN;
51548cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
51558cfa0ad2SJack F Vogel 
51568cfa0ad2SJack F Vogel 	/* Transmit Descriptor Control 0 */
51578cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
51588cfa0ad2SJack F Vogel 	reg |= (1 << 22);
51598cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
51608cfa0ad2SJack F Vogel 
51618cfa0ad2SJack F Vogel 	/* Transmit Descriptor Control 1 */
51628cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
51638cfa0ad2SJack F Vogel 	reg |= (1 << 22);
51648cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
51658cfa0ad2SJack F Vogel 
51668cfa0ad2SJack F Vogel 	/* Transmit Arbitration Control 0 */
51678cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TARC(0));
51688cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan)
51698cfa0ad2SJack F Vogel 		reg |= (1 << 28) | (1 << 29);
51708cfa0ad2SJack F Vogel 	reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
51718cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TARC(0), reg);
51728cfa0ad2SJack F Vogel 
51738cfa0ad2SJack F Vogel 	/* Transmit Arbitration Control 1 */
51748cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TARC(1));
51758cfa0ad2SJack F Vogel 	if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
51768cfa0ad2SJack F Vogel 		reg &= ~(1 << 28);
51778cfa0ad2SJack F Vogel 	else
51788cfa0ad2SJack F Vogel 		reg |= (1 << 28);
51798cfa0ad2SJack F Vogel 	reg |= (1 << 24) | (1 << 26) | (1 << 30);
51808cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TARC(1), reg);
51818cfa0ad2SJack F Vogel 
51828cfa0ad2SJack F Vogel 	/* Device Status */
51838cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan) {
51848cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_STATUS);
51858cc64f1eSJack F Vogel 		reg &= ~(1 << 31);
51868cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_STATUS, reg);
51878cfa0ad2SJack F Vogel 	}
51888cfa0ad2SJack F Vogel 
51896ab6bfe3SJack F Vogel 	/* work-around descriptor data corruption issue during nfs v2 udp
51908ec87fc5SJack F Vogel 	 * traffic, just disable the nfs filtering capability
51918ec87fc5SJack F Vogel 	 */
51928ec87fc5SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_RFCTL);
51938ec87fc5SJack F Vogel 	reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS);
51947609433eSJack F Vogel 
51956ab6bfe3SJack F Vogel 	/* Disable IPv6 extension header parsing because some malformed
51966ab6bfe3SJack F Vogel 	 * IPv6 headers can hang the Rx.
51976ab6bfe3SJack F Vogel 	 */
51986ab6bfe3SJack F Vogel 	if (hw->mac.type == e1000_ich8lan)
51996ab6bfe3SJack F Vogel 		reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS);
52008ec87fc5SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RFCTL, reg);
52018ec87fc5SJack F Vogel 
52026ab6bfe3SJack F Vogel 	/* Enable ECC on Lynxpoint */
5203*c80429ceSEric Joyner 	if ((hw->mac.type == e1000_pch_lpt) ||
5204*c80429ceSEric Joyner 	    (hw->mac.type == e1000_pch_spt)) {
52056ab6bfe3SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_PBECCSTS);
52066ab6bfe3SJack F Vogel 		reg |= E1000_PBECCSTS_ECC_ENABLE;
52076ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBECCSTS, reg);
52086ab6bfe3SJack F Vogel 
52096ab6bfe3SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_CTRL);
52106ab6bfe3SJack F Vogel 		reg |= E1000_CTRL_MEHE;
52116ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, reg);
52126ab6bfe3SJack F Vogel 	}
52136ab6bfe3SJack F Vogel 
52148cfa0ad2SJack F Vogel 	return;
52158cfa0ad2SJack F Vogel }
52168cfa0ad2SJack F Vogel 
52178cfa0ad2SJack F Vogel /**
52188cfa0ad2SJack F Vogel  *  e1000_setup_link_ich8lan - Setup flow control and link settings
52198cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
52208cfa0ad2SJack F Vogel  *
52218cfa0ad2SJack F Vogel  *  Determines which flow control settings to use, then configures flow
52228cfa0ad2SJack F Vogel  *  control.  Calls the appropriate media-specific link configuration
52238cfa0ad2SJack F Vogel  *  function.  Assuming the adapter has a valid link partner, a valid link
52248cfa0ad2SJack F Vogel  *  should be established.  Assumes the hardware has previously been reset
52258cfa0ad2SJack F Vogel  *  and the transmitter and receiver are not enabled.
52268cfa0ad2SJack F Vogel  **/
52278cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
52288cfa0ad2SJack F Vogel {
52296ab6bfe3SJack F Vogel 	s32 ret_val;
52308cfa0ad2SJack F Vogel 
52318cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_link_ich8lan");
52328cfa0ad2SJack F Vogel 
52338cfa0ad2SJack F Vogel 	if (hw->phy.ops.check_reset_block(hw))
52346ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
52358cfa0ad2SJack F Vogel 
52366ab6bfe3SJack F Vogel 	/* ICH parts do not have a word in the NVM to determine
52378cfa0ad2SJack F Vogel 	 * the default flow control setting, so we explicitly
52388cfa0ad2SJack F Vogel 	 * set it to full.
52398cfa0ad2SJack F Vogel 	 */
5240daf9197cSJack F Vogel 	if (hw->fc.requested_mode == e1000_fc_default)
5241daf9197cSJack F Vogel 		hw->fc.requested_mode = e1000_fc_full;
52428cfa0ad2SJack F Vogel 
52436ab6bfe3SJack F Vogel 	/* Save off the requested flow control mode for use later.  Depending
5244daf9197cSJack F Vogel 	 * on the link partner's capabilities, we may or may not use this mode.
5245daf9197cSJack F Vogel 	 */
5246daf9197cSJack F Vogel 	hw->fc.current_mode = hw->fc.requested_mode;
52478cfa0ad2SJack F Vogel 
5248daf9197cSJack F Vogel 	DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
5249daf9197cSJack F Vogel 		hw->fc.current_mode);
52508cfa0ad2SJack F Vogel 
52518cfa0ad2SJack F Vogel 	/* Continue to configure the copper link. */
52528cfa0ad2SJack F Vogel 	ret_val = hw->mac.ops.setup_physical_interface(hw);
52538cfa0ad2SJack F Vogel 	if (ret_val)
52546ab6bfe3SJack F Vogel 		return ret_val;
52558cfa0ad2SJack F Vogel 
52568cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
52579d81738fSJack F Vogel 	if ((hw->phy.type == e1000_phy_82578) ||
52587d9119bdSJack F Vogel 	    (hw->phy.type == e1000_phy_82579) ||
52596ab6bfe3SJack F Vogel 	    (hw->phy.type == e1000_phy_i217) ||
52609d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577)) {
52617d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FCRTV_PCH, hw->fc.refresh_time);
52627d9119bdSJack F Vogel 
52639d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw,
52649d81738fSJack F Vogel 					     PHY_REG(BM_PORT_CTRL_PAGE, 27),
52659d81738fSJack F Vogel 					     hw->fc.pause_time);
52669d81738fSJack F Vogel 		if (ret_val)
52676ab6bfe3SJack F Vogel 			return ret_val;
52689d81738fSJack F Vogel 	}
52698cfa0ad2SJack F Vogel 
52706ab6bfe3SJack F Vogel 	return e1000_set_fc_watermarks_generic(hw);
52718cfa0ad2SJack F Vogel }
52728cfa0ad2SJack F Vogel 
52738cfa0ad2SJack F Vogel /**
52748cfa0ad2SJack F Vogel  *  e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
52758cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
52768cfa0ad2SJack F Vogel  *
52778cfa0ad2SJack F Vogel  *  Configures the kumeran interface to the PHY to wait the appropriate time
52788cfa0ad2SJack F Vogel  *  when polling the PHY, then call the generic setup_copper_link to finish
52798cfa0ad2SJack F Vogel  *  configuring the copper link.
52808cfa0ad2SJack F Vogel  **/
52818cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
52828cfa0ad2SJack F Vogel {
52838cfa0ad2SJack F Vogel 	u32 ctrl;
52848cfa0ad2SJack F Vogel 	s32 ret_val;
52858cfa0ad2SJack F Vogel 	u16 reg_data;
52868cfa0ad2SJack F Vogel 
52878cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_copper_link_ich8lan");
52888cfa0ad2SJack F Vogel 
52898cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
52908cfa0ad2SJack F Vogel 	ctrl |= E1000_CTRL_SLU;
52918cfa0ad2SJack F Vogel 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
52928cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
52938cfa0ad2SJack F Vogel 
52946ab6bfe3SJack F Vogel 	/* Set the mac to wait the maximum time between each iteration
52958cfa0ad2SJack F Vogel 	 * and increase the max iterations when polling the phy;
52968cfa0ad2SJack F Vogel 	 * this fixes erroneous timeouts at 10Mbps.
52978cfa0ad2SJack F Vogel 	 */
52984edd8523SJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_TIMEOUTS,
52998cfa0ad2SJack F Vogel 					       0xFFFF);
53008cfa0ad2SJack F Vogel 	if (ret_val)
53016ab6bfe3SJack F Vogel 		return ret_val;
53029d81738fSJack F Vogel 	ret_val = e1000_read_kmrn_reg_generic(hw,
53039d81738fSJack F Vogel 					      E1000_KMRNCTRLSTA_INBAND_PARAM,
53048cfa0ad2SJack F Vogel 					      &reg_data);
53058cfa0ad2SJack F Vogel 	if (ret_val)
53066ab6bfe3SJack F Vogel 		return ret_val;
53078cfa0ad2SJack F Vogel 	reg_data |= 0x3F;
53089d81738fSJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
53099d81738fSJack F Vogel 					       E1000_KMRNCTRLSTA_INBAND_PARAM,
53108cfa0ad2SJack F Vogel 					       reg_data);
53118cfa0ad2SJack F Vogel 	if (ret_val)
53126ab6bfe3SJack F Vogel 		return ret_val;
53138cfa0ad2SJack F Vogel 
5314d035aa2dSJack F Vogel 	switch (hw->phy.type) {
5315d035aa2dSJack F Vogel 	case e1000_phy_igp_3:
53168cfa0ad2SJack F Vogel 		ret_val = e1000_copper_link_setup_igp(hw);
53178cfa0ad2SJack F Vogel 		if (ret_val)
53186ab6bfe3SJack F Vogel 			return ret_val;
5319d035aa2dSJack F Vogel 		break;
5320d035aa2dSJack F Vogel 	case e1000_phy_bm:
53219d81738fSJack F Vogel 	case e1000_phy_82578:
53228cfa0ad2SJack F Vogel 		ret_val = e1000_copper_link_setup_m88(hw);
53238cfa0ad2SJack F Vogel 		if (ret_val)
53246ab6bfe3SJack F Vogel 			return ret_val;
5325d035aa2dSJack F Vogel 		break;
53269d81738fSJack F Vogel 	case e1000_phy_82577:
53277d9119bdSJack F Vogel 	case e1000_phy_82579:
53289d81738fSJack F Vogel 		ret_val = e1000_copper_link_setup_82577(hw);
53299d81738fSJack F Vogel 		if (ret_val)
53306ab6bfe3SJack F Vogel 			return ret_val;
53319d81738fSJack F Vogel 		break;
5332d035aa2dSJack F Vogel 	case e1000_phy_ife:
53338cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL,
53348cfa0ad2SJack F Vogel 					       &reg_data);
53358cfa0ad2SJack F Vogel 		if (ret_val)
53366ab6bfe3SJack F Vogel 			return ret_val;
53378cfa0ad2SJack F Vogel 
53388cfa0ad2SJack F Vogel 		reg_data &= ~IFE_PMC_AUTO_MDIX;
53398cfa0ad2SJack F Vogel 
53408cfa0ad2SJack F Vogel 		switch (hw->phy.mdix) {
53418cfa0ad2SJack F Vogel 		case 1:
53428cfa0ad2SJack F Vogel 			reg_data &= ~IFE_PMC_FORCE_MDIX;
53438cfa0ad2SJack F Vogel 			break;
53448cfa0ad2SJack F Vogel 		case 2:
53458cfa0ad2SJack F Vogel 			reg_data |= IFE_PMC_FORCE_MDIX;
53468cfa0ad2SJack F Vogel 			break;
53478cfa0ad2SJack F Vogel 		case 0:
53488cfa0ad2SJack F Vogel 		default:
53498cfa0ad2SJack F Vogel 			reg_data |= IFE_PMC_AUTO_MDIX;
53508cfa0ad2SJack F Vogel 			break;
53518cfa0ad2SJack F Vogel 		}
53528cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL,
53538cfa0ad2SJack F Vogel 						reg_data);
53548cfa0ad2SJack F Vogel 		if (ret_val)
53556ab6bfe3SJack F Vogel 			return ret_val;
5356d035aa2dSJack F Vogel 		break;
5357d035aa2dSJack F Vogel 	default:
5358d035aa2dSJack F Vogel 		break;
53598cfa0ad2SJack F Vogel 	}
53608cfa0ad2SJack F Vogel 
53616ab6bfe3SJack F Vogel 	return e1000_setup_copper_link_generic(hw);
53626ab6bfe3SJack F Vogel }
53636ab6bfe3SJack F Vogel 
53646ab6bfe3SJack F Vogel /**
53656ab6bfe3SJack F Vogel  *  e1000_setup_copper_link_pch_lpt - Configure MAC/PHY interface
53666ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
53676ab6bfe3SJack F Vogel  *
53686ab6bfe3SJack F Vogel  *  Calls the PHY specific link setup function and then calls the
53696ab6bfe3SJack F Vogel  *  generic setup_copper_link to finish configuring the link for
53706ab6bfe3SJack F Vogel  *  Lynxpoint PCH devices
53716ab6bfe3SJack F Vogel  **/
53726ab6bfe3SJack F Vogel static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw)
53736ab6bfe3SJack F Vogel {
53746ab6bfe3SJack F Vogel 	u32 ctrl;
53756ab6bfe3SJack F Vogel 	s32 ret_val;
53766ab6bfe3SJack F Vogel 
53776ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_setup_copper_link_pch_lpt");
53786ab6bfe3SJack F Vogel 
53796ab6bfe3SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
53806ab6bfe3SJack F Vogel 	ctrl |= E1000_CTRL_SLU;
53816ab6bfe3SJack F Vogel 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
53826ab6bfe3SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
53836ab6bfe3SJack F Vogel 
53846ab6bfe3SJack F Vogel 	ret_val = e1000_copper_link_setup_82577(hw);
53856ab6bfe3SJack F Vogel 	if (ret_val)
53868cfa0ad2SJack F Vogel 		return ret_val;
53876ab6bfe3SJack F Vogel 
53886ab6bfe3SJack F Vogel 	return e1000_setup_copper_link_generic(hw);
53898cfa0ad2SJack F Vogel }
53908cfa0ad2SJack F Vogel 
53918cfa0ad2SJack F Vogel /**
53928cfa0ad2SJack F Vogel  *  e1000_get_link_up_info_ich8lan - Get current link speed and duplex
53938cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
53948cfa0ad2SJack F Vogel  *  @speed: pointer to store current link speed
53958cfa0ad2SJack F Vogel  *  @duplex: pointer to store the current link duplex
53968cfa0ad2SJack F Vogel  *
53978cfa0ad2SJack F Vogel  *  Calls the generic get_speed_and_duplex to retrieve the current link
53988cfa0ad2SJack F Vogel  *  information and then calls the Kumeran lock loss workaround for links at
53998cfa0ad2SJack F Vogel  *  gigabit speeds.
54008cfa0ad2SJack F Vogel  **/
54018cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
54028cfa0ad2SJack F Vogel 					  u16 *duplex)
54038cfa0ad2SJack F Vogel {
54048cfa0ad2SJack F Vogel 	s32 ret_val;
54058cfa0ad2SJack F Vogel 
54068cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_link_up_info_ich8lan");
54078cfa0ad2SJack F Vogel 
54088cfa0ad2SJack F Vogel 	ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
54098cfa0ad2SJack F Vogel 	if (ret_val)
54106ab6bfe3SJack F Vogel 		return ret_val;
54118cfa0ad2SJack F Vogel 
54128cfa0ad2SJack F Vogel 	if ((hw->mac.type == e1000_ich8lan) &&
54138cfa0ad2SJack F Vogel 	    (hw->phy.type == e1000_phy_igp_3) &&
54148cfa0ad2SJack F Vogel 	    (*speed == SPEED_1000)) {
54158cfa0ad2SJack F Vogel 		ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
54168cfa0ad2SJack F Vogel 	}
54178cfa0ad2SJack F Vogel 
54188cfa0ad2SJack F Vogel 	return ret_val;
54198cfa0ad2SJack F Vogel }
54208cfa0ad2SJack F Vogel 
54218cfa0ad2SJack F Vogel /**
54228cfa0ad2SJack F Vogel  *  e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
54238cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
54248cfa0ad2SJack F Vogel  *
54258cfa0ad2SJack F Vogel  *  Work-around for 82566 Kumeran PCS lock loss:
54268cfa0ad2SJack F Vogel  *  On link status change (i.e. PCI reset, speed change) and link is up and
54278cfa0ad2SJack F Vogel  *  speed is gigabit-
54288cfa0ad2SJack F Vogel  *    0) if workaround is optionally disabled do nothing
54298cfa0ad2SJack F Vogel  *    1) wait 1ms for Kumeran link to come up
54308cfa0ad2SJack F Vogel  *    2) check Kumeran Diagnostic register PCS lock loss bit
54318cfa0ad2SJack F Vogel  *    3) if not set the link is locked (all is good), otherwise...
54328cfa0ad2SJack F Vogel  *    4) reset the PHY
54338cfa0ad2SJack F Vogel  *    5) repeat up to 10 times
54348cfa0ad2SJack F Vogel  *  Note: this is only called for IGP3 copper when speed is 1gb.
54358cfa0ad2SJack F Vogel  **/
54368cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
54378cfa0ad2SJack F Vogel {
5438daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
54398cfa0ad2SJack F Vogel 	u32 phy_ctrl;
54406ab6bfe3SJack F Vogel 	s32 ret_val;
54418cfa0ad2SJack F Vogel 	u16 i, data;
54428cfa0ad2SJack F Vogel 	bool link;
54438cfa0ad2SJack F Vogel 
54448cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan");
54458cfa0ad2SJack F Vogel 
5446730d3130SJack F Vogel 	if (!dev_spec->kmrn_lock_loss_workaround_enabled)
54476ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
54488cfa0ad2SJack F Vogel 
54496ab6bfe3SJack F Vogel 	/* Make sure link is up before proceeding.  If not just return.
54508cfa0ad2SJack F Vogel 	 * Attempting this while link is negotiating fouled up link
54518cfa0ad2SJack F Vogel 	 * stability
54528cfa0ad2SJack F Vogel 	 */
54538cfa0ad2SJack F Vogel 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
54546ab6bfe3SJack F Vogel 	if (!link)
54556ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
54568cfa0ad2SJack F Vogel 
54578cfa0ad2SJack F Vogel 	for (i = 0; i < 10; i++) {
54588cfa0ad2SJack F Vogel 		/* read once to clear */
54598cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
54608cfa0ad2SJack F Vogel 		if (ret_val)
54616ab6bfe3SJack F Vogel 			return ret_val;
54628cfa0ad2SJack F Vogel 		/* and again to get new status */
54638cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
54648cfa0ad2SJack F Vogel 		if (ret_val)
54656ab6bfe3SJack F Vogel 			return ret_val;
54668cfa0ad2SJack F Vogel 
54678cfa0ad2SJack F Vogel 		/* check for PCS lock */
54686ab6bfe3SJack F Vogel 		if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS))
54696ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
54708cfa0ad2SJack F Vogel 
54718cfa0ad2SJack F Vogel 		/* Issue PHY reset */
54728cfa0ad2SJack F Vogel 		hw->phy.ops.reset(hw);
54738cfa0ad2SJack F Vogel 		msec_delay_irq(5);
54748cfa0ad2SJack F Vogel 	}
54758cfa0ad2SJack F Vogel 	/* Disable GigE link negotiation */
54768cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
54778cfa0ad2SJack F Vogel 	phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
54788cfa0ad2SJack F Vogel 		     E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
54798cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
54808cfa0ad2SJack F Vogel 
54816ab6bfe3SJack F Vogel 	/* Call gig speed drop workaround on Gig disable before accessing
54828cfa0ad2SJack F Vogel 	 * any PHY registers
54838cfa0ad2SJack F Vogel 	 */
54848cfa0ad2SJack F Vogel 	e1000_gig_downshift_workaround_ich8lan(hw);
54858cfa0ad2SJack F Vogel 
54868cfa0ad2SJack F Vogel 	/* unable to acquire PCS lock */
54876ab6bfe3SJack F Vogel 	return -E1000_ERR_PHY;
54888cfa0ad2SJack F Vogel }
54898cfa0ad2SJack F Vogel 
54908cfa0ad2SJack F Vogel /**
54918cfa0ad2SJack F Vogel  *  e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
54928cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
54938cfa0ad2SJack F Vogel  *  @state: boolean value used to set the current Kumeran workaround state
54948cfa0ad2SJack F Vogel  *
54958cfa0ad2SJack F Vogel  *  If ICH8, set the current Kumeran workaround state (enabled - TRUE
54968cfa0ad2SJack F Vogel  *  /disabled - FALSE).
54978cfa0ad2SJack F Vogel  **/
54988cfa0ad2SJack F Vogel void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
54998cfa0ad2SJack F Vogel 						 bool state)
55008cfa0ad2SJack F Vogel {
5501daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
55028cfa0ad2SJack F Vogel 
55038cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan");
55048cfa0ad2SJack F Vogel 
55058cfa0ad2SJack F Vogel 	if (hw->mac.type != e1000_ich8lan) {
55068cfa0ad2SJack F Vogel 		DEBUGOUT("Workaround applies to ICH8 only.\n");
5507daf9197cSJack F Vogel 		return;
55088cfa0ad2SJack F Vogel 	}
55098cfa0ad2SJack F Vogel 
55108cfa0ad2SJack F Vogel 	dev_spec->kmrn_lock_loss_workaround_enabled = state;
55118cfa0ad2SJack F Vogel 
55128cfa0ad2SJack F Vogel 	return;
55138cfa0ad2SJack F Vogel }
55148cfa0ad2SJack F Vogel 
55158cfa0ad2SJack F Vogel /**
55168cfa0ad2SJack F Vogel  *  e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
55178cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
55188cfa0ad2SJack F Vogel  *
55198cfa0ad2SJack F Vogel  *  Workaround for 82566 power-down on D3 entry:
55208cfa0ad2SJack F Vogel  *    1) disable gigabit link
55218cfa0ad2SJack F Vogel  *    2) write VR power-down enable
55228cfa0ad2SJack F Vogel  *    3) read it back
55238cfa0ad2SJack F Vogel  *  Continue if successful, else issue LCD reset and repeat
55248cfa0ad2SJack F Vogel  **/
55258cfa0ad2SJack F Vogel void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
55268cfa0ad2SJack F Vogel {
55278cfa0ad2SJack F Vogel 	u32 reg;
55288cfa0ad2SJack F Vogel 	u16 data;
55298cfa0ad2SJack F Vogel 	u8  retry = 0;
55308cfa0ad2SJack F Vogel 
55318cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan");
55328cfa0ad2SJack F Vogel 
55338cfa0ad2SJack F Vogel 	if (hw->phy.type != e1000_phy_igp_3)
55346ab6bfe3SJack F Vogel 		return;
55358cfa0ad2SJack F Vogel 
55368cfa0ad2SJack F Vogel 	/* Try the workaround twice (if needed) */
55378cfa0ad2SJack F Vogel 	do {
55388cfa0ad2SJack F Vogel 		/* Disable link */
55398cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
55408cfa0ad2SJack F Vogel 		reg |= (E1000_PHY_CTRL_GBE_DISABLE |
55418cfa0ad2SJack F Vogel 			E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
55428cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg);
55438cfa0ad2SJack F Vogel 
55446ab6bfe3SJack F Vogel 		/* Call gig speed drop workaround on Gig disable before
55458cfa0ad2SJack F Vogel 		 * accessing any PHY registers
55468cfa0ad2SJack F Vogel 		 */
55478cfa0ad2SJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
55488cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
55498cfa0ad2SJack F Vogel 
55508cfa0ad2SJack F Vogel 		/* Write VR power-down enable */
55518cfa0ad2SJack F Vogel 		hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
55528cfa0ad2SJack F Vogel 		data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
5553daf9197cSJack F Vogel 		hw->phy.ops.write_reg(hw, IGP3_VR_CTRL,
55548cfa0ad2SJack F Vogel 				      data | IGP3_VR_CTRL_MODE_SHUTDOWN);
55558cfa0ad2SJack F Vogel 
55568cfa0ad2SJack F Vogel 		/* Read it back and test */
55578cfa0ad2SJack F Vogel 		hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
55588cfa0ad2SJack F Vogel 		data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
55598cfa0ad2SJack F Vogel 		if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
55608cfa0ad2SJack F Vogel 			break;
55618cfa0ad2SJack F Vogel 
55628cfa0ad2SJack F Vogel 		/* Issue PHY reset and repeat at most one more time */
55638cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_CTRL);
55648cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST);
55658cfa0ad2SJack F Vogel 		retry++;
55668cfa0ad2SJack F Vogel 	} while (retry);
55678cfa0ad2SJack F Vogel }
55688cfa0ad2SJack F Vogel 
55698cfa0ad2SJack F Vogel /**
55708cfa0ad2SJack F Vogel  *  e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working
55718cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
55728cfa0ad2SJack F Vogel  *
55738cfa0ad2SJack F Vogel  *  Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
55748cfa0ad2SJack F Vogel  *  LPLU, Gig disable, MDIC PHY reset):
55758cfa0ad2SJack F Vogel  *    1) Set Kumeran Near-end loopback
55768cfa0ad2SJack F Vogel  *    2) Clear Kumeran Near-end loopback
55774dab5c37SJack F Vogel  *  Should only be called for ICH8[m] devices with any 1G Phy.
55788cfa0ad2SJack F Vogel  **/
55798cfa0ad2SJack F Vogel void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
55808cfa0ad2SJack F Vogel {
55816ab6bfe3SJack F Vogel 	s32 ret_val;
55828cfa0ad2SJack F Vogel 	u16 reg_data;
55838cfa0ad2SJack F Vogel 
55848cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan");
55858cfa0ad2SJack F Vogel 
55868cfa0ad2SJack F Vogel 	if ((hw->mac.type != e1000_ich8lan) ||
55874dab5c37SJack F Vogel 	    (hw->phy.type == e1000_phy_ife))
55886ab6bfe3SJack F Vogel 		return;
55898cfa0ad2SJack F Vogel 
55908cfa0ad2SJack F Vogel 	ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
55918cfa0ad2SJack F Vogel 					      &reg_data);
55928cfa0ad2SJack F Vogel 	if (ret_val)
55936ab6bfe3SJack F Vogel 		return;
55948cfa0ad2SJack F Vogel 	reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
55958cfa0ad2SJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
55968cfa0ad2SJack F Vogel 					       E1000_KMRNCTRLSTA_DIAG_OFFSET,
55978cfa0ad2SJack F Vogel 					       reg_data);
55988cfa0ad2SJack F Vogel 	if (ret_val)
55998cfa0ad2SJack F Vogel 		return;
56006ab6bfe3SJack F Vogel 	reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
56016ab6bfe3SJack F Vogel 	e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
56026ab6bfe3SJack F Vogel 				     reg_data);
56038cfa0ad2SJack F Vogel }
56048cfa0ad2SJack F Vogel 
56058cfa0ad2SJack F Vogel /**
56064dab5c37SJack F Vogel  *  e1000_suspend_workarounds_ich8lan - workarounds needed during S0->Sx
56078cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
56088cfa0ad2SJack F Vogel  *
56098cfa0ad2SJack F Vogel  *  During S0 to Sx transition, it is possible the link remains at gig
56108cfa0ad2SJack F Vogel  *  instead of negotiating to a lower speed.  Before going to Sx, set
56114dab5c37SJack F Vogel  *  'Gig Disable' to force link speed negotiation to a lower speed based on
56124dab5c37SJack F Vogel  *  the LPLU setting in the NVM or custom setting.  For PCH and newer parts,
56134dab5c37SJack F Vogel  *  the OEM bits PHY register (LED, GbE disable and LPLU configurations) also
56144dab5c37SJack F Vogel  *  needs to be written.
56156ab6bfe3SJack F Vogel  *  Parts that support (and are linked to a partner which support) EEE in
56166ab6bfe3SJack F Vogel  *  100Mbps should disable LPLU since 100Mbps w/ EEE requires less power
56176ab6bfe3SJack F Vogel  *  than 10Mbps w/o EEE.
56188cfa0ad2SJack F Vogel  **/
56194dab5c37SJack F Vogel void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
56208cfa0ad2SJack F Vogel {
56216ab6bfe3SJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
56228cfa0ad2SJack F Vogel 	u32 phy_ctrl;
56237d9119bdSJack F Vogel 	s32 ret_val;
56248cfa0ad2SJack F Vogel 
56254dab5c37SJack F Vogel 	DEBUGFUNC("e1000_suspend_workarounds_ich8lan");
56267d9119bdSJack F Vogel 
56278cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
56284dab5c37SJack F Vogel 	phy_ctrl |= E1000_PHY_CTRL_GBE_DISABLE;
56296ab6bfe3SJack F Vogel 
56306ab6bfe3SJack F Vogel 	if (hw->phy.type == e1000_phy_i217) {
56316ab6bfe3SJack F Vogel 		u16 phy_reg, device_id = hw->device_id;
56326ab6bfe3SJack F Vogel 
56336ab6bfe3SJack F Vogel 		if ((device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
56348cc64f1eSJack F Vogel 		    (device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) ||
56358cc64f1eSJack F Vogel 		    (device_id == E1000_DEV_ID_PCH_I218_LM3) ||
5636*c80429ceSEric Joyner 		    (device_id == E1000_DEV_ID_PCH_I218_V3) ||
5637*c80429ceSEric Joyner 		    (hw->mac.type == e1000_pch_spt)) {
56386ab6bfe3SJack F Vogel 			u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6);
56396ab6bfe3SJack F Vogel 
56406ab6bfe3SJack F Vogel 			E1000_WRITE_REG(hw, E1000_FEXTNVM6,
56416ab6bfe3SJack F Vogel 					fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK);
56426ab6bfe3SJack F Vogel 		}
56436ab6bfe3SJack F Vogel 
56446ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
56456ab6bfe3SJack F Vogel 		if (ret_val)
56466ab6bfe3SJack F Vogel 			goto out;
56476ab6bfe3SJack F Vogel 
56486ab6bfe3SJack F Vogel 		if (!dev_spec->eee_disable) {
56496ab6bfe3SJack F Vogel 			u16 eee_advert;
56506ab6bfe3SJack F Vogel 
56516ab6bfe3SJack F Vogel 			ret_val =
56526ab6bfe3SJack F Vogel 			    e1000_read_emi_reg_locked(hw,
56536ab6bfe3SJack F Vogel 						      I217_EEE_ADVERTISEMENT,
56546ab6bfe3SJack F Vogel 						      &eee_advert);
56556ab6bfe3SJack F Vogel 			if (ret_val)
56566ab6bfe3SJack F Vogel 				goto release;
56576ab6bfe3SJack F Vogel 
56586ab6bfe3SJack F Vogel 			/* Disable LPLU if both link partners support 100BaseT
56596ab6bfe3SJack F Vogel 			 * EEE and 100Full is advertised on both ends of the
56607609433eSJack F Vogel 			 * link, and enable Auto Enable LPI since there will
56617609433eSJack F Vogel 			 * be no driver to enable LPI while in Sx.
56626ab6bfe3SJack F Vogel 			 */
56636ab6bfe3SJack F Vogel 			if ((eee_advert & I82579_EEE_100_SUPPORTED) &&
56646ab6bfe3SJack F Vogel 			    (dev_spec->eee_lp_ability &
56656ab6bfe3SJack F Vogel 			     I82579_EEE_100_SUPPORTED) &&
56667609433eSJack F Vogel 			    (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)) {
56676ab6bfe3SJack F Vogel 				phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU |
56686ab6bfe3SJack F Vogel 					      E1000_PHY_CTRL_NOND0A_LPLU);
56697609433eSJack F Vogel 
56707609433eSJack F Vogel 				/* Set Auto Enable LPI after link up */
56717609433eSJack F Vogel 				hw->phy.ops.read_reg_locked(hw,
56727609433eSJack F Vogel 							    I217_LPI_GPIO_CTRL,
56737609433eSJack F Vogel 							    &phy_reg);
56747609433eSJack F Vogel 				phy_reg |= I217_LPI_GPIO_CTRL_AUTO_EN_LPI;
56757609433eSJack F Vogel 				hw->phy.ops.write_reg_locked(hw,
56767609433eSJack F Vogel 							     I217_LPI_GPIO_CTRL,
56777609433eSJack F Vogel 							     phy_reg);
56787609433eSJack F Vogel 			}
56796ab6bfe3SJack F Vogel 		}
56806ab6bfe3SJack F Vogel 
56816ab6bfe3SJack F Vogel 		/* For i217 Intel Rapid Start Technology support,
56826ab6bfe3SJack F Vogel 		 * when the system is going into Sx and no manageability engine
56836ab6bfe3SJack F Vogel 		 * is present, the driver must configure proxy to reset only on
56846ab6bfe3SJack F Vogel 		 * power good.  LPI (Low Power Idle) state must also reset only
56856ab6bfe3SJack F Vogel 		 * on power good, as well as the MTA (Multicast table array).
56866ab6bfe3SJack F Vogel 		 * The SMBus release must also be disabled on LCD reset.
56876ab6bfe3SJack F Vogel 		 */
56886ab6bfe3SJack F Vogel 		if (!(E1000_READ_REG(hw, E1000_FWSM) &
56896ab6bfe3SJack F Vogel 		      E1000_ICH_FWSM_FW_VALID)) {
56906ab6bfe3SJack F Vogel 			/* Enable proxy to reset only on power good. */
56916ab6bfe3SJack F Vogel 			hw->phy.ops.read_reg_locked(hw, I217_PROXY_CTRL,
56926ab6bfe3SJack F Vogel 						    &phy_reg);
56936ab6bfe3SJack F Vogel 			phy_reg |= I217_PROXY_CTRL_AUTO_DISABLE;
56946ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_PROXY_CTRL,
56956ab6bfe3SJack F Vogel 						     phy_reg);
56966ab6bfe3SJack F Vogel 
56976ab6bfe3SJack F Vogel 			/* Set bit enable LPI (EEE) to reset only on
56986ab6bfe3SJack F Vogel 			 * power good.
56996ab6bfe3SJack F Vogel 			*/
57006ab6bfe3SJack F Vogel 			hw->phy.ops.read_reg_locked(hw, I217_SxCTRL, &phy_reg);
57016ab6bfe3SJack F Vogel 			phy_reg |= I217_SxCTRL_ENABLE_LPI_RESET;
57026ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_SxCTRL, phy_reg);
57036ab6bfe3SJack F Vogel 
57046ab6bfe3SJack F Vogel 			/* Disable the SMB release on LCD reset. */
57056ab6bfe3SJack F Vogel 			hw->phy.ops.read_reg_locked(hw, I217_MEMPWR, &phy_reg);
57066ab6bfe3SJack F Vogel 			phy_reg &= ~I217_MEMPWR_DISABLE_SMB_RELEASE;
57076ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_MEMPWR, phy_reg);
57086ab6bfe3SJack F Vogel 		}
57096ab6bfe3SJack F Vogel 
57106ab6bfe3SJack F Vogel 		/* Enable MTA to reset for Intel Rapid Start Technology
57116ab6bfe3SJack F Vogel 		 * Support
57126ab6bfe3SJack F Vogel 		 */
57136ab6bfe3SJack F Vogel 		hw->phy.ops.read_reg_locked(hw, I217_CGFREG, &phy_reg);
57146ab6bfe3SJack F Vogel 		phy_reg |= I217_CGFREG_ENABLE_MTA_RESET;
57156ab6bfe3SJack F Vogel 		hw->phy.ops.write_reg_locked(hw, I217_CGFREG, phy_reg);
57166ab6bfe3SJack F Vogel 
57176ab6bfe3SJack F Vogel release:
57186ab6bfe3SJack F Vogel 		hw->phy.ops.release(hw);
57196ab6bfe3SJack F Vogel 	}
57206ab6bfe3SJack F Vogel out:
57218cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
57226ab6bfe3SJack F Vogel 
57234dab5c37SJack F Vogel 	if (hw->mac.type == e1000_ich8lan)
57244dab5c37SJack F Vogel 		e1000_gig_downshift_workaround_ich8lan(hw);
57259d81738fSJack F Vogel 
57267d9119bdSJack F Vogel 	if (hw->mac.type >= e1000_pchlan) {
57277d9119bdSJack F Vogel 		e1000_oem_bits_config_ich8lan(hw, FALSE);
57286ab6bfe3SJack F Vogel 
57296ab6bfe3SJack F Vogel 		/* Reset PHY to activate OEM bits on 82577/8 */
57306ab6bfe3SJack F Vogel 		if (hw->mac.type == e1000_pchlan)
57316ab6bfe3SJack F Vogel 			e1000_phy_hw_reset_generic(hw);
57326ab6bfe3SJack F Vogel 
57337d9119bdSJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
57347d9119bdSJack F Vogel 		if (ret_val)
57357d9119bdSJack F Vogel 			return;
57367d9119bdSJack F Vogel 		e1000_write_smbus_addr(hw);
57377d9119bdSJack F Vogel 		hw->phy.ops.release(hw);
57388cfa0ad2SJack F Vogel 	}
57398cfa0ad2SJack F Vogel 
57408cfa0ad2SJack F Vogel 	return;
57418cfa0ad2SJack F Vogel }
57428cfa0ad2SJack F Vogel 
57438cfa0ad2SJack F Vogel /**
57444dab5c37SJack F Vogel  *  e1000_resume_workarounds_pchlan - workarounds needed during Sx->S0
57454dab5c37SJack F Vogel  *  @hw: pointer to the HW structure
57464dab5c37SJack F Vogel  *
57474dab5c37SJack F Vogel  *  During Sx to S0 transitions on non-managed devices or managed devices
57484dab5c37SJack F Vogel  *  on which PHY resets are not blocked, if the PHY registers cannot be
57494dab5c37SJack F Vogel  *  accessed properly by the s/w toggle the LANPHYPC value to power cycle
57504dab5c37SJack F Vogel  *  the PHY.
57516ab6bfe3SJack F Vogel  *  On i217, setup Intel Rapid Start Technology.
57524dab5c37SJack F Vogel  **/
5753*c80429ceSEric Joyner u32 e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
57544dab5c37SJack F Vogel {
57554dab5c37SJack F Vogel 	s32 ret_val;
57564dab5c37SJack F Vogel 
57574dab5c37SJack F Vogel 	DEBUGFUNC("e1000_resume_workarounds_pchlan");
57586ab6bfe3SJack F Vogel 	if (hw->mac.type < e1000_pch2lan)
5759*c80429ceSEric Joyner 		return E1000_SUCCESS;
57604dab5c37SJack F Vogel 
57616ab6bfe3SJack F Vogel 	ret_val = e1000_init_phy_workarounds_pchlan(hw);
57624dab5c37SJack F Vogel 	if (ret_val) {
57636ab6bfe3SJack F Vogel 		DEBUGOUT1("Failed to init PHY flow ret_val=%d\n", ret_val);
5764*c80429ceSEric Joyner 		return ret_val;
57654dab5c37SJack F Vogel 	}
57664dab5c37SJack F Vogel 
57676ab6bfe3SJack F Vogel 	/* For i217 Intel Rapid Start Technology support when the system
57686ab6bfe3SJack F Vogel 	 * is transitioning from Sx and no manageability engine is present
57696ab6bfe3SJack F Vogel 	 * configure SMBus to restore on reset, disable proxy, and enable
57706ab6bfe3SJack F Vogel 	 * the reset on MTA (Multicast table array).
57716ab6bfe3SJack F Vogel 	 */
57726ab6bfe3SJack F Vogel 	if (hw->phy.type == e1000_phy_i217) {
57736ab6bfe3SJack F Vogel 		u16 phy_reg;
57744dab5c37SJack F Vogel 
57756ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
57766ab6bfe3SJack F Vogel 		if (ret_val) {
57776ab6bfe3SJack F Vogel 			DEBUGOUT("Failed to setup iRST\n");
5778*c80429ceSEric Joyner 			return ret_val;
57796ab6bfe3SJack F Vogel 		}
57804dab5c37SJack F Vogel 
57817609433eSJack F Vogel 		/* Clear Auto Enable LPI after link up */
57827609433eSJack F Vogel 		hw->phy.ops.read_reg_locked(hw, I217_LPI_GPIO_CTRL, &phy_reg);
57837609433eSJack F Vogel 		phy_reg &= ~I217_LPI_GPIO_CTRL_AUTO_EN_LPI;
57847609433eSJack F Vogel 		hw->phy.ops.write_reg_locked(hw, I217_LPI_GPIO_CTRL, phy_reg);
57857609433eSJack F Vogel 
57866ab6bfe3SJack F Vogel 		if (!(E1000_READ_REG(hw, E1000_FWSM) &
57876ab6bfe3SJack F Vogel 		    E1000_ICH_FWSM_FW_VALID)) {
57886ab6bfe3SJack F Vogel 			/* Restore clear on SMB if no manageability engine
57896ab6bfe3SJack F Vogel 			 * is present
57906ab6bfe3SJack F Vogel 			 */
57916ab6bfe3SJack F Vogel 			ret_val = hw->phy.ops.read_reg_locked(hw, I217_MEMPWR,
57926ab6bfe3SJack F Vogel 							      &phy_reg);
57936ab6bfe3SJack F Vogel 			if (ret_val)
57946ab6bfe3SJack F Vogel 				goto release;
57956ab6bfe3SJack F Vogel 			phy_reg |= I217_MEMPWR_DISABLE_SMB_RELEASE;
57966ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_MEMPWR, phy_reg);
57976ab6bfe3SJack F Vogel 
57986ab6bfe3SJack F Vogel 			/* Disable Proxy */
57996ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_PROXY_CTRL, 0);
58006ab6bfe3SJack F Vogel 		}
58016ab6bfe3SJack F Vogel 		/* Enable reset on MTA */
58026ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.read_reg_locked(hw, I217_CGFREG,
58036ab6bfe3SJack F Vogel 						      &phy_reg);
58046ab6bfe3SJack F Vogel 		if (ret_val)
58056ab6bfe3SJack F Vogel 			goto release;
58066ab6bfe3SJack F Vogel 		phy_reg &= ~I217_CGFREG_ENABLE_MTA_RESET;
58076ab6bfe3SJack F Vogel 		hw->phy.ops.write_reg_locked(hw, I217_CGFREG, phy_reg);
58084dab5c37SJack F Vogel release:
58096ab6bfe3SJack F Vogel 		if (ret_val)
58106ab6bfe3SJack F Vogel 			DEBUGOUT1("Error %d in resume workarounds\n", ret_val);
58114dab5c37SJack F Vogel 		hw->phy.ops.release(hw);
5812*c80429ceSEric Joyner 		return ret_val;
58136ab6bfe3SJack F Vogel 	}
5814*c80429ceSEric Joyner 	return E1000_SUCCESS;
58154dab5c37SJack F Vogel }
58164dab5c37SJack F Vogel 
58174dab5c37SJack F Vogel /**
58188cfa0ad2SJack F Vogel  *  e1000_cleanup_led_ich8lan - Restore the default LED operation
58198cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
58208cfa0ad2SJack F Vogel  *
58218cfa0ad2SJack F Vogel  *  Return the LED back to the default configuration.
58228cfa0ad2SJack F Vogel  **/
58238cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
58248cfa0ad2SJack F Vogel {
58258cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_cleanup_led_ich8lan");
58268cfa0ad2SJack F Vogel 
58278cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
5828a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
58298cfa0ad2SJack F Vogel 					     0);
58308cfa0ad2SJack F Vogel 
5831a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
5832a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
58338cfa0ad2SJack F Vogel }
58348cfa0ad2SJack F Vogel 
58358cfa0ad2SJack F Vogel /**
58368cfa0ad2SJack F Vogel  *  e1000_led_on_ich8lan - Turn LEDs on
58378cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
58388cfa0ad2SJack F Vogel  *
58398cfa0ad2SJack F Vogel  *  Turn on the LEDs.
58408cfa0ad2SJack F Vogel  **/
58418cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw)
58428cfa0ad2SJack F Vogel {
58438cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_led_on_ich8lan");
58448cfa0ad2SJack F Vogel 
58458cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
5846a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
58478cfa0ad2SJack F Vogel 				(IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
58488cfa0ad2SJack F Vogel 
5849a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
5850a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
58518cfa0ad2SJack F Vogel }
58528cfa0ad2SJack F Vogel 
58538cfa0ad2SJack F Vogel /**
58548cfa0ad2SJack F Vogel  *  e1000_led_off_ich8lan - Turn LEDs off
58558cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
58568cfa0ad2SJack F Vogel  *
58578cfa0ad2SJack F Vogel  *  Turn off the LEDs.
58588cfa0ad2SJack F Vogel  **/
58598cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
58608cfa0ad2SJack F Vogel {
58618cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_led_off_ich8lan");
58628cfa0ad2SJack F Vogel 
58638cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
5864a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
58658cfa0ad2SJack F Vogel 			       (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
58668cfa0ad2SJack F Vogel 
5867a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
5868a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
58698cfa0ad2SJack F Vogel }
58708cfa0ad2SJack F Vogel 
58718cfa0ad2SJack F Vogel /**
58729d81738fSJack F Vogel  *  e1000_setup_led_pchlan - Configures SW controllable LED
58739d81738fSJack F Vogel  *  @hw: pointer to the HW structure
58749d81738fSJack F Vogel  *
58759d81738fSJack F Vogel  *  This prepares the SW controllable LED for use.
58769d81738fSJack F Vogel  **/
58779d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw)
58789d81738fSJack F Vogel {
58799d81738fSJack F Vogel 	DEBUGFUNC("e1000_setup_led_pchlan");
58809d81738fSJack F Vogel 
58819d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
58829d81738fSJack F Vogel 				     (u16)hw->mac.ledctl_mode1);
58839d81738fSJack F Vogel }
58849d81738fSJack F Vogel 
58859d81738fSJack F Vogel /**
58869d81738fSJack F Vogel  *  e1000_cleanup_led_pchlan - Restore the default LED operation
58879d81738fSJack F Vogel  *  @hw: pointer to the HW structure
58889d81738fSJack F Vogel  *
58899d81738fSJack F Vogel  *  Return the LED back to the default configuration.
58909d81738fSJack F Vogel  **/
58919d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw)
58929d81738fSJack F Vogel {
58939d81738fSJack F Vogel 	DEBUGFUNC("e1000_cleanup_led_pchlan");
58949d81738fSJack F Vogel 
58959d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
58969d81738fSJack F Vogel 				     (u16)hw->mac.ledctl_default);
58979d81738fSJack F Vogel }
58989d81738fSJack F Vogel 
58999d81738fSJack F Vogel /**
59009d81738fSJack F Vogel  *  e1000_led_on_pchlan - Turn LEDs on
59019d81738fSJack F Vogel  *  @hw: pointer to the HW structure
59029d81738fSJack F Vogel  *
59039d81738fSJack F Vogel  *  Turn on the LEDs.
59049d81738fSJack F Vogel  **/
59059d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw)
59069d81738fSJack F Vogel {
59079d81738fSJack F Vogel 	u16 data = (u16)hw->mac.ledctl_mode2;
59089d81738fSJack F Vogel 	u32 i, led;
59099d81738fSJack F Vogel 
59109d81738fSJack F Vogel 	DEBUGFUNC("e1000_led_on_pchlan");
59119d81738fSJack F Vogel 
59126ab6bfe3SJack F Vogel 	/* If no link, then turn LED on by setting the invert bit
59139d81738fSJack F Vogel 	 * for each LED that's mode is "link_up" in ledctl_mode2.
59149d81738fSJack F Vogel 	 */
59159d81738fSJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
59169d81738fSJack F Vogel 		for (i = 0; i < 3; i++) {
59179d81738fSJack F Vogel 			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
59189d81738fSJack F Vogel 			if ((led & E1000_PHY_LED0_MODE_MASK) !=
59199d81738fSJack F Vogel 			    E1000_LEDCTL_MODE_LINK_UP)
59209d81738fSJack F Vogel 				continue;
59219d81738fSJack F Vogel 			if (led & E1000_PHY_LED0_IVRT)
59229d81738fSJack F Vogel 				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
59239d81738fSJack F Vogel 			else
59249d81738fSJack F Vogel 				data |= (E1000_PHY_LED0_IVRT << (i * 5));
59259d81738fSJack F Vogel 		}
59269d81738fSJack F Vogel 	}
59279d81738fSJack F Vogel 
59289d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
59299d81738fSJack F Vogel }
59309d81738fSJack F Vogel 
59319d81738fSJack F Vogel /**
59329d81738fSJack F Vogel  *  e1000_led_off_pchlan - Turn LEDs off
59339d81738fSJack F Vogel  *  @hw: pointer to the HW structure
59349d81738fSJack F Vogel  *
59359d81738fSJack F Vogel  *  Turn off the LEDs.
59369d81738fSJack F Vogel  **/
59379d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw)
59389d81738fSJack F Vogel {
59399d81738fSJack F Vogel 	u16 data = (u16)hw->mac.ledctl_mode1;
59409d81738fSJack F Vogel 	u32 i, led;
59419d81738fSJack F Vogel 
59429d81738fSJack F Vogel 	DEBUGFUNC("e1000_led_off_pchlan");
59439d81738fSJack F Vogel 
59446ab6bfe3SJack F Vogel 	/* If no link, then turn LED off by clearing the invert bit
59459d81738fSJack F Vogel 	 * for each LED that's mode is "link_up" in ledctl_mode1.
59469d81738fSJack F Vogel 	 */
59479d81738fSJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
59489d81738fSJack F Vogel 		for (i = 0; i < 3; i++) {
59499d81738fSJack F Vogel 			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
59509d81738fSJack F Vogel 			if ((led & E1000_PHY_LED0_MODE_MASK) !=
59519d81738fSJack F Vogel 			    E1000_LEDCTL_MODE_LINK_UP)
59529d81738fSJack F Vogel 				continue;
59539d81738fSJack F Vogel 			if (led & E1000_PHY_LED0_IVRT)
59549d81738fSJack F Vogel 				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
59559d81738fSJack F Vogel 			else
59569d81738fSJack F Vogel 				data |= (E1000_PHY_LED0_IVRT << (i * 5));
59579d81738fSJack F Vogel 		}
59589d81738fSJack F Vogel 	}
59599d81738fSJack F Vogel 
59609d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
59619d81738fSJack F Vogel }
59629d81738fSJack F Vogel 
59639d81738fSJack F Vogel /**
59647d9119bdSJack F Vogel  *  e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset
59658cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
59668cfa0ad2SJack F Vogel  *
59677d9119bdSJack F Vogel  *  Read appropriate register for the config done bit for completion status
59687d9119bdSJack F Vogel  *  and configure the PHY through s/w for EEPROM-less parts.
59697d9119bdSJack F Vogel  *
59707d9119bdSJack F Vogel  *  NOTE: some silicon which is EEPROM-less will fail trying to read the
59717d9119bdSJack F Vogel  *  config done bit, so only an error is logged and continues.  If we were
59727d9119bdSJack F Vogel  *  to return with error, EEPROM-less silicon would not be able to be reset
59737d9119bdSJack F Vogel  *  or change link.
59748cfa0ad2SJack F Vogel  **/
59758cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
59768cfa0ad2SJack F Vogel {
59778cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
59788cfa0ad2SJack F Vogel 	u32 bank = 0;
59797d9119bdSJack F Vogel 	u32 status;
59808cfa0ad2SJack F Vogel 
59817d9119bdSJack F Vogel 	DEBUGFUNC("e1000_get_cfg_done_ich8lan");
59829d81738fSJack F Vogel 
59838cfa0ad2SJack F Vogel 	e1000_get_cfg_done_generic(hw);
59848cfa0ad2SJack F Vogel 
59857d9119bdSJack F Vogel 	/* Wait for indication from h/w that it has completed basic config */
59867d9119bdSJack F Vogel 	if (hw->mac.type >= e1000_ich10lan) {
59877d9119bdSJack F Vogel 		e1000_lan_init_done_ich8lan(hw);
59887d9119bdSJack F Vogel 	} else {
59897d9119bdSJack F Vogel 		ret_val = e1000_get_auto_rd_done_generic(hw);
59907d9119bdSJack F Vogel 		if (ret_val) {
59916ab6bfe3SJack F Vogel 			/* When auto config read does not complete, do not
59927d9119bdSJack F Vogel 			 * return with an error. This can happen in situations
59937d9119bdSJack F Vogel 			 * where there is no eeprom and prevents getting link.
59947d9119bdSJack F Vogel 			 */
59957d9119bdSJack F Vogel 			DEBUGOUT("Auto Read Done did not complete\n");
59967d9119bdSJack F Vogel 			ret_val = E1000_SUCCESS;
59977d9119bdSJack F Vogel 		}
59987d9119bdSJack F Vogel 	}
59997d9119bdSJack F Vogel 
60007d9119bdSJack F Vogel 	/* Clear PHY Reset Asserted bit */
60017d9119bdSJack F Vogel 	status = E1000_READ_REG(hw, E1000_STATUS);
60027d9119bdSJack F Vogel 	if (status & E1000_STATUS_PHYRA)
60037d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_STATUS, status & ~E1000_STATUS_PHYRA);
60047d9119bdSJack F Vogel 	else
60057d9119bdSJack F Vogel 		DEBUGOUT("PHY Reset Asserted not set - needs delay\n");
60067d9119bdSJack F Vogel 
60078cfa0ad2SJack F Vogel 	/* If EEPROM is not marked present, init the IGP 3 PHY manually */
60084edd8523SJack F Vogel 	if (hw->mac.type <= e1000_ich9lan) {
60096ab6bfe3SJack F Vogel 		if (!(E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) &&
60108cfa0ad2SJack F Vogel 		    (hw->phy.type == e1000_phy_igp_3)) {
60118cfa0ad2SJack F Vogel 			e1000_phy_init_script_igp3(hw);
60128cfa0ad2SJack F Vogel 		}
60138cfa0ad2SJack F Vogel 	} else {
60148cfa0ad2SJack F Vogel 		if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
6015daf9197cSJack F Vogel 			/* Maybe we should do a basic PHY config */
60168cfa0ad2SJack F Vogel 			DEBUGOUT("EEPROM not present\n");
60178cfa0ad2SJack F Vogel 			ret_val = -E1000_ERR_CONFIG;
60188cfa0ad2SJack F Vogel 		}
60198cfa0ad2SJack F Vogel 	}
60208cfa0ad2SJack F Vogel 
60218cfa0ad2SJack F Vogel 	return ret_val;
60228cfa0ad2SJack F Vogel }
60238cfa0ad2SJack F Vogel 
60248cfa0ad2SJack F Vogel /**
60258cfa0ad2SJack F Vogel  * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down
60268cfa0ad2SJack F Vogel  * @hw: pointer to the HW structure
60278cfa0ad2SJack F Vogel  *
60288cfa0ad2SJack F Vogel  * In the case of a PHY power down to save power, or to turn off link during a
60298cfa0ad2SJack F Vogel  * driver unload, or wake on lan is not enabled, remove the link.
60308cfa0ad2SJack F Vogel  **/
60318cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
60328cfa0ad2SJack F Vogel {
60338cfa0ad2SJack F Vogel 	/* If the management interface is not enabled, then power down */
6034daf9197cSJack F Vogel 	if (!(hw->mac.ops.check_mng_mode(hw) ||
6035daf9197cSJack F Vogel 	      hw->phy.ops.check_reset_block(hw)))
60368cfa0ad2SJack F Vogel 		e1000_power_down_phy_copper(hw);
60378cfa0ad2SJack F Vogel 
60388cfa0ad2SJack F Vogel 	return;
60398cfa0ad2SJack F Vogel }
60408cfa0ad2SJack F Vogel 
60418cfa0ad2SJack F Vogel /**
60428cfa0ad2SJack F Vogel  *  e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
60438cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
60448cfa0ad2SJack F Vogel  *
60458cfa0ad2SJack F Vogel  *  Clears hardware counters specific to the silicon family and calls
60468cfa0ad2SJack F Vogel  *  clear_hw_cntrs_generic to clear all general purpose counters.
60478cfa0ad2SJack F Vogel  **/
60488cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
60498cfa0ad2SJack F Vogel {
60509d81738fSJack F Vogel 	u16 phy_data;
60514dab5c37SJack F Vogel 	s32 ret_val;
60529d81738fSJack F Vogel 
60538cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan");
60548cfa0ad2SJack F Vogel 
60558cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_base_generic(hw);
60568cfa0ad2SJack F Vogel 
6057daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ALGNERRC);
6058daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_RXERRC);
6059daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TNCRS);
6060daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_CEXTERR);
6061daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTC);
6062daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTFC);
60638cfa0ad2SJack F Vogel 
6064daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPRC);
6065daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPDC);
6066daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPTC);
60678cfa0ad2SJack F Vogel 
6068daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_IAC);
6069daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ICRXOC);
60709d81738fSJack F Vogel 
60719d81738fSJack F Vogel 	/* Clear PHY statistics registers */
60729d81738fSJack F Vogel 	if ((hw->phy.type == e1000_phy_82578) ||
60737d9119bdSJack F Vogel 	    (hw->phy.type == e1000_phy_82579) ||
60746ab6bfe3SJack F Vogel 	    (hw->phy.type == e1000_phy_i217) ||
60759d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577)) {
60764dab5c37SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
60774dab5c37SJack F Vogel 		if (ret_val)
60784dab5c37SJack F Vogel 			return;
60794dab5c37SJack F Vogel 		ret_val = hw->phy.ops.set_page(hw,
60804dab5c37SJack F Vogel 					       HV_STATS_PAGE << IGP_PAGE_SHIFT);
60814dab5c37SJack F Vogel 		if (ret_val)
60824dab5c37SJack F Vogel 			goto release;
60834dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_SCC_UPPER, &phy_data);
60844dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_SCC_LOWER, &phy_data);
60854dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_ECOL_UPPER, &phy_data);
60864dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_ECOL_LOWER, &phy_data);
60874dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_MCC_UPPER, &phy_data);
60884dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_MCC_LOWER, &phy_data);
60894dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_LATECOL_UPPER, &phy_data);
60904dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_LATECOL_LOWER, &phy_data);
60914dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_COLC_UPPER, &phy_data);
60924dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_COLC_LOWER, &phy_data);
60934dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_DC_UPPER, &phy_data);
60944dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_DC_LOWER, &phy_data);
60954dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_TNCRS_UPPER, &phy_data);
60964dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_TNCRS_LOWER, &phy_data);
60974dab5c37SJack F Vogel release:
60984dab5c37SJack F Vogel 		hw->phy.ops.release(hw);
60999d81738fSJack F Vogel 	}
61008cfa0ad2SJack F Vogel }
61018cfa0ad2SJack F Vogel 
6102