xref: /freebsd/sys/dev/e1000/e1000_ich8lan.c (revision 8cc64f1e21bd827f2f169f1173aad38e3fdb6d61)
18cfa0ad2SJack F Vogel /******************************************************************************
28cfa0ad2SJack F Vogel 
3*8cc64f1eSJack F Vogel   Copyright (c) 2001-2014, 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
66*8cc64f1eSJack F Vogel  * Ethernet Connection (2) I218-LM
67*8cc64f1eSJack F Vogel  * Ethernet Connection (2) I218-V
68*8cc64f1eSJack F Vogel  * Ethernet Connection (3) I218-LM
69*8cc64f1eSJack 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);
80*8cc64f1eSJack F Vogel static int  e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index);
81*8cc64f1eSJack 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);
958cfa0ad2SJack F Vogel static s32  e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
968cfa0ad2SJack F Vogel 				    u16 words, u16 *data);
978cfa0ad2SJack F Vogel static s32  e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw);
988cfa0ad2SJack F Vogel static s32  e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
998cfa0ad2SJack F Vogel static s32  e1000_valid_led_default_ich8lan(struct e1000_hw *hw,
1008cfa0ad2SJack F Vogel 					    u16 *data);
1019d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw);
1028cfa0ad2SJack F Vogel static s32  e1000_get_bus_info_ich8lan(struct e1000_hw *hw);
1038cfa0ad2SJack F Vogel static s32  e1000_reset_hw_ich8lan(struct e1000_hw *hw);
1048cfa0ad2SJack F Vogel static s32  e1000_init_hw_ich8lan(struct e1000_hw *hw);
1058cfa0ad2SJack F Vogel static s32  e1000_setup_link_ich8lan(struct e1000_hw *hw);
1068cfa0ad2SJack F Vogel static s32  e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
1076ab6bfe3SJack F Vogel static s32  e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw);
1088cfa0ad2SJack F Vogel static s32  e1000_get_link_up_info_ich8lan(struct e1000_hw *hw,
1098cfa0ad2SJack F Vogel 					   u16 *speed, u16 *duplex);
1108cfa0ad2SJack F Vogel static s32  e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
1118cfa0ad2SJack F Vogel static s32  e1000_led_on_ich8lan(struct e1000_hw *hw);
1128cfa0ad2SJack F Vogel static s32  e1000_led_off_ich8lan(struct e1000_hw *hw);
1134edd8523SJack F Vogel static s32  e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
1149d81738fSJack F Vogel static s32  e1000_setup_led_pchlan(struct e1000_hw *hw);
1159d81738fSJack F Vogel static s32  e1000_cleanup_led_pchlan(struct e1000_hw *hw);
1169d81738fSJack F Vogel static s32  e1000_led_on_pchlan(struct e1000_hw *hw);
1179d81738fSJack F Vogel static s32  e1000_led_off_pchlan(struct e1000_hw *hw);
1188cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
1198cfa0ad2SJack F Vogel static s32  e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
1208cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
1218cfa0ad2SJack F Vogel static s32  e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
1228cfa0ad2SJack F Vogel static s32  e1000_read_flash_byte_ich8lan(struct e1000_hw *hw,
1238cfa0ad2SJack F Vogel 					  u32 offset, u8 *data);
1248cfa0ad2SJack F Vogel static s32  e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
1258cfa0ad2SJack F Vogel 					  u8 size, u16 *data);
1268cfa0ad2SJack F Vogel static s32  e1000_read_flash_word_ich8lan(struct e1000_hw *hw,
1278cfa0ad2SJack F Vogel 					  u32 offset, u16 *data);
1288cfa0ad2SJack F Vogel static s32  e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
1298cfa0ad2SJack F Vogel 						 u32 offset, u8 byte);
1308cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
1318cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
1324edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw);
133a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
1347d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw);
1357d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate);
1366ab6bfe3SJack F Vogel static s32 e1000_set_obff_timer_pch_lpt(struct e1000_hw *hw, u32 itr);
1378cfa0ad2SJack F Vogel 
1388cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
1398cfa0ad2SJack F Vogel /* Offset 04h HSFSTS */
1408cfa0ad2SJack F Vogel union ich8_hws_flash_status {
1418cfa0ad2SJack F Vogel 	struct ich8_hsfsts {
1428cfa0ad2SJack F Vogel 		u16 flcdone:1; /* bit 0 Flash Cycle Done */
1438cfa0ad2SJack F Vogel 		u16 flcerr:1; /* bit 1 Flash Cycle Error */
1448cfa0ad2SJack F Vogel 		u16 dael:1; /* bit 2 Direct Access error Log */
1458cfa0ad2SJack F Vogel 		u16 berasesz:2; /* bit 4:3 Sector Erase Size */
1468cfa0ad2SJack F Vogel 		u16 flcinprog:1; /* bit 5 flash cycle in Progress */
1478cfa0ad2SJack F Vogel 		u16 reserved1:2; /* bit 13:6 Reserved */
1488cfa0ad2SJack F Vogel 		u16 reserved2:6; /* bit 13:6 Reserved */
1498cfa0ad2SJack F Vogel 		u16 fldesvalid:1; /* bit 14 Flash Descriptor Valid */
1508cfa0ad2SJack F Vogel 		u16 flockdn:1; /* bit 15 Flash Config Lock-Down */
1518cfa0ad2SJack F Vogel 	} hsf_status;
1528cfa0ad2SJack F Vogel 	u16 regval;
1538cfa0ad2SJack F Vogel };
1548cfa0ad2SJack F Vogel 
1558cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
1568cfa0ad2SJack F Vogel /* Offset 06h FLCTL */
1578cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl {
1588cfa0ad2SJack F Vogel 	struct ich8_hsflctl {
1598cfa0ad2SJack F Vogel 		u16 flcgo:1;   /* 0 Flash Cycle Go */
1608cfa0ad2SJack F Vogel 		u16 flcycle:2;   /* 2:1 Flash Cycle */
1618cfa0ad2SJack F Vogel 		u16 reserved:5;   /* 7:3 Reserved  */
1628cfa0ad2SJack F Vogel 		u16 fldbcount:2;   /* 9:8 Flash Data Byte Count */
1638cfa0ad2SJack F Vogel 		u16 flockdn:6;   /* 15:10 Reserved */
1648cfa0ad2SJack F Vogel 	} hsf_ctrl;
1658cfa0ad2SJack F Vogel 	u16 regval;
1668cfa0ad2SJack F Vogel };
1678cfa0ad2SJack F Vogel 
1688cfa0ad2SJack F Vogel /* ICH Flash Region Access Permissions */
1698cfa0ad2SJack F Vogel union ich8_hws_flash_regacc {
1708cfa0ad2SJack F Vogel 	struct ich8_flracc {
1718cfa0ad2SJack F Vogel 		u32 grra:8; /* 0:7 GbE region Read Access */
1728cfa0ad2SJack F Vogel 		u32 grwa:8; /* 8:15 GbE region Write Access */
1738cfa0ad2SJack F Vogel 		u32 gmrag:8; /* 23:16 GbE Master Read Access Grant */
1748cfa0ad2SJack F Vogel 		u32 gmwag:8; /* 31:24 GbE Master Write Access Grant */
1758cfa0ad2SJack F Vogel 	} hsf_flregacc;
1768cfa0ad2SJack F Vogel 	u16 regval;
1778cfa0ad2SJack F Vogel };
1788cfa0ad2SJack F Vogel 
1796ab6bfe3SJack F Vogel /**
1806ab6bfe3SJack F Vogel  *  e1000_phy_is_accessible_pchlan - Check if able to access PHY registers
1816ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
1826ab6bfe3SJack F Vogel  *
1836ab6bfe3SJack F Vogel  *  Test access to the PHY registers by reading the PHY ID registers.  If
1846ab6bfe3SJack F Vogel  *  the PHY ID is already known (e.g. resume path) compare it with known ID,
1856ab6bfe3SJack F Vogel  *  otherwise assume the read PHY ID is correct if it is valid.
1866ab6bfe3SJack F Vogel  *
1876ab6bfe3SJack F Vogel  *  Assumes the sw/fw/hw semaphore is already acquired.
1886ab6bfe3SJack F Vogel  **/
1896ab6bfe3SJack F Vogel static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
1904dab5c37SJack F Vogel {
1916ab6bfe3SJack F Vogel 	u16 phy_reg = 0;
1926ab6bfe3SJack F Vogel 	u32 phy_id = 0;
1937609433eSJack F Vogel 	s32 ret_val = 0;
1946ab6bfe3SJack F Vogel 	u16 retry_count;
1957609433eSJack F Vogel 	u32 mac_reg = 0;
1964dab5c37SJack F Vogel 
1976ab6bfe3SJack F Vogel 	for (retry_count = 0; retry_count < 2; retry_count++) {
1986ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID1, &phy_reg);
1996ab6bfe3SJack F Vogel 		if (ret_val || (phy_reg == 0xFFFF))
2006ab6bfe3SJack F Vogel 			continue;
2016ab6bfe3SJack F Vogel 		phy_id = (u32)(phy_reg << 16);
2024dab5c37SJack F Vogel 
2036ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID2, &phy_reg);
2046ab6bfe3SJack F Vogel 		if (ret_val || (phy_reg == 0xFFFF)) {
2056ab6bfe3SJack F Vogel 			phy_id = 0;
2066ab6bfe3SJack F Vogel 			continue;
2076ab6bfe3SJack F Vogel 		}
2086ab6bfe3SJack F Vogel 		phy_id |= (u32)(phy_reg & PHY_REVISION_MASK);
2096ab6bfe3SJack F Vogel 		break;
2106ab6bfe3SJack F Vogel 	}
2116ab6bfe3SJack F Vogel 
2126ab6bfe3SJack F Vogel 	if (hw->phy.id) {
2136ab6bfe3SJack F Vogel 		if  (hw->phy.id == phy_id)
2147609433eSJack F Vogel 			goto out;
2156ab6bfe3SJack F Vogel 	} else if (phy_id) {
2166ab6bfe3SJack F Vogel 		hw->phy.id = phy_id;
2176ab6bfe3SJack F Vogel 		hw->phy.revision = (u32)(phy_reg & ~PHY_REVISION_MASK);
2187609433eSJack F Vogel 		goto out;
2196ab6bfe3SJack F Vogel 	}
2206ab6bfe3SJack F Vogel 
2216ab6bfe3SJack F Vogel 	/* In case the PHY needs to be in mdio slow mode,
2226ab6bfe3SJack F Vogel 	 * set slow mode and try to get the PHY id again.
2236ab6bfe3SJack F Vogel 	 */
2247609433eSJack F Vogel 	if (hw->mac.type < e1000_pch_lpt) {
2256ab6bfe3SJack F Vogel 		hw->phy.ops.release(hw);
2266ab6bfe3SJack F Vogel 		ret_val = e1000_set_mdio_slow_mode_hv(hw);
2276ab6bfe3SJack F Vogel 		if (!ret_val)
2286ab6bfe3SJack F Vogel 			ret_val = e1000_get_phy_id(hw);
2296ab6bfe3SJack F Vogel 		hw->phy.ops.acquire(hw);
2307609433eSJack F Vogel 	}
2316ab6bfe3SJack F Vogel 
2327609433eSJack F Vogel 	if (ret_val)
2337609433eSJack F Vogel 		return FALSE;
2347609433eSJack F Vogel out:
2357609433eSJack F Vogel 	if (hw->mac.type == e1000_pch_lpt) {
2367609433eSJack F Vogel 		/* Unforce SMBus mode in PHY */
2377609433eSJack F Vogel 		hw->phy.ops.read_reg_locked(hw, CV_SMB_CTRL, &phy_reg);
2387609433eSJack F Vogel 		phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
2397609433eSJack F Vogel 		hw->phy.ops.write_reg_locked(hw, CV_SMB_CTRL, phy_reg);
2407609433eSJack F Vogel 
2417609433eSJack F Vogel 		/* Unforce SMBus mode in MAC */
2427609433eSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
2437609433eSJack F Vogel 		mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
2447609433eSJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
2457609433eSJack F Vogel 	}
2467609433eSJack F Vogel 
2477609433eSJack F Vogel 	return TRUE;
2487609433eSJack F Vogel }
2497609433eSJack F Vogel 
2507609433eSJack F Vogel /**
2517609433eSJack F Vogel  *  e1000_toggle_lanphypc_pch_lpt - toggle the LANPHYPC pin value
2527609433eSJack F Vogel  *  @hw: pointer to the HW structure
2537609433eSJack F Vogel  *
2547609433eSJack F Vogel  *  Toggling the LANPHYPC pin value fully power-cycles the PHY and is
2557609433eSJack F Vogel  *  used to reset the PHY to a quiescent state when necessary.
2567609433eSJack F Vogel  **/
257*8cc64f1eSJack F Vogel static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw)
2587609433eSJack F Vogel {
2597609433eSJack F Vogel 	u32 mac_reg;
2607609433eSJack F Vogel 
2617609433eSJack F Vogel 	DEBUGFUNC("e1000_toggle_lanphypc_pch_lpt");
2627609433eSJack F Vogel 
2637609433eSJack F Vogel 	/* Set Phy Config Counter to 50msec */
2647609433eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM3);
2657609433eSJack F Vogel 	mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
2667609433eSJack F Vogel 	mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
2677609433eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_FEXTNVM3, mac_reg);
2687609433eSJack F Vogel 
2697609433eSJack F Vogel 	/* Toggle LANPHYPC Value bit */
2707609433eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_CTRL);
2717609433eSJack F Vogel 	mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
2727609433eSJack F Vogel 	mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
2737609433eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, mac_reg);
2747609433eSJack F Vogel 	E1000_WRITE_FLUSH(hw);
2757609433eSJack F Vogel 	usec_delay(10);
2767609433eSJack F Vogel 	mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
2777609433eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, mac_reg);
2787609433eSJack F Vogel 	E1000_WRITE_FLUSH(hw);
2797609433eSJack F Vogel 
2807609433eSJack F Vogel 	if (hw->mac.type < e1000_pch_lpt) {
2817609433eSJack F Vogel 		msec_delay(50);
2827609433eSJack F Vogel 	} else {
2837609433eSJack F Vogel 		u16 count = 20;
2847609433eSJack F Vogel 
2857609433eSJack F Vogel 		do {
2867609433eSJack F Vogel 			msec_delay(5);
2877609433eSJack F Vogel 		} while (!(E1000_READ_REG(hw, E1000_CTRL_EXT) &
2887609433eSJack F Vogel 			   E1000_CTRL_EXT_LPCD) && count--);
2897609433eSJack F Vogel 
2907609433eSJack F Vogel 		msec_delay(30);
2917609433eSJack F Vogel 	}
2926ab6bfe3SJack F Vogel }
2936ab6bfe3SJack F Vogel 
2946ab6bfe3SJack F Vogel /**
2956ab6bfe3SJack F Vogel  *  e1000_init_phy_workarounds_pchlan - PHY initialization workarounds
2966ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
2976ab6bfe3SJack F Vogel  *
2986ab6bfe3SJack F Vogel  *  Workarounds/flow necessary for PHY initialization during driver load
2996ab6bfe3SJack F Vogel  *  and resume paths.
3006ab6bfe3SJack F Vogel  **/
3016ab6bfe3SJack F Vogel static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
3026ab6bfe3SJack F Vogel {
3036ab6bfe3SJack F Vogel 	u32 mac_reg, fwsm = E1000_READ_REG(hw, E1000_FWSM);
3046ab6bfe3SJack F Vogel 	s32 ret_val;
3056ab6bfe3SJack F Vogel 
3066ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_init_phy_workarounds_pchlan");
3076ab6bfe3SJack F Vogel 
3086ab6bfe3SJack F Vogel 	/* Gate automatic PHY configuration by hardware on managed and
3096ab6bfe3SJack F Vogel 	 * non-managed 82579 and newer adapters.
3106ab6bfe3SJack F Vogel 	 */
3116ab6bfe3SJack F Vogel 	e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
3126ab6bfe3SJack F Vogel 
313*8cc64f1eSJack F Vogel 	/* It is not possible to be certain of the current state of ULP
314*8cc64f1eSJack F Vogel 	 * so forcibly disable it.
315*8cc64f1eSJack F Vogel 	 */
316*8cc64f1eSJack F Vogel 	hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_unknown;
317*8cc64f1eSJack F Vogel 	e1000_disable_ulp_lpt_lp(hw, TRUE);
318*8cc64f1eSJack F Vogel 
3196ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
3206ab6bfe3SJack F Vogel 	if (ret_val) {
3216ab6bfe3SJack F Vogel 		DEBUGOUT("Failed to initialize PHY flow\n");
3226ab6bfe3SJack F Vogel 		goto out;
3236ab6bfe3SJack F Vogel 	}
3246ab6bfe3SJack F Vogel 
3256ab6bfe3SJack F Vogel 	/* The MAC-PHY interconnect may be in SMBus mode.  If the PHY is
3266ab6bfe3SJack F Vogel 	 * inaccessible and resetting the PHY is not blocked, toggle the
3276ab6bfe3SJack F Vogel 	 * LANPHYPC Value bit to force the interconnect to PCIe mode.
3286ab6bfe3SJack F Vogel 	 */
3296ab6bfe3SJack F Vogel 	switch (hw->mac.type) {
3306ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
3316ab6bfe3SJack F Vogel 		if (e1000_phy_is_accessible_pchlan(hw))
3326ab6bfe3SJack F Vogel 			break;
3336ab6bfe3SJack F Vogel 
3346ab6bfe3SJack F Vogel 		/* Before toggling LANPHYPC, see if PHY is accessible by
3356ab6bfe3SJack F Vogel 		 * forcing MAC to SMBus mode first.
3366ab6bfe3SJack F Vogel 		 */
3376ab6bfe3SJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
3386ab6bfe3SJack F Vogel 		mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
3396ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
3406ab6bfe3SJack F Vogel 
3417609433eSJack F Vogel 		/* Wait 50 milliseconds for MAC to finish any retries
3427609433eSJack F Vogel 		 * that it might be trying to perform from previous
3437609433eSJack F Vogel 		 * attempts to acknowledge any phy read requests.
3447609433eSJack F Vogel 		 */
3457609433eSJack F Vogel 		 msec_delay(50);
3467609433eSJack F Vogel 
3476ab6bfe3SJack F Vogel 		/* fall-through */
3486ab6bfe3SJack F Vogel 	case e1000_pch2lan:
3497609433eSJack F Vogel 		if (e1000_phy_is_accessible_pchlan(hw))
3506ab6bfe3SJack F Vogel 			break;
3516ab6bfe3SJack F Vogel 
3526ab6bfe3SJack F Vogel 		/* fall-through */
3536ab6bfe3SJack F Vogel 	case e1000_pchlan:
3546ab6bfe3SJack F Vogel 		if ((hw->mac.type == e1000_pchlan) &&
3556ab6bfe3SJack F Vogel 		    (fwsm & E1000_ICH_FWSM_FW_VALID))
3566ab6bfe3SJack F Vogel 			break;
3576ab6bfe3SJack F Vogel 
3586ab6bfe3SJack F Vogel 		if (hw->phy.ops.check_reset_block(hw)) {
3596ab6bfe3SJack F Vogel 			DEBUGOUT("Required LANPHYPC toggle blocked by ME\n");
3607609433eSJack F Vogel 			ret_val = -E1000_ERR_PHY;
3616ab6bfe3SJack F Vogel 			break;
3626ab6bfe3SJack F Vogel 		}
3636ab6bfe3SJack F Vogel 
3647609433eSJack F Vogel 		/* Toggle LANPHYPC Value bit */
3657609433eSJack F Vogel 		e1000_toggle_lanphypc_pch_lpt(hw);
3667609433eSJack F Vogel 		if (hw->mac.type >= e1000_pch_lpt) {
3677609433eSJack F Vogel 			if (e1000_phy_is_accessible_pchlan(hw))
3687609433eSJack F Vogel 				break;
3696ab6bfe3SJack F Vogel 
3706ab6bfe3SJack F Vogel 			/* Toggling LANPHYPC brings the PHY out of SMBus mode
3717609433eSJack F Vogel 			 * so ensure that the MAC is also out of SMBus mode
3726ab6bfe3SJack F Vogel 			 */
3736ab6bfe3SJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
3746ab6bfe3SJack F Vogel 			mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
3756ab6bfe3SJack F Vogel 			E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
3766ab6bfe3SJack F Vogel 
3777609433eSJack F Vogel 			if (e1000_phy_is_accessible_pchlan(hw))
3787609433eSJack F Vogel 				break;
3797609433eSJack F Vogel 
3807609433eSJack F Vogel 			ret_val = -E1000_ERR_PHY;
3816ab6bfe3SJack F Vogel 		}
3826ab6bfe3SJack F Vogel 		break;
3836ab6bfe3SJack F Vogel 	default:
3846ab6bfe3SJack F Vogel 		break;
3856ab6bfe3SJack F Vogel 	}
3866ab6bfe3SJack F Vogel 
3876ab6bfe3SJack F Vogel 	hw->phy.ops.release(hw);
3887609433eSJack F Vogel 	if (!ret_val) {
3897609433eSJack F Vogel 
3907609433eSJack F Vogel 		/* Check to see if able to reset PHY.  Print error if not */
3917609433eSJack F Vogel 		if (hw->phy.ops.check_reset_block(hw)) {
3927609433eSJack F Vogel 			ERROR_REPORT("Reset blocked by ME\n");
3937609433eSJack F Vogel 			goto out;
3947609433eSJack F Vogel 		}
3956ab6bfe3SJack F Vogel 
3966ab6bfe3SJack F Vogel 		/* Reset the PHY before any access to it.  Doing so, ensures
3976ab6bfe3SJack F Vogel 		 * that the PHY is in a known good state before we read/write
3986ab6bfe3SJack F Vogel 		 * PHY registers.  The generic reset is sufficient here,
3996ab6bfe3SJack F Vogel 		 * because we haven't determined the PHY type yet.
4006ab6bfe3SJack F Vogel 		 */
4016ab6bfe3SJack F Vogel 		ret_val = e1000_phy_hw_reset_generic(hw);
4027609433eSJack F Vogel 		if (ret_val)
4037609433eSJack F Vogel 			goto out;
4047609433eSJack F Vogel 
4057609433eSJack F Vogel 		/* On a successful reset, possibly need to wait for the PHY
4067609433eSJack F Vogel 		 * to quiesce to an accessible state before returning control
4077609433eSJack F Vogel 		 * to the calling function.  If the PHY does not quiesce, then
4087609433eSJack F Vogel 		 * return E1000E_BLK_PHY_RESET, as this is the condition that
4097609433eSJack F Vogel 		 *  the PHY is in.
4107609433eSJack F Vogel 		 */
4117609433eSJack F Vogel 		ret_val = hw->phy.ops.check_reset_block(hw);
4127609433eSJack F Vogel 		if (ret_val)
4137609433eSJack F Vogel 			ERROR_REPORT("ME blocked access to PHY after reset\n");
4147609433eSJack F Vogel 	}
4156ab6bfe3SJack F Vogel 
4166ab6bfe3SJack F Vogel out:
4176ab6bfe3SJack F Vogel 	/* Ungate automatic PHY configuration on non-managed 82579 */
4186ab6bfe3SJack F Vogel 	if ((hw->mac.type == e1000_pch2lan) &&
4196ab6bfe3SJack F Vogel 	    !(fwsm & E1000_ICH_FWSM_FW_VALID)) {
4206ab6bfe3SJack F Vogel 		msec_delay(10);
4216ab6bfe3SJack F Vogel 		e1000_gate_hw_phy_config_ich8lan(hw, FALSE);
4226ab6bfe3SJack F Vogel 	}
4236ab6bfe3SJack F Vogel 
4246ab6bfe3SJack F Vogel 	return ret_val;
4254dab5c37SJack F Vogel }
4264dab5c37SJack F Vogel 
4278cfa0ad2SJack F Vogel /**
4289d81738fSJack F Vogel  *  e1000_init_phy_params_pchlan - Initialize PHY function pointers
4299d81738fSJack F Vogel  *  @hw: pointer to the HW structure
4309d81738fSJack F Vogel  *
4319d81738fSJack F Vogel  *  Initialize family-specific PHY parameters and function pointers.
4329d81738fSJack F Vogel  **/
4339d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
4349d81738fSJack F Vogel {
4359d81738fSJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
4366ab6bfe3SJack F Vogel 	s32 ret_val;
4379d81738fSJack F Vogel 
4389d81738fSJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_pchlan");
4399d81738fSJack F Vogel 
4409d81738fSJack F Vogel 	phy->addr		= 1;
4419d81738fSJack F Vogel 	phy->reset_delay_us	= 100;
4429d81738fSJack F Vogel 
4439d81738fSJack F Vogel 	phy->ops.acquire	= e1000_acquire_swflag_ich8lan;
4449d81738fSJack F Vogel 	phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
4459d81738fSJack F Vogel 	phy->ops.get_cfg_done	= e1000_get_cfg_done_ich8lan;
4464dab5c37SJack F Vogel 	phy->ops.set_page	= e1000_set_page_igp;
4479d81738fSJack F Vogel 	phy->ops.read_reg	= e1000_read_phy_reg_hv;
4484edd8523SJack F Vogel 	phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked;
4494dab5c37SJack F Vogel 	phy->ops.read_reg_page	= e1000_read_phy_reg_page_hv;
4509d81738fSJack F Vogel 	phy->ops.release	= e1000_release_swflag_ich8lan;
4519d81738fSJack F Vogel 	phy->ops.reset		= e1000_phy_hw_reset_ich8lan;
4524edd8523SJack F Vogel 	phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan;
4534edd8523SJack F Vogel 	phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan;
4549d81738fSJack F Vogel 	phy->ops.write_reg	= e1000_write_phy_reg_hv;
4554edd8523SJack F Vogel 	phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked;
4564dab5c37SJack F Vogel 	phy->ops.write_reg_page	= e1000_write_phy_reg_page_hv;
4579d81738fSJack F Vogel 	phy->ops.power_up	= e1000_power_up_phy_copper;
4589d81738fSJack F Vogel 	phy->ops.power_down	= e1000_power_down_phy_copper_ich8lan;
4599d81738fSJack F Vogel 	phy->autoneg_mask	= AUTONEG_ADVERTISE_SPEED_DEFAULT;
4609d81738fSJack F Vogel 
4619d81738fSJack F Vogel 	phy->id = e1000_phy_unknown;
4626ab6bfe3SJack F Vogel 
4636ab6bfe3SJack F Vogel 	ret_val = e1000_init_phy_workarounds_pchlan(hw);
4646ab6bfe3SJack F Vogel 	if (ret_val)
4656ab6bfe3SJack F Vogel 		return ret_val;
4666ab6bfe3SJack F Vogel 
4676ab6bfe3SJack F Vogel 	if (phy->id == e1000_phy_unknown)
4687d9119bdSJack F Vogel 		switch (hw->mac.type) {
4697d9119bdSJack F Vogel 		default:
470a69ed8dfSJack F Vogel 			ret_val = e1000_get_phy_id(hw);
471a69ed8dfSJack F Vogel 			if (ret_val)
4726ab6bfe3SJack F Vogel 				return ret_val;
4737d9119bdSJack F Vogel 			if ((phy->id != 0) && (phy->id != PHY_REVISION_MASK))
4747d9119bdSJack F Vogel 				break;
4757d9119bdSJack F Vogel 			/* fall-through */
4767d9119bdSJack F Vogel 		case e1000_pch2lan:
4776ab6bfe3SJack F Vogel 		case e1000_pch_lpt:
4786ab6bfe3SJack F Vogel 			/* In case the PHY needs to be in mdio slow mode,
479a69ed8dfSJack F Vogel 			 * set slow mode and try to get the PHY id again.
480a69ed8dfSJack F Vogel 			 */
481a69ed8dfSJack F Vogel 			ret_val = e1000_set_mdio_slow_mode_hv(hw);
482a69ed8dfSJack F Vogel 			if (ret_val)
4836ab6bfe3SJack F Vogel 				return ret_val;
484a69ed8dfSJack F Vogel 			ret_val = e1000_get_phy_id(hw);
485a69ed8dfSJack F Vogel 			if (ret_val)
4866ab6bfe3SJack F Vogel 				return ret_val;
4877d9119bdSJack F Vogel 			break;
488a69ed8dfSJack F Vogel 		}
4899d81738fSJack F Vogel 	phy->type = e1000_get_phy_type_from_id(phy->id);
4909d81738fSJack F Vogel 
4914edd8523SJack F Vogel 	switch (phy->type) {
4924edd8523SJack F Vogel 	case e1000_phy_82577:
4937d9119bdSJack F Vogel 	case e1000_phy_82579:
4946ab6bfe3SJack F Vogel 	case e1000_phy_i217:
4959d81738fSJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_82577;
4969d81738fSJack F Vogel 		phy->ops.force_speed_duplex =
4979d81738fSJack F Vogel 			e1000_phy_force_speed_duplex_82577;
4989d81738fSJack F Vogel 		phy->ops.get_cable_length = e1000_get_cable_length_82577;
4999d81738fSJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_82577;
5009d81738fSJack F Vogel 		phy->ops.commit = e1000_phy_sw_reset_generic;
5018ec87fc5SJack F Vogel 		break;
5024edd8523SJack F Vogel 	case e1000_phy_82578:
5034edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_m88;
5044edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
5054edd8523SJack F Vogel 		phy->ops.get_cable_length = e1000_get_cable_length_m88;
5064edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_m88;
5074edd8523SJack F Vogel 		break;
5084edd8523SJack F Vogel 	default:
5094edd8523SJack F Vogel 		ret_val = -E1000_ERR_PHY;
5104edd8523SJack F Vogel 		break;
5119d81738fSJack F Vogel 	}
5129d81738fSJack F Vogel 
5139d81738fSJack F Vogel 	return ret_val;
5149d81738fSJack F Vogel }
5159d81738fSJack F Vogel 
5169d81738fSJack F Vogel /**
5178cfa0ad2SJack F Vogel  *  e1000_init_phy_params_ich8lan - Initialize PHY function pointers
5188cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5198cfa0ad2SJack F Vogel  *
5208cfa0ad2SJack F Vogel  *  Initialize family-specific PHY parameters and function pointers.
5218cfa0ad2SJack F Vogel  **/
5228cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
5238cfa0ad2SJack F Vogel {
5248cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
5256ab6bfe3SJack F Vogel 	s32 ret_val;
5268cfa0ad2SJack F Vogel 	u16 i = 0;
5278cfa0ad2SJack F Vogel 
5288cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_ich8lan");
5298cfa0ad2SJack F Vogel 
5308cfa0ad2SJack F Vogel 	phy->addr		= 1;
5318cfa0ad2SJack F Vogel 	phy->reset_delay_us	= 100;
5328cfa0ad2SJack F Vogel 
5338cfa0ad2SJack F Vogel 	phy->ops.acquire	= e1000_acquire_swflag_ich8lan;
5348cfa0ad2SJack F Vogel 	phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
5358cfa0ad2SJack F Vogel 	phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
5368cfa0ad2SJack F Vogel 	phy->ops.get_cfg_done	= e1000_get_cfg_done_ich8lan;
5378cfa0ad2SJack F Vogel 	phy->ops.read_reg	= e1000_read_phy_reg_igp;
5388cfa0ad2SJack F Vogel 	phy->ops.release	= e1000_release_swflag_ich8lan;
5398cfa0ad2SJack F Vogel 	phy->ops.reset		= e1000_phy_hw_reset_ich8lan;
5408cfa0ad2SJack F Vogel 	phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan;
5418cfa0ad2SJack F Vogel 	phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan;
5428cfa0ad2SJack F Vogel 	phy->ops.write_reg	= e1000_write_phy_reg_igp;
5438cfa0ad2SJack F Vogel 	phy->ops.power_up	= e1000_power_up_phy_copper;
5448cfa0ad2SJack F Vogel 	phy->ops.power_down	= e1000_power_down_phy_copper_ich8lan;
5458cfa0ad2SJack F Vogel 
5466ab6bfe3SJack F Vogel 	/* We may need to do this twice - once for IGP and if that fails,
5478cfa0ad2SJack F Vogel 	 * we'll set BM func pointers and try again
5488cfa0ad2SJack F Vogel 	 */
5498cfa0ad2SJack F Vogel 	ret_val = e1000_determine_phy_address(hw);
5508cfa0ad2SJack F Vogel 	if (ret_val) {
5518cfa0ad2SJack F Vogel 		phy->ops.write_reg = e1000_write_phy_reg_bm;
5528cfa0ad2SJack F Vogel 		phy->ops.read_reg  = e1000_read_phy_reg_bm;
5538cfa0ad2SJack F Vogel 		ret_val = e1000_determine_phy_address(hw);
5548cfa0ad2SJack F Vogel 		if (ret_val) {
555d035aa2dSJack F Vogel 			DEBUGOUT("Cannot determine PHY addr. Erroring out\n");
5566ab6bfe3SJack F Vogel 			return ret_val;
5578cfa0ad2SJack F Vogel 		}
5588cfa0ad2SJack F Vogel 	}
5598cfa0ad2SJack F Vogel 
5608cfa0ad2SJack F Vogel 	phy->id = 0;
5618cfa0ad2SJack F Vogel 	while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) &&
5628cfa0ad2SJack F Vogel 	       (i++ < 100)) {
5638cfa0ad2SJack F Vogel 		msec_delay(1);
5648cfa0ad2SJack F Vogel 		ret_val = e1000_get_phy_id(hw);
5658cfa0ad2SJack F Vogel 		if (ret_val)
5666ab6bfe3SJack F Vogel 			return ret_val;
5678cfa0ad2SJack F Vogel 	}
5688cfa0ad2SJack F Vogel 
5698cfa0ad2SJack F Vogel 	/* Verify phy id */
5708cfa0ad2SJack F Vogel 	switch (phy->id) {
5718cfa0ad2SJack F Vogel 	case IGP03E1000_E_PHY_ID:
5728cfa0ad2SJack F Vogel 		phy->type = e1000_phy_igp_3;
5738cfa0ad2SJack F Vogel 		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
5744edd8523SJack F Vogel 		phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked;
5754edd8523SJack F Vogel 		phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked;
5764edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_igp;
5774edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_igp;
5784edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
5798cfa0ad2SJack F Vogel 		break;
5808cfa0ad2SJack F Vogel 	case IFE_E_PHY_ID:
5818cfa0ad2SJack F Vogel 	case IFE_PLUS_E_PHY_ID:
5828cfa0ad2SJack F Vogel 	case IFE_C_E_PHY_ID:
5838cfa0ad2SJack F Vogel 		phy->type = e1000_phy_ife;
5848cfa0ad2SJack F Vogel 		phy->autoneg_mask = E1000_ALL_NOT_GIG;
5854edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_ife;
5864edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_ife;
5874edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife;
5888cfa0ad2SJack F Vogel 		break;
5898cfa0ad2SJack F Vogel 	case BME1000_E_PHY_ID:
5908cfa0ad2SJack F Vogel 		phy->type = e1000_phy_bm;
5918cfa0ad2SJack F Vogel 		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
5928cfa0ad2SJack F Vogel 		phy->ops.read_reg = e1000_read_phy_reg_bm;
5938cfa0ad2SJack F Vogel 		phy->ops.write_reg = e1000_write_phy_reg_bm;
5948cfa0ad2SJack F Vogel 		phy->ops.commit = e1000_phy_sw_reset_generic;
5954edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_m88;
5964edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_m88;
5974edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
5988cfa0ad2SJack F Vogel 		break;
5998cfa0ad2SJack F Vogel 	default:
6006ab6bfe3SJack F Vogel 		return -E1000_ERR_PHY;
6016ab6bfe3SJack F Vogel 		break;
6028cfa0ad2SJack F Vogel 	}
6038cfa0ad2SJack F Vogel 
6046ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
6058cfa0ad2SJack F Vogel }
6068cfa0ad2SJack F Vogel 
6078cfa0ad2SJack F Vogel /**
6088cfa0ad2SJack F Vogel  *  e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
6098cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
6108cfa0ad2SJack F Vogel  *
6118cfa0ad2SJack F Vogel  *  Initialize family-specific NVM parameters and function
6128cfa0ad2SJack F Vogel  *  pointers.
6138cfa0ad2SJack F Vogel  **/
6148cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
6158cfa0ad2SJack F Vogel {
6168cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
617daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
6188cfa0ad2SJack F Vogel 	u32 gfpreg, sector_base_addr, sector_end_addr;
6198cfa0ad2SJack F Vogel 	u16 i;
6208cfa0ad2SJack F Vogel 
6218cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_nvm_params_ich8lan");
6228cfa0ad2SJack F Vogel 
6238cfa0ad2SJack F Vogel 	/* Can't read flash registers if the register set isn't mapped. */
624*8cc64f1eSJack F Vogel 	nvm->type = e1000_nvm_flash_sw;
6258cfa0ad2SJack F Vogel 	if (!hw->flash_address) {
6268cfa0ad2SJack F Vogel 		DEBUGOUT("ERROR: Flash registers not mapped\n");
6276ab6bfe3SJack F Vogel 		return -E1000_ERR_CONFIG;
6288cfa0ad2SJack F Vogel 	}
6298cfa0ad2SJack F Vogel 
6308cfa0ad2SJack F Vogel 	gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG);
6318cfa0ad2SJack F Vogel 
6326ab6bfe3SJack F Vogel 	/* sector_X_addr is a "sector"-aligned address (4096 bytes)
6338cfa0ad2SJack F Vogel 	 * Add 1 to sector_end_addr since this sector is included in
6348cfa0ad2SJack F Vogel 	 * the overall size.
6358cfa0ad2SJack F Vogel 	 */
6368cfa0ad2SJack F Vogel 	sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
6378cfa0ad2SJack F Vogel 	sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
6388cfa0ad2SJack F Vogel 
6398cfa0ad2SJack F Vogel 	/* flash_base_addr is byte-aligned */
6408cfa0ad2SJack F Vogel 	nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
6418cfa0ad2SJack F Vogel 
6426ab6bfe3SJack F Vogel 	/* find total size of the NVM, then cut in half since the total
6438cfa0ad2SJack F Vogel 	 * size represents two separate NVM banks.
6448cfa0ad2SJack F Vogel 	 */
6457609433eSJack F Vogel 	nvm->flash_bank_size = ((sector_end_addr - sector_base_addr)
6467609433eSJack F Vogel 				<< FLASH_SECTOR_ADDR_SHIFT);
6478cfa0ad2SJack F Vogel 	nvm->flash_bank_size /= 2;
6488cfa0ad2SJack F Vogel 	/* Adjust to word count */
6498cfa0ad2SJack F Vogel 	nvm->flash_bank_size /= sizeof(u16);
6508cfa0ad2SJack F Vogel 
6518cfa0ad2SJack F Vogel 	nvm->word_size = E1000_SHADOW_RAM_WORDS;
6528cfa0ad2SJack F Vogel 
6538cfa0ad2SJack F Vogel 	/* Clear shadow ram */
6548cfa0ad2SJack F Vogel 	for (i = 0; i < nvm->word_size; i++) {
6558cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].modified = FALSE;
6568cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].value    = 0xFFFF;
6578cfa0ad2SJack F Vogel 	}
6588cfa0ad2SJack F Vogel 
6594edd8523SJack F Vogel 	E1000_MUTEX_INIT(&dev_spec->nvm_mutex);
6604edd8523SJack F Vogel 	E1000_MUTEX_INIT(&dev_spec->swflag_mutex);
6614edd8523SJack F Vogel 
6628cfa0ad2SJack F Vogel 	/* Function Pointers */
6634edd8523SJack F Vogel 	nvm->ops.acquire	= e1000_acquire_nvm_ich8lan;
6644edd8523SJack F Vogel 	nvm->ops.release	= e1000_release_nvm_ich8lan;
6658cfa0ad2SJack F Vogel 	nvm->ops.read		= e1000_read_nvm_ich8lan;
6668cfa0ad2SJack F Vogel 	nvm->ops.update		= e1000_update_nvm_checksum_ich8lan;
6678cfa0ad2SJack F Vogel 	nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan;
6688cfa0ad2SJack F Vogel 	nvm->ops.validate	= e1000_validate_nvm_checksum_ich8lan;
6698cfa0ad2SJack F Vogel 	nvm->ops.write		= e1000_write_nvm_ich8lan;
6708cfa0ad2SJack F Vogel 
6716ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
6728cfa0ad2SJack F Vogel }
6738cfa0ad2SJack F Vogel 
6748cfa0ad2SJack F Vogel /**
6758cfa0ad2SJack F Vogel  *  e1000_init_mac_params_ich8lan - Initialize MAC function pointers
6768cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
6778cfa0ad2SJack F Vogel  *
6788cfa0ad2SJack F Vogel  *  Initialize family-specific MAC parameters and function
6798cfa0ad2SJack F Vogel  *  pointers.
6808cfa0ad2SJack F Vogel  **/
6818cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
6828cfa0ad2SJack F Vogel {
6838cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
684*8cc64f1eSJack F Vogel #if defined(QV_RELEASE) || !defined(NO_PCH_LPT_B0_SUPPORT)
685*8cc64f1eSJack F Vogel 	u16 pci_cfg;
686*8cc64f1eSJack F Vogel #endif /* QV_RELEASE || !defined(NO_PCH_LPT_B0_SUPPORT) */
6878cfa0ad2SJack F Vogel 
6888cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_mac_params_ich8lan");
6898cfa0ad2SJack F Vogel 
6908cfa0ad2SJack F Vogel 	/* Set media type function pointer */
6918cfa0ad2SJack F Vogel 	hw->phy.media_type = e1000_media_type_copper;
6928cfa0ad2SJack F Vogel 
6938cfa0ad2SJack F Vogel 	/* Set mta register count */
6948cfa0ad2SJack F Vogel 	mac->mta_reg_count = 32;
6958cfa0ad2SJack F Vogel 	/* Set rar entry count */
6968cfa0ad2SJack F Vogel 	mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
6978cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
6988cfa0ad2SJack F Vogel 		mac->rar_entry_count--;
6998cfa0ad2SJack F Vogel 	/* Set if part includes ASF firmware */
7008cfa0ad2SJack F Vogel 	mac->asf_firmware_present = TRUE;
7018ec87fc5SJack F Vogel 	/* FWSM register */
7028ec87fc5SJack F Vogel 	mac->has_fwsm = TRUE;
7038ec87fc5SJack F Vogel 	/* ARC subsystem not supported */
7048ec87fc5SJack F Vogel 	mac->arc_subsystem_valid = FALSE;
7054edd8523SJack F Vogel 	/* Adaptive IFS supported */
7064edd8523SJack F Vogel 	mac->adaptive_ifs = TRUE;
7078cfa0ad2SJack F Vogel 
7088cfa0ad2SJack F Vogel 	/* Function pointers */
7098cfa0ad2SJack F Vogel 
7108cfa0ad2SJack F Vogel 	/* bus type/speed/width */
7118cfa0ad2SJack F Vogel 	mac->ops.get_bus_info = e1000_get_bus_info_ich8lan;
712daf9197cSJack F Vogel 	/* function id */
713daf9197cSJack F Vogel 	mac->ops.set_lan_id = e1000_set_lan_id_single_port;
7148cfa0ad2SJack F Vogel 	/* reset */
7158cfa0ad2SJack F Vogel 	mac->ops.reset_hw = e1000_reset_hw_ich8lan;
7168cfa0ad2SJack F Vogel 	/* hw initialization */
7178cfa0ad2SJack F Vogel 	mac->ops.init_hw = e1000_init_hw_ich8lan;
7188cfa0ad2SJack F Vogel 	/* link setup */
7198cfa0ad2SJack F Vogel 	mac->ops.setup_link = e1000_setup_link_ich8lan;
7208cfa0ad2SJack F Vogel 	/* physical interface setup */
7218cfa0ad2SJack F Vogel 	mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan;
7228cfa0ad2SJack F Vogel 	/* check for link */
7234edd8523SJack F Vogel 	mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan;
7248cfa0ad2SJack F Vogel 	/* link info */
7258cfa0ad2SJack F Vogel 	mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan;
7268cfa0ad2SJack F Vogel 	/* multicast address update */
7278cfa0ad2SJack F Vogel 	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
728d035aa2dSJack F Vogel 	/* clear hardware counters */
729d035aa2dSJack F Vogel 	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan;
730d035aa2dSJack F Vogel 
7316ab6bfe3SJack F Vogel 	/* LED and other operations */
732d035aa2dSJack F Vogel 	switch (mac->type) {
733d035aa2dSJack F Vogel 	case e1000_ich8lan:
734d035aa2dSJack F Vogel 	case e1000_ich9lan:
735d035aa2dSJack F Vogel 	case e1000_ich10lan:
7367d9119bdSJack F Vogel 		/* check management mode */
7377d9119bdSJack F Vogel 		mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
738d035aa2dSJack F Vogel 		/* ID LED init */
739d035aa2dSJack F Vogel 		mac->ops.id_led_init = e1000_id_led_init_generic;
7408cfa0ad2SJack F Vogel 		/* blink LED */
7418cfa0ad2SJack F Vogel 		mac->ops.blink_led = e1000_blink_led_generic;
7428cfa0ad2SJack F Vogel 		/* setup LED */
7438cfa0ad2SJack F Vogel 		mac->ops.setup_led = e1000_setup_led_generic;
7448cfa0ad2SJack F Vogel 		/* cleanup LED */
7458cfa0ad2SJack F Vogel 		mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
7468cfa0ad2SJack F Vogel 		/* turn on/off LED */
7478cfa0ad2SJack F Vogel 		mac->ops.led_on = e1000_led_on_ich8lan;
7488cfa0ad2SJack F Vogel 		mac->ops.led_off = e1000_led_off_ich8lan;
749d035aa2dSJack F Vogel 		break;
7507d9119bdSJack F Vogel 	case e1000_pch2lan:
7517d9119bdSJack F Vogel 		mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES;
7527d9119bdSJack F Vogel 		mac->ops.rar_set = e1000_rar_set_pch2lan;
7536ab6bfe3SJack F Vogel 		/* fall-through */
7546ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
755730d3130SJack F Vogel 		/* multicast address update for pch2 */
756730d3130SJack F Vogel 		mac->ops.update_mc_addr_list =
757730d3130SJack F Vogel 			e1000_update_mc_addr_list_pch2lan;
7589d81738fSJack F Vogel 	case e1000_pchlan:
759*8cc64f1eSJack F Vogel #if defined(QV_RELEASE) || !defined(NO_PCH_LPT_B0_SUPPORT)
760*8cc64f1eSJack F Vogel 		/* save PCH revision_id */
761*8cc64f1eSJack F Vogel 		e1000_read_pci_cfg(hw, E1000_PCI_REVISION_ID_REG, &pci_cfg);
762*8cc64f1eSJack F Vogel 		hw->revision_id = (u8)(pci_cfg &= 0x000F);
763*8cc64f1eSJack F Vogel #endif /* QV_RELEASE || !defined(NO_PCH_LPT_B0_SUPPORT) */
7647d9119bdSJack F Vogel 		/* check management mode */
7657d9119bdSJack F Vogel 		mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
7669d81738fSJack F Vogel 		/* ID LED init */
7679d81738fSJack F Vogel 		mac->ops.id_led_init = e1000_id_led_init_pchlan;
7689d81738fSJack F Vogel 		/* setup LED */
7699d81738fSJack F Vogel 		mac->ops.setup_led = e1000_setup_led_pchlan;
7709d81738fSJack F Vogel 		/* cleanup LED */
7719d81738fSJack F Vogel 		mac->ops.cleanup_led = e1000_cleanup_led_pchlan;
7729d81738fSJack F Vogel 		/* turn on/off LED */
7739d81738fSJack F Vogel 		mac->ops.led_on = e1000_led_on_pchlan;
7749d81738fSJack F Vogel 		mac->ops.led_off = e1000_led_off_pchlan;
7759d81738fSJack F Vogel 		break;
776d035aa2dSJack F Vogel 	default:
777d035aa2dSJack F Vogel 		break;
778d035aa2dSJack F Vogel 	}
7798cfa0ad2SJack F Vogel 
7804dab5c37SJack F Vogel 	if (mac->type == e1000_pch_lpt) {
7816ab6bfe3SJack F Vogel 		mac->rar_entry_count = E1000_PCH_LPT_RAR_ENTRIES;
7826ab6bfe3SJack F Vogel 		mac->ops.rar_set = e1000_rar_set_pch_lpt;
7836ab6bfe3SJack F Vogel 		mac->ops.setup_physical_interface = e1000_setup_copper_link_pch_lpt;
7846ab6bfe3SJack F Vogel 		mac->ops.set_obff_timer = e1000_set_obff_timer_pch_lpt;
7854dab5c37SJack F Vogel 	}
7864dab5c37SJack F Vogel 
7878cfa0ad2SJack F Vogel 	/* Enable PCS Lock-loss workaround for ICH8 */
7888cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
7898cfa0ad2SJack F Vogel 		e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE);
7908cfa0ad2SJack F Vogel 
791daf9197cSJack F Vogel 	return E1000_SUCCESS;
7928cfa0ad2SJack F Vogel }
7938cfa0ad2SJack F Vogel 
7948cfa0ad2SJack F Vogel /**
7956ab6bfe3SJack F Vogel  *  __e1000_access_emi_reg_locked - Read/write EMI register
7966ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
7976ab6bfe3SJack F Vogel  *  @addr: EMI address to program
7986ab6bfe3SJack F Vogel  *  @data: pointer to value to read/write from/to the EMI address
7996ab6bfe3SJack F Vogel  *  @read: boolean flag to indicate read or write
8006ab6bfe3SJack F Vogel  *
8016ab6bfe3SJack F Vogel  *  This helper function assumes the SW/FW/HW Semaphore is already acquired.
8026ab6bfe3SJack F Vogel  **/
8036ab6bfe3SJack F Vogel static s32 __e1000_access_emi_reg_locked(struct e1000_hw *hw, u16 address,
8046ab6bfe3SJack F Vogel 					 u16 *data, bool read)
8056ab6bfe3SJack F Vogel {
8066ab6bfe3SJack F Vogel 	s32 ret_val;
8076ab6bfe3SJack F Vogel 
8086ab6bfe3SJack F Vogel 	DEBUGFUNC("__e1000_access_emi_reg_locked");
8096ab6bfe3SJack F Vogel 
8106ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR, address);
8116ab6bfe3SJack F Vogel 	if (ret_val)
8126ab6bfe3SJack F Vogel 		return ret_val;
8136ab6bfe3SJack F Vogel 
8146ab6bfe3SJack F Vogel 	if (read)
8156ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.read_reg_locked(hw, I82579_EMI_DATA,
8166ab6bfe3SJack F Vogel 						      data);
8176ab6bfe3SJack F Vogel 	else
8186ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_DATA,
8196ab6bfe3SJack F Vogel 						       *data);
8206ab6bfe3SJack F Vogel 
8216ab6bfe3SJack F Vogel 	return ret_val;
8226ab6bfe3SJack F Vogel }
8236ab6bfe3SJack F Vogel 
8246ab6bfe3SJack F Vogel /**
8256ab6bfe3SJack F Vogel  *  e1000_read_emi_reg_locked - Read Extended Management Interface register
8266ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
8276ab6bfe3SJack F Vogel  *  @addr: EMI address to program
8286ab6bfe3SJack F Vogel  *  @data: value to be read from the EMI address
8296ab6bfe3SJack F Vogel  *
8306ab6bfe3SJack F Vogel  *  Assumes the SW/FW/HW Semaphore is already acquired.
8316ab6bfe3SJack F Vogel  **/
8326ab6bfe3SJack F Vogel s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data)
8336ab6bfe3SJack F Vogel {
8346ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_read_emi_reg_locked");
8356ab6bfe3SJack F Vogel 
8366ab6bfe3SJack F Vogel 	return __e1000_access_emi_reg_locked(hw, addr, data, TRUE);
8376ab6bfe3SJack F Vogel }
8386ab6bfe3SJack F Vogel 
8396ab6bfe3SJack F Vogel /**
8406ab6bfe3SJack F Vogel  *  e1000_write_emi_reg_locked - Write Extended Management Interface register
8416ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
8426ab6bfe3SJack F Vogel  *  @addr: EMI address to program
8436ab6bfe3SJack F Vogel  *  @data: value to be written to the EMI address
8446ab6bfe3SJack F Vogel  *
8456ab6bfe3SJack F Vogel  *  Assumes the SW/FW/HW Semaphore is already acquired.
8466ab6bfe3SJack F Vogel  **/
8477609433eSJack F Vogel s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
8486ab6bfe3SJack F Vogel {
8496ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_read_emi_reg_locked");
8506ab6bfe3SJack F Vogel 
8516ab6bfe3SJack F Vogel 	return __e1000_access_emi_reg_locked(hw, addr, &data, FALSE);
8526ab6bfe3SJack F Vogel }
8536ab6bfe3SJack F Vogel 
8546ab6bfe3SJack F Vogel /**
8557d9119bdSJack F Vogel  *  e1000_set_eee_pchlan - Enable/disable EEE support
8567d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
8577d9119bdSJack F Vogel  *
8586ab6bfe3SJack F Vogel  *  Enable/disable EEE based on setting in dev_spec structure, the duplex of
8596ab6bfe3SJack F Vogel  *  the link and the EEE capabilities of the link partner.  The LPI Control
8606ab6bfe3SJack F Vogel  *  register bits will remain set only if/when link is up.
8617609433eSJack F Vogel  *
8627609433eSJack F Vogel  *  EEE LPI must not be asserted earlier than one second after link is up.
8637609433eSJack F Vogel  *  On 82579, EEE LPI should not be enabled until such time otherwise there
8647609433eSJack F Vogel  *  can be link issues with some switches.  Other devices can have EEE LPI
8657609433eSJack F Vogel  *  enabled immediately upon link up since they have a timer in hardware which
8667609433eSJack F Vogel  *  prevents LPI from being asserted too early.
8677d9119bdSJack F Vogel  **/
8687609433eSJack F Vogel s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
8697d9119bdSJack F Vogel {
8704dab5c37SJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
8716ab6bfe3SJack F Vogel 	s32 ret_val;
8727609433eSJack F Vogel 	u16 lpa, pcs_status, adv, adv_addr, lpi_ctrl, data;
8737d9119bdSJack F Vogel 
8747d9119bdSJack F Vogel 	DEBUGFUNC("e1000_set_eee_pchlan");
8757d9119bdSJack F Vogel 
8767609433eSJack F Vogel 	switch (hw->phy.type) {
8777609433eSJack F Vogel 	case e1000_phy_82579:
8787609433eSJack F Vogel 		lpa = I82579_EEE_LP_ABILITY;
8797609433eSJack F Vogel 		pcs_status = I82579_EEE_PCS_STATUS;
8807609433eSJack F Vogel 		adv_addr = I82579_EEE_ADVERTISEMENT;
8817609433eSJack F Vogel 		break;
8827609433eSJack F Vogel 	case e1000_phy_i217:
8837609433eSJack F Vogel 		lpa = I217_EEE_LP_ABILITY;
8847609433eSJack F Vogel 		pcs_status = I217_EEE_PCS_STATUS;
8857609433eSJack F Vogel 		adv_addr = I217_EEE_ADVERTISEMENT;
8867609433eSJack F Vogel 		break;
8877609433eSJack F Vogel 	default:
8886ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
8897609433eSJack F Vogel 	}
8907d9119bdSJack F Vogel 
8916ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
8927d9119bdSJack F Vogel 	if (ret_val)
8937d9119bdSJack F Vogel 		return ret_val;
8946ab6bfe3SJack F Vogel 
8956ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw, I82579_LPI_CTRL, &lpi_ctrl);
8966ab6bfe3SJack F Vogel 	if (ret_val)
8976ab6bfe3SJack F Vogel 		goto release;
8986ab6bfe3SJack F Vogel 
8996ab6bfe3SJack F Vogel 	/* Clear bits that enable EEE in various speeds */
9006ab6bfe3SJack F Vogel 	lpi_ctrl &= ~I82579_LPI_CTRL_ENABLE_MASK;
9016ab6bfe3SJack F Vogel 
9026ab6bfe3SJack F Vogel 	/* Enable EEE if not disabled by user */
9036ab6bfe3SJack F Vogel 	if (!dev_spec->eee_disable) {
9046ab6bfe3SJack F Vogel 		/* Save off link partner's EEE ability */
9056ab6bfe3SJack F Vogel 		ret_val = e1000_read_emi_reg_locked(hw, lpa,
9066ab6bfe3SJack F Vogel 						    &dev_spec->eee_lp_ability);
9076ab6bfe3SJack F Vogel 		if (ret_val)
9086ab6bfe3SJack F Vogel 			goto release;
9096ab6bfe3SJack F Vogel 
9107609433eSJack F Vogel 		/* Read EEE advertisement */
9117609433eSJack F Vogel 		ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &adv);
9127609433eSJack F Vogel 		if (ret_val)
9137609433eSJack F Vogel 			goto release;
9147609433eSJack F Vogel 
9156ab6bfe3SJack F Vogel 		/* Enable EEE only for speeds in which the link partner is
9167609433eSJack F Vogel 		 * EEE capable and for which we advertise EEE.
9176ab6bfe3SJack F Vogel 		 */
9187609433eSJack F Vogel 		if (adv & dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED)
9196ab6bfe3SJack F Vogel 			lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE;
9206ab6bfe3SJack F Vogel 
9217609433eSJack F Vogel 		if (adv & dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) {
9226ab6bfe3SJack F Vogel 			hw->phy.ops.read_reg_locked(hw, PHY_LP_ABILITY, &data);
9236ab6bfe3SJack F Vogel 			if (data & NWAY_LPAR_100TX_FD_CAPS)
9246ab6bfe3SJack F Vogel 				lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE;
9256ab6bfe3SJack F Vogel 			else
9266ab6bfe3SJack F Vogel 				/* EEE is not supported in 100Half, so ignore
9276ab6bfe3SJack F Vogel 				 * partner's EEE in 100 ability if full-duplex
9286ab6bfe3SJack F Vogel 				 * is not advertised.
9296ab6bfe3SJack F Vogel 				 */
9306ab6bfe3SJack F Vogel 				dev_spec->eee_lp_ability &=
9316ab6bfe3SJack F Vogel 				    ~I82579_EEE_100_SUPPORTED;
9326ab6bfe3SJack F Vogel 		}
9337609433eSJack F Vogel 	}
9346ab6bfe3SJack F Vogel 
935*8cc64f1eSJack F Vogel 	if (hw->phy.type == e1000_phy_82579) {
936*8cc64f1eSJack F Vogel 		ret_val = e1000_read_emi_reg_locked(hw, I82579_LPI_PLL_SHUT,
937*8cc64f1eSJack F Vogel 						    &data);
938*8cc64f1eSJack F Vogel 		if (ret_val)
939*8cc64f1eSJack F Vogel 			goto release;
940*8cc64f1eSJack F Vogel 
941*8cc64f1eSJack F Vogel 		data &= ~I82579_LPI_100_PLL_SHUT;
942*8cc64f1eSJack F Vogel 		ret_val = e1000_write_emi_reg_locked(hw, I82579_LPI_PLL_SHUT,
943*8cc64f1eSJack F Vogel 						     data);
944*8cc64f1eSJack F Vogel 	}
945*8cc64f1eSJack F Vogel 
9466ab6bfe3SJack F Vogel 	/* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */
9476ab6bfe3SJack F Vogel 	ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data);
9486ab6bfe3SJack F Vogel 	if (ret_val)
9496ab6bfe3SJack F Vogel 		goto release;
9506ab6bfe3SJack F Vogel 
9516ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, I82579_LPI_CTRL, lpi_ctrl);
9526ab6bfe3SJack F Vogel release:
9536ab6bfe3SJack F Vogel 	hw->phy.ops.release(hw);
9546ab6bfe3SJack F Vogel 
9556ab6bfe3SJack F Vogel 	return ret_val;
9566ab6bfe3SJack F Vogel }
9576ab6bfe3SJack F Vogel 
9586ab6bfe3SJack F Vogel /**
9596ab6bfe3SJack F Vogel  *  e1000_k1_workaround_lpt_lp - K1 workaround on Lynxpoint-LP
9606ab6bfe3SJack F Vogel  *  @hw:   pointer to the HW structure
9616ab6bfe3SJack F Vogel  *  @link: link up bool flag
9626ab6bfe3SJack F Vogel  *
9636ab6bfe3SJack F Vogel  *  When K1 is enabled for 1Gbps, the MAC can miss 2 DMA completion indications
9646ab6bfe3SJack F Vogel  *  preventing further DMA write requests.  Workaround the issue by disabling
9656ab6bfe3SJack F Vogel  *  the de-assertion of the clock request when in 1Gpbs mode.
9667609433eSJack F Vogel  *  Also, set appropriate Tx re-transmission timeouts for 10 and 100Half link
9677609433eSJack F Vogel  *  speeds in order to avoid Tx hangs.
9686ab6bfe3SJack F Vogel  **/
9696ab6bfe3SJack F Vogel static s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link)
9706ab6bfe3SJack F Vogel {
9716ab6bfe3SJack F Vogel 	u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6);
9727609433eSJack F Vogel 	u32 status = E1000_READ_REG(hw, E1000_STATUS);
9736ab6bfe3SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
9747609433eSJack F Vogel 	u16 reg;
9756ab6bfe3SJack F Vogel 
9767609433eSJack F Vogel 	if (link && (status & E1000_STATUS_SPEED_1000)) {
9776ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
9786ab6bfe3SJack F Vogel 		if (ret_val)
9796ab6bfe3SJack F Vogel 			return ret_val;
9806ab6bfe3SJack F Vogel 
9816ab6bfe3SJack F Vogel 		ret_val =
9826ab6bfe3SJack F Vogel 		    e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
9837609433eSJack F Vogel 					       &reg);
9846ab6bfe3SJack F Vogel 		if (ret_val)
9856ab6bfe3SJack F Vogel 			goto release;
9866ab6bfe3SJack F Vogel 
9876ab6bfe3SJack F Vogel 		ret_val =
9886ab6bfe3SJack F Vogel 		    e1000_write_kmrn_reg_locked(hw,
9896ab6bfe3SJack F Vogel 						E1000_KMRNCTRLSTA_K1_CONFIG,
9907609433eSJack F Vogel 						reg &
9916ab6bfe3SJack F Vogel 						~E1000_KMRNCTRLSTA_K1_ENABLE);
9926ab6bfe3SJack F Vogel 		if (ret_val)
9936ab6bfe3SJack F Vogel 			goto release;
9946ab6bfe3SJack F Vogel 
9956ab6bfe3SJack F Vogel 		usec_delay(10);
9966ab6bfe3SJack F Vogel 
9976ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_FEXTNVM6,
9986ab6bfe3SJack F Vogel 				fextnvm6 | E1000_FEXTNVM6_REQ_PLL_CLK);
9996ab6bfe3SJack F Vogel 
10006ab6bfe3SJack F Vogel 		ret_val =
10016ab6bfe3SJack F Vogel 		    e1000_write_kmrn_reg_locked(hw,
10026ab6bfe3SJack F Vogel 						E1000_KMRNCTRLSTA_K1_CONFIG,
10037609433eSJack F Vogel 						reg);
10046ab6bfe3SJack F Vogel release:
10056ab6bfe3SJack F Vogel 		hw->phy.ops.release(hw);
10066ab6bfe3SJack F Vogel 	} else {
10076ab6bfe3SJack F Vogel 		/* clear FEXTNVM6 bit 8 on link down or 10/100 */
10087609433eSJack F Vogel 		fextnvm6 &= ~E1000_FEXTNVM6_REQ_PLL_CLK;
10097609433eSJack F Vogel 
10107609433eSJack F Vogel 		if (!link || ((status & E1000_STATUS_SPEED_100) &&
10117609433eSJack F Vogel 			      (status & E1000_STATUS_FD)))
10127609433eSJack F Vogel 			goto update_fextnvm6;
10137609433eSJack F Vogel 
10147609433eSJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, I217_INBAND_CTRL, &reg);
10157609433eSJack F Vogel 		if (ret_val)
10167609433eSJack F Vogel 			return ret_val;
10177609433eSJack F Vogel 
10187609433eSJack F Vogel 		/* Clear link status transmit timeout */
10197609433eSJack F Vogel 		reg &= ~I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_MASK;
10207609433eSJack F Vogel 
10217609433eSJack F Vogel 		if (status & E1000_STATUS_SPEED_100) {
10227609433eSJack F Vogel 			/* Set inband Tx timeout to 5x10us for 100Half */
10237609433eSJack F Vogel 			reg |= 5 << I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT;
10247609433eSJack F Vogel 
10257609433eSJack F Vogel 			/* Do not extend the K1 entry latency for 100Half */
10267609433eSJack F Vogel 			fextnvm6 &= ~E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION;
10277609433eSJack F Vogel 		} else {
10287609433eSJack F Vogel 			/* Set inband Tx timeout to 50x10us for 10Full/Half */
10297609433eSJack F Vogel 			reg |= 50 <<
10307609433eSJack F Vogel 			       I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT;
10317609433eSJack F Vogel 
10327609433eSJack F Vogel 			/* Extend the K1 entry latency for 10 Mbps */
10337609433eSJack F Vogel 			fextnvm6 |= E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION;
10347609433eSJack F Vogel 		}
10357609433eSJack F Vogel 
10367609433eSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, I217_INBAND_CTRL, reg);
10377609433eSJack F Vogel 		if (ret_val)
10387609433eSJack F Vogel 			return ret_val;
10397609433eSJack F Vogel 
10407609433eSJack F Vogel update_fextnvm6:
10417609433eSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FEXTNVM6, fextnvm6);
10426ab6bfe3SJack F Vogel 	}
10436ab6bfe3SJack F Vogel 
10446ab6bfe3SJack F Vogel 	return ret_val;
10456ab6bfe3SJack F Vogel }
10466ab6bfe3SJack F Vogel 
10476ab6bfe3SJack F Vogel static u64 e1000_ltr2ns(u16 ltr)
10486ab6bfe3SJack F Vogel {
10496ab6bfe3SJack F Vogel 	u32 value, scale;
10506ab6bfe3SJack F Vogel 
10516ab6bfe3SJack F Vogel 	/* Determine the latency in nsec based on the LTR value & scale */
10526ab6bfe3SJack F Vogel 	value = ltr & E1000_LTRV_VALUE_MASK;
10536ab6bfe3SJack F Vogel 	scale = (ltr & E1000_LTRV_SCALE_MASK) >> E1000_LTRV_SCALE_SHIFT;
10546ab6bfe3SJack F Vogel 
10556ab6bfe3SJack F Vogel 	return value * (1 << (scale * E1000_LTRV_SCALE_FACTOR));
10566ab6bfe3SJack F Vogel }
10576ab6bfe3SJack F Vogel 
10586ab6bfe3SJack F Vogel /**
10596ab6bfe3SJack F Vogel  *  e1000_platform_pm_pch_lpt - Set platform power management values
10606ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
10616ab6bfe3SJack F Vogel  *  @link: bool indicating link status
10626ab6bfe3SJack F Vogel  *
10636ab6bfe3SJack F Vogel  *  Set the Latency Tolerance Reporting (LTR) values for the "PCIe-like"
10646ab6bfe3SJack F Vogel  *  GbE MAC in the Lynx Point PCH based on Rx buffer size and link speed
10656ab6bfe3SJack F Vogel  *  when link is up (which must not exceed the maximum latency supported
10666ab6bfe3SJack F Vogel  *  by the platform), otherwise specify there is no LTR requirement.
10676ab6bfe3SJack F Vogel  *  Unlike TRUE-PCIe devices which set the LTR maximum snoop/no-snoop
10686ab6bfe3SJack F Vogel  *  latencies in the LTR Extended Capability Structure in the PCIe Extended
10696ab6bfe3SJack F Vogel  *  Capability register set, on this device LTR is set by writing the
10706ab6bfe3SJack F Vogel  *  equivalent snoop/no-snoop latencies in the LTRV register in the MAC and
10716ab6bfe3SJack F Vogel  *  set the SEND bit to send an Intel On-chip System Fabric sideband (IOSF-SB)
10726ab6bfe3SJack F Vogel  *  message to the PMC.
10736ab6bfe3SJack F Vogel  *
10746ab6bfe3SJack F Vogel  *  Use the LTR value to calculate the Optimized Buffer Flush/Fill (OBFF)
10756ab6bfe3SJack F Vogel  *  high-water mark.
10766ab6bfe3SJack F Vogel  **/
10776ab6bfe3SJack F Vogel static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link)
10786ab6bfe3SJack F Vogel {
10796ab6bfe3SJack F Vogel 	u32 reg = link << (E1000_LTRV_REQ_SHIFT + E1000_LTRV_NOSNOOP_SHIFT) |
10806ab6bfe3SJack F Vogel 		  link << E1000_LTRV_REQ_SHIFT | E1000_LTRV_SEND;
10816ab6bfe3SJack F Vogel 	u16 lat_enc = 0;	/* latency encoded */
10826ab6bfe3SJack F Vogel 	s32 obff_hwm = 0;
10836ab6bfe3SJack F Vogel 
10846ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_platform_pm_pch_lpt");
10856ab6bfe3SJack F Vogel 
10866ab6bfe3SJack F Vogel 	if (link) {
10876ab6bfe3SJack F Vogel 		u16 speed, duplex, scale = 0;
10886ab6bfe3SJack F Vogel 		u16 max_snoop, max_nosnoop;
10896ab6bfe3SJack F Vogel 		u16 max_ltr_enc;	/* max LTR latency encoded */
10906ab6bfe3SJack F Vogel 		s64 lat_ns;		/* latency (ns) */
10916ab6bfe3SJack F Vogel 		s64 value;
10926ab6bfe3SJack F Vogel 		u32 rxa;
10936ab6bfe3SJack F Vogel 
10946ab6bfe3SJack F Vogel 		if (!hw->mac.max_frame_size) {
10956ab6bfe3SJack F Vogel 			DEBUGOUT("max_frame_size not set.\n");
10966ab6bfe3SJack F Vogel 			return -E1000_ERR_CONFIG;
10976ab6bfe3SJack F Vogel 		}
10986ab6bfe3SJack F Vogel 
10996ab6bfe3SJack F Vogel 		hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
11006ab6bfe3SJack F Vogel 		if (!speed) {
11016ab6bfe3SJack F Vogel 			DEBUGOUT("Speed not set.\n");
11026ab6bfe3SJack F Vogel 			return -E1000_ERR_CONFIG;
11036ab6bfe3SJack F Vogel 		}
11046ab6bfe3SJack F Vogel 
11056ab6bfe3SJack F Vogel 		/* Rx Packet Buffer Allocation size (KB) */
11066ab6bfe3SJack F Vogel 		rxa = E1000_READ_REG(hw, E1000_PBA) & E1000_PBA_RXA_MASK;
11076ab6bfe3SJack F Vogel 
11086ab6bfe3SJack F Vogel 		/* Determine the maximum latency tolerated by the device.
11096ab6bfe3SJack F Vogel 		 *
11106ab6bfe3SJack F Vogel 		 * Per the PCIe spec, the tolerated latencies are encoded as
11116ab6bfe3SJack F Vogel 		 * a 3-bit encoded scale (only 0-5 are valid) multiplied by
11126ab6bfe3SJack F Vogel 		 * a 10-bit value (0-1023) to provide a range from 1 ns to
11136ab6bfe3SJack F Vogel 		 * 2^25*(2^10-1) ns.  The scale is encoded as 0=2^0ns,
11146ab6bfe3SJack F Vogel 		 * 1=2^5ns, 2=2^10ns,...5=2^25ns.
11156ab6bfe3SJack F Vogel 		 */
11166ab6bfe3SJack F Vogel 		lat_ns = ((s64)rxa * 1024 -
11176ab6bfe3SJack F Vogel 			  (2 * (s64)hw->mac.max_frame_size)) * 8 * 1000;
11186ab6bfe3SJack F Vogel 		if (lat_ns < 0)
11196ab6bfe3SJack F Vogel 			lat_ns = 0;
11206ab6bfe3SJack F Vogel 		else
11216ab6bfe3SJack F Vogel 			lat_ns /= speed;
11226ab6bfe3SJack F Vogel 
11236ab6bfe3SJack F Vogel 		value = lat_ns;
11246ab6bfe3SJack F Vogel 		while (value > E1000_LTRV_VALUE_MASK) {
11256ab6bfe3SJack F Vogel 			scale++;
11266ab6bfe3SJack F Vogel 			value = E1000_DIVIDE_ROUND_UP(value, (1 << 5));
11276ab6bfe3SJack F Vogel 		}
11286ab6bfe3SJack F Vogel 		if (scale > E1000_LTRV_SCALE_MAX) {
11296ab6bfe3SJack F Vogel 			DEBUGOUT1("Invalid LTR latency scale %d\n", scale);
11306ab6bfe3SJack F Vogel 			return -E1000_ERR_CONFIG;
11316ab6bfe3SJack F Vogel 		}
11326ab6bfe3SJack F Vogel 		lat_enc = (u16)((scale << E1000_LTRV_SCALE_SHIFT) | value);
11336ab6bfe3SJack F Vogel 
11346ab6bfe3SJack F Vogel 		/* Determine the maximum latency tolerated by the platform */
11356ab6bfe3SJack F Vogel 		e1000_read_pci_cfg(hw, E1000_PCI_LTR_CAP_LPT, &max_snoop);
11366ab6bfe3SJack F Vogel 		e1000_read_pci_cfg(hw, E1000_PCI_LTR_CAP_LPT + 2, &max_nosnoop);
11376ab6bfe3SJack F Vogel 		max_ltr_enc = E1000_MAX(max_snoop, max_nosnoop);
11386ab6bfe3SJack F Vogel 
11396ab6bfe3SJack F Vogel 		if (lat_enc > max_ltr_enc) {
11406ab6bfe3SJack F Vogel 			lat_enc = max_ltr_enc;
11416ab6bfe3SJack F Vogel 			lat_ns = e1000_ltr2ns(max_ltr_enc);
11426ab6bfe3SJack F Vogel 		}
11436ab6bfe3SJack F Vogel 
11446ab6bfe3SJack F Vogel 		if (lat_ns) {
11456ab6bfe3SJack F Vogel 			lat_ns *= speed * 1000;
11466ab6bfe3SJack F Vogel 			lat_ns /= 8;
11476ab6bfe3SJack F Vogel 			lat_ns /= 1000000000;
11486ab6bfe3SJack F Vogel 			obff_hwm = (s32)(rxa - lat_ns);
11496ab6bfe3SJack F Vogel 		}
11506ab6bfe3SJack F Vogel 		if ((obff_hwm < 0) || (obff_hwm > E1000_SVT_OFF_HWM_MASK)) {
11516ab6bfe3SJack F Vogel 			DEBUGOUT1("Invalid high water mark %d\n", obff_hwm);
11526ab6bfe3SJack F Vogel 			return -E1000_ERR_CONFIG;
11536ab6bfe3SJack F Vogel 		}
11546ab6bfe3SJack F Vogel 	}
11556ab6bfe3SJack F Vogel 
11566ab6bfe3SJack F Vogel 	/* Set Snoop and No-Snoop latencies the same */
11576ab6bfe3SJack F Vogel 	reg |= lat_enc | (lat_enc << E1000_LTRV_NOSNOOP_SHIFT);
11586ab6bfe3SJack F Vogel 	E1000_WRITE_REG(hw, E1000_LTRV, reg);
11596ab6bfe3SJack F Vogel 
11606ab6bfe3SJack F Vogel 	/* Set OBFF high water mark */
11616ab6bfe3SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_SVT) & ~E1000_SVT_OFF_HWM_MASK;
11626ab6bfe3SJack F Vogel 	reg |= obff_hwm;
11636ab6bfe3SJack F Vogel 	E1000_WRITE_REG(hw, E1000_SVT, reg);
11646ab6bfe3SJack F Vogel 
11656ab6bfe3SJack F Vogel 	/* Enable OBFF */
11666ab6bfe3SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_SVCR);
11676ab6bfe3SJack F Vogel 	reg |= E1000_SVCR_OFF_EN;
11686ab6bfe3SJack F Vogel 	/* Always unblock interrupts to the CPU even when the system is
11696ab6bfe3SJack F Vogel 	 * in OBFF mode. This ensures that small round-robin traffic
11706ab6bfe3SJack F Vogel 	 * (like ping) does not get dropped or experience long latency.
11716ab6bfe3SJack F Vogel 	 */
11726ab6bfe3SJack F Vogel 	reg |= E1000_SVCR_OFF_MASKINT;
11736ab6bfe3SJack F Vogel 	E1000_WRITE_REG(hw, E1000_SVCR, reg);
11746ab6bfe3SJack F Vogel 
11756ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
11766ab6bfe3SJack F Vogel }
11776ab6bfe3SJack F Vogel 
11786ab6bfe3SJack F Vogel /**
11796ab6bfe3SJack F Vogel  *  e1000_set_obff_timer_pch_lpt - Update Optimized Buffer Flush/Fill timer
11806ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
11816ab6bfe3SJack F Vogel  *  @itr: interrupt throttling rate
11826ab6bfe3SJack F Vogel  *
11836ab6bfe3SJack F Vogel  *  Configure OBFF with the updated interrupt rate.
11846ab6bfe3SJack F Vogel  **/
11856ab6bfe3SJack F Vogel static s32 e1000_set_obff_timer_pch_lpt(struct e1000_hw *hw, u32 itr)
11866ab6bfe3SJack F Vogel {
11876ab6bfe3SJack F Vogel 	u32 svcr;
11886ab6bfe3SJack F Vogel 	s32 timer;
11896ab6bfe3SJack F Vogel 
11906ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_set_obff_timer_pch_lpt");
11916ab6bfe3SJack F Vogel 
11926ab6bfe3SJack F Vogel 	/* Convert ITR value into microseconds for OBFF timer */
11936ab6bfe3SJack F Vogel 	timer = itr & E1000_ITR_MASK;
11946ab6bfe3SJack F Vogel 	timer = (timer * E1000_ITR_MULT) / 1000;
11956ab6bfe3SJack F Vogel 
11966ab6bfe3SJack F Vogel 	if ((timer < 0) || (timer > E1000_ITR_MASK)) {
11976ab6bfe3SJack F Vogel 		DEBUGOUT1("Invalid OBFF timer %d\n", timer);
11986ab6bfe3SJack F Vogel 		return -E1000_ERR_CONFIG;
11996ab6bfe3SJack F Vogel 	}
12006ab6bfe3SJack F Vogel 
12016ab6bfe3SJack F Vogel 	svcr = E1000_READ_REG(hw, E1000_SVCR);
12026ab6bfe3SJack F Vogel 	svcr &= ~E1000_SVCR_OFF_TIMER_MASK;
12036ab6bfe3SJack F Vogel 	svcr |= timer << E1000_SVCR_OFF_TIMER_SHIFT;
12046ab6bfe3SJack F Vogel 	E1000_WRITE_REG(hw, E1000_SVCR, svcr);
12056ab6bfe3SJack F Vogel 
12066ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
12077d9119bdSJack F Vogel }
12087d9119bdSJack F Vogel 
12097d9119bdSJack F Vogel /**
1210*8cc64f1eSJack F Vogel  *  e1000_enable_ulp_lpt_lp - configure Ultra Low Power mode for LynxPoint-LP
1211*8cc64f1eSJack F Vogel  *  @hw: pointer to the HW structure
1212*8cc64f1eSJack F Vogel  *  @to_sx: boolean indicating a system power state transition to Sx
1213*8cc64f1eSJack F Vogel  *
1214*8cc64f1eSJack F Vogel  *  When link is down, configure ULP mode to significantly reduce the power
1215*8cc64f1eSJack F Vogel  *  to the PHY.  If on a Manageability Engine (ME) enabled system, tell the
1216*8cc64f1eSJack F Vogel  *  ME firmware to start the ULP configuration.  If not on an ME enabled
1217*8cc64f1eSJack F Vogel  *  system, configure the ULP mode by software.
1218*8cc64f1eSJack F Vogel  */
1219*8cc64f1eSJack F Vogel s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
1220*8cc64f1eSJack F Vogel {
1221*8cc64f1eSJack F Vogel 	u32 mac_reg;
1222*8cc64f1eSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
1223*8cc64f1eSJack F Vogel 	u16 phy_reg;
1224*8cc64f1eSJack F Vogel 
1225*8cc64f1eSJack F Vogel 	if ((hw->mac.type < e1000_pch_lpt) ||
1226*8cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) ||
1227*8cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V) ||
1228*8cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_LM2) ||
1229*8cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_V2) ||
1230*8cc64f1eSJack F Vogel 	    (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_on))
1231*8cc64f1eSJack F Vogel 		return 0;
1232*8cc64f1eSJack F Vogel 
1233*8cc64f1eSJack F Vogel 	if (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID) {
1234*8cc64f1eSJack F Vogel 		/* Request ME configure ULP mode in the PHY */
1235*8cc64f1eSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_H2ME);
1236*8cc64f1eSJack F Vogel 		mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS;
1237*8cc64f1eSJack F Vogel 		E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
1238*8cc64f1eSJack F Vogel 
1239*8cc64f1eSJack F Vogel 		goto out;
1240*8cc64f1eSJack F Vogel 	}
1241*8cc64f1eSJack F Vogel 
1242*8cc64f1eSJack F Vogel 	if (!to_sx) {
1243*8cc64f1eSJack F Vogel 		int i = 0;
1244*8cc64f1eSJack F Vogel 
1245*8cc64f1eSJack F Vogel 		/* Poll up to 5 seconds for Cable Disconnected indication */
1246*8cc64f1eSJack F Vogel 		while (!(E1000_READ_REG(hw, E1000_FEXT) &
1247*8cc64f1eSJack F Vogel 			 E1000_FEXT_PHY_CABLE_DISCONNECTED)) {
1248*8cc64f1eSJack F Vogel 			/* Bail if link is re-acquired */
1249*8cc64f1eSJack F Vogel 			if (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)
1250*8cc64f1eSJack F Vogel 				return -E1000_ERR_PHY;
1251*8cc64f1eSJack F Vogel 
1252*8cc64f1eSJack F Vogel 			if (i++ == 100)
1253*8cc64f1eSJack F Vogel 				break;
1254*8cc64f1eSJack F Vogel 
1255*8cc64f1eSJack F Vogel 			msec_delay(50);
1256*8cc64f1eSJack F Vogel 		}
1257*8cc64f1eSJack F Vogel 		DEBUGOUT2("CABLE_DISCONNECTED %s set after %dmsec\n",
1258*8cc64f1eSJack F Vogel 			 (E1000_READ_REG(hw, E1000_FEXT) &
1259*8cc64f1eSJack F Vogel 			  E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not",
1260*8cc64f1eSJack F Vogel 			 i * 50);
1261*8cc64f1eSJack F Vogel 	}
1262*8cc64f1eSJack F Vogel 
1263*8cc64f1eSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
1264*8cc64f1eSJack F Vogel 	if (ret_val)
1265*8cc64f1eSJack F Vogel 		goto out;
1266*8cc64f1eSJack F Vogel 
1267*8cc64f1eSJack F Vogel 	/* Force SMBus mode in PHY */
1268*8cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
1269*8cc64f1eSJack F Vogel 	if (ret_val)
1270*8cc64f1eSJack F Vogel 		goto release;
1271*8cc64f1eSJack F Vogel 	phy_reg |= CV_SMB_CTRL_FORCE_SMBUS;
1272*8cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
1273*8cc64f1eSJack F Vogel 
1274*8cc64f1eSJack F Vogel 	/* Force SMBus mode in MAC */
1275*8cc64f1eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
1276*8cc64f1eSJack F Vogel 	mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
1277*8cc64f1eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
1278*8cc64f1eSJack F Vogel 
1279*8cc64f1eSJack F Vogel 	/* Set Inband ULP Exit, Reset to SMBus mode and
1280*8cc64f1eSJack F Vogel 	 * Disable SMBus Release on PERST# in PHY
1281*8cc64f1eSJack F Vogel 	 */
1282*8cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
1283*8cc64f1eSJack F Vogel 	if (ret_val)
1284*8cc64f1eSJack F Vogel 		goto release;
1285*8cc64f1eSJack F Vogel 	phy_reg |= (I218_ULP_CONFIG1_RESET_TO_SMBUS |
1286*8cc64f1eSJack F Vogel 		    I218_ULP_CONFIG1_DISABLE_SMB_PERST);
1287*8cc64f1eSJack F Vogel 	if (to_sx) {
1288*8cc64f1eSJack F Vogel 		if (E1000_READ_REG(hw, E1000_WUFC) & E1000_WUFC_LNKC)
1289*8cc64f1eSJack F Vogel 			phy_reg |= I218_ULP_CONFIG1_WOL_HOST;
1290*8cc64f1eSJack F Vogel 
1291*8cc64f1eSJack F Vogel 		phy_reg |= I218_ULP_CONFIG1_STICKY_ULP;
1292*8cc64f1eSJack F Vogel 	} else {
1293*8cc64f1eSJack F Vogel 		phy_reg |= I218_ULP_CONFIG1_INBAND_EXIT;
1294*8cc64f1eSJack F Vogel 	}
1295*8cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
1296*8cc64f1eSJack F Vogel 
1297*8cc64f1eSJack F Vogel 	/* Set Disable SMBus Release on PERST# in MAC */
1298*8cc64f1eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM7);
1299*8cc64f1eSJack F Vogel 	mac_reg |= E1000_FEXTNVM7_DISABLE_SMB_PERST;
1300*8cc64f1eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_FEXTNVM7, mac_reg);
1301*8cc64f1eSJack F Vogel 
1302*8cc64f1eSJack F Vogel 	/* Commit ULP changes in PHY by starting auto ULP configuration */
1303*8cc64f1eSJack F Vogel 	phy_reg |= I218_ULP_CONFIG1_START;
1304*8cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
1305*8cc64f1eSJack F Vogel release:
1306*8cc64f1eSJack F Vogel 	hw->phy.ops.release(hw);
1307*8cc64f1eSJack F Vogel out:
1308*8cc64f1eSJack F Vogel 	if (ret_val)
1309*8cc64f1eSJack F Vogel 		DEBUGOUT1("Error in ULP enable flow: %d\n", ret_val);
1310*8cc64f1eSJack F Vogel 	else
1311*8cc64f1eSJack F Vogel 		hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_on;
1312*8cc64f1eSJack F Vogel 
1313*8cc64f1eSJack F Vogel 	return ret_val;
1314*8cc64f1eSJack F Vogel }
1315*8cc64f1eSJack F Vogel 
1316*8cc64f1eSJack F Vogel /**
1317*8cc64f1eSJack F Vogel  *  e1000_disable_ulp_lpt_lp - unconfigure Ultra Low Power mode for LynxPoint-LP
1318*8cc64f1eSJack F Vogel  *  @hw: pointer to the HW structure
1319*8cc64f1eSJack F Vogel  *  @force: boolean indicating whether or not to force disabling ULP
1320*8cc64f1eSJack F Vogel  *
1321*8cc64f1eSJack F Vogel  *  Un-configure ULP mode when link is up, the system is transitioned from
1322*8cc64f1eSJack F Vogel  *  Sx or the driver is unloaded.  If on a Manageability Engine (ME) enabled
1323*8cc64f1eSJack F Vogel  *  system, poll for an indication from ME that ULP has been un-configured.
1324*8cc64f1eSJack F Vogel  *  If not on an ME enabled system, un-configure the ULP mode by software.
1325*8cc64f1eSJack F Vogel  *
1326*8cc64f1eSJack F Vogel  *  During nominal operation, this function is called when link is acquired
1327*8cc64f1eSJack F Vogel  *  to disable ULP mode (force=FALSE); otherwise, for example when unloading
1328*8cc64f1eSJack F Vogel  *  the driver or during Sx->S0 transitions, this is called with force=TRUE
1329*8cc64f1eSJack F Vogel  *  to forcibly disable ULP.
1330*8cc64f1eSJack F Vogel  */
1331*8cc64f1eSJack F Vogel s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
1332*8cc64f1eSJack F Vogel {
1333*8cc64f1eSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
1334*8cc64f1eSJack F Vogel 	u32 mac_reg;
1335*8cc64f1eSJack F Vogel 	u16 phy_reg;
1336*8cc64f1eSJack F Vogel 	int i = 0;
1337*8cc64f1eSJack F Vogel 
1338*8cc64f1eSJack F Vogel 	if ((hw->mac.type < e1000_pch_lpt) ||
1339*8cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) ||
1340*8cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V) ||
1341*8cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_LM2) ||
1342*8cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_V2) ||
1343*8cc64f1eSJack F Vogel 	    (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_off))
1344*8cc64f1eSJack F Vogel 		return 0;
1345*8cc64f1eSJack F Vogel 
1346*8cc64f1eSJack F Vogel 	if (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID) {
1347*8cc64f1eSJack F Vogel 		if (force) {
1348*8cc64f1eSJack F Vogel 			/* Request ME un-configure ULP mode in the PHY */
1349*8cc64f1eSJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_H2ME);
1350*8cc64f1eSJack F Vogel 			mac_reg &= ~E1000_H2ME_ULP;
1351*8cc64f1eSJack F Vogel 			mac_reg |= E1000_H2ME_ENFORCE_SETTINGS;
1352*8cc64f1eSJack F Vogel 			E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
1353*8cc64f1eSJack F Vogel 		}
1354*8cc64f1eSJack F Vogel 
1355*8cc64f1eSJack F Vogel 		/* Poll up to 100msec for ME to clear ULP_CFG_DONE */
1356*8cc64f1eSJack F Vogel 		while (E1000_READ_REG(hw, E1000_FWSM) &
1357*8cc64f1eSJack F Vogel 		       E1000_FWSM_ULP_CFG_DONE) {
1358*8cc64f1eSJack F Vogel 			if (i++ == 10) {
1359*8cc64f1eSJack F Vogel 				ret_val = -E1000_ERR_PHY;
1360*8cc64f1eSJack F Vogel 				goto out;
1361*8cc64f1eSJack F Vogel 			}
1362*8cc64f1eSJack F Vogel 
1363*8cc64f1eSJack F Vogel 			msec_delay(10);
1364*8cc64f1eSJack F Vogel 		}
1365*8cc64f1eSJack F Vogel 		DEBUGOUT1("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10);
1366*8cc64f1eSJack F Vogel 
1367*8cc64f1eSJack F Vogel 		if (force) {
1368*8cc64f1eSJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_H2ME);
1369*8cc64f1eSJack F Vogel 			mac_reg &= ~E1000_H2ME_ENFORCE_SETTINGS;
1370*8cc64f1eSJack F Vogel 			E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
1371*8cc64f1eSJack F Vogel 		} else {
1372*8cc64f1eSJack F Vogel 			/* Clear H2ME.ULP after ME ULP configuration */
1373*8cc64f1eSJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_H2ME);
1374*8cc64f1eSJack F Vogel 			mac_reg &= ~E1000_H2ME_ULP;
1375*8cc64f1eSJack F Vogel 			E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
1376*8cc64f1eSJack F Vogel 		}
1377*8cc64f1eSJack F Vogel 
1378*8cc64f1eSJack F Vogel 		goto out;
1379*8cc64f1eSJack F Vogel 	}
1380*8cc64f1eSJack F Vogel 
1381*8cc64f1eSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
1382*8cc64f1eSJack F Vogel 	if (ret_val)
1383*8cc64f1eSJack F Vogel 		goto out;
1384*8cc64f1eSJack F Vogel 
1385*8cc64f1eSJack F Vogel 	if (force)
1386*8cc64f1eSJack F Vogel 		/* Toggle LANPHYPC Value bit */
1387*8cc64f1eSJack F Vogel 		e1000_toggle_lanphypc_pch_lpt(hw);
1388*8cc64f1eSJack F Vogel 
1389*8cc64f1eSJack F Vogel 	/* Unforce SMBus mode in PHY */
1390*8cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
1391*8cc64f1eSJack F Vogel 	if (ret_val) {
1392*8cc64f1eSJack F Vogel 		/* The MAC might be in PCIe mode, so temporarily force to
1393*8cc64f1eSJack F Vogel 		 * SMBus mode in order to access the PHY.
1394*8cc64f1eSJack F Vogel 		 */
1395*8cc64f1eSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
1396*8cc64f1eSJack F Vogel 		mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
1397*8cc64f1eSJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
1398*8cc64f1eSJack F Vogel 
1399*8cc64f1eSJack F Vogel 		msec_delay(50);
1400*8cc64f1eSJack F Vogel 
1401*8cc64f1eSJack F Vogel 		ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL,
1402*8cc64f1eSJack F Vogel 						       &phy_reg);
1403*8cc64f1eSJack F Vogel 		if (ret_val)
1404*8cc64f1eSJack F Vogel 			goto release;
1405*8cc64f1eSJack F Vogel 	}
1406*8cc64f1eSJack F Vogel 	phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
1407*8cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
1408*8cc64f1eSJack F Vogel 
1409*8cc64f1eSJack F Vogel 	/* Unforce SMBus mode in MAC */
1410*8cc64f1eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
1411*8cc64f1eSJack F Vogel 	mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
1412*8cc64f1eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
1413*8cc64f1eSJack F Vogel 
1414*8cc64f1eSJack F Vogel 	/* When ULP mode was previously entered, K1 was disabled by the
1415*8cc64f1eSJack F Vogel 	 * hardware.  Re-Enable K1 in the PHY when exiting ULP.
1416*8cc64f1eSJack F Vogel 	 */
1417*8cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, HV_PM_CTRL, &phy_reg);
1418*8cc64f1eSJack F Vogel 	if (ret_val)
1419*8cc64f1eSJack F Vogel 		goto release;
1420*8cc64f1eSJack F Vogel 	phy_reg |= HV_PM_CTRL_K1_ENABLE;
1421*8cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, HV_PM_CTRL, phy_reg);
1422*8cc64f1eSJack F Vogel 
1423*8cc64f1eSJack F Vogel 	/* Clear ULP enabled configuration */
1424*8cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
1425*8cc64f1eSJack F Vogel 	if (ret_val)
1426*8cc64f1eSJack F Vogel 		goto release;
1427*8cc64f1eSJack F Vogel 		phy_reg &= ~(I218_ULP_CONFIG1_IND |
1428*8cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_STICKY_ULP |
1429*8cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_RESET_TO_SMBUS |
1430*8cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_WOL_HOST |
1431*8cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_INBAND_EXIT |
1432*8cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_DISABLE_SMB_PERST);
1433*8cc64f1eSJack F Vogel 		e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
1434*8cc64f1eSJack F Vogel 
1435*8cc64f1eSJack F Vogel 		/* Commit ULP changes by starting auto ULP configuration */
1436*8cc64f1eSJack F Vogel 		phy_reg |= I218_ULP_CONFIG1_START;
1437*8cc64f1eSJack F Vogel 		e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
1438*8cc64f1eSJack F Vogel 
1439*8cc64f1eSJack F Vogel 		/* Clear Disable SMBus Release on PERST# in MAC */
1440*8cc64f1eSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM7);
1441*8cc64f1eSJack F Vogel 		mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST;
1442*8cc64f1eSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FEXTNVM7, mac_reg);
1443*8cc64f1eSJack F Vogel 
1444*8cc64f1eSJack F Vogel release:
1445*8cc64f1eSJack F Vogel 	hw->phy.ops.release(hw);
1446*8cc64f1eSJack F Vogel 	if (force) {
1447*8cc64f1eSJack F Vogel 		hw->phy.ops.reset(hw);
1448*8cc64f1eSJack F Vogel 		msec_delay(50);
1449*8cc64f1eSJack F Vogel 	}
1450*8cc64f1eSJack F Vogel out:
1451*8cc64f1eSJack F Vogel 	if (ret_val)
1452*8cc64f1eSJack F Vogel 		DEBUGOUT1("Error in ULP disable flow: %d\n", ret_val);
1453*8cc64f1eSJack F Vogel 	else
1454*8cc64f1eSJack F Vogel 		hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_off;
1455*8cc64f1eSJack F Vogel 
1456*8cc64f1eSJack F Vogel 	return ret_val;
1457*8cc64f1eSJack F Vogel }
1458*8cc64f1eSJack F Vogel 
1459*8cc64f1eSJack F Vogel /**
14604edd8523SJack F Vogel  *  e1000_check_for_copper_link_ich8lan - Check for link (Copper)
14614edd8523SJack F Vogel  *  @hw: pointer to the HW structure
14624edd8523SJack F Vogel  *
14634edd8523SJack F Vogel  *  Checks to see of the link status of the hardware has changed.  If a
14644edd8523SJack F Vogel  *  change in link status has been detected, then we read the PHY registers
14654edd8523SJack F Vogel  *  to get the current speed/duplex if link exists.
14664edd8523SJack F Vogel  **/
14674edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
14684edd8523SJack F Vogel {
14694edd8523SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
14704edd8523SJack F Vogel 	s32 ret_val;
14714edd8523SJack F Vogel 	bool link;
14724dab5c37SJack F Vogel 	u16 phy_reg;
14734edd8523SJack F Vogel 
14744edd8523SJack F Vogel 	DEBUGFUNC("e1000_check_for_copper_link_ich8lan");
14754edd8523SJack F Vogel 
14766ab6bfe3SJack F Vogel 	/* We only want to go out to the PHY registers to see if Auto-Neg
14774edd8523SJack F Vogel 	 * has completed and/or if our link status has changed.  The
14784edd8523SJack F Vogel 	 * get_link_status flag is set upon receiving a Link Status
14794edd8523SJack F Vogel 	 * Change or Rx Sequence Error interrupt.
14804edd8523SJack F Vogel 	 */
14816ab6bfe3SJack F Vogel 	if (!mac->get_link_status)
14826ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
14834edd8523SJack F Vogel 
14846ab6bfe3SJack F Vogel 		/* First we want to see if the MII Status Register reports
14854edd8523SJack F Vogel 		 * link.  If so, then we want to get the current speed/duplex
14864edd8523SJack F Vogel 		 * of the PHY.
14874edd8523SJack F Vogel 		 */
14884edd8523SJack F Vogel 		ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
14894edd8523SJack F Vogel 		if (ret_val)
14906ab6bfe3SJack F Vogel 			return ret_val;
14914edd8523SJack F Vogel 
14924edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan) {
14934edd8523SJack F Vogel 		ret_val = e1000_k1_gig_workaround_hv(hw, link);
14944edd8523SJack F Vogel 		if (ret_val)
14956ab6bfe3SJack F Vogel 			return ret_val;
14964edd8523SJack F Vogel 	}
14974edd8523SJack F Vogel 
1498*8cc64f1eSJack F Vogel 	/* When connected at 10Mbps half-duplex, some parts are excessively
14996ab6bfe3SJack F Vogel 	 * aggressive resulting in many collisions. To avoid this, increase
15006ab6bfe3SJack F Vogel 	 * the IPG and reduce Rx latency in the PHY.
15016ab6bfe3SJack F Vogel 	 */
1502*8cc64f1eSJack F Vogel 	if (((hw->mac.type == e1000_pch2lan) ||
1503*8cc64f1eSJack F Vogel 	     (hw->mac.type == e1000_pch_lpt)) && link) {
15046ab6bfe3SJack F Vogel 		u32 reg;
15056ab6bfe3SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_STATUS);
15066ab6bfe3SJack F Vogel 		if (!(reg & (E1000_STATUS_FD | E1000_STATUS_SPEED_MASK))) {
1507*8cc64f1eSJack F Vogel 			u16 emi_addr;
1508*8cc64f1eSJack F Vogel 
15096ab6bfe3SJack F Vogel 			reg = E1000_READ_REG(hw, E1000_TIPG);
15106ab6bfe3SJack F Vogel 			reg &= ~E1000_TIPG_IPGT_MASK;
15116ab6bfe3SJack F Vogel 			reg |= 0xFF;
15126ab6bfe3SJack F Vogel 			E1000_WRITE_REG(hw, E1000_TIPG, reg);
15136ab6bfe3SJack F Vogel 
15146ab6bfe3SJack F Vogel 			/* Reduce Rx latency in analog PHY */
15156ab6bfe3SJack F Vogel 			ret_val = hw->phy.ops.acquire(hw);
15166ab6bfe3SJack F Vogel 			if (ret_val)
15176ab6bfe3SJack F Vogel 				return ret_val;
15186ab6bfe3SJack F Vogel 
1519*8cc64f1eSJack F Vogel 			if (hw->mac.type == e1000_pch2lan)
1520*8cc64f1eSJack F Vogel 				emi_addr = I82579_RX_CONFIG;
1521*8cc64f1eSJack F Vogel 			else
1522*8cc64f1eSJack F Vogel 				emi_addr = I217_RX_CONFIG;
1523*8cc64f1eSJack F Vogel 			ret_val = e1000_write_emi_reg_locked(hw, emi_addr, 0);
15246ab6bfe3SJack F Vogel 
15256ab6bfe3SJack F Vogel 			hw->phy.ops.release(hw);
15266ab6bfe3SJack F Vogel 
15276ab6bfe3SJack F Vogel 			if (ret_val)
15286ab6bfe3SJack F Vogel 				return ret_val;
15296ab6bfe3SJack F Vogel 		}
15306ab6bfe3SJack F Vogel 	}
15316ab6bfe3SJack F Vogel 
15326ab6bfe3SJack F Vogel 	/* Work-around I218 hang issue */
15336ab6bfe3SJack F Vogel 	if ((hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
1534*8cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) ||
1535*8cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_LM3) ||
1536*8cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_V3)) {
15376ab6bfe3SJack F Vogel 		ret_val = e1000_k1_workaround_lpt_lp(hw, link);
15386ab6bfe3SJack F Vogel 		if (ret_val)
15396ab6bfe3SJack F Vogel 			return ret_val;
15406ab6bfe3SJack F Vogel 	}
15414dab5c37SJack F Vogel 	if (hw->mac.type == e1000_pch_lpt) {
15427609433eSJack F Vogel 		/* Set platform power management values for
15437609433eSJack F Vogel 		 * Latency Tolerance Reporting (LTR)
15447609433eSJack F Vogel 		 * Optimized Buffer Flush/Fill (OBFF)
15456ab6bfe3SJack F Vogel 		 */
15466ab6bfe3SJack F Vogel 		ret_val = e1000_platform_pm_pch_lpt(hw, link);
15476ab6bfe3SJack F Vogel 		if (ret_val)
15486ab6bfe3SJack F Vogel 			return ret_val;
15494dab5c37SJack F Vogel 	}
15504dab5c37SJack F Vogel 
15516ab6bfe3SJack F Vogel 	/* Clear link partner's EEE ability */
15526ab6bfe3SJack F Vogel 	hw->dev_spec.ich8lan.eee_lp_ability = 0;
15536ab6bfe3SJack F Vogel 
15544edd8523SJack F Vogel 	if (!link)
15556ab6bfe3SJack F Vogel 		return E1000_SUCCESS; /* No link detected */
15564edd8523SJack F Vogel 
15574edd8523SJack F Vogel 	mac->get_link_status = FALSE;
15584edd8523SJack F Vogel 
15594dab5c37SJack F Vogel 	switch (hw->mac.type) {
15604dab5c37SJack F Vogel 	case e1000_pch2lan:
15614dab5c37SJack F Vogel 		ret_val = e1000_k1_workaround_lv(hw);
15624dab5c37SJack F Vogel 		if (ret_val)
15636ab6bfe3SJack F Vogel 			return ret_val;
15644dab5c37SJack F Vogel 		/* fall-thru */
15654dab5c37SJack F Vogel 	case e1000_pchlan:
15664edd8523SJack F Vogel 		if (hw->phy.type == e1000_phy_82578) {
15674edd8523SJack F Vogel 			ret_val = e1000_link_stall_workaround_hv(hw);
15684edd8523SJack F Vogel 			if (ret_val)
15696ab6bfe3SJack F Vogel 				return ret_val;
15704edd8523SJack F Vogel 		}
15714edd8523SJack F Vogel 
15726ab6bfe3SJack F Vogel 		/* Workaround for PCHx parts in half-duplex:
15734dab5c37SJack F Vogel 		 * Set the number of preambles removed from the packet
15744dab5c37SJack F Vogel 		 * when it is passed from the PHY to the MAC to prevent
15754dab5c37SJack F Vogel 		 * the MAC from misinterpreting the packet type.
15764dab5c37SJack F Vogel 		 */
15774dab5c37SJack F Vogel 		hw->phy.ops.read_reg(hw, HV_KMRN_FIFO_CTRLSTA, &phy_reg);
15784dab5c37SJack F Vogel 		phy_reg &= ~HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK;
15794dab5c37SJack F Vogel 
15804dab5c37SJack F Vogel 		if ((E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_FD) !=
15814dab5c37SJack F Vogel 		    E1000_STATUS_FD)
15824dab5c37SJack F Vogel 			phy_reg |= (1 << HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT);
15834dab5c37SJack F Vogel 
15844dab5c37SJack F Vogel 		hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA, phy_reg);
15854dab5c37SJack F Vogel 		break;
15864dab5c37SJack F Vogel 	default:
15874dab5c37SJack F Vogel 		break;
15887d9119bdSJack F Vogel 	}
15897d9119bdSJack F Vogel 
15906ab6bfe3SJack F Vogel 	/* Check if there was DownShift, must be checked
15914edd8523SJack F Vogel 	 * immediately after link-up
15924edd8523SJack F Vogel 	 */
15934edd8523SJack F Vogel 	e1000_check_downshift_generic(hw);
15944edd8523SJack F Vogel 
15957d9119bdSJack F Vogel 	/* Enable/Disable EEE after link up */
15967609433eSJack F Vogel 	if (hw->phy.type > e1000_phy_82579) {
15977d9119bdSJack F Vogel 		ret_val = e1000_set_eee_pchlan(hw);
15987d9119bdSJack F Vogel 		if (ret_val)
15996ab6bfe3SJack F Vogel 			return ret_val;
16007609433eSJack F Vogel 	}
16017d9119bdSJack F Vogel 
16026ab6bfe3SJack F Vogel 	/* If we are forcing speed/duplex, then we simply return since
16034edd8523SJack F Vogel 	 * we have already determined whether we have link or not.
16044edd8523SJack F Vogel 	 */
16056ab6bfe3SJack F Vogel 	if (!mac->autoneg)
16066ab6bfe3SJack F Vogel 		return -E1000_ERR_CONFIG;
16074edd8523SJack F Vogel 
16086ab6bfe3SJack F Vogel 	/* Auto-Neg is enabled.  Auto Speed Detection takes care
16094edd8523SJack F Vogel 	 * of MAC speed/duplex configuration.  So we only need to
16104edd8523SJack F Vogel 	 * configure Collision Distance in the MAC.
16114edd8523SJack F Vogel 	 */
16126ab6bfe3SJack F Vogel 	mac->ops.config_collision_dist(hw);
16134edd8523SJack F Vogel 
16146ab6bfe3SJack F Vogel 	/* Configure Flow Control now that Auto-Neg has completed.
16154edd8523SJack F Vogel 	 * First, we need to restore the desired flow control
16164edd8523SJack F Vogel 	 * settings because we may have had to re-autoneg with a
16174edd8523SJack F Vogel 	 * different link partner.
16184edd8523SJack F Vogel 	 */
16194edd8523SJack F Vogel 	ret_val = e1000_config_fc_after_link_up_generic(hw);
16204edd8523SJack F Vogel 	if (ret_val)
16214edd8523SJack F Vogel 		DEBUGOUT("Error configuring flow control\n");
16224edd8523SJack F Vogel 
16234edd8523SJack F Vogel 	return ret_val;
16244edd8523SJack F Vogel }
16254edd8523SJack F Vogel 
16264edd8523SJack F Vogel /**
16278cfa0ad2SJack F Vogel  *  e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers
16288cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
16298cfa0ad2SJack F Vogel  *
16308cfa0ad2SJack F Vogel  *  Initialize family-specific function pointers for PHY, MAC, and NVM.
16318cfa0ad2SJack F Vogel  **/
16328cfa0ad2SJack F Vogel void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw)
16338cfa0ad2SJack F Vogel {
16348cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_function_pointers_ich8lan");
16358cfa0ad2SJack F Vogel 
16368cfa0ad2SJack F Vogel 	hw->mac.ops.init_params = e1000_init_mac_params_ich8lan;
16378cfa0ad2SJack F Vogel 	hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan;
16389d81738fSJack F Vogel 	switch (hw->mac.type) {
16399d81738fSJack F Vogel 	case e1000_ich8lan:
16409d81738fSJack F Vogel 	case e1000_ich9lan:
16419d81738fSJack F Vogel 	case e1000_ich10lan:
16428cfa0ad2SJack F Vogel 		hw->phy.ops.init_params = e1000_init_phy_params_ich8lan;
16439d81738fSJack F Vogel 		break;
16449d81738fSJack F Vogel 	case e1000_pchlan:
16457d9119bdSJack F Vogel 	case e1000_pch2lan:
16466ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
16479d81738fSJack F Vogel 		hw->phy.ops.init_params = e1000_init_phy_params_pchlan;
16489d81738fSJack F Vogel 		break;
16499d81738fSJack F Vogel 	default:
16509d81738fSJack F Vogel 		break;
16519d81738fSJack F Vogel 	}
16528cfa0ad2SJack F Vogel }
16538cfa0ad2SJack F Vogel 
16548cfa0ad2SJack F Vogel /**
16554edd8523SJack F Vogel  *  e1000_acquire_nvm_ich8lan - Acquire NVM mutex
16564edd8523SJack F Vogel  *  @hw: pointer to the HW structure
16574edd8523SJack F Vogel  *
16584edd8523SJack F Vogel  *  Acquires the mutex for performing NVM operations.
16594edd8523SJack F Vogel  **/
16604edd8523SJack F Vogel static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
16614edd8523SJack F Vogel {
16624edd8523SJack F Vogel 	DEBUGFUNC("e1000_acquire_nvm_ich8lan");
16634edd8523SJack F Vogel 
16644edd8523SJack F Vogel 	E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.nvm_mutex);
16654edd8523SJack F Vogel 
16664edd8523SJack F Vogel 	return E1000_SUCCESS;
16674edd8523SJack F Vogel }
16684edd8523SJack F Vogel 
16694edd8523SJack F Vogel /**
16704edd8523SJack F Vogel  *  e1000_release_nvm_ich8lan - Release NVM mutex
16714edd8523SJack F Vogel  *  @hw: pointer to the HW structure
16724edd8523SJack F Vogel  *
16734edd8523SJack F Vogel  *  Releases the mutex used while performing NVM operations.
16744edd8523SJack F Vogel  **/
16754edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
16764edd8523SJack F Vogel {
16774edd8523SJack F Vogel 	DEBUGFUNC("e1000_release_nvm_ich8lan");
16784edd8523SJack F Vogel 
16794edd8523SJack F Vogel 	E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.nvm_mutex);
16804edd8523SJack F Vogel 
16814edd8523SJack F Vogel 	return;
16824edd8523SJack F Vogel }
16834edd8523SJack F Vogel 
16844edd8523SJack F Vogel /**
16858cfa0ad2SJack F Vogel  *  e1000_acquire_swflag_ich8lan - Acquire software control flag
16868cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
16878cfa0ad2SJack F Vogel  *
16884edd8523SJack F Vogel  *  Acquires the software control flag for performing PHY and select
16894edd8523SJack F Vogel  *  MAC CSR accesses.
16908cfa0ad2SJack F Vogel  **/
16918cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
16928cfa0ad2SJack F Vogel {
16938cfa0ad2SJack F Vogel 	u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
16948cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
16958cfa0ad2SJack F Vogel 
16968cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_acquire_swflag_ich8lan");
16978cfa0ad2SJack F Vogel 
16984edd8523SJack F Vogel 	E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.swflag_mutex);
16994edd8523SJack F Vogel 
17008cfa0ad2SJack F Vogel 	while (timeout) {
17018cfa0ad2SJack F Vogel 		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
17024edd8523SJack F Vogel 		if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG))
17038cfa0ad2SJack F Vogel 			break;
17044edd8523SJack F Vogel 
17058cfa0ad2SJack F Vogel 		msec_delay_irq(1);
17068cfa0ad2SJack F Vogel 		timeout--;
17078cfa0ad2SJack F Vogel 	}
17088cfa0ad2SJack F Vogel 
17098cfa0ad2SJack F Vogel 	if (!timeout) {
17104dab5c37SJack F Vogel 		DEBUGOUT("SW has already locked the resource.\n");
17114edd8523SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
17124edd8523SJack F Vogel 		goto out;
17134edd8523SJack F Vogel 	}
17144edd8523SJack F Vogel 
17154edd8523SJack F Vogel 	timeout = SW_FLAG_TIMEOUT;
17164edd8523SJack F Vogel 
17174edd8523SJack F Vogel 	extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
17184edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
17194edd8523SJack F Vogel 
17204edd8523SJack F Vogel 	while (timeout) {
17214edd8523SJack F Vogel 		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
17224edd8523SJack F Vogel 		if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
17234edd8523SJack F Vogel 			break;
17244edd8523SJack F Vogel 
17254edd8523SJack F Vogel 		msec_delay_irq(1);
17264edd8523SJack F Vogel 		timeout--;
17274edd8523SJack F Vogel 	}
17284edd8523SJack F Vogel 
17294edd8523SJack F Vogel 	if (!timeout) {
17304dab5c37SJack F Vogel 		DEBUGOUT2("Failed to acquire the semaphore, FW or HW has it: FWSM=0x%8.8x EXTCNF_CTRL=0x%8.8x)\n",
17314dab5c37SJack F Vogel 			  E1000_READ_REG(hw, E1000_FWSM), extcnf_ctrl);
17328cfa0ad2SJack F Vogel 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
17338cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
17348cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
17358cfa0ad2SJack F Vogel 		goto out;
17368cfa0ad2SJack F Vogel 	}
17378cfa0ad2SJack F Vogel 
17388cfa0ad2SJack F Vogel out:
17394edd8523SJack F Vogel 	if (ret_val)
17404edd8523SJack F Vogel 		E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
17414edd8523SJack F Vogel 
17428cfa0ad2SJack F Vogel 	return ret_val;
17438cfa0ad2SJack F Vogel }
17448cfa0ad2SJack F Vogel 
17458cfa0ad2SJack F Vogel /**
17468cfa0ad2SJack F Vogel  *  e1000_release_swflag_ich8lan - Release software control flag
17478cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
17488cfa0ad2SJack F Vogel  *
17494edd8523SJack F Vogel  *  Releases the software control flag for performing PHY and select
17504edd8523SJack F Vogel  *  MAC CSR accesses.
17518cfa0ad2SJack F Vogel  **/
17528cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
17538cfa0ad2SJack F Vogel {
17548cfa0ad2SJack F Vogel 	u32 extcnf_ctrl;
17558cfa0ad2SJack F Vogel 
17568cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_release_swflag_ich8lan");
17578cfa0ad2SJack F Vogel 
17588cfa0ad2SJack F Vogel 	extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
1759730d3130SJack F Vogel 
1760730d3130SJack F Vogel 	if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) {
17618cfa0ad2SJack F Vogel 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
17628cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
1763730d3130SJack F Vogel 	} else {
1764730d3130SJack F Vogel 		DEBUGOUT("Semaphore unexpectedly released by sw/fw/hw\n");
1765730d3130SJack F Vogel 	}
17668cfa0ad2SJack F Vogel 
17674edd8523SJack F Vogel 	E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
17684edd8523SJack F Vogel 
17698cfa0ad2SJack F Vogel 	return;
17708cfa0ad2SJack F Vogel }
17718cfa0ad2SJack F Vogel 
17728cfa0ad2SJack F Vogel /**
17738cfa0ad2SJack F Vogel  *  e1000_check_mng_mode_ich8lan - Checks management mode
17748cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
17758cfa0ad2SJack F Vogel  *
17767d9119bdSJack F Vogel  *  This checks if the adapter has any manageability enabled.
17778cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by read/write
17788cfa0ad2SJack F Vogel  *  routines for the PHY and NVM parts.
17798cfa0ad2SJack F Vogel  **/
17808cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
17818cfa0ad2SJack F Vogel {
17828cfa0ad2SJack F Vogel 	u32 fwsm;
17838cfa0ad2SJack F Vogel 
17848cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_mng_mode_ich8lan");
17858cfa0ad2SJack F Vogel 
17868cfa0ad2SJack F Vogel 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
17878cfa0ad2SJack F Vogel 
1788*8cc64f1eSJack F Vogel 	return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
17897d9119bdSJack F Vogel 	       ((fwsm & E1000_FWSM_MODE_MASK) ==
1790*8cc64f1eSJack F Vogel 		(E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
17917d9119bdSJack F Vogel }
17927d9119bdSJack F Vogel 
17937d9119bdSJack F Vogel /**
17947d9119bdSJack F Vogel  *  e1000_check_mng_mode_pchlan - Checks management mode
17957d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
17967d9119bdSJack F Vogel  *
17977d9119bdSJack F Vogel  *  This checks if the adapter has iAMT enabled.
17987d9119bdSJack F Vogel  *  This is a function pointer entry point only called by read/write
17997d9119bdSJack F Vogel  *  routines for the PHY and NVM parts.
18007d9119bdSJack F Vogel  **/
18017d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw)
18027d9119bdSJack F Vogel {
18037d9119bdSJack F Vogel 	u32 fwsm;
18047d9119bdSJack F Vogel 
18057d9119bdSJack F Vogel 	DEBUGFUNC("e1000_check_mng_mode_pchlan");
18067d9119bdSJack F Vogel 
18077d9119bdSJack F Vogel 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
18087d9119bdSJack F Vogel 
18097d9119bdSJack F Vogel 	return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
18107d9119bdSJack F Vogel 	       (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
18117d9119bdSJack F Vogel }
18127d9119bdSJack F Vogel 
18137d9119bdSJack F Vogel /**
18147d9119bdSJack F Vogel  *  e1000_rar_set_pch2lan - Set receive address register
18157d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
18167d9119bdSJack F Vogel  *  @addr: pointer to the receive address
18177d9119bdSJack F Vogel  *  @index: receive address array register
18187d9119bdSJack F Vogel  *
18197d9119bdSJack F Vogel  *  Sets the receive address array register at index to the address passed
18207d9119bdSJack F Vogel  *  in by addr.  For 82579, RAR[0] is the base address register that is to
18217d9119bdSJack F Vogel  *  contain the MAC address but RAR[1-6] are reserved for manageability (ME).
18227d9119bdSJack F Vogel  *  Use SHRA[0-3] in place of those reserved for ME.
18237d9119bdSJack F Vogel  **/
1824*8cc64f1eSJack F Vogel static int e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index)
18257d9119bdSJack F Vogel {
18267d9119bdSJack F Vogel 	u32 rar_low, rar_high;
18277d9119bdSJack F Vogel 
18287d9119bdSJack F Vogel 	DEBUGFUNC("e1000_rar_set_pch2lan");
18297d9119bdSJack F Vogel 
18306ab6bfe3SJack F Vogel 	/* HW expects these in little endian so we reverse the byte order
18317d9119bdSJack F Vogel 	 * from network order (big endian) to little endian
18327d9119bdSJack F Vogel 	 */
18337d9119bdSJack F Vogel 	rar_low = ((u32) addr[0] |
18347d9119bdSJack F Vogel 		   ((u32) addr[1] << 8) |
18357d9119bdSJack F Vogel 		   ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
18367d9119bdSJack F Vogel 
18377d9119bdSJack F Vogel 	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
18387d9119bdSJack F Vogel 
18397d9119bdSJack F Vogel 	/* If MAC address zero, no need to set the AV bit */
18407d9119bdSJack F Vogel 	if (rar_low || rar_high)
18417d9119bdSJack F Vogel 		rar_high |= E1000_RAH_AV;
18427d9119bdSJack F Vogel 
18437d9119bdSJack F Vogel 	if (index == 0) {
18447d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
18457d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
18467d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
18477d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
1848*8cc64f1eSJack F Vogel 		return E1000_SUCCESS;
18497d9119bdSJack F Vogel 	}
18507d9119bdSJack F Vogel 
18517609433eSJack F Vogel 	/* RAR[1-6] are owned by manageability.  Skip those and program the
18527609433eSJack F Vogel 	 * next address into the SHRA register array.
18537609433eSJack F Vogel 	 */
1854*8cc64f1eSJack F Vogel 	if (index < (u32) (hw->mac.rar_entry_count)) {
18556ab6bfe3SJack F Vogel 		s32 ret_val;
18566ab6bfe3SJack F Vogel 
18576ab6bfe3SJack F Vogel 		ret_val = e1000_acquire_swflag_ich8lan(hw);
18586ab6bfe3SJack F Vogel 		if (ret_val)
18596ab6bfe3SJack F Vogel 			goto out;
18606ab6bfe3SJack F Vogel 
18617d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_SHRAL(index - 1), rar_low);
18627d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
18637d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_SHRAH(index - 1), rar_high);
18647d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
18657d9119bdSJack F Vogel 
18666ab6bfe3SJack F Vogel 		e1000_release_swflag_ich8lan(hw);
18676ab6bfe3SJack F Vogel 
18687d9119bdSJack F Vogel 		/* verify the register updates */
18697d9119bdSJack F Vogel 		if ((E1000_READ_REG(hw, E1000_SHRAL(index - 1)) == rar_low) &&
18707d9119bdSJack F Vogel 		    (E1000_READ_REG(hw, E1000_SHRAH(index - 1)) == rar_high))
1871*8cc64f1eSJack F Vogel 			return E1000_SUCCESS;
18727d9119bdSJack F Vogel 
18737d9119bdSJack F Vogel 		DEBUGOUT2("SHRA[%d] might be locked by ME - FWSM=0x%8.8x\n",
18747d9119bdSJack F Vogel 			 (index - 1), E1000_READ_REG(hw, E1000_FWSM));
18757d9119bdSJack F Vogel 	}
18767d9119bdSJack F Vogel 
18776ab6bfe3SJack F Vogel out:
18786ab6bfe3SJack F Vogel 	DEBUGOUT1("Failed to write receive address at index %d\n", index);
1879*8cc64f1eSJack F Vogel 	return -E1000_ERR_CONFIG;
18806ab6bfe3SJack F Vogel }
18816ab6bfe3SJack F Vogel 
18826ab6bfe3SJack F Vogel /**
18836ab6bfe3SJack F Vogel  *  e1000_rar_set_pch_lpt - Set receive address registers
18846ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
18856ab6bfe3SJack F Vogel  *  @addr: pointer to the receive address
18866ab6bfe3SJack F Vogel  *  @index: receive address array register
18876ab6bfe3SJack F Vogel  *
18886ab6bfe3SJack F Vogel  *  Sets the receive address register array at index to the address passed
18896ab6bfe3SJack F Vogel  *  in by addr. For LPT, RAR[0] is the base address register that is to
18906ab6bfe3SJack F Vogel  *  contain the MAC address. SHRA[0-10] are the shared receive address
18916ab6bfe3SJack F Vogel  *  registers that are shared between the Host and manageability engine (ME).
18926ab6bfe3SJack F Vogel  **/
1893*8cc64f1eSJack F Vogel static int e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index)
18946ab6bfe3SJack F Vogel {
18956ab6bfe3SJack F Vogel 	u32 rar_low, rar_high;
18966ab6bfe3SJack F Vogel 	u32 wlock_mac;
18976ab6bfe3SJack F Vogel 
18986ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_rar_set_pch_lpt");
18996ab6bfe3SJack F Vogel 
19006ab6bfe3SJack F Vogel 	/* HW expects these in little endian so we reverse the byte order
19016ab6bfe3SJack F Vogel 	 * from network order (big endian) to little endian
19026ab6bfe3SJack F Vogel 	 */
19036ab6bfe3SJack F Vogel 	rar_low = ((u32) addr[0] | ((u32) addr[1] << 8) |
19046ab6bfe3SJack F Vogel 		   ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
19056ab6bfe3SJack F Vogel 
19066ab6bfe3SJack F Vogel 	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
19076ab6bfe3SJack F Vogel 
19086ab6bfe3SJack F Vogel 	/* If MAC address zero, no need to set the AV bit */
19096ab6bfe3SJack F Vogel 	if (rar_low || rar_high)
19106ab6bfe3SJack F Vogel 		rar_high |= E1000_RAH_AV;
19116ab6bfe3SJack F Vogel 
19126ab6bfe3SJack F Vogel 	if (index == 0) {
19136ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
19146ab6bfe3SJack F Vogel 		E1000_WRITE_FLUSH(hw);
19156ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
19166ab6bfe3SJack F Vogel 		E1000_WRITE_FLUSH(hw);
1917*8cc64f1eSJack F Vogel 		return E1000_SUCCESS;
19186ab6bfe3SJack F Vogel 	}
19196ab6bfe3SJack F Vogel 
19206ab6bfe3SJack F Vogel 	/* The manageability engine (ME) can lock certain SHRAR registers that
19216ab6bfe3SJack F Vogel 	 * it is using - those registers are unavailable for use.
19226ab6bfe3SJack F Vogel 	 */
19236ab6bfe3SJack F Vogel 	if (index < hw->mac.rar_entry_count) {
19246ab6bfe3SJack F Vogel 		wlock_mac = E1000_READ_REG(hw, E1000_FWSM) &
19256ab6bfe3SJack F Vogel 			    E1000_FWSM_WLOCK_MAC_MASK;
19266ab6bfe3SJack F Vogel 		wlock_mac >>= E1000_FWSM_WLOCK_MAC_SHIFT;
19276ab6bfe3SJack F Vogel 
19286ab6bfe3SJack F Vogel 		/* Check if all SHRAR registers are locked */
19296ab6bfe3SJack F Vogel 		if (wlock_mac == 1)
19306ab6bfe3SJack F Vogel 			goto out;
19316ab6bfe3SJack F Vogel 
19326ab6bfe3SJack F Vogel 		if ((wlock_mac == 0) || (index <= wlock_mac)) {
19336ab6bfe3SJack F Vogel 			s32 ret_val;
19346ab6bfe3SJack F Vogel 
19356ab6bfe3SJack F Vogel 			ret_val = e1000_acquire_swflag_ich8lan(hw);
19366ab6bfe3SJack F Vogel 
19376ab6bfe3SJack F Vogel 			if (ret_val)
19386ab6bfe3SJack F Vogel 				goto out;
19396ab6bfe3SJack F Vogel 
19406ab6bfe3SJack F Vogel 			E1000_WRITE_REG(hw, E1000_SHRAL_PCH_LPT(index - 1),
19416ab6bfe3SJack F Vogel 					rar_low);
19426ab6bfe3SJack F Vogel 			E1000_WRITE_FLUSH(hw);
19436ab6bfe3SJack F Vogel 			E1000_WRITE_REG(hw, E1000_SHRAH_PCH_LPT(index - 1),
19446ab6bfe3SJack F Vogel 					rar_high);
19456ab6bfe3SJack F Vogel 			E1000_WRITE_FLUSH(hw);
19466ab6bfe3SJack F Vogel 
19476ab6bfe3SJack F Vogel 			e1000_release_swflag_ich8lan(hw);
19486ab6bfe3SJack F Vogel 
19496ab6bfe3SJack F Vogel 			/* verify the register updates */
19506ab6bfe3SJack F Vogel 			if ((E1000_READ_REG(hw, E1000_SHRAL_PCH_LPT(index - 1)) == rar_low) &&
19516ab6bfe3SJack F Vogel 			    (E1000_READ_REG(hw, E1000_SHRAH_PCH_LPT(index - 1)) == rar_high))
1952*8cc64f1eSJack F Vogel 				return E1000_SUCCESS;
19536ab6bfe3SJack F Vogel 		}
19546ab6bfe3SJack F Vogel 	}
19556ab6bfe3SJack F Vogel 
19566ab6bfe3SJack F Vogel out:
19577d9119bdSJack F Vogel 	DEBUGOUT1("Failed to write receive address at index %d\n", index);
1958*8cc64f1eSJack F Vogel 	return -E1000_ERR_CONFIG;
19598cfa0ad2SJack F Vogel }
19608cfa0ad2SJack F Vogel 
19618cfa0ad2SJack F Vogel /**
1962730d3130SJack F Vogel  *  e1000_update_mc_addr_list_pch2lan - Update Multicast addresses
1963730d3130SJack F Vogel  *  @hw: pointer to the HW structure
1964730d3130SJack F Vogel  *  @mc_addr_list: array of multicast addresses to program
1965730d3130SJack F Vogel  *  @mc_addr_count: number of multicast addresses to program
1966730d3130SJack F Vogel  *
1967730d3130SJack F Vogel  *  Updates entire Multicast Table Array of the PCH2 MAC and PHY.
1968730d3130SJack F Vogel  *  The caller must have a packed mc_addr_list of multicast addresses.
1969730d3130SJack F Vogel  **/
1970730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw,
1971730d3130SJack F Vogel 					      u8 *mc_addr_list,
1972730d3130SJack F Vogel 					      u32 mc_addr_count)
1973730d3130SJack F Vogel {
19744dab5c37SJack F Vogel 	u16 phy_reg = 0;
1975730d3130SJack F Vogel 	int i;
19764dab5c37SJack F Vogel 	s32 ret_val;
1977730d3130SJack F Vogel 
1978730d3130SJack F Vogel 	DEBUGFUNC("e1000_update_mc_addr_list_pch2lan");
1979730d3130SJack F Vogel 
1980730d3130SJack F Vogel 	e1000_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count);
1981730d3130SJack F Vogel 
19824dab5c37SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
19834dab5c37SJack F Vogel 	if (ret_val)
19844dab5c37SJack F Vogel 		return;
19854dab5c37SJack F Vogel 
19864dab5c37SJack F Vogel 	ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg);
19874dab5c37SJack F Vogel 	if (ret_val)
19884dab5c37SJack F Vogel 		goto release;
19894dab5c37SJack F Vogel 
1990730d3130SJack F Vogel 	for (i = 0; i < hw->mac.mta_reg_count; i++) {
19914dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_MTA(i),
19924dab5c37SJack F Vogel 					   (u16)(hw->mac.mta_shadow[i] &
19934dab5c37SJack F Vogel 						 0xFFFF));
19944dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, (BM_MTA(i) + 1),
1995730d3130SJack F Vogel 					   (u16)((hw->mac.mta_shadow[i] >> 16) &
1996730d3130SJack F Vogel 						 0xFFFF));
1997730d3130SJack F Vogel 	}
19984dab5c37SJack F Vogel 
19994dab5c37SJack F Vogel 	e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg);
20004dab5c37SJack F Vogel 
20014dab5c37SJack F Vogel release:
20024dab5c37SJack F Vogel 	hw->phy.ops.release(hw);
2003730d3130SJack F Vogel }
2004730d3130SJack F Vogel 
2005730d3130SJack F Vogel /**
20068cfa0ad2SJack F Vogel  *  e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
20078cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
20088cfa0ad2SJack F Vogel  *
20098cfa0ad2SJack F Vogel  *  Checks if firmware is blocking the reset of the PHY.
20108cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
20118cfa0ad2SJack F Vogel  *  reset routines.
20128cfa0ad2SJack F Vogel  **/
20138cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
20148cfa0ad2SJack F Vogel {
20158cfa0ad2SJack F Vogel 	u32 fwsm;
20167609433eSJack F Vogel 	bool blocked = FALSE;
20177609433eSJack F Vogel 	int i = 0;
20188cfa0ad2SJack F Vogel 
20198cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_reset_block_ich8lan");
20208cfa0ad2SJack F Vogel 
20217609433eSJack F Vogel 	do {
20228cfa0ad2SJack F Vogel 		fwsm = E1000_READ_REG(hw, E1000_FWSM);
20237609433eSJack F Vogel 		if (!(fwsm & E1000_ICH_FWSM_RSPCIPHY)) {
20247609433eSJack F Vogel 			blocked = TRUE;
20257609433eSJack F Vogel 			msec_delay(10);
20267609433eSJack F Vogel 			continue;
20277609433eSJack F Vogel 		}
20287609433eSJack F Vogel 		blocked = FALSE;
20297609433eSJack F Vogel 	} while (blocked && (i++ < 10));
20307609433eSJack F Vogel 	return blocked ? E1000_BLK_PHY_RESET : E1000_SUCCESS;
20318cfa0ad2SJack F Vogel }
20328cfa0ad2SJack F Vogel 
20338cfa0ad2SJack F Vogel /**
20347d9119bdSJack F Vogel  *  e1000_write_smbus_addr - Write SMBus address to PHY needed during Sx states
20357d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
20367d9119bdSJack F Vogel  *
20377d9119bdSJack F Vogel  *  Assumes semaphore already acquired.
20387d9119bdSJack F Vogel  *
20397d9119bdSJack F Vogel  **/
20407d9119bdSJack F Vogel static s32 e1000_write_smbus_addr(struct e1000_hw *hw)
20417d9119bdSJack F Vogel {
20427d9119bdSJack F Vogel 	u16 phy_data;
20437d9119bdSJack F Vogel 	u32 strap = E1000_READ_REG(hw, E1000_STRAP);
20446ab6bfe3SJack F Vogel 	u32 freq = (strap & E1000_STRAP_SMT_FREQ_MASK) >>
20456ab6bfe3SJack F Vogel 		E1000_STRAP_SMT_FREQ_SHIFT;
20466ab6bfe3SJack F Vogel 	s32 ret_val;
20477d9119bdSJack F Vogel 
20487d9119bdSJack F Vogel 	strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
20497d9119bdSJack F Vogel 
20507d9119bdSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, HV_SMB_ADDR, &phy_data);
20517d9119bdSJack F Vogel 	if (ret_val)
20526ab6bfe3SJack F Vogel 		return ret_val;
20537d9119bdSJack F Vogel 
20547d9119bdSJack F Vogel 	phy_data &= ~HV_SMB_ADDR_MASK;
20557d9119bdSJack F Vogel 	phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT);
20567d9119bdSJack F Vogel 	phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
20577d9119bdSJack F Vogel 
20586ab6bfe3SJack F Vogel 	if (hw->phy.type == e1000_phy_i217) {
20596ab6bfe3SJack F Vogel 		/* Restore SMBus frequency */
20606ab6bfe3SJack F Vogel 		if (freq--) {
20616ab6bfe3SJack F Vogel 			phy_data &= ~HV_SMB_ADDR_FREQ_MASK;
20626ab6bfe3SJack F Vogel 			phy_data |= (freq & (1 << 0)) <<
20636ab6bfe3SJack F Vogel 				HV_SMB_ADDR_FREQ_LOW_SHIFT;
20646ab6bfe3SJack F Vogel 			phy_data |= (freq & (1 << 1)) <<
20656ab6bfe3SJack F Vogel 				(HV_SMB_ADDR_FREQ_HIGH_SHIFT - 1);
20666ab6bfe3SJack F Vogel 		} else {
20676ab6bfe3SJack F Vogel 			DEBUGOUT("Unsupported SMB frequency in PHY\n");
20686ab6bfe3SJack F Vogel 		}
20696ab6bfe3SJack F Vogel 	}
20706ab6bfe3SJack F Vogel 
20716ab6bfe3SJack F Vogel 	return e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data);
20727d9119bdSJack F Vogel }
20737d9119bdSJack F Vogel 
20747d9119bdSJack F Vogel /**
20754edd8523SJack F Vogel  *  e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration
20764edd8523SJack F Vogel  *  @hw:   pointer to the HW structure
20774edd8523SJack F Vogel  *
20784edd8523SJack F Vogel  *  SW should configure the LCD from the NVM extended configuration region
20794edd8523SJack F Vogel  *  as a workaround for certain parts.
20804edd8523SJack F Vogel  **/
20814edd8523SJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
20824edd8523SJack F Vogel {
20834edd8523SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
20844edd8523SJack F Vogel 	u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
2085a69ed8dfSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
20864edd8523SJack F Vogel 	u16 word_addr, reg_data, reg_addr, phy_page = 0;
20874edd8523SJack F Vogel 
20887d9119bdSJack F Vogel 	DEBUGFUNC("e1000_sw_lcd_config_ich8lan");
20894edd8523SJack F Vogel 
20906ab6bfe3SJack F Vogel 	/* Initialize the PHY from the NVM on ICH platforms.  This
20914edd8523SJack F Vogel 	 * is needed due to an issue where the NVM configuration is
20924edd8523SJack F Vogel 	 * not properly autoloaded after power transitions.
20934edd8523SJack F Vogel 	 * Therefore, after each PHY reset, we will load the
20944edd8523SJack F Vogel 	 * configuration data out of the NVM manually.
20954edd8523SJack F Vogel 	 */
20967d9119bdSJack F Vogel 	switch (hw->mac.type) {
20977d9119bdSJack F Vogel 	case e1000_ich8lan:
20987d9119bdSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
20997d9119bdSJack F Vogel 			return ret_val;
21007d9119bdSJack F Vogel 
21017d9119bdSJack F Vogel 		if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_AMT) ||
21027d9119bdSJack F Vogel 		    (hw->device_id == E1000_DEV_ID_ICH8_IGP_C)) {
21034edd8523SJack F Vogel 			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
21047d9119bdSJack F Vogel 			break;
21057d9119bdSJack F Vogel 		}
21067d9119bdSJack F Vogel 		/* Fall-thru */
21077d9119bdSJack F Vogel 	case e1000_pchlan:
21087d9119bdSJack F Vogel 	case e1000_pch2lan:
21096ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
21107d9119bdSJack F Vogel 		sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
21117d9119bdSJack F Vogel 		break;
21127d9119bdSJack F Vogel 	default:
21137d9119bdSJack F Vogel 		return ret_val;
21147d9119bdSJack F Vogel 	}
21157d9119bdSJack F Vogel 
21167d9119bdSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
21177d9119bdSJack F Vogel 	if (ret_val)
21187d9119bdSJack F Vogel 		return ret_val;
21194edd8523SJack F Vogel 
21204edd8523SJack F Vogel 	data = E1000_READ_REG(hw, E1000_FEXTNVM);
21214edd8523SJack F Vogel 	if (!(data & sw_cfg_mask))
21226ab6bfe3SJack F Vogel 		goto release;
21234edd8523SJack F Vogel 
21246ab6bfe3SJack F Vogel 	/* Make sure HW does not configure LCD from PHY
21254edd8523SJack F Vogel 	 * extended configuration before SW configuration
21264edd8523SJack F Vogel 	 */
21274edd8523SJack F Vogel 	data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
21286ab6bfe3SJack F Vogel 	if ((hw->mac.type < e1000_pch2lan) &&
21296ab6bfe3SJack F Vogel 	    (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE))
21306ab6bfe3SJack F Vogel 			goto release;
21314edd8523SJack F Vogel 
21324edd8523SJack F Vogel 	cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE);
21334edd8523SJack F Vogel 	cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
21344edd8523SJack F Vogel 	cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
21354edd8523SJack F Vogel 	if (!cnf_size)
21366ab6bfe3SJack F Vogel 		goto release;
21374edd8523SJack F Vogel 
21384edd8523SJack F Vogel 	cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
21394edd8523SJack F Vogel 	cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
21404edd8523SJack F Vogel 
21416ab6bfe3SJack F Vogel 	if (((hw->mac.type == e1000_pchlan) &&
21426ab6bfe3SJack F Vogel 	     !(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)) ||
21436ab6bfe3SJack F Vogel 	    (hw->mac.type > e1000_pchlan)) {
21446ab6bfe3SJack F Vogel 		/* HW configures the SMBus address and LEDs when the
21454edd8523SJack F Vogel 		 * OEM and LCD Write Enable bits are set in the NVM.
21464edd8523SJack F Vogel 		 * When both NVM bits are cleared, SW will configure
21474edd8523SJack F Vogel 		 * them instead.
21484edd8523SJack F Vogel 		 */
21497d9119bdSJack F Vogel 		ret_val = e1000_write_smbus_addr(hw);
21504edd8523SJack F Vogel 		if (ret_val)
21516ab6bfe3SJack F Vogel 			goto release;
21524edd8523SJack F Vogel 
21534edd8523SJack F Vogel 		data = E1000_READ_REG(hw, E1000_LEDCTL);
2154a69ed8dfSJack F Vogel 		ret_val = e1000_write_phy_reg_hv_locked(hw, HV_LED_CONFIG,
21554edd8523SJack F Vogel 							(u16)data);
21564edd8523SJack F Vogel 		if (ret_val)
21576ab6bfe3SJack F Vogel 			goto release;
21584edd8523SJack F Vogel 	}
21594edd8523SJack F Vogel 
21604edd8523SJack F Vogel 	/* Configure LCD from extended configuration region. */
21614edd8523SJack F Vogel 
21624edd8523SJack F Vogel 	/* cnf_base_addr is in DWORD */
21634edd8523SJack F Vogel 	word_addr = (u16)(cnf_base_addr << 1);
21644edd8523SJack F Vogel 
21654edd8523SJack F Vogel 	for (i = 0; i < cnf_size; i++) {
21664edd8523SJack F Vogel 		ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1,
21674edd8523SJack F Vogel 					   &reg_data);
21684edd8523SJack F Vogel 		if (ret_val)
21696ab6bfe3SJack F Vogel 			goto release;
21704edd8523SJack F Vogel 
21714edd8523SJack F Vogel 		ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1),
21724edd8523SJack F Vogel 					   1, &reg_addr);
21734edd8523SJack F Vogel 		if (ret_val)
21746ab6bfe3SJack F Vogel 			goto release;
21754edd8523SJack F Vogel 
21764edd8523SJack F Vogel 		/* Save off the PHY page for future writes. */
21774edd8523SJack F Vogel 		if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
21784edd8523SJack F Vogel 			phy_page = reg_data;
21794edd8523SJack F Vogel 			continue;
21804edd8523SJack F Vogel 		}
21814edd8523SJack F Vogel 
21824edd8523SJack F Vogel 		reg_addr &= PHY_REG_MASK;
21834edd8523SJack F Vogel 		reg_addr |= phy_page;
21844edd8523SJack F Vogel 
21854edd8523SJack F Vogel 		ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr,
21864edd8523SJack F Vogel 						    reg_data);
21874edd8523SJack F Vogel 		if (ret_val)
21886ab6bfe3SJack F Vogel 			goto release;
21894edd8523SJack F Vogel 	}
21904edd8523SJack F Vogel 
21916ab6bfe3SJack F Vogel release:
21924edd8523SJack F Vogel 	hw->phy.ops.release(hw);
21934edd8523SJack F Vogel 	return ret_val;
21944edd8523SJack F Vogel }
21954edd8523SJack F Vogel 
21964edd8523SJack F Vogel /**
21974edd8523SJack F Vogel  *  e1000_k1_gig_workaround_hv - K1 Si workaround
21984edd8523SJack F Vogel  *  @hw:   pointer to the HW structure
21994edd8523SJack F Vogel  *  @link: link up bool flag
22004edd8523SJack F Vogel  *
22014edd8523SJack F Vogel  *  If K1 is enabled for 1Gbps, the MAC might stall when transitioning
22024edd8523SJack F Vogel  *  from a lower speed.  This workaround disables K1 whenever link is at 1Gig
22034edd8523SJack F Vogel  *  If link is down, the function will restore the default K1 setting located
22044edd8523SJack F Vogel  *  in the NVM.
22054edd8523SJack F Vogel  **/
22064edd8523SJack F Vogel static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
22074edd8523SJack F Vogel {
22084edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
22094edd8523SJack F Vogel 	u16 status_reg = 0;
22104edd8523SJack F Vogel 	bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled;
22114edd8523SJack F Vogel 
22124edd8523SJack F Vogel 	DEBUGFUNC("e1000_k1_gig_workaround_hv");
22134edd8523SJack F Vogel 
22144edd8523SJack F Vogel 	if (hw->mac.type != e1000_pchlan)
22156ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
22164edd8523SJack F Vogel 
22174edd8523SJack F Vogel 	/* Wrap the whole flow with the sw flag */
22184edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
22194edd8523SJack F Vogel 	if (ret_val)
22206ab6bfe3SJack F Vogel 		return ret_val;
22214edd8523SJack F Vogel 
22224edd8523SJack F Vogel 	/* Disable K1 when link is 1Gbps, otherwise use the NVM setting */
22234edd8523SJack F Vogel 	if (link) {
22244edd8523SJack F Vogel 		if (hw->phy.type == e1000_phy_82578) {
22254edd8523SJack F Vogel 			ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS,
22264edd8523SJack F Vogel 							      &status_reg);
22274edd8523SJack F Vogel 			if (ret_val)
22284edd8523SJack F Vogel 				goto release;
22294edd8523SJack F Vogel 
22307609433eSJack F Vogel 			status_reg &= (BM_CS_STATUS_LINK_UP |
22314edd8523SJack F Vogel 				       BM_CS_STATUS_RESOLVED |
22327609433eSJack F Vogel 				       BM_CS_STATUS_SPEED_MASK);
22334edd8523SJack F Vogel 
22344edd8523SJack F Vogel 			if (status_reg == (BM_CS_STATUS_LINK_UP |
22354edd8523SJack F Vogel 					   BM_CS_STATUS_RESOLVED |
22364edd8523SJack F Vogel 					   BM_CS_STATUS_SPEED_1000))
22374edd8523SJack F Vogel 				k1_enable = FALSE;
22384edd8523SJack F Vogel 		}
22394edd8523SJack F Vogel 
22404edd8523SJack F Vogel 		if (hw->phy.type == e1000_phy_82577) {
22414edd8523SJack F Vogel 			ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS,
22424edd8523SJack F Vogel 							      &status_reg);
22434edd8523SJack F Vogel 			if (ret_val)
22444edd8523SJack F Vogel 				goto release;
22454edd8523SJack F Vogel 
22467609433eSJack F Vogel 			status_reg &= (HV_M_STATUS_LINK_UP |
22474edd8523SJack F Vogel 				       HV_M_STATUS_AUTONEG_COMPLETE |
22487609433eSJack F Vogel 				       HV_M_STATUS_SPEED_MASK);
22494edd8523SJack F Vogel 
22504edd8523SJack F Vogel 			if (status_reg == (HV_M_STATUS_LINK_UP |
22514edd8523SJack F Vogel 					   HV_M_STATUS_AUTONEG_COMPLETE |
22524edd8523SJack F Vogel 					   HV_M_STATUS_SPEED_1000))
22534edd8523SJack F Vogel 				k1_enable = FALSE;
22544edd8523SJack F Vogel 		}
22554edd8523SJack F Vogel 
22564edd8523SJack F Vogel 		/* Link stall fix for link up */
22574edd8523SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
22584edd8523SJack F Vogel 						       0x0100);
22594edd8523SJack F Vogel 		if (ret_val)
22604edd8523SJack F Vogel 			goto release;
22614edd8523SJack F Vogel 
22624edd8523SJack F Vogel 	} else {
22634edd8523SJack F Vogel 		/* Link stall fix for link down */
22644edd8523SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
22654edd8523SJack F Vogel 						       0x4100);
22664edd8523SJack F Vogel 		if (ret_val)
22674edd8523SJack F Vogel 			goto release;
22684edd8523SJack F Vogel 	}
22694edd8523SJack F Vogel 
22704edd8523SJack F Vogel 	ret_val = e1000_configure_k1_ich8lan(hw, k1_enable);
22714edd8523SJack F Vogel 
22724edd8523SJack F Vogel release:
22734edd8523SJack F Vogel 	hw->phy.ops.release(hw);
22746ab6bfe3SJack F Vogel 
22754edd8523SJack F Vogel 	return ret_val;
22764edd8523SJack F Vogel }
22774edd8523SJack F Vogel 
22784edd8523SJack F Vogel /**
22794edd8523SJack F Vogel  *  e1000_configure_k1_ich8lan - Configure K1 power state
22804edd8523SJack F Vogel  *  @hw: pointer to the HW structure
22814edd8523SJack F Vogel  *  @enable: K1 state to configure
22824edd8523SJack F Vogel  *
22834edd8523SJack F Vogel  *  Configure the K1 power state based on the provided parameter.
22844edd8523SJack F Vogel  *  Assumes semaphore already acquired.
22854edd8523SJack F Vogel  *
22864edd8523SJack F Vogel  *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
22874edd8523SJack F Vogel  **/
22884edd8523SJack F Vogel s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
22894edd8523SJack F Vogel {
22906ab6bfe3SJack F Vogel 	s32 ret_val;
22914edd8523SJack F Vogel 	u32 ctrl_reg = 0;
22924edd8523SJack F Vogel 	u32 ctrl_ext = 0;
22934edd8523SJack F Vogel 	u32 reg = 0;
22944edd8523SJack F Vogel 	u16 kmrn_reg = 0;
22954edd8523SJack F Vogel 
22967d9119bdSJack F Vogel 	DEBUGFUNC("e1000_configure_k1_ich8lan");
22977d9119bdSJack F Vogel 
22984dab5c37SJack F Vogel 	ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
22994edd8523SJack F Vogel 					     &kmrn_reg);
23004edd8523SJack F Vogel 	if (ret_val)
23016ab6bfe3SJack F Vogel 		return ret_val;
23024edd8523SJack F Vogel 
23034edd8523SJack F Vogel 	if (k1_enable)
23044edd8523SJack F Vogel 		kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE;
23054edd8523SJack F Vogel 	else
23064edd8523SJack F Vogel 		kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE;
23074edd8523SJack F Vogel 
23084dab5c37SJack F Vogel 	ret_val = e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
23094edd8523SJack F Vogel 					      kmrn_reg);
23104edd8523SJack F Vogel 	if (ret_val)
23116ab6bfe3SJack F Vogel 		return ret_val;
23124edd8523SJack F Vogel 
23134edd8523SJack F Vogel 	usec_delay(20);
23144edd8523SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
23154edd8523SJack F Vogel 	ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
23164edd8523SJack F Vogel 
23174edd8523SJack F Vogel 	reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
23184edd8523SJack F Vogel 	reg |= E1000_CTRL_FRCSPD;
23194edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, reg);
23204edd8523SJack F Vogel 
23214edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
23224dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
23234edd8523SJack F Vogel 	usec_delay(20);
23244edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
23254edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
23264dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
23274edd8523SJack F Vogel 	usec_delay(20);
23284edd8523SJack F Vogel 
23296ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
23304edd8523SJack F Vogel }
23314edd8523SJack F Vogel 
23324edd8523SJack F Vogel /**
23334edd8523SJack F Vogel  *  e1000_oem_bits_config_ich8lan - SW-based LCD Configuration
23344edd8523SJack F Vogel  *  @hw:       pointer to the HW structure
23354edd8523SJack F Vogel  *  @d0_state: boolean if entering d0 or d3 device state
23364edd8523SJack F Vogel  *
23374edd8523SJack F Vogel  *  SW will configure Gbe Disable and LPLU based on the NVM. The four bits are
23384edd8523SJack F Vogel  *  collectively called OEM bits.  The OEM Write Enable bit and SW Config bit
23394edd8523SJack F Vogel  *  in NVM determines whether HW should configure LPLU and Gbe Disable.
23404edd8523SJack F Vogel  **/
23414dab5c37SJack F Vogel static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
23424edd8523SJack F Vogel {
23434edd8523SJack F Vogel 	s32 ret_val = 0;
23444edd8523SJack F Vogel 	u32 mac_reg;
23454edd8523SJack F Vogel 	u16 oem_reg;
23464edd8523SJack F Vogel 
23477d9119bdSJack F Vogel 	DEBUGFUNC("e1000_oem_bits_config_ich8lan");
23487d9119bdSJack F Vogel 
23496ab6bfe3SJack F Vogel 	if (hw->mac.type < e1000_pchlan)
23504edd8523SJack F Vogel 		return ret_val;
23514edd8523SJack F Vogel 
23524edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
23534edd8523SJack F Vogel 	if (ret_val)
23544edd8523SJack F Vogel 		return ret_val;
23554edd8523SJack F Vogel 
23566ab6bfe3SJack F Vogel 	if (hw->mac.type == e1000_pchlan) {
23574edd8523SJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
23584edd8523SJack F Vogel 		if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
23596ab6bfe3SJack F Vogel 			goto release;
23607d9119bdSJack F Vogel 	}
23614edd8523SJack F Vogel 
23624edd8523SJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM);
23634edd8523SJack F Vogel 	if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
23646ab6bfe3SJack F Vogel 		goto release;
23654edd8523SJack F Vogel 
23664edd8523SJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
23674edd8523SJack F Vogel 
23684edd8523SJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg);
23694edd8523SJack F Vogel 	if (ret_val)
23706ab6bfe3SJack F Vogel 		goto release;
23714edd8523SJack F Vogel 
23724edd8523SJack F Vogel 	oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU);
23734edd8523SJack F Vogel 
23744edd8523SJack F Vogel 	if (d0_state) {
23754edd8523SJack F Vogel 		if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE)
23764edd8523SJack F Vogel 			oem_reg |= HV_OEM_BITS_GBE_DIS;
23774edd8523SJack F Vogel 
23784edd8523SJack F Vogel 		if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
23794edd8523SJack F Vogel 			oem_reg |= HV_OEM_BITS_LPLU;
23804dab5c37SJack F Vogel 	} else {
23814dab5c37SJack F Vogel 		if (mac_reg & (E1000_PHY_CTRL_GBE_DISABLE |
23824dab5c37SJack F Vogel 		    E1000_PHY_CTRL_NOND0A_GBE_DISABLE))
23834dab5c37SJack F Vogel 			oem_reg |= HV_OEM_BITS_GBE_DIS;
23844dab5c37SJack F Vogel 
23854dab5c37SJack F Vogel 		if (mac_reg & (E1000_PHY_CTRL_D0A_LPLU |
23864dab5c37SJack F Vogel 		    E1000_PHY_CTRL_NOND0A_LPLU))
23874dab5c37SJack F Vogel 			oem_reg |= HV_OEM_BITS_LPLU;
23884dab5c37SJack F Vogel 	}
23894dab5c37SJack F Vogel 
23906ab6bfe3SJack F Vogel 	/* Set Restart auto-neg to activate the bits */
23916ab6bfe3SJack F Vogel 	if ((d0_state || (hw->mac.type != e1000_pchlan)) &&
23926ab6bfe3SJack F Vogel 	    !hw->phy.ops.check_reset_block(hw))
23936ab6bfe3SJack F Vogel 		oem_reg |= HV_OEM_BITS_RESTART_AN;
23946ab6bfe3SJack F Vogel 
23954edd8523SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg);
23964edd8523SJack F Vogel 
23976ab6bfe3SJack F Vogel release:
23984edd8523SJack F Vogel 	hw->phy.ops.release(hw);
23994edd8523SJack F Vogel 
24004edd8523SJack F Vogel 	return ret_val;
24014edd8523SJack F Vogel }
24024edd8523SJack F Vogel 
24034edd8523SJack F Vogel 
24044edd8523SJack F Vogel /**
2405a69ed8dfSJack F Vogel  *  e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode
2406a69ed8dfSJack F Vogel  *  @hw:   pointer to the HW structure
2407a69ed8dfSJack F Vogel  **/
2408a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw)
2409a69ed8dfSJack F Vogel {
2410a69ed8dfSJack F Vogel 	s32 ret_val;
2411a69ed8dfSJack F Vogel 	u16 data;
2412a69ed8dfSJack F Vogel 
24137d9119bdSJack F Vogel 	DEBUGFUNC("e1000_set_mdio_slow_mode_hv");
24147d9119bdSJack F Vogel 
2415a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, HV_KMRN_MODE_CTRL, &data);
2416a69ed8dfSJack F Vogel 	if (ret_val)
2417a69ed8dfSJack F Vogel 		return ret_val;
2418a69ed8dfSJack F Vogel 
2419a69ed8dfSJack F Vogel 	data |= HV_KMRN_MDIO_SLOW;
2420a69ed8dfSJack F Vogel 
2421a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_MODE_CTRL, data);
2422a69ed8dfSJack F Vogel 
2423a69ed8dfSJack F Vogel 	return ret_val;
2424a69ed8dfSJack F Vogel }
2425a69ed8dfSJack F Vogel 
2426a69ed8dfSJack F Vogel /**
24279d81738fSJack F Vogel  *  e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
24289d81738fSJack F Vogel  *  done after every PHY reset.
24299d81738fSJack F Vogel  **/
24309d81738fSJack F Vogel static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
24319d81738fSJack F Vogel {
24329d81738fSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
2433a69ed8dfSJack F Vogel 	u16 phy_data;
24349d81738fSJack F Vogel 
24357d9119bdSJack F Vogel 	DEBUGFUNC("e1000_hv_phy_workarounds_ich8lan");
24367d9119bdSJack F Vogel 
24379d81738fSJack F Vogel 	if (hw->mac.type != e1000_pchlan)
24386ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
24399d81738fSJack F Vogel 
2440a69ed8dfSJack F Vogel 	/* Set MDIO slow mode before any other MDIO access */
2441a69ed8dfSJack F Vogel 	if (hw->phy.type == e1000_phy_82577) {
2442a69ed8dfSJack F Vogel 		ret_val = e1000_set_mdio_slow_mode_hv(hw);
2443a69ed8dfSJack F Vogel 		if (ret_val)
24446ab6bfe3SJack F Vogel 			return ret_val;
2445a69ed8dfSJack F Vogel 	}
2446a69ed8dfSJack F Vogel 
24479d81738fSJack F Vogel 	if (((hw->phy.type == e1000_phy_82577) &&
24489d81738fSJack F Vogel 	     ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
24499d81738fSJack F Vogel 	    ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
24509d81738fSJack F Vogel 		/* Disable generation of early preamble */
24519d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
24529d81738fSJack F Vogel 		if (ret_val)
24536ab6bfe3SJack F Vogel 			return ret_val;
24549d81738fSJack F Vogel 
24559d81738fSJack F Vogel 		/* Preamble tuning for SSC */
24564dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA,
24574dab5c37SJack F Vogel 						0xA204);
24589d81738fSJack F Vogel 		if (ret_val)
24596ab6bfe3SJack F Vogel 			return ret_val;
24609d81738fSJack F Vogel 	}
24619d81738fSJack F Vogel 
24629d81738fSJack F Vogel 	if (hw->phy.type == e1000_phy_82578) {
24636ab6bfe3SJack F Vogel 		/* Return registers to default by doing a soft reset then
24649d81738fSJack F Vogel 		 * writing 0x3140 to the control register.
24659d81738fSJack F Vogel 		 */
24669d81738fSJack F Vogel 		if (hw->phy.revision < 2) {
24679d81738fSJack F Vogel 			e1000_phy_sw_reset_generic(hw);
24689d81738fSJack F Vogel 			ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL,
24699d81738fSJack F Vogel 							0x3140);
24709d81738fSJack F Vogel 		}
24719d81738fSJack F Vogel 	}
24729d81738fSJack F Vogel 
24739d81738fSJack F Vogel 	/* Select page 0 */
24749d81738fSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
24759d81738fSJack F Vogel 	if (ret_val)
24766ab6bfe3SJack F Vogel 		return ret_val;
24774edd8523SJack F Vogel 
24789d81738fSJack F Vogel 	hw->phy.addr = 1;
24794edd8523SJack F Vogel 	ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
2480a69ed8dfSJack F Vogel 	hw->phy.ops.release(hw);
24814edd8523SJack F Vogel 	if (ret_val)
24826ab6bfe3SJack F Vogel 		return ret_val;
24839d81738fSJack F Vogel 
24846ab6bfe3SJack F Vogel 	/* Configure the K1 Si workaround during phy reset assuming there is
24854edd8523SJack F Vogel 	 * link so that it disables K1 if link is in 1Gbps.
24864edd8523SJack F Vogel 	 */
24874edd8523SJack F Vogel 	ret_val = e1000_k1_gig_workaround_hv(hw, TRUE);
2488a69ed8dfSJack F Vogel 	if (ret_val)
24896ab6bfe3SJack F Vogel 		return ret_val;
24904edd8523SJack F Vogel 
2491a69ed8dfSJack F Vogel 	/* Workaround for link disconnects on a busy hub in half duplex */
2492a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
2493a69ed8dfSJack F Vogel 	if (ret_val)
24946ab6bfe3SJack F Vogel 		return ret_val;
24954dab5c37SJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw, BM_PORT_GEN_CFG, &phy_data);
2496a69ed8dfSJack F Vogel 	if (ret_val)
2497a69ed8dfSJack F Vogel 		goto release;
24984dab5c37SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, BM_PORT_GEN_CFG,
2499a69ed8dfSJack F Vogel 					       phy_data & 0x00FF);
25006ab6bfe3SJack F Vogel 	if (ret_val)
25016ab6bfe3SJack F Vogel 		goto release;
25026ab6bfe3SJack F Vogel 
25036ab6bfe3SJack F Vogel 	/* set MSE higher to enable link to stay up when noise is high */
25046ab6bfe3SJack F Vogel 	ret_val = e1000_write_emi_reg_locked(hw, I82577_MSE_THRESHOLD, 0x0034);
2505a69ed8dfSJack F Vogel release:
2506a69ed8dfSJack F Vogel 	hw->phy.ops.release(hw);
25076ab6bfe3SJack F Vogel 
25089d81738fSJack F Vogel 	return ret_val;
25099d81738fSJack F Vogel }
25109d81738fSJack F Vogel 
25119d81738fSJack F Vogel /**
25127d9119bdSJack F Vogel  *  e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY
25137d9119bdSJack F Vogel  *  @hw:   pointer to the HW structure
25147d9119bdSJack F Vogel  **/
25157d9119bdSJack F Vogel void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
25167d9119bdSJack F Vogel {
25177d9119bdSJack F Vogel 	u32 mac_reg;
25184dab5c37SJack F Vogel 	u16 i, phy_reg = 0;
25194dab5c37SJack F Vogel 	s32 ret_val;
25207d9119bdSJack F Vogel 
25217d9119bdSJack F Vogel 	DEBUGFUNC("e1000_copy_rx_addrs_to_phy_ich8lan");
25227d9119bdSJack F Vogel 
25234dab5c37SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
25244dab5c37SJack F Vogel 	if (ret_val)
25254dab5c37SJack F Vogel 		return;
25264dab5c37SJack F Vogel 	ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg);
25274dab5c37SJack F Vogel 	if (ret_val)
25284dab5c37SJack F Vogel 		goto release;
25294dab5c37SJack F Vogel 
25307609433eSJack F Vogel 	/* Copy both RAL/H (rar_entry_count) and SHRAL/H to PHY */
25317609433eSJack F Vogel 	for (i = 0; i < (hw->mac.rar_entry_count); i++) {
25327d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RAL(i));
25334dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_L(i),
25344dab5c37SJack F Vogel 					   (u16)(mac_reg & 0xFFFF));
25354dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_M(i),
25364dab5c37SJack F Vogel 					   (u16)((mac_reg >> 16) & 0xFFFF));
25374dab5c37SJack F Vogel 
25387d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RAH(i));
25394dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_H(i),
25404dab5c37SJack F Vogel 					   (u16)(mac_reg & 0xFFFF));
25414dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_CTRL(i),
25424dab5c37SJack F Vogel 					   (u16)((mac_reg & E1000_RAH_AV)
25434dab5c37SJack F Vogel 						 >> 16));
25447d9119bdSJack F Vogel 	}
25454dab5c37SJack F Vogel 
25464dab5c37SJack F Vogel 	e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg);
25474dab5c37SJack F Vogel 
25484dab5c37SJack F Vogel release:
25494dab5c37SJack F Vogel 	hw->phy.ops.release(hw);
25507d9119bdSJack F Vogel }
25517d9119bdSJack F Vogel 
25527d9119bdSJack F Vogel static u32 e1000_calc_rx_da_crc(u8 mac[])
25537d9119bdSJack F Vogel {
25547d9119bdSJack F Vogel 	u32 poly = 0xEDB88320;	/* Polynomial for 802.3 CRC calculation */
25557d9119bdSJack F Vogel 	u32 i, j, mask, crc;
25567d9119bdSJack F Vogel 
25577d9119bdSJack F Vogel 	DEBUGFUNC("e1000_calc_rx_da_crc");
25587d9119bdSJack F Vogel 
25597d9119bdSJack F Vogel 	crc = 0xffffffff;
25607d9119bdSJack F Vogel 	for (i = 0; i < 6; i++) {
25617d9119bdSJack F Vogel 		crc = crc ^ mac[i];
25627d9119bdSJack F Vogel 		for (j = 8; j > 0; j--) {
25637d9119bdSJack F Vogel 			mask = (crc & 1) * (-1);
25647d9119bdSJack F Vogel 			crc = (crc >> 1) ^ (poly & mask);
25657d9119bdSJack F Vogel 		}
25667d9119bdSJack F Vogel 	}
25677d9119bdSJack F Vogel 	return ~crc;
25687d9119bdSJack F Vogel }
25697d9119bdSJack F Vogel 
25707d9119bdSJack F Vogel /**
25717d9119bdSJack F Vogel  *  e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation
25727d9119bdSJack F Vogel  *  with 82579 PHY
25737d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
25747d9119bdSJack F Vogel  *  @enable: flag to enable/disable workaround when enabling/disabling jumbos
25757d9119bdSJack F Vogel  **/
25767d9119bdSJack F Vogel s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
25777d9119bdSJack F Vogel {
25787d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
25797d9119bdSJack F Vogel 	u16 phy_reg, data;
25807d9119bdSJack F Vogel 	u32 mac_reg;
25817d9119bdSJack F Vogel 	u16 i;
25827d9119bdSJack F Vogel 
25837d9119bdSJack F Vogel 	DEBUGFUNC("e1000_lv_jumbo_workaround_ich8lan");
25847d9119bdSJack F Vogel 
25856ab6bfe3SJack F Vogel 	if (hw->mac.type < e1000_pch2lan)
25866ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
25877d9119bdSJack F Vogel 
25887d9119bdSJack F Vogel 	/* disable Rx path while enabling/disabling workaround */
25897d9119bdSJack F Vogel 	hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg);
25904dab5c37SJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20),
25914dab5c37SJack F Vogel 					phy_reg | (1 << 14));
25927d9119bdSJack F Vogel 	if (ret_val)
25936ab6bfe3SJack F Vogel 		return ret_val;
25947d9119bdSJack F Vogel 
25957d9119bdSJack F Vogel 	if (enable) {
25967609433eSJack F Vogel 		/* Write Rx addresses (rar_entry_count for RAL/H, and
25977d9119bdSJack F Vogel 		 * SHRAL/H) and initial CRC values to the MAC
25987d9119bdSJack F Vogel 		 */
25997609433eSJack F Vogel 		for (i = 0; i < hw->mac.rar_entry_count; i++) {
26007d9119bdSJack F Vogel 			u8 mac_addr[ETH_ADDR_LEN] = {0};
26017d9119bdSJack F Vogel 			u32 addr_high, addr_low;
26027d9119bdSJack F Vogel 
26037d9119bdSJack F Vogel 			addr_high = E1000_READ_REG(hw, E1000_RAH(i));
26047d9119bdSJack F Vogel 			if (!(addr_high & E1000_RAH_AV))
26057d9119bdSJack F Vogel 				continue;
26067d9119bdSJack F Vogel 			addr_low = E1000_READ_REG(hw, E1000_RAL(i));
26077d9119bdSJack F Vogel 			mac_addr[0] = (addr_low & 0xFF);
26087d9119bdSJack F Vogel 			mac_addr[1] = ((addr_low >> 8) & 0xFF);
26097d9119bdSJack F Vogel 			mac_addr[2] = ((addr_low >> 16) & 0xFF);
26107d9119bdSJack F Vogel 			mac_addr[3] = ((addr_low >> 24) & 0xFF);
26117d9119bdSJack F Vogel 			mac_addr[4] = (addr_high & 0xFF);
26127d9119bdSJack F Vogel 			mac_addr[5] = ((addr_high >> 8) & 0xFF);
26137d9119bdSJack F Vogel 
26147d9119bdSJack F Vogel 			E1000_WRITE_REG(hw, E1000_PCH_RAICC(i),
26157d9119bdSJack F Vogel 					e1000_calc_rx_da_crc(mac_addr));
26167d9119bdSJack F Vogel 		}
26177d9119bdSJack F Vogel 
26187d9119bdSJack F Vogel 		/* Write Rx addresses to the PHY */
26197d9119bdSJack F Vogel 		e1000_copy_rx_addrs_to_phy_ich8lan(hw);
26207d9119bdSJack F Vogel 
26217d9119bdSJack F Vogel 		/* Enable jumbo frame workaround in the MAC */
26227d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
26237d9119bdSJack F Vogel 		mac_reg &= ~(1 << 14);
26247d9119bdSJack F Vogel 		mac_reg |= (7 << 15);
26257d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
26267d9119bdSJack F Vogel 
26277d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RCTL);
26287d9119bdSJack F Vogel 		mac_reg |= E1000_RCTL_SECRC;
26297d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
26307d9119bdSJack F Vogel 
26317d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
26327d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
26337d9119bdSJack F Vogel 						&data);
26347d9119bdSJack F Vogel 		if (ret_val)
26356ab6bfe3SJack F Vogel 			return ret_val;
26367d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
26377d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
26387d9119bdSJack F Vogel 						data | (1 << 0));
26397d9119bdSJack F Vogel 		if (ret_val)
26406ab6bfe3SJack F Vogel 			return ret_val;
26417d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
26427d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
26437d9119bdSJack F Vogel 						&data);
26447d9119bdSJack F Vogel 		if (ret_val)
26456ab6bfe3SJack F Vogel 			return ret_val;
26467d9119bdSJack F Vogel 		data &= ~(0xF << 8);
26477d9119bdSJack F Vogel 		data |= (0xB << 8);
26487d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
26497d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
26507d9119bdSJack F Vogel 						data);
26517d9119bdSJack F Vogel 		if (ret_val)
26526ab6bfe3SJack F Vogel 			return ret_val;
26537d9119bdSJack F Vogel 
26547d9119bdSJack F Vogel 		/* Enable jumbo frame workaround in the PHY */
26557d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
26567d9119bdSJack F Vogel 		data &= ~(0x7F << 5);
26577d9119bdSJack F Vogel 		data |= (0x37 << 5);
26587d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
26597d9119bdSJack F Vogel 		if (ret_val)
26606ab6bfe3SJack F Vogel 			return ret_val;
26617d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
26627d9119bdSJack F Vogel 		data &= ~(1 << 13);
26637d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
26647d9119bdSJack F Vogel 		if (ret_val)
26656ab6bfe3SJack F Vogel 			return ret_val;
26667d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
26677d9119bdSJack F Vogel 		data &= ~(0x3FF << 2);
2668*8cc64f1eSJack F Vogel 		data |= (E1000_TX_PTR_GAP << 2);
26697d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
26707d9119bdSJack F Vogel 		if (ret_val)
26716ab6bfe3SJack F Vogel 			return ret_val;
26724dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0xF100);
26737d9119bdSJack F Vogel 		if (ret_val)
26746ab6bfe3SJack F Vogel 			return ret_val;
26757d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
26764dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data |
26774dab5c37SJack F Vogel 						(1 << 10));
26787d9119bdSJack F Vogel 		if (ret_val)
26796ab6bfe3SJack F Vogel 			return ret_val;
26807d9119bdSJack F Vogel 	} else {
26817d9119bdSJack F Vogel 		/* Write MAC register values back to h/w defaults */
26827d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
26837d9119bdSJack F Vogel 		mac_reg &= ~(0xF << 14);
26847d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
26857d9119bdSJack F Vogel 
26867d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RCTL);
26877d9119bdSJack F Vogel 		mac_reg &= ~E1000_RCTL_SECRC;
26887d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
26897d9119bdSJack F Vogel 
26907d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
26917d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
26927d9119bdSJack F Vogel 						&data);
26937d9119bdSJack F Vogel 		if (ret_val)
26946ab6bfe3SJack F Vogel 			return ret_val;
26957d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
26967d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
26977d9119bdSJack F Vogel 						data & ~(1 << 0));
26987d9119bdSJack F Vogel 		if (ret_val)
26996ab6bfe3SJack F Vogel 			return ret_val;
27007d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
27017d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
27027d9119bdSJack F Vogel 						&data);
27037d9119bdSJack F Vogel 		if (ret_val)
27046ab6bfe3SJack F Vogel 			return ret_val;
27057d9119bdSJack F Vogel 		data &= ~(0xF << 8);
27067d9119bdSJack F Vogel 		data |= (0xB << 8);
27077d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
27087d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
27097d9119bdSJack F Vogel 						data);
27107d9119bdSJack F Vogel 		if (ret_val)
27116ab6bfe3SJack F Vogel 			return ret_val;
27127d9119bdSJack F Vogel 
27137d9119bdSJack F Vogel 		/* Write PHY register values back to h/w defaults */
27147d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
27157d9119bdSJack F Vogel 		data &= ~(0x7F << 5);
27167d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
27177d9119bdSJack F Vogel 		if (ret_val)
27186ab6bfe3SJack F Vogel 			return ret_val;
27197d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
27207d9119bdSJack F Vogel 		data |= (1 << 13);
27217d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
27227d9119bdSJack F Vogel 		if (ret_val)
27236ab6bfe3SJack F Vogel 			return ret_val;
27247d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
27257d9119bdSJack F Vogel 		data &= ~(0x3FF << 2);
27267d9119bdSJack F Vogel 		data |= (0x8 << 2);
27277d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
27287d9119bdSJack F Vogel 		if (ret_val)
27296ab6bfe3SJack F Vogel 			return ret_val;
27307d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0x7E00);
27317d9119bdSJack F Vogel 		if (ret_val)
27326ab6bfe3SJack F Vogel 			return ret_val;
27337d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
27344dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data &
27354dab5c37SJack F Vogel 						~(1 << 10));
27367d9119bdSJack F Vogel 		if (ret_val)
27376ab6bfe3SJack F Vogel 			return ret_val;
27387d9119bdSJack F Vogel 	}
27397d9119bdSJack F Vogel 
27407d9119bdSJack F Vogel 	/* re-enable Rx path after enabling/disabling workaround */
27416ab6bfe3SJack F Vogel 	return hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg &
27424dab5c37SJack F Vogel 				     ~(1 << 14));
27437d9119bdSJack F Vogel }
27447d9119bdSJack F Vogel 
27457d9119bdSJack F Vogel /**
27467d9119bdSJack F Vogel  *  e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be
27477d9119bdSJack F Vogel  *  done after every PHY reset.
27487d9119bdSJack F Vogel  **/
27497d9119bdSJack F Vogel static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw)
27507d9119bdSJack F Vogel {
27517d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
27527d9119bdSJack F Vogel 
27537d9119bdSJack F Vogel 	DEBUGFUNC("e1000_lv_phy_workarounds_ich8lan");
27547d9119bdSJack F Vogel 
27557d9119bdSJack F Vogel 	if (hw->mac.type != e1000_pch2lan)
27566ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
27577d9119bdSJack F Vogel 
27587d9119bdSJack F Vogel 	/* Set MDIO slow mode before any other MDIO access */
27597d9119bdSJack F Vogel 	ret_val = e1000_set_mdio_slow_mode_hv(hw);
27606ab6bfe3SJack F Vogel 	if (ret_val)
27616ab6bfe3SJack F Vogel 		return ret_val;
27627d9119bdSJack F Vogel 
27634dab5c37SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
27644dab5c37SJack F Vogel 	if (ret_val)
27656ab6bfe3SJack F Vogel 		return ret_val;
27664dab5c37SJack F Vogel 	/* set MSE higher to enable link to stay up when noise is high */
27676ab6bfe3SJack F Vogel 	ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_THRESHOLD, 0x0034);
27684dab5c37SJack F Vogel 	if (ret_val)
27694dab5c37SJack F Vogel 		goto release;
27704dab5c37SJack F Vogel 	/* drop link after 5 times MSE threshold was reached */
27716ab6bfe3SJack F Vogel 	ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_LINK_DOWN, 0x0005);
27724dab5c37SJack F Vogel release:
27734dab5c37SJack F Vogel 	hw->phy.ops.release(hw);
27744dab5c37SJack F Vogel 
27757d9119bdSJack F Vogel 	return ret_val;
27767d9119bdSJack F Vogel }
27777d9119bdSJack F Vogel 
27787d9119bdSJack F Vogel /**
27797d9119bdSJack F Vogel  *  e1000_k1_gig_workaround_lv - K1 Si workaround
27807d9119bdSJack F Vogel  *  @hw:   pointer to the HW structure
27817d9119bdSJack F Vogel  *
2782*8cc64f1eSJack F Vogel  *  Workaround to set the K1 beacon duration for 82579 parts in 10Mbps
2783*8cc64f1eSJack F Vogel  *  Disable K1 for 1000 and 100 speeds
27847d9119bdSJack F Vogel  **/
27857d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw)
27867d9119bdSJack F Vogel {
27877d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
27887d9119bdSJack F Vogel 	u16 status_reg = 0;
27897d9119bdSJack F Vogel 
27907d9119bdSJack F Vogel 	DEBUGFUNC("e1000_k1_workaround_lv");
27917d9119bdSJack F Vogel 
27927d9119bdSJack F Vogel 	if (hw->mac.type != e1000_pch2lan)
27936ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
27947d9119bdSJack F Vogel 
2795*8cc64f1eSJack F Vogel 	/* Set K1 beacon duration based on 10Mbs speed */
27967d9119bdSJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, HV_M_STATUS, &status_reg);
27977d9119bdSJack F Vogel 	if (ret_val)
27986ab6bfe3SJack F Vogel 		return ret_val;
27997d9119bdSJack F Vogel 
28007d9119bdSJack F Vogel 	if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE))
28017d9119bdSJack F Vogel 	    == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) {
2802*8cc64f1eSJack F Vogel 		if (status_reg &
2803*8cc64f1eSJack F Vogel 		    (HV_M_STATUS_SPEED_1000 | HV_M_STATUS_SPEED_100)) {
28046ab6bfe3SJack F Vogel 			u16 pm_phy_reg;
28056ab6bfe3SJack F Vogel 
2806*8cc64f1eSJack F Vogel 			/* LV 1G/100 Packet drop issue wa  */
28076ab6bfe3SJack F Vogel 			ret_val = hw->phy.ops.read_reg(hw, HV_PM_CTRL,
28086ab6bfe3SJack F Vogel 						       &pm_phy_reg);
28096ab6bfe3SJack F Vogel 			if (ret_val)
28106ab6bfe3SJack F Vogel 				return ret_val;
2811*8cc64f1eSJack F Vogel 			pm_phy_reg &= ~HV_PM_CTRL_K1_ENABLE;
28126ab6bfe3SJack F Vogel 			ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL,
28136ab6bfe3SJack F Vogel 							pm_phy_reg);
28146ab6bfe3SJack F Vogel 			if (ret_val)
28156ab6bfe3SJack F Vogel 				return ret_val;
28164dab5c37SJack F Vogel 		} else {
2817*8cc64f1eSJack F Vogel 			u32 mac_reg;
2818*8cc64f1eSJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4);
2819*8cc64f1eSJack F Vogel 			mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
28204dab5c37SJack F Vogel 			mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
28217d9119bdSJack F Vogel 			E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg);
2822*8cc64f1eSJack F Vogel 		}
28237d9119bdSJack F Vogel 	}
28247d9119bdSJack F Vogel 
28257d9119bdSJack F Vogel 	return ret_val;
28267d9119bdSJack F Vogel }
28277d9119bdSJack F Vogel 
28287d9119bdSJack F Vogel /**
28297d9119bdSJack F Vogel  *  e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware
28307d9119bdSJack F Vogel  *  @hw:   pointer to the HW structure
2831730d3130SJack F Vogel  *  @gate: boolean set to TRUE to gate, FALSE to ungate
28327d9119bdSJack F Vogel  *
28337d9119bdSJack F Vogel  *  Gate/ungate the automatic PHY configuration via hardware; perform
28347d9119bdSJack F Vogel  *  the configuration via software instead.
28357d9119bdSJack F Vogel  **/
28367d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate)
28377d9119bdSJack F Vogel {
28387d9119bdSJack F Vogel 	u32 extcnf_ctrl;
28397d9119bdSJack F Vogel 
28407d9119bdSJack F Vogel 	DEBUGFUNC("e1000_gate_hw_phy_config_ich8lan");
28417d9119bdSJack F Vogel 
28426ab6bfe3SJack F Vogel 	if (hw->mac.type < e1000_pch2lan)
28437d9119bdSJack F Vogel 		return;
28447d9119bdSJack F Vogel 
28457d9119bdSJack F Vogel 	extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
28467d9119bdSJack F Vogel 
28477d9119bdSJack F Vogel 	if (gate)
28487d9119bdSJack F Vogel 		extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
28497d9119bdSJack F Vogel 	else
28507d9119bdSJack F Vogel 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG;
28517d9119bdSJack F Vogel 
28527d9119bdSJack F Vogel 	E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
28537d9119bdSJack F Vogel }
28547d9119bdSJack F Vogel 
28557d9119bdSJack F Vogel /**
28569d81738fSJack F Vogel  *  e1000_lan_init_done_ich8lan - Check for PHY config completion
28578cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
28588cfa0ad2SJack F Vogel  *
28599d81738fSJack F Vogel  *  Check the appropriate indication the MAC has finished configuring the
28609d81738fSJack F Vogel  *  PHY after a software reset.
28618cfa0ad2SJack F Vogel  **/
28629d81738fSJack F Vogel static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw)
28638cfa0ad2SJack F Vogel {
28649d81738fSJack F Vogel 	u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT;
28658cfa0ad2SJack F Vogel 
28669d81738fSJack F Vogel 	DEBUGFUNC("e1000_lan_init_done_ich8lan");
28678cfa0ad2SJack F Vogel 
28689d81738fSJack F Vogel 	/* Wait for basic configuration completes before proceeding */
28699d81738fSJack F Vogel 	do {
28709d81738fSJack F Vogel 		data = E1000_READ_REG(hw, E1000_STATUS);
28719d81738fSJack F Vogel 		data &= E1000_STATUS_LAN_INIT_DONE;
28729d81738fSJack F Vogel 		usec_delay(100);
28739d81738fSJack F Vogel 	} while ((!data) && --loop);
28748cfa0ad2SJack F Vogel 
28756ab6bfe3SJack F Vogel 	/* If basic configuration is incomplete before the above loop
28769d81738fSJack F Vogel 	 * count reaches 0, loading the configuration from NVM will
28779d81738fSJack F Vogel 	 * leave the PHY in a bad state possibly resulting in no link.
28789d81738fSJack F Vogel 	 */
28799d81738fSJack F Vogel 	if (loop == 0)
28809d81738fSJack F Vogel 		DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n");
28818cfa0ad2SJack F Vogel 
28829d81738fSJack F Vogel 	/* Clear the Init Done bit for the next init event */
28839d81738fSJack F Vogel 	data = E1000_READ_REG(hw, E1000_STATUS);
28849d81738fSJack F Vogel 	data &= ~E1000_STATUS_LAN_INIT_DONE;
28859d81738fSJack F Vogel 	E1000_WRITE_REG(hw, E1000_STATUS, data);
28868cfa0ad2SJack F Vogel }
28878cfa0ad2SJack F Vogel 
28888cfa0ad2SJack F Vogel /**
28897d9119bdSJack F Vogel  *  e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset
28907d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
28917d9119bdSJack F Vogel  **/
28927d9119bdSJack F Vogel static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
28937d9119bdSJack F Vogel {
28947d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
28957d9119bdSJack F Vogel 	u16 reg;
28967d9119bdSJack F Vogel 
28977d9119bdSJack F Vogel 	DEBUGFUNC("e1000_post_phy_reset_ich8lan");
28987d9119bdSJack F Vogel 
28997d9119bdSJack F Vogel 	if (hw->phy.ops.check_reset_block(hw))
29006ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
29017d9119bdSJack F Vogel 
29027d9119bdSJack F Vogel 	/* Allow time for h/w to get to quiescent state after reset */
29037d9119bdSJack F Vogel 	msec_delay(10);
29047d9119bdSJack F Vogel 
29057d9119bdSJack F Vogel 	/* Perform any necessary post-reset workarounds */
29067d9119bdSJack F Vogel 	switch (hw->mac.type) {
29077d9119bdSJack F Vogel 	case e1000_pchlan:
29087d9119bdSJack F Vogel 		ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
29097d9119bdSJack F Vogel 		if (ret_val)
29106ab6bfe3SJack F Vogel 			return ret_val;
29117d9119bdSJack F Vogel 		break;
29127d9119bdSJack F Vogel 	case e1000_pch2lan:
29137d9119bdSJack F Vogel 		ret_val = e1000_lv_phy_workarounds_ich8lan(hw);
29147d9119bdSJack F Vogel 		if (ret_val)
29156ab6bfe3SJack F Vogel 			return ret_val;
29167d9119bdSJack F Vogel 		break;
29177d9119bdSJack F Vogel 	default:
29187d9119bdSJack F Vogel 		break;
29197d9119bdSJack F Vogel 	}
29207d9119bdSJack F Vogel 
29214dab5c37SJack F Vogel 	/* Clear the host wakeup bit after lcd reset */
29224dab5c37SJack F Vogel 	if (hw->mac.type >= e1000_pchlan) {
29234dab5c37SJack F Vogel 		hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, &reg);
29244dab5c37SJack F Vogel 		reg &= ~BM_WUC_HOST_WU_BIT;
29254dab5c37SJack F Vogel 		hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, reg);
29267d9119bdSJack F Vogel 	}
29277d9119bdSJack F Vogel 
29287d9119bdSJack F Vogel 	/* Configure the LCD with the extended configuration region in NVM */
29297d9119bdSJack F Vogel 	ret_val = e1000_sw_lcd_config_ich8lan(hw);
29307d9119bdSJack F Vogel 	if (ret_val)
29316ab6bfe3SJack F Vogel 		return ret_val;
29327d9119bdSJack F Vogel 
29337d9119bdSJack F Vogel 	/* Configure the LCD with the OEM bits in NVM */
29347d9119bdSJack F Vogel 	ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE);
29357d9119bdSJack F Vogel 
2936730d3130SJack F Vogel 	if (hw->mac.type == e1000_pch2lan) {
29377d9119bdSJack F Vogel 		/* Ungate automatic PHY configuration on non-managed 82579 */
2938730d3130SJack F Vogel 		if (!(E1000_READ_REG(hw, E1000_FWSM) &
2939730d3130SJack F Vogel 		    E1000_ICH_FWSM_FW_VALID)) {
29407d9119bdSJack F Vogel 			msec_delay(10);
29417d9119bdSJack F Vogel 			e1000_gate_hw_phy_config_ich8lan(hw, FALSE);
29427d9119bdSJack F Vogel 		}
29437d9119bdSJack F Vogel 
2944730d3130SJack F Vogel 		/* Set EEE LPI Update Timer to 200usec */
2945730d3130SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
2946730d3130SJack F Vogel 		if (ret_val)
29476ab6bfe3SJack F Vogel 			return ret_val;
29486ab6bfe3SJack F Vogel 		ret_val = e1000_write_emi_reg_locked(hw,
29496ab6bfe3SJack F Vogel 						     I82579_LPI_UPDATE_TIMER,
2950730d3130SJack F Vogel 						     0x1387);
2951730d3130SJack F Vogel 		hw->phy.ops.release(hw);
2952730d3130SJack F Vogel 	}
2953730d3130SJack F Vogel 
29547d9119bdSJack F Vogel 	return ret_val;
29557d9119bdSJack F Vogel }
29567d9119bdSJack F Vogel 
29577d9119bdSJack F Vogel /**
29588cfa0ad2SJack F Vogel  *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
29598cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
29608cfa0ad2SJack F Vogel  *
29618cfa0ad2SJack F Vogel  *  Resets the PHY
29628cfa0ad2SJack F Vogel  *  This is a function pointer entry point called by drivers
29638cfa0ad2SJack F Vogel  *  or other shared routines.
29648cfa0ad2SJack F Vogel  **/
29658cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
29668cfa0ad2SJack F Vogel {
29674edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
29688cfa0ad2SJack F Vogel 
29698cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
29708cfa0ad2SJack F Vogel 
29717d9119bdSJack F Vogel 	/* Gate automatic PHY configuration by hardware on non-managed 82579 */
29727d9119bdSJack F Vogel 	if ((hw->mac.type == e1000_pch2lan) &&
29737d9119bdSJack F Vogel 	    !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
29747d9119bdSJack F Vogel 		e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
29757d9119bdSJack F Vogel 
29768cfa0ad2SJack F Vogel 	ret_val = e1000_phy_hw_reset_generic(hw);
29778cfa0ad2SJack F Vogel 	if (ret_val)
29788cfa0ad2SJack F Vogel 		return ret_val;
29796ab6bfe3SJack F Vogel 
29806ab6bfe3SJack F Vogel 	return e1000_post_phy_reset_ich8lan(hw);
29818cfa0ad2SJack F Vogel }
29828cfa0ad2SJack F Vogel 
29838cfa0ad2SJack F Vogel /**
29844edd8523SJack F Vogel  *  e1000_set_lplu_state_pchlan - Set Low Power Link Up state
29858cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
29864edd8523SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
29878cfa0ad2SJack F Vogel  *
29884edd8523SJack F Vogel  *  Sets the LPLU state according to the active flag.  For PCH, if OEM write
29894edd8523SJack F Vogel  *  bit are disabled in the NVM, writing the LPLU bits in the MAC will not set
29904edd8523SJack F Vogel  *  the phy speed. This function will manually set the LPLU bit and restart
29914edd8523SJack F Vogel  *  auto-neg as hw would do. D3 and D0 LPLU will call the same function
29924edd8523SJack F Vogel  *  since it configures the same bit.
29938cfa0ad2SJack F Vogel  **/
29944edd8523SJack F Vogel static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
29958cfa0ad2SJack F Vogel {
29966ab6bfe3SJack F Vogel 	s32 ret_val;
29974edd8523SJack F Vogel 	u16 oem_reg;
29988cfa0ad2SJack F Vogel 
29994edd8523SJack F Vogel 	DEBUGFUNC("e1000_set_lplu_state_pchlan");
30008cfa0ad2SJack F Vogel 
30014edd8523SJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg);
30028cfa0ad2SJack F Vogel 	if (ret_val)
30036ab6bfe3SJack F Vogel 		return ret_val;
30048cfa0ad2SJack F Vogel 
30054edd8523SJack F Vogel 	if (active)
30064edd8523SJack F Vogel 		oem_reg |= HV_OEM_BITS_LPLU;
30074edd8523SJack F Vogel 	else
30084edd8523SJack F Vogel 		oem_reg &= ~HV_OEM_BITS_LPLU;
30098cfa0ad2SJack F Vogel 
30104dab5c37SJack F Vogel 	if (!hw->phy.ops.check_reset_block(hw))
30114edd8523SJack F Vogel 		oem_reg |= HV_OEM_BITS_RESTART_AN;
30124dab5c37SJack F Vogel 
30136ab6bfe3SJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg);
30148cfa0ad2SJack F Vogel }
30158cfa0ad2SJack F Vogel 
30168cfa0ad2SJack F Vogel /**
30178cfa0ad2SJack F Vogel  *  e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
30188cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
30198cfa0ad2SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
30208cfa0ad2SJack F Vogel  *
30218cfa0ad2SJack F Vogel  *  Sets the LPLU D0 state according to the active flag.  When
30228cfa0ad2SJack F Vogel  *  activating LPLU this function also disables smart speed
30238cfa0ad2SJack F Vogel  *  and vice versa.  LPLU will not be activated unless the
30248cfa0ad2SJack F Vogel  *  device autonegotiation advertisement meets standards of
30258cfa0ad2SJack F Vogel  *  either 10 or 10/100 or 10/100/1000 at all duplexes.
30268cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
30278cfa0ad2SJack F Vogel  *  PHY setup routines.
30288cfa0ad2SJack F Vogel  **/
3029daf9197cSJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
30308cfa0ad2SJack F Vogel {
30318cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
30328cfa0ad2SJack F Vogel 	u32 phy_ctrl;
30338cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
30348cfa0ad2SJack F Vogel 	u16 data;
30358cfa0ad2SJack F Vogel 
30368cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan");
30378cfa0ad2SJack F Vogel 
30388cfa0ad2SJack F Vogel 	if (phy->type == e1000_phy_ife)
30396ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
30408cfa0ad2SJack F Vogel 
30418cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
30428cfa0ad2SJack F Vogel 
30438cfa0ad2SJack F Vogel 	if (active) {
30448cfa0ad2SJack F Vogel 		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
30458cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
30468cfa0ad2SJack F Vogel 
30479d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
30486ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
30499d81738fSJack F Vogel 
30506ab6bfe3SJack F Vogel 		/* Call gig speed drop workaround on LPLU before accessing
30518cfa0ad2SJack F Vogel 		 * any PHY registers
30528cfa0ad2SJack F Vogel 		 */
30539d81738fSJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
30548cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
30558cfa0ad2SJack F Vogel 
30568cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
30578cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw,
30588cfa0ad2SJack F Vogel 					    IGP01E1000_PHY_PORT_CONFIG,
30598cfa0ad2SJack F Vogel 					    &data);
30606ab6bfe3SJack F Vogel 		if (ret_val)
30616ab6bfe3SJack F Vogel 			return ret_val;
30628cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
30638cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
30648cfa0ad2SJack F Vogel 					     IGP01E1000_PHY_PORT_CONFIG,
30658cfa0ad2SJack F Vogel 					     data);
30668cfa0ad2SJack F Vogel 		if (ret_val)
30676ab6bfe3SJack F Vogel 			return ret_val;
30688cfa0ad2SJack F Vogel 	} else {
30698cfa0ad2SJack F Vogel 		phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
30708cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
30718cfa0ad2SJack F Vogel 
30729d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
30736ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
30749d81738fSJack F Vogel 
30756ab6bfe3SJack F Vogel 		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
30768cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
30778cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
30788cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
30798cfa0ad2SJack F Vogel 		 */
30808cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
30818cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
30828cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
30838cfa0ad2SJack F Vogel 						    &data);
30848cfa0ad2SJack F Vogel 			if (ret_val)
30856ab6bfe3SJack F Vogel 				return ret_val;
30868cfa0ad2SJack F Vogel 
30878cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
30888cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
30898cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
30908cfa0ad2SJack F Vogel 						     data);
30918cfa0ad2SJack F Vogel 			if (ret_val)
30926ab6bfe3SJack F Vogel 				return ret_val;
30938cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
30948cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
30958cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
30968cfa0ad2SJack F Vogel 						    &data);
30978cfa0ad2SJack F Vogel 			if (ret_val)
30986ab6bfe3SJack F Vogel 				return ret_val;
30998cfa0ad2SJack F Vogel 
31008cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
31018cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
31028cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
31038cfa0ad2SJack F Vogel 						     data);
31048cfa0ad2SJack F Vogel 			if (ret_val)
31056ab6bfe3SJack F Vogel 				return ret_val;
31068cfa0ad2SJack F Vogel 		}
31078cfa0ad2SJack F Vogel 	}
31088cfa0ad2SJack F Vogel 
31096ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
31108cfa0ad2SJack F Vogel }
31118cfa0ad2SJack F Vogel 
31128cfa0ad2SJack F Vogel /**
31138cfa0ad2SJack F Vogel  *  e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
31148cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
31158cfa0ad2SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
31168cfa0ad2SJack F Vogel  *
31178cfa0ad2SJack F Vogel  *  Sets the LPLU D3 state according to the active flag.  When
31188cfa0ad2SJack F Vogel  *  activating LPLU this function also disables smart speed
31198cfa0ad2SJack F Vogel  *  and vice versa.  LPLU will not be activated unless the
31208cfa0ad2SJack F Vogel  *  device autonegotiation advertisement meets standards of
31218cfa0ad2SJack F Vogel  *  either 10 or 10/100 or 10/100/1000 at all duplexes.
31228cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
31238cfa0ad2SJack F Vogel  *  PHY setup routines.
31248cfa0ad2SJack F Vogel  **/
3125daf9197cSJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
31268cfa0ad2SJack F Vogel {
31278cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
31288cfa0ad2SJack F Vogel 	u32 phy_ctrl;
31298cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
31308cfa0ad2SJack F Vogel 	u16 data;
31318cfa0ad2SJack F Vogel 
31328cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan");
31338cfa0ad2SJack F Vogel 
31348cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
31358cfa0ad2SJack F Vogel 
31368cfa0ad2SJack F Vogel 	if (!active) {
31378cfa0ad2SJack F Vogel 		phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
31388cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
31399d81738fSJack F Vogel 
31409d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
31416ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
31429d81738fSJack F Vogel 
31436ab6bfe3SJack F Vogel 		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
31448cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
31458cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
31468cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
31478cfa0ad2SJack F Vogel 		 */
31488cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
31498cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
31508cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
31518cfa0ad2SJack F Vogel 						    &data);
31528cfa0ad2SJack F Vogel 			if (ret_val)
31536ab6bfe3SJack F Vogel 				return ret_val;
31548cfa0ad2SJack F Vogel 
31558cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
31568cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
31578cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
31588cfa0ad2SJack F Vogel 						     data);
31598cfa0ad2SJack F Vogel 			if (ret_val)
31606ab6bfe3SJack F Vogel 				return ret_val;
31618cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
31628cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
31638cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
31648cfa0ad2SJack F Vogel 						    &data);
31658cfa0ad2SJack F Vogel 			if (ret_val)
31666ab6bfe3SJack F Vogel 				return ret_val;
31678cfa0ad2SJack F Vogel 
31688cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
31698cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
31708cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
31718cfa0ad2SJack F Vogel 						     data);
31728cfa0ad2SJack F Vogel 			if (ret_val)
31736ab6bfe3SJack F Vogel 				return ret_val;
31748cfa0ad2SJack F Vogel 		}
31758cfa0ad2SJack F Vogel 	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
31768cfa0ad2SJack F Vogel 		   (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
31778cfa0ad2SJack F Vogel 		   (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
31788cfa0ad2SJack F Vogel 		phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
31798cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
31808cfa0ad2SJack F Vogel 
31819d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
31826ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
31839d81738fSJack F Vogel 
31846ab6bfe3SJack F Vogel 		/* Call gig speed drop workaround on LPLU before accessing
31858cfa0ad2SJack F Vogel 		 * any PHY registers
31868cfa0ad2SJack F Vogel 		 */
31879d81738fSJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
31888cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
31898cfa0ad2SJack F Vogel 
31908cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
31918cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw,
31928cfa0ad2SJack F Vogel 					    IGP01E1000_PHY_PORT_CONFIG,
31938cfa0ad2SJack F Vogel 					    &data);
31948cfa0ad2SJack F Vogel 		if (ret_val)
31956ab6bfe3SJack F Vogel 			return ret_val;
31968cfa0ad2SJack F Vogel 
31978cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
31988cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
31998cfa0ad2SJack F Vogel 					     IGP01E1000_PHY_PORT_CONFIG,
32008cfa0ad2SJack F Vogel 					     data);
32018cfa0ad2SJack F Vogel 	}
32028cfa0ad2SJack F Vogel 
32038cfa0ad2SJack F Vogel 	return ret_val;
32048cfa0ad2SJack F Vogel }
32058cfa0ad2SJack F Vogel 
32068cfa0ad2SJack F Vogel /**
32078cfa0ad2SJack F Vogel  *  e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
32088cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
32098cfa0ad2SJack F Vogel  *  @bank:  pointer to the variable that returns the active bank
32108cfa0ad2SJack F Vogel  *
32118cfa0ad2SJack F Vogel  *  Reads signature byte from the NVM using the flash access registers.
3212d035aa2dSJack F Vogel  *  Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
32138cfa0ad2SJack F Vogel  **/
32148cfa0ad2SJack F Vogel static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
32158cfa0ad2SJack F Vogel {
3216d035aa2dSJack F Vogel 	u32 eecd;
32178cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
32188cfa0ad2SJack F Vogel 	u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
32198cfa0ad2SJack F Vogel 	u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
3220d035aa2dSJack F Vogel 	u8 sig_byte = 0;
32216ab6bfe3SJack F Vogel 	s32 ret_val;
32228cfa0ad2SJack F Vogel 
32237d9119bdSJack F Vogel 	DEBUGFUNC("e1000_valid_nvm_bank_detect_ich8lan");
32247d9119bdSJack F Vogel 
3225d035aa2dSJack F Vogel 	switch (hw->mac.type) {
3226d035aa2dSJack F Vogel 	case e1000_ich8lan:
3227d035aa2dSJack F Vogel 	case e1000_ich9lan:
3228d035aa2dSJack F Vogel 		eecd = E1000_READ_REG(hw, E1000_EECD);
3229d035aa2dSJack F Vogel 		if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
3230d035aa2dSJack F Vogel 		    E1000_EECD_SEC1VAL_VALID_MASK) {
3231d035aa2dSJack F Vogel 			if (eecd & E1000_EECD_SEC1VAL)
32328cfa0ad2SJack F Vogel 				*bank = 1;
32338cfa0ad2SJack F Vogel 			else
32348cfa0ad2SJack F Vogel 				*bank = 0;
3235d035aa2dSJack F Vogel 
32366ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
3237d035aa2dSJack F Vogel 		}
32384dab5c37SJack F Vogel 		DEBUGOUT("Unable to determine valid NVM bank via EEC - reading flash signature\n");
3239d035aa2dSJack F Vogel 		/* fall-thru */
3240d035aa2dSJack F Vogel 	default:
3241d035aa2dSJack F Vogel 		/* set bank to 0 in case flash read fails */
32428cfa0ad2SJack F Vogel 		*bank = 0;
32438cfa0ad2SJack F Vogel 
3244d035aa2dSJack F Vogel 		/* Check bank 0 */
3245d035aa2dSJack F Vogel 		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
3246d035aa2dSJack F Vogel 							&sig_byte);
3247d035aa2dSJack F Vogel 		if (ret_val)
32486ab6bfe3SJack F Vogel 			return ret_val;
3249d035aa2dSJack F Vogel 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
3250d035aa2dSJack F Vogel 		    E1000_ICH_NVM_SIG_VALUE) {
3251d035aa2dSJack F Vogel 			*bank = 0;
32526ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
3253d035aa2dSJack F Vogel 		}
3254d035aa2dSJack F Vogel 
3255d035aa2dSJack F Vogel 		/* Check bank 1 */
3256d035aa2dSJack F Vogel 		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
3257d035aa2dSJack F Vogel 							bank1_offset,
3258d035aa2dSJack F Vogel 							&sig_byte);
3259d035aa2dSJack F Vogel 		if (ret_val)
32606ab6bfe3SJack F Vogel 			return ret_val;
3261d035aa2dSJack F Vogel 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
3262d035aa2dSJack F Vogel 		    E1000_ICH_NVM_SIG_VALUE) {
32638cfa0ad2SJack F Vogel 			*bank = 1;
32646ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
32658cfa0ad2SJack F Vogel 		}
32668cfa0ad2SJack F Vogel 
3267d035aa2dSJack F Vogel 		DEBUGOUT("ERROR: No valid NVM bank present\n");
32686ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
3269d035aa2dSJack F Vogel 	}
32708cfa0ad2SJack F Vogel }
32718cfa0ad2SJack F Vogel 
32728cfa0ad2SJack F Vogel /**
32738cfa0ad2SJack F Vogel  *  e1000_read_nvm_ich8lan - Read word(s) from the NVM
32748cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
32758cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the word(s) to read.
32768cfa0ad2SJack F Vogel  *  @words: Size of data to read in words
32778cfa0ad2SJack F Vogel  *  @data: Pointer to the word(s) to read at offset.
32788cfa0ad2SJack F Vogel  *
32798cfa0ad2SJack F Vogel  *  Reads a word(s) from the NVM using the flash access registers.
32808cfa0ad2SJack F Vogel  **/
32818cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
32828cfa0ad2SJack F Vogel 				  u16 *data)
32838cfa0ad2SJack F Vogel {
32848cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
3285daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
32868cfa0ad2SJack F Vogel 	u32 act_offset;
32878cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
32888cfa0ad2SJack F Vogel 	u32 bank = 0;
32898cfa0ad2SJack F Vogel 	u16 i, word;
32908cfa0ad2SJack F Vogel 
32918cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_nvm_ich8lan");
32928cfa0ad2SJack F Vogel 
32938cfa0ad2SJack F Vogel 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
32948cfa0ad2SJack F Vogel 	    (words == 0)) {
32958cfa0ad2SJack F Vogel 		DEBUGOUT("nvm parameter(s) out of bounds\n");
32968cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
32978cfa0ad2SJack F Vogel 		goto out;
32988cfa0ad2SJack F Vogel 	}
32998cfa0ad2SJack F Vogel 
33004edd8523SJack F Vogel 	nvm->ops.acquire(hw);
33018cfa0ad2SJack F Vogel 
33028cfa0ad2SJack F Vogel 	ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
33034edd8523SJack F Vogel 	if (ret_val != E1000_SUCCESS) {
33044edd8523SJack F Vogel 		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
33054edd8523SJack F Vogel 		bank = 0;
33064edd8523SJack F Vogel 	}
33078cfa0ad2SJack F Vogel 
33088cfa0ad2SJack F Vogel 	act_offset = (bank) ? nvm->flash_bank_size : 0;
33098cfa0ad2SJack F Vogel 	act_offset += offset;
33108cfa0ad2SJack F Vogel 
33114edd8523SJack F Vogel 	ret_val = E1000_SUCCESS;
33128cfa0ad2SJack F Vogel 	for (i = 0; i < words; i++) {
33134dab5c37SJack F Vogel 		if (dev_spec->shadow_ram[offset+i].modified) {
33148cfa0ad2SJack F Vogel 			data[i] = dev_spec->shadow_ram[offset+i].value;
33158cfa0ad2SJack F Vogel 		} else {
33168cfa0ad2SJack F Vogel 			ret_val = e1000_read_flash_word_ich8lan(hw,
33178cfa0ad2SJack F Vogel 								act_offset + i,
33188cfa0ad2SJack F Vogel 								&word);
33198cfa0ad2SJack F Vogel 			if (ret_val)
33208cfa0ad2SJack F Vogel 				break;
33218cfa0ad2SJack F Vogel 			data[i] = word;
33228cfa0ad2SJack F Vogel 		}
33238cfa0ad2SJack F Vogel 	}
33248cfa0ad2SJack F Vogel 
33258cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
33268cfa0ad2SJack F Vogel 
33278cfa0ad2SJack F Vogel out:
3328d035aa2dSJack F Vogel 	if (ret_val)
3329d035aa2dSJack F Vogel 		DEBUGOUT1("NVM read error: %d\n", ret_val);
3330d035aa2dSJack F Vogel 
33318cfa0ad2SJack F Vogel 	return ret_val;
33328cfa0ad2SJack F Vogel }
33338cfa0ad2SJack F Vogel 
33348cfa0ad2SJack F Vogel /**
33358cfa0ad2SJack F Vogel  *  e1000_flash_cycle_init_ich8lan - Initialize flash
33368cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
33378cfa0ad2SJack F Vogel  *
33388cfa0ad2SJack F Vogel  *  This function does initial flash setup so that a new read/write/erase cycle
33398cfa0ad2SJack F Vogel  *  can be started.
33408cfa0ad2SJack F Vogel  **/
33418cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
33428cfa0ad2SJack F Vogel {
33438cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
33448cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
33458cfa0ad2SJack F Vogel 
33468cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_flash_cycle_init_ich8lan");
33478cfa0ad2SJack F Vogel 
33488cfa0ad2SJack F Vogel 	hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
33498cfa0ad2SJack F Vogel 
33508cfa0ad2SJack F Vogel 	/* Check if the flash descriptor is valid */
33516ab6bfe3SJack F Vogel 	if (!hsfsts.hsf_status.fldesvalid) {
33524dab5c37SJack F Vogel 		DEBUGOUT("Flash descriptor invalid.  SW Sequencing must be used.\n");
33536ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
33548cfa0ad2SJack F Vogel 	}
33558cfa0ad2SJack F Vogel 
33568cfa0ad2SJack F Vogel 	/* Clear FCERR and DAEL in hw status by writing 1 */
33578cfa0ad2SJack F Vogel 	hsfsts.hsf_status.flcerr = 1;
33588cfa0ad2SJack F Vogel 	hsfsts.hsf_status.dael = 1;
33598cfa0ad2SJack F Vogel 	E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
33608cfa0ad2SJack F Vogel 
33616ab6bfe3SJack F Vogel 	/* Either we should have a hardware SPI cycle in progress
33628cfa0ad2SJack F Vogel 	 * bit to check against, in order to start a new cycle or
33638cfa0ad2SJack F Vogel 	 * FDONE bit should be changed in the hardware so that it
33648cfa0ad2SJack F Vogel 	 * is 1 after hardware reset, which can then be used as an
33658cfa0ad2SJack F Vogel 	 * indication whether a cycle is in progress or has been
33668cfa0ad2SJack F Vogel 	 * completed.
33678cfa0ad2SJack F Vogel 	 */
33688cfa0ad2SJack F Vogel 
33696ab6bfe3SJack F Vogel 	if (!hsfsts.hsf_status.flcinprog) {
33706ab6bfe3SJack F Vogel 		/* There is no cycle running at present,
33718cfa0ad2SJack F Vogel 		 * so we can start a cycle.
33728cfa0ad2SJack F Vogel 		 * Begin by setting Flash Cycle Done.
33738cfa0ad2SJack F Vogel 		 */
33748cfa0ad2SJack F Vogel 		hsfsts.hsf_status.flcdone = 1;
33758cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
33768cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
33778cfa0ad2SJack F Vogel 	} else {
3378730d3130SJack F Vogel 		s32 i;
3379730d3130SJack F Vogel 
33806ab6bfe3SJack F Vogel 		/* Otherwise poll for sometime so the current
33818cfa0ad2SJack F Vogel 		 * cycle has a chance to end before giving up.
33828cfa0ad2SJack F Vogel 		 */
33838cfa0ad2SJack F Vogel 		for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
33848cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
33858cfa0ad2SJack F Vogel 							      ICH_FLASH_HSFSTS);
33866ab6bfe3SJack F Vogel 			if (!hsfsts.hsf_status.flcinprog) {
33878cfa0ad2SJack F Vogel 				ret_val = E1000_SUCCESS;
33888cfa0ad2SJack F Vogel 				break;
33898cfa0ad2SJack F Vogel 			}
33908cfa0ad2SJack F Vogel 			usec_delay(1);
33918cfa0ad2SJack F Vogel 		}
33928cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS) {
33936ab6bfe3SJack F Vogel 			/* Successful in waiting for previous cycle to timeout,
33948cfa0ad2SJack F Vogel 			 * now set the Flash Cycle Done.
33958cfa0ad2SJack F Vogel 			 */
33968cfa0ad2SJack F Vogel 			hsfsts.hsf_status.flcdone = 1;
3397daf9197cSJack F Vogel 			E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
33988cfa0ad2SJack F Vogel 						hsfsts.regval);
33998cfa0ad2SJack F Vogel 		} else {
34004dab5c37SJack F Vogel 			DEBUGOUT("Flash controller busy, cannot get access\n");
34018cfa0ad2SJack F Vogel 		}
34028cfa0ad2SJack F Vogel 	}
34038cfa0ad2SJack F Vogel 
34048cfa0ad2SJack F Vogel 	return ret_val;
34058cfa0ad2SJack F Vogel }
34068cfa0ad2SJack F Vogel 
34078cfa0ad2SJack F Vogel /**
34088cfa0ad2SJack F Vogel  *  e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
34098cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
34108cfa0ad2SJack F Vogel  *  @timeout: maximum time to wait for completion
34118cfa0ad2SJack F Vogel  *
34128cfa0ad2SJack F Vogel  *  This function starts a flash cycle and waits for its completion.
34138cfa0ad2SJack F Vogel  **/
34148cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
34158cfa0ad2SJack F Vogel {
34168cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
34178cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
34188cfa0ad2SJack F Vogel 	u32 i = 0;
34198cfa0ad2SJack F Vogel 
34208cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_flash_cycle_ich8lan");
34218cfa0ad2SJack F Vogel 
34228cfa0ad2SJack F Vogel 	/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
34238cfa0ad2SJack F Vogel 	hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
34248cfa0ad2SJack F Vogel 	hsflctl.hsf_ctrl.flcgo = 1;
3425*8cc64f1eSJack F Vogel 
34268cfa0ad2SJack F Vogel 	E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
34278cfa0ad2SJack F Vogel 
34288cfa0ad2SJack F Vogel 	/* wait till FDONE bit is set to 1 */
34298cfa0ad2SJack F Vogel 	do {
34308cfa0ad2SJack F Vogel 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
34316ab6bfe3SJack F Vogel 		if (hsfsts.hsf_status.flcdone)
34328cfa0ad2SJack F Vogel 			break;
34338cfa0ad2SJack F Vogel 		usec_delay(1);
34348cfa0ad2SJack F Vogel 	} while (i++ < timeout);
34358cfa0ad2SJack F Vogel 
34366ab6bfe3SJack F Vogel 	if (hsfsts.hsf_status.flcdone && !hsfsts.hsf_status.flcerr)
34376ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
34388cfa0ad2SJack F Vogel 
34396ab6bfe3SJack F Vogel 	return -E1000_ERR_NVM;
34408cfa0ad2SJack F Vogel }
34418cfa0ad2SJack F Vogel 
34428cfa0ad2SJack F Vogel /**
34438cfa0ad2SJack F Vogel  *  e1000_read_flash_word_ich8lan - Read word from flash
34448cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
34458cfa0ad2SJack F Vogel  *  @offset: offset to data location
34468cfa0ad2SJack F Vogel  *  @data: pointer to the location for storing the data
34478cfa0ad2SJack F Vogel  *
34488cfa0ad2SJack F Vogel  *  Reads the flash word at offset into data.  Offset is converted
34498cfa0ad2SJack F Vogel  *  to bytes before read.
34508cfa0ad2SJack F Vogel  **/
34518cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
34528cfa0ad2SJack F Vogel 					 u16 *data)
34538cfa0ad2SJack F Vogel {
34548cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_flash_word_ich8lan");
34558cfa0ad2SJack F Vogel 
34566ab6bfe3SJack F Vogel 	if (!data)
34576ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
34588cfa0ad2SJack F Vogel 
34598cfa0ad2SJack F Vogel 	/* Must convert offset into bytes. */
34608cfa0ad2SJack F Vogel 	offset <<= 1;
34618cfa0ad2SJack F Vogel 
34626ab6bfe3SJack F Vogel 	return e1000_read_flash_data_ich8lan(hw, offset, 2, data);
34638cfa0ad2SJack F Vogel }
34648cfa0ad2SJack F Vogel 
34658cfa0ad2SJack F Vogel /**
34668cfa0ad2SJack F Vogel  *  e1000_read_flash_byte_ich8lan - Read byte from flash
34678cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
34688cfa0ad2SJack F Vogel  *  @offset: The offset of the byte to read.
34698cfa0ad2SJack F Vogel  *  @data: Pointer to a byte to store the value read.
34708cfa0ad2SJack F Vogel  *
34718cfa0ad2SJack F Vogel  *  Reads a single byte from the NVM using the flash access registers.
34728cfa0ad2SJack F Vogel  **/
34738cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
34748cfa0ad2SJack F Vogel 					 u8 *data)
34758cfa0ad2SJack F Vogel {
34766ab6bfe3SJack F Vogel 	s32 ret_val;
34778cfa0ad2SJack F Vogel 	u16 word = 0;
34788cfa0ad2SJack F Vogel 
34798cfa0ad2SJack F Vogel 	ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
3480*8cc64f1eSJack F Vogel 
34818cfa0ad2SJack F Vogel 	if (ret_val)
34826ab6bfe3SJack F Vogel 		return ret_val;
34838cfa0ad2SJack F Vogel 
34848cfa0ad2SJack F Vogel 	*data = (u8)word;
34858cfa0ad2SJack F Vogel 
34866ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
34878cfa0ad2SJack F Vogel }
34888cfa0ad2SJack F Vogel 
34898cfa0ad2SJack F Vogel /**
34908cfa0ad2SJack F Vogel  *  e1000_read_flash_data_ich8lan - Read byte or word from NVM
34918cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
34928cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the byte or word to read.
34938cfa0ad2SJack F Vogel  *  @size: Size of data to read, 1=byte 2=word
34948cfa0ad2SJack F Vogel  *  @data: Pointer to the word to store the value read.
34958cfa0ad2SJack F Vogel  *
34968cfa0ad2SJack F Vogel  *  Reads a byte or word from the NVM using the flash access registers.
34978cfa0ad2SJack F Vogel  **/
34988cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
34998cfa0ad2SJack F Vogel 					 u8 size, u16 *data)
35008cfa0ad2SJack F Vogel {
35018cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
35028cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
35038cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
35048cfa0ad2SJack F Vogel 	u32 flash_data = 0;
35058cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
35068cfa0ad2SJack F Vogel 	u8 count = 0;
35078cfa0ad2SJack F Vogel 
35088cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_flash_data_ich8lan");
35098cfa0ad2SJack F Vogel 
35108cfa0ad2SJack F Vogel 	if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
35116ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
35127609433eSJack F Vogel 	flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
35137609433eSJack F Vogel 			     hw->nvm.flash_base_addr);
35148cfa0ad2SJack F Vogel 
35158cfa0ad2SJack F Vogel 	do {
35168cfa0ad2SJack F Vogel 		usec_delay(1);
35178cfa0ad2SJack F Vogel 		/* Steps */
35188cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
35198cfa0ad2SJack F Vogel 		if (ret_val != E1000_SUCCESS)
35208cfa0ad2SJack F Vogel 			break;
35218cfa0ad2SJack F Vogel 		hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
3522*8cc64f1eSJack F Vogel 
35238cfa0ad2SJack F Vogel 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
35248cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.fldbcount = size - 1;
35258cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
35268cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
35278cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
35288cfa0ad2SJack F Vogel 
3529*8cc64f1eSJack F Vogel 		ret_val = e1000_flash_cycle_ich8lan(hw,
35308cfa0ad2SJack F Vogel 						ICH_FLASH_READ_COMMAND_TIMEOUT);
35318cfa0ad2SJack F Vogel 
35326ab6bfe3SJack F Vogel 		/* Check if FCERR is set to 1, if set to 1, clear it
35338cfa0ad2SJack F Vogel 		 * and try the whole sequence a few more times, else
35348cfa0ad2SJack F Vogel 		 * read in (shift in) the Flash Data0, the order is
35358cfa0ad2SJack F Vogel 		 * least significant byte first msb to lsb
35368cfa0ad2SJack F Vogel 		 */
35378cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS) {
35388cfa0ad2SJack F Vogel 			flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
3539daf9197cSJack F Vogel 			if (size == 1)
35408cfa0ad2SJack F Vogel 				*data = (u8)(flash_data & 0x000000FF);
3541daf9197cSJack F Vogel 			else if (size == 2)
35428cfa0ad2SJack F Vogel 				*data = (u16)(flash_data & 0x0000FFFF);
35438cfa0ad2SJack F Vogel 			break;
35448cfa0ad2SJack F Vogel 		} else {
35456ab6bfe3SJack F Vogel 			/* If we've gotten here, then things are probably
35468cfa0ad2SJack F Vogel 			 * completely hosed, but if the error condition is
35478cfa0ad2SJack F Vogel 			 * detected, it won't hurt to give it another try...
35488cfa0ad2SJack F Vogel 			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
35498cfa0ad2SJack F Vogel 			 */
35508cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
35518cfa0ad2SJack F Vogel 							      ICH_FLASH_HSFSTS);
35526ab6bfe3SJack F Vogel 			if (hsfsts.hsf_status.flcerr) {
35538cfa0ad2SJack F Vogel 				/* Repeat for some time before giving up. */
35548cfa0ad2SJack F Vogel 				continue;
35556ab6bfe3SJack F Vogel 			} else if (!hsfsts.hsf_status.flcdone) {
35564dab5c37SJack F Vogel 				DEBUGOUT("Timeout error - flash cycle did not complete.\n");
35578cfa0ad2SJack F Vogel 				break;
35588cfa0ad2SJack F Vogel 			}
35598cfa0ad2SJack F Vogel 		}
35608cfa0ad2SJack F Vogel 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
35618cfa0ad2SJack F Vogel 
35628cfa0ad2SJack F Vogel 	return ret_val;
35638cfa0ad2SJack F Vogel }
35648cfa0ad2SJack F Vogel 
3565*8cc64f1eSJack F Vogel 
35668cfa0ad2SJack F Vogel /**
35678cfa0ad2SJack F Vogel  *  e1000_write_nvm_ich8lan - Write word(s) to the NVM
35688cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
35698cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the word(s) to write.
35708cfa0ad2SJack F Vogel  *  @words: Size of data to write in words
35718cfa0ad2SJack F Vogel  *  @data: Pointer to the word(s) to write at offset.
35728cfa0ad2SJack F Vogel  *
35738cfa0ad2SJack F Vogel  *  Writes a byte or word to the NVM using the flash access registers.
35748cfa0ad2SJack F Vogel  **/
35758cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
35768cfa0ad2SJack F Vogel 				   u16 *data)
35778cfa0ad2SJack F Vogel {
35788cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
3579daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
35808cfa0ad2SJack F Vogel 	u16 i;
35818cfa0ad2SJack F Vogel 
35828cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_nvm_ich8lan");
35838cfa0ad2SJack F Vogel 
35848cfa0ad2SJack F Vogel 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
35858cfa0ad2SJack F Vogel 	    (words == 0)) {
35868cfa0ad2SJack F Vogel 		DEBUGOUT("nvm parameter(s) out of bounds\n");
35876ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
35888cfa0ad2SJack F Vogel 	}
35898cfa0ad2SJack F Vogel 
35904edd8523SJack F Vogel 	nvm->ops.acquire(hw);
35918cfa0ad2SJack F Vogel 
35928cfa0ad2SJack F Vogel 	for (i = 0; i < words; i++) {
35938cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[offset+i].modified = TRUE;
35948cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[offset+i].value = data[i];
35958cfa0ad2SJack F Vogel 	}
35968cfa0ad2SJack F Vogel 
35978cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
35988cfa0ad2SJack F Vogel 
35996ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
36008cfa0ad2SJack F Vogel }
36018cfa0ad2SJack F Vogel 
36028cfa0ad2SJack F Vogel /**
36038cfa0ad2SJack F Vogel  *  e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
36048cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
36058cfa0ad2SJack F Vogel  *
36068cfa0ad2SJack F Vogel  *  The NVM checksum is updated by calling the generic update_nvm_checksum,
36078cfa0ad2SJack F Vogel  *  which writes the checksum to the shadow ram.  The changes in the shadow
36088cfa0ad2SJack F Vogel  *  ram are then committed to the EEPROM by processing each bank at a time
36098cfa0ad2SJack F Vogel  *  checking for the modified bit and writing only the pending changes.
36108cfa0ad2SJack F Vogel  *  After a successful commit, the shadow ram is cleared and is ready for
36118cfa0ad2SJack F Vogel  *  future writes.
36128cfa0ad2SJack F Vogel  **/
36138cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
36148cfa0ad2SJack F Vogel {
36158cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
3616daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
36178cfa0ad2SJack F Vogel 	u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
36188cfa0ad2SJack F Vogel 	s32 ret_val;
3619*8cc64f1eSJack F Vogel 	u16 data = 0;
36208cfa0ad2SJack F Vogel 
36218cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_update_nvm_checksum_ich8lan");
36228cfa0ad2SJack F Vogel 
36238cfa0ad2SJack F Vogel 	ret_val = e1000_update_nvm_checksum_generic(hw);
36248cfa0ad2SJack F Vogel 	if (ret_val)
36258cfa0ad2SJack F Vogel 		goto out;
36268cfa0ad2SJack F Vogel 
36278cfa0ad2SJack F Vogel 	if (nvm->type != e1000_nvm_flash_sw)
36288cfa0ad2SJack F Vogel 		goto out;
36298cfa0ad2SJack F Vogel 
36304edd8523SJack F Vogel 	nvm->ops.acquire(hw);
36318cfa0ad2SJack F Vogel 
36326ab6bfe3SJack F Vogel 	/* We're writing to the opposite bank so if we're on bank 1,
36338cfa0ad2SJack F Vogel 	 * write to bank 0 etc.  We also need to erase the segment that
36348cfa0ad2SJack F Vogel 	 * is going to be written
36358cfa0ad2SJack F Vogel 	 */
36368cfa0ad2SJack F Vogel 	ret_val =  e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
3637d035aa2dSJack F Vogel 	if (ret_val != E1000_SUCCESS) {
36384edd8523SJack F Vogel 		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
36394edd8523SJack F Vogel 		bank = 0;
3640d035aa2dSJack F Vogel 	}
36418cfa0ad2SJack F Vogel 
36428cfa0ad2SJack F Vogel 	if (bank == 0) {
36438cfa0ad2SJack F Vogel 		new_bank_offset = nvm->flash_bank_size;
36448cfa0ad2SJack F Vogel 		old_bank_offset = 0;
3645d035aa2dSJack F Vogel 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
3646a69ed8dfSJack F Vogel 		if (ret_val)
3647a69ed8dfSJack F Vogel 			goto release;
36488cfa0ad2SJack F Vogel 	} else {
36498cfa0ad2SJack F Vogel 		old_bank_offset = nvm->flash_bank_size;
36508cfa0ad2SJack F Vogel 		new_bank_offset = 0;
3651d035aa2dSJack F Vogel 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
3652a69ed8dfSJack F Vogel 		if (ret_val)
3653a69ed8dfSJack F Vogel 			goto release;
36548cfa0ad2SJack F Vogel 	}
36558cfa0ad2SJack F Vogel 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
36568cfa0ad2SJack F Vogel 		if (dev_spec->shadow_ram[i].modified) {
36578cfa0ad2SJack F Vogel 			data = dev_spec->shadow_ram[i].value;
36588cfa0ad2SJack F Vogel 		} else {
3659d035aa2dSJack F Vogel 			ret_val = e1000_read_flash_word_ich8lan(hw, i +
3660d035aa2dSJack F Vogel 								old_bank_offset,
36618cfa0ad2SJack F Vogel 								&data);
3662d035aa2dSJack F Vogel 			if (ret_val)
3663d035aa2dSJack F Vogel 				break;
36648cfa0ad2SJack F Vogel 		}
36656ab6bfe3SJack F Vogel 		/* If the word is 0x13, then make sure the signature bits
36668cfa0ad2SJack F Vogel 		 * (15:14) are 11b until the commit has completed.
36678cfa0ad2SJack F Vogel 		 * This will allow us to write 10b which indicates the
36688cfa0ad2SJack F Vogel 		 * signature is valid.  We want to do this after the write
36698cfa0ad2SJack F Vogel 		 * has completed so that we don't mark the segment valid
36708cfa0ad2SJack F Vogel 		 * while the write is still in progress
36718cfa0ad2SJack F Vogel 		 */
36728cfa0ad2SJack F Vogel 		if (i == E1000_ICH_NVM_SIG_WORD)
36738cfa0ad2SJack F Vogel 			data |= E1000_ICH_NVM_SIG_MASK;
36748cfa0ad2SJack F Vogel 
36758cfa0ad2SJack F Vogel 		/* Convert offset to bytes. */
36768cfa0ad2SJack F Vogel 		act_offset = (i + new_bank_offset) << 1;
36778cfa0ad2SJack F Vogel 
36788cfa0ad2SJack F Vogel 		usec_delay(100);
3679*8cc64f1eSJack F Vogel 
36808cfa0ad2SJack F Vogel 		/* Write the bytes to the new bank. */
36818cfa0ad2SJack F Vogel 		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
36828cfa0ad2SJack F Vogel 							       act_offset,
36838cfa0ad2SJack F Vogel 							       (u8)data);
36848cfa0ad2SJack F Vogel 		if (ret_val)
36858cfa0ad2SJack F Vogel 			break;
36868cfa0ad2SJack F Vogel 
36878cfa0ad2SJack F Vogel 		usec_delay(100);
36888cfa0ad2SJack F Vogel 		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
36898cfa0ad2SJack F Vogel 							  act_offset + 1,
36908cfa0ad2SJack F Vogel 							  (u8)(data >> 8));
36918cfa0ad2SJack F Vogel 		if (ret_val)
36928cfa0ad2SJack F Vogel 			break;
36938cfa0ad2SJack F Vogel 	 }
36948cfa0ad2SJack F Vogel 
36956ab6bfe3SJack F Vogel 	/* Don't bother writing the segment valid bits if sector
36968cfa0ad2SJack F Vogel 	 * programming failed.
36978cfa0ad2SJack F Vogel 	 */
36988cfa0ad2SJack F Vogel 	if (ret_val) {
36998cfa0ad2SJack F Vogel 		DEBUGOUT("Flash commit failed.\n");
3700a69ed8dfSJack F Vogel 		goto release;
37018cfa0ad2SJack F Vogel 	}
37028cfa0ad2SJack F Vogel 
37036ab6bfe3SJack F Vogel 	/* Finally validate the new segment by setting bit 15:14
37048cfa0ad2SJack F Vogel 	 * to 10b in word 0x13 , this can be done without an
37058cfa0ad2SJack F Vogel 	 * erase as well since these bits are 11 to start with
37068cfa0ad2SJack F Vogel 	 * and we need to change bit 14 to 0b
37078cfa0ad2SJack F Vogel 	 */
37088cfa0ad2SJack F Vogel 	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
3709d035aa2dSJack F Vogel 	ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
3710a69ed8dfSJack F Vogel 	if (ret_val)
3711a69ed8dfSJack F Vogel 		goto release;
37124edd8523SJack F Vogel 
37138cfa0ad2SJack F Vogel 	data &= 0xBFFF;
3714*8cc64f1eSJack F Vogel 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset * 2 + 1,
37158cfa0ad2SJack F Vogel 						       (u8)(data >> 8));
3716a69ed8dfSJack F Vogel 	if (ret_val)
3717a69ed8dfSJack F Vogel 		goto release;
37188cfa0ad2SJack F Vogel 
37196ab6bfe3SJack F Vogel 	/* And invalidate the previously valid segment by setting
37208cfa0ad2SJack F Vogel 	 * its signature word (0x13) high_byte to 0b. This can be
37218cfa0ad2SJack F Vogel 	 * done without an erase because flash erase sets all bits
37228cfa0ad2SJack F Vogel 	 * to 1's. We can write 1's to 0's without an erase
37238cfa0ad2SJack F Vogel 	 */
37248cfa0ad2SJack F Vogel 	act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
3725*8cc64f1eSJack F Vogel 
37268cfa0ad2SJack F Vogel 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
3727*8cc64f1eSJack F Vogel 
3728a69ed8dfSJack F Vogel 	if (ret_val)
3729a69ed8dfSJack F Vogel 		goto release;
37308cfa0ad2SJack F Vogel 
37318cfa0ad2SJack F Vogel 	/* Great!  Everything worked, we can now clear the cached entries. */
37328cfa0ad2SJack F Vogel 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
37338cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].modified = FALSE;
37348cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].value = 0xFFFF;
37358cfa0ad2SJack F Vogel 	}
37368cfa0ad2SJack F Vogel 
3737a69ed8dfSJack F Vogel release:
37388cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
37398cfa0ad2SJack F Vogel 
37406ab6bfe3SJack F Vogel 	/* Reload the EEPROM, or else modifications will not appear
37418cfa0ad2SJack F Vogel 	 * until after the next adapter reset.
37428cfa0ad2SJack F Vogel 	 */
3743a69ed8dfSJack F Vogel 	if (!ret_val) {
37448cfa0ad2SJack F Vogel 		nvm->ops.reload(hw);
37458cfa0ad2SJack F Vogel 		msec_delay(10);
3746a69ed8dfSJack F Vogel 	}
37478cfa0ad2SJack F Vogel 
37488cfa0ad2SJack F Vogel out:
3749d035aa2dSJack F Vogel 	if (ret_val)
3750d035aa2dSJack F Vogel 		DEBUGOUT1("NVM update error: %d\n", ret_val);
3751d035aa2dSJack F Vogel 
37528cfa0ad2SJack F Vogel 	return ret_val;
37538cfa0ad2SJack F Vogel }
37548cfa0ad2SJack F Vogel 
37558cfa0ad2SJack F Vogel /**
37568cfa0ad2SJack F Vogel  *  e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
37578cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
37588cfa0ad2SJack F Vogel  *
37598cfa0ad2SJack F Vogel  *  Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
3760daf9197cSJack F Vogel  *  If the bit is 0, that the EEPROM had been modified, but the checksum was not
3761daf9197cSJack F Vogel  *  calculated, in which case we need to calculate the checksum and set bit 6.
37628cfa0ad2SJack F Vogel  **/
37638cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
37648cfa0ad2SJack F Vogel {
37656ab6bfe3SJack F Vogel 	s32 ret_val;
37668cfa0ad2SJack F Vogel 	u16 data;
37676ab6bfe3SJack F Vogel 	u16 word;
37686ab6bfe3SJack F Vogel 	u16 valid_csum_mask;
37698cfa0ad2SJack F Vogel 
37708cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan");
37718cfa0ad2SJack F Vogel 
37726ab6bfe3SJack F Vogel 	/* Read NVM and check Invalid Image CSUM bit.  If this bit is 0,
37736ab6bfe3SJack F Vogel 	 * the checksum needs to be fixed.  This bit is an indication that
37746ab6bfe3SJack F Vogel 	 * the NVM was prepared by OEM software and did not calculate
37756ab6bfe3SJack F Vogel 	 * the checksum...a likely scenario.
37768cfa0ad2SJack F Vogel 	 */
37776ab6bfe3SJack F Vogel 	switch (hw->mac.type) {
37786ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
37796ab6bfe3SJack F Vogel 		word = NVM_COMPAT;
37806ab6bfe3SJack F Vogel 		valid_csum_mask = NVM_COMPAT_VALID_CSUM;
37816ab6bfe3SJack F Vogel 		break;
37826ab6bfe3SJack F Vogel 	default:
37836ab6bfe3SJack F Vogel 		word = NVM_FUTURE_INIT_WORD1;
37846ab6bfe3SJack F Vogel 		valid_csum_mask = NVM_FUTURE_INIT_WORD1_VALID_CSUM;
37856ab6bfe3SJack F Vogel 		break;
37868cfa0ad2SJack F Vogel 	}
37878cfa0ad2SJack F Vogel 
37886ab6bfe3SJack F Vogel 	ret_val = hw->nvm.ops.read(hw, word, 1, &data);
37896ab6bfe3SJack F Vogel 	if (ret_val)
37908cfa0ad2SJack F Vogel 		return ret_val;
37916ab6bfe3SJack F Vogel 
37926ab6bfe3SJack F Vogel 	if (!(data & valid_csum_mask)) {
37936ab6bfe3SJack F Vogel 		data |= valid_csum_mask;
37946ab6bfe3SJack F Vogel 		ret_val = hw->nvm.ops.write(hw, word, 1, &data);
37956ab6bfe3SJack F Vogel 		if (ret_val)
37966ab6bfe3SJack F Vogel 			return ret_val;
37976ab6bfe3SJack F Vogel 		ret_val = hw->nvm.ops.update(hw);
37986ab6bfe3SJack F Vogel 		if (ret_val)
37996ab6bfe3SJack F Vogel 			return ret_val;
38006ab6bfe3SJack F Vogel 	}
38016ab6bfe3SJack F Vogel 
38026ab6bfe3SJack F Vogel 	return e1000_validate_nvm_checksum_generic(hw);
38038cfa0ad2SJack F Vogel }
38048cfa0ad2SJack F Vogel 
38058cfa0ad2SJack F Vogel /**
38068cfa0ad2SJack F Vogel  *  e1000_write_flash_data_ich8lan - Writes bytes to the NVM
38078cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
38088cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the byte/word to read.
38098cfa0ad2SJack F Vogel  *  @size: Size of data to read, 1=byte 2=word
38108cfa0ad2SJack F Vogel  *  @data: The byte(s) to write to the NVM.
38118cfa0ad2SJack F Vogel  *
38128cfa0ad2SJack F Vogel  *  Writes one/two bytes to the NVM using the flash access registers.
38138cfa0ad2SJack F Vogel  **/
38148cfa0ad2SJack F Vogel static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
38158cfa0ad2SJack F Vogel 					  u8 size, u16 data)
38168cfa0ad2SJack F Vogel {
38178cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
38188cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
38198cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
38208cfa0ad2SJack F Vogel 	u32 flash_data = 0;
38216ab6bfe3SJack F Vogel 	s32 ret_val;
38228cfa0ad2SJack F Vogel 	u8 count = 0;
38238cfa0ad2SJack F Vogel 
38248cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_ich8_data");
38258cfa0ad2SJack F Vogel 
3826*8cc64f1eSJack F Vogel 	if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
38276ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
38288cfa0ad2SJack F Vogel 
38297609433eSJack F Vogel 	flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
38307609433eSJack F Vogel 			     hw->nvm.flash_base_addr);
38318cfa0ad2SJack F Vogel 
38328cfa0ad2SJack F Vogel 	do {
38338cfa0ad2SJack F Vogel 		usec_delay(1);
38348cfa0ad2SJack F Vogel 		/* Steps */
38358cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
38368cfa0ad2SJack F Vogel 		if (ret_val != E1000_SUCCESS)
38378cfa0ad2SJack F Vogel 			break;
38388cfa0ad2SJack F Vogel 		hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
3839*8cc64f1eSJack F Vogel 
38408cfa0ad2SJack F Vogel 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
38418cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.fldbcount = size - 1;
38428cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
38438cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
38448cfa0ad2SJack F Vogel 
38458cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
38468cfa0ad2SJack F Vogel 
38478cfa0ad2SJack F Vogel 		if (size == 1)
38488cfa0ad2SJack F Vogel 			flash_data = (u32)data & 0x00FF;
38498cfa0ad2SJack F Vogel 		else
38508cfa0ad2SJack F Vogel 			flash_data = (u32)data;
38518cfa0ad2SJack F Vogel 
38528cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data);
38538cfa0ad2SJack F Vogel 
38546ab6bfe3SJack F Vogel 		/* check if FCERR is set to 1 , if set to 1, clear it
38558cfa0ad2SJack F Vogel 		 * and try the whole sequence a few more times else done
38568cfa0ad2SJack F Vogel 		 */
38577609433eSJack F Vogel 		ret_val =
38587609433eSJack F Vogel 		    e1000_flash_cycle_ich8lan(hw,
38598cfa0ad2SJack F Vogel 					      ICH_FLASH_WRITE_COMMAND_TIMEOUT);
3860daf9197cSJack F Vogel 		if (ret_val == E1000_SUCCESS)
38618cfa0ad2SJack F Vogel 			break;
3862daf9197cSJack F Vogel 
38636ab6bfe3SJack F Vogel 		/* If we're here, then things are most likely
38648cfa0ad2SJack F Vogel 		 * completely hosed, but if the error condition
38658cfa0ad2SJack F Vogel 		 * is detected, it won't hurt to give it another
38668cfa0ad2SJack F Vogel 		 * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
38678cfa0ad2SJack F Vogel 		 */
3868daf9197cSJack F Vogel 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
38696ab6bfe3SJack F Vogel 		if (hsfsts.hsf_status.flcerr)
38708cfa0ad2SJack F Vogel 			/* Repeat for some time before giving up. */
38718cfa0ad2SJack F Vogel 			continue;
38726ab6bfe3SJack F Vogel 		if (!hsfsts.hsf_status.flcdone) {
38734dab5c37SJack F Vogel 			DEBUGOUT("Timeout error - flash cycle did not complete.\n");
38748cfa0ad2SJack F Vogel 			break;
38758cfa0ad2SJack F Vogel 		}
38768cfa0ad2SJack F Vogel 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
38778cfa0ad2SJack F Vogel 
38788cfa0ad2SJack F Vogel 	return ret_val;
38798cfa0ad2SJack F Vogel }
38808cfa0ad2SJack F Vogel 
3881*8cc64f1eSJack F Vogel 
38828cfa0ad2SJack F Vogel /**
38838cfa0ad2SJack F Vogel  *  e1000_write_flash_byte_ich8lan - Write a single byte to NVM
38848cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
38858cfa0ad2SJack F Vogel  *  @offset: The index of the byte to read.
38868cfa0ad2SJack F Vogel  *  @data: The byte to write to the NVM.
38878cfa0ad2SJack F Vogel  *
38888cfa0ad2SJack F Vogel  *  Writes a single byte to the NVM using the flash access registers.
38898cfa0ad2SJack F Vogel  **/
38908cfa0ad2SJack F Vogel static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
38918cfa0ad2SJack F Vogel 					  u8 data)
38928cfa0ad2SJack F Vogel {
38938cfa0ad2SJack F Vogel 	u16 word = (u16)data;
38948cfa0ad2SJack F Vogel 
38958cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_flash_byte_ich8lan");
38968cfa0ad2SJack F Vogel 
38978cfa0ad2SJack F Vogel 	return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
38988cfa0ad2SJack F Vogel }
38998cfa0ad2SJack F Vogel 
3900*8cc64f1eSJack F Vogel 
3901*8cc64f1eSJack F Vogel 
39028cfa0ad2SJack F Vogel /**
39038cfa0ad2SJack F Vogel  *  e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
39048cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
39058cfa0ad2SJack F Vogel  *  @offset: The offset of the byte to write.
39068cfa0ad2SJack F Vogel  *  @byte: The byte to write to the NVM.
39078cfa0ad2SJack F Vogel  *
39088cfa0ad2SJack F Vogel  *  Writes a single byte to the NVM using the flash access registers.
39098cfa0ad2SJack F Vogel  *  Goes through a retry algorithm before giving up.
39108cfa0ad2SJack F Vogel  **/
39118cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
39128cfa0ad2SJack F Vogel 						u32 offset, u8 byte)
39138cfa0ad2SJack F Vogel {
39148cfa0ad2SJack F Vogel 	s32 ret_val;
39158cfa0ad2SJack F Vogel 	u16 program_retries;
39168cfa0ad2SJack F Vogel 
39178cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan");
39188cfa0ad2SJack F Vogel 
39198cfa0ad2SJack F Vogel 	ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
39206ab6bfe3SJack F Vogel 	if (!ret_val)
39216ab6bfe3SJack F Vogel 		return ret_val;
39228cfa0ad2SJack F Vogel 
39238cfa0ad2SJack F Vogel 	for (program_retries = 0; program_retries < 100; program_retries++) {
39248cfa0ad2SJack F Vogel 		DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset);
39258cfa0ad2SJack F Vogel 		usec_delay(100);
39268cfa0ad2SJack F Vogel 		ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
39278cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS)
39288cfa0ad2SJack F Vogel 			break;
39298cfa0ad2SJack F Vogel 	}
39306ab6bfe3SJack F Vogel 	if (program_retries == 100)
39316ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
39328cfa0ad2SJack F Vogel 
39336ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
39348cfa0ad2SJack F Vogel }
39358cfa0ad2SJack F Vogel 
39368cfa0ad2SJack F Vogel /**
39378cfa0ad2SJack F Vogel  *  e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
39388cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
39398cfa0ad2SJack F Vogel  *  @bank: 0 for first bank, 1 for second bank, etc.
39408cfa0ad2SJack F Vogel  *
39418cfa0ad2SJack F Vogel  *  Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
39428cfa0ad2SJack F Vogel  *  bank N is 4096 * N + flash_reg_addr.
39438cfa0ad2SJack F Vogel  **/
39448cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
39458cfa0ad2SJack F Vogel {
39468cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
39478cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
39488cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
39498cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
39508cfa0ad2SJack F Vogel 	/* bank size is in 16bit words - adjust to bytes */
39518cfa0ad2SJack F Vogel 	u32 flash_bank_size = nvm->flash_bank_size * 2;
39526ab6bfe3SJack F Vogel 	s32 ret_val;
39538cfa0ad2SJack F Vogel 	s32 count = 0;
39548cfa0ad2SJack F Vogel 	s32 j, iteration, sector_size;
39558cfa0ad2SJack F Vogel 
39568cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_erase_flash_bank_ich8lan");
39578cfa0ad2SJack F Vogel 
39588cfa0ad2SJack F Vogel 	hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
39598cfa0ad2SJack F Vogel 
39606ab6bfe3SJack F Vogel 	/* Determine HW Sector size: Read BERASE bits of hw flash status
39618cfa0ad2SJack F Vogel 	 * register
39628cfa0ad2SJack F Vogel 	 * 00: The Hw sector is 256 bytes, hence we need to erase 16
39638cfa0ad2SJack F Vogel 	 *     consecutive sectors.  The start index for the nth Hw sector
39648cfa0ad2SJack F Vogel 	 *     can be calculated as = bank * 4096 + n * 256
39658cfa0ad2SJack F Vogel 	 * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
39668cfa0ad2SJack F Vogel 	 *     The start index for the nth Hw sector can be calculated
39678cfa0ad2SJack F Vogel 	 *     as = bank * 4096
39688cfa0ad2SJack F Vogel 	 * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
39698cfa0ad2SJack F Vogel 	 *     (ich9 only, otherwise error condition)
39708cfa0ad2SJack F Vogel 	 * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
39718cfa0ad2SJack F Vogel 	 */
39728cfa0ad2SJack F Vogel 	switch (hsfsts.hsf_status.berasesz) {
39738cfa0ad2SJack F Vogel 	case 0:
39748cfa0ad2SJack F Vogel 		/* Hw sector size 256 */
39758cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_256;
39768cfa0ad2SJack F Vogel 		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
39778cfa0ad2SJack F Vogel 		break;
39788cfa0ad2SJack F Vogel 	case 1:
39798cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_4K;
39809d81738fSJack F Vogel 		iteration = 1;
39818cfa0ad2SJack F Vogel 		break;
39828cfa0ad2SJack F Vogel 	case 2:
39838cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_8K;
39848bd0025fSJack F Vogel 		iteration = 1;
39858cfa0ad2SJack F Vogel 		break;
39868cfa0ad2SJack F Vogel 	case 3:
39878cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_64K;
39889d81738fSJack F Vogel 		iteration = 1;
39898cfa0ad2SJack F Vogel 		break;
39908cfa0ad2SJack F Vogel 	default:
39916ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
39928cfa0ad2SJack F Vogel 	}
39938cfa0ad2SJack F Vogel 
39948cfa0ad2SJack F Vogel 	/* Start with the base address, then add the sector offset. */
39958cfa0ad2SJack F Vogel 	flash_linear_addr = hw->nvm.flash_base_addr;
39964edd8523SJack F Vogel 	flash_linear_addr += (bank) ? flash_bank_size : 0;
39978cfa0ad2SJack F Vogel 
39988cfa0ad2SJack F Vogel 	for (j = 0; j < iteration; j++) {
39998cfa0ad2SJack F Vogel 		do {
40007609433eSJack F Vogel 			u32 timeout = ICH_FLASH_ERASE_COMMAND_TIMEOUT;
40017609433eSJack F Vogel 
40028cfa0ad2SJack F Vogel 			/* Steps */
40038cfa0ad2SJack F Vogel 			ret_val = e1000_flash_cycle_init_ich8lan(hw);
40048cfa0ad2SJack F Vogel 			if (ret_val)
40056ab6bfe3SJack F Vogel 				return ret_val;
40068cfa0ad2SJack F Vogel 
40076ab6bfe3SJack F Vogel 			/* Write a value 11 (block Erase) in Flash
40088cfa0ad2SJack F Vogel 			 * Cycle field in hw flash control
40098cfa0ad2SJack F Vogel 			 */
4010*8cc64f1eSJack F Vogel 			hsflctl.regval =
4011*8cc64f1eSJack F Vogel 			    E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
4012*8cc64f1eSJack F Vogel 
40138cfa0ad2SJack F Vogel 			hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
4014daf9197cSJack F Vogel 			E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
40158cfa0ad2SJack F Vogel 						hsflctl.regval);
40168cfa0ad2SJack F Vogel 
40176ab6bfe3SJack F Vogel 			/* Write the last 24 bits of an index within the
40188cfa0ad2SJack F Vogel 			 * block into Flash Linear address field in Flash
40198cfa0ad2SJack F Vogel 			 * Address.
40208cfa0ad2SJack F Vogel 			 */
40218cfa0ad2SJack F Vogel 			flash_linear_addr += (j * sector_size);
4022daf9197cSJack F Vogel 			E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR,
40238cfa0ad2SJack F Vogel 					      flash_linear_addr);
40248cfa0ad2SJack F Vogel 
40257609433eSJack F Vogel 			ret_val = e1000_flash_cycle_ich8lan(hw, timeout);
4026daf9197cSJack F Vogel 			if (ret_val == E1000_SUCCESS)
40278cfa0ad2SJack F Vogel 				break;
4028daf9197cSJack F Vogel 
40296ab6bfe3SJack F Vogel 			/* Check if FCERR is set to 1.  If 1,
40308cfa0ad2SJack F Vogel 			 * clear it and try the whole sequence
40318cfa0ad2SJack F Vogel 			 * a few more times else Done
40328cfa0ad2SJack F Vogel 			 */
40338cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
40348cfa0ad2SJack F Vogel 						      ICH_FLASH_HSFSTS);
40356ab6bfe3SJack F Vogel 			if (hsfsts.hsf_status.flcerr)
4036daf9197cSJack F Vogel 				/* repeat for some time before giving up */
40378cfa0ad2SJack F Vogel 				continue;
40386ab6bfe3SJack F Vogel 			else if (!hsfsts.hsf_status.flcdone)
40396ab6bfe3SJack F Vogel 				return ret_val;
40408cfa0ad2SJack F Vogel 		} while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
40418cfa0ad2SJack F Vogel 	}
40428cfa0ad2SJack F Vogel 
40436ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
40448cfa0ad2SJack F Vogel }
40458cfa0ad2SJack F Vogel 
40468cfa0ad2SJack F Vogel /**
40478cfa0ad2SJack F Vogel  *  e1000_valid_led_default_ich8lan - Set the default LED settings
40488cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
40498cfa0ad2SJack F Vogel  *  @data: Pointer to the LED settings
40508cfa0ad2SJack F Vogel  *
40518cfa0ad2SJack F Vogel  *  Reads the LED default settings from the NVM to data.  If the NVM LED
40528cfa0ad2SJack F Vogel  *  settings is all 0's or F's, set the LED default to a valid LED default
40538cfa0ad2SJack F Vogel  *  setting.
40548cfa0ad2SJack F Vogel  **/
40558cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
40568cfa0ad2SJack F Vogel {
40578cfa0ad2SJack F Vogel 	s32 ret_val;
40588cfa0ad2SJack F Vogel 
40598cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_valid_led_default_ich8lan");
40608cfa0ad2SJack F Vogel 
40618cfa0ad2SJack F Vogel 	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
40628cfa0ad2SJack F Vogel 	if (ret_val) {
40638cfa0ad2SJack F Vogel 		DEBUGOUT("NVM Read Error\n");
40646ab6bfe3SJack F Vogel 		return ret_val;
40658cfa0ad2SJack F Vogel 	}
40668cfa0ad2SJack F Vogel 
40674dab5c37SJack F Vogel 	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
40688cfa0ad2SJack F Vogel 		*data = ID_LED_DEFAULT_ICH8LAN;
40698cfa0ad2SJack F Vogel 
40706ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
40718cfa0ad2SJack F Vogel }
40728cfa0ad2SJack F Vogel 
40738cfa0ad2SJack F Vogel /**
40749d81738fSJack F Vogel  *  e1000_id_led_init_pchlan - store LED configurations
40759d81738fSJack F Vogel  *  @hw: pointer to the HW structure
40769d81738fSJack F Vogel  *
40779d81738fSJack F Vogel  *  PCH does not control LEDs via the LEDCTL register, rather it uses
40789d81738fSJack F Vogel  *  the PHY LED configuration register.
40799d81738fSJack F Vogel  *
40809d81738fSJack F Vogel  *  PCH also does not have an "always on" or "always off" mode which
40819d81738fSJack F Vogel  *  complicates the ID feature.  Instead of using the "on" mode to indicate
40829d81738fSJack F Vogel  *  in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()),
40839d81738fSJack F Vogel  *  use "link_up" mode.  The LEDs will still ID on request if there is no
40849d81738fSJack F Vogel  *  link based on logic in e1000_led_[on|off]_pchlan().
40859d81738fSJack F Vogel  **/
40869d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw)
40879d81738fSJack F Vogel {
40889d81738fSJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
40899d81738fSJack F Vogel 	s32 ret_val;
40909d81738fSJack F Vogel 	const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
40919d81738fSJack F Vogel 	const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
40929d81738fSJack F Vogel 	u16 data, i, temp, shift;
40939d81738fSJack F Vogel 
40949d81738fSJack F Vogel 	DEBUGFUNC("e1000_id_led_init_pchlan");
40959d81738fSJack F Vogel 
40969d81738fSJack F Vogel 	/* Get default ID LED modes */
40979d81738fSJack F Vogel 	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
40989d81738fSJack F Vogel 	if (ret_val)
40996ab6bfe3SJack F Vogel 		return ret_val;
41009d81738fSJack F Vogel 
41019d81738fSJack F Vogel 	mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
41029d81738fSJack F Vogel 	mac->ledctl_mode1 = mac->ledctl_default;
41039d81738fSJack F Vogel 	mac->ledctl_mode2 = mac->ledctl_default;
41049d81738fSJack F Vogel 
41059d81738fSJack F Vogel 	for (i = 0; i < 4; i++) {
41069d81738fSJack F Vogel 		temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
41079d81738fSJack F Vogel 		shift = (i * 5);
41089d81738fSJack F Vogel 		switch (temp) {
41099d81738fSJack F Vogel 		case ID_LED_ON1_DEF2:
41109d81738fSJack F Vogel 		case ID_LED_ON1_ON2:
41119d81738fSJack F Vogel 		case ID_LED_ON1_OFF2:
41129d81738fSJack F Vogel 			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
41139d81738fSJack F Vogel 			mac->ledctl_mode1 |= (ledctl_on << shift);
41149d81738fSJack F Vogel 			break;
41159d81738fSJack F Vogel 		case ID_LED_OFF1_DEF2:
41169d81738fSJack F Vogel 		case ID_LED_OFF1_ON2:
41179d81738fSJack F Vogel 		case ID_LED_OFF1_OFF2:
41189d81738fSJack F Vogel 			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
41199d81738fSJack F Vogel 			mac->ledctl_mode1 |= (ledctl_off << shift);
41209d81738fSJack F Vogel 			break;
41219d81738fSJack F Vogel 		default:
41229d81738fSJack F Vogel 			/* Do nothing */
41239d81738fSJack F Vogel 			break;
41249d81738fSJack F Vogel 		}
41259d81738fSJack F Vogel 		switch (temp) {
41269d81738fSJack F Vogel 		case ID_LED_DEF1_ON2:
41279d81738fSJack F Vogel 		case ID_LED_ON1_ON2:
41289d81738fSJack F Vogel 		case ID_LED_OFF1_ON2:
41299d81738fSJack F Vogel 			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
41309d81738fSJack F Vogel 			mac->ledctl_mode2 |= (ledctl_on << shift);
41319d81738fSJack F Vogel 			break;
41329d81738fSJack F Vogel 		case ID_LED_DEF1_OFF2:
41339d81738fSJack F Vogel 		case ID_LED_ON1_OFF2:
41349d81738fSJack F Vogel 		case ID_LED_OFF1_OFF2:
41359d81738fSJack F Vogel 			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
41369d81738fSJack F Vogel 			mac->ledctl_mode2 |= (ledctl_off << shift);
41379d81738fSJack F Vogel 			break;
41389d81738fSJack F Vogel 		default:
41399d81738fSJack F Vogel 			/* Do nothing */
41409d81738fSJack F Vogel 			break;
41419d81738fSJack F Vogel 		}
41429d81738fSJack F Vogel 	}
41439d81738fSJack F Vogel 
41446ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
41459d81738fSJack F Vogel }
41469d81738fSJack F Vogel 
41479d81738fSJack F Vogel /**
41488cfa0ad2SJack F Vogel  *  e1000_get_bus_info_ich8lan - Get/Set the bus type and width
41498cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
41508cfa0ad2SJack F Vogel  *
41518cfa0ad2SJack F Vogel  *  ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
41526ab6bfe3SJack F Vogel  *  register, so the the bus width is hard coded.
41538cfa0ad2SJack F Vogel  **/
41548cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
41558cfa0ad2SJack F Vogel {
41568cfa0ad2SJack F Vogel 	struct e1000_bus_info *bus = &hw->bus;
41578cfa0ad2SJack F Vogel 	s32 ret_val;
41588cfa0ad2SJack F Vogel 
41598cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_bus_info_ich8lan");
41608cfa0ad2SJack F Vogel 
41618cfa0ad2SJack F Vogel 	ret_val = e1000_get_bus_info_pcie_generic(hw);
41628cfa0ad2SJack F Vogel 
41636ab6bfe3SJack F Vogel 	/* ICH devices are "PCI Express"-ish.  They have
41648cfa0ad2SJack F Vogel 	 * a configuration space, but do not contain
41658cfa0ad2SJack F Vogel 	 * PCI Express Capability registers, so bus width
41668cfa0ad2SJack F Vogel 	 * must be hardcoded.
41678cfa0ad2SJack F Vogel 	 */
41688cfa0ad2SJack F Vogel 	if (bus->width == e1000_bus_width_unknown)
41698cfa0ad2SJack F Vogel 		bus->width = e1000_bus_width_pcie_x1;
41708cfa0ad2SJack F Vogel 
41718cfa0ad2SJack F Vogel 	return ret_val;
41728cfa0ad2SJack F Vogel }
41738cfa0ad2SJack F Vogel 
41748cfa0ad2SJack F Vogel /**
41758cfa0ad2SJack F Vogel  *  e1000_reset_hw_ich8lan - Reset the hardware
41768cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
41778cfa0ad2SJack F Vogel  *
41788cfa0ad2SJack F Vogel  *  Does a full reset of the hardware which includes a reset of the PHY and
41798cfa0ad2SJack F Vogel  *  MAC.
41808cfa0ad2SJack F Vogel  **/
41818cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
41828cfa0ad2SJack F Vogel {
41834edd8523SJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
41846ab6bfe3SJack F Vogel 	u16 kum_cfg;
41856ab6bfe3SJack F Vogel 	u32 ctrl, reg;
41868cfa0ad2SJack F Vogel 	s32 ret_val;
41878cfa0ad2SJack F Vogel 
41888cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_reset_hw_ich8lan");
41898cfa0ad2SJack F Vogel 
41906ab6bfe3SJack F Vogel 	/* Prevent the PCI-E bus from sticking if there is no TLP connection
41918cfa0ad2SJack F Vogel 	 * on the last TLP read/write transaction when MAC is reset.
41928cfa0ad2SJack F Vogel 	 */
41938cfa0ad2SJack F Vogel 	ret_val = e1000_disable_pcie_master_generic(hw);
4194daf9197cSJack F Vogel 	if (ret_val)
41958cfa0ad2SJack F Vogel 		DEBUGOUT("PCI-E Master disable polling has failed.\n");
41968cfa0ad2SJack F Vogel 
41978cfa0ad2SJack F Vogel 	DEBUGOUT("Masking off all interrupts\n");
41988cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
41998cfa0ad2SJack F Vogel 
42006ab6bfe3SJack F Vogel 	/* Disable the Transmit and Receive units.  Then delay to allow
42018cfa0ad2SJack F Vogel 	 * any pending transactions to complete before we hit the MAC
42028cfa0ad2SJack F Vogel 	 * with the global reset.
42038cfa0ad2SJack F Vogel 	 */
42048cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RCTL, 0);
42058cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
42068cfa0ad2SJack F Vogel 	E1000_WRITE_FLUSH(hw);
42078cfa0ad2SJack F Vogel 
42088cfa0ad2SJack F Vogel 	msec_delay(10);
42098cfa0ad2SJack F Vogel 
42108cfa0ad2SJack F Vogel 	/* Workaround for ICH8 bit corruption issue in FIFO memory */
42118cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan) {
42128cfa0ad2SJack F Vogel 		/* Set Tx and Rx buffer allocation to 8k apiece. */
42138cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K);
42148cfa0ad2SJack F Vogel 		/* Set Packet Buffer Size to 16k. */
42158cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K);
42168cfa0ad2SJack F Vogel 	}
42178cfa0ad2SJack F Vogel 
42184edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan) {
42194edd8523SJack F Vogel 		/* Save the NVM K1 bit setting*/
42206ab6bfe3SJack F Vogel 		ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, &kum_cfg);
42214edd8523SJack F Vogel 		if (ret_val)
42224edd8523SJack F Vogel 			return ret_val;
42234edd8523SJack F Vogel 
42246ab6bfe3SJack F Vogel 		if (kum_cfg & E1000_NVM_K1_ENABLE)
42254edd8523SJack F Vogel 			dev_spec->nvm_k1_enabled = TRUE;
42264edd8523SJack F Vogel 		else
42274edd8523SJack F Vogel 			dev_spec->nvm_k1_enabled = FALSE;
42284edd8523SJack F Vogel 	}
42294edd8523SJack F Vogel 
42308cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
42318cfa0ad2SJack F Vogel 
42327d9119bdSJack F Vogel 	if (!hw->phy.ops.check_reset_block(hw)) {
42336ab6bfe3SJack F Vogel 		/* Full-chip reset requires MAC and PHY reset at the same
42348cfa0ad2SJack F Vogel 		 * time to make sure the interface between MAC and the
42358cfa0ad2SJack F Vogel 		 * external PHY is reset.
42368cfa0ad2SJack F Vogel 		 */
42378cfa0ad2SJack F Vogel 		ctrl |= E1000_CTRL_PHY_RST;
42387d9119bdSJack F Vogel 
42396ab6bfe3SJack F Vogel 		/* Gate automatic PHY configuration by hardware on
42407d9119bdSJack F Vogel 		 * non-managed 82579
42417d9119bdSJack F Vogel 		 */
42427d9119bdSJack F Vogel 		if ((hw->mac.type == e1000_pch2lan) &&
42437d9119bdSJack F Vogel 		    !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
42447d9119bdSJack F Vogel 			e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
42458cfa0ad2SJack F Vogel 	}
42468cfa0ad2SJack F Vogel 	ret_val = e1000_acquire_swflag_ich8lan(hw);
4247daf9197cSJack F Vogel 	DEBUGOUT("Issuing a global reset to ich8lan\n");
42488cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST));
42494dab5c37SJack F Vogel 	/* cannot issue a flush here because it hangs the hardware */
42508cfa0ad2SJack F Vogel 	msec_delay(20);
42518cfa0ad2SJack F Vogel 
42526ab6bfe3SJack F Vogel 	/* Set Phy Config Counter to 50msec */
42536ab6bfe3SJack F Vogel 	if (hw->mac.type == e1000_pch2lan) {
42546ab6bfe3SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_FEXTNVM3);
42556ab6bfe3SJack F Vogel 		reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
42566ab6bfe3SJack F Vogel 		reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
42576ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_FEXTNVM3, reg);
42586ab6bfe3SJack F Vogel 	}
42596ab6bfe3SJack F Vogel 
42609d81738fSJack F Vogel 	if (!ret_val)
42614dab5c37SJack F Vogel 		E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
42629d81738fSJack F Vogel 
42637d9119bdSJack F Vogel 	if (ctrl & E1000_CTRL_PHY_RST) {
42649d81738fSJack F Vogel 		ret_val = hw->phy.ops.get_cfg_done(hw);
42654edd8523SJack F Vogel 		if (ret_val)
42666ab6bfe3SJack F Vogel 			return ret_val;
42674edd8523SJack F Vogel 
42687d9119bdSJack F Vogel 		ret_val = e1000_post_phy_reset_ich8lan(hw);
42694edd8523SJack F Vogel 		if (ret_val)
42706ab6bfe3SJack F Vogel 			return ret_val;
42717d9119bdSJack F Vogel 	}
42727d9119bdSJack F Vogel 
42736ab6bfe3SJack F Vogel 	/* For PCH, this write will make sure that any noise
42744edd8523SJack F Vogel 	 * will be detected as a CRC error and be dropped rather than show up
42754edd8523SJack F Vogel 	 * as a bad packet to the DMA engine.
42764edd8523SJack F Vogel 	 */
42774edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan)
42784edd8523SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565);
42798cfa0ad2SJack F Vogel 
42808cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
4281730d3130SJack F Vogel 	E1000_READ_REG(hw, E1000_ICR);
42828cfa0ad2SJack F Vogel 
42836ab6bfe3SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_KABGTXD);
42846ab6bfe3SJack F Vogel 	reg |= E1000_KABGTXD_BGSQLBIAS;
42856ab6bfe3SJack F Vogel 	E1000_WRITE_REG(hw, E1000_KABGTXD, reg);
42868cfa0ad2SJack F Vogel 
42876ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
42888cfa0ad2SJack F Vogel }
42898cfa0ad2SJack F Vogel 
42908cfa0ad2SJack F Vogel /**
42918cfa0ad2SJack F Vogel  *  e1000_init_hw_ich8lan - Initialize the hardware
42928cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
42938cfa0ad2SJack F Vogel  *
42948cfa0ad2SJack F Vogel  *  Prepares the hardware for transmit and receive by doing the following:
42958cfa0ad2SJack F Vogel  *   - initialize hardware bits
42968cfa0ad2SJack F Vogel  *   - initialize LED identification
42978cfa0ad2SJack F Vogel  *   - setup receive address registers
42988cfa0ad2SJack F Vogel  *   - setup flow control
42998cfa0ad2SJack F Vogel  *   - setup transmit descriptors
43008cfa0ad2SJack F Vogel  *   - clear statistics
43018cfa0ad2SJack F Vogel  **/
43028cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
43038cfa0ad2SJack F Vogel {
43048cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
43058cfa0ad2SJack F Vogel 	u32 ctrl_ext, txdctl, snoop;
43068cfa0ad2SJack F Vogel 	s32 ret_val;
43078cfa0ad2SJack F Vogel 	u16 i;
43088cfa0ad2SJack F Vogel 
43098cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_hw_ich8lan");
43108cfa0ad2SJack F Vogel 
43118cfa0ad2SJack F Vogel 	e1000_initialize_hw_bits_ich8lan(hw);
43128cfa0ad2SJack F Vogel 
43138cfa0ad2SJack F Vogel 	/* Initialize identification LED */
4314d035aa2dSJack F Vogel 	ret_val = mac->ops.id_led_init(hw);
43156ab6bfe3SJack F Vogel 	/* An error is not fatal and we should not stop init due to this */
4316d035aa2dSJack F Vogel 	if (ret_val)
4317d035aa2dSJack F Vogel 		DEBUGOUT("Error initializing identification LED\n");
43188cfa0ad2SJack F Vogel 
43198cfa0ad2SJack F Vogel 	/* Setup the receive address. */
43208cfa0ad2SJack F Vogel 	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
43218cfa0ad2SJack F Vogel 
43228cfa0ad2SJack F Vogel 	/* Zero out the Multicast HASH table */
43238cfa0ad2SJack F Vogel 	DEBUGOUT("Zeroing the MTA\n");
43248cfa0ad2SJack F Vogel 	for (i = 0; i < mac->mta_reg_count; i++)
43258cfa0ad2SJack F Vogel 		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
43268cfa0ad2SJack F Vogel 
43276ab6bfe3SJack F Vogel 	/* The 82578 Rx buffer will stall if wakeup is enabled in host and
43284dab5c37SJack F Vogel 	 * the ME.  Disable wakeup by clearing the host wakeup bit.
43299d81738fSJack F Vogel 	 * Reset the phy after disabling host wakeup to reset the Rx buffer.
43309d81738fSJack F Vogel 	 */
43319d81738fSJack F Vogel 	if (hw->phy.type == e1000_phy_82578) {
43324dab5c37SJack F Vogel 		hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, &i);
43334dab5c37SJack F Vogel 		i &= ~BM_WUC_HOST_WU_BIT;
43344dab5c37SJack F Vogel 		hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, i);
43359d81738fSJack F Vogel 		ret_val = e1000_phy_hw_reset_ich8lan(hw);
43369d81738fSJack F Vogel 		if (ret_val)
43379d81738fSJack F Vogel 			return ret_val;
43389d81738fSJack F Vogel 	}
43399d81738fSJack F Vogel 
43408cfa0ad2SJack F Vogel 	/* Setup link and flow control */
43418cfa0ad2SJack F Vogel 	ret_val = mac->ops.setup_link(hw);
43428cfa0ad2SJack F Vogel 
43438cfa0ad2SJack F Vogel 	/* Set the transmit descriptor write-back policy for both queues */
43448cfa0ad2SJack F Vogel 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
43457609433eSJack F Vogel 	txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) |
43467609433eSJack F Vogel 		  E1000_TXDCTL_FULL_TX_DESC_WB);
43477609433eSJack F Vogel 	txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) |
43487609433eSJack F Vogel 		  E1000_TXDCTL_MAX_TX_DESC_PREFETCH);
43498cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
43508cfa0ad2SJack F Vogel 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1));
43517609433eSJack F Vogel 	txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) |
43527609433eSJack F Vogel 		  E1000_TXDCTL_FULL_TX_DESC_WB);
43537609433eSJack F Vogel 	txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) |
43547609433eSJack F Vogel 		  E1000_TXDCTL_MAX_TX_DESC_PREFETCH);
43558cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl);
43568cfa0ad2SJack F Vogel 
43576ab6bfe3SJack F Vogel 	/* ICH8 has opposite polarity of no_snoop bits.
43588cfa0ad2SJack F Vogel 	 * By default, we should use snoop behavior.
43598cfa0ad2SJack F Vogel 	 */
43608cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
43618cfa0ad2SJack F Vogel 		snoop = PCIE_ICH8_SNOOP_ALL;
43628cfa0ad2SJack F Vogel 	else
43638cfa0ad2SJack F Vogel 		snoop = (u32) ~(PCIE_NO_SNOOP_ALL);
43648cfa0ad2SJack F Vogel 	e1000_set_pcie_no_snoop_generic(hw, snoop);
43658cfa0ad2SJack F Vogel 
43668cfa0ad2SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
43678cfa0ad2SJack F Vogel 	ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
43688cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
43698cfa0ad2SJack F Vogel 
43706ab6bfe3SJack F Vogel 	/* Clear all of the statistics registers (clear on read).  It is
43718cfa0ad2SJack F Vogel 	 * important that we do this after we have tried to establish link
43728cfa0ad2SJack F Vogel 	 * because the symbol error count will increment wildly if there
43738cfa0ad2SJack F Vogel 	 * is no link.
43748cfa0ad2SJack F Vogel 	 */
43758cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_ich8lan(hw);
43768cfa0ad2SJack F Vogel 
43778cfa0ad2SJack F Vogel 	return ret_val;
43788cfa0ad2SJack F Vogel }
43796ab6bfe3SJack F Vogel 
43808cfa0ad2SJack F Vogel /**
43818cfa0ad2SJack F Vogel  *  e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
43828cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
43838cfa0ad2SJack F Vogel  *
43848cfa0ad2SJack F Vogel  *  Sets/Clears required hardware bits necessary for correctly setting up the
43858cfa0ad2SJack F Vogel  *  hardware for transmit and receive.
43868cfa0ad2SJack F Vogel  **/
43878cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
43888cfa0ad2SJack F Vogel {
43898cfa0ad2SJack F Vogel 	u32 reg;
43908cfa0ad2SJack F Vogel 
43918cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_initialize_hw_bits_ich8lan");
43928cfa0ad2SJack F Vogel 
43938cfa0ad2SJack F Vogel 	/* Extended Device Control */
43948cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
43958cfa0ad2SJack F Vogel 	reg |= (1 << 22);
43969d81738fSJack F Vogel 	/* Enable PHY low-power state when MAC is at D3 w/o WoL */
43979d81738fSJack F Vogel 	if (hw->mac.type >= e1000_pchlan)
43989d81738fSJack F Vogel 		reg |= E1000_CTRL_EXT_PHYPDEN;
43998cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
44008cfa0ad2SJack F Vogel 
44018cfa0ad2SJack F Vogel 	/* Transmit Descriptor Control 0 */
44028cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
44038cfa0ad2SJack F Vogel 	reg |= (1 << 22);
44048cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
44058cfa0ad2SJack F Vogel 
44068cfa0ad2SJack F Vogel 	/* Transmit Descriptor Control 1 */
44078cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
44088cfa0ad2SJack F Vogel 	reg |= (1 << 22);
44098cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
44108cfa0ad2SJack F Vogel 
44118cfa0ad2SJack F Vogel 	/* Transmit Arbitration Control 0 */
44128cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TARC(0));
44138cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan)
44148cfa0ad2SJack F Vogel 		reg |= (1 << 28) | (1 << 29);
44158cfa0ad2SJack F Vogel 	reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
44168cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TARC(0), reg);
44178cfa0ad2SJack F Vogel 
44188cfa0ad2SJack F Vogel 	/* Transmit Arbitration Control 1 */
44198cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TARC(1));
44208cfa0ad2SJack F Vogel 	if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
44218cfa0ad2SJack F Vogel 		reg &= ~(1 << 28);
44228cfa0ad2SJack F Vogel 	else
44238cfa0ad2SJack F Vogel 		reg |= (1 << 28);
44248cfa0ad2SJack F Vogel 	reg |= (1 << 24) | (1 << 26) | (1 << 30);
44258cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TARC(1), reg);
44268cfa0ad2SJack F Vogel 
44278cfa0ad2SJack F Vogel 	/* Device Status */
44288cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan) {
44298cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_STATUS);
4430*8cc64f1eSJack F Vogel 		reg &= ~(1 << 31);
44318cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_STATUS, reg);
44328cfa0ad2SJack F Vogel 	}
44338cfa0ad2SJack F Vogel 
44346ab6bfe3SJack F Vogel 	/* work-around descriptor data corruption issue during nfs v2 udp
44358ec87fc5SJack F Vogel 	 * traffic, just disable the nfs filtering capability
44368ec87fc5SJack F Vogel 	 */
44378ec87fc5SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_RFCTL);
44388ec87fc5SJack F Vogel 	reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS);
44397609433eSJack F Vogel 
44406ab6bfe3SJack F Vogel 	/* Disable IPv6 extension header parsing because some malformed
44416ab6bfe3SJack F Vogel 	 * IPv6 headers can hang the Rx.
44426ab6bfe3SJack F Vogel 	 */
44436ab6bfe3SJack F Vogel 	if (hw->mac.type == e1000_ich8lan)
44446ab6bfe3SJack F Vogel 		reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS);
44458ec87fc5SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RFCTL, reg);
44468ec87fc5SJack F Vogel 
44476ab6bfe3SJack F Vogel 	/* Enable ECC on Lynxpoint */
44486ab6bfe3SJack F Vogel 	if (hw->mac.type == e1000_pch_lpt) {
44496ab6bfe3SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_PBECCSTS);
44506ab6bfe3SJack F Vogel 		reg |= E1000_PBECCSTS_ECC_ENABLE;
44516ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBECCSTS, reg);
44526ab6bfe3SJack F Vogel 
44536ab6bfe3SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_CTRL);
44546ab6bfe3SJack F Vogel 		reg |= E1000_CTRL_MEHE;
44556ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, reg);
44566ab6bfe3SJack F Vogel 	}
44576ab6bfe3SJack F Vogel 
44588cfa0ad2SJack F Vogel 	return;
44598cfa0ad2SJack F Vogel }
44608cfa0ad2SJack F Vogel 
44618cfa0ad2SJack F Vogel /**
44628cfa0ad2SJack F Vogel  *  e1000_setup_link_ich8lan - Setup flow control and link settings
44638cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
44648cfa0ad2SJack F Vogel  *
44658cfa0ad2SJack F Vogel  *  Determines which flow control settings to use, then configures flow
44668cfa0ad2SJack F Vogel  *  control.  Calls the appropriate media-specific link configuration
44678cfa0ad2SJack F Vogel  *  function.  Assuming the adapter has a valid link partner, a valid link
44688cfa0ad2SJack F Vogel  *  should be established.  Assumes the hardware has previously been reset
44698cfa0ad2SJack F Vogel  *  and the transmitter and receiver are not enabled.
44708cfa0ad2SJack F Vogel  **/
44718cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
44728cfa0ad2SJack F Vogel {
44736ab6bfe3SJack F Vogel 	s32 ret_val;
44748cfa0ad2SJack F Vogel 
44758cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_link_ich8lan");
44768cfa0ad2SJack F Vogel 
44778cfa0ad2SJack F Vogel 	if (hw->phy.ops.check_reset_block(hw))
44786ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
44798cfa0ad2SJack F Vogel 
44806ab6bfe3SJack F Vogel 	/* ICH parts do not have a word in the NVM to determine
44818cfa0ad2SJack F Vogel 	 * the default flow control setting, so we explicitly
44828cfa0ad2SJack F Vogel 	 * set it to full.
44838cfa0ad2SJack F Vogel 	 */
4484daf9197cSJack F Vogel 	if (hw->fc.requested_mode == e1000_fc_default)
4485daf9197cSJack F Vogel 		hw->fc.requested_mode = e1000_fc_full;
44868cfa0ad2SJack F Vogel 
44876ab6bfe3SJack F Vogel 	/* Save off the requested flow control mode for use later.  Depending
4488daf9197cSJack F Vogel 	 * on the link partner's capabilities, we may or may not use this mode.
4489daf9197cSJack F Vogel 	 */
4490daf9197cSJack F Vogel 	hw->fc.current_mode = hw->fc.requested_mode;
44918cfa0ad2SJack F Vogel 
4492daf9197cSJack F Vogel 	DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
4493daf9197cSJack F Vogel 		hw->fc.current_mode);
44948cfa0ad2SJack F Vogel 
44958cfa0ad2SJack F Vogel 	/* Continue to configure the copper link. */
44968cfa0ad2SJack F Vogel 	ret_val = hw->mac.ops.setup_physical_interface(hw);
44978cfa0ad2SJack F Vogel 	if (ret_val)
44986ab6bfe3SJack F Vogel 		return ret_val;
44998cfa0ad2SJack F Vogel 
45008cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
45019d81738fSJack F Vogel 	if ((hw->phy.type == e1000_phy_82578) ||
45027d9119bdSJack F Vogel 	    (hw->phy.type == e1000_phy_82579) ||
45036ab6bfe3SJack F Vogel 	    (hw->phy.type == e1000_phy_i217) ||
45049d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577)) {
45057d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FCRTV_PCH, hw->fc.refresh_time);
45067d9119bdSJack F Vogel 
45079d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw,
45089d81738fSJack F Vogel 					     PHY_REG(BM_PORT_CTRL_PAGE, 27),
45099d81738fSJack F Vogel 					     hw->fc.pause_time);
45109d81738fSJack F Vogel 		if (ret_val)
45116ab6bfe3SJack F Vogel 			return ret_val;
45129d81738fSJack F Vogel 	}
45138cfa0ad2SJack F Vogel 
45146ab6bfe3SJack F Vogel 	return e1000_set_fc_watermarks_generic(hw);
45158cfa0ad2SJack F Vogel }
45168cfa0ad2SJack F Vogel 
45178cfa0ad2SJack F Vogel /**
45188cfa0ad2SJack F Vogel  *  e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
45198cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
45208cfa0ad2SJack F Vogel  *
45218cfa0ad2SJack F Vogel  *  Configures the kumeran interface to the PHY to wait the appropriate time
45228cfa0ad2SJack F Vogel  *  when polling the PHY, then call the generic setup_copper_link to finish
45238cfa0ad2SJack F Vogel  *  configuring the copper link.
45248cfa0ad2SJack F Vogel  **/
45258cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
45268cfa0ad2SJack F Vogel {
45278cfa0ad2SJack F Vogel 	u32 ctrl;
45288cfa0ad2SJack F Vogel 	s32 ret_val;
45298cfa0ad2SJack F Vogel 	u16 reg_data;
45308cfa0ad2SJack F Vogel 
45318cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_copper_link_ich8lan");
45328cfa0ad2SJack F Vogel 
45338cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
45348cfa0ad2SJack F Vogel 	ctrl |= E1000_CTRL_SLU;
45358cfa0ad2SJack F Vogel 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
45368cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
45378cfa0ad2SJack F Vogel 
45386ab6bfe3SJack F Vogel 	/* Set the mac to wait the maximum time between each iteration
45398cfa0ad2SJack F Vogel 	 * and increase the max iterations when polling the phy;
45408cfa0ad2SJack F Vogel 	 * this fixes erroneous timeouts at 10Mbps.
45418cfa0ad2SJack F Vogel 	 */
45424edd8523SJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_TIMEOUTS,
45438cfa0ad2SJack F Vogel 					       0xFFFF);
45448cfa0ad2SJack F Vogel 	if (ret_val)
45456ab6bfe3SJack F Vogel 		return ret_val;
45469d81738fSJack F Vogel 	ret_val = e1000_read_kmrn_reg_generic(hw,
45479d81738fSJack F Vogel 					      E1000_KMRNCTRLSTA_INBAND_PARAM,
45488cfa0ad2SJack F Vogel 					      &reg_data);
45498cfa0ad2SJack F Vogel 	if (ret_val)
45506ab6bfe3SJack F Vogel 		return ret_val;
45518cfa0ad2SJack F Vogel 	reg_data |= 0x3F;
45529d81738fSJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
45539d81738fSJack F Vogel 					       E1000_KMRNCTRLSTA_INBAND_PARAM,
45548cfa0ad2SJack F Vogel 					       reg_data);
45558cfa0ad2SJack F Vogel 	if (ret_val)
45566ab6bfe3SJack F Vogel 		return ret_val;
45578cfa0ad2SJack F Vogel 
4558d035aa2dSJack F Vogel 	switch (hw->phy.type) {
4559d035aa2dSJack F Vogel 	case e1000_phy_igp_3:
45608cfa0ad2SJack F Vogel 		ret_val = e1000_copper_link_setup_igp(hw);
45618cfa0ad2SJack F Vogel 		if (ret_val)
45626ab6bfe3SJack F Vogel 			return ret_val;
4563d035aa2dSJack F Vogel 		break;
4564d035aa2dSJack F Vogel 	case e1000_phy_bm:
45659d81738fSJack F Vogel 	case e1000_phy_82578:
45668cfa0ad2SJack F Vogel 		ret_val = e1000_copper_link_setup_m88(hw);
45678cfa0ad2SJack F Vogel 		if (ret_val)
45686ab6bfe3SJack F Vogel 			return ret_val;
4569d035aa2dSJack F Vogel 		break;
45709d81738fSJack F Vogel 	case e1000_phy_82577:
45717d9119bdSJack F Vogel 	case e1000_phy_82579:
45729d81738fSJack F Vogel 		ret_val = e1000_copper_link_setup_82577(hw);
45739d81738fSJack F Vogel 		if (ret_val)
45746ab6bfe3SJack F Vogel 			return ret_val;
45759d81738fSJack F Vogel 		break;
4576d035aa2dSJack F Vogel 	case e1000_phy_ife:
45778cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL,
45788cfa0ad2SJack F Vogel 					       &reg_data);
45798cfa0ad2SJack F Vogel 		if (ret_val)
45806ab6bfe3SJack F Vogel 			return ret_val;
45818cfa0ad2SJack F Vogel 
45828cfa0ad2SJack F Vogel 		reg_data &= ~IFE_PMC_AUTO_MDIX;
45838cfa0ad2SJack F Vogel 
45848cfa0ad2SJack F Vogel 		switch (hw->phy.mdix) {
45858cfa0ad2SJack F Vogel 		case 1:
45868cfa0ad2SJack F Vogel 			reg_data &= ~IFE_PMC_FORCE_MDIX;
45878cfa0ad2SJack F Vogel 			break;
45888cfa0ad2SJack F Vogel 		case 2:
45898cfa0ad2SJack F Vogel 			reg_data |= IFE_PMC_FORCE_MDIX;
45908cfa0ad2SJack F Vogel 			break;
45918cfa0ad2SJack F Vogel 		case 0:
45928cfa0ad2SJack F Vogel 		default:
45938cfa0ad2SJack F Vogel 			reg_data |= IFE_PMC_AUTO_MDIX;
45948cfa0ad2SJack F Vogel 			break;
45958cfa0ad2SJack F Vogel 		}
45968cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL,
45978cfa0ad2SJack F Vogel 						reg_data);
45988cfa0ad2SJack F Vogel 		if (ret_val)
45996ab6bfe3SJack F Vogel 			return ret_val;
4600d035aa2dSJack F Vogel 		break;
4601d035aa2dSJack F Vogel 	default:
4602d035aa2dSJack F Vogel 		break;
46038cfa0ad2SJack F Vogel 	}
46048cfa0ad2SJack F Vogel 
46056ab6bfe3SJack F Vogel 	return e1000_setup_copper_link_generic(hw);
46066ab6bfe3SJack F Vogel }
46076ab6bfe3SJack F Vogel 
46086ab6bfe3SJack F Vogel /**
46096ab6bfe3SJack F Vogel  *  e1000_setup_copper_link_pch_lpt - Configure MAC/PHY interface
46106ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
46116ab6bfe3SJack F Vogel  *
46126ab6bfe3SJack F Vogel  *  Calls the PHY specific link setup function and then calls the
46136ab6bfe3SJack F Vogel  *  generic setup_copper_link to finish configuring the link for
46146ab6bfe3SJack F Vogel  *  Lynxpoint PCH devices
46156ab6bfe3SJack F Vogel  **/
46166ab6bfe3SJack F Vogel static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw)
46176ab6bfe3SJack F Vogel {
46186ab6bfe3SJack F Vogel 	u32 ctrl;
46196ab6bfe3SJack F Vogel 	s32 ret_val;
46206ab6bfe3SJack F Vogel 
46216ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_setup_copper_link_pch_lpt");
46226ab6bfe3SJack F Vogel 
46236ab6bfe3SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
46246ab6bfe3SJack F Vogel 	ctrl |= E1000_CTRL_SLU;
46256ab6bfe3SJack F Vogel 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
46266ab6bfe3SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
46276ab6bfe3SJack F Vogel 
46286ab6bfe3SJack F Vogel 	ret_val = e1000_copper_link_setup_82577(hw);
46296ab6bfe3SJack F Vogel 	if (ret_val)
46308cfa0ad2SJack F Vogel 		return ret_val;
46316ab6bfe3SJack F Vogel 
46326ab6bfe3SJack F Vogel 	return e1000_setup_copper_link_generic(hw);
46338cfa0ad2SJack F Vogel }
46348cfa0ad2SJack F Vogel 
46358cfa0ad2SJack F Vogel /**
46368cfa0ad2SJack F Vogel  *  e1000_get_link_up_info_ich8lan - Get current link speed and duplex
46378cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
46388cfa0ad2SJack F Vogel  *  @speed: pointer to store current link speed
46398cfa0ad2SJack F Vogel  *  @duplex: pointer to store the current link duplex
46408cfa0ad2SJack F Vogel  *
46418cfa0ad2SJack F Vogel  *  Calls the generic get_speed_and_duplex to retrieve the current link
46428cfa0ad2SJack F Vogel  *  information and then calls the Kumeran lock loss workaround for links at
46438cfa0ad2SJack F Vogel  *  gigabit speeds.
46448cfa0ad2SJack F Vogel  **/
46458cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
46468cfa0ad2SJack F Vogel 					  u16 *duplex)
46478cfa0ad2SJack F Vogel {
46488cfa0ad2SJack F Vogel 	s32 ret_val;
46498cfa0ad2SJack F Vogel 
46508cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_link_up_info_ich8lan");
46518cfa0ad2SJack F Vogel 
46528cfa0ad2SJack F Vogel 	ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
46538cfa0ad2SJack F Vogel 	if (ret_val)
46546ab6bfe3SJack F Vogel 		return ret_val;
46558cfa0ad2SJack F Vogel 
46568cfa0ad2SJack F Vogel 	if ((hw->mac.type == e1000_ich8lan) &&
46578cfa0ad2SJack F Vogel 	    (hw->phy.type == e1000_phy_igp_3) &&
46588cfa0ad2SJack F Vogel 	    (*speed == SPEED_1000)) {
46598cfa0ad2SJack F Vogel 		ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
46608cfa0ad2SJack F Vogel 	}
46618cfa0ad2SJack F Vogel 
46628cfa0ad2SJack F Vogel 	return ret_val;
46638cfa0ad2SJack F Vogel }
46648cfa0ad2SJack F Vogel 
46658cfa0ad2SJack F Vogel /**
46668cfa0ad2SJack F Vogel  *  e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
46678cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
46688cfa0ad2SJack F Vogel  *
46698cfa0ad2SJack F Vogel  *  Work-around for 82566 Kumeran PCS lock loss:
46708cfa0ad2SJack F Vogel  *  On link status change (i.e. PCI reset, speed change) and link is up and
46718cfa0ad2SJack F Vogel  *  speed is gigabit-
46728cfa0ad2SJack F Vogel  *    0) if workaround is optionally disabled do nothing
46738cfa0ad2SJack F Vogel  *    1) wait 1ms for Kumeran link to come up
46748cfa0ad2SJack F Vogel  *    2) check Kumeran Diagnostic register PCS lock loss bit
46758cfa0ad2SJack F Vogel  *    3) if not set the link is locked (all is good), otherwise...
46768cfa0ad2SJack F Vogel  *    4) reset the PHY
46778cfa0ad2SJack F Vogel  *    5) repeat up to 10 times
46788cfa0ad2SJack F Vogel  *  Note: this is only called for IGP3 copper when speed is 1gb.
46798cfa0ad2SJack F Vogel  **/
46808cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
46818cfa0ad2SJack F Vogel {
4682daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
46838cfa0ad2SJack F Vogel 	u32 phy_ctrl;
46846ab6bfe3SJack F Vogel 	s32 ret_val;
46858cfa0ad2SJack F Vogel 	u16 i, data;
46868cfa0ad2SJack F Vogel 	bool link;
46878cfa0ad2SJack F Vogel 
46888cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan");
46898cfa0ad2SJack F Vogel 
4690730d3130SJack F Vogel 	if (!dev_spec->kmrn_lock_loss_workaround_enabled)
46916ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
46928cfa0ad2SJack F Vogel 
46936ab6bfe3SJack F Vogel 	/* Make sure link is up before proceeding.  If not just return.
46948cfa0ad2SJack F Vogel 	 * Attempting this while link is negotiating fouled up link
46958cfa0ad2SJack F Vogel 	 * stability
46968cfa0ad2SJack F Vogel 	 */
46978cfa0ad2SJack F Vogel 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
46986ab6bfe3SJack F Vogel 	if (!link)
46996ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
47008cfa0ad2SJack F Vogel 
47018cfa0ad2SJack F Vogel 	for (i = 0; i < 10; i++) {
47028cfa0ad2SJack F Vogel 		/* read once to clear */
47038cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
47048cfa0ad2SJack F Vogel 		if (ret_val)
47056ab6bfe3SJack F Vogel 			return ret_val;
47068cfa0ad2SJack F Vogel 		/* and again to get new status */
47078cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
47088cfa0ad2SJack F Vogel 		if (ret_val)
47096ab6bfe3SJack F Vogel 			return ret_val;
47108cfa0ad2SJack F Vogel 
47118cfa0ad2SJack F Vogel 		/* check for PCS lock */
47126ab6bfe3SJack F Vogel 		if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS))
47136ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
47148cfa0ad2SJack F Vogel 
47158cfa0ad2SJack F Vogel 		/* Issue PHY reset */
47168cfa0ad2SJack F Vogel 		hw->phy.ops.reset(hw);
47178cfa0ad2SJack F Vogel 		msec_delay_irq(5);
47188cfa0ad2SJack F Vogel 	}
47198cfa0ad2SJack F Vogel 	/* Disable GigE link negotiation */
47208cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
47218cfa0ad2SJack F Vogel 	phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
47228cfa0ad2SJack F Vogel 		     E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
47238cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
47248cfa0ad2SJack F Vogel 
47256ab6bfe3SJack F Vogel 	/* Call gig speed drop workaround on Gig disable before accessing
47268cfa0ad2SJack F Vogel 	 * any PHY registers
47278cfa0ad2SJack F Vogel 	 */
47288cfa0ad2SJack F Vogel 	e1000_gig_downshift_workaround_ich8lan(hw);
47298cfa0ad2SJack F Vogel 
47308cfa0ad2SJack F Vogel 	/* unable to acquire PCS lock */
47316ab6bfe3SJack F Vogel 	return -E1000_ERR_PHY;
47328cfa0ad2SJack F Vogel }
47338cfa0ad2SJack F Vogel 
47348cfa0ad2SJack F Vogel /**
47358cfa0ad2SJack F Vogel  *  e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
47368cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
47378cfa0ad2SJack F Vogel  *  @state: boolean value used to set the current Kumeran workaround state
47388cfa0ad2SJack F Vogel  *
47398cfa0ad2SJack F Vogel  *  If ICH8, set the current Kumeran workaround state (enabled - TRUE
47408cfa0ad2SJack F Vogel  *  /disabled - FALSE).
47418cfa0ad2SJack F Vogel  **/
47428cfa0ad2SJack F Vogel void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
47438cfa0ad2SJack F Vogel 						 bool state)
47448cfa0ad2SJack F Vogel {
4745daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
47468cfa0ad2SJack F Vogel 
47478cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan");
47488cfa0ad2SJack F Vogel 
47498cfa0ad2SJack F Vogel 	if (hw->mac.type != e1000_ich8lan) {
47508cfa0ad2SJack F Vogel 		DEBUGOUT("Workaround applies to ICH8 only.\n");
4751daf9197cSJack F Vogel 		return;
47528cfa0ad2SJack F Vogel 	}
47538cfa0ad2SJack F Vogel 
47548cfa0ad2SJack F Vogel 	dev_spec->kmrn_lock_loss_workaround_enabled = state;
47558cfa0ad2SJack F Vogel 
47568cfa0ad2SJack F Vogel 	return;
47578cfa0ad2SJack F Vogel }
47588cfa0ad2SJack F Vogel 
47598cfa0ad2SJack F Vogel /**
47608cfa0ad2SJack F Vogel  *  e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
47618cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
47628cfa0ad2SJack F Vogel  *
47638cfa0ad2SJack F Vogel  *  Workaround for 82566 power-down on D3 entry:
47648cfa0ad2SJack F Vogel  *    1) disable gigabit link
47658cfa0ad2SJack F Vogel  *    2) write VR power-down enable
47668cfa0ad2SJack F Vogel  *    3) read it back
47678cfa0ad2SJack F Vogel  *  Continue if successful, else issue LCD reset and repeat
47688cfa0ad2SJack F Vogel  **/
47698cfa0ad2SJack F Vogel void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
47708cfa0ad2SJack F Vogel {
47718cfa0ad2SJack F Vogel 	u32 reg;
47728cfa0ad2SJack F Vogel 	u16 data;
47738cfa0ad2SJack F Vogel 	u8  retry = 0;
47748cfa0ad2SJack F Vogel 
47758cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan");
47768cfa0ad2SJack F Vogel 
47778cfa0ad2SJack F Vogel 	if (hw->phy.type != e1000_phy_igp_3)
47786ab6bfe3SJack F Vogel 		return;
47798cfa0ad2SJack F Vogel 
47808cfa0ad2SJack F Vogel 	/* Try the workaround twice (if needed) */
47818cfa0ad2SJack F Vogel 	do {
47828cfa0ad2SJack F Vogel 		/* Disable link */
47838cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
47848cfa0ad2SJack F Vogel 		reg |= (E1000_PHY_CTRL_GBE_DISABLE |
47858cfa0ad2SJack F Vogel 			E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
47868cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg);
47878cfa0ad2SJack F Vogel 
47886ab6bfe3SJack F Vogel 		/* Call gig speed drop workaround on Gig disable before
47898cfa0ad2SJack F Vogel 		 * accessing any PHY registers
47908cfa0ad2SJack F Vogel 		 */
47918cfa0ad2SJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
47928cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
47938cfa0ad2SJack F Vogel 
47948cfa0ad2SJack F Vogel 		/* Write VR power-down enable */
47958cfa0ad2SJack F Vogel 		hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
47968cfa0ad2SJack F Vogel 		data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
4797daf9197cSJack F Vogel 		hw->phy.ops.write_reg(hw, IGP3_VR_CTRL,
47988cfa0ad2SJack F Vogel 				      data | IGP3_VR_CTRL_MODE_SHUTDOWN);
47998cfa0ad2SJack F Vogel 
48008cfa0ad2SJack F Vogel 		/* Read it back and test */
48018cfa0ad2SJack F Vogel 		hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
48028cfa0ad2SJack F Vogel 		data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
48038cfa0ad2SJack F Vogel 		if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
48048cfa0ad2SJack F Vogel 			break;
48058cfa0ad2SJack F Vogel 
48068cfa0ad2SJack F Vogel 		/* Issue PHY reset and repeat at most one more time */
48078cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_CTRL);
48088cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST);
48098cfa0ad2SJack F Vogel 		retry++;
48108cfa0ad2SJack F Vogel 	} while (retry);
48118cfa0ad2SJack F Vogel }
48128cfa0ad2SJack F Vogel 
48138cfa0ad2SJack F Vogel /**
48148cfa0ad2SJack F Vogel  *  e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working
48158cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
48168cfa0ad2SJack F Vogel  *
48178cfa0ad2SJack F Vogel  *  Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
48188cfa0ad2SJack F Vogel  *  LPLU, Gig disable, MDIC PHY reset):
48198cfa0ad2SJack F Vogel  *    1) Set Kumeran Near-end loopback
48208cfa0ad2SJack F Vogel  *    2) Clear Kumeran Near-end loopback
48214dab5c37SJack F Vogel  *  Should only be called for ICH8[m] devices with any 1G Phy.
48228cfa0ad2SJack F Vogel  **/
48238cfa0ad2SJack F Vogel void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
48248cfa0ad2SJack F Vogel {
48256ab6bfe3SJack F Vogel 	s32 ret_val;
48268cfa0ad2SJack F Vogel 	u16 reg_data;
48278cfa0ad2SJack F Vogel 
48288cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan");
48298cfa0ad2SJack F Vogel 
48308cfa0ad2SJack F Vogel 	if ((hw->mac.type != e1000_ich8lan) ||
48314dab5c37SJack F Vogel 	    (hw->phy.type == e1000_phy_ife))
48326ab6bfe3SJack F Vogel 		return;
48338cfa0ad2SJack F Vogel 
48348cfa0ad2SJack F Vogel 	ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
48358cfa0ad2SJack F Vogel 					      &reg_data);
48368cfa0ad2SJack F Vogel 	if (ret_val)
48376ab6bfe3SJack F Vogel 		return;
48388cfa0ad2SJack F Vogel 	reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
48398cfa0ad2SJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
48408cfa0ad2SJack F Vogel 					       E1000_KMRNCTRLSTA_DIAG_OFFSET,
48418cfa0ad2SJack F Vogel 					       reg_data);
48428cfa0ad2SJack F Vogel 	if (ret_val)
48438cfa0ad2SJack F Vogel 		return;
48446ab6bfe3SJack F Vogel 	reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
48456ab6bfe3SJack F Vogel 	e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
48466ab6bfe3SJack F Vogel 				     reg_data);
48478cfa0ad2SJack F Vogel }
48488cfa0ad2SJack F Vogel 
48498cfa0ad2SJack F Vogel /**
48504dab5c37SJack F Vogel  *  e1000_suspend_workarounds_ich8lan - workarounds needed during S0->Sx
48518cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
48528cfa0ad2SJack F Vogel  *
48538cfa0ad2SJack F Vogel  *  During S0 to Sx transition, it is possible the link remains at gig
48548cfa0ad2SJack F Vogel  *  instead of negotiating to a lower speed.  Before going to Sx, set
48554dab5c37SJack F Vogel  *  'Gig Disable' to force link speed negotiation to a lower speed based on
48564dab5c37SJack F Vogel  *  the LPLU setting in the NVM or custom setting.  For PCH and newer parts,
48574dab5c37SJack F Vogel  *  the OEM bits PHY register (LED, GbE disable and LPLU configurations) also
48584dab5c37SJack F Vogel  *  needs to be written.
48596ab6bfe3SJack F Vogel  *  Parts that support (and are linked to a partner which support) EEE in
48606ab6bfe3SJack F Vogel  *  100Mbps should disable LPLU since 100Mbps w/ EEE requires less power
48616ab6bfe3SJack F Vogel  *  than 10Mbps w/o EEE.
48628cfa0ad2SJack F Vogel  **/
48634dab5c37SJack F Vogel void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
48648cfa0ad2SJack F Vogel {
48656ab6bfe3SJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
48668cfa0ad2SJack F Vogel 	u32 phy_ctrl;
48677d9119bdSJack F Vogel 	s32 ret_val;
48688cfa0ad2SJack F Vogel 
48694dab5c37SJack F Vogel 	DEBUGFUNC("e1000_suspend_workarounds_ich8lan");
48707d9119bdSJack F Vogel 
48718cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
48724dab5c37SJack F Vogel 	phy_ctrl |= E1000_PHY_CTRL_GBE_DISABLE;
48736ab6bfe3SJack F Vogel 
48746ab6bfe3SJack F Vogel 	if (hw->phy.type == e1000_phy_i217) {
48756ab6bfe3SJack F Vogel 		u16 phy_reg, device_id = hw->device_id;
48766ab6bfe3SJack F Vogel 
48776ab6bfe3SJack F Vogel 		if ((device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
4878*8cc64f1eSJack F Vogel 		    (device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) ||
4879*8cc64f1eSJack F Vogel 		    (device_id == E1000_DEV_ID_PCH_I218_LM3) ||
4880*8cc64f1eSJack F Vogel 		    (device_id == E1000_DEV_ID_PCH_I218_V3)) {
48816ab6bfe3SJack F Vogel 			u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6);
48826ab6bfe3SJack F Vogel 
48836ab6bfe3SJack F Vogel 			E1000_WRITE_REG(hw, E1000_FEXTNVM6,
48846ab6bfe3SJack F Vogel 					fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK);
48856ab6bfe3SJack F Vogel 		}
48866ab6bfe3SJack F Vogel 
48876ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
48886ab6bfe3SJack F Vogel 		if (ret_val)
48896ab6bfe3SJack F Vogel 			goto out;
48906ab6bfe3SJack F Vogel 
48916ab6bfe3SJack F Vogel 		if (!dev_spec->eee_disable) {
48926ab6bfe3SJack F Vogel 			u16 eee_advert;
48936ab6bfe3SJack F Vogel 
48946ab6bfe3SJack F Vogel 			ret_val =
48956ab6bfe3SJack F Vogel 			    e1000_read_emi_reg_locked(hw,
48966ab6bfe3SJack F Vogel 						      I217_EEE_ADVERTISEMENT,
48976ab6bfe3SJack F Vogel 						      &eee_advert);
48986ab6bfe3SJack F Vogel 			if (ret_val)
48996ab6bfe3SJack F Vogel 				goto release;
49006ab6bfe3SJack F Vogel 
49016ab6bfe3SJack F Vogel 			/* Disable LPLU if both link partners support 100BaseT
49026ab6bfe3SJack F Vogel 			 * EEE and 100Full is advertised on both ends of the
49037609433eSJack F Vogel 			 * link, and enable Auto Enable LPI since there will
49047609433eSJack F Vogel 			 * be no driver to enable LPI while in Sx.
49056ab6bfe3SJack F Vogel 			 */
49066ab6bfe3SJack F Vogel 			if ((eee_advert & I82579_EEE_100_SUPPORTED) &&
49076ab6bfe3SJack F Vogel 			    (dev_spec->eee_lp_ability &
49086ab6bfe3SJack F Vogel 			     I82579_EEE_100_SUPPORTED) &&
49097609433eSJack F Vogel 			    (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)) {
49106ab6bfe3SJack F Vogel 				phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU |
49116ab6bfe3SJack F Vogel 					      E1000_PHY_CTRL_NOND0A_LPLU);
49127609433eSJack F Vogel 
49137609433eSJack F Vogel 				/* Set Auto Enable LPI after link up */
49147609433eSJack F Vogel 				hw->phy.ops.read_reg_locked(hw,
49157609433eSJack F Vogel 							    I217_LPI_GPIO_CTRL,
49167609433eSJack F Vogel 							    &phy_reg);
49177609433eSJack F Vogel 				phy_reg |= I217_LPI_GPIO_CTRL_AUTO_EN_LPI;
49187609433eSJack F Vogel 				hw->phy.ops.write_reg_locked(hw,
49197609433eSJack F Vogel 							     I217_LPI_GPIO_CTRL,
49207609433eSJack F Vogel 							     phy_reg);
49217609433eSJack F Vogel 			}
49226ab6bfe3SJack F Vogel 		}
49236ab6bfe3SJack F Vogel 
49246ab6bfe3SJack F Vogel 		/* For i217 Intel Rapid Start Technology support,
49256ab6bfe3SJack F Vogel 		 * when the system is going into Sx and no manageability engine
49266ab6bfe3SJack F Vogel 		 * is present, the driver must configure proxy to reset only on
49276ab6bfe3SJack F Vogel 		 * power good.  LPI (Low Power Idle) state must also reset only
49286ab6bfe3SJack F Vogel 		 * on power good, as well as the MTA (Multicast table array).
49296ab6bfe3SJack F Vogel 		 * The SMBus release must also be disabled on LCD reset.
49306ab6bfe3SJack F Vogel 		 */
49316ab6bfe3SJack F Vogel 		if (!(E1000_READ_REG(hw, E1000_FWSM) &
49326ab6bfe3SJack F Vogel 		      E1000_ICH_FWSM_FW_VALID)) {
49336ab6bfe3SJack F Vogel 			/* Enable proxy to reset only on power good. */
49346ab6bfe3SJack F Vogel 			hw->phy.ops.read_reg_locked(hw, I217_PROXY_CTRL,
49356ab6bfe3SJack F Vogel 						    &phy_reg);
49366ab6bfe3SJack F Vogel 			phy_reg |= I217_PROXY_CTRL_AUTO_DISABLE;
49376ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_PROXY_CTRL,
49386ab6bfe3SJack F Vogel 						     phy_reg);
49396ab6bfe3SJack F Vogel 
49406ab6bfe3SJack F Vogel 			/* Set bit enable LPI (EEE) to reset only on
49416ab6bfe3SJack F Vogel 			 * power good.
49426ab6bfe3SJack F Vogel 			*/
49436ab6bfe3SJack F Vogel 			hw->phy.ops.read_reg_locked(hw, I217_SxCTRL, &phy_reg);
49446ab6bfe3SJack F Vogel 			phy_reg |= I217_SxCTRL_ENABLE_LPI_RESET;
49456ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_SxCTRL, phy_reg);
49466ab6bfe3SJack F Vogel 
49476ab6bfe3SJack F Vogel 			/* Disable the SMB release on LCD reset. */
49486ab6bfe3SJack F Vogel 			hw->phy.ops.read_reg_locked(hw, I217_MEMPWR, &phy_reg);
49496ab6bfe3SJack F Vogel 			phy_reg &= ~I217_MEMPWR_DISABLE_SMB_RELEASE;
49506ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_MEMPWR, phy_reg);
49516ab6bfe3SJack F Vogel 		}
49526ab6bfe3SJack F Vogel 
49536ab6bfe3SJack F Vogel 		/* Enable MTA to reset for Intel Rapid Start Technology
49546ab6bfe3SJack F Vogel 		 * Support
49556ab6bfe3SJack F Vogel 		 */
49566ab6bfe3SJack F Vogel 		hw->phy.ops.read_reg_locked(hw, I217_CGFREG, &phy_reg);
49576ab6bfe3SJack F Vogel 		phy_reg |= I217_CGFREG_ENABLE_MTA_RESET;
49586ab6bfe3SJack F Vogel 		hw->phy.ops.write_reg_locked(hw, I217_CGFREG, phy_reg);
49596ab6bfe3SJack F Vogel 
49606ab6bfe3SJack F Vogel release:
49616ab6bfe3SJack F Vogel 		hw->phy.ops.release(hw);
49626ab6bfe3SJack F Vogel 	}
49636ab6bfe3SJack F Vogel out:
49648cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
49656ab6bfe3SJack F Vogel 
49664dab5c37SJack F Vogel 	if (hw->mac.type == e1000_ich8lan)
49674dab5c37SJack F Vogel 		e1000_gig_downshift_workaround_ich8lan(hw);
49689d81738fSJack F Vogel 
49697d9119bdSJack F Vogel 	if (hw->mac.type >= e1000_pchlan) {
49707d9119bdSJack F Vogel 		e1000_oem_bits_config_ich8lan(hw, FALSE);
49716ab6bfe3SJack F Vogel 
49726ab6bfe3SJack F Vogel 		/* Reset PHY to activate OEM bits on 82577/8 */
49736ab6bfe3SJack F Vogel 		if (hw->mac.type == e1000_pchlan)
49746ab6bfe3SJack F Vogel 			e1000_phy_hw_reset_generic(hw);
49756ab6bfe3SJack F Vogel 
49767d9119bdSJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
49777d9119bdSJack F Vogel 		if (ret_val)
49787d9119bdSJack F Vogel 			return;
49797d9119bdSJack F Vogel 		e1000_write_smbus_addr(hw);
49807d9119bdSJack F Vogel 		hw->phy.ops.release(hw);
49818cfa0ad2SJack F Vogel 	}
49828cfa0ad2SJack F Vogel 
49838cfa0ad2SJack F Vogel 	return;
49848cfa0ad2SJack F Vogel }
49858cfa0ad2SJack F Vogel 
49868cfa0ad2SJack F Vogel /**
49874dab5c37SJack F Vogel  *  e1000_resume_workarounds_pchlan - workarounds needed during Sx->S0
49884dab5c37SJack F Vogel  *  @hw: pointer to the HW structure
49894dab5c37SJack F Vogel  *
49904dab5c37SJack F Vogel  *  During Sx to S0 transitions on non-managed devices or managed devices
49914dab5c37SJack F Vogel  *  on which PHY resets are not blocked, if the PHY registers cannot be
49924dab5c37SJack F Vogel  *  accessed properly by the s/w toggle the LANPHYPC value to power cycle
49934dab5c37SJack F Vogel  *  the PHY.
49946ab6bfe3SJack F Vogel  *  On i217, setup Intel Rapid Start Technology.
49954dab5c37SJack F Vogel  **/
49964dab5c37SJack F Vogel void e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
49974dab5c37SJack F Vogel {
49984dab5c37SJack F Vogel 	s32 ret_val;
49994dab5c37SJack F Vogel 
50004dab5c37SJack F Vogel 	DEBUGFUNC("e1000_resume_workarounds_pchlan");
50014dab5c37SJack F Vogel 
50026ab6bfe3SJack F Vogel 	if (hw->mac.type < e1000_pch2lan)
50034dab5c37SJack F Vogel 		return;
50044dab5c37SJack F Vogel 
50056ab6bfe3SJack F Vogel 	ret_val = e1000_init_phy_workarounds_pchlan(hw);
50064dab5c37SJack F Vogel 	if (ret_val) {
50076ab6bfe3SJack F Vogel 		DEBUGOUT1("Failed to init PHY flow ret_val=%d\n", ret_val);
50084dab5c37SJack F Vogel 		return;
50094dab5c37SJack F Vogel 	}
50104dab5c37SJack F Vogel 
50116ab6bfe3SJack F Vogel 	/* For i217 Intel Rapid Start Technology support when the system
50126ab6bfe3SJack F Vogel 	 * is transitioning from Sx and no manageability engine is present
50136ab6bfe3SJack F Vogel 	 * configure SMBus to restore on reset, disable proxy, and enable
50146ab6bfe3SJack F Vogel 	 * the reset on MTA (Multicast table array).
50156ab6bfe3SJack F Vogel 	 */
50166ab6bfe3SJack F Vogel 	if (hw->phy.type == e1000_phy_i217) {
50176ab6bfe3SJack F Vogel 		u16 phy_reg;
50184dab5c37SJack F Vogel 
50196ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
50206ab6bfe3SJack F Vogel 		if (ret_val) {
50216ab6bfe3SJack F Vogel 			DEBUGOUT("Failed to setup iRST\n");
50224dab5c37SJack F Vogel 			return;
50236ab6bfe3SJack F Vogel 		}
50244dab5c37SJack F Vogel 
50257609433eSJack F Vogel 		/* Clear Auto Enable LPI after link up */
50267609433eSJack F Vogel 		hw->phy.ops.read_reg_locked(hw, I217_LPI_GPIO_CTRL, &phy_reg);
50277609433eSJack F Vogel 		phy_reg &= ~I217_LPI_GPIO_CTRL_AUTO_EN_LPI;
50287609433eSJack F Vogel 		hw->phy.ops.write_reg_locked(hw, I217_LPI_GPIO_CTRL, phy_reg);
50297609433eSJack F Vogel 
50306ab6bfe3SJack F Vogel 		if (!(E1000_READ_REG(hw, E1000_FWSM) &
50316ab6bfe3SJack F Vogel 		    E1000_ICH_FWSM_FW_VALID)) {
50326ab6bfe3SJack F Vogel 			/* Restore clear on SMB if no manageability engine
50336ab6bfe3SJack F Vogel 			 * is present
50346ab6bfe3SJack F Vogel 			 */
50356ab6bfe3SJack F Vogel 			ret_val = hw->phy.ops.read_reg_locked(hw, I217_MEMPWR,
50366ab6bfe3SJack F Vogel 							      &phy_reg);
50376ab6bfe3SJack F Vogel 			if (ret_val)
50386ab6bfe3SJack F Vogel 				goto release;
50396ab6bfe3SJack F Vogel 			phy_reg |= I217_MEMPWR_DISABLE_SMB_RELEASE;
50406ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_MEMPWR, phy_reg);
50416ab6bfe3SJack F Vogel 
50426ab6bfe3SJack F Vogel 			/* Disable Proxy */
50436ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_PROXY_CTRL, 0);
50446ab6bfe3SJack F Vogel 		}
50456ab6bfe3SJack F Vogel 		/* Enable reset on MTA */
50466ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.read_reg_locked(hw, I217_CGFREG,
50476ab6bfe3SJack F Vogel 						      &phy_reg);
50486ab6bfe3SJack F Vogel 		if (ret_val)
50496ab6bfe3SJack F Vogel 			goto release;
50506ab6bfe3SJack F Vogel 		phy_reg &= ~I217_CGFREG_ENABLE_MTA_RESET;
50516ab6bfe3SJack F Vogel 		hw->phy.ops.write_reg_locked(hw, I217_CGFREG, phy_reg);
50524dab5c37SJack F Vogel release:
50536ab6bfe3SJack F Vogel 		if (ret_val)
50546ab6bfe3SJack F Vogel 			DEBUGOUT1("Error %d in resume workarounds\n", ret_val);
50554dab5c37SJack F Vogel 		hw->phy.ops.release(hw);
50566ab6bfe3SJack F Vogel 	}
50574dab5c37SJack F Vogel }
50584dab5c37SJack F Vogel 
50594dab5c37SJack F Vogel /**
50608cfa0ad2SJack F Vogel  *  e1000_cleanup_led_ich8lan - Restore the default LED operation
50618cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
50628cfa0ad2SJack F Vogel  *
50638cfa0ad2SJack F Vogel  *  Return the LED back to the default configuration.
50648cfa0ad2SJack F Vogel  **/
50658cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
50668cfa0ad2SJack F Vogel {
50678cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_cleanup_led_ich8lan");
50688cfa0ad2SJack F Vogel 
50698cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
5070a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
50718cfa0ad2SJack F Vogel 					     0);
50728cfa0ad2SJack F Vogel 
5073a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
5074a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
50758cfa0ad2SJack F Vogel }
50768cfa0ad2SJack F Vogel 
50778cfa0ad2SJack F Vogel /**
50788cfa0ad2SJack F Vogel  *  e1000_led_on_ich8lan - Turn LEDs on
50798cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
50808cfa0ad2SJack F Vogel  *
50818cfa0ad2SJack F Vogel  *  Turn on the LEDs.
50828cfa0ad2SJack F Vogel  **/
50838cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw)
50848cfa0ad2SJack F Vogel {
50858cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_led_on_ich8lan");
50868cfa0ad2SJack F Vogel 
50878cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
5088a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
50898cfa0ad2SJack F Vogel 				(IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
50908cfa0ad2SJack F Vogel 
5091a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
5092a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
50938cfa0ad2SJack F Vogel }
50948cfa0ad2SJack F Vogel 
50958cfa0ad2SJack F Vogel /**
50968cfa0ad2SJack F Vogel  *  e1000_led_off_ich8lan - Turn LEDs off
50978cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
50988cfa0ad2SJack F Vogel  *
50998cfa0ad2SJack F Vogel  *  Turn off the LEDs.
51008cfa0ad2SJack F Vogel  **/
51018cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
51028cfa0ad2SJack F Vogel {
51038cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_led_off_ich8lan");
51048cfa0ad2SJack F Vogel 
51058cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
5106a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
51078cfa0ad2SJack F Vogel 			       (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
51088cfa0ad2SJack F Vogel 
5109a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
5110a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
51118cfa0ad2SJack F Vogel }
51128cfa0ad2SJack F Vogel 
51138cfa0ad2SJack F Vogel /**
51149d81738fSJack F Vogel  *  e1000_setup_led_pchlan - Configures SW controllable LED
51159d81738fSJack F Vogel  *  @hw: pointer to the HW structure
51169d81738fSJack F Vogel  *
51179d81738fSJack F Vogel  *  This prepares the SW controllable LED for use.
51189d81738fSJack F Vogel  **/
51199d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw)
51209d81738fSJack F Vogel {
51219d81738fSJack F Vogel 	DEBUGFUNC("e1000_setup_led_pchlan");
51229d81738fSJack F Vogel 
51239d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
51249d81738fSJack F Vogel 				     (u16)hw->mac.ledctl_mode1);
51259d81738fSJack F Vogel }
51269d81738fSJack F Vogel 
51279d81738fSJack F Vogel /**
51289d81738fSJack F Vogel  *  e1000_cleanup_led_pchlan - Restore the default LED operation
51299d81738fSJack F Vogel  *  @hw: pointer to the HW structure
51309d81738fSJack F Vogel  *
51319d81738fSJack F Vogel  *  Return the LED back to the default configuration.
51329d81738fSJack F Vogel  **/
51339d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw)
51349d81738fSJack F Vogel {
51359d81738fSJack F Vogel 	DEBUGFUNC("e1000_cleanup_led_pchlan");
51369d81738fSJack F Vogel 
51379d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
51389d81738fSJack F Vogel 				     (u16)hw->mac.ledctl_default);
51399d81738fSJack F Vogel }
51409d81738fSJack F Vogel 
51419d81738fSJack F Vogel /**
51429d81738fSJack F Vogel  *  e1000_led_on_pchlan - Turn LEDs on
51439d81738fSJack F Vogel  *  @hw: pointer to the HW structure
51449d81738fSJack F Vogel  *
51459d81738fSJack F Vogel  *  Turn on the LEDs.
51469d81738fSJack F Vogel  **/
51479d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw)
51489d81738fSJack F Vogel {
51499d81738fSJack F Vogel 	u16 data = (u16)hw->mac.ledctl_mode2;
51509d81738fSJack F Vogel 	u32 i, led;
51519d81738fSJack F Vogel 
51529d81738fSJack F Vogel 	DEBUGFUNC("e1000_led_on_pchlan");
51539d81738fSJack F Vogel 
51546ab6bfe3SJack F Vogel 	/* If no link, then turn LED on by setting the invert bit
51559d81738fSJack F Vogel 	 * for each LED that's mode is "link_up" in ledctl_mode2.
51569d81738fSJack F Vogel 	 */
51579d81738fSJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
51589d81738fSJack F Vogel 		for (i = 0; i < 3; i++) {
51599d81738fSJack F Vogel 			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
51609d81738fSJack F Vogel 			if ((led & E1000_PHY_LED0_MODE_MASK) !=
51619d81738fSJack F Vogel 			    E1000_LEDCTL_MODE_LINK_UP)
51629d81738fSJack F Vogel 				continue;
51639d81738fSJack F Vogel 			if (led & E1000_PHY_LED0_IVRT)
51649d81738fSJack F Vogel 				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
51659d81738fSJack F Vogel 			else
51669d81738fSJack F Vogel 				data |= (E1000_PHY_LED0_IVRT << (i * 5));
51679d81738fSJack F Vogel 		}
51689d81738fSJack F Vogel 	}
51699d81738fSJack F Vogel 
51709d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
51719d81738fSJack F Vogel }
51729d81738fSJack F Vogel 
51739d81738fSJack F Vogel /**
51749d81738fSJack F Vogel  *  e1000_led_off_pchlan - Turn LEDs off
51759d81738fSJack F Vogel  *  @hw: pointer to the HW structure
51769d81738fSJack F Vogel  *
51779d81738fSJack F Vogel  *  Turn off the LEDs.
51789d81738fSJack F Vogel  **/
51799d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw)
51809d81738fSJack F Vogel {
51819d81738fSJack F Vogel 	u16 data = (u16)hw->mac.ledctl_mode1;
51829d81738fSJack F Vogel 	u32 i, led;
51839d81738fSJack F Vogel 
51849d81738fSJack F Vogel 	DEBUGFUNC("e1000_led_off_pchlan");
51859d81738fSJack F Vogel 
51866ab6bfe3SJack F Vogel 	/* If no link, then turn LED off by clearing the invert bit
51879d81738fSJack F Vogel 	 * for each LED that's mode is "link_up" in ledctl_mode1.
51889d81738fSJack F Vogel 	 */
51899d81738fSJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
51909d81738fSJack F Vogel 		for (i = 0; i < 3; i++) {
51919d81738fSJack F Vogel 			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
51929d81738fSJack F Vogel 			if ((led & E1000_PHY_LED0_MODE_MASK) !=
51939d81738fSJack F Vogel 			    E1000_LEDCTL_MODE_LINK_UP)
51949d81738fSJack F Vogel 				continue;
51959d81738fSJack F Vogel 			if (led & E1000_PHY_LED0_IVRT)
51969d81738fSJack F Vogel 				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
51979d81738fSJack F Vogel 			else
51989d81738fSJack F Vogel 				data |= (E1000_PHY_LED0_IVRT << (i * 5));
51999d81738fSJack F Vogel 		}
52009d81738fSJack F Vogel 	}
52019d81738fSJack F Vogel 
52029d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
52039d81738fSJack F Vogel }
52049d81738fSJack F Vogel 
52059d81738fSJack F Vogel /**
52067d9119bdSJack F Vogel  *  e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset
52078cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
52088cfa0ad2SJack F Vogel  *
52097d9119bdSJack F Vogel  *  Read appropriate register for the config done bit for completion status
52107d9119bdSJack F Vogel  *  and configure the PHY through s/w for EEPROM-less parts.
52117d9119bdSJack F Vogel  *
52127d9119bdSJack F Vogel  *  NOTE: some silicon which is EEPROM-less will fail trying to read the
52137d9119bdSJack F Vogel  *  config done bit, so only an error is logged and continues.  If we were
52147d9119bdSJack F Vogel  *  to return with error, EEPROM-less silicon would not be able to be reset
52157d9119bdSJack F Vogel  *  or change link.
52168cfa0ad2SJack F Vogel  **/
52178cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
52188cfa0ad2SJack F Vogel {
52198cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
52208cfa0ad2SJack F Vogel 	u32 bank = 0;
52217d9119bdSJack F Vogel 	u32 status;
52228cfa0ad2SJack F Vogel 
52237d9119bdSJack F Vogel 	DEBUGFUNC("e1000_get_cfg_done_ich8lan");
52249d81738fSJack F Vogel 
52258cfa0ad2SJack F Vogel 	e1000_get_cfg_done_generic(hw);
52268cfa0ad2SJack F Vogel 
52277d9119bdSJack F Vogel 	/* Wait for indication from h/w that it has completed basic config */
52287d9119bdSJack F Vogel 	if (hw->mac.type >= e1000_ich10lan) {
52297d9119bdSJack F Vogel 		e1000_lan_init_done_ich8lan(hw);
52307d9119bdSJack F Vogel 	} else {
52317d9119bdSJack F Vogel 		ret_val = e1000_get_auto_rd_done_generic(hw);
52327d9119bdSJack F Vogel 		if (ret_val) {
52336ab6bfe3SJack F Vogel 			/* When auto config read does not complete, do not
52347d9119bdSJack F Vogel 			 * return with an error. This can happen in situations
52357d9119bdSJack F Vogel 			 * where there is no eeprom and prevents getting link.
52367d9119bdSJack F Vogel 			 */
52377d9119bdSJack F Vogel 			DEBUGOUT("Auto Read Done did not complete\n");
52387d9119bdSJack F Vogel 			ret_val = E1000_SUCCESS;
52397d9119bdSJack F Vogel 		}
52407d9119bdSJack F Vogel 	}
52417d9119bdSJack F Vogel 
52427d9119bdSJack F Vogel 	/* Clear PHY Reset Asserted bit */
52437d9119bdSJack F Vogel 	status = E1000_READ_REG(hw, E1000_STATUS);
52447d9119bdSJack F Vogel 	if (status & E1000_STATUS_PHYRA)
52457d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_STATUS, status & ~E1000_STATUS_PHYRA);
52467d9119bdSJack F Vogel 	else
52477d9119bdSJack F Vogel 		DEBUGOUT("PHY Reset Asserted not set - needs delay\n");
52487d9119bdSJack F Vogel 
52498cfa0ad2SJack F Vogel 	/* If EEPROM is not marked present, init the IGP 3 PHY manually */
52504edd8523SJack F Vogel 	if (hw->mac.type <= e1000_ich9lan) {
52516ab6bfe3SJack F Vogel 		if (!(E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) &&
52528cfa0ad2SJack F Vogel 		    (hw->phy.type == e1000_phy_igp_3)) {
52538cfa0ad2SJack F Vogel 			e1000_phy_init_script_igp3(hw);
52548cfa0ad2SJack F Vogel 		}
52558cfa0ad2SJack F Vogel 	} else {
52568cfa0ad2SJack F Vogel 		if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
5257daf9197cSJack F Vogel 			/* Maybe we should do a basic PHY config */
52588cfa0ad2SJack F Vogel 			DEBUGOUT("EEPROM not present\n");
52598cfa0ad2SJack F Vogel 			ret_val = -E1000_ERR_CONFIG;
52608cfa0ad2SJack F Vogel 		}
52618cfa0ad2SJack F Vogel 	}
52628cfa0ad2SJack F Vogel 
52638cfa0ad2SJack F Vogel 	return ret_val;
52648cfa0ad2SJack F Vogel }
52658cfa0ad2SJack F Vogel 
52668cfa0ad2SJack F Vogel /**
52678cfa0ad2SJack F Vogel  * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down
52688cfa0ad2SJack F Vogel  * @hw: pointer to the HW structure
52698cfa0ad2SJack F Vogel  *
52708cfa0ad2SJack F Vogel  * In the case of a PHY power down to save power, or to turn off link during a
52718cfa0ad2SJack F Vogel  * driver unload, or wake on lan is not enabled, remove the link.
52728cfa0ad2SJack F Vogel  **/
52738cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
52748cfa0ad2SJack F Vogel {
52758cfa0ad2SJack F Vogel 	/* If the management interface is not enabled, then power down */
5276daf9197cSJack F Vogel 	if (!(hw->mac.ops.check_mng_mode(hw) ||
5277daf9197cSJack F Vogel 	      hw->phy.ops.check_reset_block(hw)))
52788cfa0ad2SJack F Vogel 		e1000_power_down_phy_copper(hw);
52798cfa0ad2SJack F Vogel 
52808cfa0ad2SJack F Vogel 	return;
52818cfa0ad2SJack F Vogel }
52828cfa0ad2SJack F Vogel 
52838cfa0ad2SJack F Vogel /**
52848cfa0ad2SJack F Vogel  *  e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
52858cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
52868cfa0ad2SJack F Vogel  *
52878cfa0ad2SJack F Vogel  *  Clears hardware counters specific to the silicon family and calls
52888cfa0ad2SJack F Vogel  *  clear_hw_cntrs_generic to clear all general purpose counters.
52898cfa0ad2SJack F Vogel  **/
52908cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
52918cfa0ad2SJack F Vogel {
52929d81738fSJack F Vogel 	u16 phy_data;
52934dab5c37SJack F Vogel 	s32 ret_val;
52949d81738fSJack F Vogel 
52958cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan");
52968cfa0ad2SJack F Vogel 
52978cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_base_generic(hw);
52988cfa0ad2SJack F Vogel 
5299daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ALGNERRC);
5300daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_RXERRC);
5301daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TNCRS);
5302daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_CEXTERR);
5303daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTC);
5304daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTFC);
53058cfa0ad2SJack F Vogel 
5306daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPRC);
5307daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPDC);
5308daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPTC);
53098cfa0ad2SJack F Vogel 
5310daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_IAC);
5311daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ICRXOC);
53129d81738fSJack F Vogel 
53139d81738fSJack F Vogel 	/* Clear PHY statistics registers */
53149d81738fSJack F Vogel 	if ((hw->phy.type == e1000_phy_82578) ||
53157d9119bdSJack F Vogel 	    (hw->phy.type == e1000_phy_82579) ||
53166ab6bfe3SJack F Vogel 	    (hw->phy.type == e1000_phy_i217) ||
53179d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577)) {
53184dab5c37SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
53194dab5c37SJack F Vogel 		if (ret_val)
53204dab5c37SJack F Vogel 			return;
53214dab5c37SJack F Vogel 		ret_val = hw->phy.ops.set_page(hw,
53224dab5c37SJack F Vogel 					       HV_STATS_PAGE << IGP_PAGE_SHIFT);
53234dab5c37SJack F Vogel 		if (ret_val)
53244dab5c37SJack F Vogel 			goto release;
53254dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_SCC_UPPER, &phy_data);
53264dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_SCC_LOWER, &phy_data);
53274dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_ECOL_UPPER, &phy_data);
53284dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_ECOL_LOWER, &phy_data);
53294dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_MCC_UPPER, &phy_data);
53304dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_MCC_LOWER, &phy_data);
53314dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_LATECOL_UPPER, &phy_data);
53324dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_LATECOL_LOWER, &phy_data);
53334dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_COLC_UPPER, &phy_data);
53344dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_COLC_LOWER, &phy_data);
53354dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_DC_UPPER, &phy_data);
53364dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_DC_LOWER, &phy_data);
53374dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_TNCRS_UPPER, &phy_data);
53384dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_TNCRS_LOWER, &phy_data);
53394dab5c37SJack F Vogel release:
53404dab5c37SJack F Vogel 		hw->phy.ops.release(hw);
53419d81738fSJack F Vogel 	}
53428cfa0ad2SJack F Vogel }
53438cfa0ad2SJack F Vogel 
5344