xref: /freebsd/sys/dev/e1000/e1000_ich8lan.c (revision fc7682b17f3738573099b8b03f5628dcc8148adb)
18cfa0ad2SJack F Vogel /******************************************************************************
27282444bSPedro F. Giffuni   SPDX-License-Identifier: BSD-3-Clause
38cfa0ad2SJack F Vogel 
4*fc7682b1SKevin Bowling   Copyright (c) 2001-2020, Intel Corporation
58cfa0ad2SJack F Vogel   All rights reserved.
68cfa0ad2SJack F Vogel 
78cfa0ad2SJack F Vogel   Redistribution and use in source and binary forms, with or without
88cfa0ad2SJack F Vogel   modification, are permitted provided that the following conditions are met:
98cfa0ad2SJack F Vogel 
108cfa0ad2SJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
118cfa0ad2SJack F Vogel       this list of conditions and the following disclaimer.
128cfa0ad2SJack F Vogel 
138cfa0ad2SJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
148cfa0ad2SJack F Vogel       notice, this list of conditions and the following disclaimer in the
158cfa0ad2SJack F Vogel       documentation and/or other materials provided with the distribution.
168cfa0ad2SJack F Vogel 
178cfa0ad2SJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
188cfa0ad2SJack F Vogel       contributors may be used to endorse or promote products derived from
198cfa0ad2SJack F Vogel       this software without specific prior written permission.
208cfa0ad2SJack F Vogel 
218cfa0ad2SJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
228cfa0ad2SJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
238cfa0ad2SJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
248cfa0ad2SJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
258cfa0ad2SJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
268cfa0ad2SJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
278cfa0ad2SJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
288cfa0ad2SJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
298cfa0ad2SJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
308cfa0ad2SJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
318cfa0ad2SJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
328cfa0ad2SJack F Vogel 
338cfa0ad2SJack F Vogel ******************************************************************************/
348cfa0ad2SJack F Vogel /*$FreeBSD$*/
358cfa0ad2SJack F Vogel 
366ab6bfe3SJack F Vogel /* 82562G 10/100 Network Connection
37daf9197cSJack F Vogel  * 82562G-2 10/100 Network Connection
38daf9197cSJack F Vogel  * 82562GT 10/100 Network Connection
39daf9197cSJack F Vogel  * 82562GT-2 10/100 Network Connection
40daf9197cSJack F Vogel  * 82562V 10/100 Network Connection
41daf9197cSJack F Vogel  * 82562V-2 10/100 Network Connection
42daf9197cSJack F Vogel  * 82566DC-2 Gigabit Network Connection
43daf9197cSJack F Vogel  * 82566DC Gigabit Network Connection
44daf9197cSJack F Vogel  * 82566DM-2 Gigabit Network Connection
45daf9197cSJack F Vogel  * 82566DM Gigabit Network Connection
46daf9197cSJack F Vogel  * 82566MC Gigabit Network Connection
47daf9197cSJack F Vogel  * 82566MM Gigabit Network Connection
48daf9197cSJack F Vogel  * 82567LM Gigabit Network Connection
49daf9197cSJack F Vogel  * 82567LF Gigabit Network Connection
50daf9197cSJack F Vogel  * 82567V Gigabit Network Connection
51daf9197cSJack F Vogel  * 82567LM-2 Gigabit Network Connection
52daf9197cSJack F Vogel  * 82567LF-2 Gigabit Network Connection
53daf9197cSJack F Vogel  * 82567V-2 Gigabit Network Connection
54daf9197cSJack F Vogel  * 82567LF-3 Gigabit Network Connection
55daf9197cSJack F Vogel  * 82567LM-3 Gigabit Network Connection
56daf9197cSJack F Vogel  * 82567LM-4 Gigabit Network Connection
579d81738fSJack F Vogel  * 82577LM Gigabit Network Connection
589d81738fSJack F Vogel  * 82577LC Gigabit Network Connection
599d81738fSJack F Vogel  * 82578DM Gigabit Network Connection
609d81738fSJack F Vogel  * 82578DC Gigabit Network Connection
617d9119bdSJack F Vogel  * 82579LM Gigabit Network Connection
627d9119bdSJack F Vogel  * 82579V Gigabit Network Connection
637609433eSJack F Vogel  * Ethernet Connection I217-LM
647609433eSJack F Vogel  * Ethernet Connection I217-V
657609433eSJack F Vogel  * Ethernet Connection I218-V
667609433eSJack F Vogel  * Ethernet Connection I218-LM
678cc64f1eSJack F Vogel  * Ethernet Connection (2) I218-LM
688cc64f1eSJack F Vogel  * Ethernet Connection (2) I218-V
698cc64f1eSJack F Vogel  * Ethernet Connection (3) I218-LM
708cc64f1eSJack F Vogel  * Ethernet Connection (3) I218-V
718cfa0ad2SJack F Vogel  */
728cfa0ad2SJack F Vogel 
738cfa0ad2SJack F Vogel #include "e1000_api.h"
748cfa0ad2SJack F Vogel 
75*fc7682b1SKevin Bowling static s32  e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state);
768cfa0ad2SJack F Vogel static s32  e1000_acquire_swflag_ich8lan(struct e1000_hw *hw);
778cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw);
784edd8523SJack F Vogel static s32  e1000_acquire_nvm_ich8lan(struct e1000_hw *hw);
794edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw);
808cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
817d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
828cc64f1eSJack F Vogel static int  e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index);
838cc64f1eSJack F Vogel static int  e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index);
847609433eSJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw);
85730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw,
86730d3130SJack F Vogel 					      u8 *mc_addr_list,
87730d3130SJack F Vogel 					      u32 mc_addr_count);
888cfa0ad2SJack F Vogel static s32  e1000_check_reset_block_ich8lan(struct e1000_hw *hw);
898cfa0ad2SJack F Vogel static s32  e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw);
904edd8523SJack F Vogel static s32  e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active);
918cfa0ad2SJack F Vogel static s32  e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
928cfa0ad2SJack F Vogel 					    bool active);
938cfa0ad2SJack F Vogel static s32  e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
948cfa0ad2SJack F Vogel 					    bool active);
958cfa0ad2SJack F Vogel static s32  e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
968cfa0ad2SJack F Vogel 				   u16 words, u16 *data);
97c80429ceSEric Joyner static s32  e1000_read_nvm_spt(struct e1000_hw *hw, u16 offset, u16 words,
98c80429ceSEric Joyner 			       u16 *data);
998cfa0ad2SJack F Vogel static s32  e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
1008cfa0ad2SJack F Vogel 				    u16 words, u16 *data);
1018cfa0ad2SJack F Vogel static s32  e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw);
1028cfa0ad2SJack F Vogel static s32  e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
103c80429ceSEric Joyner static s32  e1000_update_nvm_checksum_spt(struct e1000_hw *hw);
1048cfa0ad2SJack F Vogel static s32  e1000_valid_led_default_ich8lan(struct e1000_hw *hw,
1058cfa0ad2SJack F Vogel 					    u16 *data);
1069d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw);
1078cfa0ad2SJack F Vogel static s32  e1000_get_bus_info_ich8lan(struct e1000_hw *hw);
1088cfa0ad2SJack F Vogel static s32  e1000_reset_hw_ich8lan(struct e1000_hw *hw);
1098cfa0ad2SJack F Vogel static s32  e1000_init_hw_ich8lan(struct e1000_hw *hw);
1108cfa0ad2SJack F Vogel static s32  e1000_setup_link_ich8lan(struct e1000_hw *hw);
1118cfa0ad2SJack F Vogel static s32  e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
1126ab6bfe3SJack F Vogel static s32  e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw);
1138cfa0ad2SJack F Vogel static s32  e1000_get_link_up_info_ich8lan(struct e1000_hw *hw,
1148cfa0ad2SJack F Vogel 					   u16 *speed, u16 *duplex);
1158cfa0ad2SJack F Vogel static s32  e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
1168cfa0ad2SJack F Vogel static s32  e1000_led_on_ich8lan(struct e1000_hw *hw);
1178cfa0ad2SJack F Vogel static s32  e1000_led_off_ich8lan(struct e1000_hw *hw);
1184edd8523SJack F Vogel static s32  e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
1199d81738fSJack F Vogel static s32  e1000_setup_led_pchlan(struct e1000_hw *hw);
1209d81738fSJack F Vogel static s32  e1000_cleanup_led_pchlan(struct e1000_hw *hw);
1219d81738fSJack F Vogel static s32  e1000_led_on_pchlan(struct e1000_hw *hw);
1229d81738fSJack F Vogel static s32  e1000_led_off_pchlan(struct e1000_hw *hw);
1238cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
1248cfa0ad2SJack F Vogel static s32  e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
1258cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
1268cfa0ad2SJack F Vogel static s32  e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
1278cfa0ad2SJack F Vogel static s32  e1000_read_flash_byte_ich8lan(struct e1000_hw *hw,
1288cfa0ad2SJack F Vogel 					  u32 offset, u8 *data);
1298cfa0ad2SJack F Vogel static s32  e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
1308cfa0ad2SJack F Vogel 					  u8 size, u16 *data);
131c80429ceSEric Joyner static s32  e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
132c80429ceSEric Joyner 					    u32 *data);
133c80429ceSEric Joyner static s32  e1000_read_flash_dword_ich8lan(struct e1000_hw *hw,
134c80429ceSEric Joyner 					   u32 offset, u32 *data);
135c80429ceSEric Joyner static s32  e1000_write_flash_data32_ich8lan(struct e1000_hw *hw,
136c80429ceSEric Joyner 					     u32 offset, u32 data);
137c80429ceSEric Joyner static s32  e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw,
138c80429ceSEric Joyner 						  u32 offset, u32 dword);
1398cfa0ad2SJack F Vogel static s32  e1000_read_flash_word_ich8lan(struct e1000_hw *hw,
1408cfa0ad2SJack F Vogel 					  u32 offset, u16 *data);
1418cfa0ad2SJack F Vogel static s32  e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
1428cfa0ad2SJack F Vogel 						 u32 offset, u8 byte);
1438cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
1448cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
1454edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw);
146a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
1477d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw);
1487d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate);
149e373323fSSean Bruno static s32 e1000_set_obff_timer_pch_lpt(struct e1000_hw *hw, u32 itr);
1508cfa0ad2SJack F Vogel 
1518cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
1528cfa0ad2SJack F Vogel /* Offset 04h HSFSTS */
1538cfa0ad2SJack F Vogel union ich8_hws_flash_status {
1548cfa0ad2SJack F Vogel 	struct ich8_hsfsts {
1558cfa0ad2SJack F Vogel 		u16 flcdone:1; /* bit 0 Flash Cycle Done */
1568cfa0ad2SJack F Vogel 		u16 flcerr:1; /* bit 1 Flash Cycle Error */
1578cfa0ad2SJack F Vogel 		u16 dael:1; /* bit 2 Direct Access error Log */
1588cfa0ad2SJack F Vogel 		u16 berasesz:2; /* bit 4:3 Sector Erase Size */
1598cfa0ad2SJack F Vogel 		u16 flcinprog:1; /* bit 5 flash cycle in Progress */
1608cfa0ad2SJack F Vogel 		u16 reserved1:2; /* bit 13:6 Reserved */
1618cfa0ad2SJack F Vogel 		u16 reserved2:6; /* bit 13:6 Reserved */
1628cfa0ad2SJack F Vogel 		u16 fldesvalid:1; /* bit 14 Flash Descriptor Valid */
1638cfa0ad2SJack F Vogel 		u16 flockdn:1; /* bit 15 Flash Config Lock-Down */
1648cfa0ad2SJack F Vogel 	} hsf_status;
1658cfa0ad2SJack F Vogel 	u16 regval;
1668cfa0ad2SJack F Vogel };
1678cfa0ad2SJack F Vogel 
1688cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
1698cfa0ad2SJack F Vogel /* Offset 06h FLCTL */
1708cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl {
1718cfa0ad2SJack F Vogel 	struct ich8_hsflctl {
1728cfa0ad2SJack F Vogel 		u16 flcgo:1;   /* 0 Flash Cycle Go */
1738cfa0ad2SJack F Vogel 		u16 flcycle:2;   /* 2:1 Flash Cycle */
1748cfa0ad2SJack F Vogel 		u16 reserved:5;   /* 7:3 Reserved  */
1758cfa0ad2SJack F Vogel 		u16 fldbcount:2;   /* 9:8 Flash Data Byte Count */
1768cfa0ad2SJack F Vogel 		u16 flockdn:6;   /* 15:10 Reserved */
1778cfa0ad2SJack F Vogel 	} hsf_ctrl;
1788cfa0ad2SJack F Vogel 	u16 regval;
1798cfa0ad2SJack F Vogel };
1808cfa0ad2SJack F Vogel 
1818cfa0ad2SJack F Vogel /* ICH Flash Region Access Permissions */
1828cfa0ad2SJack F Vogel union ich8_hws_flash_regacc {
1838cfa0ad2SJack F Vogel 	struct ich8_flracc {
1848cfa0ad2SJack F Vogel 		u32 grra:8; /* 0:7 GbE region Read Access */
1858cfa0ad2SJack F Vogel 		u32 grwa:8; /* 8:15 GbE region Write Access */
1868cfa0ad2SJack F Vogel 		u32 gmrag:8; /* 23:16 GbE Master Read Access Grant */
1878cfa0ad2SJack F Vogel 		u32 gmwag:8; /* 31:24 GbE Master Write Access Grant */
1888cfa0ad2SJack F Vogel 	} hsf_flregacc;
1898cfa0ad2SJack F Vogel 	u16 regval;
1908cfa0ad2SJack F Vogel };
1918cfa0ad2SJack F Vogel 
1926ab6bfe3SJack F Vogel /**
1936ab6bfe3SJack F Vogel  *  e1000_phy_is_accessible_pchlan - Check if able to access PHY registers
1946ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
1956ab6bfe3SJack F Vogel  *
1966ab6bfe3SJack F Vogel  *  Test access to the PHY registers by reading the PHY ID registers.  If
1976ab6bfe3SJack F Vogel  *  the PHY ID is already known (e.g. resume path) compare it with known ID,
1986ab6bfe3SJack F Vogel  *  otherwise assume the read PHY ID is correct if it is valid.
1996ab6bfe3SJack F Vogel  *
2006ab6bfe3SJack F Vogel  *  Assumes the sw/fw/hw semaphore is already acquired.
2016ab6bfe3SJack F Vogel  **/
2026ab6bfe3SJack F Vogel static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
2034dab5c37SJack F Vogel {
2046ab6bfe3SJack F Vogel 	u16 phy_reg = 0;
2056ab6bfe3SJack F Vogel 	u32 phy_id = 0;
2067609433eSJack F Vogel 	s32 ret_val = 0;
2076ab6bfe3SJack F Vogel 	u16 retry_count;
2087609433eSJack F Vogel 	u32 mac_reg = 0;
2094dab5c37SJack F Vogel 
2106ab6bfe3SJack F Vogel 	for (retry_count = 0; retry_count < 2; retry_count++) {
2116ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID1, &phy_reg);
2126ab6bfe3SJack F Vogel 		if (ret_val || (phy_reg == 0xFFFF))
2136ab6bfe3SJack F Vogel 			continue;
2146ab6bfe3SJack F Vogel 		phy_id = (u32)(phy_reg << 16);
2154dab5c37SJack F Vogel 
2166ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID2, &phy_reg);
2176ab6bfe3SJack F Vogel 		if (ret_val || (phy_reg == 0xFFFF)) {
2186ab6bfe3SJack F Vogel 			phy_id = 0;
2196ab6bfe3SJack F Vogel 			continue;
2206ab6bfe3SJack F Vogel 		}
2216ab6bfe3SJack F Vogel 		phy_id |= (u32)(phy_reg & PHY_REVISION_MASK);
2226ab6bfe3SJack F Vogel 		break;
2236ab6bfe3SJack F Vogel 	}
2246ab6bfe3SJack F Vogel 
2256ab6bfe3SJack F Vogel 	if (hw->phy.id) {
2266ab6bfe3SJack F Vogel 		if  (hw->phy.id == phy_id)
2277609433eSJack F Vogel 			goto out;
2286ab6bfe3SJack F Vogel 	} else if (phy_id) {
2296ab6bfe3SJack F Vogel 		hw->phy.id = phy_id;
2306ab6bfe3SJack F Vogel 		hw->phy.revision = (u32)(phy_reg & ~PHY_REVISION_MASK);
2317609433eSJack F Vogel 		goto out;
2326ab6bfe3SJack F Vogel 	}
2336ab6bfe3SJack F Vogel 
2346ab6bfe3SJack F Vogel 	/* In case the PHY needs to be in mdio slow mode,
2356ab6bfe3SJack F Vogel 	 * set slow mode and try to get the PHY id again.
2366ab6bfe3SJack F Vogel 	 */
2377609433eSJack F Vogel 	if (hw->mac.type < e1000_pch_lpt) {
2386ab6bfe3SJack F Vogel 		hw->phy.ops.release(hw);
2396ab6bfe3SJack F Vogel 		ret_val = e1000_set_mdio_slow_mode_hv(hw);
2406ab6bfe3SJack F Vogel 		if (!ret_val)
2416ab6bfe3SJack F Vogel 			ret_val = e1000_get_phy_id(hw);
2426ab6bfe3SJack F Vogel 		hw->phy.ops.acquire(hw);
2437609433eSJack F Vogel 	}
2446ab6bfe3SJack F Vogel 
2457609433eSJack F Vogel 	if (ret_val)
2467609433eSJack F Vogel 		return FALSE;
2477609433eSJack F Vogel out:
248295df609SEric Joyner 	if (hw->mac.type >= e1000_pch_lpt) {
249c80429ceSEric Joyner 		/* Only unforce SMBus if ME is not active */
250c80429ceSEric Joyner 		if (!(E1000_READ_REG(hw, E1000_FWSM) &
251c80429ceSEric Joyner 		    E1000_ICH_FWSM_FW_VALID)) {
2527609433eSJack F Vogel 			/* Unforce SMBus mode in PHY */
2537609433eSJack F Vogel 			hw->phy.ops.read_reg_locked(hw, CV_SMB_CTRL, &phy_reg);
2547609433eSJack F Vogel 			phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
2557609433eSJack F Vogel 			hw->phy.ops.write_reg_locked(hw, CV_SMB_CTRL, phy_reg);
2567609433eSJack F Vogel 
2577609433eSJack F Vogel 			/* Unforce SMBus mode in MAC */
2587609433eSJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
2597609433eSJack F Vogel 			mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
2607609433eSJack F Vogel 			E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
2617609433eSJack F Vogel 		}
262c80429ceSEric Joyner 	}
2637609433eSJack F Vogel 
2647609433eSJack F Vogel 	return TRUE;
2657609433eSJack F Vogel }
2667609433eSJack F Vogel 
2677609433eSJack F Vogel /**
2687609433eSJack F Vogel  *  e1000_toggle_lanphypc_pch_lpt - toggle the LANPHYPC pin value
2697609433eSJack F Vogel  *  @hw: pointer to the HW structure
2707609433eSJack F Vogel  *
2717609433eSJack F Vogel  *  Toggling the LANPHYPC pin value fully power-cycles the PHY and is
2727609433eSJack F Vogel  *  used to reset the PHY to a quiescent state when necessary.
2737609433eSJack F Vogel  **/
2748cc64f1eSJack F Vogel static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw)
2757609433eSJack F Vogel {
2767609433eSJack F Vogel 	u32 mac_reg;
2777609433eSJack F Vogel 
2787609433eSJack F Vogel 	DEBUGFUNC("e1000_toggle_lanphypc_pch_lpt");
2797609433eSJack F Vogel 
2807609433eSJack F Vogel 	/* Set Phy Config Counter to 50msec */
2817609433eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM3);
2827609433eSJack F Vogel 	mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
2837609433eSJack F Vogel 	mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
2847609433eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_FEXTNVM3, mac_reg);
2857609433eSJack F Vogel 
2867609433eSJack F Vogel 	/* Toggle LANPHYPC Value bit */
2877609433eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_CTRL);
2887609433eSJack F Vogel 	mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
2897609433eSJack F Vogel 	mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
2907609433eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, mac_reg);
2917609433eSJack F Vogel 	E1000_WRITE_FLUSH(hw);
292e760e292SSean Bruno 	msec_delay(1);
2937609433eSJack F Vogel 	mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
2947609433eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, mac_reg);
2957609433eSJack F Vogel 	E1000_WRITE_FLUSH(hw);
2967609433eSJack F Vogel 
2977609433eSJack F Vogel 	if (hw->mac.type < e1000_pch_lpt) {
2987609433eSJack F Vogel 		msec_delay(50);
2997609433eSJack F Vogel 	} else {
3007609433eSJack F Vogel 		u16 count = 20;
3017609433eSJack F Vogel 
3027609433eSJack F Vogel 		do {
3037609433eSJack F Vogel 			msec_delay(5);
3047609433eSJack F Vogel 		} while (!(E1000_READ_REG(hw, E1000_CTRL_EXT) &
3057609433eSJack F Vogel 			   E1000_CTRL_EXT_LPCD) && count--);
3067609433eSJack F Vogel 
3077609433eSJack F Vogel 		msec_delay(30);
3087609433eSJack F Vogel 	}
3096ab6bfe3SJack F Vogel }
3106ab6bfe3SJack F Vogel 
3116ab6bfe3SJack F Vogel /**
3126ab6bfe3SJack F Vogel  *  e1000_init_phy_workarounds_pchlan - PHY initialization workarounds
3136ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
3146ab6bfe3SJack F Vogel  *
3156ab6bfe3SJack F Vogel  *  Workarounds/flow necessary for PHY initialization during driver load
3166ab6bfe3SJack F Vogel  *  and resume paths.
3176ab6bfe3SJack F Vogel  **/
3186ab6bfe3SJack F Vogel static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
3196ab6bfe3SJack F Vogel {
3206ab6bfe3SJack F Vogel 	u32 mac_reg, fwsm = E1000_READ_REG(hw, E1000_FWSM);
3216ab6bfe3SJack F Vogel 	s32 ret_val;
3226ab6bfe3SJack F Vogel 
3236ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_init_phy_workarounds_pchlan");
3246ab6bfe3SJack F Vogel 
3256ab6bfe3SJack F Vogel 	/* Gate automatic PHY configuration by hardware on managed and
3266ab6bfe3SJack F Vogel 	 * non-managed 82579 and newer adapters.
3276ab6bfe3SJack F Vogel 	 */
3286ab6bfe3SJack F Vogel 	e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
3296ab6bfe3SJack F Vogel 
3308cc64f1eSJack F Vogel 	/* It is not possible to be certain of the current state of ULP
3318cc64f1eSJack F Vogel 	 * so forcibly disable it.
3328cc64f1eSJack F Vogel 	 */
3338cc64f1eSJack F Vogel 	hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_unknown;
3348cc64f1eSJack F Vogel 	e1000_disable_ulp_lpt_lp(hw, TRUE);
3358cc64f1eSJack F Vogel 
3366ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
3376ab6bfe3SJack F Vogel 	if (ret_val) {
3386ab6bfe3SJack F Vogel 		DEBUGOUT("Failed to initialize PHY flow\n");
3396ab6bfe3SJack F Vogel 		goto out;
3406ab6bfe3SJack F Vogel 	}
3416ab6bfe3SJack F Vogel 
3426ab6bfe3SJack F Vogel 	/* The MAC-PHY interconnect may be in SMBus mode.  If the PHY is
3436ab6bfe3SJack F Vogel 	 * inaccessible and resetting the PHY is not blocked, toggle the
3446ab6bfe3SJack F Vogel 	 * LANPHYPC Value bit to force the interconnect to PCIe mode.
3456ab6bfe3SJack F Vogel 	 */
3466ab6bfe3SJack F Vogel 	switch (hw->mac.type) {
3476ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
348c80429ceSEric Joyner 	case e1000_pch_spt:
3496fe4c0a0SSean Bruno 	case e1000_pch_cnp:
35059690eabSKevin Bowling 	case e1000_pch_tgp:
35159690eabSKevin Bowling 	case e1000_pch_adp:
35259690eabSKevin Bowling 	case e1000_pch_mtp:
3536ab6bfe3SJack F Vogel 		if (e1000_phy_is_accessible_pchlan(hw))
3546ab6bfe3SJack F Vogel 			break;
3556ab6bfe3SJack F Vogel 
3566ab6bfe3SJack F Vogel 		/* Before toggling LANPHYPC, see if PHY is accessible by
3576ab6bfe3SJack F Vogel 		 * forcing MAC to SMBus mode first.
3586ab6bfe3SJack F Vogel 		 */
3596ab6bfe3SJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
3606ab6bfe3SJack F Vogel 		mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
3616ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
3626ab6bfe3SJack F Vogel 
3637609433eSJack F Vogel 		/* Wait 50 milliseconds for MAC to finish any retries
3647609433eSJack F Vogel 		 * that it might be trying to perform from previous
3657609433eSJack F Vogel 		 * attempts to acknowledge any phy read requests.
3667609433eSJack F Vogel 		 */
3677609433eSJack F Vogel 		 msec_delay(50);
3687609433eSJack F Vogel 
3696ab6bfe3SJack F Vogel 		/* fall-through */
3706ab6bfe3SJack F Vogel 	case e1000_pch2lan:
3717609433eSJack F Vogel 		if (e1000_phy_is_accessible_pchlan(hw))
3726ab6bfe3SJack F Vogel 			break;
3736ab6bfe3SJack F Vogel 
3746ab6bfe3SJack F Vogel 		/* fall-through */
3756ab6bfe3SJack F Vogel 	case e1000_pchlan:
3766ab6bfe3SJack F Vogel 		if ((hw->mac.type == e1000_pchlan) &&
3776ab6bfe3SJack F Vogel 		    (fwsm & E1000_ICH_FWSM_FW_VALID))
3786ab6bfe3SJack F Vogel 			break;
3796ab6bfe3SJack F Vogel 
3806ab6bfe3SJack F Vogel 		if (hw->phy.ops.check_reset_block(hw)) {
3816ab6bfe3SJack F Vogel 			DEBUGOUT("Required LANPHYPC toggle blocked by ME\n");
3827609433eSJack F Vogel 			ret_val = -E1000_ERR_PHY;
3836ab6bfe3SJack F Vogel 			break;
3846ab6bfe3SJack F Vogel 		}
3856ab6bfe3SJack F Vogel 
3867609433eSJack F Vogel 		/* Toggle LANPHYPC Value bit */
3877609433eSJack F Vogel 		e1000_toggle_lanphypc_pch_lpt(hw);
3887609433eSJack F Vogel 		if (hw->mac.type >= e1000_pch_lpt) {
3897609433eSJack F Vogel 			if (e1000_phy_is_accessible_pchlan(hw))
3907609433eSJack F Vogel 				break;
3916ab6bfe3SJack F Vogel 
3926ab6bfe3SJack F Vogel 			/* Toggling LANPHYPC brings the PHY out of SMBus mode
3937609433eSJack F Vogel 			 * so ensure that the MAC is also out of SMBus mode
3946ab6bfe3SJack F Vogel 			 */
3956ab6bfe3SJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
3966ab6bfe3SJack F Vogel 			mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
3976ab6bfe3SJack F Vogel 			E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
3986ab6bfe3SJack F Vogel 
3997609433eSJack F Vogel 			if (e1000_phy_is_accessible_pchlan(hw))
4007609433eSJack F Vogel 				break;
4017609433eSJack F Vogel 
4027609433eSJack F Vogel 			ret_val = -E1000_ERR_PHY;
4036ab6bfe3SJack F Vogel 		}
4046ab6bfe3SJack F Vogel 		break;
4056ab6bfe3SJack F Vogel 	default:
4066ab6bfe3SJack F Vogel 		break;
4076ab6bfe3SJack F Vogel 	}
4086ab6bfe3SJack F Vogel 
4096ab6bfe3SJack F Vogel 	hw->phy.ops.release(hw);
4107609433eSJack F Vogel 	if (!ret_val) {
4117609433eSJack F Vogel 
4127609433eSJack F Vogel 		/* Check to see if able to reset PHY.  Print error if not */
4137609433eSJack F Vogel 		if (hw->phy.ops.check_reset_block(hw)) {
4147609433eSJack F Vogel 			ERROR_REPORT("Reset blocked by ME\n");
4157609433eSJack F Vogel 			goto out;
4167609433eSJack F Vogel 		}
4176ab6bfe3SJack F Vogel 
4186ab6bfe3SJack F Vogel 		/* Reset the PHY before any access to it.  Doing so, ensures
4196ab6bfe3SJack F Vogel 		 * that the PHY is in a known good state before we read/write
4206ab6bfe3SJack F Vogel 		 * PHY registers.  The generic reset is sufficient here,
4216ab6bfe3SJack F Vogel 		 * because we haven't determined the PHY type yet.
4226ab6bfe3SJack F Vogel 		 */
4236ab6bfe3SJack F Vogel 		ret_val = e1000_phy_hw_reset_generic(hw);
4247609433eSJack F Vogel 		if (ret_val)
4257609433eSJack F Vogel 			goto out;
4267609433eSJack F Vogel 
4277609433eSJack F Vogel 		/* On a successful reset, possibly need to wait for the PHY
4287609433eSJack F Vogel 		 * to quiesce to an accessible state before returning control
4297609433eSJack F Vogel 		 * to the calling function.  If the PHY does not quiesce, then
4307609433eSJack F Vogel 		 * return E1000E_BLK_PHY_RESET, as this is the condition that
4317609433eSJack F Vogel 		 *  the PHY is in.
4327609433eSJack F Vogel 		 */
4337609433eSJack F Vogel 		ret_val = hw->phy.ops.check_reset_block(hw);
4347609433eSJack F Vogel 		if (ret_val)
4357609433eSJack F Vogel 			ERROR_REPORT("ME blocked access to PHY after reset\n");
4367609433eSJack F Vogel 	}
4376ab6bfe3SJack F Vogel 
4386ab6bfe3SJack F Vogel out:
4396ab6bfe3SJack F Vogel 	/* Ungate automatic PHY configuration on non-managed 82579 */
4406ab6bfe3SJack F Vogel 	if ((hw->mac.type == e1000_pch2lan) &&
4416ab6bfe3SJack F Vogel 	    !(fwsm & E1000_ICH_FWSM_FW_VALID)) {
4426ab6bfe3SJack F Vogel 		msec_delay(10);
4436ab6bfe3SJack F Vogel 		e1000_gate_hw_phy_config_ich8lan(hw, FALSE);
4446ab6bfe3SJack F Vogel 	}
4456ab6bfe3SJack F Vogel 
4466ab6bfe3SJack F Vogel 	return ret_val;
4474dab5c37SJack F Vogel }
4484dab5c37SJack F Vogel 
4498cfa0ad2SJack F Vogel /**
4509d81738fSJack F Vogel  *  e1000_init_phy_params_pchlan - Initialize PHY function pointers
4519d81738fSJack F Vogel  *  @hw: pointer to the HW structure
4529d81738fSJack F Vogel  *
4539d81738fSJack F Vogel  *  Initialize family-specific PHY parameters and function pointers.
4549d81738fSJack F Vogel  **/
4559d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
4569d81738fSJack F Vogel {
4579d81738fSJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
4586ab6bfe3SJack F Vogel 	s32 ret_val;
4599d81738fSJack F Vogel 
4609d81738fSJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_pchlan");
4619d81738fSJack F Vogel 
4629d81738fSJack F Vogel 	phy->addr		= 1;
4639d81738fSJack F Vogel 	phy->reset_delay_us	= 100;
4649d81738fSJack F Vogel 
4659d81738fSJack F Vogel 	phy->ops.acquire	= e1000_acquire_swflag_ich8lan;
4669d81738fSJack F Vogel 	phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
4679d81738fSJack F Vogel 	phy->ops.get_cfg_done	= e1000_get_cfg_done_ich8lan;
4684dab5c37SJack F Vogel 	phy->ops.set_page	= e1000_set_page_igp;
4699d81738fSJack F Vogel 	phy->ops.read_reg	= e1000_read_phy_reg_hv;
4704edd8523SJack F Vogel 	phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked;
4714dab5c37SJack F Vogel 	phy->ops.read_reg_page	= e1000_read_phy_reg_page_hv;
4729d81738fSJack F Vogel 	phy->ops.release	= e1000_release_swflag_ich8lan;
4739d81738fSJack F Vogel 	phy->ops.reset		= e1000_phy_hw_reset_ich8lan;
4744edd8523SJack F Vogel 	phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan;
4754edd8523SJack F Vogel 	phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan;
4769d81738fSJack F Vogel 	phy->ops.write_reg	= e1000_write_phy_reg_hv;
4774edd8523SJack F Vogel 	phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked;
4784dab5c37SJack F Vogel 	phy->ops.write_reg_page	= e1000_write_phy_reg_page_hv;
4799d81738fSJack F Vogel 	phy->ops.power_up	= e1000_power_up_phy_copper;
4809d81738fSJack F Vogel 	phy->ops.power_down	= e1000_power_down_phy_copper_ich8lan;
4819d81738fSJack F Vogel 	phy->autoneg_mask	= AUTONEG_ADVERTISE_SPEED_DEFAULT;
4829d81738fSJack F Vogel 
4839d81738fSJack F Vogel 	phy->id = e1000_phy_unknown;
4846ab6bfe3SJack F Vogel 
4856ab6bfe3SJack F Vogel 	ret_val = e1000_init_phy_workarounds_pchlan(hw);
4866ab6bfe3SJack F Vogel 	if (ret_val)
4876ab6bfe3SJack F Vogel 		return ret_val;
4886ab6bfe3SJack F Vogel 
4896ab6bfe3SJack F Vogel 	if (phy->id == e1000_phy_unknown)
4907d9119bdSJack F Vogel 		switch (hw->mac.type) {
4917d9119bdSJack F Vogel 		default:
492a69ed8dfSJack F Vogel 			ret_val = e1000_get_phy_id(hw);
493a69ed8dfSJack F Vogel 			if (ret_val)
4946ab6bfe3SJack F Vogel 				return ret_val;
4957d9119bdSJack F Vogel 			if ((phy->id != 0) && (phy->id != PHY_REVISION_MASK))
4967d9119bdSJack F Vogel 				break;
4977d9119bdSJack F Vogel 			/* fall-through */
4987d9119bdSJack F Vogel 		case e1000_pch2lan:
4996ab6bfe3SJack F Vogel 		case e1000_pch_lpt:
500c80429ceSEric Joyner 		case e1000_pch_spt:
5016fe4c0a0SSean Bruno 		case e1000_pch_cnp:
50259690eabSKevin Bowling 		case e1000_pch_tgp:
50359690eabSKevin Bowling 		case e1000_pch_adp:
50459690eabSKevin Bowling 		case e1000_pch_mtp:
5056ab6bfe3SJack F Vogel 			/* In case the PHY needs to be in mdio slow mode,
506a69ed8dfSJack F Vogel 			 * set slow mode and try to get the PHY id again.
507a69ed8dfSJack F Vogel 			 */
508a69ed8dfSJack F Vogel 			ret_val = e1000_set_mdio_slow_mode_hv(hw);
509a69ed8dfSJack F Vogel 			if (ret_val)
5106ab6bfe3SJack F Vogel 				return ret_val;
511a69ed8dfSJack F Vogel 			ret_val = e1000_get_phy_id(hw);
512a69ed8dfSJack F Vogel 			if (ret_val)
5136ab6bfe3SJack F Vogel 				return ret_val;
5147d9119bdSJack F Vogel 			break;
515a69ed8dfSJack F Vogel 		}
5169d81738fSJack F Vogel 	phy->type = e1000_get_phy_type_from_id(phy->id);
5179d81738fSJack F Vogel 
5184edd8523SJack F Vogel 	switch (phy->type) {
5194edd8523SJack F Vogel 	case e1000_phy_82577:
5207d9119bdSJack F Vogel 	case e1000_phy_82579:
5216ab6bfe3SJack F Vogel 	case e1000_phy_i217:
5229d81738fSJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_82577;
5239d81738fSJack F Vogel 		phy->ops.force_speed_duplex =
5249d81738fSJack F Vogel 			e1000_phy_force_speed_duplex_82577;
5259d81738fSJack F Vogel 		phy->ops.get_cable_length = e1000_get_cable_length_82577;
5269d81738fSJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_82577;
5279d81738fSJack F Vogel 		phy->ops.commit = e1000_phy_sw_reset_generic;
5288ec87fc5SJack F Vogel 		break;
5294edd8523SJack F Vogel 	case e1000_phy_82578:
5304edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_m88;
5314edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
5324edd8523SJack F Vogel 		phy->ops.get_cable_length = e1000_get_cable_length_m88;
5334edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_m88;
5344edd8523SJack F Vogel 		break;
5354edd8523SJack F Vogel 	default:
5364edd8523SJack F Vogel 		ret_val = -E1000_ERR_PHY;
5374edd8523SJack F Vogel 		break;
5389d81738fSJack F Vogel 	}
5399d81738fSJack F Vogel 
5409d81738fSJack F Vogel 	return ret_val;
5419d81738fSJack F Vogel }
5429d81738fSJack F Vogel 
5439d81738fSJack F Vogel /**
5448cfa0ad2SJack F Vogel  *  e1000_init_phy_params_ich8lan - Initialize PHY function pointers
5458cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5468cfa0ad2SJack F Vogel  *
5478cfa0ad2SJack F Vogel  *  Initialize family-specific PHY parameters and function pointers.
5488cfa0ad2SJack F Vogel  **/
5498cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
5508cfa0ad2SJack F Vogel {
5518cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
5526ab6bfe3SJack F Vogel 	s32 ret_val;
5538cfa0ad2SJack F Vogel 	u16 i = 0;
5548cfa0ad2SJack F Vogel 
5558cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_ich8lan");
5568cfa0ad2SJack F Vogel 
5578cfa0ad2SJack F Vogel 	phy->addr		= 1;
5588cfa0ad2SJack F Vogel 	phy->reset_delay_us	= 100;
5598cfa0ad2SJack F Vogel 
5608cfa0ad2SJack F Vogel 	phy->ops.acquire	= e1000_acquire_swflag_ich8lan;
5618cfa0ad2SJack F Vogel 	phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
5628cfa0ad2SJack F Vogel 	phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
5638cfa0ad2SJack F Vogel 	phy->ops.get_cfg_done	= e1000_get_cfg_done_ich8lan;
5648cfa0ad2SJack F Vogel 	phy->ops.read_reg	= e1000_read_phy_reg_igp;
5658cfa0ad2SJack F Vogel 	phy->ops.release	= e1000_release_swflag_ich8lan;
5668cfa0ad2SJack F Vogel 	phy->ops.reset		= e1000_phy_hw_reset_ich8lan;
5678cfa0ad2SJack F Vogel 	phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan;
5688cfa0ad2SJack F Vogel 	phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan;
5698cfa0ad2SJack F Vogel 	phy->ops.write_reg	= e1000_write_phy_reg_igp;
5708cfa0ad2SJack F Vogel 	phy->ops.power_up	= e1000_power_up_phy_copper;
5718cfa0ad2SJack F Vogel 	phy->ops.power_down	= e1000_power_down_phy_copper_ich8lan;
5728cfa0ad2SJack F Vogel 
5736ab6bfe3SJack F Vogel 	/* We may need to do this twice - once for IGP and if that fails,
5748cfa0ad2SJack F Vogel 	 * we'll set BM func pointers and try again
5758cfa0ad2SJack F Vogel 	 */
5768cfa0ad2SJack F Vogel 	ret_val = e1000_determine_phy_address(hw);
5778cfa0ad2SJack F Vogel 	if (ret_val) {
5788cfa0ad2SJack F Vogel 		phy->ops.write_reg = e1000_write_phy_reg_bm;
5798cfa0ad2SJack F Vogel 		phy->ops.read_reg  = e1000_read_phy_reg_bm;
5808cfa0ad2SJack F Vogel 		ret_val = e1000_determine_phy_address(hw);
5818cfa0ad2SJack F Vogel 		if (ret_val) {
582d035aa2dSJack F Vogel 			DEBUGOUT("Cannot determine PHY addr. Erroring out\n");
5836ab6bfe3SJack F Vogel 			return ret_val;
5848cfa0ad2SJack F Vogel 		}
5858cfa0ad2SJack F Vogel 	}
5868cfa0ad2SJack F Vogel 
5878cfa0ad2SJack F Vogel 	phy->id = 0;
5888cfa0ad2SJack F Vogel 	while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) &&
5898cfa0ad2SJack F Vogel 	       (i++ < 100)) {
5908cfa0ad2SJack F Vogel 		msec_delay(1);
5918cfa0ad2SJack F Vogel 		ret_val = e1000_get_phy_id(hw);
5928cfa0ad2SJack F Vogel 		if (ret_val)
5936ab6bfe3SJack F Vogel 			return ret_val;
5948cfa0ad2SJack F Vogel 	}
5958cfa0ad2SJack F Vogel 
5968cfa0ad2SJack F Vogel 	/* Verify phy id */
5978cfa0ad2SJack F Vogel 	switch (phy->id) {
5988cfa0ad2SJack F Vogel 	case IGP03E1000_E_PHY_ID:
5998cfa0ad2SJack F Vogel 		phy->type = e1000_phy_igp_3;
6008cfa0ad2SJack F Vogel 		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
6014edd8523SJack F Vogel 		phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked;
6024edd8523SJack F Vogel 		phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked;
6034edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_igp;
6044edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_igp;
6054edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
6068cfa0ad2SJack F Vogel 		break;
6078cfa0ad2SJack F Vogel 	case IFE_E_PHY_ID:
6088cfa0ad2SJack F Vogel 	case IFE_PLUS_E_PHY_ID:
6098cfa0ad2SJack F Vogel 	case IFE_C_E_PHY_ID:
6108cfa0ad2SJack F Vogel 		phy->type = e1000_phy_ife;
6118cfa0ad2SJack F Vogel 		phy->autoneg_mask = E1000_ALL_NOT_GIG;
6124edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_ife;
6134edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_ife;
6144edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife;
6158cfa0ad2SJack F Vogel 		break;
6168cfa0ad2SJack F Vogel 	case BME1000_E_PHY_ID:
6178cfa0ad2SJack F Vogel 		phy->type = e1000_phy_bm;
6188cfa0ad2SJack F Vogel 		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
6198cfa0ad2SJack F Vogel 		phy->ops.read_reg = e1000_read_phy_reg_bm;
6208cfa0ad2SJack F Vogel 		phy->ops.write_reg = e1000_write_phy_reg_bm;
6218cfa0ad2SJack F Vogel 		phy->ops.commit = e1000_phy_sw_reset_generic;
6224edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_m88;
6234edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_m88;
6244edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
6258cfa0ad2SJack F Vogel 		break;
6268cfa0ad2SJack F Vogel 	default:
6276ab6bfe3SJack F Vogel 		return -E1000_ERR_PHY;
6286ab6bfe3SJack F Vogel 		break;
6298cfa0ad2SJack F Vogel 	}
6308cfa0ad2SJack F Vogel 
6316ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
6328cfa0ad2SJack F Vogel }
6338cfa0ad2SJack F Vogel 
6348cfa0ad2SJack F Vogel /**
6358cfa0ad2SJack F Vogel  *  e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
6368cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
6378cfa0ad2SJack F Vogel  *
6388cfa0ad2SJack F Vogel  *  Initialize family-specific NVM parameters and function
6398cfa0ad2SJack F Vogel  *  pointers.
6408cfa0ad2SJack F Vogel  **/
6418cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
6428cfa0ad2SJack F Vogel {
6438cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
644daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
6458cfa0ad2SJack F Vogel 	u32 gfpreg, sector_base_addr, sector_end_addr;
6468cfa0ad2SJack F Vogel 	u16 i;
647c80429ceSEric Joyner 	u32 nvm_size;
6488cfa0ad2SJack F Vogel 
6498cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_nvm_params_ich8lan");
6508cfa0ad2SJack F Vogel 
6518cc64f1eSJack F Vogel 	nvm->type = e1000_nvm_flash_sw;
652c80429ceSEric Joyner 
653295df609SEric Joyner 	if (hw->mac.type >= e1000_pch_spt) {
654c80429ceSEric Joyner 		/* in SPT, gfpreg doesn't exist. NVM size is taken from the
655c80429ceSEric Joyner 		 * STRAP register. This is because in SPT the GbE Flash region
656c80429ceSEric Joyner 		 * is no longer accessed through the flash registers. Instead,
657c80429ceSEric Joyner 		 * the mechanism has changed, and the Flash region access
658c80429ceSEric Joyner 		 * registers are now implemented in GbE memory space.
659c80429ceSEric Joyner 		 */
660c80429ceSEric Joyner 		nvm->flash_base_addr = 0;
661c80429ceSEric Joyner 		nvm_size =
662c80429ceSEric Joyner 		    (((E1000_READ_REG(hw, E1000_STRAP) >> 1) & 0x1F) + 1)
663c80429ceSEric Joyner 		    * NVM_SIZE_MULTIPLIER;
664c80429ceSEric Joyner 		nvm->flash_bank_size = nvm_size / 2;
665c80429ceSEric Joyner 		/* Adjust to word count */
666c80429ceSEric Joyner 		nvm->flash_bank_size /= sizeof(u16);
667c80429ceSEric Joyner 		/* Set the base address for flash register access */
668c80429ceSEric Joyner 		hw->flash_address = hw->hw_addr + E1000_FLASH_BASE_ADDR;
669c80429ceSEric Joyner 	} else {
670c80429ceSEric Joyner 		/* Can't read flash registers if register set isn't mapped. */
6718cfa0ad2SJack F Vogel 		if (!hw->flash_address) {
6728cfa0ad2SJack F Vogel 			DEBUGOUT("ERROR: Flash registers not mapped\n");
6736ab6bfe3SJack F Vogel 			return -E1000_ERR_CONFIG;
6748cfa0ad2SJack F Vogel 		}
6758cfa0ad2SJack F Vogel 
6768cfa0ad2SJack F Vogel 		gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG);
6778cfa0ad2SJack F Vogel 
6786ab6bfe3SJack F Vogel 		/* sector_X_addr is a "sector"-aligned address (4096 bytes)
6798cfa0ad2SJack F Vogel 		 * Add 1 to sector_end_addr since this sector is included in
6808cfa0ad2SJack F Vogel 		 * the overall size.
6818cfa0ad2SJack F Vogel 		 */
6828cfa0ad2SJack F Vogel 		sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
6838cfa0ad2SJack F Vogel 		sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
6848cfa0ad2SJack F Vogel 
6858cfa0ad2SJack F Vogel 		/* flash_base_addr is byte-aligned */
686c80429ceSEric Joyner 		nvm->flash_base_addr = sector_base_addr
687c80429ceSEric Joyner 				       << FLASH_SECTOR_ADDR_SHIFT;
6888cfa0ad2SJack F Vogel 
6896ab6bfe3SJack F Vogel 		/* find total size of the NVM, then cut in half since the total
6908cfa0ad2SJack F Vogel 		 * size represents two separate NVM banks.
6918cfa0ad2SJack F Vogel 		 */
6927609433eSJack F Vogel 		nvm->flash_bank_size = ((sector_end_addr - sector_base_addr)
6937609433eSJack F Vogel 					<< FLASH_SECTOR_ADDR_SHIFT);
6948cfa0ad2SJack F Vogel 		nvm->flash_bank_size /= 2;
6958cfa0ad2SJack F Vogel 		/* Adjust to word count */
6968cfa0ad2SJack F Vogel 		nvm->flash_bank_size /= sizeof(u16);
697c80429ceSEric Joyner 	}
6988cfa0ad2SJack F Vogel 
6998cfa0ad2SJack F Vogel 	nvm->word_size = E1000_SHADOW_RAM_WORDS;
7008cfa0ad2SJack F Vogel 
7018cfa0ad2SJack F Vogel 	/* Clear shadow ram */
7028cfa0ad2SJack F Vogel 	for (i = 0; i < nvm->word_size; i++) {
7038cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].modified = FALSE;
7048cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].value    = 0xFFFF;
7058cfa0ad2SJack F Vogel 	}
7068cfa0ad2SJack F Vogel 
7078cfa0ad2SJack F Vogel 	/* Function Pointers */
7084edd8523SJack F Vogel 	nvm->ops.acquire	= e1000_acquire_nvm_ich8lan;
7094edd8523SJack F Vogel 	nvm->ops.release	= e1000_release_nvm_ich8lan;
710295df609SEric Joyner 	if (hw->mac.type >= e1000_pch_spt) {
711c80429ceSEric Joyner 		nvm->ops.read	= e1000_read_nvm_spt;
712c80429ceSEric Joyner 		nvm->ops.update	= e1000_update_nvm_checksum_spt;
713c80429ceSEric Joyner 	} else {
7148cfa0ad2SJack F Vogel 		nvm->ops.read	= e1000_read_nvm_ich8lan;
7158cfa0ad2SJack F Vogel 		nvm->ops.update	= e1000_update_nvm_checksum_ich8lan;
716c80429ceSEric Joyner 	}
7178cfa0ad2SJack F Vogel 	nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan;
7188cfa0ad2SJack F Vogel 	nvm->ops.validate	= e1000_validate_nvm_checksum_ich8lan;
7198cfa0ad2SJack F Vogel 	nvm->ops.write		= e1000_write_nvm_ich8lan;
7208cfa0ad2SJack F Vogel 
7216ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
7228cfa0ad2SJack F Vogel }
7238cfa0ad2SJack F Vogel 
7248cfa0ad2SJack F Vogel /**
7258cfa0ad2SJack F Vogel  *  e1000_init_mac_params_ich8lan - Initialize MAC function pointers
7268cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
7278cfa0ad2SJack F Vogel  *
7288cfa0ad2SJack F Vogel  *  Initialize family-specific MAC parameters and function
7298cfa0ad2SJack F Vogel  *  pointers.
7308cfa0ad2SJack F Vogel  **/
7318cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
7328cfa0ad2SJack F Vogel {
7338cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
734*fc7682b1SKevin Bowling 	u16 pci_cfg;
7358cfa0ad2SJack F Vogel 
7368cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_mac_params_ich8lan");
7378cfa0ad2SJack F Vogel 
7388cfa0ad2SJack F Vogel 	/* Set media type function pointer */
7398cfa0ad2SJack F Vogel 	hw->phy.media_type = e1000_media_type_copper;
7408cfa0ad2SJack F Vogel 
7418cfa0ad2SJack F Vogel 	/* Set mta register count */
7428cfa0ad2SJack F Vogel 	mac->mta_reg_count = 32;
7438cfa0ad2SJack F Vogel 	/* Set rar entry count */
7448cfa0ad2SJack F Vogel 	mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
7458cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
7468cfa0ad2SJack F Vogel 		mac->rar_entry_count--;
7478cfa0ad2SJack F Vogel 	/* Set if part includes ASF firmware */
7488cfa0ad2SJack F Vogel 	mac->asf_firmware_present = TRUE;
7498ec87fc5SJack F Vogel 	/* FWSM register */
7508ec87fc5SJack F Vogel 	mac->has_fwsm = TRUE;
7518ec87fc5SJack F Vogel 	/* ARC subsystem not supported */
7528ec87fc5SJack F Vogel 	mac->arc_subsystem_valid = FALSE;
7534edd8523SJack F Vogel 	/* Adaptive IFS supported */
7544edd8523SJack F Vogel 	mac->adaptive_ifs = TRUE;
7558cfa0ad2SJack F Vogel 
7568cfa0ad2SJack F Vogel 	/* Function pointers */
7578cfa0ad2SJack F Vogel 
7588cfa0ad2SJack F Vogel 	/* bus type/speed/width */
7598cfa0ad2SJack F Vogel 	mac->ops.get_bus_info = e1000_get_bus_info_ich8lan;
760daf9197cSJack F Vogel 	/* function id */
761daf9197cSJack F Vogel 	mac->ops.set_lan_id = e1000_set_lan_id_single_port;
7628cfa0ad2SJack F Vogel 	/* reset */
7638cfa0ad2SJack F Vogel 	mac->ops.reset_hw = e1000_reset_hw_ich8lan;
7648cfa0ad2SJack F Vogel 	/* hw initialization */
7658cfa0ad2SJack F Vogel 	mac->ops.init_hw = e1000_init_hw_ich8lan;
7668cfa0ad2SJack F Vogel 	/* link setup */
7678cfa0ad2SJack F Vogel 	mac->ops.setup_link = e1000_setup_link_ich8lan;
7688cfa0ad2SJack F Vogel 	/* physical interface setup */
7698cfa0ad2SJack F Vogel 	mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan;
7708cfa0ad2SJack F Vogel 	/* check for link */
7714edd8523SJack F Vogel 	mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan;
7728cfa0ad2SJack F Vogel 	/* link info */
7738cfa0ad2SJack F Vogel 	mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan;
7748cfa0ad2SJack F Vogel 	/* multicast address update */
7758cfa0ad2SJack F Vogel 	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
776d035aa2dSJack F Vogel 	/* clear hardware counters */
777d035aa2dSJack F Vogel 	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan;
778d035aa2dSJack F Vogel 
7796ab6bfe3SJack F Vogel 	/* LED and other operations */
780d035aa2dSJack F Vogel 	switch (mac->type) {
781d035aa2dSJack F Vogel 	case e1000_ich8lan:
782d035aa2dSJack F Vogel 	case e1000_ich9lan:
783d035aa2dSJack F Vogel 	case e1000_ich10lan:
7847d9119bdSJack F Vogel 		/* check management mode */
7857d9119bdSJack F Vogel 		mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
786d035aa2dSJack F Vogel 		/* ID LED init */
787d035aa2dSJack F Vogel 		mac->ops.id_led_init = e1000_id_led_init_generic;
7888cfa0ad2SJack F Vogel 		/* blink LED */
7898cfa0ad2SJack F Vogel 		mac->ops.blink_led = e1000_blink_led_generic;
7908cfa0ad2SJack F Vogel 		/* setup LED */
7918cfa0ad2SJack F Vogel 		mac->ops.setup_led = e1000_setup_led_generic;
7928cfa0ad2SJack F Vogel 		/* cleanup LED */
7938cfa0ad2SJack F Vogel 		mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
7948cfa0ad2SJack F Vogel 		/* turn on/off LED */
7958cfa0ad2SJack F Vogel 		mac->ops.led_on = e1000_led_on_ich8lan;
7968cfa0ad2SJack F Vogel 		mac->ops.led_off = e1000_led_off_ich8lan;
797d035aa2dSJack F Vogel 		break;
7987d9119bdSJack F Vogel 	case e1000_pch2lan:
7997d9119bdSJack F Vogel 		mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES;
8007d9119bdSJack F Vogel 		mac->ops.rar_set = e1000_rar_set_pch2lan;
8016ab6bfe3SJack F Vogel 		/* fall-through */
8026ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
803c80429ceSEric Joyner 	case e1000_pch_spt:
8046fe4c0a0SSean Bruno 	case e1000_pch_cnp:
80559690eabSKevin Bowling 	case e1000_pch_tgp:
80659690eabSKevin Bowling 	case e1000_pch_adp:
80759690eabSKevin Bowling 	case e1000_pch_mtp:
808730d3130SJack F Vogel 		/* multicast address update for pch2 */
809730d3130SJack F Vogel 		mac->ops.update_mc_addr_list =
810730d3130SJack F Vogel 			e1000_update_mc_addr_list_pch2lan;
811c80429ceSEric Joyner 		/* fall-through */
8129d81738fSJack F Vogel 	case e1000_pchlan:
813*fc7682b1SKevin Bowling 		/* save PCH revision_id */
814*fc7682b1SKevin Bowling 		e1000_read_pci_cfg(hw, E1000_PCI_REVISION_ID_REG, &pci_cfg);
815*fc7682b1SKevin Bowling 		/* SPT uses full byte for revision ID,
816*fc7682b1SKevin Bowling 		 * as opposed to previous generations
817*fc7682b1SKevin Bowling 		 */
818*fc7682b1SKevin Bowling 		if (hw->mac.type >= e1000_pch_spt)
819*fc7682b1SKevin Bowling 			hw->revision_id = (u8)(pci_cfg &= 0x00FF);
820*fc7682b1SKevin Bowling 		else
821*fc7682b1SKevin Bowling 			hw->revision_id = (u8)(pci_cfg &= 0x000F);
8227d9119bdSJack F Vogel 		/* check management mode */
8237d9119bdSJack F Vogel 		mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
8249d81738fSJack F Vogel 		/* ID LED init */
8259d81738fSJack F Vogel 		mac->ops.id_led_init = e1000_id_led_init_pchlan;
8269d81738fSJack F Vogel 		/* setup LED */
8279d81738fSJack F Vogel 		mac->ops.setup_led = e1000_setup_led_pchlan;
8289d81738fSJack F Vogel 		/* cleanup LED */
8299d81738fSJack F Vogel 		mac->ops.cleanup_led = e1000_cleanup_led_pchlan;
8309d81738fSJack F Vogel 		/* turn on/off LED */
8319d81738fSJack F Vogel 		mac->ops.led_on = e1000_led_on_pchlan;
8329d81738fSJack F Vogel 		mac->ops.led_off = e1000_led_off_pchlan;
8339d81738fSJack F Vogel 		break;
834d035aa2dSJack F Vogel 	default:
835d035aa2dSJack F Vogel 		break;
836d035aa2dSJack F Vogel 	}
8378cfa0ad2SJack F Vogel 
838295df609SEric Joyner 	if (mac->type >= e1000_pch_lpt) {
8396ab6bfe3SJack F Vogel 		mac->rar_entry_count = E1000_PCH_LPT_RAR_ENTRIES;
8406ab6bfe3SJack F Vogel 		mac->ops.rar_set = e1000_rar_set_pch_lpt;
8416ab6bfe3SJack F Vogel 		mac->ops.setup_physical_interface = e1000_setup_copper_link_pch_lpt;
842e373323fSSean Bruno 		mac->ops.set_obff_timer = e1000_set_obff_timer_pch_lpt;
8434dab5c37SJack F Vogel 	}
8444dab5c37SJack F Vogel 
8458cfa0ad2SJack F Vogel 	/* Enable PCS Lock-loss workaround for ICH8 */
8468cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
8478cfa0ad2SJack F Vogel 		e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE);
8488cfa0ad2SJack F Vogel 
849daf9197cSJack F Vogel 	return E1000_SUCCESS;
8508cfa0ad2SJack F Vogel }
8518cfa0ad2SJack F Vogel 
8528cfa0ad2SJack F Vogel /**
8536ab6bfe3SJack F Vogel  *  __e1000_access_emi_reg_locked - Read/write EMI register
8546ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
855*fc7682b1SKevin Bowling  *  @address: EMI address to program
8566ab6bfe3SJack F Vogel  *  @data: pointer to value to read/write from/to the EMI address
8576ab6bfe3SJack F Vogel  *  @read: boolean flag to indicate read or write
8586ab6bfe3SJack F Vogel  *
8596ab6bfe3SJack F Vogel  *  This helper function assumes the SW/FW/HW Semaphore is already acquired.
8606ab6bfe3SJack F Vogel  **/
8616ab6bfe3SJack F Vogel static s32 __e1000_access_emi_reg_locked(struct e1000_hw *hw, u16 address,
8626ab6bfe3SJack F Vogel 					 u16 *data, bool read)
8636ab6bfe3SJack F Vogel {
8646ab6bfe3SJack F Vogel 	s32 ret_val;
8656ab6bfe3SJack F Vogel 
8666ab6bfe3SJack F Vogel 	DEBUGFUNC("__e1000_access_emi_reg_locked");
8676ab6bfe3SJack F Vogel 
8686ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR, address);
8696ab6bfe3SJack F Vogel 	if (ret_val)
8706ab6bfe3SJack F Vogel 		return ret_val;
8716ab6bfe3SJack F Vogel 
8726ab6bfe3SJack F Vogel 	if (read)
8736ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.read_reg_locked(hw, I82579_EMI_DATA,
8746ab6bfe3SJack F Vogel 						      data);
8756ab6bfe3SJack F Vogel 	else
8766ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_DATA,
8776ab6bfe3SJack F Vogel 						       *data);
8786ab6bfe3SJack F Vogel 
8796ab6bfe3SJack F Vogel 	return ret_val;
8806ab6bfe3SJack F Vogel }
8816ab6bfe3SJack F Vogel 
8826ab6bfe3SJack F Vogel /**
8836ab6bfe3SJack F Vogel  *  e1000_read_emi_reg_locked - Read Extended Management Interface register
8846ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
8856ab6bfe3SJack F Vogel  *  @addr: EMI address to program
8866ab6bfe3SJack F Vogel  *  @data: value to be read from the EMI address
8876ab6bfe3SJack F Vogel  *
8886ab6bfe3SJack F Vogel  *  Assumes the SW/FW/HW Semaphore is already acquired.
8896ab6bfe3SJack F Vogel  **/
8906ab6bfe3SJack F Vogel s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data)
8916ab6bfe3SJack F Vogel {
8926ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_read_emi_reg_locked");
8936ab6bfe3SJack F Vogel 
8946ab6bfe3SJack F Vogel 	return __e1000_access_emi_reg_locked(hw, addr, data, TRUE);
8956ab6bfe3SJack F Vogel }
8966ab6bfe3SJack F Vogel 
8976ab6bfe3SJack F Vogel /**
8986ab6bfe3SJack F Vogel  *  e1000_write_emi_reg_locked - Write Extended Management Interface register
8996ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
9006ab6bfe3SJack F Vogel  *  @addr: EMI address to program
9016ab6bfe3SJack F Vogel  *  @data: value to be written to the EMI address
9026ab6bfe3SJack F Vogel  *
9036ab6bfe3SJack F Vogel  *  Assumes the SW/FW/HW Semaphore is already acquired.
9046ab6bfe3SJack F Vogel  **/
9057609433eSJack F Vogel s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
9066ab6bfe3SJack F Vogel {
9076ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_read_emi_reg_locked");
9086ab6bfe3SJack F Vogel 
9096ab6bfe3SJack F Vogel 	return __e1000_access_emi_reg_locked(hw, addr, &data, FALSE);
9106ab6bfe3SJack F Vogel }
9116ab6bfe3SJack F Vogel 
9126ab6bfe3SJack F Vogel /**
9137d9119bdSJack F Vogel  *  e1000_set_eee_pchlan - Enable/disable EEE support
9147d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
9157d9119bdSJack F Vogel  *
9166ab6bfe3SJack F Vogel  *  Enable/disable EEE based on setting in dev_spec structure, the duplex of
9176ab6bfe3SJack F Vogel  *  the link and the EEE capabilities of the link partner.  The LPI Control
9186ab6bfe3SJack F Vogel  *  register bits will remain set only if/when link is up.
9197609433eSJack F Vogel  *
9207609433eSJack F Vogel  *  EEE LPI must not be asserted earlier than one second after link is up.
9217609433eSJack F Vogel  *  On 82579, EEE LPI should not be enabled until such time otherwise there
9227609433eSJack F Vogel  *  can be link issues with some switches.  Other devices can have EEE LPI
9237609433eSJack F Vogel  *  enabled immediately upon link up since they have a timer in hardware which
9247609433eSJack F Vogel  *  prevents LPI from being asserted too early.
9257d9119bdSJack F Vogel  **/
9267609433eSJack F Vogel s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
9277d9119bdSJack F Vogel {
9284dab5c37SJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
9296ab6bfe3SJack F Vogel 	s32 ret_val;
9307609433eSJack F Vogel 	u16 lpa, pcs_status, adv, adv_addr, lpi_ctrl, data;
9317d9119bdSJack F Vogel 
9327d9119bdSJack F Vogel 	DEBUGFUNC("e1000_set_eee_pchlan");
9337d9119bdSJack F Vogel 
9347609433eSJack F Vogel 	switch (hw->phy.type) {
9357609433eSJack F Vogel 	case e1000_phy_82579:
9367609433eSJack F Vogel 		lpa = I82579_EEE_LP_ABILITY;
9377609433eSJack F Vogel 		pcs_status = I82579_EEE_PCS_STATUS;
9387609433eSJack F Vogel 		adv_addr = I82579_EEE_ADVERTISEMENT;
9397609433eSJack F Vogel 		break;
9407609433eSJack F Vogel 	case e1000_phy_i217:
9417609433eSJack F Vogel 		lpa = I217_EEE_LP_ABILITY;
9427609433eSJack F Vogel 		pcs_status = I217_EEE_PCS_STATUS;
9437609433eSJack F Vogel 		adv_addr = I217_EEE_ADVERTISEMENT;
9447609433eSJack F Vogel 		break;
9457609433eSJack F Vogel 	default:
9466ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
9477609433eSJack F Vogel 	}
9487d9119bdSJack F Vogel 
9496ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
9507d9119bdSJack F Vogel 	if (ret_val)
9517d9119bdSJack F Vogel 		return ret_val;
9526ab6bfe3SJack F Vogel 
9536ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw, I82579_LPI_CTRL, &lpi_ctrl);
9546ab6bfe3SJack F Vogel 	if (ret_val)
9556ab6bfe3SJack F Vogel 		goto release;
9566ab6bfe3SJack F Vogel 
9576ab6bfe3SJack F Vogel 	/* Clear bits that enable EEE in various speeds */
9586ab6bfe3SJack F Vogel 	lpi_ctrl &= ~I82579_LPI_CTRL_ENABLE_MASK;
9596ab6bfe3SJack F Vogel 
9606ab6bfe3SJack F Vogel 	/* Enable EEE if not disabled by user */
9616ab6bfe3SJack F Vogel 	if (!dev_spec->eee_disable) {
9626ab6bfe3SJack F Vogel 		/* Save off link partner's EEE ability */
9636ab6bfe3SJack F Vogel 		ret_val = e1000_read_emi_reg_locked(hw, lpa,
9646ab6bfe3SJack F Vogel 						    &dev_spec->eee_lp_ability);
9656ab6bfe3SJack F Vogel 		if (ret_val)
9666ab6bfe3SJack F Vogel 			goto release;
9676ab6bfe3SJack F Vogel 
9687609433eSJack F Vogel 		/* Read EEE advertisement */
9697609433eSJack F Vogel 		ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &adv);
9707609433eSJack F Vogel 		if (ret_val)
9717609433eSJack F Vogel 			goto release;
9727609433eSJack F Vogel 
9736ab6bfe3SJack F Vogel 		/* Enable EEE only for speeds in which the link partner is
9747609433eSJack F Vogel 		 * EEE capable and for which we advertise EEE.
9756ab6bfe3SJack F Vogel 		 */
9767609433eSJack F Vogel 		if (adv & dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED)
9776ab6bfe3SJack F Vogel 			lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE;
9786ab6bfe3SJack F Vogel 
9797609433eSJack F Vogel 		if (adv & dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) {
9806ab6bfe3SJack F Vogel 			hw->phy.ops.read_reg_locked(hw, PHY_LP_ABILITY, &data);
9816ab6bfe3SJack F Vogel 			if (data & NWAY_LPAR_100TX_FD_CAPS)
9826ab6bfe3SJack F Vogel 				lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE;
9836ab6bfe3SJack F Vogel 			else
9846ab6bfe3SJack F Vogel 				/* EEE is not supported in 100Half, so ignore
9856ab6bfe3SJack F Vogel 				 * partner's EEE in 100 ability if full-duplex
9866ab6bfe3SJack F Vogel 				 * is not advertised.
9876ab6bfe3SJack F Vogel 				 */
9886ab6bfe3SJack F Vogel 				dev_spec->eee_lp_ability &=
9896ab6bfe3SJack F Vogel 				    ~I82579_EEE_100_SUPPORTED;
9906ab6bfe3SJack F Vogel 		}
9917609433eSJack F Vogel 	}
9926ab6bfe3SJack F Vogel 
9938cc64f1eSJack F Vogel 	if (hw->phy.type == e1000_phy_82579) {
9948cc64f1eSJack F Vogel 		ret_val = e1000_read_emi_reg_locked(hw, I82579_LPI_PLL_SHUT,
9958cc64f1eSJack F Vogel 						    &data);
9968cc64f1eSJack F Vogel 		if (ret_val)
9978cc64f1eSJack F Vogel 			goto release;
9988cc64f1eSJack F Vogel 
9998cc64f1eSJack F Vogel 		data &= ~I82579_LPI_100_PLL_SHUT;
10008cc64f1eSJack F Vogel 		ret_val = e1000_write_emi_reg_locked(hw, I82579_LPI_PLL_SHUT,
10018cc64f1eSJack F Vogel 						     data);
10028cc64f1eSJack F Vogel 	}
10038cc64f1eSJack F Vogel 
10046ab6bfe3SJack F Vogel 	/* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */
10056ab6bfe3SJack F Vogel 	ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data);
10066ab6bfe3SJack F Vogel 	if (ret_val)
10076ab6bfe3SJack F Vogel 		goto release;
10086ab6bfe3SJack F Vogel 
10096ab6bfe3SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, I82579_LPI_CTRL, lpi_ctrl);
10106ab6bfe3SJack F Vogel release:
10116ab6bfe3SJack F Vogel 	hw->phy.ops.release(hw);
10126ab6bfe3SJack F Vogel 
10136ab6bfe3SJack F Vogel 	return ret_val;
10146ab6bfe3SJack F Vogel }
10156ab6bfe3SJack F Vogel 
10166ab6bfe3SJack F Vogel /**
10176ab6bfe3SJack F Vogel  *  e1000_k1_workaround_lpt_lp - K1 workaround on Lynxpoint-LP
10186ab6bfe3SJack F Vogel  *  @hw:   pointer to the HW structure
10196ab6bfe3SJack F Vogel  *  @link: link up bool flag
10206ab6bfe3SJack F Vogel  *
10216ab6bfe3SJack F Vogel  *  When K1 is enabled for 1Gbps, the MAC can miss 2 DMA completion indications
10226ab6bfe3SJack F Vogel  *  preventing further DMA write requests.  Workaround the issue by disabling
10236ab6bfe3SJack F Vogel  *  the de-assertion of the clock request when in 1Gpbs mode.
10247609433eSJack F Vogel  *  Also, set appropriate Tx re-transmission timeouts for 10 and 100Half link
10257609433eSJack F Vogel  *  speeds in order to avoid Tx hangs.
10266ab6bfe3SJack F Vogel  **/
10276ab6bfe3SJack F Vogel static s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link)
10286ab6bfe3SJack F Vogel {
10296ab6bfe3SJack F Vogel 	u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6);
10307609433eSJack F Vogel 	u32 status = E1000_READ_REG(hw, E1000_STATUS);
10316ab6bfe3SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
10327609433eSJack F Vogel 	u16 reg;
10336ab6bfe3SJack F Vogel 
10347609433eSJack F Vogel 	if (link && (status & E1000_STATUS_SPEED_1000)) {
10356ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
10366ab6bfe3SJack F Vogel 		if (ret_val)
10376ab6bfe3SJack F Vogel 			return ret_val;
10386ab6bfe3SJack F Vogel 
10396ab6bfe3SJack F Vogel 		ret_val =
10406ab6bfe3SJack F Vogel 		    e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
10417609433eSJack F Vogel 					       &reg);
10426ab6bfe3SJack F Vogel 		if (ret_val)
10436ab6bfe3SJack F Vogel 			goto release;
10446ab6bfe3SJack F Vogel 
10456ab6bfe3SJack F Vogel 		ret_val =
10466ab6bfe3SJack F Vogel 		    e1000_write_kmrn_reg_locked(hw,
10476ab6bfe3SJack F Vogel 						E1000_KMRNCTRLSTA_K1_CONFIG,
10487609433eSJack F Vogel 						reg &
10496ab6bfe3SJack F Vogel 						~E1000_KMRNCTRLSTA_K1_ENABLE);
10506ab6bfe3SJack F Vogel 		if (ret_val)
10516ab6bfe3SJack F Vogel 			goto release;
10526ab6bfe3SJack F Vogel 
10536ab6bfe3SJack F Vogel 		usec_delay(10);
10546ab6bfe3SJack F Vogel 
10556ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_FEXTNVM6,
10566ab6bfe3SJack F Vogel 				fextnvm6 | E1000_FEXTNVM6_REQ_PLL_CLK);
10576ab6bfe3SJack F Vogel 
10586ab6bfe3SJack F Vogel 		ret_val =
10596ab6bfe3SJack F Vogel 		    e1000_write_kmrn_reg_locked(hw,
10606ab6bfe3SJack F Vogel 						E1000_KMRNCTRLSTA_K1_CONFIG,
10617609433eSJack F Vogel 						reg);
10626ab6bfe3SJack F Vogel release:
10636ab6bfe3SJack F Vogel 		hw->phy.ops.release(hw);
10646ab6bfe3SJack F Vogel 	} else {
10656ab6bfe3SJack F Vogel 		/* clear FEXTNVM6 bit 8 on link down or 10/100 */
10667609433eSJack F Vogel 		fextnvm6 &= ~E1000_FEXTNVM6_REQ_PLL_CLK;
10677609433eSJack F Vogel 
1068c80429ceSEric Joyner 		if ((hw->phy.revision > 5) || !link ||
1069c80429ceSEric Joyner 		    ((status & E1000_STATUS_SPEED_100) &&
10707609433eSJack F Vogel 		     (status & E1000_STATUS_FD)))
10717609433eSJack F Vogel 			goto update_fextnvm6;
10727609433eSJack F Vogel 
10737609433eSJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, I217_INBAND_CTRL, &reg);
10747609433eSJack F Vogel 		if (ret_val)
10757609433eSJack F Vogel 			return ret_val;
10767609433eSJack F Vogel 
10777609433eSJack F Vogel 		/* Clear link status transmit timeout */
10787609433eSJack F Vogel 		reg &= ~I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_MASK;
10797609433eSJack F Vogel 
10807609433eSJack F Vogel 		if (status & E1000_STATUS_SPEED_100) {
10817609433eSJack F Vogel 			/* Set inband Tx timeout to 5x10us for 100Half */
10827609433eSJack F Vogel 			reg |= 5 << I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT;
10837609433eSJack F Vogel 
10847609433eSJack F Vogel 			/* Do not extend the K1 entry latency for 100Half */
10857609433eSJack F Vogel 			fextnvm6 &= ~E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION;
10867609433eSJack F Vogel 		} else {
10877609433eSJack F Vogel 			/* Set inband Tx timeout to 50x10us for 10Full/Half */
10887609433eSJack F Vogel 			reg |= 50 <<
10897609433eSJack F Vogel 			       I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT;
10907609433eSJack F Vogel 
10917609433eSJack F Vogel 			/* Extend the K1 entry latency for 10 Mbps */
10927609433eSJack F Vogel 			fextnvm6 |= E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION;
10937609433eSJack F Vogel 		}
10947609433eSJack F Vogel 
10957609433eSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, I217_INBAND_CTRL, reg);
10967609433eSJack F Vogel 		if (ret_val)
10977609433eSJack F Vogel 			return ret_val;
10987609433eSJack F Vogel 
10997609433eSJack F Vogel update_fextnvm6:
11007609433eSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FEXTNVM6, fextnvm6);
11016ab6bfe3SJack F Vogel 	}
11026ab6bfe3SJack F Vogel 
11036ab6bfe3SJack F Vogel 	return ret_val;
11046ab6bfe3SJack F Vogel }
11056ab6bfe3SJack F Vogel 
1106e373323fSSean Bruno static u64 e1000_ltr2ns(u16 ltr)
1107e373323fSSean Bruno {
1108e373323fSSean Bruno 	u32 value, scale;
1109e373323fSSean Bruno 
1110e373323fSSean Bruno 	/* Determine the latency in nsec based on the LTR value & scale */
1111e373323fSSean Bruno 	value = ltr & E1000_LTRV_VALUE_MASK;
1112e373323fSSean Bruno 	scale = (ltr & E1000_LTRV_SCALE_MASK) >> E1000_LTRV_SCALE_SHIFT;
1113e373323fSSean Bruno 
111451569bd7SEric Joyner 	return value * (1ULL << (scale * E1000_LTRV_SCALE_FACTOR));
1115e373323fSSean Bruno }
1116e373323fSSean Bruno 
1117e373323fSSean Bruno /**
1118e373323fSSean Bruno  *  e1000_platform_pm_pch_lpt - Set platform power management values
1119e373323fSSean Bruno  *  @hw: pointer to the HW structure
1120e373323fSSean Bruno  *  @link: bool indicating link status
1121e373323fSSean Bruno  *
1122e373323fSSean Bruno  *  Set the Latency Tolerance Reporting (LTR) values for the "PCIe-like"
1123e373323fSSean Bruno  *  GbE MAC in the Lynx Point PCH based on Rx buffer size and link speed
1124e373323fSSean Bruno  *  when link is up (which must not exceed the maximum latency supported
1125e373323fSSean Bruno  *  by the platform), otherwise specify there is no LTR requirement.
1126e373323fSSean Bruno  *  Unlike TRUE-PCIe devices which set the LTR maximum snoop/no-snoop
1127e373323fSSean Bruno  *  latencies in the LTR Extended Capability Structure in the PCIe Extended
1128e373323fSSean Bruno  *  Capability register set, on this device LTR is set by writing the
1129e373323fSSean Bruno  *  equivalent snoop/no-snoop latencies in the LTRV register in the MAC and
1130e373323fSSean Bruno  *  set the SEND bit to send an Intel On-chip System Fabric sideband (IOSF-SB)
1131e373323fSSean Bruno  *  message to the PMC.
1132e373323fSSean Bruno  *
1133e373323fSSean Bruno  *  Use the LTR value to calculate the Optimized Buffer Flush/Fill (OBFF)
1134e373323fSSean Bruno  *  high-water mark.
1135e373323fSSean Bruno  **/
1136e373323fSSean Bruno static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link)
1137e373323fSSean Bruno {
1138e373323fSSean Bruno 	u32 reg = link << (E1000_LTRV_REQ_SHIFT + E1000_LTRV_NOSNOOP_SHIFT) |
1139e373323fSSean Bruno 		  link << E1000_LTRV_REQ_SHIFT | E1000_LTRV_SEND;
1140e373323fSSean Bruno 	u16 lat_enc = 0;	/* latency encoded */
1141e373323fSSean Bruno 	s32 obff_hwm = 0;
1142e373323fSSean Bruno 
1143e373323fSSean Bruno 	DEBUGFUNC("e1000_platform_pm_pch_lpt");
1144e373323fSSean Bruno 
1145e373323fSSean Bruno 	if (link) {
1146e373323fSSean Bruno 		u16 speed, duplex, scale = 0;
1147e373323fSSean Bruno 		u16 max_snoop, max_nosnoop;
1148e373323fSSean Bruno 		u16 max_ltr_enc;	/* max LTR latency encoded */
1149e373323fSSean Bruno 		s64 lat_ns;
1150e373323fSSean Bruno 		s64 value;
1151e373323fSSean Bruno 		u32 rxa;
1152e373323fSSean Bruno 
1153e373323fSSean Bruno 		if (!hw->mac.max_frame_size) {
1154e373323fSSean Bruno 			DEBUGOUT("max_frame_size not set.\n");
1155e373323fSSean Bruno 			return -E1000_ERR_CONFIG;
1156e373323fSSean Bruno 		}
1157e373323fSSean Bruno 
1158e373323fSSean Bruno 		hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
1159e373323fSSean Bruno 		if (!speed) {
1160e373323fSSean Bruno 			DEBUGOUT("Speed not set.\n");
1161e373323fSSean Bruno 			return -E1000_ERR_CONFIG;
1162e373323fSSean Bruno 		}
1163e373323fSSean Bruno 
1164e373323fSSean Bruno 		/* Rx Packet Buffer Allocation size (KB) */
1165e373323fSSean Bruno 		rxa = E1000_READ_REG(hw, E1000_PBA) & E1000_PBA_RXA_MASK;
1166e373323fSSean Bruno 
1167e373323fSSean Bruno 		/* Determine the maximum latency tolerated by the device.
1168e373323fSSean Bruno 		 *
1169e373323fSSean Bruno 		 * Per the PCIe spec, the tolerated latencies are encoded as
1170e373323fSSean Bruno 		 * a 3-bit encoded scale (only 0-5 are valid) multiplied by
1171e373323fSSean Bruno 		 * a 10-bit value (0-1023) to provide a range from 1 ns to
1172e373323fSSean Bruno 		 * 2^25*(2^10-1) ns.  The scale is encoded as 0=2^0ns,
1173e373323fSSean Bruno 		 * 1=2^5ns, 2=2^10ns,...5=2^25ns.
1174e373323fSSean Bruno 		 */
1175e373323fSSean Bruno 		lat_ns = ((s64)rxa * 1024 -
1176e373323fSSean Bruno 			  (2 * (s64)hw->mac.max_frame_size)) * 8 * 1000;
1177e373323fSSean Bruno 		if (lat_ns < 0)
1178e373323fSSean Bruno 			lat_ns = 0;
1179e373323fSSean Bruno 		else
1180e373323fSSean Bruno 			lat_ns /= speed;
1181e373323fSSean Bruno 		value = lat_ns;
1182e373323fSSean Bruno 
1183e373323fSSean Bruno 		while (value > E1000_LTRV_VALUE_MASK) {
1184e373323fSSean Bruno 			scale++;
1185e373323fSSean Bruno 			value = E1000_DIVIDE_ROUND_UP(value, (1 << 5));
1186e373323fSSean Bruno 		}
1187e373323fSSean Bruno 		if (scale > E1000_LTRV_SCALE_MAX) {
1188e373323fSSean Bruno 			DEBUGOUT1("Invalid LTR latency scale %d\n", scale);
1189e373323fSSean Bruno 			return -E1000_ERR_CONFIG;
1190e373323fSSean Bruno 		}
1191e373323fSSean Bruno 		lat_enc = (u16)((scale << E1000_LTRV_SCALE_SHIFT) | value);
1192e373323fSSean Bruno 
1193e373323fSSean Bruno 		/* Determine the maximum latency tolerated by the platform */
1194e373323fSSean Bruno 		e1000_read_pci_cfg(hw, E1000_PCI_LTR_CAP_LPT, &max_snoop);
1195e373323fSSean Bruno 		e1000_read_pci_cfg(hw, E1000_PCI_LTR_CAP_LPT + 2, &max_nosnoop);
1196e373323fSSean Bruno 		max_ltr_enc = E1000_MAX(max_snoop, max_nosnoop);
1197e373323fSSean Bruno 
1198e373323fSSean Bruno 		if (lat_enc > max_ltr_enc) {
1199e373323fSSean Bruno 			lat_enc = max_ltr_enc;
1200e373323fSSean Bruno 			lat_ns = e1000_ltr2ns(max_ltr_enc);
1201e373323fSSean Bruno 		}
1202e373323fSSean Bruno 
1203e373323fSSean Bruno 		if (lat_ns) {
1204e373323fSSean Bruno 			lat_ns *= speed * 1000;
1205e373323fSSean Bruno 			lat_ns /= 8;
1206e373323fSSean Bruno 			lat_ns /= 1000000000;
1207e373323fSSean Bruno 			obff_hwm = (s32)(rxa - lat_ns);
1208e373323fSSean Bruno 		}
1209e373323fSSean Bruno 		if ((obff_hwm < 0) || (obff_hwm > E1000_SVT_OFF_HWM_MASK)) {
1210e373323fSSean Bruno 			DEBUGOUT1("Invalid high water mark %d\n", obff_hwm);
1211e373323fSSean Bruno 			return -E1000_ERR_CONFIG;
1212e373323fSSean Bruno 		}
1213e373323fSSean Bruno 	}
1214e373323fSSean Bruno 
1215e373323fSSean Bruno 	/* Set Snoop and No-Snoop latencies the same */
1216e373323fSSean Bruno 	reg |= lat_enc | (lat_enc << E1000_LTRV_NOSNOOP_SHIFT);
1217e373323fSSean Bruno 	E1000_WRITE_REG(hw, E1000_LTRV, reg);
1218e373323fSSean Bruno 
1219e373323fSSean Bruno 	/* Set OBFF high water mark */
1220e373323fSSean Bruno 	reg = E1000_READ_REG(hw, E1000_SVT) & ~E1000_SVT_OFF_HWM_MASK;
1221e373323fSSean Bruno 	reg |= obff_hwm;
1222e373323fSSean Bruno 	E1000_WRITE_REG(hw, E1000_SVT, reg);
1223e373323fSSean Bruno 
1224e373323fSSean Bruno 	/* Enable OBFF */
1225e373323fSSean Bruno 	reg = E1000_READ_REG(hw, E1000_SVCR);
1226e373323fSSean Bruno 	reg |= E1000_SVCR_OFF_EN;
1227e373323fSSean Bruno 	/* Always unblock interrupts to the CPU even when the system is
1228e373323fSSean Bruno 	 * in OBFF mode. This ensures that small round-robin traffic
1229e373323fSSean Bruno 	 * (like ping) does not get dropped or experience long latency.
1230e373323fSSean Bruno 	 */
1231e373323fSSean Bruno 	reg |= E1000_SVCR_OFF_MASKINT;
1232e373323fSSean Bruno 	E1000_WRITE_REG(hw, E1000_SVCR, reg);
1233e373323fSSean Bruno 
1234e373323fSSean Bruno 	return E1000_SUCCESS;
1235e373323fSSean Bruno }
1236e373323fSSean Bruno 
1237e373323fSSean Bruno /**
1238e373323fSSean Bruno  *  e1000_set_obff_timer_pch_lpt - Update Optimized Buffer Flush/Fill timer
1239e373323fSSean Bruno  *  @hw: pointer to the HW structure
1240e373323fSSean Bruno  *  @itr: interrupt throttling rate
1241e373323fSSean Bruno  *
1242e373323fSSean Bruno  *  Configure OBFF with the updated interrupt rate.
1243e373323fSSean Bruno  **/
1244e373323fSSean Bruno static s32 e1000_set_obff_timer_pch_lpt(struct e1000_hw *hw, u32 itr)
1245e373323fSSean Bruno {
1246e373323fSSean Bruno 	u32 svcr;
1247e373323fSSean Bruno 	s32 timer;
1248e373323fSSean Bruno 
1249e373323fSSean Bruno 	DEBUGFUNC("e1000_set_obff_timer_pch_lpt");
1250e373323fSSean Bruno 
1251e373323fSSean Bruno 	/* Convert ITR value into microseconds for OBFF timer */
1252e373323fSSean Bruno 	timer = itr & E1000_ITR_MASK;
1253e373323fSSean Bruno 	timer = (timer * E1000_ITR_MULT) / 1000;
1254e373323fSSean Bruno 
1255e373323fSSean Bruno 	if ((timer < 0) || (timer > E1000_ITR_MASK)) {
1256e373323fSSean Bruno 		DEBUGOUT1("Invalid OBFF timer %d\n", timer);
1257e373323fSSean Bruno 		return -E1000_ERR_CONFIG;
1258e373323fSSean Bruno 	}
1259e373323fSSean Bruno 
1260e373323fSSean Bruno 	svcr = E1000_READ_REG(hw, E1000_SVCR);
1261e373323fSSean Bruno 	svcr &= ~E1000_SVCR_OFF_TIMER_MASK;
1262e373323fSSean Bruno 	svcr |= timer << E1000_SVCR_OFF_TIMER_SHIFT;
1263e373323fSSean Bruno 	E1000_WRITE_REG(hw, E1000_SVCR, svcr);
1264e373323fSSean Bruno 
1265e373323fSSean Bruno 	return E1000_SUCCESS;
1266e373323fSSean Bruno }
1267e373323fSSean Bruno 
12687d9119bdSJack F Vogel /**
12698cc64f1eSJack F Vogel  *  e1000_enable_ulp_lpt_lp - configure Ultra Low Power mode for LynxPoint-LP
12708cc64f1eSJack F Vogel  *  @hw: pointer to the HW structure
12718cc64f1eSJack F Vogel  *  @to_sx: boolean indicating a system power state transition to Sx
12728cc64f1eSJack F Vogel  *
12738cc64f1eSJack F Vogel  *  When link is down, configure ULP mode to significantly reduce the power
12748cc64f1eSJack F Vogel  *  to the PHY.  If on a Manageability Engine (ME) enabled system, tell the
12758cc64f1eSJack F Vogel  *  ME firmware to start the ULP configuration.  If not on an ME enabled
12768cc64f1eSJack F Vogel  *  system, configure the ULP mode by software.
12778cc64f1eSJack F Vogel  */
12788cc64f1eSJack F Vogel s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
12798cc64f1eSJack F Vogel {
12808cc64f1eSJack F Vogel 	u32 mac_reg;
12818cc64f1eSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
12828cc64f1eSJack F Vogel 	u16 phy_reg;
1283c80429ceSEric Joyner 	u16 oem_reg = 0;
12848cc64f1eSJack F Vogel 
12858cc64f1eSJack F Vogel 	if ((hw->mac.type < e1000_pch_lpt) ||
12868cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) ||
12878cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V) ||
12888cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_LM2) ||
12898cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_V2) ||
12908cc64f1eSJack F Vogel 	    (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_on))
12918cc64f1eSJack F Vogel 		return 0;
12928cc64f1eSJack F Vogel 
12938cc64f1eSJack F Vogel 	if (!to_sx) {
12948cc64f1eSJack F Vogel 		int i = 0;
12958cc64f1eSJack F Vogel 		/* Poll up to 5 seconds for Cable Disconnected indication */
12968cc64f1eSJack F Vogel 		while (!(E1000_READ_REG(hw, E1000_FEXT) &
12978cc64f1eSJack F Vogel 			 E1000_FEXT_PHY_CABLE_DISCONNECTED)) {
12988cc64f1eSJack F Vogel 			/* Bail if link is re-acquired */
12998cc64f1eSJack F Vogel 			if (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)
13008cc64f1eSJack F Vogel 				return -E1000_ERR_PHY;
13018cc64f1eSJack F Vogel 			if (i++ == 100)
13028cc64f1eSJack F Vogel 				break;
13038cc64f1eSJack F Vogel 
13048cc64f1eSJack F Vogel 			msec_delay(50);
13058cc64f1eSJack F Vogel 		}
13068cc64f1eSJack F Vogel 		DEBUGOUT2("CABLE_DISCONNECTED %s set after %dmsec\n",
13078cc64f1eSJack F Vogel 			  (E1000_READ_REG(hw, E1000_FEXT) &
13088cc64f1eSJack F Vogel 			   E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not",
13098cc64f1eSJack F Vogel 			  i * 50);
1310*fc7682b1SKevin Bowling 		if (!(E1000_READ_REG(hw, E1000_FEXT) &
1311*fc7682b1SKevin Bowling 		    E1000_FEXT_PHY_CABLE_DISCONNECTED))
1312*fc7682b1SKevin Bowling 			return 0;
1313*fc7682b1SKevin Bowling 	}
1314*fc7682b1SKevin Bowling 
1315*fc7682b1SKevin Bowling 	if (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID) {
1316*fc7682b1SKevin Bowling 		/* Request ME configure ULP mode in the PHY */
1317*fc7682b1SKevin Bowling 		mac_reg = E1000_READ_REG(hw, E1000_H2ME);
1318*fc7682b1SKevin Bowling 		mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS;
1319*fc7682b1SKevin Bowling 		E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
1320*fc7682b1SKevin Bowling 
1321*fc7682b1SKevin Bowling 		goto out;
13228cc64f1eSJack F Vogel 	}
13238cc64f1eSJack F Vogel 
13248cc64f1eSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
13258cc64f1eSJack F Vogel 	if (ret_val)
13268cc64f1eSJack F Vogel 		goto out;
13278cc64f1eSJack F Vogel 
1328*fc7682b1SKevin Bowling 	/* During S0 Idle keep the phy in PCI-E mode */
1329*fc7682b1SKevin Bowling 	if (hw->dev_spec.ich8lan.smbus_disable)
1330*fc7682b1SKevin Bowling 		goto skip_smbus;
1331*fc7682b1SKevin Bowling 
13328cc64f1eSJack F Vogel 	/* Force SMBus mode in PHY */
13338cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
13348cc64f1eSJack F Vogel 	if (ret_val)
13358cc64f1eSJack F Vogel 		goto release;
13368cc64f1eSJack F Vogel 	phy_reg |= CV_SMB_CTRL_FORCE_SMBUS;
13378cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
13388cc64f1eSJack F Vogel 
13398cc64f1eSJack F Vogel 	/* Force SMBus mode in MAC */
13408cc64f1eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
13418cc64f1eSJack F Vogel 	mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
13428cc64f1eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
13438cc64f1eSJack F Vogel 
1344*fc7682b1SKevin Bowling 	/* Si workaround for ULP entry flow on i217/rev6 h/w.  Enable
1345c80429ceSEric Joyner 	 * LPLU and disable Gig speed when entering ULP
1346c80429ceSEric Joyner 	 */
1347c80429ceSEric Joyner 	if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6)) {
1348c80429ceSEric Joyner 		ret_val = e1000_read_phy_reg_hv_locked(hw, HV_OEM_BITS,
1349c80429ceSEric Joyner 						       &oem_reg);
1350c80429ceSEric Joyner 		if (ret_val)
1351c80429ceSEric Joyner 			goto release;
1352c80429ceSEric Joyner 
1353c80429ceSEric Joyner 		phy_reg = oem_reg;
1354c80429ceSEric Joyner 		phy_reg |= HV_OEM_BITS_LPLU | HV_OEM_BITS_GBE_DIS;
1355c80429ceSEric Joyner 
1356c80429ceSEric Joyner 		ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS,
1357c80429ceSEric Joyner 							phy_reg);
1358c80429ceSEric Joyner 
1359c80429ceSEric Joyner 		if (ret_val)
1360c80429ceSEric Joyner 			goto release;
1361c80429ceSEric Joyner 	}
1362c80429ceSEric Joyner 
1363*fc7682b1SKevin Bowling skip_smbus:
1364*fc7682b1SKevin Bowling 	if (!to_sx) {
1365*fc7682b1SKevin Bowling 		/* Change the 'Link Status Change' interrupt to trigger
1366*fc7682b1SKevin Bowling 		 * on 'Cable Status Change'
1367*fc7682b1SKevin Bowling 		 */
1368*fc7682b1SKevin Bowling 		ret_val = e1000_read_kmrn_reg_locked(hw,
1369*fc7682b1SKevin Bowling 						     E1000_KMRNCTRLSTA_OP_MODES,
1370*fc7682b1SKevin Bowling 						     &phy_reg);
1371*fc7682b1SKevin Bowling 		if (ret_val)
1372*fc7682b1SKevin Bowling 			goto release;
1373*fc7682b1SKevin Bowling 		phy_reg |= E1000_KMRNCTRLSTA_OP_MODES_LSC2CSC;
1374*fc7682b1SKevin Bowling 		e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_OP_MODES,
1375*fc7682b1SKevin Bowling 					    phy_reg);
1376*fc7682b1SKevin Bowling 	}
1377*fc7682b1SKevin Bowling 
13788cc64f1eSJack F Vogel 	/* Set Inband ULP Exit, Reset to SMBus mode and
13798cc64f1eSJack F Vogel 	 * Disable SMBus Release on PERST# in PHY
13808cc64f1eSJack F Vogel 	 */
13818cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
13828cc64f1eSJack F Vogel 	if (ret_val)
13838cc64f1eSJack F Vogel 		goto release;
13848cc64f1eSJack F Vogel 	phy_reg |= (I218_ULP_CONFIG1_RESET_TO_SMBUS |
13858cc64f1eSJack F Vogel 		    I218_ULP_CONFIG1_DISABLE_SMB_PERST);
13868cc64f1eSJack F Vogel 	if (to_sx) {
13878cc64f1eSJack F Vogel 		if (E1000_READ_REG(hw, E1000_WUFC) & E1000_WUFC_LNKC)
13888cc64f1eSJack F Vogel 			phy_reg |= I218_ULP_CONFIG1_WOL_HOST;
1389c80429ceSEric Joyner 		else
1390c80429ceSEric Joyner 			phy_reg &= ~I218_ULP_CONFIG1_WOL_HOST;
13918cc64f1eSJack F Vogel 
13928cc64f1eSJack F Vogel 		phy_reg |= I218_ULP_CONFIG1_STICKY_ULP;
1393c80429ceSEric Joyner 		phy_reg &= ~I218_ULP_CONFIG1_INBAND_EXIT;
13948cc64f1eSJack F Vogel 	} else {
13958cc64f1eSJack F Vogel 		phy_reg |= I218_ULP_CONFIG1_INBAND_EXIT;
1396c80429ceSEric Joyner 		phy_reg &= ~I218_ULP_CONFIG1_STICKY_ULP;
1397c80429ceSEric Joyner 		phy_reg &= ~I218_ULP_CONFIG1_WOL_HOST;
13988cc64f1eSJack F Vogel 	}
13998cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
14008cc64f1eSJack F Vogel 
14018cc64f1eSJack F Vogel 	/* Set Disable SMBus Release on PERST# in MAC */
14028cc64f1eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM7);
14038cc64f1eSJack F Vogel 	mac_reg |= E1000_FEXTNVM7_DISABLE_SMB_PERST;
14048cc64f1eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_FEXTNVM7, mac_reg);
14058cc64f1eSJack F Vogel 
14068cc64f1eSJack F Vogel 	/* Commit ULP changes in PHY by starting auto ULP configuration */
14078cc64f1eSJack F Vogel 	phy_reg |= I218_ULP_CONFIG1_START;
14088cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
1409c80429ceSEric Joyner 
1410*fc7682b1SKevin Bowling 	if (!to_sx) {
1411*fc7682b1SKevin Bowling 		/* Disable Tx so that the MAC doesn't send any (buffered)
1412*fc7682b1SKevin Bowling 		 * packets to the PHY.
1413*fc7682b1SKevin Bowling 		 */
1414*fc7682b1SKevin Bowling 		mac_reg = E1000_READ_REG(hw, E1000_TCTL);
1415*fc7682b1SKevin Bowling 		mac_reg &= ~E1000_TCTL_EN;
1416*fc7682b1SKevin Bowling 		E1000_WRITE_REG(hw, E1000_TCTL, mac_reg);
1417*fc7682b1SKevin Bowling 	}
1418*fc7682b1SKevin Bowling 
1419c80429ceSEric Joyner 	if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6) &&
1420c80429ceSEric Joyner 	    to_sx && (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
1421c80429ceSEric Joyner 		ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS,
1422c80429ceSEric Joyner 							oem_reg);
1423c80429ceSEric Joyner 		if (ret_val)
1424c80429ceSEric Joyner 			goto release;
1425c80429ceSEric Joyner 	}
1426c80429ceSEric Joyner 
14278cc64f1eSJack F Vogel release:
14288cc64f1eSJack F Vogel 	hw->phy.ops.release(hw);
14298cc64f1eSJack F Vogel out:
14308cc64f1eSJack F Vogel 	if (ret_val)
14318cc64f1eSJack F Vogel 		DEBUGOUT1("Error in ULP enable flow: %d\n", ret_val);
14328cc64f1eSJack F Vogel 	else
14338cc64f1eSJack F Vogel 		hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_on;
14348cc64f1eSJack F Vogel 
14358cc64f1eSJack F Vogel 	return ret_val;
14368cc64f1eSJack F Vogel }
14378cc64f1eSJack F Vogel 
14388cc64f1eSJack F Vogel /**
14398cc64f1eSJack F Vogel  *  e1000_disable_ulp_lpt_lp - unconfigure Ultra Low Power mode for LynxPoint-LP
14408cc64f1eSJack F Vogel  *  @hw: pointer to the HW structure
14418cc64f1eSJack F Vogel  *  @force: boolean indicating whether or not to force disabling ULP
14428cc64f1eSJack F Vogel  *
14438cc64f1eSJack F Vogel  *  Un-configure ULP mode when link is up, the system is transitioned from
14448cc64f1eSJack F Vogel  *  Sx or the driver is unloaded.  If on a Manageability Engine (ME) enabled
14458cc64f1eSJack F Vogel  *  system, poll for an indication from ME that ULP has been un-configured.
14468cc64f1eSJack F Vogel  *  If not on an ME enabled system, un-configure the ULP mode by software.
14478cc64f1eSJack F Vogel  *
14488cc64f1eSJack F Vogel  *  During nominal operation, this function is called when link is acquired
14498cc64f1eSJack F Vogel  *  to disable ULP mode (force=FALSE); otherwise, for example when unloading
14508cc64f1eSJack F Vogel  *  the driver or during Sx->S0 transitions, this is called with force=TRUE
14518cc64f1eSJack F Vogel  *  to forcibly disable ULP.
1452*fc7682b1SKevin Bowling 
1453*fc7682b1SKevin Bowling  *  When the cable is plugged in while the device is in D0, a Cable Status
1454*fc7682b1SKevin Bowling  *  Change interrupt is generated which causes this function to be called
1455*fc7682b1SKevin Bowling  *  to partially disable ULP mode and restart autonegotiation.  This function
1456*fc7682b1SKevin Bowling  *  is then called again due to the resulting Link Status Change interrupt
1457*fc7682b1SKevin Bowling  *  to finish cleaning up after the ULP flow.
14588cc64f1eSJack F Vogel  */
14598cc64f1eSJack F Vogel s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
14608cc64f1eSJack F Vogel {
14618cc64f1eSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
1462*fc7682b1SKevin Bowling 	u8 ulp_exit_timeout = 30;
14638cc64f1eSJack F Vogel 	u32 mac_reg;
14648cc64f1eSJack F Vogel 	u16 phy_reg;
14658cc64f1eSJack F Vogel 	int i = 0;
14668cc64f1eSJack F Vogel 
14678cc64f1eSJack F Vogel 	if ((hw->mac.type < e1000_pch_lpt) ||
14688cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) ||
14698cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V) ||
14708cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_LM2) ||
14718cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_V2) ||
14728cc64f1eSJack F Vogel 	    (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_off))
14738cc64f1eSJack F Vogel 		return 0;
14748cc64f1eSJack F Vogel 
14758cc64f1eSJack F Vogel 	if (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID) {
14768cc64f1eSJack F Vogel 		if (force) {
14778cc64f1eSJack F Vogel 			/* Request ME un-configure ULP mode in the PHY */
14788cc64f1eSJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_H2ME);
14798cc64f1eSJack F Vogel 			mac_reg &= ~E1000_H2ME_ULP;
14808cc64f1eSJack F Vogel 			mac_reg |= E1000_H2ME_ENFORCE_SETTINGS;
14818cc64f1eSJack F Vogel 			E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
14828cc64f1eSJack F Vogel 		}
14838cc64f1eSJack F Vogel 
1484*fc7682b1SKevin Bowling 		if (hw->mac.type == e1000_pch_cnp)
1485*fc7682b1SKevin Bowling 			ulp_exit_timeout = 100;
1486*fc7682b1SKevin Bowling 
14878cc64f1eSJack F Vogel 		while (E1000_READ_REG(hw, E1000_FWSM) &
14888cc64f1eSJack F Vogel 		       E1000_FWSM_ULP_CFG_DONE) {
1489*fc7682b1SKevin Bowling 			if (i++ == ulp_exit_timeout) {
14908cc64f1eSJack F Vogel 				ret_val = -E1000_ERR_PHY;
14918cc64f1eSJack F Vogel 				goto out;
14928cc64f1eSJack F Vogel 			}
14938cc64f1eSJack F Vogel 
14948cc64f1eSJack F Vogel 			msec_delay(10);
14958cc64f1eSJack F Vogel 		}
14968cc64f1eSJack F Vogel 		DEBUGOUT1("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10);
14978cc64f1eSJack F Vogel 
14988cc64f1eSJack F Vogel 		if (force) {
14998cc64f1eSJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_H2ME);
15008cc64f1eSJack F Vogel 			mac_reg &= ~E1000_H2ME_ENFORCE_SETTINGS;
15018cc64f1eSJack F Vogel 			E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
15028cc64f1eSJack F Vogel 		} else {
15038cc64f1eSJack F Vogel 			/* Clear H2ME.ULP after ME ULP configuration */
15048cc64f1eSJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_H2ME);
15058cc64f1eSJack F Vogel 			mac_reg &= ~E1000_H2ME_ULP;
15068cc64f1eSJack F Vogel 			E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
1507*fc7682b1SKevin Bowling 
1508*fc7682b1SKevin Bowling 			/* Restore link speed advertisements and restart
1509*fc7682b1SKevin Bowling 			 * Auto-negotiation
1510*fc7682b1SKevin Bowling 			 */
1511*fc7682b1SKevin Bowling 			if (hw->mac.autoneg) {
1512*fc7682b1SKevin Bowling 				ret_val = e1000_phy_setup_autoneg(hw);
1513*fc7682b1SKevin Bowling 				if (ret_val)
1514*fc7682b1SKevin Bowling 					goto out;
1515*fc7682b1SKevin Bowling 			} else {
1516*fc7682b1SKevin Bowling 				ret_val = e1000_setup_copper_link_generic(hw);
1517*fc7682b1SKevin Bowling 				if (ret_val)
1518*fc7682b1SKevin Bowling 					goto out;
1519*fc7682b1SKevin Bowling 			}
1520*fc7682b1SKevin Bowling 			ret_val = e1000_oem_bits_config_ich8lan(hw, true);
15218cc64f1eSJack F Vogel 		}
15228cc64f1eSJack F Vogel 
15238cc64f1eSJack F Vogel 		goto out;
15248cc64f1eSJack F Vogel 	}
15258cc64f1eSJack F Vogel 
15268cc64f1eSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
15278cc64f1eSJack F Vogel 	if (ret_val)
15288cc64f1eSJack F Vogel 		goto out;
15298cc64f1eSJack F Vogel 
1530*fc7682b1SKevin Bowling 	/* Revert the change to the 'Link Status Change'
1531*fc7682b1SKevin Bowling 	 * interrupt to trigger on 'Cable Status Change'
1532*fc7682b1SKevin Bowling 	 */
1533*fc7682b1SKevin Bowling 	ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_OP_MODES,
1534*fc7682b1SKevin Bowling 					     &phy_reg);
1535*fc7682b1SKevin Bowling 	if (ret_val)
1536*fc7682b1SKevin Bowling 		goto release;
1537*fc7682b1SKevin Bowling 	phy_reg &= ~E1000_KMRNCTRLSTA_OP_MODES_LSC2CSC;
1538*fc7682b1SKevin Bowling 	e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_OP_MODES, phy_reg);
1539*fc7682b1SKevin Bowling 
15408cc64f1eSJack F Vogel 	if (force)
15418cc64f1eSJack F Vogel 		/* Toggle LANPHYPC Value bit */
15428cc64f1eSJack F Vogel 		e1000_toggle_lanphypc_pch_lpt(hw);
15438cc64f1eSJack F Vogel 
15448cc64f1eSJack F Vogel 	/* Unforce SMBus mode in PHY */
15458cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
15468cc64f1eSJack F Vogel 	if (ret_val) {
15478cc64f1eSJack F Vogel 		/* The MAC might be in PCIe mode, so temporarily force to
15488cc64f1eSJack F Vogel 		 * SMBus mode in order to access the PHY.
15498cc64f1eSJack F Vogel 		 */
15508cc64f1eSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
15518cc64f1eSJack F Vogel 		mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
15528cc64f1eSJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
15538cc64f1eSJack F Vogel 
15548cc64f1eSJack F Vogel 		msec_delay(50);
15558cc64f1eSJack F Vogel 
15568cc64f1eSJack F Vogel 		ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL,
15578cc64f1eSJack F Vogel 						       &phy_reg);
15588cc64f1eSJack F Vogel 		if (ret_val)
15598cc64f1eSJack F Vogel 			goto release;
15608cc64f1eSJack F Vogel 	}
15618cc64f1eSJack F Vogel 	phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
15628cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
15638cc64f1eSJack F Vogel 
15648cc64f1eSJack F Vogel 	/* Unforce SMBus mode in MAC */
15658cc64f1eSJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
15668cc64f1eSJack F Vogel 	mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
15678cc64f1eSJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
15688cc64f1eSJack F Vogel 
15698cc64f1eSJack F Vogel 	/* When ULP mode was previously entered, K1 was disabled by the
15708cc64f1eSJack F Vogel 	 * hardware.  Re-Enable K1 in the PHY when exiting ULP.
15718cc64f1eSJack F Vogel 	 */
15728cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, HV_PM_CTRL, &phy_reg);
15738cc64f1eSJack F Vogel 	if (ret_val)
15748cc64f1eSJack F Vogel 		goto release;
15758cc64f1eSJack F Vogel 	phy_reg |= HV_PM_CTRL_K1_ENABLE;
15768cc64f1eSJack F Vogel 	e1000_write_phy_reg_hv_locked(hw, HV_PM_CTRL, phy_reg);
15778cc64f1eSJack F Vogel 
15788cc64f1eSJack F Vogel 	/* Clear ULP enabled configuration */
15798cc64f1eSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
15808cc64f1eSJack F Vogel 	if (ret_val)
15818cc64f1eSJack F Vogel 		goto release;
1582*fc7682b1SKevin Bowling 	/* CSC interrupt received due to ULP Indication */
1583*fc7682b1SKevin Bowling 	if ((phy_reg & I218_ULP_CONFIG1_IND) || force) {
15848cc64f1eSJack F Vogel 		phy_reg &= ~(I218_ULP_CONFIG1_IND |
15858cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_STICKY_ULP |
15868cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_RESET_TO_SMBUS |
15878cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_WOL_HOST |
15888cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_INBAND_EXIT |
1589c80429ceSEric Joyner 			     I218_ULP_CONFIG1_EN_ULP_LANPHYPC |
1590c80429ceSEric Joyner 			     I218_ULP_CONFIG1_DIS_CLR_STICKY_ON_PERST |
15918cc64f1eSJack F Vogel 			     I218_ULP_CONFIG1_DISABLE_SMB_PERST);
15928cc64f1eSJack F Vogel 		e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
15938cc64f1eSJack F Vogel 
15948cc64f1eSJack F Vogel 		/* Commit ULP changes by starting auto ULP configuration */
15958cc64f1eSJack F Vogel 		phy_reg |= I218_ULP_CONFIG1_START;
15968cc64f1eSJack F Vogel 		e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
15978cc64f1eSJack F Vogel 
15988cc64f1eSJack F Vogel 		/* Clear Disable SMBus Release on PERST# in MAC */
15998cc64f1eSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM7);
16008cc64f1eSJack F Vogel 		mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST;
16018cc64f1eSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FEXTNVM7, mac_reg);
16028cc64f1eSJack F Vogel 
1603*fc7682b1SKevin Bowling 		if (!force) {
1604*fc7682b1SKevin Bowling 			hw->phy.ops.release(hw);
1605*fc7682b1SKevin Bowling 
1606*fc7682b1SKevin Bowling 			if (hw->mac.autoneg)
1607*fc7682b1SKevin Bowling 				e1000_phy_setup_autoneg(hw);
1608*fc7682b1SKevin Bowling 			else
1609*fc7682b1SKevin Bowling 				e1000_setup_copper_link_generic(hw);
1610*fc7682b1SKevin Bowling 
1611*fc7682b1SKevin Bowling 			e1000_sw_lcd_config_ich8lan(hw);
1612*fc7682b1SKevin Bowling 
1613*fc7682b1SKevin Bowling 			e1000_oem_bits_config_ich8lan(hw, true);
1614*fc7682b1SKevin Bowling 
1615*fc7682b1SKevin Bowling 			/* Set ULP state to unknown and return non-zero to
1616*fc7682b1SKevin Bowling 			 * indicate no link (yet) and re-enter on the next LSC
1617*fc7682b1SKevin Bowling 			 * to finish disabling ULP flow.
1618*fc7682b1SKevin Bowling 			 */
1619*fc7682b1SKevin Bowling 			hw->dev_spec.ich8lan.ulp_state =
1620*fc7682b1SKevin Bowling 			    e1000_ulp_state_unknown;
1621*fc7682b1SKevin Bowling 
1622*fc7682b1SKevin Bowling 			return 1;
1623*fc7682b1SKevin Bowling 		}
1624*fc7682b1SKevin Bowling 	}
1625*fc7682b1SKevin Bowling 
1626*fc7682b1SKevin Bowling 	/* Re-enable Tx */
1627*fc7682b1SKevin Bowling 	mac_reg = E1000_READ_REG(hw, E1000_TCTL);
1628*fc7682b1SKevin Bowling 	mac_reg |= E1000_TCTL_EN;
1629*fc7682b1SKevin Bowling 	E1000_WRITE_REG(hw, E1000_TCTL, mac_reg);
1630*fc7682b1SKevin Bowling 
16318cc64f1eSJack F Vogel release:
16328cc64f1eSJack F Vogel 	hw->phy.ops.release(hw);
16338cc64f1eSJack F Vogel 	if (force) {
16348cc64f1eSJack F Vogel 		hw->phy.ops.reset(hw);
16358cc64f1eSJack F Vogel 		msec_delay(50);
16368cc64f1eSJack F Vogel 	}
16378cc64f1eSJack F Vogel out:
16388cc64f1eSJack F Vogel 	if (ret_val)
16398cc64f1eSJack F Vogel 		DEBUGOUT1("Error in ULP disable flow: %d\n", ret_val);
16408cc64f1eSJack F Vogel 	else
16418cc64f1eSJack F Vogel 		hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_off;
16428cc64f1eSJack F Vogel 
16438cc64f1eSJack F Vogel 	return ret_val;
16448cc64f1eSJack F Vogel }
16458cc64f1eSJack F Vogel 
16468cc64f1eSJack F Vogel /**
16474edd8523SJack F Vogel  *  e1000_check_for_copper_link_ich8lan - Check for link (Copper)
16484edd8523SJack F Vogel  *  @hw: pointer to the HW structure
16494edd8523SJack F Vogel  *
16504edd8523SJack F Vogel  *  Checks to see of the link status of the hardware has changed.  If a
16514edd8523SJack F Vogel  *  change in link status has been detected, then we read the PHY registers
16524edd8523SJack F Vogel  *  to get the current speed/duplex if link exists.
16534edd8523SJack F Vogel  **/
16544edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
16554edd8523SJack F Vogel {
16564edd8523SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
1657c80429ceSEric Joyner 	s32 ret_val, tipg_reg = 0;
1658c80429ceSEric Joyner 	u16 emi_addr, emi_val = 0;
1659*fc7682b1SKevin Bowling 	bool link = false;
16604dab5c37SJack F Vogel 	u16 phy_reg;
16614edd8523SJack F Vogel 
16624edd8523SJack F Vogel 	DEBUGFUNC("e1000_check_for_copper_link_ich8lan");
16634edd8523SJack F Vogel 
16646ab6bfe3SJack F Vogel 	/* We only want to go out to the PHY registers to see if Auto-Neg
16654edd8523SJack F Vogel 	 * has completed and/or if our link status has changed.  The
16664edd8523SJack F Vogel 	 * get_link_status flag is set upon receiving a Link Status
16674edd8523SJack F Vogel 	 * Change or Rx Sequence Error interrupt.
16684edd8523SJack F Vogel 	 */
16696ab6bfe3SJack F Vogel 	if (!mac->get_link_status)
16706ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
16714edd8523SJack F Vogel 
1672*fc7682b1SKevin Bowling 	if ((hw->mac.type < e1000_pch_lpt) ||
1673*fc7682b1SKevin Bowling 	    (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) ||
1674*fc7682b1SKevin Bowling 	    (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V)) {
16756ab6bfe3SJack F Vogel 		/* First we want to see if the MII Status Register reports
16764edd8523SJack F Vogel 		 * link.  If so, then we want to get the current speed/duplex
16774edd8523SJack F Vogel 		 * of the PHY.
16784edd8523SJack F Vogel 		 */
16794edd8523SJack F Vogel 		ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
16804edd8523SJack F Vogel 		if (ret_val)
16816ab6bfe3SJack F Vogel 			return ret_val;
1682*fc7682b1SKevin Bowling 	} else {
1683*fc7682b1SKevin Bowling 		/* Check the MAC's STATUS register to determine link state
1684*fc7682b1SKevin Bowling 		 * since the PHY could be inaccessible while in ULP mode.
1685*fc7682b1SKevin Bowling 		 */
1686*fc7682b1SKevin Bowling 		link = !!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU);
1687*fc7682b1SKevin Bowling 		if (link)
1688*fc7682b1SKevin Bowling 			ret_val = e1000_disable_ulp_lpt_lp(hw, false);
1689*fc7682b1SKevin Bowling 		else
1690*fc7682b1SKevin Bowling 			ret_val = e1000_enable_ulp_lpt_lp(hw, false);
1691*fc7682b1SKevin Bowling 		if (ret_val)
1692*fc7682b1SKevin Bowling 			return ret_val;
1693*fc7682b1SKevin Bowling 	}
16944edd8523SJack F Vogel 
16954edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan) {
16964edd8523SJack F Vogel 		ret_val = e1000_k1_gig_workaround_hv(hw, link);
16974edd8523SJack F Vogel 		if (ret_val)
16986ab6bfe3SJack F Vogel 			return ret_val;
16994edd8523SJack F Vogel 	}
17004edd8523SJack F Vogel 
17018cc64f1eSJack F Vogel 	/* When connected at 10Mbps half-duplex, some parts are excessively
17026ab6bfe3SJack F Vogel 	 * aggressive resulting in many collisions. To avoid this, increase
17036ab6bfe3SJack F Vogel 	 * the IPG and reduce Rx latency in the PHY.
17046ab6bfe3SJack F Vogel 	 */
1705295df609SEric Joyner 	if ((hw->mac.type >= e1000_pch2lan) && link) {
1706c80429ceSEric Joyner 		u16 speed, duplex;
17078cc64f1eSJack F Vogel 
1708c80429ceSEric Joyner 		e1000_get_speed_and_duplex_copper_generic(hw, &speed, &duplex);
1709c80429ceSEric Joyner 		tipg_reg = E1000_READ_REG(hw, E1000_TIPG);
1710c80429ceSEric Joyner 		tipg_reg &= ~E1000_TIPG_IPGT_MASK;
17116ab6bfe3SJack F Vogel 
1712c80429ceSEric Joyner 		if (duplex == HALF_DUPLEX && speed == SPEED_10) {
1713c80429ceSEric Joyner 			tipg_reg |= 0xFF;
17146ab6bfe3SJack F Vogel 			/* Reduce Rx latency in analog PHY */
1715c80429ceSEric Joyner 			emi_val = 0;
1716295df609SEric Joyner 		} else if (hw->mac.type >= e1000_pch_spt &&
1717c80429ceSEric Joyner 			   duplex == FULL_DUPLEX && speed != SPEED_1000) {
1718c80429ceSEric Joyner 			tipg_reg |= 0xC;
1719c80429ceSEric Joyner 			emi_val = 1;
1720c80429ceSEric Joyner 		} else {
1721c80429ceSEric Joyner 			/* Roll back the default values */
1722c80429ceSEric Joyner 			tipg_reg |= 0x08;
1723c80429ceSEric Joyner 			emi_val = 1;
1724c80429ceSEric Joyner 		}
1725c80429ceSEric Joyner 
1726c80429ceSEric Joyner 		E1000_WRITE_REG(hw, E1000_TIPG, tipg_reg);
1727c80429ceSEric Joyner 
17286ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
17296ab6bfe3SJack F Vogel 		if (ret_val)
17306ab6bfe3SJack F Vogel 			return ret_val;
17316ab6bfe3SJack F Vogel 
17328cc64f1eSJack F Vogel 		if (hw->mac.type == e1000_pch2lan)
17338cc64f1eSJack F Vogel 			emi_addr = I82579_RX_CONFIG;
17348cc64f1eSJack F Vogel 		else
17358cc64f1eSJack F Vogel 			emi_addr = I217_RX_CONFIG;
1736c80429ceSEric Joyner 		ret_val = e1000_write_emi_reg_locked(hw, emi_addr, emi_val);
17376ab6bfe3SJack F Vogel 
1738295df609SEric Joyner 
1739295df609SEric Joyner 		if (hw->mac.type >= e1000_pch_lpt) {
1740c80429ceSEric Joyner 			hw->phy.ops.read_reg_locked(hw, I217_PLL_CLOCK_GATE_REG,
1741c80429ceSEric Joyner 						    &phy_reg);
1742c80429ceSEric Joyner 			phy_reg &= ~I217_PLL_CLOCK_GATE_MASK;
1743c80429ceSEric Joyner 			if (speed == SPEED_100 || speed == SPEED_10)
1744c80429ceSEric Joyner 				phy_reg |= 0x3E8;
1745c80429ceSEric Joyner 			else
1746c80429ceSEric Joyner 				phy_reg |= 0xFA;
1747c80429ceSEric Joyner 			hw->phy.ops.write_reg_locked(hw,
1748c80429ceSEric Joyner 						     I217_PLL_CLOCK_GATE_REG,
1749c80429ceSEric Joyner 						     phy_reg);
1750e760e292SSean Bruno 
1751e760e292SSean Bruno 			if (speed == SPEED_1000) {
1752e760e292SSean Bruno 				hw->phy.ops.read_reg_locked(hw, HV_PM_CTRL,
1753e760e292SSean Bruno 							    &phy_reg);
1754e760e292SSean Bruno 
1755e760e292SSean Bruno 				phy_reg |= HV_PM_CTRL_K1_CLK_REQ;
1756e760e292SSean Bruno 
1757e760e292SSean Bruno 				hw->phy.ops.write_reg_locked(hw, HV_PM_CTRL,
1758e760e292SSean Bruno 							     phy_reg);
1759e760e292SSean Bruno 				}
1760c80429ceSEric Joyner 		 }
17616ab6bfe3SJack F Vogel 		hw->phy.ops.release(hw);
17626ab6bfe3SJack F Vogel 
17636ab6bfe3SJack F Vogel 		if (ret_val)
17646ab6bfe3SJack F Vogel 			return ret_val;
1765c80429ceSEric Joyner 
1766295df609SEric Joyner 		if (hw->mac.type >= e1000_pch_spt) {
1767c80429ceSEric Joyner 			u16 data;
1768c80429ceSEric Joyner 			u16 ptr_gap;
1769c80429ceSEric Joyner 
1770c80429ceSEric Joyner 			if (speed == SPEED_1000) {
1771c80429ceSEric Joyner 				ret_val = hw->phy.ops.acquire(hw);
1772c80429ceSEric Joyner 				if (ret_val)
1773c80429ceSEric Joyner 					return ret_val;
1774c80429ceSEric Joyner 
1775c80429ceSEric Joyner 				ret_val = hw->phy.ops.read_reg_locked(hw,
1776c80429ceSEric Joyner 							      PHY_REG(776, 20),
1777c80429ceSEric Joyner 							      &data);
1778c80429ceSEric Joyner 				if (ret_val) {
1779c80429ceSEric Joyner 					hw->phy.ops.release(hw);
1780c80429ceSEric Joyner 					return ret_val;
17816ab6bfe3SJack F Vogel 				}
1782c80429ceSEric Joyner 
1783c80429ceSEric Joyner 				ptr_gap = (data & (0x3FF << 2)) >> 2;
1784c80429ceSEric Joyner 				if (ptr_gap < 0x18) {
1785c80429ceSEric Joyner 					data &= ~(0x3FF << 2);
1786c80429ceSEric Joyner 					data |= (0x18 << 2);
1787c80429ceSEric Joyner 					ret_val =
1788c80429ceSEric Joyner 						hw->phy.ops.write_reg_locked(hw,
1789c80429ceSEric Joyner 							PHY_REG(776, 20), data);
1790c80429ceSEric Joyner 				}
1791c80429ceSEric Joyner 				hw->phy.ops.release(hw);
1792c80429ceSEric Joyner 				if (ret_val)
1793c80429ceSEric Joyner 					return ret_val;
1794c80429ceSEric Joyner 			} else {
1795c80429ceSEric Joyner 				ret_val = hw->phy.ops.acquire(hw);
1796c80429ceSEric Joyner 				if (ret_val)
1797c80429ceSEric Joyner 					return ret_val;
1798c80429ceSEric Joyner 
1799c80429ceSEric Joyner 				ret_val = hw->phy.ops.write_reg_locked(hw,
1800c80429ceSEric Joyner 							     PHY_REG(776, 20),
1801c80429ceSEric Joyner 							     0xC023);
1802c80429ceSEric Joyner 				hw->phy.ops.release(hw);
1803c80429ceSEric Joyner 				if (ret_val)
1804c80429ceSEric Joyner 					return ret_val;
1805c80429ceSEric Joyner 
1806c80429ceSEric Joyner 			}
1807c80429ceSEric Joyner 		}
1808c80429ceSEric Joyner 	}
1809c80429ceSEric Joyner 
1810c80429ceSEric Joyner 	/* I217 Packet Loss issue:
1811c80429ceSEric Joyner 	 * ensure that FEXTNVM4 Beacon Duration is set correctly
1812c80429ceSEric Joyner 	 * on power up.
1813c80429ceSEric Joyner 	 * Set the Beacon Duration for I217 to 8 usec
1814c80429ceSEric Joyner 	 */
1815295df609SEric Joyner 	if (hw->mac.type >= e1000_pch_lpt) {
1816c80429ceSEric Joyner 		u32 mac_reg;
1817c80429ceSEric Joyner 
1818c80429ceSEric Joyner 		mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4);
1819c80429ceSEric Joyner 		mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
1820c80429ceSEric Joyner 		mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
1821c80429ceSEric Joyner 		E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg);
18226ab6bfe3SJack F Vogel 	}
18236ab6bfe3SJack F Vogel 
18246ab6bfe3SJack F Vogel 	/* Work-around I218 hang issue */
18256ab6bfe3SJack F Vogel 	if ((hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
18268cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) ||
18278cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_LM3) ||
18288cc64f1eSJack F Vogel 	    (hw->device_id == E1000_DEV_ID_PCH_I218_V3)) {
18296ab6bfe3SJack F Vogel 		ret_val = e1000_k1_workaround_lpt_lp(hw, link);
18306ab6bfe3SJack F Vogel 		if (ret_val)
18316ab6bfe3SJack F Vogel 			return ret_val;
18326ab6bfe3SJack F Vogel 	}
1833295df609SEric Joyner 	if (hw->mac.type >= e1000_pch_lpt) {
1834e373323fSSean Bruno 		/* Set platform power management values for
1835e373323fSSean Bruno 		 * Latency Tolerance Reporting (LTR)
1836e373323fSSean Bruno 		 * Optimized Buffer Flush/Fill (OBFF)
1837e373323fSSean Bruno 		 */
1838e373323fSSean Bruno 		ret_val = e1000_platform_pm_pch_lpt(hw, link);
1839e373323fSSean Bruno 		if (ret_val)
1840e373323fSSean Bruno 			return ret_val;
1841e373323fSSean Bruno 	}
1842e373323fSSean Bruno 
18436ab6bfe3SJack F Vogel 	/* Clear link partner's EEE ability */
18446ab6bfe3SJack F Vogel 	hw->dev_spec.ich8lan.eee_lp_ability = 0;
18456ab6bfe3SJack F Vogel 
1846*fc7682b1SKevin Bowling 	/* Configure K0s minimum time */
1847*fc7682b1SKevin Bowling 	if (hw->mac.type >= e1000_pch_lpt) {
1848*fc7682b1SKevin Bowling 		e1000_configure_k0s_lpt(hw, K1_ENTRY_LATENCY, K1_MIN_TIME);
1849*fc7682b1SKevin Bowling 	}
1850*fc7682b1SKevin Bowling 
1851295df609SEric Joyner 	if (hw->mac.type >= e1000_pch_lpt) {
1852c80429ceSEric Joyner 		u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6);
1853c80429ceSEric Joyner 
1854295df609SEric Joyner 		if (hw->mac.type == e1000_pch_spt) {
1855295df609SEric Joyner 			/* FEXTNVM6 K1-off workaround - for SPT only */
1856295df609SEric Joyner 			u32 pcieanacfg = E1000_READ_REG(hw, E1000_PCIEANACFG);
1857295df609SEric Joyner 
1858295df609SEric Joyner 			if (pcieanacfg & E1000_FEXTNVM6_K1_OFF_ENABLE)
1859c80429ceSEric Joyner 				fextnvm6 |= E1000_FEXTNVM6_K1_OFF_ENABLE;
1860c80429ceSEric Joyner 			else
1861c80429ceSEric Joyner 				fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE;
1862295df609SEric Joyner 		}
1863295df609SEric Joyner 
1864295df609SEric Joyner 		if (hw->dev_spec.ich8lan.disable_k1_off == TRUE)
1865295df609SEric Joyner 			fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE;
1866c80429ceSEric Joyner 
1867c80429ceSEric Joyner 		E1000_WRITE_REG(hw, E1000_FEXTNVM6, fextnvm6);
1868c80429ceSEric Joyner 	}
1869c80429ceSEric Joyner 
18704edd8523SJack F Vogel 	if (!link)
18716ab6bfe3SJack F Vogel 		return E1000_SUCCESS; /* No link detected */
18724edd8523SJack F Vogel 
18734edd8523SJack F Vogel 	mac->get_link_status = FALSE;
18744edd8523SJack F Vogel 
18754dab5c37SJack F Vogel 	switch (hw->mac.type) {
18764dab5c37SJack F Vogel 	case e1000_pch2lan:
18774dab5c37SJack F Vogel 		ret_val = e1000_k1_workaround_lv(hw);
18784dab5c37SJack F Vogel 		if (ret_val)
18796ab6bfe3SJack F Vogel 			return ret_val;
18804dab5c37SJack F Vogel 		/* fall-thru */
18814dab5c37SJack F Vogel 	case e1000_pchlan:
18824edd8523SJack F Vogel 		if (hw->phy.type == e1000_phy_82578) {
18834edd8523SJack F Vogel 			ret_val = e1000_link_stall_workaround_hv(hw);
18844edd8523SJack F Vogel 			if (ret_val)
18856ab6bfe3SJack F Vogel 				return ret_val;
18864edd8523SJack F Vogel 		}
18874edd8523SJack F Vogel 
18886ab6bfe3SJack F Vogel 		/* Workaround for PCHx parts in half-duplex:
18894dab5c37SJack F Vogel 		 * Set the number of preambles removed from the packet
18904dab5c37SJack F Vogel 		 * when it is passed from the PHY to the MAC to prevent
18914dab5c37SJack F Vogel 		 * the MAC from misinterpreting the packet type.
18924dab5c37SJack F Vogel 		 */
18934dab5c37SJack F Vogel 		hw->phy.ops.read_reg(hw, HV_KMRN_FIFO_CTRLSTA, &phy_reg);
18944dab5c37SJack F Vogel 		phy_reg &= ~HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK;
18954dab5c37SJack F Vogel 
18964dab5c37SJack F Vogel 		if ((E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_FD) !=
18974dab5c37SJack F Vogel 		    E1000_STATUS_FD)
18984dab5c37SJack F Vogel 			phy_reg |= (1 << HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT);
18994dab5c37SJack F Vogel 
19004dab5c37SJack F Vogel 		hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA, phy_reg);
19014dab5c37SJack F Vogel 		break;
19024dab5c37SJack F Vogel 	default:
19034dab5c37SJack F Vogel 		break;
19047d9119bdSJack F Vogel 	}
19057d9119bdSJack F Vogel 
19066ab6bfe3SJack F Vogel 	/* Check if there was DownShift, must be checked
19074edd8523SJack F Vogel 	 * immediately after link-up
19084edd8523SJack F Vogel 	 */
19094edd8523SJack F Vogel 	e1000_check_downshift_generic(hw);
19104edd8523SJack F Vogel 
19117d9119bdSJack F Vogel 	/* Enable/Disable EEE after link up */
19127609433eSJack F Vogel 	if (hw->phy.type > e1000_phy_82579) {
19137d9119bdSJack F Vogel 		ret_val = e1000_set_eee_pchlan(hw);
19147d9119bdSJack F Vogel 		if (ret_val)
19156ab6bfe3SJack F Vogel 			return ret_val;
19167609433eSJack F Vogel 	}
19177d9119bdSJack F Vogel 
19186ab6bfe3SJack F Vogel 	/* If we are forcing speed/duplex, then we simply return since
19194edd8523SJack F Vogel 	 * we have already determined whether we have link or not.
19204edd8523SJack F Vogel 	 */
19216ab6bfe3SJack F Vogel 	if (!mac->autoneg)
19226ab6bfe3SJack F Vogel 		return -E1000_ERR_CONFIG;
19234edd8523SJack F Vogel 
19246ab6bfe3SJack F Vogel 	/* Auto-Neg is enabled.  Auto Speed Detection takes care
19254edd8523SJack F Vogel 	 * of MAC speed/duplex configuration.  So we only need to
19264edd8523SJack F Vogel 	 * configure Collision Distance in the MAC.
19274edd8523SJack F Vogel 	 */
19286ab6bfe3SJack F Vogel 	mac->ops.config_collision_dist(hw);
19294edd8523SJack F Vogel 
19306ab6bfe3SJack F Vogel 	/* Configure Flow Control now that Auto-Neg has completed.
19314edd8523SJack F Vogel 	 * First, we need to restore the desired flow control
19324edd8523SJack F Vogel 	 * settings because we may have had to re-autoneg with a
19334edd8523SJack F Vogel 	 * different link partner.
19344edd8523SJack F Vogel 	 */
19354edd8523SJack F Vogel 	ret_val = e1000_config_fc_after_link_up_generic(hw);
19364edd8523SJack F Vogel 	if (ret_val)
19374edd8523SJack F Vogel 		DEBUGOUT("Error configuring flow control\n");
19384edd8523SJack F Vogel 
19394edd8523SJack F Vogel 	return ret_val;
19404edd8523SJack F Vogel }
19414edd8523SJack F Vogel 
19424edd8523SJack F Vogel /**
19438cfa0ad2SJack F Vogel  *  e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers
19448cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
19458cfa0ad2SJack F Vogel  *
19468cfa0ad2SJack F Vogel  *  Initialize family-specific function pointers for PHY, MAC, and NVM.
19478cfa0ad2SJack F Vogel  **/
19488cfa0ad2SJack F Vogel void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw)
19498cfa0ad2SJack F Vogel {
19508cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_function_pointers_ich8lan");
19518cfa0ad2SJack F Vogel 
19528cfa0ad2SJack F Vogel 	hw->mac.ops.init_params = e1000_init_mac_params_ich8lan;
19538cfa0ad2SJack F Vogel 	hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan;
19549d81738fSJack F Vogel 	switch (hw->mac.type) {
19559d81738fSJack F Vogel 	case e1000_ich8lan:
19569d81738fSJack F Vogel 	case e1000_ich9lan:
19579d81738fSJack F Vogel 	case e1000_ich10lan:
19588cfa0ad2SJack F Vogel 		hw->phy.ops.init_params = e1000_init_phy_params_ich8lan;
19599d81738fSJack F Vogel 		break;
19609d81738fSJack F Vogel 	case e1000_pchlan:
19617d9119bdSJack F Vogel 	case e1000_pch2lan:
19626ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
1963c80429ceSEric Joyner 	case e1000_pch_spt:
19646fe4c0a0SSean Bruno 	case e1000_pch_cnp:
196559690eabSKevin Bowling 	case e1000_pch_tgp:
196659690eabSKevin Bowling 	case e1000_pch_adp:
196759690eabSKevin Bowling 	case e1000_pch_mtp:
19689d81738fSJack F Vogel 		hw->phy.ops.init_params = e1000_init_phy_params_pchlan;
19699d81738fSJack F Vogel 		break;
19709d81738fSJack F Vogel 	default:
19719d81738fSJack F Vogel 		break;
19729d81738fSJack F Vogel 	}
19738cfa0ad2SJack F Vogel }
19748cfa0ad2SJack F Vogel 
19758cfa0ad2SJack F Vogel /**
19764edd8523SJack F Vogel  *  e1000_acquire_nvm_ich8lan - Acquire NVM mutex
19774edd8523SJack F Vogel  *  @hw: pointer to the HW structure
19784edd8523SJack F Vogel  *
19794edd8523SJack F Vogel  *  Acquires the mutex for performing NVM operations.
19804edd8523SJack F Vogel  **/
19814edd8523SJack F Vogel static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
19824edd8523SJack F Vogel {
19834edd8523SJack F Vogel 	DEBUGFUNC("e1000_acquire_nvm_ich8lan");
19844edd8523SJack F Vogel 
1985d5210708SMatt Macy 	ASSERT_CTX_LOCK_HELD(hw);
19864edd8523SJack F Vogel 
19874edd8523SJack F Vogel 	return E1000_SUCCESS;
19884edd8523SJack F Vogel }
19894edd8523SJack F Vogel 
19904edd8523SJack F Vogel /**
19914edd8523SJack F Vogel  *  e1000_release_nvm_ich8lan - Release NVM mutex
19924edd8523SJack F Vogel  *  @hw: pointer to the HW structure
19934edd8523SJack F Vogel  *
19944edd8523SJack F Vogel  *  Releases the mutex used while performing NVM operations.
19954edd8523SJack F Vogel  **/
19964edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
19974edd8523SJack F Vogel {
19984edd8523SJack F Vogel 	DEBUGFUNC("e1000_release_nvm_ich8lan");
19994edd8523SJack F Vogel 
2000d5210708SMatt Macy 	ASSERT_CTX_LOCK_HELD(hw);
20014edd8523SJack F Vogel }
20024edd8523SJack F Vogel 
20034edd8523SJack F Vogel /**
20048cfa0ad2SJack F Vogel  *  e1000_acquire_swflag_ich8lan - Acquire software control flag
20058cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
20068cfa0ad2SJack F Vogel  *
20074edd8523SJack F Vogel  *  Acquires the software control flag for performing PHY and select
20084edd8523SJack F Vogel  *  MAC CSR accesses.
20098cfa0ad2SJack F Vogel  **/
20108cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
20118cfa0ad2SJack F Vogel {
20128cfa0ad2SJack F Vogel 	u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
20138cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
20148cfa0ad2SJack F Vogel 
20158cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_acquire_swflag_ich8lan");
20168cfa0ad2SJack F Vogel 
2017d5210708SMatt Macy 	ASSERT_CTX_LOCK_HELD(hw);
20184edd8523SJack F Vogel 
20198cfa0ad2SJack F Vogel 	while (timeout) {
20208cfa0ad2SJack F Vogel 		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
20214edd8523SJack F Vogel 		if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG))
20228cfa0ad2SJack F Vogel 			break;
20234edd8523SJack F Vogel 
20248cfa0ad2SJack F Vogel 		msec_delay_irq(1);
20258cfa0ad2SJack F Vogel 		timeout--;
20268cfa0ad2SJack F Vogel 	}
20278cfa0ad2SJack F Vogel 
20288cfa0ad2SJack F Vogel 	if (!timeout) {
20294dab5c37SJack F Vogel 		DEBUGOUT("SW has already locked the resource.\n");
20304edd8523SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
20314edd8523SJack F Vogel 		goto out;
20324edd8523SJack F Vogel 	}
20334edd8523SJack F Vogel 
20344edd8523SJack F Vogel 	timeout = SW_FLAG_TIMEOUT;
20354edd8523SJack F Vogel 
20364edd8523SJack F Vogel 	extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
20374edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
20384edd8523SJack F Vogel 
20394edd8523SJack F Vogel 	while (timeout) {
20404edd8523SJack F Vogel 		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
20414edd8523SJack F Vogel 		if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
20424edd8523SJack F Vogel 			break;
20434edd8523SJack F Vogel 
20444edd8523SJack F Vogel 		msec_delay_irq(1);
20454edd8523SJack F Vogel 		timeout--;
20464edd8523SJack F Vogel 	}
20474edd8523SJack F Vogel 
20484edd8523SJack F Vogel 	if (!timeout) {
20494dab5c37SJack F Vogel 		DEBUGOUT2("Failed to acquire the semaphore, FW or HW has it: FWSM=0x%8.8x EXTCNF_CTRL=0x%8.8x)\n",
20504dab5c37SJack F Vogel 			  E1000_READ_REG(hw, E1000_FWSM), extcnf_ctrl);
20518cfa0ad2SJack F Vogel 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
20528cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
20538cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
20548cfa0ad2SJack F Vogel 		goto out;
20558cfa0ad2SJack F Vogel 	}
20568cfa0ad2SJack F Vogel 
20578cfa0ad2SJack F Vogel out:
20588cfa0ad2SJack F Vogel 	return ret_val;
20598cfa0ad2SJack F Vogel }
20608cfa0ad2SJack F Vogel 
20618cfa0ad2SJack F Vogel /**
20628cfa0ad2SJack F Vogel  *  e1000_release_swflag_ich8lan - Release software control flag
20638cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
20648cfa0ad2SJack F Vogel  *
20654edd8523SJack F Vogel  *  Releases the software control flag for performing PHY and select
20664edd8523SJack F Vogel  *  MAC CSR accesses.
20678cfa0ad2SJack F Vogel  **/
20688cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
20698cfa0ad2SJack F Vogel {
20708cfa0ad2SJack F Vogel 	u32 extcnf_ctrl;
20718cfa0ad2SJack F Vogel 
20728cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_release_swflag_ich8lan");
20738cfa0ad2SJack F Vogel 
20748cfa0ad2SJack F Vogel 	extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
2075730d3130SJack F Vogel 
2076730d3130SJack F Vogel 	if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) {
20778cfa0ad2SJack F Vogel 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
20788cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
2079730d3130SJack F Vogel 	} else {
2080730d3130SJack F Vogel 		DEBUGOUT("Semaphore unexpectedly released by sw/fw/hw\n");
2081730d3130SJack F Vogel 	}
20828cfa0ad2SJack F Vogel }
20838cfa0ad2SJack F Vogel 
20848cfa0ad2SJack F Vogel /**
20858cfa0ad2SJack F Vogel  *  e1000_check_mng_mode_ich8lan - Checks management mode
20868cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
20878cfa0ad2SJack F Vogel  *
20887d9119bdSJack F Vogel  *  This checks if the adapter has any manageability enabled.
20898cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by read/write
20908cfa0ad2SJack F Vogel  *  routines for the PHY and NVM parts.
20918cfa0ad2SJack F Vogel  **/
20928cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
20938cfa0ad2SJack F Vogel {
20948cfa0ad2SJack F Vogel 	u32 fwsm;
20958cfa0ad2SJack F Vogel 
20968cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_mng_mode_ich8lan");
20978cfa0ad2SJack F Vogel 
20988cfa0ad2SJack F Vogel 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
20998cfa0ad2SJack F Vogel 
21008cc64f1eSJack F Vogel 	return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
21017d9119bdSJack F Vogel 	       ((fwsm & E1000_FWSM_MODE_MASK) ==
21028cc64f1eSJack F Vogel 		(E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
21037d9119bdSJack F Vogel }
21047d9119bdSJack F Vogel 
21057d9119bdSJack F Vogel /**
21067d9119bdSJack F Vogel  *  e1000_check_mng_mode_pchlan - Checks management mode
21077d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
21087d9119bdSJack F Vogel  *
21097d9119bdSJack F Vogel  *  This checks if the adapter has iAMT enabled.
21107d9119bdSJack F Vogel  *  This is a function pointer entry point only called by read/write
21117d9119bdSJack F Vogel  *  routines for the PHY and NVM parts.
21127d9119bdSJack F Vogel  **/
21137d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw)
21147d9119bdSJack F Vogel {
21157d9119bdSJack F Vogel 	u32 fwsm;
21167d9119bdSJack F Vogel 
21177d9119bdSJack F Vogel 	DEBUGFUNC("e1000_check_mng_mode_pchlan");
21187d9119bdSJack F Vogel 
21197d9119bdSJack F Vogel 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
21207d9119bdSJack F Vogel 
21217d9119bdSJack F Vogel 	return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
21227d9119bdSJack F Vogel 	       (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
21237d9119bdSJack F Vogel }
21247d9119bdSJack F Vogel 
21257d9119bdSJack F Vogel /**
21267d9119bdSJack F Vogel  *  e1000_rar_set_pch2lan - Set receive address register
21277d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
21287d9119bdSJack F Vogel  *  @addr: pointer to the receive address
21297d9119bdSJack F Vogel  *  @index: receive address array register
21307d9119bdSJack F Vogel  *
21317d9119bdSJack F Vogel  *  Sets the receive address array register at index to the address passed
21327d9119bdSJack F Vogel  *  in by addr.  For 82579, RAR[0] is the base address register that is to
21337d9119bdSJack F Vogel  *  contain the MAC address but RAR[1-6] are reserved for manageability (ME).
21347d9119bdSJack F Vogel  *  Use SHRA[0-3] in place of those reserved for ME.
21357d9119bdSJack F Vogel  **/
21368cc64f1eSJack F Vogel static int e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index)
21377d9119bdSJack F Vogel {
21387d9119bdSJack F Vogel 	u32 rar_low, rar_high;
21397d9119bdSJack F Vogel 
21407d9119bdSJack F Vogel 	DEBUGFUNC("e1000_rar_set_pch2lan");
21417d9119bdSJack F Vogel 
21426ab6bfe3SJack F Vogel 	/* HW expects these in little endian so we reverse the byte order
21437d9119bdSJack F Vogel 	 * from network order (big endian) to little endian
21447d9119bdSJack F Vogel 	 */
21457d9119bdSJack F Vogel 	rar_low = ((u32) addr[0] |
21467d9119bdSJack F Vogel 		   ((u32) addr[1] << 8) |
21477d9119bdSJack F Vogel 		   ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
21487d9119bdSJack F Vogel 
21497d9119bdSJack F Vogel 	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
21507d9119bdSJack F Vogel 
21517d9119bdSJack F Vogel 	/* If MAC address zero, no need to set the AV bit */
21527d9119bdSJack F Vogel 	if (rar_low || rar_high)
21537d9119bdSJack F Vogel 		rar_high |= E1000_RAH_AV;
21547d9119bdSJack F Vogel 
21557d9119bdSJack F Vogel 	if (index == 0) {
21567d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
21577d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
21587d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
21597d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
21608cc64f1eSJack F Vogel 		return E1000_SUCCESS;
21617d9119bdSJack F Vogel 	}
21627d9119bdSJack F Vogel 
21637609433eSJack F Vogel 	/* RAR[1-6] are owned by manageability.  Skip those and program the
21647609433eSJack F Vogel 	 * next address into the SHRA register array.
21657609433eSJack F Vogel 	 */
21668cc64f1eSJack F Vogel 	if (index < (u32) (hw->mac.rar_entry_count)) {
21676ab6bfe3SJack F Vogel 		s32 ret_val;
21686ab6bfe3SJack F Vogel 
21696ab6bfe3SJack F Vogel 		ret_val = e1000_acquire_swflag_ich8lan(hw);
21706ab6bfe3SJack F Vogel 		if (ret_val)
21716ab6bfe3SJack F Vogel 			goto out;
21726ab6bfe3SJack F Vogel 
21737d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_SHRAL(index - 1), rar_low);
21747d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
21757d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_SHRAH(index - 1), rar_high);
21767d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
21777d9119bdSJack F Vogel 
21786ab6bfe3SJack F Vogel 		e1000_release_swflag_ich8lan(hw);
21796ab6bfe3SJack F Vogel 
21807d9119bdSJack F Vogel 		/* verify the register updates */
21817d9119bdSJack F Vogel 		if ((E1000_READ_REG(hw, E1000_SHRAL(index - 1)) == rar_low) &&
21827d9119bdSJack F Vogel 		    (E1000_READ_REG(hw, E1000_SHRAH(index - 1)) == rar_high))
21838cc64f1eSJack F Vogel 			return E1000_SUCCESS;
21847d9119bdSJack F Vogel 
21857d9119bdSJack F Vogel 		DEBUGOUT2("SHRA[%d] might be locked by ME - FWSM=0x%8.8x\n",
21867d9119bdSJack F Vogel 			 (index - 1), E1000_READ_REG(hw, E1000_FWSM));
21877d9119bdSJack F Vogel 	}
21887d9119bdSJack F Vogel 
21896ab6bfe3SJack F Vogel out:
21906ab6bfe3SJack F Vogel 	DEBUGOUT1("Failed to write receive address at index %d\n", index);
21918cc64f1eSJack F Vogel 	return -E1000_ERR_CONFIG;
21926ab6bfe3SJack F Vogel }
21936ab6bfe3SJack F Vogel 
21946ab6bfe3SJack F Vogel /**
21956ab6bfe3SJack F Vogel  *  e1000_rar_set_pch_lpt - Set receive address registers
21966ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
21976ab6bfe3SJack F Vogel  *  @addr: pointer to the receive address
21986ab6bfe3SJack F Vogel  *  @index: receive address array register
21996ab6bfe3SJack F Vogel  *
22006ab6bfe3SJack F Vogel  *  Sets the receive address register array at index to the address passed
22016ab6bfe3SJack F Vogel  *  in by addr. For LPT, RAR[0] is the base address register that is to
22026ab6bfe3SJack F Vogel  *  contain the MAC address. SHRA[0-10] are the shared receive address
22036ab6bfe3SJack F Vogel  *  registers that are shared between the Host and manageability engine (ME).
22046ab6bfe3SJack F Vogel  **/
22058cc64f1eSJack F Vogel static int e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index)
22066ab6bfe3SJack F Vogel {
22076ab6bfe3SJack F Vogel 	u32 rar_low, rar_high;
22086ab6bfe3SJack F Vogel 	u32 wlock_mac;
22096ab6bfe3SJack F Vogel 
22106ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_rar_set_pch_lpt");
22116ab6bfe3SJack F Vogel 
22126ab6bfe3SJack F Vogel 	/* HW expects these in little endian so we reverse the byte order
22136ab6bfe3SJack F Vogel 	 * from network order (big endian) to little endian
22146ab6bfe3SJack F Vogel 	 */
22156ab6bfe3SJack F Vogel 	rar_low = ((u32) addr[0] | ((u32) addr[1] << 8) |
22166ab6bfe3SJack F Vogel 		   ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
22176ab6bfe3SJack F Vogel 
22186ab6bfe3SJack F Vogel 	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
22196ab6bfe3SJack F Vogel 
22206ab6bfe3SJack F Vogel 	/* If MAC address zero, no need to set the AV bit */
22216ab6bfe3SJack F Vogel 	if (rar_low || rar_high)
22226ab6bfe3SJack F Vogel 		rar_high |= E1000_RAH_AV;
22236ab6bfe3SJack F Vogel 
22246ab6bfe3SJack F Vogel 	if (index == 0) {
22256ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
22266ab6bfe3SJack F Vogel 		E1000_WRITE_FLUSH(hw);
22276ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
22286ab6bfe3SJack F Vogel 		E1000_WRITE_FLUSH(hw);
22298cc64f1eSJack F Vogel 		return E1000_SUCCESS;
22306ab6bfe3SJack F Vogel 	}
22316ab6bfe3SJack F Vogel 
22326ab6bfe3SJack F Vogel 	/* The manageability engine (ME) can lock certain SHRAR registers that
22336ab6bfe3SJack F Vogel 	 * it is using - those registers are unavailable for use.
22346ab6bfe3SJack F Vogel 	 */
22356ab6bfe3SJack F Vogel 	if (index < hw->mac.rar_entry_count) {
22366ab6bfe3SJack F Vogel 		wlock_mac = E1000_READ_REG(hw, E1000_FWSM) &
22376ab6bfe3SJack F Vogel 			    E1000_FWSM_WLOCK_MAC_MASK;
22386ab6bfe3SJack F Vogel 		wlock_mac >>= E1000_FWSM_WLOCK_MAC_SHIFT;
22396ab6bfe3SJack F Vogel 
22406ab6bfe3SJack F Vogel 		/* Check if all SHRAR registers are locked */
22416ab6bfe3SJack F Vogel 		if (wlock_mac == 1)
22426ab6bfe3SJack F Vogel 			goto out;
22436ab6bfe3SJack F Vogel 
22446ab6bfe3SJack F Vogel 		if ((wlock_mac == 0) || (index <= wlock_mac)) {
22456ab6bfe3SJack F Vogel 			s32 ret_val;
22466ab6bfe3SJack F Vogel 
22476ab6bfe3SJack F Vogel 			ret_val = e1000_acquire_swflag_ich8lan(hw);
22486ab6bfe3SJack F Vogel 
22496ab6bfe3SJack F Vogel 			if (ret_val)
22506ab6bfe3SJack F Vogel 				goto out;
22516ab6bfe3SJack F Vogel 
22526ab6bfe3SJack F Vogel 			E1000_WRITE_REG(hw, E1000_SHRAL_PCH_LPT(index - 1),
22536ab6bfe3SJack F Vogel 					rar_low);
22546ab6bfe3SJack F Vogel 			E1000_WRITE_FLUSH(hw);
22556ab6bfe3SJack F Vogel 			E1000_WRITE_REG(hw, E1000_SHRAH_PCH_LPT(index - 1),
22566ab6bfe3SJack F Vogel 					rar_high);
22576ab6bfe3SJack F Vogel 			E1000_WRITE_FLUSH(hw);
22586ab6bfe3SJack F Vogel 
22596ab6bfe3SJack F Vogel 			e1000_release_swflag_ich8lan(hw);
22606ab6bfe3SJack F Vogel 
22616ab6bfe3SJack F Vogel 			/* verify the register updates */
22626ab6bfe3SJack F Vogel 			if ((E1000_READ_REG(hw, E1000_SHRAL_PCH_LPT(index - 1)) == rar_low) &&
22636ab6bfe3SJack F Vogel 			    (E1000_READ_REG(hw, E1000_SHRAH_PCH_LPT(index - 1)) == rar_high))
22648cc64f1eSJack F Vogel 				return E1000_SUCCESS;
22656ab6bfe3SJack F Vogel 		}
22666ab6bfe3SJack F Vogel 	}
22676ab6bfe3SJack F Vogel 
22686ab6bfe3SJack F Vogel out:
22697d9119bdSJack F Vogel 	DEBUGOUT1("Failed to write receive address at index %d\n", index);
22708cc64f1eSJack F Vogel 	return -E1000_ERR_CONFIG;
22718cfa0ad2SJack F Vogel }
22728cfa0ad2SJack F Vogel 
22738cfa0ad2SJack F Vogel /**
2274730d3130SJack F Vogel  *  e1000_update_mc_addr_list_pch2lan - Update Multicast addresses
2275730d3130SJack F Vogel  *  @hw: pointer to the HW structure
2276730d3130SJack F Vogel  *  @mc_addr_list: array of multicast addresses to program
2277730d3130SJack F Vogel  *  @mc_addr_count: number of multicast addresses to program
2278730d3130SJack F Vogel  *
2279730d3130SJack F Vogel  *  Updates entire Multicast Table Array of the PCH2 MAC and PHY.
2280730d3130SJack F Vogel  *  The caller must have a packed mc_addr_list of multicast addresses.
2281730d3130SJack F Vogel  **/
2282730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw,
2283730d3130SJack F Vogel 					      u8 *mc_addr_list,
2284730d3130SJack F Vogel 					      u32 mc_addr_count)
2285730d3130SJack F Vogel {
22864dab5c37SJack F Vogel 	u16 phy_reg = 0;
2287730d3130SJack F Vogel 	int i;
22884dab5c37SJack F Vogel 	s32 ret_val;
2289730d3130SJack F Vogel 
2290730d3130SJack F Vogel 	DEBUGFUNC("e1000_update_mc_addr_list_pch2lan");
2291730d3130SJack F Vogel 
2292730d3130SJack F Vogel 	e1000_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count);
2293730d3130SJack F Vogel 
22944dab5c37SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
22954dab5c37SJack F Vogel 	if (ret_val)
22964dab5c37SJack F Vogel 		return;
22974dab5c37SJack F Vogel 
22984dab5c37SJack F Vogel 	ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg);
22994dab5c37SJack F Vogel 	if (ret_val)
23004dab5c37SJack F Vogel 		goto release;
23014dab5c37SJack F Vogel 
2302730d3130SJack F Vogel 	for (i = 0; i < hw->mac.mta_reg_count; i++) {
23034dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_MTA(i),
23044dab5c37SJack F Vogel 					   (u16)(hw->mac.mta_shadow[i] &
23054dab5c37SJack F Vogel 						 0xFFFF));
23064dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, (BM_MTA(i) + 1),
2307730d3130SJack F Vogel 					   (u16)((hw->mac.mta_shadow[i] >> 16) &
2308730d3130SJack F Vogel 						 0xFFFF));
2309730d3130SJack F Vogel 	}
23104dab5c37SJack F Vogel 
23114dab5c37SJack F Vogel 	e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg);
23124dab5c37SJack F Vogel 
23134dab5c37SJack F Vogel release:
23144dab5c37SJack F Vogel 	hw->phy.ops.release(hw);
2315730d3130SJack F Vogel }
2316730d3130SJack F Vogel 
2317730d3130SJack F Vogel /**
23188cfa0ad2SJack F Vogel  *  e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
23198cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
23208cfa0ad2SJack F Vogel  *
23218cfa0ad2SJack F Vogel  *  Checks if firmware is blocking the reset of the PHY.
23228cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
23238cfa0ad2SJack F Vogel  *  reset routines.
23248cfa0ad2SJack F Vogel  **/
23258cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
23268cfa0ad2SJack F Vogel {
23278cfa0ad2SJack F Vogel 	u32 fwsm;
23287609433eSJack F Vogel 	bool blocked = FALSE;
23297609433eSJack F Vogel 	int i = 0;
23308cfa0ad2SJack F Vogel 
23318cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_reset_block_ich8lan");
23328cfa0ad2SJack F Vogel 
23337609433eSJack F Vogel 	do {
23348cfa0ad2SJack F Vogel 		fwsm = E1000_READ_REG(hw, E1000_FWSM);
23357609433eSJack F Vogel 		if (!(fwsm & E1000_ICH_FWSM_RSPCIPHY)) {
23367609433eSJack F Vogel 			blocked = TRUE;
23377609433eSJack F Vogel 			msec_delay(10);
23387609433eSJack F Vogel 			continue;
23397609433eSJack F Vogel 		}
23407609433eSJack F Vogel 		blocked = FALSE;
2341c80429ceSEric Joyner 	} while (blocked && (i++ < 30));
23427609433eSJack F Vogel 	return blocked ? E1000_BLK_PHY_RESET : E1000_SUCCESS;
23438cfa0ad2SJack F Vogel }
23448cfa0ad2SJack F Vogel 
23458cfa0ad2SJack F Vogel /**
23467d9119bdSJack F Vogel  *  e1000_write_smbus_addr - Write SMBus address to PHY needed during Sx states
23477d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
23487d9119bdSJack F Vogel  *
23497d9119bdSJack F Vogel  *  Assumes semaphore already acquired.
23507d9119bdSJack F Vogel  *
23517d9119bdSJack F Vogel  **/
23527d9119bdSJack F Vogel static s32 e1000_write_smbus_addr(struct e1000_hw *hw)
23537d9119bdSJack F Vogel {
23547d9119bdSJack F Vogel 	u16 phy_data;
23557d9119bdSJack F Vogel 	u32 strap = E1000_READ_REG(hw, E1000_STRAP);
23566ab6bfe3SJack F Vogel 	u32 freq = (strap & E1000_STRAP_SMT_FREQ_MASK) >>
23576ab6bfe3SJack F Vogel 		E1000_STRAP_SMT_FREQ_SHIFT;
23586ab6bfe3SJack F Vogel 	s32 ret_val;
23597d9119bdSJack F Vogel 
23607d9119bdSJack F Vogel 	strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
23617d9119bdSJack F Vogel 
23627d9119bdSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, HV_SMB_ADDR, &phy_data);
23637d9119bdSJack F Vogel 	if (ret_val)
23646ab6bfe3SJack F Vogel 		return ret_val;
23657d9119bdSJack F Vogel 
23667d9119bdSJack F Vogel 	phy_data &= ~HV_SMB_ADDR_MASK;
23677d9119bdSJack F Vogel 	phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT);
23687d9119bdSJack F Vogel 	phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
23697d9119bdSJack F Vogel 
23706ab6bfe3SJack F Vogel 	if (hw->phy.type == e1000_phy_i217) {
23716ab6bfe3SJack F Vogel 		/* Restore SMBus frequency */
23726ab6bfe3SJack F Vogel 		if (freq--) {
23736ab6bfe3SJack F Vogel 			phy_data &= ~HV_SMB_ADDR_FREQ_MASK;
23746ab6bfe3SJack F Vogel 			phy_data |= (freq & (1 << 0)) <<
23756ab6bfe3SJack F Vogel 				HV_SMB_ADDR_FREQ_LOW_SHIFT;
23766ab6bfe3SJack F Vogel 			phy_data |= (freq & (1 << 1)) <<
23776ab6bfe3SJack F Vogel 				(HV_SMB_ADDR_FREQ_HIGH_SHIFT - 1);
23786ab6bfe3SJack F Vogel 		} else {
23796ab6bfe3SJack F Vogel 			DEBUGOUT("Unsupported SMB frequency in PHY\n");
23806ab6bfe3SJack F Vogel 		}
23816ab6bfe3SJack F Vogel 	}
23826ab6bfe3SJack F Vogel 
23836ab6bfe3SJack F Vogel 	return e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data);
23847d9119bdSJack F Vogel }
23857d9119bdSJack F Vogel 
23867d9119bdSJack F Vogel /**
23874edd8523SJack F Vogel  *  e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration
23884edd8523SJack F Vogel  *  @hw:   pointer to the HW structure
23894edd8523SJack F Vogel  *
23904edd8523SJack F Vogel  *  SW should configure the LCD from the NVM extended configuration region
23914edd8523SJack F Vogel  *  as a workaround for certain parts.
23924edd8523SJack F Vogel  **/
23934edd8523SJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
23944edd8523SJack F Vogel {
23954edd8523SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
23964edd8523SJack F Vogel 	u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
2397a69ed8dfSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
23984edd8523SJack F Vogel 	u16 word_addr, reg_data, reg_addr, phy_page = 0;
23994edd8523SJack F Vogel 
24007d9119bdSJack F Vogel 	DEBUGFUNC("e1000_sw_lcd_config_ich8lan");
24014edd8523SJack F Vogel 
24026ab6bfe3SJack F Vogel 	/* Initialize the PHY from the NVM on ICH platforms.  This
24034edd8523SJack F Vogel 	 * is needed due to an issue where the NVM configuration is
24044edd8523SJack F Vogel 	 * not properly autoloaded after power transitions.
24054edd8523SJack F Vogel 	 * Therefore, after each PHY reset, we will load the
24064edd8523SJack F Vogel 	 * configuration data out of the NVM manually.
24074edd8523SJack F Vogel 	 */
24087d9119bdSJack F Vogel 	switch (hw->mac.type) {
24097d9119bdSJack F Vogel 	case e1000_ich8lan:
24107d9119bdSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
24117d9119bdSJack F Vogel 			return ret_val;
24127d9119bdSJack F Vogel 
24137d9119bdSJack F Vogel 		if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_AMT) ||
24147d9119bdSJack F Vogel 		    (hw->device_id == E1000_DEV_ID_ICH8_IGP_C)) {
24154edd8523SJack F Vogel 			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
24167d9119bdSJack F Vogel 			break;
24177d9119bdSJack F Vogel 		}
24187d9119bdSJack F Vogel 		/* Fall-thru */
24197d9119bdSJack F Vogel 	case e1000_pchlan:
24207d9119bdSJack F Vogel 	case e1000_pch2lan:
24216ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
2422c80429ceSEric Joyner 	case e1000_pch_spt:
24236fe4c0a0SSean Bruno 	case e1000_pch_cnp:
242459690eabSKevin Bowling 	case e1000_pch_tgp:
242559690eabSKevin Bowling 	case e1000_pch_adp:
242659690eabSKevin Bowling 	case e1000_pch_mtp:
24277d9119bdSJack F Vogel 		sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
24287d9119bdSJack F Vogel 		break;
24297d9119bdSJack F Vogel 	default:
24307d9119bdSJack F Vogel 		return ret_val;
24317d9119bdSJack F Vogel 	}
24327d9119bdSJack F Vogel 
24337d9119bdSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
24347d9119bdSJack F Vogel 	if (ret_val)
24357d9119bdSJack F Vogel 		return ret_val;
24364edd8523SJack F Vogel 
24374edd8523SJack F Vogel 	data = E1000_READ_REG(hw, E1000_FEXTNVM);
24384edd8523SJack F Vogel 	if (!(data & sw_cfg_mask))
24396ab6bfe3SJack F Vogel 		goto release;
24404edd8523SJack F Vogel 
24416ab6bfe3SJack F Vogel 	/* Make sure HW does not configure LCD from PHY
24424edd8523SJack F Vogel 	 * extended configuration before SW configuration
24434edd8523SJack F Vogel 	 */
24444edd8523SJack F Vogel 	data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
24456ab6bfe3SJack F Vogel 	if ((hw->mac.type < e1000_pch2lan) &&
24466ab6bfe3SJack F Vogel 	    (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE))
24476ab6bfe3SJack F Vogel 			goto release;
24484edd8523SJack F Vogel 
24494edd8523SJack F Vogel 	cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE);
24504edd8523SJack F Vogel 	cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
24514edd8523SJack F Vogel 	cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
24524edd8523SJack F Vogel 	if (!cnf_size)
24536ab6bfe3SJack F Vogel 		goto release;
24544edd8523SJack F Vogel 
24554edd8523SJack F Vogel 	cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
24564edd8523SJack F Vogel 	cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
24574edd8523SJack F Vogel 
24586ab6bfe3SJack F Vogel 	if (((hw->mac.type == e1000_pchlan) &&
24596ab6bfe3SJack F Vogel 	     !(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)) ||
24606ab6bfe3SJack F Vogel 	    (hw->mac.type > e1000_pchlan)) {
24616ab6bfe3SJack F Vogel 		/* HW configures the SMBus address and LEDs when the
24624edd8523SJack F Vogel 		 * OEM and LCD Write Enable bits are set in the NVM.
24634edd8523SJack F Vogel 		 * When both NVM bits are cleared, SW will configure
24644edd8523SJack F Vogel 		 * them instead.
24654edd8523SJack F Vogel 		 */
24667d9119bdSJack F Vogel 		ret_val = e1000_write_smbus_addr(hw);
24674edd8523SJack F Vogel 		if (ret_val)
24686ab6bfe3SJack F Vogel 			goto release;
24694edd8523SJack F Vogel 
24704edd8523SJack F Vogel 		data = E1000_READ_REG(hw, E1000_LEDCTL);
2471a69ed8dfSJack F Vogel 		ret_val = e1000_write_phy_reg_hv_locked(hw, HV_LED_CONFIG,
24724edd8523SJack F Vogel 							(u16)data);
24734edd8523SJack F Vogel 		if (ret_val)
24746ab6bfe3SJack F Vogel 			goto release;
24754edd8523SJack F Vogel 	}
24764edd8523SJack F Vogel 
24774edd8523SJack F Vogel 	/* Configure LCD from extended configuration region. */
24784edd8523SJack F Vogel 
24794edd8523SJack F Vogel 	/* cnf_base_addr is in DWORD */
24804edd8523SJack F Vogel 	word_addr = (u16)(cnf_base_addr << 1);
24814edd8523SJack F Vogel 
24824edd8523SJack F Vogel 	for (i = 0; i < cnf_size; i++) {
24834edd8523SJack F Vogel 		ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1,
24844edd8523SJack F Vogel 					   &reg_data);
24854edd8523SJack F Vogel 		if (ret_val)
24866ab6bfe3SJack F Vogel 			goto release;
24874edd8523SJack F Vogel 
24884edd8523SJack F Vogel 		ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1),
24894edd8523SJack F Vogel 					   1, &reg_addr);
24904edd8523SJack F Vogel 		if (ret_val)
24916ab6bfe3SJack F Vogel 			goto release;
24924edd8523SJack F Vogel 
24934edd8523SJack F Vogel 		/* Save off the PHY page for future writes. */
24944edd8523SJack F Vogel 		if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
24954edd8523SJack F Vogel 			phy_page = reg_data;
24964edd8523SJack F Vogel 			continue;
24974edd8523SJack F Vogel 		}
24984edd8523SJack F Vogel 
24994edd8523SJack F Vogel 		reg_addr &= PHY_REG_MASK;
25004edd8523SJack F Vogel 		reg_addr |= phy_page;
25014edd8523SJack F Vogel 
25024edd8523SJack F Vogel 		ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr,
25034edd8523SJack F Vogel 						    reg_data);
25044edd8523SJack F Vogel 		if (ret_val)
25056ab6bfe3SJack F Vogel 			goto release;
25064edd8523SJack F Vogel 	}
25074edd8523SJack F Vogel 
25086ab6bfe3SJack F Vogel release:
25094edd8523SJack F Vogel 	hw->phy.ops.release(hw);
25104edd8523SJack F Vogel 	return ret_val;
25114edd8523SJack F Vogel }
25124edd8523SJack F Vogel 
25134edd8523SJack F Vogel /**
25144edd8523SJack F Vogel  *  e1000_k1_gig_workaround_hv - K1 Si workaround
25154edd8523SJack F Vogel  *  @hw:   pointer to the HW structure
25164edd8523SJack F Vogel  *  @link: link up bool flag
25174edd8523SJack F Vogel  *
25184edd8523SJack F Vogel  *  If K1 is enabled for 1Gbps, the MAC might stall when transitioning
25194edd8523SJack F Vogel  *  from a lower speed.  This workaround disables K1 whenever link is at 1Gig
25204edd8523SJack F Vogel  *  If link is down, the function will restore the default K1 setting located
25214edd8523SJack F Vogel  *  in the NVM.
25224edd8523SJack F Vogel  **/
25234edd8523SJack F Vogel static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
25244edd8523SJack F Vogel {
25254edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
25264edd8523SJack F Vogel 	u16 status_reg = 0;
25274edd8523SJack F Vogel 	bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled;
25284edd8523SJack F Vogel 
25294edd8523SJack F Vogel 	DEBUGFUNC("e1000_k1_gig_workaround_hv");
25304edd8523SJack F Vogel 
25314edd8523SJack F Vogel 	if (hw->mac.type != e1000_pchlan)
25326ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
25334edd8523SJack F Vogel 
25344edd8523SJack F Vogel 	/* Wrap the whole flow with the sw flag */
25354edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
25364edd8523SJack F Vogel 	if (ret_val)
25376ab6bfe3SJack F Vogel 		return ret_val;
25384edd8523SJack F Vogel 
25394edd8523SJack F Vogel 	/* Disable K1 when link is 1Gbps, otherwise use the NVM setting */
25404edd8523SJack F Vogel 	if (link) {
25414edd8523SJack F Vogel 		if (hw->phy.type == e1000_phy_82578) {
25424edd8523SJack F Vogel 			ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS,
25434edd8523SJack F Vogel 							      &status_reg);
25444edd8523SJack F Vogel 			if (ret_val)
25454edd8523SJack F Vogel 				goto release;
25464edd8523SJack F Vogel 
25477609433eSJack F Vogel 			status_reg &= (BM_CS_STATUS_LINK_UP |
25484edd8523SJack F Vogel 				       BM_CS_STATUS_RESOLVED |
25497609433eSJack F Vogel 				       BM_CS_STATUS_SPEED_MASK);
25504edd8523SJack F Vogel 
25514edd8523SJack F Vogel 			if (status_reg == (BM_CS_STATUS_LINK_UP |
25524edd8523SJack F Vogel 					   BM_CS_STATUS_RESOLVED |
25534edd8523SJack F Vogel 					   BM_CS_STATUS_SPEED_1000))
25544edd8523SJack F Vogel 				k1_enable = FALSE;
25554edd8523SJack F Vogel 		}
25564edd8523SJack F Vogel 
25574edd8523SJack F Vogel 		if (hw->phy.type == e1000_phy_82577) {
25584edd8523SJack F Vogel 			ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS,
25594edd8523SJack F Vogel 							      &status_reg);
25604edd8523SJack F Vogel 			if (ret_val)
25614edd8523SJack F Vogel 				goto release;
25624edd8523SJack F Vogel 
25637609433eSJack F Vogel 			status_reg &= (HV_M_STATUS_LINK_UP |
25644edd8523SJack F Vogel 				       HV_M_STATUS_AUTONEG_COMPLETE |
25657609433eSJack F Vogel 				       HV_M_STATUS_SPEED_MASK);
25664edd8523SJack F Vogel 
25674edd8523SJack F Vogel 			if (status_reg == (HV_M_STATUS_LINK_UP |
25684edd8523SJack F Vogel 					   HV_M_STATUS_AUTONEG_COMPLETE |
25694edd8523SJack F Vogel 					   HV_M_STATUS_SPEED_1000))
25704edd8523SJack F Vogel 				k1_enable = FALSE;
25714edd8523SJack F Vogel 		}
25724edd8523SJack F Vogel 
25734edd8523SJack F Vogel 		/* Link stall fix for link up */
25744edd8523SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
25754edd8523SJack F Vogel 						       0x0100);
25764edd8523SJack F Vogel 		if (ret_val)
25774edd8523SJack F Vogel 			goto release;
25784edd8523SJack F Vogel 
25794edd8523SJack F Vogel 	} else {
25804edd8523SJack F Vogel 		/* Link stall fix for link down */
25814edd8523SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
25824edd8523SJack F Vogel 						       0x4100);
25834edd8523SJack F Vogel 		if (ret_val)
25844edd8523SJack F Vogel 			goto release;
25854edd8523SJack F Vogel 	}
25864edd8523SJack F Vogel 
25874edd8523SJack F Vogel 	ret_val = e1000_configure_k1_ich8lan(hw, k1_enable);
25884edd8523SJack F Vogel 
25894edd8523SJack F Vogel release:
25904edd8523SJack F Vogel 	hw->phy.ops.release(hw);
25916ab6bfe3SJack F Vogel 
25924edd8523SJack F Vogel 	return ret_val;
25934edd8523SJack F Vogel }
25944edd8523SJack F Vogel 
25954edd8523SJack F Vogel /**
25964edd8523SJack F Vogel  *  e1000_configure_k1_ich8lan - Configure K1 power state
25974edd8523SJack F Vogel  *  @hw: pointer to the HW structure
2598*fc7682b1SKevin Bowling  *  @k1_enable: K1 state to configure
25994edd8523SJack F Vogel  *
26004edd8523SJack F Vogel  *  Configure the K1 power state based on the provided parameter.
26014edd8523SJack F Vogel  *  Assumes semaphore already acquired.
26024edd8523SJack F Vogel  *
26034edd8523SJack F Vogel  *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
26044edd8523SJack F Vogel  **/
26054edd8523SJack F Vogel s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
26064edd8523SJack F Vogel {
26076ab6bfe3SJack F Vogel 	s32 ret_val;
26084edd8523SJack F Vogel 	u32 ctrl_reg = 0;
26094edd8523SJack F Vogel 	u32 ctrl_ext = 0;
26104edd8523SJack F Vogel 	u32 reg = 0;
26114edd8523SJack F Vogel 	u16 kmrn_reg = 0;
26124edd8523SJack F Vogel 
26137d9119bdSJack F Vogel 	DEBUGFUNC("e1000_configure_k1_ich8lan");
26147d9119bdSJack F Vogel 
26154dab5c37SJack F Vogel 	ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
26164edd8523SJack F Vogel 					     &kmrn_reg);
26174edd8523SJack F Vogel 	if (ret_val)
26186ab6bfe3SJack F Vogel 		return ret_val;
26194edd8523SJack F Vogel 
26204edd8523SJack F Vogel 	if (k1_enable)
26214edd8523SJack F Vogel 		kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE;
26224edd8523SJack F Vogel 	else
26234edd8523SJack F Vogel 		kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE;
26244edd8523SJack F Vogel 
26254dab5c37SJack F Vogel 	ret_val = e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
26264edd8523SJack F Vogel 					      kmrn_reg);
26274edd8523SJack F Vogel 	if (ret_val)
26286ab6bfe3SJack F Vogel 		return ret_val;
26294edd8523SJack F Vogel 
26304edd8523SJack F Vogel 	usec_delay(20);
26314edd8523SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
26324edd8523SJack F Vogel 	ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
26334edd8523SJack F Vogel 
26344edd8523SJack F Vogel 	reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
26354edd8523SJack F Vogel 	reg |= E1000_CTRL_FRCSPD;
26364edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, reg);
26374edd8523SJack F Vogel 
26384edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
26394dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
26404edd8523SJack F Vogel 	usec_delay(20);
26414edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
26424edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
26434dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
26444edd8523SJack F Vogel 	usec_delay(20);
26454edd8523SJack F Vogel 
26466ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
26474edd8523SJack F Vogel }
26484edd8523SJack F Vogel 
26494edd8523SJack F Vogel /**
26504edd8523SJack F Vogel  *  e1000_oem_bits_config_ich8lan - SW-based LCD Configuration
26514edd8523SJack F Vogel  *  @hw:       pointer to the HW structure
26524edd8523SJack F Vogel  *  @d0_state: boolean if entering d0 or d3 device state
26534edd8523SJack F Vogel  *
26544edd8523SJack F Vogel  *  SW will configure Gbe Disable and LPLU based on the NVM. The four bits are
26554edd8523SJack F Vogel  *  collectively called OEM bits.  The OEM Write Enable bit and SW Config bit
26564edd8523SJack F Vogel  *  in NVM determines whether HW should configure LPLU and Gbe Disable.
26574edd8523SJack F Vogel  **/
26584dab5c37SJack F Vogel static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
26594edd8523SJack F Vogel {
26604edd8523SJack F Vogel 	s32 ret_val = 0;
26614edd8523SJack F Vogel 	u32 mac_reg;
26624edd8523SJack F Vogel 	u16 oem_reg;
26634edd8523SJack F Vogel 
26647d9119bdSJack F Vogel 	DEBUGFUNC("e1000_oem_bits_config_ich8lan");
26657d9119bdSJack F Vogel 
26666ab6bfe3SJack F Vogel 	if (hw->mac.type < e1000_pchlan)
26674edd8523SJack F Vogel 		return ret_val;
26684edd8523SJack F Vogel 
26694edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
26704edd8523SJack F Vogel 	if (ret_val)
26714edd8523SJack F Vogel 		return ret_val;
26724edd8523SJack F Vogel 
26736ab6bfe3SJack F Vogel 	if (hw->mac.type == e1000_pchlan) {
26744edd8523SJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
26754edd8523SJack F Vogel 		if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
26766ab6bfe3SJack F Vogel 			goto release;
26777d9119bdSJack F Vogel 	}
26784edd8523SJack F Vogel 
26794edd8523SJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM);
26804edd8523SJack F Vogel 	if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
26816ab6bfe3SJack F Vogel 		goto release;
26824edd8523SJack F Vogel 
26834edd8523SJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
26844edd8523SJack F Vogel 
26854edd8523SJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg);
26864edd8523SJack F Vogel 	if (ret_val)
26876ab6bfe3SJack F Vogel 		goto release;
26884edd8523SJack F Vogel 
26894edd8523SJack F Vogel 	oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU);
26904edd8523SJack F Vogel 
26914edd8523SJack F Vogel 	if (d0_state) {
26924edd8523SJack F Vogel 		if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE)
26934edd8523SJack F Vogel 			oem_reg |= HV_OEM_BITS_GBE_DIS;
26944edd8523SJack F Vogel 
26954edd8523SJack F Vogel 		if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
26964edd8523SJack F Vogel 			oem_reg |= HV_OEM_BITS_LPLU;
26974dab5c37SJack F Vogel 	} else {
26984dab5c37SJack F Vogel 		if (mac_reg & (E1000_PHY_CTRL_GBE_DISABLE |
26994dab5c37SJack F Vogel 		    E1000_PHY_CTRL_NOND0A_GBE_DISABLE))
27004dab5c37SJack F Vogel 			oem_reg |= HV_OEM_BITS_GBE_DIS;
27014dab5c37SJack F Vogel 
27024dab5c37SJack F Vogel 		if (mac_reg & (E1000_PHY_CTRL_D0A_LPLU |
27034dab5c37SJack F Vogel 		    E1000_PHY_CTRL_NOND0A_LPLU))
27044dab5c37SJack F Vogel 			oem_reg |= HV_OEM_BITS_LPLU;
27054dab5c37SJack F Vogel 	}
27064dab5c37SJack F Vogel 
27076ab6bfe3SJack F Vogel 	/* Set Restart auto-neg to activate the bits */
27086ab6bfe3SJack F Vogel 	if ((d0_state || (hw->mac.type != e1000_pchlan)) &&
27096ab6bfe3SJack F Vogel 	    !hw->phy.ops.check_reset_block(hw))
27106ab6bfe3SJack F Vogel 		oem_reg |= HV_OEM_BITS_RESTART_AN;
27116ab6bfe3SJack F Vogel 
27124edd8523SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg);
27134edd8523SJack F Vogel 
27146ab6bfe3SJack F Vogel release:
27154edd8523SJack F Vogel 	hw->phy.ops.release(hw);
27164edd8523SJack F Vogel 
27174edd8523SJack F Vogel 	return ret_val;
27184edd8523SJack F Vogel }
27194edd8523SJack F Vogel 
27204edd8523SJack F Vogel 
27214edd8523SJack F Vogel /**
2722a69ed8dfSJack F Vogel  *  e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode
2723a69ed8dfSJack F Vogel  *  @hw:   pointer to the HW structure
2724a69ed8dfSJack F Vogel  **/
2725a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw)
2726a69ed8dfSJack F Vogel {
2727a69ed8dfSJack F Vogel 	s32 ret_val;
2728a69ed8dfSJack F Vogel 	u16 data;
2729a69ed8dfSJack F Vogel 
27307d9119bdSJack F Vogel 	DEBUGFUNC("e1000_set_mdio_slow_mode_hv");
27317d9119bdSJack F Vogel 
2732a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, HV_KMRN_MODE_CTRL, &data);
2733a69ed8dfSJack F Vogel 	if (ret_val)
2734a69ed8dfSJack F Vogel 		return ret_val;
2735a69ed8dfSJack F Vogel 
2736a69ed8dfSJack F Vogel 	data |= HV_KMRN_MDIO_SLOW;
2737a69ed8dfSJack F Vogel 
2738a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_MODE_CTRL, data);
2739a69ed8dfSJack F Vogel 
2740a69ed8dfSJack F Vogel 	return ret_val;
2741a69ed8dfSJack F Vogel }
2742a69ed8dfSJack F Vogel 
2743a69ed8dfSJack F Vogel /**
27449d81738fSJack F Vogel  *  e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
27459d81738fSJack F Vogel  *  done after every PHY reset.
2746*fc7682b1SKevin Bowling  *  @hw: pointer to the HW structure
27479d81738fSJack F Vogel  **/
27489d81738fSJack F Vogel static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
27499d81738fSJack F Vogel {
27509d81738fSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
2751a69ed8dfSJack F Vogel 	u16 phy_data;
27529d81738fSJack F Vogel 
27537d9119bdSJack F Vogel 	DEBUGFUNC("e1000_hv_phy_workarounds_ich8lan");
27547d9119bdSJack F Vogel 
27559d81738fSJack F Vogel 	if (hw->mac.type != e1000_pchlan)
27566ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
27579d81738fSJack F Vogel 
2758a69ed8dfSJack F Vogel 	/* Set MDIO slow mode before any other MDIO access */
2759a69ed8dfSJack F Vogel 	if (hw->phy.type == e1000_phy_82577) {
2760a69ed8dfSJack F Vogel 		ret_val = e1000_set_mdio_slow_mode_hv(hw);
2761a69ed8dfSJack F Vogel 		if (ret_val)
27626ab6bfe3SJack F Vogel 			return ret_val;
2763a69ed8dfSJack F Vogel 	}
2764a69ed8dfSJack F Vogel 
27659d81738fSJack F Vogel 	if (((hw->phy.type == e1000_phy_82577) &&
27669d81738fSJack F Vogel 	     ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
27679d81738fSJack F Vogel 	    ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
27689d81738fSJack F Vogel 		/* Disable generation of early preamble */
27699d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
27709d81738fSJack F Vogel 		if (ret_val)
27716ab6bfe3SJack F Vogel 			return ret_val;
27729d81738fSJack F Vogel 
27739d81738fSJack F Vogel 		/* Preamble tuning for SSC */
27744dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA,
27754dab5c37SJack F Vogel 						0xA204);
27769d81738fSJack F Vogel 		if (ret_val)
27776ab6bfe3SJack F Vogel 			return ret_val;
27789d81738fSJack F Vogel 	}
27799d81738fSJack F Vogel 
27809d81738fSJack F Vogel 	if (hw->phy.type == e1000_phy_82578) {
27816ab6bfe3SJack F Vogel 		/* Return registers to default by doing a soft reset then
27829d81738fSJack F Vogel 		 * writing 0x3140 to the control register.
27839d81738fSJack F Vogel 		 */
27849d81738fSJack F Vogel 		if (hw->phy.revision < 2) {
27859d81738fSJack F Vogel 			e1000_phy_sw_reset_generic(hw);
27869d81738fSJack F Vogel 			ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL,
27879d81738fSJack F Vogel 							0x3140);
27886fe4c0a0SSean Bruno 			if (ret_val)
27896fe4c0a0SSean Bruno 				return ret_val;
27909d81738fSJack F Vogel 		}
27919d81738fSJack F Vogel 	}
27929d81738fSJack F Vogel 
27939d81738fSJack F Vogel 	/* Select page 0 */
27949d81738fSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
27959d81738fSJack F Vogel 	if (ret_val)
27966ab6bfe3SJack F Vogel 		return ret_val;
27974edd8523SJack F Vogel 
27989d81738fSJack F Vogel 	hw->phy.addr = 1;
27994edd8523SJack F Vogel 	ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
2800a69ed8dfSJack F Vogel 	hw->phy.ops.release(hw);
28014edd8523SJack F Vogel 	if (ret_val)
28026ab6bfe3SJack F Vogel 		return ret_val;
28039d81738fSJack F Vogel 
28046ab6bfe3SJack F Vogel 	/* Configure the K1 Si workaround during phy reset assuming there is
28054edd8523SJack F Vogel 	 * link so that it disables K1 if link is in 1Gbps.
28064edd8523SJack F Vogel 	 */
28074edd8523SJack F Vogel 	ret_val = e1000_k1_gig_workaround_hv(hw, TRUE);
2808a69ed8dfSJack F Vogel 	if (ret_val)
28096ab6bfe3SJack F Vogel 		return ret_val;
28104edd8523SJack F Vogel 
2811a69ed8dfSJack F Vogel 	/* Workaround for link disconnects on a busy hub in half duplex */
2812a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
2813a69ed8dfSJack F Vogel 	if (ret_val)
28146ab6bfe3SJack F Vogel 		return ret_val;
28154dab5c37SJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw, BM_PORT_GEN_CFG, &phy_data);
2816a69ed8dfSJack F Vogel 	if (ret_val)
2817a69ed8dfSJack F Vogel 		goto release;
28184dab5c37SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, BM_PORT_GEN_CFG,
2819a69ed8dfSJack F Vogel 					       phy_data & 0x00FF);
28206ab6bfe3SJack F Vogel 	if (ret_val)
28216ab6bfe3SJack F Vogel 		goto release;
28226ab6bfe3SJack F Vogel 
28236ab6bfe3SJack F Vogel 	/* set MSE higher to enable link to stay up when noise is high */
28246ab6bfe3SJack F Vogel 	ret_val = e1000_write_emi_reg_locked(hw, I82577_MSE_THRESHOLD, 0x0034);
2825a69ed8dfSJack F Vogel release:
2826a69ed8dfSJack F Vogel 	hw->phy.ops.release(hw);
28276ab6bfe3SJack F Vogel 
28289d81738fSJack F Vogel 	return ret_val;
28299d81738fSJack F Vogel }
28309d81738fSJack F Vogel 
28319d81738fSJack F Vogel /**
28327d9119bdSJack F Vogel  *  e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY
28337d9119bdSJack F Vogel  *  @hw:   pointer to the HW structure
28347d9119bdSJack F Vogel  **/
28357d9119bdSJack F Vogel void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
28367d9119bdSJack F Vogel {
28377d9119bdSJack F Vogel 	u32 mac_reg;
28384dab5c37SJack F Vogel 	u16 i, phy_reg = 0;
28394dab5c37SJack F Vogel 	s32 ret_val;
28407d9119bdSJack F Vogel 
28417d9119bdSJack F Vogel 	DEBUGFUNC("e1000_copy_rx_addrs_to_phy_ich8lan");
28427d9119bdSJack F Vogel 
28434dab5c37SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
28444dab5c37SJack F Vogel 	if (ret_val)
28454dab5c37SJack F Vogel 		return;
28464dab5c37SJack F Vogel 	ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg);
28474dab5c37SJack F Vogel 	if (ret_val)
28484dab5c37SJack F Vogel 		goto release;
28494dab5c37SJack F Vogel 
28507609433eSJack F Vogel 	/* Copy both RAL/H (rar_entry_count) and SHRAL/H to PHY */
28517609433eSJack F Vogel 	for (i = 0; i < (hw->mac.rar_entry_count); i++) {
28527d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RAL(i));
28534dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_L(i),
28544dab5c37SJack F Vogel 					   (u16)(mac_reg & 0xFFFF));
28554dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_M(i),
28564dab5c37SJack F Vogel 					   (u16)((mac_reg >> 16) & 0xFFFF));
28574dab5c37SJack F Vogel 
28587d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RAH(i));
28594dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_H(i),
28604dab5c37SJack F Vogel 					   (u16)(mac_reg & 0xFFFF));
28614dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_CTRL(i),
28624dab5c37SJack F Vogel 					   (u16)((mac_reg & E1000_RAH_AV)
28634dab5c37SJack F Vogel 						 >> 16));
28647d9119bdSJack F Vogel 	}
28654dab5c37SJack F Vogel 
28664dab5c37SJack F Vogel 	e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg);
28674dab5c37SJack F Vogel 
28684dab5c37SJack F Vogel release:
28694dab5c37SJack F Vogel 	hw->phy.ops.release(hw);
28707d9119bdSJack F Vogel }
28717d9119bdSJack F Vogel 
28727d9119bdSJack F Vogel static u32 e1000_calc_rx_da_crc(u8 mac[])
28737d9119bdSJack F Vogel {
28747d9119bdSJack F Vogel 	u32 poly = 0xEDB88320;	/* Polynomial for 802.3 CRC calculation */
28757d9119bdSJack F Vogel 	u32 i, j, mask, crc;
28767d9119bdSJack F Vogel 
28777d9119bdSJack F Vogel 	DEBUGFUNC("e1000_calc_rx_da_crc");
28787d9119bdSJack F Vogel 
28797d9119bdSJack F Vogel 	crc = 0xffffffff;
28807d9119bdSJack F Vogel 	for (i = 0; i < 6; i++) {
28817d9119bdSJack F Vogel 		crc = crc ^ mac[i];
28827d9119bdSJack F Vogel 		for (j = 8; j > 0; j--) {
28837d9119bdSJack F Vogel 			mask = (crc & 1) * (-1);
28847d9119bdSJack F Vogel 			crc = (crc >> 1) ^ (poly & mask);
28857d9119bdSJack F Vogel 		}
28867d9119bdSJack F Vogel 	}
28877d9119bdSJack F Vogel 	return ~crc;
28887d9119bdSJack F Vogel }
28897d9119bdSJack F Vogel 
28907d9119bdSJack F Vogel /**
28917d9119bdSJack F Vogel  *  e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation
28927d9119bdSJack F Vogel  *  with 82579 PHY
28937d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
28947d9119bdSJack F Vogel  *  @enable: flag to enable/disable workaround when enabling/disabling jumbos
28957d9119bdSJack F Vogel  **/
28967d9119bdSJack F Vogel s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
28977d9119bdSJack F Vogel {
28987d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
28997d9119bdSJack F Vogel 	u16 phy_reg, data;
29007d9119bdSJack F Vogel 	u32 mac_reg;
29017d9119bdSJack F Vogel 	u16 i;
29027d9119bdSJack F Vogel 
29037d9119bdSJack F Vogel 	DEBUGFUNC("e1000_lv_jumbo_workaround_ich8lan");
29047d9119bdSJack F Vogel 
29056ab6bfe3SJack F Vogel 	if (hw->mac.type < e1000_pch2lan)
29066ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
29077d9119bdSJack F Vogel 
29087d9119bdSJack F Vogel 	/* disable Rx path while enabling/disabling workaround */
29097d9119bdSJack F Vogel 	hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg);
29104dab5c37SJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20),
29114dab5c37SJack F Vogel 					phy_reg | (1 << 14));
29127d9119bdSJack F Vogel 	if (ret_val)
29136ab6bfe3SJack F Vogel 		return ret_val;
29147d9119bdSJack F Vogel 
29157d9119bdSJack F Vogel 	if (enable) {
29167609433eSJack F Vogel 		/* Write Rx addresses (rar_entry_count for RAL/H, and
29177d9119bdSJack F Vogel 		 * SHRAL/H) and initial CRC values to the MAC
29187d9119bdSJack F Vogel 		 */
29197609433eSJack F Vogel 		for (i = 0; i < hw->mac.rar_entry_count; i++) {
2920e81998f4SEric Joyner 			u8 mac_addr[ETHER_ADDR_LEN] = {0};
29217d9119bdSJack F Vogel 			u32 addr_high, addr_low;
29227d9119bdSJack F Vogel 
29237d9119bdSJack F Vogel 			addr_high = E1000_READ_REG(hw, E1000_RAH(i));
29247d9119bdSJack F Vogel 			if (!(addr_high & E1000_RAH_AV))
29257d9119bdSJack F Vogel 				continue;
29267d9119bdSJack F Vogel 			addr_low = E1000_READ_REG(hw, E1000_RAL(i));
29277d9119bdSJack F Vogel 			mac_addr[0] = (addr_low & 0xFF);
29287d9119bdSJack F Vogel 			mac_addr[1] = ((addr_low >> 8) & 0xFF);
29297d9119bdSJack F Vogel 			mac_addr[2] = ((addr_low >> 16) & 0xFF);
29307d9119bdSJack F Vogel 			mac_addr[3] = ((addr_low >> 24) & 0xFF);
29317d9119bdSJack F Vogel 			mac_addr[4] = (addr_high & 0xFF);
29327d9119bdSJack F Vogel 			mac_addr[5] = ((addr_high >> 8) & 0xFF);
29337d9119bdSJack F Vogel 
29347d9119bdSJack F Vogel 			E1000_WRITE_REG(hw, E1000_PCH_RAICC(i),
29357d9119bdSJack F Vogel 					e1000_calc_rx_da_crc(mac_addr));
29367d9119bdSJack F Vogel 		}
29377d9119bdSJack F Vogel 
29387d9119bdSJack F Vogel 		/* Write Rx addresses to the PHY */
29397d9119bdSJack F Vogel 		e1000_copy_rx_addrs_to_phy_ich8lan(hw);
29407d9119bdSJack F Vogel 
29417d9119bdSJack F Vogel 		/* Enable jumbo frame workaround in the MAC */
29427d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
29437d9119bdSJack F Vogel 		mac_reg &= ~(1 << 14);
29447d9119bdSJack F Vogel 		mac_reg |= (7 << 15);
29457d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
29467d9119bdSJack F Vogel 
29477d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RCTL);
29487d9119bdSJack F Vogel 		mac_reg |= E1000_RCTL_SECRC;
29497d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
29507d9119bdSJack F Vogel 
29517d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
29527d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
29537d9119bdSJack F Vogel 						&data);
29547d9119bdSJack F Vogel 		if (ret_val)
29556ab6bfe3SJack F Vogel 			return ret_val;
29567d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
29577d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
29587d9119bdSJack F Vogel 						data | (1 << 0));
29597d9119bdSJack F Vogel 		if (ret_val)
29606ab6bfe3SJack F Vogel 			return ret_val;
29617d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
29627d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
29637d9119bdSJack F Vogel 						&data);
29647d9119bdSJack F Vogel 		if (ret_val)
29656ab6bfe3SJack F Vogel 			return ret_val;
29667d9119bdSJack F Vogel 		data &= ~(0xF << 8);
29677d9119bdSJack F Vogel 		data |= (0xB << 8);
29687d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
29697d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
29707d9119bdSJack F Vogel 						data);
29717d9119bdSJack F Vogel 		if (ret_val)
29726ab6bfe3SJack F Vogel 			return ret_val;
29737d9119bdSJack F Vogel 
29747d9119bdSJack F Vogel 		/* Enable jumbo frame workaround in the PHY */
29757d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
29767d9119bdSJack F Vogel 		data &= ~(0x7F << 5);
29777d9119bdSJack F Vogel 		data |= (0x37 << 5);
29787d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
29797d9119bdSJack F Vogel 		if (ret_val)
29806ab6bfe3SJack F Vogel 			return ret_val;
29817d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
29827d9119bdSJack F Vogel 		data &= ~(1 << 13);
29837d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
29847d9119bdSJack F Vogel 		if (ret_val)
29856ab6bfe3SJack F Vogel 			return ret_val;
29867d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
29877d9119bdSJack F Vogel 		data &= ~(0x3FF << 2);
29888cc64f1eSJack F Vogel 		data |= (E1000_TX_PTR_GAP << 2);
29897d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
29907d9119bdSJack F Vogel 		if (ret_val)
29916ab6bfe3SJack F Vogel 			return ret_val;
29924dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0xF100);
29937d9119bdSJack F Vogel 		if (ret_val)
29946ab6bfe3SJack F Vogel 			return ret_val;
29957d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
29964dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data |
29974dab5c37SJack F Vogel 						(1 << 10));
29987d9119bdSJack F Vogel 		if (ret_val)
29996ab6bfe3SJack F Vogel 			return ret_val;
30007d9119bdSJack F Vogel 	} else {
30017d9119bdSJack F Vogel 		/* Write MAC register values back to h/w defaults */
30027d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
30037d9119bdSJack F Vogel 		mac_reg &= ~(0xF << 14);
30047d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
30057d9119bdSJack F Vogel 
30067d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RCTL);
30077d9119bdSJack F Vogel 		mac_reg &= ~E1000_RCTL_SECRC;
30087d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
30097d9119bdSJack F Vogel 
30107d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
30117d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
30127d9119bdSJack F Vogel 						&data);
30137d9119bdSJack F Vogel 		if (ret_val)
30146ab6bfe3SJack F Vogel 			return ret_val;
30157d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
30167d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
30177d9119bdSJack F Vogel 						data & ~(1 << 0));
30187d9119bdSJack F Vogel 		if (ret_val)
30196ab6bfe3SJack F Vogel 			return ret_val;
30207d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
30217d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
30227d9119bdSJack F Vogel 						&data);
30237d9119bdSJack F Vogel 		if (ret_val)
30246ab6bfe3SJack F Vogel 			return ret_val;
30257d9119bdSJack F Vogel 		data &= ~(0xF << 8);
30267d9119bdSJack F Vogel 		data |= (0xB << 8);
30277d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
30287d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
30297d9119bdSJack F Vogel 						data);
30307d9119bdSJack F Vogel 		if (ret_val)
30316ab6bfe3SJack F Vogel 			return ret_val;
30327d9119bdSJack F Vogel 
30337d9119bdSJack F Vogel 		/* Write PHY register values back to h/w defaults */
30347d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
30357d9119bdSJack F Vogel 		data &= ~(0x7F << 5);
30367d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
30377d9119bdSJack F Vogel 		if (ret_val)
30386ab6bfe3SJack F Vogel 			return ret_val;
30397d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
30407d9119bdSJack F Vogel 		data |= (1 << 13);
30417d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
30427d9119bdSJack F Vogel 		if (ret_val)
30436ab6bfe3SJack F Vogel 			return ret_val;
30447d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
30457d9119bdSJack F Vogel 		data &= ~(0x3FF << 2);
30467d9119bdSJack F Vogel 		data |= (0x8 << 2);
30477d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
30487d9119bdSJack F Vogel 		if (ret_val)
30496ab6bfe3SJack F Vogel 			return ret_val;
30507d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0x7E00);
30517d9119bdSJack F Vogel 		if (ret_val)
30526ab6bfe3SJack F Vogel 			return ret_val;
30537d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
30544dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data &
30554dab5c37SJack F Vogel 						~(1 << 10));
30567d9119bdSJack F Vogel 		if (ret_val)
30576ab6bfe3SJack F Vogel 			return ret_val;
30587d9119bdSJack F Vogel 	}
30597d9119bdSJack F Vogel 
30607d9119bdSJack F Vogel 	/* re-enable Rx path after enabling/disabling workaround */
30616ab6bfe3SJack F Vogel 	return hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg &
30624dab5c37SJack F Vogel 				     ~(1 << 14));
30637d9119bdSJack F Vogel }
30647d9119bdSJack F Vogel 
30657d9119bdSJack F Vogel /**
30667d9119bdSJack F Vogel  *  e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be
30677d9119bdSJack F Vogel  *  done after every PHY reset.
3068*fc7682b1SKevin Bowling  *  @hw: pointer to the HW structure
30697d9119bdSJack F Vogel  **/
30707d9119bdSJack F Vogel static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw)
30717d9119bdSJack F Vogel {
30727d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
30737d9119bdSJack F Vogel 
30747d9119bdSJack F Vogel 	DEBUGFUNC("e1000_lv_phy_workarounds_ich8lan");
30757d9119bdSJack F Vogel 
30767d9119bdSJack F Vogel 	if (hw->mac.type != e1000_pch2lan)
30776ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
30787d9119bdSJack F Vogel 
30797d9119bdSJack F Vogel 	/* Set MDIO slow mode before any other MDIO access */
30807d9119bdSJack F Vogel 	ret_val = e1000_set_mdio_slow_mode_hv(hw);
30816ab6bfe3SJack F Vogel 	if (ret_val)
30826ab6bfe3SJack F Vogel 		return ret_val;
30837d9119bdSJack F Vogel 
30844dab5c37SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
30854dab5c37SJack F Vogel 	if (ret_val)
30866ab6bfe3SJack F Vogel 		return ret_val;
30874dab5c37SJack F Vogel 	/* set MSE higher to enable link to stay up when noise is high */
30886ab6bfe3SJack F Vogel 	ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_THRESHOLD, 0x0034);
30894dab5c37SJack F Vogel 	if (ret_val)
30904dab5c37SJack F Vogel 		goto release;
30914dab5c37SJack F Vogel 	/* drop link after 5 times MSE threshold was reached */
30926ab6bfe3SJack F Vogel 	ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_LINK_DOWN, 0x0005);
30934dab5c37SJack F Vogel release:
30944dab5c37SJack F Vogel 	hw->phy.ops.release(hw);
30954dab5c37SJack F Vogel 
30967d9119bdSJack F Vogel 	return ret_val;
30977d9119bdSJack F Vogel }
30987d9119bdSJack F Vogel 
30997d9119bdSJack F Vogel /**
31007d9119bdSJack F Vogel  *  e1000_k1_gig_workaround_lv - K1 Si workaround
31017d9119bdSJack F Vogel  *  @hw:   pointer to the HW structure
31027d9119bdSJack F Vogel  *
31038cc64f1eSJack F Vogel  *  Workaround to set the K1 beacon duration for 82579 parts in 10Mbps
31048cc64f1eSJack F Vogel  *  Disable K1 for 1000 and 100 speeds
31057d9119bdSJack F Vogel  **/
31067d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw)
31077d9119bdSJack F Vogel {
31087d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
31097d9119bdSJack F Vogel 	u16 status_reg = 0;
31107d9119bdSJack F Vogel 
31117d9119bdSJack F Vogel 	DEBUGFUNC("e1000_k1_workaround_lv");
31127d9119bdSJack F Vogel 
31137d9119bdSJack F Vogel 	if (hw->mac.type != e1000_pch2lan)
31146ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
31157d9119bdSJack F Vogel 
31168cc64f1eSJack F Vogel 	/* Set K1 beacon duration based on 10Mbs speed */
31177d9119bdSJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, HV_M_STATUS, &status_reg);
31187d9119bdSJack F Vogel 	if (ret_val)
31196ab6bfe3SJack F Vogel 		return ret_val;
31207d9119bdSJack F Vogel 
31217d9119bdSJack F Vogel 	if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE))
31227d9119bdSJack F Vogel 	    == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) {
31238cc64f1eSJack F Vogel 		if (status_reg &
31248cc64f1eSJack F Vogel 		    (HV_M_STATUS_SPEED_1000 | HV_M_STATUS_SPEED_100)) {
31256ab6bfe3SJack F Vogel 			u16 pm_phy_reg;
31266ab6bfe3SJack F Vogel 
31278cc64f1eSJack F Vogel 			/* LV 1G/100 Packet drop issue wa  */
31286ab6bfe3SJack F Vogel 			ret_val = hw->phy.ops.read_reg(hw, HV_PM_CTRL,
31296ab6bfe3SJack F Vogel 						       &pm_phy_reg);
31306ab6bfe3SJack F Vogel 			if (ret_val)
31316ab6bfe3SJack F Vogel 				return ret_val;
31328cc64f1eSJack F Vogel 			pm_phy_reg &= ~HV_PM_CTRL_K1_ENABLE;
31336ab6bfe3SJack F Vogel 			ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL,
31346ab6bfe3SJack F Vogel 							pm_phy_reg);
31356ab6bfe3SJack F Vogel 			if (ret_val)
31366ab6bfe3SJack F Vogel 				return ret_val;
31374dab5c37SJack F Vogel 		} else {
31388cc64f1eSJack F Vogel 			u32 mac_reg;
31398cc64f1eSJack F Vogel 			mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4);
31408cc64f1eSJack F Vogel 			mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
31414dab5c37SJack F Vogel 			mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
31427d9119bdSJack F Vogel 			E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg);
31438cc64f1eSJack F Vogel 		}
31447d9119bdSJack F Vogel 	}
31457d9119bdSJack F Vogel 
31467d9119bdSJack F Vogel 	return ret_val;
31477d9119bdSJack F Vogel }
31487d9119bdSJack F Vogel 
31497d9119bdSJack F Vogel /**
31507d9119bdSJack F Vogel  *  e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware
31517d9119bdSJack F Vogel  *  @hw:   pointer to the HW structure
3152730d3130SJack F Vogel  *  @gate: boolean set to TRUE to gate, FALSE to ungate
31537d9119bdSJack F Vogel  *
31547d9119bdSJack F Vogel  *  Gate/ungate the automatic PHY configuration via hardware; perform
31557d9119bdSJack F Vogel  *  the configuration via software instead.
31567d9119bdSJack F Vogel  **/
31577d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate)
31587d9119bdSJack F Vogel {
31597d9119bdSJack F Vogel 	u32 extcnf_ctrl;
31607d9119bdSJack F Vogel 
31617d9119bdSJack F Vogel 	DEBUGFUNC("e1000_gate_hw_phy_config_ich8lan");
31627d9119bdSJack F Vogel 
31636ab6bfe3SJack F Vogel 	if (hw->mac.type < e1000_pch2lan)
31647d9119bdSJack F Vogel 		return;
31657d9119bdSJack F Vogel 
31667d9119bdSJack F Vogel 	extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
31677d9119bdSJack F Vogel 
31687d9119bdSJack F Vogel 	if (gate)
31697d9119bdSJack F Vogel 		extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
31707d9119bdSJack F Vogel 	else
31717d9119bdSJack F Vogel 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG;
31727d9119bdSJack F Vogel 
31737d9119bdSJack F Vogel 	E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
31747d9119bdSJack F Vogel }
31757d9119bdSJack F Vogel 
31767d9119bdSJack F Vogel /**
31779d81738fSJack F Vogel  *  e1000_lan_init_done_ich8lan - Check for PHY config completion
31788cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
31798cfa0ad2SJack F Vogel  *
31809d81738fSJack F Vogel  *  Check the appropriate indication the MAC has finished configuring the
31819d81738fSJack F Vogel  *  PHY after a software reset.
31828cfa0ad2SJack F Vogel  **/
31839d81738fSJack F Vogel static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw)
31848cfa0ad2SJack F Vogel {
31859d81738fSJack F Vogel 	u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT;
31868cfa0ad2SJack F Vogel 
31879d81738fSJack F Vogel 	DEBUGFUNC("e1000_lan_init_done_ich8lan");
31888cfa0ad2SJack F Vogel 
31899d81738fSJack F Vogel 	/* Wait for basic configuration completes before proceeding */
31909d81738fSJack F Vogel 	do {
31919d81738fSJack F Vogel 		data = E1000_READ_REG(hw, E1000_STATUS);
31929d81738fSJack F Vogel 		data &= E1000_STATUS_LAN_INIT_DONE;
31939d81738fSJack F Vogel 		usec_delay(100);
31949d81738fSJack F Vogel 	} while ((!data) && --loop);
31958cfa0ad2SJack F Vogel 
31966ab6bfe3SJack F Vogel 	/* If basic configuration is incomplete before the above loop
31979d81738fSJack F Vogel 	 * count reaches 0, loading the configuration from NVM will
31989d81738fSJack F Vogel 	 * leave the PHY in a bad state possibly resulting in no link.
31999d81738fSJack F Vogel 	 */
32009d81738fSJack F Vogel 	if (loop == 0)
32019d81738fSJack F Vogel 		DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n");
32028cfa0ad2SJack F Vogel 
32039d81738fSJack F Vogel 	/* Clear the Init Done bit for the next init event */
32049d81738fSJack F Vogel 	data = E1000_READ_REG(hw, E1000_STATUS);
32059d81738fSJack F Vogel 	data &= ~E1000_STATUS_LAN_INIT_DONE;
32069d81738fSJack F Vogel 	E1000_WRITE_REG(hw, E1000_STATUS, data);
32078cfa0ad2SJack F Vogel }
32088cfa0ad2SJack F Vogel 
32098cfa0ad2SJack F Vogel /**
32107d9119bdSJack F Vogel  *  e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset
32117d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
32127d9119bdSJack F Vogel  **/
32137d9119bdSJack F Vogel static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
32147d9119bdSJack F Vogel {
32157d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
32167d9119bdSJack F Vogel 	u16 reg;
32177d9119bdSJack F Vogel 
32187d9119bdSJack F Vogel 	DEBUGFUNC("e1000_post_phy_reset_ich8lan");
32197d9119bdSJack F Vogel 
32207d9119bdSJack F Vogel 	if (hw->phy.ops.check_reset_block(hw))
32216ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
32227d9119bdSJack F Vogel 
32237d9119bdSJack F Vogel 	/* Allow time for h/w to get to quiescent state after reset */
32247d9119bdSJack F Vogel 	msec_delay(10);
32257d9119bdSJack F Vogel 
32267d9119bdSJack F Vogel 	/* Perform any necessary post-reset workarounds */
32277d9119bdSJack F Vogel 	switch (hw->mac.type) {
32287d9119bdSJack F Vogel 	case e1000_pchlan:
32297d9119bdSJack F Vogel 		ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
32307d9119bdSJack F Vogel 		if (ret_val)
32316ab6bfe3SJack F Vogel 			return ret_val;
32327d9119bdSJack F Vogel 		break;
32337d9119bdSJack F Vogel 	case e1000_pch2lan:
32347d9119bdSJack F Vogel 		ret_val = e1000_lv_phy_workarounds_ich8lan(hw);
32357d9119bdSJack F Vogel 		if (ret_val)
32366ab6bfe3SJack F Vogel 			return ret_val;
32377d9119bdSJack F Vogel 		break;
32387d9119bdSJack F Vogel 	default:
32397d9119bdSJack F Vogel 		break;
32407d9119bdSJack F Vogel 	}
32417d9119bdSJack F Vogel 
32424dab5c37SJack F Vogel 	/* Clear the host wakeup bit after lcd reset */
32434dab5c37SJack F Vogel 	if (hw->mac.type >= e1000_pchlan) {
32444dab5c37SJack F Vogel 		hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, &reg);
32454dab5c37SJack F Vogel 		reg &= ~BM_WUC_HOST_WU_BIT;
32464dab5c37SJack F Vogel 		hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, reg);
32477d9119bdSJack F Vogel 	}
32487d9119bdSJack F Vogel 
32497d9119bdSJack F Vogel 	/* Configure the LCD with the extended configuration region in NVM */
32507d9119bdSJack F Vogel 	ret_val = e1000_sw_lcd_config_ich8lan(hw);
32517d9119bdSJack F Vogel 	if (ret_val)
32526ab6bfe3SJack F Vogel 		return ret_val;
32537d9119bdSJack F Vogel 
32547d9119bdSJack F Vogel 	/* Configure the LCD with the OEM bits in NVM */
32557d9119bdSJack F Vogel 	ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE);
32567d9119bdSJack F Vogel 
3257730d3130SJack F Vogel 	if (hw->mac.type == e1000_pch2lan) {
32587d9119bdSJack F Vogel 		/* Ungate automatic PHY configuration on non-managed 82579 */
3259730d3130SJack F Vogel 		if (!(E1000_READ_REG(hw, E1000_FWSM) &
3260730d3130SJack F Vogel 		    E1000_ICH_FWSM_FW_VALID)) {
32617d9119bdSJack F Vogel 			msec_delay(10);
32627d9119bdSJack F Vogel 			e1000_gate_hw_phy_config_ich8lan(hw, FALSE);
32637d9119bdSJack F Vogel 		}
32647d9119bdSJack F Vogel 
3265730d3130SJack F Vogel 		/* Set EEE LPI Update Timer to 200usec */
3266730d3130SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
3267730d3130SJack F Vogel 		if (ret_val)
32686ab6bfe3SJack F Vogel 			return ret_val;
32696ab6bfe3SJack F Vogel 		ret_val = e1000_write_emi_reg_locked(hw,
32706ab6bfe3SJack F Vogel 						     I82579_LPI_UPDATE_TIMER,
3271730d3130SJack F Vogel 						     0x1387);
3272730d3130SJack F Vogel 		hw->phy.ops.release(hw);
3273730d3130SJack F Vogel 	}
3274730d3130SJack F Vogel 
32757d9119bdSJack F Vogel 	return ret_val;
32767d9119bdSJack F Vogel }
32777d9119bdSJack F Vogel 
32787d9119bdSJack F Vogel /**
32798cfa0ad2SJack F Vogel  *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
32808cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
32818cfa0ad2SJack F Vogel  *
32828cfa0ad2SJack F Vogel  *  Resets the PHY
32838cfa0ad2SJack F Vogel  *  This is a function pointer entry point called by drivers
32848cfa0ad2SJack F Vogel  *  or other shared routines.
32858cfa0ad2SJack F Vogel  **/
32868cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
32878cfa0ad2SJack F Vogel {
32884edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
32898cfa0ad2SJack F Vogel 
32908cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
32918cfa0ad2SJack F Vogel 
32927d9119bdSJack F Vogel 	/* Gate automatic PHY configuration by hardware on non-managed 82579 */
32937d9119bdSJack F Vogel 	if ((hw->mac.type == e1000_pch2lan) &&
32947d9119bdSJack F Vogel 	    !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
32957d9119bdSJack F Vogel 		e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
32967d9119bdSJack F Vogel 
32978cfa0ad2SJack F Vogel 	ret_val = e1000_phy_hw_reset_generic(hw);
32988cfa0ad2SJack F Vogel 	if (ret_val)
32998cfa0ad2SJack F Vogel 		return ret_val;
33006ab6bfe3SJack F Vogel 
33016ab6bfe3SJack F Vogel 	return e1000_post_phy_reset_ich8lan(hw);
33028cfa0ad2SJack F Vogel }
33038cfa0ad2SJack F Vogel 
33048cfa0ad2SJack F Vogel /**
33054edd8523SJack F Vogel  *  e1000_set_lplu_state_pchlan - Set Low Power Link Up state
33068cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
33074edd8523SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
33088cfa0ad2SJack F Vogel  *
33094edd8523SJack F Vogel  *  Sets the LPLU state according to the active flag.  For PCH, if OEM write
33104edd8523SJack F Vogel  *  bit are disabled in the NVM, writing the LPLU bits in the MAC will not set
33114edd8523SJack F Vogel  *  the phy speed. This function will manually set the LPLU bit and restart
33124edd8523SJack F Vogel  *  auto-neg as hw would do. D3 and D0 LPLU will call the same function
33134edd8523SJack F Vogel  *  since it configures the same bit.
33148cfa0ad2SJack F Vogel  **/
33154edd8523SJack F Vogel static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
33168cfa0ad2SJack F Vogel {
33176ab6bfe3SJack F Vogel 	s32 ret_val;
33184edd8523SJack F Vogel 	u16 oem_reg;
33198cfa0ad2SJack F Vogel 
33204edd8523SJack F Vogel 	DEBUGFUNC("e1000_set_lplu_state_pchlan");
33214edd8523SJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg);
33228cfa0ad2SJack F Vogel 	if (ret_val)
33236ab6bfe3SJack F Vogel 		return ret_val;
33248cfa0ad2SJack F Vogel 
33254edd8523SJack F Vogel 	if (active)
33264edd8523SJack F Vogel 		oem_reg |= HV_OEM_BITS_LPLU;
33274edd8523SJack F Vogel 	else
33284edd8523SJack F Vogel 		oem_reg &= ~HV_OEM_BITS_LPLU;
33298cfa0ad2SJack F Vogel 
33304dab5c37SJack F Vogel 	if (!hw->phy.ops.check_reset_block(hw))
33314edd8523SJack F Vogel 		oem_reg |= HV_OEM_BITS_RESTART_AN;
33324dab5c37SJack F Vogel 
33336ab6bfe3SJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg);
33348cfa0ad2SJack F Vogel }
33358cfa0ad2SJack F Vogel 
33368cfa0ad2SJack F Vogel /**
33378cfa0ad2SJack F Vogel  *  e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
33388cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
33398cfa0ad2SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
33408cfa0ad2SJack F Vogel  *
33418cfa0ad2SJack F Vogel  *  Sets the LPLU D0 state according to the active flag.  When
33428cfa0ad2SJack F Vogel  *  activating LPLU this function also disables smart speed
33438cfa0ad2SJack F Vogel  *  and vice versa.  LPLU will not be activated unless the
33448cfa0ad2SJack F Vogel  *  device autonegotiation advertisement meets standards of
33458cfa0ad2SJack F Vogel  *  either 10 or 10/100 or 10/100/1000 at all duplexes.
33468cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
33478cfa0ad2SJack F Vogel  *  PHY setup routines.
33488cfa0ad2SJack F Vogel  **/
3349daf9197cSJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
33508cfa0ad2SJack F Vogel {
33518cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
33528cfa0ad2SJack F Vogel 	u32 phy_ctrl;
33538cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
33548cfa0ad2SJack F Vogel 	u16 data;
33558cfa0ad2SJack F Vogel 
33568cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan");
33578cfa0ad2SJack F Vogel 
33588cfa0ad2SJack F Vogel 	if (phy->type == e1000_phy_ife)
33596ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
33608cfa0ad2SJack F Vogel 
33618cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
33628cfa0ad2SJack F Vogel 
33638cfa0ad2SJack F Vogel 	if (active) {
33648cfa0ad2SJack F Vogel 		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
33658cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
33668cfa0ad2SJack F Vogel 
33679d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
33686ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
33699d81738fSJack F Vogel 
33706ab6bfe3SJack F Vogel 		/* Call gig speed drop workaround on LPLU before accessing
33718cfa0ad2SJack F Vogel 		 * any PHY registers
33728cfa0ad2SJack F Vogel 		 */
33739d81738fSJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
33748cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
33758cfa0ad2SJack F Vogel 
33768cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
33778cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw,
33788cfa0ad2SJack F Vogel 					    IGP01E1000_PHY_PORT_CONFIG,
33798cfa0ad2SJack F Vogel 					    &data);
33806ab6bfe3SJack F Vogel 		if (ret_val)
33816ab6bfe3SJack F Vogel 			return ret_val;
33828cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
33838cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
33848cfa0ad2SJack F Vogel 					     IGP01E1000_PHY_PORT_CONFIG,
33858cfa0ad2SJack F Vogel 					     data);
33868cfa0ad2SJack F Vogel 		if (ret_val)
33876ab6bfe3SJack F Vogel 			return ret_val;
33888cfa0ad2SJack F Vogel 	} else {
33898cfa0ad2SJack F Vogel 		phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
33908cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
33918cfa0ad2SJack F Vogel 
33929d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
33936ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
33949d81738fSJack F Vogel 
33956ab6bfe3SJack F Vogel 		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
33968cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
33978cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
33988cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
33998cfa0ad2SJack F Vogel 		 */
34008cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
34018cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
34028cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
34038cfa0ad2SJack F Vogel 						    &data);
34048cfa0ad2SJack F Vogel 			if (ret_val)
34056ab6bfe3SJack F Vogel 				return ret_val;
34068cfa0ad2SJack F Vogel 
34078cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
34088cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
34098cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
34108cfa0ad2SJack F Vogel 						     data);
34118cfa0ad2SJack F Vogel 			if (ret_val)
34126ab6bfe3SJack F Vogel 				return ret_val;
34138cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
34148cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
34158cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
34168cfa0ad2SJack F Vogel 						    &data);
34178cfa0ad2SJack F Vogel 			if (ret_val)
34186ab6bfe3SJack F Vogel 				return ret_val;
34198cfa0ad2SJack F Vogel 
34208cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
34218cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
34228cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
34238cfa0ad2SJack F Vogel 						     data);
34248cfa0ad2SJack F Vogel 			if (ret_val)
34256ab6bfe3SJack F Vogel 				return ret_val;
34268cfa0ad2SJack F Vogel 		}
34278cfa0ad2SJack F Vogel 	}
34288cfa0ad2SJack F Vogel 
34296ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
34308cfa0ad2SJack F Vogel }
34318cfa0ad2SJack F Vogel 
34328cfa0ad2SJack F Vogel /**
34338cfa0ad2SJack F Vogel  *  e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
34348cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
34358cfa0ad2SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
34368cfa0ad2SJack F Vogel  *
34378cfa0ad2SJack F Vogel  *  Sets the LPLU D3 state according to the active flag.  When
34388cfa0ad2SJack F Vogel  *  activating LPLU this function also disables smart speed
34398cfa0ad2SJack F Vogel  *  and vice versa.  LPLU will not be activated unless the
34408cfa0ad2SJack F Vogel  *  device autonegotiation advertisement meets standards of
34418cfa0ad2SJack F Vogel  *  either 10 or 10/100 or 10/100/1000 at all duplexes.
34428cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
34438cfa0ad2SJack F Vogel  *  PHY setup routines.
34448cfa0ad2SJack F Vogel  **/
3445daf9197cSJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
34468cfa0ad2SJack F Vogel {
34478cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
34488cfa0ad2SJack F Vogel 	u32 phy_ctrl;
34498cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
34508cfa0ad2SJack F Vogel 	u16 data;
34518cfa0ad2SJack F Vogel 
34528cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan");
34538cfa0ad2SJack F Vogel 
34548cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
34558cfa0ad2SJack F Vogel 
34568cfa0ad2SJack F Vogel 	if (!active) {
34578cfa0ad2SJack F Vogel 		phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
34588cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
34599d81738fSJack F Vogel 
34609d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
34616ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
34629d81738fSJack F Vogel 
34636ab6bfe3SJack F Vogel 		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
34648cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
34658cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
34668cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
34678cfa0ad2SJack F Vogel 		 */
34688cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
34698cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
34708cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
34718cfa0ad2SJack F Vogel 						    &data);
34728cfa0ad2SJack F Vogel 			if (ret_val)
34736ab6bfe3SJack F Vogel 				return ret_val;
34748cfa0ad2SJack F Vogel 
34758cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
34768cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
34778cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
34788cfa0ad2SJack F Vogel 						     data);
34798cfa0ad2SJack F Vogel 			if (ret_val)
34806ab6bfe3SJack F Vogel 				return ret_val;
34818cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
34828cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
34838cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
34848cfa0ad2SJack F Vogel 						    &data);
34858cfa0ad2SJack F Vogel 			if (ret_val)
34866ab6bfe3SJack F Vogel 				return ret_val;
34878cfa0ad2SJack F Vogel 
34888cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
34898cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
34908cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
34918cfa0ad2SJack F Vogel 						     data);
34928cfa0ad2SJack F Vogel 			if (ret_val)
34936ab6bfe3SJack F Vogel 				return ret_val;
34948cfa0ad2SJack F Vogel 		}
34958cfa0ad2SJack F Vogel 	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
34968cfa0ad2SJack F Vogel 		   (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
34978cfa0ad2SJack F Vogel 		   (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
34988cfa0ad2SJack F Vogel 		phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
34998cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
35008cfa0ad2SJack F Vogel 
35019d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
35026ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
35039d81738fSJack F Vogel 
35046ab6bfe3SJack F Vogel 		/* Call gig speed drop workaround on LPLU before accessing
35058cfa0ad2SJack F Vogel 		 * any PHY registers
35068cfa0ad2SJack F Vogel 		 */
35079d81738fSJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
35088cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
35098cfa0ad2SJack F Vogel 
35108cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
35118cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw,
35128cfa0ad2SJack F Vogel 					    IGP01E1000_PHY_PORT_CONFIG,
35138cfa0ad2SJack F Vogel 					    &data);
35148cfa0ad2SJack F Vogel 		if (ret_val)
35156ab6bfe3SJack F Vogel 			return ret_val;
35168cfa0ad2SJack F Vogel 
35178cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
35188cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
35198cfa0ad2SJack F Vogel 					     IGP01E1000_PHY_PORT_CONFIG,
35208cfa0ad2SJack F Vogel 					     data);
35218cfa0ad2SJack F Vogel 	}
35228cfa0ad2SJack F Vogel 
35238cfa0ad2SJack F Vogel 	return ret_val;
35248cfa0ad2SJack F Vogel }
35258cfa0ad2SJack F Vogel 
35268cfa0ad2SJack F Vogel /**
35278cfa0ad2SJack F Vogel  *  e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
35288cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
35298cfa0ad2SJack F Vogel  *  @bank:  pointer to the variable that returns the active bank
35308cfa0ad2SJack F Vogel  *
35318cfa0ad2SJack F Vogel  *  Reads signature byte from the NVM using the flash access registers.
3532d035aa2dSJack F Vogel  *  Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
35338cfa0ad2SJack F Vogel  **/
35348cfa0ad2SJack F Vogel static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
35358cfa0ad2SJack F Vogel {
3536d035aa2dSJack F Vogel 	u32 eecd;
35378cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
35388cfa0ad2SJack F Vogel 	u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
35398cfa0ad2SJack F Vogel 	u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
3540c80429ceSEric Joyner 	u32 nvm_dword = 0;
3541d035aa2dSJack F Vogel 	u8 sig_byte = 0;
35426ab6bfe3SJack F Vogel 	s32 ret_val;
35438cfa0ad2SJack F Vogel 
35447d9119bdSJack F Vogel 	DEBUGFUNC("e1000_valid_nvm_bank_detect_ich8lan");
35457d9119bdSJack F Vogel 
3546d035aa2dSJack F Vogel 	switch (hw->mac.type) {
3547c80429ceSEric Joyner 	case e1000_pch_spt:
35486fe4c0a0SSean Bruno 	case e1000_pch_cnp:
354959690eabSKevin Bowling 	case e1000_pch_tgp:
355059690eabSKevin Bowling 	case e1000_pch_adp:
355159690eabSKevin Bowling 	case e1000_pch_mtp:
3552c80429ceSEric Joyner 		bank1_offset = nvm->flash_bank_size;
3553c80429ceSEric Joyner 		act_offset = E1000_ICH_NVM_SIG_WORD;
3554c80429ceSEric Joyner 
3555c80429ceSEric Joyner 		/* set bank to 0 in case flash read fails */
3556c80429ceSEric Joyner 		*bank = 0;
3557c80429ceSEric Joyner 
3558c80429ceSEric Joyner 		/* Check bank 0 */
3559c80429ceSEric Joyner 		ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset,
3560c80429ceSEric Joyner 							 &nvm_dword);
3561c80429ceSEric Joyner 		if (ret_val)
3562c80429ceSEric Joyner 			return ret_val;
3563c80429ceSEric Joyner 		sig_byte = (u8)((nvm_dword & 0xFF00) >> 8);
3564c80429ceSEric Joyner 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
3565c80429ceSEric Joyner 		    E1000_ICH_NVM_SIG_VALUE) {
3566c80429ceSEric Joyner 			*bank = 0;
3567c80429ceSEric Joyner 			return E1000_SUCCESS;
3568c80429ceSEric Joyner 		}
3569c80429ceSEric Joyner 
3570c80429ceSEric Joyner 		/* Check bank 1 */
3571c80429ceSEric Joyner 		ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset +
3572c80429ceSEric Joyner 							 bank1_offset,
3573c80429ceSEric Joyner 							 &nvm_dword);
3574c80429ceSEric Joyner 		if (ret_val)
3575c80429ceSEric Joyner 			return ret_val;
3576c80429ceSEric Joyner 		sig_byte = (u8)((nvm_dword & 0xFF00) >> 8);
3577c80429ceSEric Joyner 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
3578c80429ceSEric Joyner 		    E1000_ICH_NVM_SIG_VALUE) {
3579c80429ceSEric Joyner 			*bank = 1;
3580c80429ceSEric Joyner 			return E1000_SUCCESS;
3581c80429ceSEric Joyner 		}
3582c80429ceSEric Joyner 
3583c80429ceSEric Joyner 		DEBUGOUT("ERROR: No valid NVM bank present\n");
3584c80429ceSEric Joyner 		return -E1000_ERR_NVM;
3585d035aa2dSJack F Vogel 	case e1000_ich8lan:
3586d035aa2dSJack F Vogel 	case e1000_ich9lan:
3587d035aa2dSJack F Vogel 		eecd = E1000_READ_REG(hw, E1000_EECD);
3588d035aa2dSJack F Vogel 		if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
3589d035aa2dSJack F Vogel 		    E1000_EECD_SEC1VAL_VALID_MASK) {
3590d035aa2dSJack F Vogel 			if (eecd & E1000_EECD_SEC1VAL)
35918cfa0ad2SJack F Vogel 				*bank = 1;
35928cfa0ad2SJack F Vogel 			else
35938cfa0ad2SJack F Vogel 				*bank = 0;
3594d035aa2dSJack F Vogel 
35956ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
3596d035aa2dSJack F Vogel 		}
35974dab5c37SJack F Vogel 		DEBUGOUT("Unable to determine valid NVM bank via EEC - reading flash signature\n");
3598d035aa2dSJack F Vogel 		/* fall-thru */
3599d035aa2dSJack F Vogel 	default:
3600d035aa2dSJack F Vogel 		/* set bank to 0 in case flash read fails */
36018cfa0ad2SJack F Vogel 		*bank = 0;
36028cfa0ad2SJack F Vogel 
3603d035aa2dSJack F Vogel 		/* Check bank 0 */
3604d035aa2dSJack F Vogel 		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
3605d035aa2dSJack F Vogel 							&sig_byte);
3606d035aa2dSJack F Vogel 		if (ret_val)
36076ab6bfe3SJack F Vogel 			return ret_val;
3608d035aa2dSJack F Vogel 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
3609d035aa2dSJack F Vogel 		    E1000_ICH_NVM_SIG_VALUE) {
3610d035aa2dSJack F Vogel 			*bank = 0;
36116ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
3612d035aa2dSJack F Vogel 		}
3613d035aa2dSJack F Vogel 
3614d035aa2dSJack F Vogel 		/* Check bank 1 */
3615d035aa2dSJack F Vogel 		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
3616d035aa2dSJack F Vogel 							bank1_offset,
3617d035aa2dSJack F Vogel 							&sig_byte);
3618d035aa2dSJack F Vogel 		if (ret_val)
36196ab6bfe3SJack F Vogel 			return ret_val;
3620d035aa2dSJack F Vogel 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
3621d035aa2dSJack F Vogel 		    E1000_ICH_NVM_SIG_VALUE) {
36228cfa0ad2SJack F Vogel 			*bank = 1;
36236ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
36248cfa0ad2SJack F Vogel 		}
36258cfa0ad2SJack F Vogel 
3626d035aa2dSJack F Vogel 		DEBUGOUT("ERROR: No valid NVM bank present\n");
36276ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
3628d035aa2dSJack F Vogel 	}
36298cfa0ad2SJack F Vogel }
36308cfa0ad2SJack F Vogel 
36318cfa0ad2SJack F Vogel /**
3632c80429ceSEric Joyner  *  e1000_read_nvm_spt - NVM access for SPT
3633c80429ceSEric Joyner  *  @hw: pointer to the HW structure
3634c80429ceSEric Joyner  *  @offset: The offset (in bytes) of the word(s) to read.
3635c80429ceSEric Joyner  *  @words: Size of data to read in words.
3636c80429ceSEric Joyner  *  @data: pointer to the word(s) to read at offset.
3637c80429ceSEric Joyner  *
3638c80429ceSEric Joyner  *  Reads a word(s) from the NVM
3639c80429ceSEric Joyner  **/
3640c80429ceSEric Joyner static s32 e1000_read_nvm_spt(struct e1000_hw *hw, u16 offset, u16 words,
3641c80429ceSEric Joyner 			      u16 *data)
3642c80429ceSEric Joyner {
3643c80429ceSEric Joyner 	struct e1000_nvm_info *nvm = &hw->nvm;
3644c80429ceSEric Joyner 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
3645c80429ceSEric Joyner 	u32 act_offset;
3646c80429ceSEric Joyner 	s32 ret_val = E1000_SUCCESS;
3647c80429ceSEric Joyner 	u32 bank = 0;
3648c80429ceSEric Joyner 	u32 dword = 0;
3649c80429ceSEric Joyner 	u16 offset_to_read;
3650c80429ceSEric Joyner 	u16 i;
3651c80429ceSEric Joyner 
3652c80429ceSEric Joyner 	DEBUGFUNC("e1000_read_nvm_spt");
3653c80429ceSEric Joyner 
3654c80429ceSEric Joyner 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
3655c80429ceSEric Joyner 	    (words == 0)) {
3656c80429ceSEric Joyner 		DEBUGOUT("nvm parameter(s) out of bounds\n");
3657c80429ceSEric Joyner 		ret_val = -E1000_ERR_NVM;
3658c80429ceSEric Joyner 		goto out;
3659c80429ceSEric Joyner 	}
3660c80429ceSEric Joyner 
3661c80429ceSEric Joyner 	nvm->ops.acquire(hw);
3662c80429ceSEric Joyner 
3663c80429ceSEric Joyner 	ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
3664c80429ceSEric Joyner 	if (ret_val != E1000_SUCCESS) {
3665c80429ceSEric Joyner 		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
3666c80429ceSEric Joyner 		bank = 0;
3667c80429ceSEric Joyner 	}
3668c80429ceSEric Joyner 
3669c80429ceSEric Joyner 	act_offset = (bank) ? nvm->flash_bank_size : 0;
3670c80429ceSEric Joyner 	act_offset += offset;
3671c80429ceSEric Joyner 
3672c80429ceSEric Joyner 	ret_val = E1000_SUCCESS;
3673c80429ceSEric Joyner 
3674c80429ceSEric Joyner 	for (i = 0; i < words; i += 2) {
3675c80429ceSEric Joyner 		if (words - i == 1) {
3676c80429ceSEric Joyner 			if (dev_spec->shadow_ram[offset+i].modified) {
3677c80429ceSEric Joyner 				data[i] = dev_spec->shadow_ram[offset+i].value;
3678c80429ceSEric Joyner 			} else {
3679c80429ceSEric Joyner 				offset_to_read = act_offset + i -
3680c80429ceSEric Joyner 						 ((act_offset + i) % 2);
3681c80429ceSEric Joyner 				ret_val =
3682c80429ceSEric Joyner 				   e1000_read_flash_dword_ich8lan(hw,
3683c80429ceSEric Joyner 								 offset_to_read,
3684c80429ceSEric Joyner 								 &dword);
3685c80429ceSEric Joyner 				if (ret_val)
3686c80429ceSEric Joyner 					break;
3687c80429ceSEric Joyner 				if ((act_offset + i) % 2 == 0)
3688c80429ceSEric Joyner 					data[i] = (u16)(dword & 0xFFFF);
3689c80429ceSEric Joyner 				else
3690c80429ceSEric Joyner 					data[i] = (u16)((dword >> 16) & 0xFFFF);
3691c80429ceSEric Joyner 			}
3692c80429ceSEric Joyner 		} else {
3693c80429ceSEric Joyner 			offset_to_read = act_offset + i;
3694c80429ceSEric Joyner 			if (!(dev_spec->shadow_ram[offset+i].modified) ||
3695c80429ceSEric Joyner 			    !(dev_spec->shadow_ram[offset+i+1].modified)) {
3696c80429ceSEric Joyner 				ret_val =
3697c80429ceSEric Joyner 				   e1000_read_flash_dword_ich8lan(hw,
3698c80429ceSEric Joyner 								 offset_to_read,
3699c80429ceSEric Joyner 								 &dword);
3700c80429ceSEric Joyner 				if (ret_val)
3701c80429ceSEric Joyner 					break;
3702c80429ceSEric Joyner 			}
3703c80429ceSEric Joyner 			if (dev_spec->shadow_ram[offset+i].modified)
3704c80429ceSEric Joyner 				data[i] = dev_spec->shadow_ram[offset+i].value;
3705c80429ceSEric Joyner 			else
3706c80429ceSEric Joyner 				data[i] = (u16) (dword & 0xFFFF);
3707c80429ceSEric Joyner 			if (dev_spec->shadow_ram[offset+i].modified)
3708c80429ceSEric Joyner 				data[i+1] =
3709c80429ceSEric Joyner 				   dev_spec->shadow_ram[offset+i+1].value;
3710c80429ceSEric Joyner 			else
3711c80429ceSEric Joyner 				data[i+1] = (u16) (dword >> 16 & 0xFFFF);
3712c80429ceSEric Joyner 		}
3713c80429ceSEric Joyner 	}
3714c80429ceSEric Joyner 
3715c80429ceSEric Joyner 	nvm->ops.release(hw);
3716c80429ceSEric Joyner 
3717c80429ceSEric Joyner out:
3718c80429ceSEric Joyner 	if (ret_val)
3719c80429ceSEric Joyner 		DEBUGOUT1("NVM read error: %d\n", ret_val);
3720c80429ceSEric Joyner 
3721c80429ceSEric Joyner 	return ret_val;
3722c80429ceSEric Joyner }
3723c80429ceSEric Joyner 
3724c80429ceSEric Joyner /**
37258cfa0ad2SJack F Vogel  *  e1000_read_nvm_ich8lan - Read word(s) from the NVM
37268cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
37278cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the word(s) to read.
37288cfa0ad2SJack F Vogel  *  @words: Size of data to read in words
37298cfa0ad2SJack F Vogel  *  @data: Pointer to the word(s) to read at offset.
37308cfa0ad2SJack F Vogel  *
37318cfa0ad2SJack F Vogel  *  Reads a word(s) from the NVM using the flash access registers.
37328cfa0ad2SJack F Vogel  **/
37338cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
37348cfa0ad2SJack F Vogel 				  u16 *data)
37358cfa0ad2SJack F Vogel {
37368cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
3737daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
37388cfa0ad2SJack F Vogel 	u32 act_offset;
37398cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
37408cfa0ad2SJack F Vogel 	u32 bank = 0;
37418cfa0ad2SJack F Vogel 	u16 i, word;
37428cfa0ad2SJack F Vogel 
37438cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_nvm_ich8lan");
37448cfa0ad2SJack F Vogel 
37458cfa0ad2SJack F Vogel 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
37468cfa0ad2SJack F Vogel 	    (words == 0)) {
37478cfa0ad2SJack F Vogel 		DEBUGOUT("nvm parameter(s) out of bounds\n");
37488cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
37498cfa0ad2SJack F Vogel 		goto out;
37508cfa0ad2SJack F Vogel 	}
37518cfa0ad2SJack F Vogel 
37524edd8523SJack F Vogel 	nvm->ops.acquire(hw);
37538cfa0ad2SJack F Vogel 
37548cfa0ad2SJack F Vogel 	ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
37554edd8523SJack F Vogel 	if (ret_val != E1000_SUCCESS) {
37564edd8523SJack F Vogel 		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
37574edd8523SJack F Vogel 		bank = 0;
37584edd8523SJack F Vogel 	}
37598cfa0ad2SJack F Vogel 
37608cfa0ad2SJack F Vogel 	act_offset = (bank) ? nvm->flash_bank_size : 0;
37618cfa0ad2SJack F Vogel 	act_offset += offset;
37628cfa0ad2SJack F Vogel 
37634edd8523SJack F Vogel 	ret_val = E1000_SUCCESS;
37648cfa0ad2SJack F Vogel 	for (i = 0; i < words; i++) {
37654dab5c37SJack F Vogel 		if (dev_spec->shadow_ram[offset+i].modified) {
37668cfa0ad2SJack F Vogel 			data[i] = dev_spec->shadow_ram[offset+i].value;
37678cfa0ad2SJack F Vogel 		} else {
37688cfa0ad2SJack F Vogel 			ret_val = e1000_read_flash_word_ich8lan(hw,
37698cfa0ad2SJack F Vogel 								act_offset + i,
37708cfa0ad2SJack F Vogel 								&word);
37718cfa0ad2SJack F Vogel 			if (ret_val)
37728cfa0ad2SJack F Vogel 				break;
37738cfa0ad2SJack F Vogel 			data[i] = word;
37748cfa0ad2SJack F Vogel 		}
37758cfa0ad2SJack F Vogel 	}
37768cfa0ad2SJack F Vogel 
37778cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
37788cfa0ad2SJack F Vogel 
37798cfa0ad2SJack F Vogel out:
3780d035aa2dSJack F Vogel 	if (ret_val)
3781d035aa2dSJack F Vogel 		DEBUGOUT1("NVM read error: %d\n", ret_val);
3782d035aa2dSJack F Vogel 
37838cfa0ad2SJack F Vogel 	return ret_val;
37848cfa0ad2SJack F Vogel }
37858cfa0ad2SJack F Vogel 
37868cfa0ad2SJack F Vogel /**
37878cfa0ad2SJack F Vogel  *  e1000_flash_cycle_init_ich8lan - Initialize flash
37888cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
37898cfa0ad2SJack F Vogel  *
37908cfa0ad2SJack F Vogel  *  This function does initial flash setup so that a new read/write/erase cycle
37918cfa0ad2SJack F Vogel  *  can be started.
37928cfa0ad2SJack F Vogel  **/
37938cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
37948cfa0ad2SJack F Vogel {
37958cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
37968cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
37978cfa0ad2SJack F Vogel 
37988cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_flash_cycle_init_ich8lan");
37998cfa0ad2SJack F Vogel 
38008cfa0ad2SJack F Vogel 	hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
38018cfa0ad2SJack F Vogel 
38028cfa0ad2SJack F Vogel 	/* Check if the flash descriptor is valid */
38036ab6bfe3SJack F Vogel 	if (!hsfsts.hsf_status.fldesvalid) {
38044dab5c37SJack F Vogel 		DEBUGOUT("Flash descriptor invalid.  SW Sequencing must be used.\n");
38056ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
38068cfa0ad2SJack F Vogel 	}
38078cfa0ad2SJack F Vogel 
38088cfa0ad2SJack F Vogel 	/* Clear FCERR and DAEL in hw status by writing 1 */
38098cfa0ad2SJack F Vogel 	hsfsts.hsf_status.flcerr = 1;
38108cfa0ad2SJack F Vogel 	hsfsts.hsf_status.dael = 1;
3811295df609SEric Joyner 	if (hw->mac.type >= e1000_pch_spt)
3812c80429ceSEric Joyner 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
3813c80429ceSEric Joyner 				      hsfsts.regval & 0xFFFF);
3814c80429ceSEric Joyner 	else
38158cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
38168cfa0ad2SJack F Vogel 
38176ab6bfe3SJack F Vogel 	/* Either we should have a hardware SPI cycle in progress
38188cfa0ad2SJack F Vogel 	 * bit to check against, in order to start a new cycle or
38198cfa0ad2SJack F Vogel 	 * FDONE bit should be changed in the hardware so that it
38208cfa0ad2SJack F Vogel 	 * is 1 after hardware reset, which can then be used as an
38218cfa0ad2SJack F Vogel 	 * indication whether a cycle is in progress or has been
38228cfa0ad2SJack F Vogel 	 * completed.
38238cfa0ad2SJack F Vogel 	 */
38248cfa0ad2SJack F Vogel 
38256ab6bfe3SJack F Vogel 	if (!hsfsts.hsf_status.flcinprog) {
38266ab6bfe3SJack F Vogel 		/* There is no cycle running at present,
38278cfa0ad2SJack F Vogel 		 * so we can start a cycle.
38288cfa0ad2SJack F Vogel 		 * Begin by setting Flash Cycle Done.
38298cfa0ad2SJack F Vogel 		 */
38308cfa0ad2SJack F Vogel 		hsfsts.hsf_status.flcdone = 1;
3831295df609SEric Joyner 		if (hw->mac.type >= e1000_pch_spt)
3832c80429ceSEric Joyner 			E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
3833c80429ceSEric Joyner 					      hsfsts.regval & 0xFFFF);
3834c80429ceSEric Joyner 		else
3835c80429ceSEric Joyner 			E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
3836c80429ceSEric Joyner 						hsfsts.regval);
38378cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
38388cfa0ad2SJack F Vogel 	} else {
3839730d3130SJack F Vogel 		s32 i;
3840730d3130SJack F Vogel 
38416ab6bfe3SJack F Vogel 		/* Otherwise poll for sometime so the current
38428cfa0ad2SJack F Vogel 		 * cycle has a chance to end before giving up.
38438cfa0ad2SJack F Vogel 		 */
38448cfa0ad2SJack F Vogel 		for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
38458cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
38468cfa0ad2SJack F Vogel 							      ICH_FLASH_HSFSTS);
38476ab6bfe3SJack F Vogel 			if (!hsfsts.hsf_status.flcinprog) {
38488cfa0ad2SJack F Vogel 				ret_val = E1000_SUCCESS;
38498cfa0ad2SJack F Vogel 				break;
38508cfa0ad2SJack F Vogel 			}
38518cfa0ad2SJack F Vogel 			usec_delay(1);
38528cfa0ad2SJack F Vogel 		}
38538cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS) {
38546ab6bfe3SJack F Vogel 			/* Successful in waiting for previous cycle to timeout,
38558cfa0ad2SJack F Vogel 			 * now set the Flash Cycle Done.
38568cfa0ad2SJack F Vogel 			 */
38578cfa0ad2SJack F Vogel 			hsfsts.hsf_status.flcdone = 1;
3858295df609SEric Joyner 			if (hw->mac.type >= e1000_pch_spt)
3859c80429ceSEric Joyner 				E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
3860c80429ceSEric Joyner 						      hsfsts.regval & 0xFFFF);
3861c80429ceSEric Joyner 			else
3862daf9197cSJack F Vogel 				E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
38638cfa0ad2SJack F Vogel 							hsfsts.regval);
38648cfa0ad2SJack F Vogel 		} else {
38654dab5c37SJack F Vogel 			DEBUGOUT("Flash controller busy, cannot get access\n");
38668cfa0ad2SJack F Vogel 		}
38678cfa0ad2SJack F Vogel 	}
38688cfa0ad2SJack F Vogel 
38698cfa0ad2SJack F Vogel 	return ret_val;
38708cfa0ad2SJack F Vogel }
38718cfa0ad2SJack F Vogel 
38728cfa0ad2SJack F Vogel /**
38738cfa0ad2SJack F Vogel  *  e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
38748cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
38758cfa0ad2SJack F Vogel  *  @timeout: maximum time to wait for completion
38768cfa0ad2SJack F Vogel  *
38778cfa0ad2SJack F Vogel  *  This function starts a flash cycle and waits for its completion.
38788cfa0ad2SJack F Vogel  **/
38798cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
38808cfa0ad2SJack F Vogel {
38818cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
38828cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
38838cfa0ad2SJack F Vogel 	u32 i = 0;
38848cfa0ad2SJack F Vogel 
38858cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_flash_cycle_ich8lan");
38868cfa0ad2SJack F Vogel 
38878cfa0ad2SJack F Vogel 	/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
3888295df609SEric Joyner 	if (hw->mac.type >= e1000_pch_spt)
3889c80429ceSEric Joyner 		hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16;
3890c80429ceSEric Joyner 	else
38918cfa0ad2SJack F Vogel 		hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
38928cfa0ad2SJack F Vogel 	hsflctl.hsf_ctrl.flcgo = 1;
38938cc64f1eSJack F Vogel 
3894295df609SEric Joyner 	if (hw->mac.type >= e1000_pch_spt)
3895c80429ceSEric Joyner 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
3896c80429ceSEric Joyner 				      hsflctl.regval << 16);
3897c80429ceSEric Joyner 	else
38988cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
38998cfa0ad2SJack F Vogel 
39008cfa0ad2SJack F Vogel 	/* wait till FDONE bit is set to 1 */
39018cfa0ad2SJack F Vogel 	do {
39028cfa0ad2SJack F Vogel 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
39036ab6bfe3SJack F Vogel 		if (hsfsts.hsf_status.flcdone)
39048cfa0ad2SJack F Vogel 			break;
39058cfa0ad2SJack F Vogel 		usec_delay(1);
39068cfa0ad2SJack F Vogel 	} while (i++ < timeout);
39078cfa0ad2SJack F Vogel 
39086ab6bfe3SJack F Vogel 	if (hsfsts.hsf_status.flcdone && !hsfsts.hsf_status.flcerr)
39096ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
39108cfa0ad2SJack F Vogel 
39116ab6bfe3SJack F Vogel 	return -E1000_ERR_NVM;
39128cfa0ad2SJack F Vogel }
39138cfa0ad2SJack F Vogel 
39148cfa0ad2SJack F Vogel /**
3915c80429ceSEric Joyner  *  e1000_read_flash_dword_ich8lan - Read dword from flash
3916c80429ceSEric Joyner  *  @hw: pointer to the HW structure
3917c80429ceSEric Joyner  *  @offset: offset to data location
3918c80429ceSEric Joyner  *  @data: pointer to the location for storing the data
3919c80429ceSEric Joyner  *
3920c80429ceSEric Joyner  *  Reads the flash dword at offset into data.  Offset is converted
3921c80429ceSEric Joyner  *  to bytes before read.
3922c80429ceSEric Joyner  **/
3923c80429ceSEric Joyner static s32 e1000_read_flash_dword_ich8lan(struct e1000_hw *hw, u32 offset,
3924c80429ceSEric Joyner 					  u32 *data)
3925c80429ceSEric Joyner {
3926c80429ceSEric Joyner 	DEBUGFUNC("e1000_read_flash_dword_ich8lan");
3927c80429ceSEric Joyner 
3928c80429ceSEric Joyner 	if (!data)
3929c80429ceSEric Joyner 		return -E1000_ERR_NVM;
3930c80429ceSEric Joyner 
3931c80429ceSEric Joyner 	/* Must convert word offset into bytes. */
3932c80429ceSEric Joyner 	offset <<= 1;
3933c80429ceSEric Joyner 
3934c80429ceSEric Joyner 	return e1000_read_flash_data32_ich8lan(hw, offset, data);
3935c80429ceSEric Joyner }
3936c80429ceSEric Joyner 
3937c80429ceSEric Joyner /**
39388cfa0ad2SJack F Vogel  *  e1000_read_flash_word_ich8lan - Read word from flash
39398cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
39408cfa0ad2SJack F Vogel  *  @offset: offset to data location
39418cfa0ad2SJack F Vogel  *  @data: pointer to the location for storing the data
39428cfa0ad2SJack F Vogel  *
39438cfa0ad2SJack F Vogel  *  Reads the flash word at offset into data.  Offset is converted
39448cfa0ad2SJack F Vogel  *  to bytes before read.
39458cfa0ad2SJack F Vogel  **/
39468cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
39478cfa0ad2SJack F Vogel 					 u16 *data)
39488cfa0ad2SJack F Vogel {
39498cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_flash_word_ich8lan");
39508cfa0ad2SJack F Vogel 
39516ab6bfe3SJack F Vogel 	if (!data)
39526ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
39538cfa0ad2SJack F Vogel 
39548cfa0ad2SJack F Vogel 	/* Must convert offset into bytes. */
39558cfa0ad2SJack F Vogel 	offset <<= 1;
39568cfa0ad2SJack F Vogel 
39576ab6bfe3SJack F Vogel 	return e1000_read_flash_data_ich8lan(hw, offset, 2, data);
39588cfa0ad2SJack F Vogel }
39598cfa0ad2SJack F Vogel 
39608cfa0ad2SJack F Vogel /**
39618cfa0ad2SJack F Vogel  *  e1000_read_flash_byte_ich8lan - Read byte from flash
39628cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
39638cfa0ad2SJack F Vogel  *  @offset: The offset of the byte to read.
39648cfa0ad2SJack F Vogel  *  @data: Pointer to a byte to store the value read.
39658cfa0ad2SJack F Vogel  *
39668cfa0ad2SJack F Vogel  *  Reads a single byte from the NVM using the flash access registers.
39678cfa0ad2SJack F Vogel  **/
39688cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
39698cfa0ad2SJack F Vogel 					 u8 *data)
39708cfa0ad2SJack F Vogel {
39716ab6bfe3SJack F Vogel 	s32 ret_val;
39728cfa0ad2SJack F Vogel 	u16 word = 0;
39738cfa0ad2SJack F Vogel 
3974c80429ceSEric Joyner 	/* In SPT, only 32 bits access is supported,
3975c80429ceSEric Joyner 	 * so this function should not be called.
3976c80429ceSEric Joyner 	 */
3977295df609SEric Joyner 	if (hw->mac.type >= e1000_pch_spt)
3978c80429ceSEric Joyner 		return -E1000_ERR_NVM;
3979c80429ceSEric Joyner 	else
39808cfa0ad2SJack F Vogel 		ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
39818cc64f1eSJack F Vogel 
39828cfa0ad2SJack F Vogel 	if (ret_val)
39836ab6bfe3SJack F Vogel 		return ret_val;
39848cfa0ad2SJack F Vogel 
39858cfa0ad2SJack F Vogel 	*data = (u8)word;
39868cfa0ad2SJack F Vogel 
39876ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
39888cfa0ad2SJack F Vogel }
39898cfa0ad2SJack F Vogel 
39908cfa0ad2SJack F Vogel /**
39918cfa0ad2SJack F Vogel  *  e1000_read_flash_data_ich8lan - Read byte or word from NVM
39928cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
39938cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the byte or word to read.
39948cfa0ad2SJack F Vogel  *  @size: Size of data to read, 1=byte 2=word
39958cfa0ad2SJack F Vogel  *  @data: Pointer to the word to store the value read.
39968cfa0ad2SJack F Vogel  *
39978cfa0ad2SJack F Vogel  *  Reads a byte or word from the NVM using the flash access registers.
39988cfa0ad2SJack F Vogel  **/
39998cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
40008cfa0ad2SJack F Vogel 					 u8 size, u16 *data)
40018cfa0ad2SJack F Vogel {
40028cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
40038cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
40048cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
40058cfa0ad2SJack F Vogel 	u32 flash_data = 0;
40068cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
40078cfa0ad2SJack F Vogel 	u8 count = 0;
40088cfa0ad2SJack F Vogel 
40098cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_flash_data_ich8lan");
40108cfa0ad2SJack F Vogel 
40118cfa0ad2SJack F Vogel 	if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
40126ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
40137609433eSJack F Vogel 	flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
40147609433eSJack F Vogel 			     hw->nvm.flash_base_addr);
40158cfa0ad2SJack F Vogel 
40168cfa0ad2SJack F Vogel 	do {
40178cfa0ad2SJack F Vogel 		usec_delay(1);
40188cfa0ad2SJack F Vogel 		/* Steps */
40198cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
40208cfa0ad2SJack F Vogel 		if (ret_val != E1000_SUCCESS)
40218cfa0ad2SJack F Vogel 			break;
40228cfa0ad2SJack F Vogel 		hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
40238cc64f1eSJack F Vogel 
40248cfa0ad2SJack F Vogel 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
40258cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.fldbcount = size - 1;
40268cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
40278cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
40288cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
40298cfa0ad2SJack F Vogel 
40308cc64f1eSJack F Vogel 		ret_val = e1000_flash_cycle_ich8lan(hw,
40318cfa0ad2SJack F Vogel 						ICH_FLASH_READ_COMMAND_TIMEOUT);
40328cfa0ad2SJack F Vogel 
40336ab6bfe3SJack F Vogel 		/* Check if FCERR is set to 1, if set to 1, clear it
40348cfa0ad2SJack F Vogel 		 * and try the whole sequence a few more times, else
40358cfa0ad2SJack F Vogel 		 * read in (shift in) the Flash Data0, the order is
40368cfa0ad2SJack F Vogel 		 * least significant byte first msb to lsb
40378cfa0ad2SJack F Vogel 		 */
40388cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS) {
40398cfa0ad2SJack F Vogel 			flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
4040daf9197cSJack F Vogel 			if (size == 1)
40418cfa0ad2SJack F Vogel 				*data = (u8)(flash_data & 0x000000FF);
4042daf9197cSJack F Vogel 			else if (size == 2)
40438cfa0ad2SJack F Vogel 				*data = (u16)(flash_data & 0x0000FFFF);
40448cfa0ad2SJack F Vogel 			break;
40458cfa0ad2SJack F Vogel 		} else {
40466ab6bfe3SJack F Vogel 			/* If we've gotten here, then things are probably
40478cfa0ad2SJack F Vogel 			 * completely hosed, but if the error condition is
40488cfa0ad2SJack F Vogel 			 * detected, it won't hurt to give it another try...
40498cfa0ad2SJack F Vogel 			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
40508cfa0ad2SJack F Vogel 			 */
40518cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
40528cfa0ad2SJack F Vogel 							      ICH_FLASH_HSFSTS);
40536ab6bfe3SJack F Vogel 			if (hsfsts.hsf_status.flcerr) {
40548cfa0ad2SJack F Vogel 				/* Repeat for some time before giving up. */
40558cfa0ad2SJack F Vogel 				continue;
40566ab6bfe3SJack F Vogel 			} else if (!hsfsts.hsf_status.flcdone) {
40574dab5c37SJack F Vogel 				DEBUGOUT("Timeout error - flash cycle did not complete.\n");
40588cfa0ad2SJack F Vogel 				break;
40598cfa0ad2SJack F Vogel 			}
40608cfa0ad2SJack F Vogel 		}
40618cfa0ad2SJack F Vogel 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
40628cfa0ad2SJack F Vogel 
40638cfa0ad2SJack F Vogel 	return ret_val;
40648cfa0ad2SJack F Vogel }
40658cfa0ad2SJack F Vogel 
4066c80429ceSEric Joyner /**
4067c80429ceSEric Joyner  *  e1000_read_flash_data32_ich8lan - Read dword from NVM
4068c80429ceSEric Joyner  *  @hw: pointer to the HW structure
4069c80429ceSEric Joyner  *  @offset: The offset (in bytes) of the dword to read.
4070c80429ceSEric Joyner  *  @data: Pointer to the dword to store the value read.
4071c80429ceSEric Joyner  *
4072c80429ceSEric Joyner  *  Reads a byte or word from the NVM using the flash access registers.
4073c80429ceSEric Joyner  **/
4074c80429ceSEric Joyner static s32 e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
4075c80429ceSEric Joyner 					   u32 *data)
4076c80429ceSEric Joyner {
4077c80429ceSEric Joyner 	union ich8_hws_flash_status hsfsts;
4078c80429ceSEric Joyner 	union ich8_hws_flash_ctrl hsflctl;
4079c80429ceSEric Joyner 	u32 flash_linear_addr;
4080c80429ceSEric Joyner 	s32 ret_val = -E1000_ERR_NVM;
4081c80429ceSEric Joyner 	u8 count = 0;
4082c80429ceSEric Joyner 
4083c80429ceSEric Joyner 	DEBUGFUNC("e1000_read_flash_data_ich8lan");
4084c80429ceSEric Joyner 
4085c80429ceSEric Joyner 		if (offset > ICH_FLASH_LINEAR_ADDR_MASK ||
4086295df609SEric Joyner 		    hw->mac.type < e1000_pch_spt)
4087c80429ceSEric Joyner 			return -E1000_ERR_NVM;
4088c80429ceSEric Joyner 	flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
4089c80429ceSEric Joyner 			     hw->nvm.flash_base_addr);
4090c80429ceSEric Joyner 
4091c80429ceSEric Joyner 	do {
4092c80429ceSEric Joyner 		usec_delay(1);
4093c80429ceSEric Joyner 		/* Steps */
4094c80429ceSEric Joyner 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
4095c80429ceSEric Joyner 		if (ret_val != E1000_SUCCESS)
4096c80429ceSEric Joyner 			break;
4097c80429ceSEric Joyner 		/* In SPT, This register is in Lan memory space, not flash.
4098c80429ceSEric Joyner 		 * Therefore, only 32 bit access is supported
4099c80429ceSEric Joyner 		 */
4100c80429ceSEric Joyner 		hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16;
4101c80429ceSEric Joyner 
4102c80429ceSEric Joyner 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
4103c80429ceSEric Joyner 		hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1;
4104c80429ceSEric Joyner 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
4105c80429ceSEric Joyner 		/* In SPT, This register is in Lan memory space, not flash.
4106c80429ceSEric Joyner 		 * Therefore, only 32 bit access is supported
4107c80429ceSEric Joyner 		 */
4108c80429ceSEric Joyner 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
4109c80429ceSEric Joyner 				      (u32)hsflctl.regval << 16);
4110c80429ceSEric Joyner 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
4111c80429ceSEric Joyner 
4112c80429ceSEric Joyner 		ret_val = e1000_flash_cycle_ich8lan(hw,
4113c80429ceSEric Joyner 						ICH_FLASH_READ_COMMAND_TIMEOUT);
4114c80429ceSEric Joyner 
4115c80429ceSEric Joyner 		/* Check if FCERR is set to 1, if set to 1, clear it
4116c80429ceSEric Joyner 		 * and try the whole sequence a few more times, else
4117c80429ceSEric Joyner 		 * read in (shift in) the Flash Data0, the order is
4118c80429ceSEric Joyner 		 * least significant byte first msb to lsb
4119c80429ceSEric Joyner 		 */
4120c80429ceSEric Joyner 		if (ret_val == E1000_SUCCESS) {
4121c80429ceSEric Joyner 			*data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
4122c80429ceSEric Joyner 			break;
4123c80429ceSEric Joyner 		} else {
4124c80429ceSEric Joyner 			/* If we've gotten here, then things are probably
4125c80429ceSEric Joyner 			 * completely hosed, but if the error condition is
4126c80429ceSEric Joyner 			 * detected, it won't hurt to give it another try...
4127c80429ceSEric Joyner 			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
4128c80429ceSEric Joyner 			 */
4129c80429ceSEric Joyner 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
4130c80429ceSEric Joyner 							      ICH_FLASH_HSFSTS);
4131c80429ceSEric Joyner 			if (hsfsts.hsf_status.flcerr) {
4132c80429ceSEric Joyner 				/* Repeat for some time before giving up. */
4133c80429ceSEric Joyner 				continue;
4134c80429ceSEric Joyner 			} else if (!hsfsts.hsf_status.flcdone) {
4135c80429ceSEric Joyner 				DEBUGOUT("Timeout error - flash cycle did not complete.\n");
4136c80429ceSEric Joyner 				break;
4137c80429ceSEric Joyner 			}
4138c80429ceSEric Joyner 		}
4139c80429ceSEric Joyner 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
4140c80429ceSEric Joyner 
4141c80429ceSEric Joyner 	return ret_val;
4142c80429ceSEric Joyner }
41438cc64f1eSJack F Vogel 
41448cfa0ad2SJack F Vogel /**
41458cfa0ad2SJack F Vogel  *  e1000_write_nvm_ich8lan - Write word(s) to the NVM
41468cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
41478cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the word(s) to write.
41488cfa0ad2SJack F Vogel  *  @words: Size of data to write in words
41498cfa0ad2SJack F Vogel  *  @data: Pointer to the word(s) to write at offset.
41508cfa0ad2SJack F Vogel  *
41518cfa0ad2SJack F Vogel  *  Writes a byte or word to the NVM using the flash access registers.
41528cfa0ad2SJack F Vogel  **/
41538cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
41548cfa0ad2SJack F Vogel 				   u16 *data)
41558cfa0ad2SJack F Vogel {
41568cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
4157daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
41588cfa0ad2SJack F Vogel 	u16 i;
41598cfa0ad2SJack F Vogel 
41608cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_nvm_ich8lan");
41618cfa0ad2SJack F Vogel 
41628cfa0ad2SJack F Vogel 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
41638cfa0ad2SJack F Vogel 	    (words == 0)) {
41648cfa0ad2SJack F Vogel 		DEBUGOUT("nvm parameter(s) out of bounds\n");
41656ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
41668cfa0ad2SJack F Vogel 	}
41678cfa0ad2SJack F Vogel 
41684edd8523SJack F Vogel 	nvm->ops.acquire(hw);
41698cfa0ad2SJack F Vogel 
41708cfa0ad2SJack F Vogel 	for (i = 0; i < words; i++) {
41718cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[offset+i].modified = TRUE;
41728cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[offset+i].value = data[i];
41738cfa0ad2SJack F Vogel 	}
41748cfa0ad2SJack F Vogel 
41758cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
41768cfa0ad2SJack F Vogel 
41776ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
41788cfa0ad2SJack F Vogel }
41798cfa0ad2SJack F Vogel 
41808cfa0ad2SJack F Vogel /**
4181c80429ceSEric Joyner  *  e1000_update_nvm_checksum_spt - Update the checksum for NVM
4182c80429ceSEric Joyner  *  @hw: pointer to the HW structure
4183c80429ceSEric Joyner  *
4184c80429ceSEric Joyner  *  The NVM checksum is updated by calling the generic update_nvm_checksum,
4185c80429ceSEric Joyner  *  which writes the checksum to the shadow ram.  The changes in the shadow
4186c80429ceSEric Joyner  *  ram are then committed to the EEPROM by processing each bank at a time
4187c80429ceSEric Joyner  *  checking for the modified bit and writing only the pending changes.
4188c80429ceSEric Joyner  *  After a successful commit, the shadow ram is cleared and is ready for
4189c80429ceSEric Joyner  *  future writes.
4190c80429ceSEric Joyner  **/
4191c80429ceSEric Joyner static s32 e1000_update_nvm_checksum_spt(struct e1000_hw *hw)
4192c80429ceSEric Joyner {
4193c80429ceSEric Joyner 	struct e1000_nvm_info *nvm = &hw->nvm;
4194c80429ceSEric Joyner 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
4195c80429ceSEric Joyner 	u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
4196c80429ceSEric Joyner 	s32 ret_val;
4197c80429ceSEric Joyner 	u32 dword = 0;
4198c80429ceSEric Joyner 
4199c80429ceSEric Joyner 	DEBUGFUNC("e1000_update_nvm_checksum_spt");
4200c80429ceSEric Joyner 
4201c80429ceSEric Joyner 	ret_val = e1000_update_nvm_checksum_generic(hw);
4202c80429ceSEric Joyner 	if (ret_val)
4203c80429ceSEric Joyner 		goto out;
4204c80429ceSEric Joyner 
4205c80429ceSEric Joyner 	if (nvm->type != e1000_nvm_flash_sw)
4206c80429ceSEric Joyner 		goto out;
4207c80429ceSEric Joyner 
4208c80429ceSEric Joyner 	nvm->ops.acquire(hw);
4209c80429ceSEric Joyner 
4210c80429ceSEric Joyner 	/* We're writing to the opposite bank so if we're on bank 1,
4211c80429ceSEric Joyner 	 * write to bank 0 etc.  We also need to erase the segment that
4212c80429ceSEric Joyner 	 * is going to be written
4213c80429ceSEric Joyner 	 */
4214c80429ceSEric Joyner 	ret_val =  e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
4215c80429ceSEric Joyner 	if (ret_val != E1000_SUCCESS) {
4216c80429ceSEric Joyner 		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
4217c80429ceSEric Joyner 		bank = 0;
4218c80429ceSEric Joyner 	}
4219c80429ceSEric Joyner 
4220c80429ceSEric Joyner 	if (bank == 0) {
4221c80429ceSEric Joyner 		new_bank_offset = nvm->flash_bank_size;
4222c80429ceSEric Joyner 		old_bank_offset = 0;
4223c80429ceSEric Joyner 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
4224c80429ceSEric Joyner 		if (ret_val)
4225c80429ceSEric Joyner 			goto release;
4226c80429ceSEric Joyner 	} else {
4227c80429ceSEric Joyner 		old_bank_offset = nvm->flash_bank_size;
4228c80429ceSEric Joyner 		new_bank_offset = 0;
4229c80429ceSEric Joyner 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
4230c80429ceSEric Joyner 		if (ret_val)
4231c80429ceSEric Joyner 			goto release;
4232c80429ceSEric Joyner 	}
4233c80429ceSEric Joyner 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i += 2) {
4234c80429ceSEric Joyner 		/* Determine whether to write the value stored
4235c80429ceSEric Joyner 		 * in the other NVM bank or a modified value stored
4236c80429ceSEric Joyner 		 * in the shadow RAM
4237c80429ceSEric Joyner 		 */
4238c80429ceSEric Joyner 		ret_val = e1000_read_flash_dword_ich8lan(hw,
4239c80429ceSEric Joyner 							 i + old_bank_offset,
4240c80429ceSEric Joyner 							 &dword);
4241c80429ceSEric Joyner 
4242c80429ceSEric Joyner 		if (dev_spec->shadow_ram[i].modified) {
4243c80429ceSEric Joyner 			dword &= 0xffff0000;
4244c80429ceSEric Joyner 			dword |= (dev_spec->shadow_ram[i].value & 0xffff);
4245c80429ceSEric Joyner 		}
4246c80429ceSEric Joyner 		if (dev_spec->shadow_ram[i + 1].modified) {
4247c80429ceSEric Joyner 			dword &= 0x0000ffff;
4248c80429ceSEric Joyner 			dword |= ((dev_spec->shadow_ram[i + 1].value & 0xffff)
4249c80429ceSEric Joyner 				  << 16);
4250c80429ceSEric Joyner 		}
4251c80429ceSEric Joyner 		if (ret_val)
4252c80429ceSEric Joyner 			break;
4253c80429ceSEric Joyner 
4254c80429ceSEric Joyner 		/* If the word is 0x13, then make sure the signature bits
4255c80429ceSEric Joyner 		 * (15:14) are 11b until the commit has completed.
4256c80429ceSEric Joyner 		 * This will allow us to write 10b which indicates the
4257c80429ceSEric Joyner 		 * signature is valid.  We want to do this after the write
4258c80429ceSEric Joyner 		 * has completed so that we don't mark the segment valid
4259c80429ceSEric Joyner 		 * while the write is still in progress
4260c80429ceSEric Joyner 		 */
4261c80429ceSEric Joyner 		if (i == E1000_ICH_NVM_SIG_WORD - 1)
4262c80429ceSEric Joyner 			dword |= E1000_ICH_NVM_SIG_MASK << 16;
4263c80429ceSEric Joyner 
4264c80429ceSEric Joyner 		/* Convert offset to bytes. */
4265c80429ceSEric Joyner 		act_offset = (i + new_bank_offset) << 1;
4266c80429ceSEric Joyner 
4267c80429ceSEric Joyner 		usec_delay(100);
4268c80429ceSEric Joyner 
4269c80429ceSEric Joyner 		/* Write the data to the new bank. Offset in words*/
4270c80429ceSEric Joyner 		act_offset = i + new_bank_offset;
4271c80429ceSEric Joyner 		ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset,
4272c80429ceSEric Joyner 								dword);
4273c80429ceSEric Joyner 		if (ret_val)
4274c80429ceSEric Joyner 			break;
4275c80429ceSEric Joyner 	 }
4276c80429ceSEric Joyner 
4277c80429ceSEric Joyner 	/* Don't bother writing the segment valid bits if sector
4278c80429ceSEric Joyner 	 * programming failed.
4279c80429ceSEric Joyner 	 */
4280c80429ceSEric Joyner 	if (ret_val) {
4281c80429ceSEric Joyner 		DEBUGOUT("Flash commit failed.\n");
4282c80429ceSEric Joyner 		goto release;
4283c80429ceSEric Joyner 	}
4284c80429ceSEric Joyner 
4285c80429ceSEric Joyner 	/* Finally validate the new segment by setting bit 15:14
4286c80429ceSEric Joyner 	 * to 10b in word 0x13 , this can be done without an
4287c80429ceSEric Joyner 	 * erase as well since these bits are 11 to start with
4288c80429ceSEric Joyner 	 * and we need to change bit 14 to 0b
4289c80429ceSEric Joyner 	 */
4290c80429ceSEric Joyner 	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
4291c80429ceSEric Joyner 
4292c80429ceSEric Joyner 	/*offset in words but we read dword*/
4293c80429ceSEric Joyner 	--act_offset;
4294c80429ceSEric Joyner 	ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword);
4295c80429ceSEric Joyner 
4296c80429ceSEric Joyner 	if (ret_val)
4297c80429ceSEric Joyner 		goto release;
4298c80429ceSEric Joyner 
4299c80429ceSEric Joyner 	dword &= 0xBFFFFFFF;
4300c80429ceSEric Joyner 	ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword);
4301c80429ceSEric Joyner 
4302c80429ceSEric Joyner 	if (ret_val)
4303c80429ceSEric Joyner 		goto release;
4304c80429ceSEric Joyner 
4305c80429ceSEric Joyner 	/* offset in words but we read dword*/
4306c80429ceSEric Joyner 	act_offset = old_bank_offset + E1000_ICH_NVM_SIG_WORD - 1;
4307c80429ceSEric Joyner 	ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword);
4308c80429ceSEric Joyner 
4309c80429ceSEric Joyner 	if (ret_val)
4310c80429ceSEric Joyner 		goto release;
4311c80429ceSEric Joyner 
4312c80429ceSEric Joyner 	dword &= 0x00FFFFFF;
4313c80429ceSEric Joyner 	ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword);
4314c80429ceSEric Joyner 
4315c80429ceSEric Joyner 	if (ret_val)
4316c80429ceSEric Joyner 		goto release;
4317c80429ceSEric Joyner 
4318c80429ceSEric Joyner 	/* Great!  Everything worked, we can now clear the cached entries. */
4319c80429ceSEric Joyner 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
4320c80429ceSEric Joyner 		dev_spec->shadow_ram[i].modified = FALSE;
4321c80429ceSEric Joyner 		dev_spec->shadow_ram[i].value = 0xFFFF;
4322c80429ceSEric Joyner 	}
4323c80429ceSEric Joyner 
4324c80429ceSEric Joyner release:
4325c80429ceSEric Joyner 	nvm->ops.release(hw);
4326c80429ceSEric Joyner 
4327c80429ceSEric Joyner 	/* Reload the EEPROM, or else modifications will not appear
4328c80429ceSEric Joyner 	 * until after the next adapter reset.
4329c80429ceSEric Joyner 	 */
4330c80429ceSEric Joyner 	if (!ret_val) {
4331c80429ceSEric Joyner 		nvm->ops.reload(hw);
4332c80429ceSEric Joyner 		msec_delay(10);
4333c80429ceSEric Joyner 	}
4334c80429ceSEric Joyner 
4335c80429ceSEric Joyner out:
4336c80429ceSEric Joyner 	if (ret_val)
4337c80429ceSEric Joyner 		DEBUGOUT1("NVM update error: %d\n", ret_val);
4338c80429ceSEric Joyner 
4339c80429ceSEric Joyner 	return ret_val;
4340c80429ceSEric Joyner }
4341c80429ceSEric Joyner 
4342c80429ceSEric Joyner /**
43438cfa0ad2SJack F Vogel  *  e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
43448cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
43458cfa0ad2SJack F Vogel  *
43468cfa0ad2SJack F Vogel  *  The NVM checksum is updated by calling the generic update_nvm_checksum,
43478cfa0ad2SJack F Vogel  *  which writes the checksum to the shadow ram.  The changes in the shadow
43488cfa0ad2SJack F Vogel  *  ram are then committed to the EEPROM by processing each bank at a time
43498cfa0ad2SJack F Vogel  *  checking for the modified bit and writing only the pending changes.
43508cfa0ad2SJack F Vogel  *  After a successful commit, the shadow ram is cleared and is ready for
43518cfa0ad2SJack F Vogel  *  future writes.
43528cfa0ad2SJack F Vogel  **/
43538cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
43548cfa0ad2SJack F Vogel {
43558cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
4356daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
43578cfa0ad2SJack F Vogel 	u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
43588cfa0ad2SJack F Vogel 	s32 ret_val;
43598cc64f1eSJack F Vogel 	u16 data = 0;
43608cfa0ad2SJack F Vogel 
43618cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_update_nvm_checksum_ich8lan");
43628cfa0ad2SJack F Vogel 
43638cfa0ad2SJack F Vogel 	ret_val = e1000_update_nvm_checksum_generic(hw);
43648cfa0ad2SJack F Vogel 	if (ret_val)
43658cfa0ad2SJack F Vogel 		goto out;
43668cfa0ad2SJack F Vogel 
43678cfa0ad2SJack F Vogel 	if (nvm->type != e1000_nvm_flash_sw)
43688cfa0ad2SJack F Vogel 		goto out;
43698cfa0ad2SJack F Vogel 
43704edd8523SJack F Vogel 	nvm->ops.acquire(hw);
43718cfa0ad2SJack F Vogel 
43726ab6bfe3SJack F Vogel 	/* We're writing to the opposite bank so if we're on bank 1,
43738cfa0ad2SJack F Vogel 	 * write to bank 0 etc.  We also need to erase the segment that
43748cfa0ad2SJack F Vogel 	 * is going to be written
43758cfa0ad2SJack F Vogel 	 */
43768cfa0ad2SJack F Vogel 	ret_val =  e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
4377d035aa2dSJack F Vogel 	if (ret_val != E1000_SUCCESS) {
43784edd8523SJack F Vogel 		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
43794edd8523SJack F Vogel 		bank = 0;
4380d035aa2dSJack F Vogel 	}
43818cfa0ad2SJack F Vogel 
43828cfa0ad2SJack F Vogel 	if (bank == 0) {
43838cfa0ad2SJack F Vogel 		new_bank_offset = nvm->flash_bank_size;
43848cfa0ad2SJack F Vogel 		old_bank_offset = 0;
4385d035aa2dSJack F Vogel 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
4386a69ed8dfSJack F Vogel 		if (ret_val)
4387a69ed8dfSJack F Vogel 			goto release;
43888cfa0ad2SJack F Vogel 	} else {
43898cfa0ad2SJack F Vogel 		old_bank_offset = nvm->flash_bank_size;
43908cfa0ad2SJack F Vogel 		new_bank_offset = 0;
4391d035aa2dSJack F Vogel 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
4392a69ed8dfSJack F Vogel 		if (ret_val)
4393a69ed8dfSJack F Vogel 			goto release;
43948cfa0ad2SJack F Vogel 	}
43958cfa0ad2SJack F Vogel 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
43968cfa0ad2SJack F Vogel 		if (dev_spec->shadow_ram[i].modified) {
43978cfa0ad2SJack F Vogel 			data = dev_spec->shadow_ram[i].value;
43988cfa0ad2SJack F Vogel 		} else {
4399d035aa2dSJack F Vogel 			ret_val = e1000_read_flash_word_ich8lan(hw, i +
4400d035aa2dSJack F Vogel 								old_bank_offset,
44018cfa0ad2SJack F Vogel 								&data);
4402d035aa2dSJack F Vogel 			if (ret_val)
4403d035aa2dSJack F Vogel 				break;
44048cfa0ad2SJack F Vogel 		}
44056ab6bfe3SJack F Vogel 		/* If the word is 0x13, then make sure the signature bits
44068cfa0ad2SJack F Vogel 		 * (15:14) are 11b until the commit has completed.
44078cfa0ad2SJack F Vogel 		 * This will allow us to write 10b which indicates the
44088cfa0ad2SJack F Vogel 		 * signature is valid.  We want to do this after the write
44098cfa0ad2SJack F Vogel 		 * has completed so that we don't mark the segment valid
44108cfa0ad2SJack F Vogel 		 * while the write is still in progress
44118cfa0ad2SJack F Vogel 		 */
44128cfa0ad2SJack F Vogel 		if (i == E1000_ICH_NVM_SIG_WORD)
44138cfa0ad2SJack F Vogel 			data |= E1000_ICH_NVM_SIG_MASK;
44148cfa0ad2SJack F Vogel 
44158cfa0ad2SJack F Vogel 		/* Convert offset to bytes. */
44168cfa0ad2SJack F Vogel 		act_offset = (i + new_bank_offset) << 1;
44178cfa0ad2SJack F Vogel 
44188cfa0ad2SJack F Vogel 		usec_delay(100);
44198cc64f1eSJack F Vogel 
44208cfa0ad2SJack F Vogel 		/* Write the bytes to the new bank. */
44218cfa0ad2SJack F Vogel 		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
44228cfa0ad2SJack F Vogel 							       act_offset,
44238cfa0ad2SJack F Vogel 							       (u8)data);
44248cfa0ad2SJack F Vogel 		if (ret_val)
44258cfa0ad2SJack F Vogel 			break;
44268cfa0ad2SJack F Vogel 
44278cfa0ad2SJack F Vogel 		usec_delay(100);
44288cfa0ad2SJack F Vogel 		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
44298cfa0ad2SJack F Vogel 							  act_offset + 1,
44308cfa0ad2SJack F Vogel 							  (u8)(data >> 8));
44318cfa0ad2SJack F Vogel 		if (ret_val)
44328cfa0ad2SJack F Vogel 			break;
44338cfa0ad2SJack F Vogel 	}
44348cfa0ad2SJack F Vogel 
44356ab6bfe3SJack F Vogel 	/* Don't bother writing the segment valid bits if sector
44368cfa0ad2SJack F Vogel 	 * programming failed.
44378cfa0ad2SJack F Vogel 	 */
44388cfa0ad2SJack F Vogel 	if (ret_val) {
44398cfa0ad2SJack F Vogel 		DEBUGOUT("Flash commit failed.\n");
4440a69ed8dfSJack F Vogel 		goto release;
44418cfa0ad2SJack F Vogel 	}
44428cfa0ad2SJack F Vogel 
44436ab6bfe3SJack F Vogel 	/* Finally validate the new segment by setting bit 15:14
44448cfa0ad2SJack F Vogel 	 * to 10b in word 0x13 , this can be done without an
44458cfa0ad2SJack F Vogel 	 * erase as well since these bits are 11 to start with
44468cfa0ad2SJack F Vogel 	 * and we need to change bit 14 to 0b
44478cfa0ad2SJack F Vogel 	 */
44488cfa0ad2SJack F Vogel 	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
4449d035aa2dSJack F Vogel 	ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
4450a69ed8dfSJack F Vogel 	if (ret_val)
4451a69ed8dfSJack F Vogel 		goto release;
44524edd8523SJack F Vogel 
44538cfa0ad2SJack F Vogel 	data &= 0xBFFF;
44548cc64f1eSJack F Vogel 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset * 2 + 1,
44558cfa0ad2SJack F Vogel 						       (u8)(data >> 8));
4456a69ed8dfSJack F Vogel 	if (ret_val)
4457a69ed8dfSJack F Vogel 		goto release;
44588cfa0ad2SJack F Vogel 
44596ab6bfe3SJack F Vogel 	/* And invalidate the previously valid segment by setting
44608cfa0ad2SJack F Vogel 	 * its signature word (0x13) high_byte to 0b. This can be
44618cfa0ad2SJack F Vogel 	 * done without an erase because flash erase sets all bits
44628cfa0ad2SJack F Vogel 	 * to 1's. We can write 1's to 0's without an erase
44638cfa0ad2SJack F Vogel 	 */
44648cfa0ad2SJack F Vogel 	act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
44658cc64f1eSJack F Vogel 
44668cfa0ad2SJack F Vogel 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
44678cc64f1eSJack F Vogel 
4468a69ed8dfSJack F Vogel 	if (ret_val)
4469a69ed8dfSJack F Vogel 		goto release;
44708cfa0ad2SJack F Vogel 
44718cfa0ad2SJack F Vogel 	/* Great!  Everything worked, we can now clear the cached entries. */
44728cfa0ad2SJack F Vogel 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
44738cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].modified = FALSE;
44748cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].value = 0xFFFF;
44758cfa0ad2SJack F Vogel 	}
44768cfa0ad2SJack F Vogel 
4477a69ed8dfSJack F Vogel release:
44788cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
44798cfa0ad2SJack F Vogel 
44806ab6bfe3SJack F Vogel 	/* Reload the EEPROM, or else modifications will not appear
44818cfa0ad2SJack F Vogel 	 * until after the next adapter reset.
44828cfa0ad2SJack F Vogel 	 */
4483a69ed8dfSJack F Vogel 	if (!ret_val) {
44848cfa0ad2SJack F Vogel 		nvm->ops.reload(hw);
44858cfa0ad2SJack F Vogel 		msec_delay(10);
4486a69ed8dfSJack F Vogel 	}
44878cfa0ad2SJack F Vogel 
44888cfa0ad2SJack F Vogel out:
4489d035aa2dSJack F Vogel 	if (ret_val)
4490d035aa2dSJack F Vogel 		DEBUGOUT1("NVM update error: %d\n", ret_val);
4491d035aa2dSJack F Vogel 
44928cfa0ad2SJack F Vogel 	return ret_val;
44938cfa0ad2SJack F Vogel }
44948cfa0ad2SJack F Vogel 
44958cfa0ad2SJack F Vogel /**
44968cfa0ad2SJack F Vogel  *  e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
44978cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
44988cfa0ad2SJack F Vogel  *
44998cfa0ad2SJack F Vogel  *  Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
4500daf9197cSJack F Vogel  *  If the bit is 0, that the EEPROM had been modified, but the checksum was not
4501daf9197cSJack F Vogel  *  calculated, in which case we need to calculate the checksum and set bit 6.
45028cfa0ad2SJack F Vogel  **/
45038cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
45048cfa0ad2SJack F Vogel {
45056ab6bfe3SJack F Vogel 	s32 ret_val;
45068cfa0ad2SJack F Vogel 	u16 data;
45076ab6bfe3SJack F Vogel 	u16 word;
45086ab6bfe3SJack F Vogel 	u16 valid_csum_mask;
45098cfa0ad2SJack F Vogel 
45108cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan");
45118cfa0ad2SJack F Vogel 
45126ab6bfe3SJack F Vogel 	/* Read NVM and check Invalid Image CSUM bit.  If this bit is 0,
45136ab6bfe3SJack F Vogel 	 * the checksum needs to be fixed.  This bit is an indication that
45146ab6bfe3SJack F Vogel 	 * the NVM was prepared by OEM software and did not calculate
45156ab6bfe3SJack F Vogel 	 * the checksum...a likely scenario.
45168cfa0ad2SJack F Vogel 	 */
45176ab6bfe3SJack F Vogel 	switch (hw->mac.type) {
45186ab6bfe3SJack F Vogel 	case e1000_pch_lpt:
4519c80429ceSEric Joyner 	case e1000_pch_spt:
45206fe4c0a0SSean Bruno 	case e1000_pch_cnp:
452159690eabSKevin Bowling 	case e1000_pch_tgp:
452259690eabSKevin Bowling 	case e1000_pch_adp:
452359690eabSKevin Bowling 	case e1000_pch_mtp:
45246ab6bfe3SJack F Vogel 		word = NVM_COMPAT;
45256ab6bfe3SJack F Vogel 		valid_csum_mask = NVM_COMPAT_VALID_CSUM;
45266ab6bfe3SJack F Vogel 		break;
45276ab6bfe3SJack F Vogel 	default:
45286ab6bfe3SJack F Vogel 		word = NVM_FUTURE_INIT_WORD1;
45296ab6bfe3SJack F Vogel 		valid_csum_mask = NVM_FUTURE_INIT_WORD1_VALID_CSUM;
45306ab6bfe3SJack F Vogel 		break;
45318cfa0ad2SJack F Vogel 	}
45328cfa0ad2SJack F Vogel 
45336ab6bfe3SJack F Vogel 	ret_val = hw->nvm.ops.read(hw, word, 1, &data);
45346ab6bfe3SJack F Vogel 	if (ret_val)
45358cfa0ad2SJack F Vogel 		return ret_val;
45366ab6bfe3SJack F Vogel 
45376ab6bfe3SJack F Vogel 	if (!(data & valid_csum_mask)) {
45386ab6bfe3SJack F Vogel 		data |= valid_csum_mask;
45396ab6bfe3SJack F Vogel 		ret_val = hw->nvm.ops.write(hw, word, 1, &data);
45406ab6bfe3SJack F Vogel 		if (ret_val)
45416ab6bfe3SJack F Vogel 			return ret_val;
45426ab6bfe3SJack F Vogel 		ret_val = hw->nvm.ops.update(hw);
45436ab6bfe3SJack F Vogel 		if (ret_val)
45446ab6bfe3SJack F Vogel 			return ret_val;
45456ab6bfe3SJack F Vogel 	}
45466ab6bfe3SJack F Vogel 
45476ab6bfe3SJack F Vogel 	return e1000_validate_nvm_checksum_generic(hw);
45488cfa0ad2SJack F Vogel }
45498cfa0ad2SJack F Vogel 
45508cfa0ad2SJack F Vogel /**
45518cfa0ad2SJack F Vogel  *  e1000_write_flash_data_ich8lan - Writes bytes to the NVM
45528cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
45538cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the byte/word to read.
45548cfa0ad2SJack F Vogel  *  @size: Size of data to read, 1=byte 2=word
45558cfa0ad2SJack F Vogel  *  @data: The byte(s) to write to the NVM.
45568cfa0ad2SJack F Vogel  *
45578cfa0ad2SJack F Vogel  *  Writes one/two bytes to the NVM using the flash access registers.
45588cfa0ad2SJack F Vogel  **/
45598cfa0ad2SJack F Vogel static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
45608cfa0ad2SJack F Vogel 					  u8 size, u16 data)
45618cfa0ad2SJack F Vogel {
45628cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
45638cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
45648cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
45658cfa0ad2SJack F Vogel 	u32 flash_data = 0;
45666ab6bfe3SJack F Vogel 	s32 ret_val;
45678cfa0ad2SJack F Vogel 	u8 count = 0;
45688cfa0ad2SJack F Vogel 
45698cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_ich8_data");
45708cfa0ad2SJack F Vogel 
4571295df609SEric Joyner 	if (hw->mac.type >= e1000_pch_spt) {
4572c80429ceSEric Joyner 		if (size != 4 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
4573c80429ceSEric Joyner 			return -E1000_ERR_NVM;
4574c80429ceSEric Joyner 	} else {
45758cc64f1eSJack F Vogel 		if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
45766ab6bfe3SJack F Vogel 			return -E1000_ERR_NVM;
4577c80429ceSEric Joyner 	}
45788cfa0ad2SJack F Vogel 
45797609433eSJack F Vogel 	flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
45807609433eSJack F Vogel 			     hw->nvm.flash_base_addr);
45818cfa0ad2SJack F Vogel 
45828cfa0ad2SJack F Vogel 	do {
45838cfa0ad2SJack F Vogel 		usec_delay(1);
45848cfa0ad2SJack F Vogel 		/* Steps */
45858cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
45868cfa0ad2SJack F Vogel 		if (ret_val != E1000_SUCCESS)
45878cfa0ad2SJack F Vogel 			break;
4588c80429ceSEric Joyner 		/* In SPT, This register is in Lan memory space, not
4589c80429ceSEric Joyner 		 * flash.  Therefore, only 32 bit access is supported
4590c80429ceSEric Joyner 		 */
4591295df609SEric Joyner 		if (hw->mac.type >= e1000_pch_spt)
4592c80429ceSEric Joyner 			hsflctl.regval =
4593c80429ceSEric Joyner 			    E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16;
4594c80429ceSEric Joyner 		else
4595c80429ceSEric Joyner 			hsflctl.regval =
4596c80429ceSEric Joyner 			    E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
45978cc64f1eSJack F Vogel 
45988cfa0ad2SJack F Vogel 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
45998cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.fldbcount = size - 1;
46008cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
4601c80429ceSEric Joyner 		/* In SPT, This register is in Lan memory space,
4602c80429ceSEric Joyner 		 * not flash.  Therefore, only 32 bit access is
4603c80429ceSEric Joyner 		 * supported
4604c80429ceSEric Joyner 		 */
4605295df609SEric Joyner 		if (hw->mac.type >= e1000_pch_spt)
4606c80429ceSEric Joyner 			E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
4607c80429ceSEric Joyner 					      hsflctl.regval << 16);
4608c80429ceSEric Joyner 		else
4609c80429ceSEric Joyner 			E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
4610c80429ceSEric Joyner 						hsflctl.regval);
46118cfa0ad2SJack F Vogel 
46128cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
46138cfa0ad2SJack F Vogel 
46148cfa0ad2SJack F Vogel 		if (size == 1)
46158cfa0ad2SJack F Vogel 			flash_data = (u32)data & 0x00FF;
46168cfa0ad2SJack F Vogel 		else
46178cfa0ad2SJack F Vogel 			flash_data = (u32)data;
46188cfa0ad2SJack F Vogel 
46198cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data);
46208cfa0ad2SJack F Vogel 
46216ab6bfe3SJack F Vogel 		/* check if FCERR is set to 1 , if set to 1, clear it
46228cfa0ad2SJack F Vogel 		 * and try the whole sequence a few more times else done
46238cfa0ad2SJack F Vogel 		 */
46247609433eSJack F Vogel 		ret_val =
46257609433eSJack F Vogel 		    e1000_flash_cycle_ich8lan(hw,
46268cfa0ad2SJack F Vogel 					      ICH_FLASH_WRITE_COMMAND_TIMEOUT);
4627daf9197cSJack F Vogel 		if (ret_val == E1000_SUCCESS)
46288cfa0ad2SJack F Vogel 			break;
4629daf9197cSJack F Vogel 
46306ab6bfe3SJack F Vogel 		/* If we're here, then things are most likely
46318cfa0ad2SJack F Vogel 		 * completely hosed, but if the error condition
46328cfa0ad2SJack F Vogel 		 * is detected, it won't hurt to give it another
46338cfa0ad2SJack F Vogel 		 * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
46348cfa0ad2SJack F Vogel 		 */
4635daf9197cSJack F Vogel 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
46366ab6bfe3SJack F Vogel 		if (hsfsts.hsf_status.flcerr)
46378cfa0ad2SJack F Vogel 			/* Repeat for some time before giving up. */
46388cfa0ad2SJack F Vogel 			continue;
46396ab6bfe3SJack F Vogel 		if (!hsfsts.hsf_status.flcdone) {
46404dab5c37SJack F Vogel 			DEBUGOUT("Timeout error - flash cycle did not complete.\n");
46418cfa0ad2SJack F Vogel 			break;
46428cfa0ad2SJack F Vogel 		}
46438cfa0ad2SJack F Vogel 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
46448cfa0ad2SJack F Vogel 
46458cfa0ad2SJack F Vogel 	return ret_val;
46468cfa0ad2SJack F Vogel }
46478cfa0ad2SJack F Vogel 
4648c80429ceSEric Joyner /**
4649c80429ceSEric Joyner *  e1000_write_flash_data32_ich8lan - Writes 4 bytes to the NVM
4650c80429ceSEric Joyner *  @hw: pointer to the HW structure
4651c80429ceSEric Joyner *  @offset: The offset (in bytes) of the dwords to read.
4652c80429ceSEric Joyner *  @data: The 4 bytes to write to the NVM.
4653c80429ceSEric Joyner *
4654c80429ceSEric Joyner *  Writes one/two/four bytes to the NVM using the flash access registers.
4655c80429ceSEric Joyner **/
4656c80429ceSEric Joyner static s32 e1000_write_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
4657c80429ceSEric Joyner 					    u32 data)
4658c80429ceSEric Joyner {
4659c80429ceSEric Joyner 	union ich8_hws_flash_status hsfsts;
4660c80429ceSEric Joyner 	union ich8_hws_flash_ctrl hsflctl;
4661c80429ceSEric Joyner 	u32 flash_linear_addr;
4662c80429ceSEric Joyner 	s32 ret_val;
4663c80429ceSEric Joyner 	u8 count = 0;
4664c80429ceSEric Joyner 
4665c80429ceSEric Joyner 	DEBUGFUNC("e1000_write_flash_data32_ich8lan");
4666c80429ceSEric Joyner 
4667295df609SEric Joyner 	if (hw->mac.type >= e1000_pch_spt) {
4668c80429ceSEric Joyner 		if (offset > ICH_FLASH_LINEAR_ADDR_MASK)
4669c80429ceSEric Joyner 			return -E1000_ERR_NVM;
4670c80429ceSEric Joyner 	}
4671c80429ceSEric Joyner 	flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
4672c80429ceSEric Joyner 			     hw->nvm.flash_base_addr);
4673c80429ceSEric Joyner 	do {
4674c80429ceSEric Joyner 		usec_delay(1);
4675c80429ceSEric Joyner 		/* Steps */
4676c80429ceSEric Joyner 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
4677c80429ceSEric Joyner 		if (ret_val != E1000_SUCCESS)
4678c80429ceSEric Joyner 			break;
4679c80429ceSEric Joyner 
4680c80429ceSEric Joyner 		/* In SPT, This register is in Lan memory space, not
4681c80429ceSEric Joyner 		 * flash.  Therefore, only 32 bit access is supported
4682c80429ceSEric Joyner 		 */
4683295df609SEric Joyner 		if (hw->mac.type >= e1000_pch_spt)
4684c80429ceSEric Joyner 			hsflctl.regval = E1000_READ_FLASH_REG(hw,
4685c80429ceSEric Joyner 							      ICH_FLASH_HSFSTS)
4686c80429ceSEric Joyner 					 >> 16;
4687c80429ceSEric Joyner 		else
4688c80429ceSEric Joyner 			hsflctl.regval = E1000_READ_FLASH_REG16(hw,
4689c80429ceSEric Joyner 							      ICH_FLASH_HSFCTL);
4690c80429ceSEric Joyner 
4691c80429ceSEric Joyner 		hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1;
4692c80429ceSEric Joyner 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
4693c80429ceSEric Joyner 
4694c80429ceSEric Joyner 		/* In SPT, This register is in Lan memory space,
4695c80429ceSEric Joyner 		 * not flash.  Therefore, only 32 bit access is
4696c80429ceSEric Joyner 		 * supported
4697c80429ceSEric Joyner 		 */
4698295df609SEric Joyner 		if (hw->mac.type >= e1000_pch_spt)
4699c80429ceSEric Joyner 			E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
4700c80429ceSEric Joyner 					      hsflctl.regval << 16);
4701c80429ceSEric Joyner 		else
4702c80429ceSEric Joyner 			E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
4703c80429ceSEric Joyner 						hsflctl.regval);
4704c80429ceSEric Joyner 
4705c80429ceSEric Joyner 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
4706c80429ceSEric Joyner 
4707c80429ceSEric Joyner 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, data);
4708c80429ceSEric Joyner 
4709c80429ceSEric Joyner 		/* check if FCERR is set to 1 , if set to 1, clear it
4710c80429ceSEric Joyner 		 * and try the whole sequence a few more times else done
4711c80429ceSEric Joyner 		 */
4712c80429ceSEric Joyner 		ret_val = e1000_flash_cycle_ich8lan(hw,
4713c80429ceSEric Joyner 					       ICH_FLASH_WRITE_COMMAND_TIMEOUT);
4714c80429ceSEric Joyner 
4715c80429ceSEric Joyner 		if (ret_val == E1000_SUCCESS)
4716c80429ceSEric Joyner 			break;
4717c80429ceSEric Joyner 
4718c80429ceSEric Joyner 		/* If we're here, then things are most likely
4719c80429ceSEric Joyner 		 * completely hosed, but if the error condition
4720c80429ceSEric Joyner 		 * is detected, it won't hurt to give it another
4721c80429ceSEric Joyner 		 * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
4722c80429ceSEric Joyner 		 */
4723c80429ceSEric Joyner 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
4724c80429ceSEric Joyner 
4725c80429ceSEric Joyner 		if (hsfsts.hsf_status.flcerr)
4726c80429ceSEric Joyner 			/* Repeat for some time before giving up. */
4727c80429ceSEric Joyner 			continue;
4728c80429ceSEric Joyner 		if (!hsfsts.hsf_status.flcdone) {
4729c80429ceSEric Joyner 			DEBUGOUT("Timeout error - flash cycle did not complete.\n");
4730c80429ceSEric Joyner 			break;
4731c80429ceSEric Joyner 		}
4732c80429ceSEric Joyner 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
4733c80429ceSEric Joyner 
4734c80429ceSEric Joyner 	return ret_val;
4735c80429ceSEric Joyner }
47368cc64f1eSJack F Vogel 
47378cfa0ad2SJack F Vogel /**
47388cfa0ad2SJack F Vogel  *  e1000_write_flash_byte_ich8lan - Write a single byte to NVM
47398cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
47408cfa0ad2SJack F Vogel  *  @offset: The index of the byte to read.
47418cfa0ad2SJack F Vogel  *  @data: The byte to write to the NVM.
47428cfa0ad2SJack F Vogel  *
47438cfa0ad2SJack F Vogel  *  Writes a single byte to the NVM using the flash access registers.
47448cfa0ad2SJack F Vogel  **/
47458cfa0ad2SJack F Vogel static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
47468cfa0ad2SJack F Vogel 					  u8 data)
47478cfa0ad2SJack F Vogel {
47488cfa0ad2SJack F Vogel 	u16 word = (u16)data;
47498cfa0ad2SJack F Vogel 
47508cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_flash_byte_ich8lan");
47518cfa0ad2SJack F Vogel 
47528cfa0ad2SJack F Vogel 	return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
47538cfa0ad2SJack F Vogel }
47548cfa0ad2SJack F Vogel 
4755c80429ceSEric Joyner /**
4756c80429ceSEric Joyner *  e1000_retry_write_flash_dword_ich8lan - Writes a dword to NVM
4757c80429ceSEric Joyner *  @hw: pointer to the HW structure
4758c80429ceSEric Joyner *  @offset: The offset of the word to write.
4759c80429ceSEric Joyner *  @dword: The dword to write to the NVM.
4760c80429ceSEric Joyner *
4761c80429ceSEric Joyner *  Writes a single dword to the NVM using the flash access registers.
4762c80429ceSEric Joyner *  Goes through a retry algorithm before giving up.
4763c80429ceSEric Joyner **/
4764c80429ceSEric Joyner static s32 e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw,
4765c80429ceSEric Joyner 						 u32 offset, u32 dword)
4766c80429ceSEric Joyner {
4767c80429ceSEric Joyner 	s32 ret_val;
4768c80429ceSEric Joyner 	u16 program_retries;
47698cc64f1eSJack F Vogel 
4770c80429ceSEric Joyner 	DEBUGFUNC("e1000_retry_write_flash_dword_ich8lan");
4771c80429ceSEric Joyner 
4772c80429ceSEric Joyner 	/* Must convert word offset into bytes. */
4773c80429ceSEric Joyner 	offset <<= 1;
4774c80429ceSEric Joyner 
4775c80429ceSEric Joyner 	ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword);
4776c80429ceSEric Joyner 
4777c80429ceSEric Joyner 	if (!ret_val)
4778c80429ceSEric Joyner 		return ret_val;
4779c80429ceSEric Joyner 	for (program_retries = 0; program_retries < 100; program_retries++) {
4780c80429ceSEric Joyner 		DEBUGOUT2("Retrying Byte %8.8X at offset %u\n", dword, offset);
4781c80429ceSEric Joyner 		usec_delay(100);
4782c80429ceSEric Joyner 		ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword);
4783c80429ceSEric Joyner 		if (ret_val == E1000_SUCCESS)
4784c80429ceSEric Joyner 			break;
4785c80429ceSEric Joyner 	}
4786c80429ceSEric Joyner 	if (program_retries == 100)
4787c80429ceSEric Joyner 		return -E1000_ERR_NVM;
4788c80429ceSEric Joyner 
4789c80429ceSEric Joyner 	return E1000_SUCCESS;
4790c80429ceSEric Joyner }
47918cc64f1eSJack F Vogel 
47928cfa0ad2SJack F Vogel /**
47938cfa0ad2SJack F Vogel  *  e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
47948cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
47958cfa0ad2SJack F Vogel  *  @offset: The offset of the byte to write.
47968cfa0ad2SJack F Vogel  *  @byte: The byte to write to the NVM.
47978cfa0ad2SJack F Vogel  *
47988cfa0ad2SJack F Vogel  *  Writes a single byte to the NVM using the flash access registers.
47998cfa0ad2SJack F Vogel  *  Goes through a retry algorithm before giving up.
48008cfa0ad2SJack F Vogel  **/
48018cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
48028cfa0ad2SJack F Vogel 						u32 offset, u8 byte)
48038cfa0ad2SJack F Vogel {
48048cfa0ad2SJack F Vogel 	s32 ret_val;
48058cfa0ad2SJack F Vogel 	u16 program_retries;
48068cfa0ad2SJack F Vogel 
48078cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan");
48088cfa0ad2SJack F Vogel 
48098cfa0ad2SJack F Vogel 	ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
48106ab6bfe3SJack F Vogel 	if (!ret_val)
48116ab6bfe3SJack F Vogel 		return ret_val;
48128cfa0ad2SJack F Vogel 
48138cfa0ad2SJack F Vogel 	for (program_retries = 0; program_retries < 100; program_retries++) {
48148cfa0ad2SJack F Vogel 		DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset);
48158cfa0ad2SJack F Vogel 		usec_delay(100);
48168cfa0ad2SJack F Vogel 		ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
48178cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS)
48188cfa0ad2SJack F Vogel 			break;
48198cfa0ad2SJack F Vogel 	}
48206ab6bfe3SJack F Vogel 	if (program_retries == 100)
48216ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
48228cfa0ad2SJack F Vogel 
48236ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
48248cfa0ad2SJack F Vogel }
48258cfa0ad2SJack F Vogel 
48268cfa0ad2SJack F Vogel /**
48278cfa0ad2SJack F Vogel  *  e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
48288cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
48298cfa0ad2SJack F Vogel  *  @bank: 0 for first bank, 1 for second bank, etc.
48308cfa0ad2SJack F Vogel  *
48318cfa0ad2SJack F Vogel  *  Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
48328cfa0ad2SJack F Vogel  *  bank N is 4096 * N + flash_reg_addr.
48338cfa0ad2SJack F Vogel  **/
48348cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
48358cfa0ad2SJack F Vogel {
48368cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
48378cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
48388cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
48398cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
48408cfa0ad2SJack F Vogel 	/* bank size is in 16bit words - adjust to bytes */
48418cfa0ad2SJack F Vogel 	u32 flash_bank_size = nvm->flash_bank_size * 2;
48426ab6bfe3SJack F Vogel 	s32 ret_val;
48438cfa0ad2SJack F Vogel 	s32 count = 0;
48448cfa0ad2SJack F Vogel 	s32 j, iteration, sector_size;
48458cfa0ad2SJack F Vogel 
48468cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_erase_flash_bank_ich8lan");
48478cfa0ad2SJack F Vogel 
48488cfa0ad2SJack F Vogel 	hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
48498cfa0ad2SJack F Vogel 
48506ab6bfe3SJack F Vogel 	/* Determine HW Sector size: Read BERASE bits of hw flash status
48518cfa0ad2SJack F Vogel 	 * register
48528cfa0ad2SJack F Vogel 	 * 00: The Hw sector is 256 bytes, hence we need to erase 16
48538cfa0ad2SJack F Vogel 	 *     consecutive sectors.  The start index for the nth Hw sector
48548cfa0ad2SJack F Vogel 	 *     can be calculated as = bank * 4096 + n * 256
48558cfa0ad2SJack F Vogel 	 * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
48568cfa0ad2SJack F Vogel 	 *     The start index for the nth Hw sector can be calculated
48578cfa0ad2SJack F Vogel 	 *     as = bank * 4096
48588cfa0ad2SJack F Vogel 	 * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
48598cfa0ad2SJack F Vogel 	 *     (ich9 only, otherwise error condition)
48608cfa0ad2SJack F Vogel 	 * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
48618cfa0ad2SJack F Vogel 	 */
48628cfa0ad2SJack F Vogel 	switch (hsfsts.hsf_status.berasesz) {
48638cfa0ad2SJack F Vogel 	case 0:
48648cfa0ad2SJack F Vogel 		/* Hw sector size 256 */
48658cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_256;
48668cfa0ad2SJack F Vogel 		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
48678cfa0ad2SJack F Vogel 		break;
48688cfa0ad2SJack F Vogel 	case 1:
48698cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_4K;
48709d81738fSJack F Vogel 		iteration = 1;
48718cfa0ad2SJack F Vogel 		break;
48728cfa0ad2SJack F Vogel 	case 2:
48738cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_8K;
48748bd0025fSJack F Vogel 		iteration = 1;
48758cfa0ad2SJack F Vogel 		break;
48768cfa0ad2SJack F Vogel 	case 3:
48778cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_64K;
48789d81738fSJack F Vogel 		iteration = 1;
48798cfa0ad2SJack F Vogel 		break;
48808cfa0ad2SJack F Vogel 	default:
48816ab6bfe3SJack F Vogel 		return -E1000_ERR_NVM;
48828cfa0ad2SJack F Vogel 	}
48838cfa0ad2SJack F Vogel 
48848cfa0ad2SJack F Vogel 	/* Start with the base address, then add the sector offset. */
48858cfa0ad2SJack F Vogel 	flash_linear_addr = hw->nvm.flash_base_addr;
48864edd8523SJack F Vogel 	flash_linear_addr += (bank) ? flash_bank_size : 0;
48878cfa0ad2SJack F Vogel 
48888cfa0ad2SJack F Vogel 	for (j = 0; j < iteration; j++) {
48898cfa0ad2SJack F Vogel 		do {
48907609433eSJack F Vogel 			u32 timeout = ICH_FLASH_ERASE_COMMAND_TIMEOUT;
48917609433eSJack F Vogel 
48928cfa0ad2SJack F Vogel 			/* Steps */
48938cfa0ad2SJack F Vogel 			ret_val = e1000_flash_cycle_init_ich8lan(hw);
48948cfa0ad2SJack F Vogel 			if (ret_val)
48956ab6bfe3SJack F Vogel 				return ret_val;
48968cfa0ad2SJack F Vogel 
48976ab6bfe3SJack F Vogel 			/* Write a value 11 (block Erase) in Flash
48988cfa0ad2SJack F Vogel 			 * Cycle field in hw flash control
48998cfa0ad2SJack F Vogel 			 */
4900295df609SEric Joyner 			if (hw->mac.type >= e1000_pch_spt)
49018cc64f1eSJack F Vogel 				hsflctl.regval =
4902c80429ceSEric Joyner 				    E1000_READ_FLASH_REG(hw,
4903c80429ceSEric Joyner 							 ICH_FLASH_HSFSTS)>>16;
4904c80429ceSEric Joyner 			else
4905c80429ceSEric Joyner 				hsflctl.regval =
4906c80429ceSEric Joyner 				    E1000_READ_FLASH_REG16(hw,
4907c80429ceSEric Joyner 							   ICH_FLASH_HSFCTL);
49088cc64f1eSJack F Vogel 
49098cfa0ad2SJack F Vogel 			hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
4910295df609SEric Joyner 			if (hw->mac.type >= e1000_pch_spt)
4911c80429ceSEric Joyner 				E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
4912c80429ceSEric Joyner 						      hsflctl.regval << 16);
4913c80429ceSEric Joyner 			else
4914daf9197cSJack F Vogel 				E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
49158cfa0ad2SJack F Vogel 							hsflctl.regval);
49168cfa0ad2SJack F Vogel 
49176ab6bfe3SJack F Vogel 			/* Write the last 24 bits of an index within the
49188cfa0ad2SJack F Vogel 			 * block into Flash Linear address field in Flash
49198cfa0ad2SJack F Vogel 			 * Address.
49208cfa0ad2SJack F Vogel 			 */
49218cfa0ad2SJack F Vogel 			flash_linear_addr += (j * sector_size);
4922daf9197cSJack F Vogel 			E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR,
49238cfa0ad2SJack F Vogel 					      flash_linear_addr);
49248cfa0ad2SJack F Vogel 
49257609433eSJack F Vogel 			ret_val = e1000_flash_cycle_ich8lan(hw, timeout);
4926daf9197cSJack F Vogel 			if (ret_val == E1000_SUCCESS)
49278cfa0ad2SJack F Vogel 				break;
4928daf9197cSJack F Vogel 
49296ab6bfe3SJack F Vogel 			/* Check if FCERR is set to 1.  If 1,
49308cfa0ad2SJack F Vogel 			 * clear it and try the whole sequence
49318cfa0ad2SJack F Vogel 			 * a few more times else Done
49328cfa0ad2SJack F Vogel 			 */
49338cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
49348cfa0ad2SJack F Vogel 						      ICH_FLASH_HSFSTS);
49356ab6bfe3SJack F Vogel 			if (hsfsts.hsf_status.flcerr)
4936daf9197cSJack F Vogel 				/* repeat for some time before giving up */
49378cfa0ad2SJack F Vogel 				continue;
49386ab6bfe3SJack F Vogel 			else if (!hsfsts.hsf_status.flcdone)
49396ab6bfe3SJack F Vogel 				return ret_val;
49408cfa0ad2SJack F Vogel 		} while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
49418cfa0ad2SJack F Vogel 	}
49428cfa0ad2SJack F Vogel 
49436ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
49448cfa0ad2SJack F Vogel }
49458cfa0ad2SJack F Vogel 
49468cfa0ad2SJack F Vogel /**
49478cfa0ad2SJack F Vogel  *  e1000_valid_led_default_ich8lan - Set the default LED settings
49488cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
49498cfa0ad2SJack F Vogel  *  @data: Pointer to the LED settings
49508cfa0ad2SJack F Vogel  *
49518cfa0ad2SJack F Vogel  *  Reads the LED default settings from the NVM to data.  If the NVM LED
49528cfa0ad2SJack F Vogel  *  settings is all 0's or F's, set the LED default to a valid LED default
49538cfa0ad2SJack F Vogel  *  setting.
49548cfa0ad2SJack F Vogel  **/
49558cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
49568cfa0ad2SJack F Vogel {
49578cfa0ad2SJack F Vogel 	s32 ret_val;
49588cfa0ad2SJack F Vogel 
49598cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_valid_led_default_ich8lan");
49608cfa0ad2SJack F Vogel 
49618cfa0ad2SJack F Vogel 	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
49628cfa0ad2SJack F Vogel 	if (ret_val) {
49638cfa0ad2SJack F Vogel 		DEBUGOUT("NVM Read Error\n");
49646ab6bfe3SJack F Vogel 		return ret_val;
49658cfa0ad2SJack F Vogel 	}
49668cfa0ad2SJack F Vogel 
49674dab5c37SJack F Vogel 	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
49688cfa0ad2SJack F Vogel 		*data = ID_LED_DEFAULT_ICH8LAN;
49698cfa0ad2SJack F Vogel 
49706ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
49718cfa0ad2SJack F Vogel }
49728cfa0ad2SJack F Vogel 
49738cfa0ad2SJack F Vogel /**
49749d81738fSJack F Vogel  *  e1000_id_led_init_pchlan - store LED configurations
49759d81738fSJack F Vogel  *  @hw: pointer to the HW structure
49769d81738fSJack F Vogel  *
49779d81738fSJack F Vogel  *  PCH does not control LEDs via the LEDCTL register, rather it uses
49789d81738fSJack F Vogel  *  the PHY LED configuration register.
49799d81738fSJack F Vogel  *
49809d81738fSJack F Vogel  *  PCH also does not have an "always on" or "always off" mode which
49819d81738fSJack F Vogel  *  complicates the ID feature.  Instead of using the "on" mode to indicate
49829d81738fSJack F Vogel  *  in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()),
49839d81738fSJack F Vogel  *  use "link_up" mode.  The LEDs will still ID on request if there is no
49849d81738fSJack F Vogel  *  link based on logic in e1000_led_[on|off]_pchlan().
49859d81738fSJack F Vogel  **/
49869d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw)
49879d81738fSJack F Vogel {
49889d81738fSJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
49899d81738fSJack F Vogel 	s32 ret_val;
49909d81738fSJack F Vogel 	const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
49919d81738fSJack F Vogel 	const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
49929d81738fSJack F Vogel 	u16 data, i, temp, shift;
49939d81738fSJack F Vogel 
49949d81738fSJack F Vogel 	DEBUGFUNC("e1000_id_led_init_pchlan");
49959d81738fSJack F Vogel 
49969d81738fSJack F Vogel 	/* Get default ID LED modes */
49979d81738fSJack F Vogel 	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
49989d81738fSJack F Vogel 	if (ret_val)
49996ab6bfe3SJack F Vogel 		return ret_val;
50009d81738fSJack F Vogel 
50019d81738fSJack F Vogel 	mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
50029d81738fSJack F Vogel 	mac->ledctl_mode1 = mac->ledctl_default;
50039d81738fSJack F Vogel 	mac->ledctl_mode2 = mac->ledctl_default;
50049d81738fSJack F Vogel 
50059d81738fSJack F Vogel 	for (i = 0; i < 4; i++) {
50069d81738fSJack F Vogel 		temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
50079d81738fSJack F Vogel 		shift = (i * 5);
50089d81738fSJack F Vogel 		switch (temp) {
50099d81738fSJack F Vogel 		case ID_LED_ON1_DEF2:
50109d81738fSJack F Vogel 		case ID_LED_ON1_ON2:
50119d81738fSJack F Vogel 		case ID_LED_ON1_OFF2:
50129d81738fSJack F Vogel 			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
50139d81738fSJack F Vogel 			mac->ledctl_mode1 |= (ledctl_on << shift);
50149d81738fSJack F Vogel 			break;
50159d81738fSJack F Vogel 		case ID_LED_OFF1_DEF2:
50169d81738fSJack F Vogel 		case ID_LED_OFF1_ON2:
50179d81738fSJack F Vogel 		case ID_LED_OFF1_OFF2:
50189d81738fSJack F Vogel 			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
50199d81738fSJack F Vogel 			mac->ledctl_mode1 |= (ledctl_off << shift);
50209d81738fSJack F Vogel 			break;
50219d81738fSJack F Vogel 		default:
50229d81738fSJack F Vogel 			/* Do nothing */
50239d81738fSJack F Vogel 			break;
50249d81738fSJack F Vogel 		}
50259d81738fSJack F Vogel 		switch (temp) {
50269d81738fSJack F Vogel 		case ID_LED_DEF1_ON2:
50279d81738fSJack F Vogel 		case ID_LED_ON1_ON2:
50289d81738fSJack F Vogel 		case ID_LED_OFF1_ON2:
50299d81738fSJack F Vogel 			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
50309d81738fSJack F Vogel 			mac->ledctl_mode2 |= (ledctl_on << shift);
50319d81738fSJack F Vogel 			break;
50329d81738fSJack F Vogel 		case ID_LED_DEF1_OFF2:
50339d81738fSJack F Vogel 		case ID_LED_ON1_OFF2:
50349d81738fSJack F Vogel 		case ID_LED_OFF1_OFF2:
50359d81738fSJack F Vogel 			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
50369d81738fSJack F Vogel 			mac->ledctl_mode2 |= (ledctl_off << shift);
50379d81738fSJack F Vogel 			break;
50389d81738fSJack F Vogel 		default:
50399d81738fSJack F Vogel 			/* Do nothing */
50409d81738fSJack F Vogel 			break;
50419d81738fSJack F Vogel 		}
50429d81738fSJack F Vogel 	}
50439d81738fSJack F Vogel 
50446ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
50459d81738fSJack F Vogel }
50469d81738fSJack F Vogel 
50479d81738fSJack F Vogel /**
50488cfa0ad2SJack F Vogel  *  e1000_get_bus_info_ich8lan - Get/Set the bus type and width
50498cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
50508cfa0ad2SJack F Vogel  *
50518cfa0ad2SJack F Vogel  *  ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
5052cef367e6SEitan Adler  *  register, so the bus width is hard coded.
50538cfa0ad2SJack F Vogel  **/
50548cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
50558cfa0ad2SJack F Vogel {
50568cfa0ad2SJack F Vogel 	struct e1000_bus_info *bus = &hw->bus;
50578cfa0ad2SJack F Vogel 	s32 ret_val;
50588cfa0ad2SJack F Vogel 
50598cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_bus_info_ich8lan");
50608cfa0ad2SJack F Vogel 
50618cfa0ad2SJack F Vogel 	ret_val = e1000_get_bus_info_pcie_generic(hw);
50628cfa0ad2SJack F Vogel 
50636ab6bfe3SJack F Vogel 	/* ICH devices are "PCI Express"-ish.  They have
50648cfa0ad2SJack F Vogel 	 * a configuration space, but do not contain
50658cfa0ad2SJack F Vogel 	 * PCI Express Capability registers, so bus width
50668cfa0ad2SJack F Vogel 	 * must be hardcoded.
50678cfa0ad2SJack F Vogel 	 */
50688cfa0ad2SJack F Vogel 	if (bus->width == e1000_bus_width_unknown)
50698cfa0ad2SJack F Vogel 		bus->width = e1000_bus_width_pcie_x1;
50708cfa0ad2SJack F Vogel 
50718cfa0ad2SJack F Vogel 	return ret_val;
50728cfa0ad2SJack F Vogel }
50738cfa0ad2SJack F Vogel 
50748cfa0ad2SJack F Vogel /**
50758cfa0ad2SJack F Vogel  *  e1000_reset_hw_ich8lan - Reset the hardware
50768cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
50778cfa0ad2SJack F Vogel  *
50788cfa0ad2SJack F Vogel  *  Does a full reset of the hardware which includes a reset of the PHY and
50798cfa0ad2SJack F Vogel  *  MAC.
50808cfa0ad2SJack F Vogel  **/
50818cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
50828cfa0ad2SJack F Vogel {
50834edd8523SJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
50846ab6bfe3SJack F Vogel 	u16 kum_cfg;
50856ab6bfe3SJack F Vogel 	u32 ctrl, reg;
50868cfa0ad2SJack F Vogel 	s32 ret_val;
5087*fc7682b1SKevin Bowling 	u16 pci_cfg;
50888cfa0ad2SJack F Vogel 
50898cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_reset_hw_ich8lan");
50908cfa0ad2SJack F Vogel 
50916ab6bfe3SJack F Vogel 	/* Prevent the PCI-E bus from sticking if there is no TLP connection
50928cfa0ad2SJack F Vogel 	 * on the last TLP read/write transaction when MAC is reset.
50938cfa0ad2SJack F Vogel 	 */
50948cfa0ad2SJack F Vogel 	ret_val = e1000_disable_pcie_master_generic(hw);
5095daf9197cSJack F Vogel 	if (ret_val)
50968cfa0ad2SJack F Vogel 		DEBUGOUT("PCI-E Master disable polling has failed.\n");
50978cfa0ad2SJack F Vogel 
50988cfa0ad2SJack F Vogel 	DEBUGOUT("Masking off all interrupts\n");
50998cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
51008cfa0ad2SJack F Vogel 
51016ab6bfe3SJack F Vogel 	/* Disable the Transmit and Receive units.  Then delay to allow
51028cfa0ad2SJack F Vogel 	 * any pending transactions to complete before we hit the MAC
51038cfa0ad2SJack F Vogel 	 * with the global reset.
51048cfa0ad2SJack F Vogel 	 */
51058cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RCTL, 0);
51068cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
51078cfa0ad2SJack F Vogel 	E1000_WRITE_FLUSH(hw);
51088cfa0ad2SJack F Vogel 
51098cfa0ad2SJack F Vogel 	msec_delay(10);
51108cfa0ad2SJack F Vogel 
51118cfa0ad2SJack F Vogel 	/* Workaround for ICH8 bit corruption issue in FIFO memory */
51128cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan) {
51138cfa0ad2SJack F Vogel 		/* Set Tx and Rx buffer allocation to 8k apiece. */
51148cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K);
51158cfa0ad2SJack F Vogel 		/* Set Packet Buffer Size to 16k. */
51168cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K);
51178cfa0ad2SJack F Vogel 	}
51188cfa0ad2SJack F Vogel 
51194edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan) {
51204edd8523SJack F Vogel 		/* Save the NVM K1 bit setting*/
51216ab6bfe3SJack F Vogel 		ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, &kum_cfg);
51224edd8523SJack F Vogel 		if (ret_val)
51234edd8523SJack F Vogel 			return ret_val;
51244edd8523SJack F Vogel 
51256ab6bfe3SJack F Vogel 		if (kum_cfg & E1000_NVM_K1_ENABLE)
51264edd8523SJack F Vogel 			dev_spec->nvm_k1_enabled = TRUE;
51274edd8523SJack F Vogel 		else
51284edd8523SJack F Vogel 			dev_spec->nvm_k1_enabled = FALSE;
51294edd8523SJack F Vogel 	}
51304edd8523SJack F Vogel 
51318cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
51328cfa0ad2SJack F Vogel 
51337d9119bdSJack F Vogel 	if (!hw->phy.ops.check_reset_block(hw)) {
51346ab6bfe3SJack F Vogel 		/* Full-chip reset requires MAC and PHY reset at the same
51358cfa0ad2SJack F Vogel 		 * time to make sure the interface between MAC and the
51368cfa0ad2SJack F Vogel 		 * external PHY is reset.
51378cfa0ad2SJack F Vogel 		 */
51388cfa0ad2SJack F Vogel 		ctrl |= E1000_CTRL_PHY_RST;
51397d9119bdSJack F Vogel 
51406ab6bfe3SJack F Vogel 		/* Gate automatic PHY configuration by hardware on
51417d9119bdSJack F Vogel 		 * non-managed 82579
51427d9119bdSJack F Vogel 		 */
51437d9119bdSJack F Vogel 		if ((hw->mac.type == e1000_pch2lan) &&
51447d9119bdSJack F Vogel 		    !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
51457d9119bdSJack F Vogel 			e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
51468cfa0ad2SJack F Vogel 	}
51478cfa0ad2SJack F Vogel 	ret_val = e1000_acquire_swflag_ich8lan(hw);
5148*fc7682b1SKevin Bowling 
5149*fc7682b1SKevin Bowling 	/* Read from EXTCNF_CTRL in e1000_acquire_swflag_ich8lan function
5150*fc7682b1SKevin Bowling 	 * may occur during global reset and cause system hang.
5151*fc7682b1SKevin Bowling 	 * Configuration space access creates the needed delay.
5152*fc7682b1SKevin Bowling 	 * Write to E1000_STRAP RO register E1000_PCI_VENDOR_ID_REGISTER value
5153*fc7682b1SKevin Bowling 	 * insures configuration space read is done before global reset.
5154*fc7682b1SKevin Bowling 	 */
5155*fc7682b1SKevin Bowling 	e1000_read_pci_cfg(hw, E1000_PCI_VENDOR_ID_REGISTER, &pci_cfg);
5156*fc7682b1SKevin Bowling 	E1000_WRITE_REG(hw, E1000_STRAP, pci_cfg);
5157daf9197cSJack F Vogel 	DEBUGOUT("Issuing a global reset to ich8lan\n");
51588cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST));
51594dab5c37SJack F Vogel 	/* cannot issue a flush here because it hangs the hardware */
51608cfa0ad2SJack F Vogel 	msec_delay(20);
51618cfa0ad2SJack F Vogel 
5162*fc7682b1SKevin Bowling 	/* Configuration space access improve HW level time sync mechanism.
5163*fc7682b1SKevin Bowling 	 * Write to E1000_STRAP RO register E1000_PCI_VENDOR_ID_REGISTER
5164*fc7682b1SKevin Bowling 	 * value to insure configuration space read is done
5165*fc7682b1SKevin Bowling 	 * before any access to mac register.
5166*fc7682b1SKevin Bowling 	 */
5167*fc7682b1SKevin Bowling 	e1000_read_pci_cfg(hw, E1000_PCI_VENDOR_ID_REGISTER, &pci_cfg);
5168*fc7682b1SKevin Bowling 	E1000_WRITE_REG(hw, E1000_STRAP, pci_cfg);
5169*fc7682b1SKevin Bowling 
51706ab6bfe3SJack F Vogel 	/* Set Phy Config Counter to 50msec */
51716ab6bfe3SJack F Vogel 	if (hw->mac.type == e1000_pch2lan) {
51726ab6bfe3SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_FEXTNVM3);
51736ab6bfe3SJack F Vogel 		reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
51746ab6bfe3SJack F Vogel 		reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
51756ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_FEXTNVM3, reg);
51766ab6bfe3SJack F Vogel 	}
51776ab6bfe3SJack F Vogel 
51789d81738fSJack F Vogel 
51797d9119bdSJack F Vogel 	if (ctrl & E1000_CTRL_PHY_RST) {
51809d81738fSJack F Vogel 		ret_val = hw->phy.ops.get_cfg_done(hw);
51814edd8523SJack F Vogel 		if (ret_val)
51826ab6bfe3SJack F Vogel 			return ret_val;
51834edd8523SJack F Vogel 
51847d9119bdSJack F Vogel 		ret_val = e1000_post_phy_reset_ich8lan(hw);
51854edd8523SJack F Vogel 		if (ret_val)
51866ab6bfe3SJack F Vogel 			return ret_val;
51877d9119bdSJack F Vogel 	}
51887d9119bdSJack F Vogel 
51896ab6bfe3SJack F Vogel 	/* For PCH, this write will make sure that any noise
51904edd8523SJack F Vogel 	 * will be detected as a CRC error and be dropped rather than show up
51914edd8523SJack F Vogel 	 * as a bad packet to the DMA engine.
51924edd8523SJack F Vogel 	 */
51934edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan)
51944edd8523SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565);
51958cfa0ad2SJack F Vogel 
51968cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
5197730d3130SJack F Vogel 	E1000_READ_REG(hw, E1000_ICR);
51988cfa0ad2SJack F Vogel 
51996ab6bfe3SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_KABGTXD);
52006ab6bfe3SJack F Vogel 	reg |= E1000_KABGTXD_BGSQLBIAS;
52016ab6bfe3SJack F Vogel 	E1000_WRITE_REG(hw, E1000_KABGTXD, reg);
52028cfa0ad2SJack F Vogel 
52036ab6bfe3SJack F Vogel 	return E1000_SUCCESS;
52048cfa0ad2SJack F Vogel }
52058cfa0ad2SJack F Vogel 
52068cfa0ad2SJack F Vogel /**
52078cfa0ad2SJack F Vogel  *  e1000_init_hw_ich8lan - Initialize the hardware
52088cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
52098cfa0ad2SJack F Vogel  *
52108cfa0ad2SJack F Vogel  *  Prepares the hardware for transmit and receive by doing the following:
52118cfa0ad2SJack F Vogel  *   - initialize hardware bits
52128cfa0ad2SJack F Vogel  *   - initialize LED identification
52138cfa0ad2SJack F Vogel  *   - setup receive address registers
52148cfa0ad2SJack F Vogel  *   - setup flow control
52158cfa0ad2SJack F Vogel  *   - setup transmit descriptors
52168cfa0ad2SJack F Vogel  *   - clear statistics
52178cfa0ad2SJack F Vogel  **/
52188cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
52198cfa0ad2SJack F Vogel {
52208cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
52218cfa0ad2SJack F Vogel 	u32 ctrl_ext, txdctl, snoop;
52228cfa0ad2SJack F Vogel 	s32 ret_val;
52238cfa0ad2SJack F Vogel 	u16 i;
52248cfa0ad2SJack F Vogel 
52258cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_hw_ich8lan");
52268cfa0ad2SJack F Vogel 
52278cfa0ad2SJack F Vogel 	e1000_initialize_hw_bits_ich8lan(hw);
52288cfa0ad2SJack F Vogel 
52298cfa0ad2SJack F Vogel 	/* Initialize identification LED */
5230d035aa2dSJack F Vogel 	ret_val = mac->ops.id_led_init(hw);
52316ab6bfe3SJack F Vogel 	/* An error is not fatal and we should not stop init due to this */
5232d035aa2dSJack F Vogel 	if (ret_val)
5233d035aa2dSJack F Vogel 		DEBUGOUT("Error initializing identification LED\n");
52348cfa0ad2SJack F Vogel 
52358cfa0ad2SJack F Vogel 	/* Setup the receive address. */
52368cfa0ad2SJack F Vogel 	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
52378cfa0ad2SJack F Vogel 
52388cfa0ad2SJack F Vogel 	/* Zero out the Multicast HASH table */
52398cfa0ad2SJack F Vogel 	DEBUGOUT("Zeroing the MTA\n");
52408cfa0ad2SJack F Vogel 	for (i = 0; i < mac->mta_reg_count; i++)
52418cfa0ad2SJack F Vogel 		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
52428cfa0ad2SJack F Vogel 
52436ab6bfe3SJack F Vogel 	/* The 82578 Rx buffer will stall if wakeup is enabled in host and
52444dab5c37SJack F Vogel 	 * the ME.  Disable wakeup by clearing the host wakeup bit.
52459d81738fSJack F Vogel 	 * Reset the phy after disabling host wakeup to reset the Rx buffer.
52469d81738fSJack F Vogel 	 */
52479d81738fSJack F Vogel 	if (hw->phy.type == e1000_phy_82578) {
52484dab5c37SJack F Vogel 		hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, &i);
52494dab5c37SJack F Vogel 		i &= ~BM_WUC_HOST_WU_BIT;
52504dab5c37SJack F Vogel 		hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, i);
52519d81738fSJack F Vogel 		ret_val = e1000_phy_hw_reset_ich8lan(hw);
52529d81738fSJack F Vogel 		if (ret_val)
52539d81738fSJack F Vogel 			return ret_val;
52549d81738fSJack F Vogel 	}
52559d81738fSJack F Vogel 
52568cfa0ad2SJack F Vogel 	/* Setup link and flow control */
52578cfa0ad2SJack F Vogel 	ret_val = mac->ops.setup_link(hw);
52588cfa0ad2SJack F Vogel 
52598cfa0ad2SJack F Vogel 	/* Set the transmit descriptor write-back policy for both queues */
52608cfa0ad2SJack F Vogel 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
52617609433eSJack F Vogel 	txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) |
52627609433eSJack F Vogel 		  E1000_TXDCTL_FULL_TX_DESC_WB);
52637609433eSJack F Vogel 	txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) |
52647609433eSJack F Vogel 		  E1000_TXDCTL_MAX_TX_DESC_PREFETCH);
52658cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
52668cfa0ad2SJack F Vogel 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1));
52677609433eSJack F Vogel 	txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) |
52687609433eSJack F Vogel 		  E1000_TXDCTL_FULL_TX_DESC_WB);
52697609433eSJack F Vogel 	txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) |
52707609433eSJack F Vogel 		  E1000_TXDCTL_MAX_TX_DESC_PREFETCH);
52718cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl);
52728cfa0ad2SJack F Vogel 
52736ab6bfe3SJack F Vogel 	/* ICH8 has opposite polarity of no_snoop bits.
52748cfa0ad2SJack F Vogel 	 * By default, we should use snoop behavior.
52758cfa0ad2SJack F Vogel 	 */
52768cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
52778cfa0ad2SJack F Vogel 		snoop = PCIE_ICH8_SNOOP_ALL;
52788cfa0ad2SJack F Vogel 	else
52798cfa0ad2SJack F Vogel 		snoop = (u32) ~(PCIE_NO_SNOOP_ALL);
52808cfa0ad2SJack F Vogel 	e1000_set_pcie_no_snoop_generic(hw, snoop);
52818cfa0ad2SJack F Vogel 
52828cfa0ad2SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
52838cfa0ad2SJack F Vogel 	ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
52848cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
52858cfa0ad2SJack F Vogel 
52866ab6bfe3SJack F Vogel 	/* Clear all of the statistics registers (clear on read).  It is
52878cfa0ad2SJack F Vogel 	 * important that we do this after we have tried to establish link
52888cfa0ad2SJack F Vogel 	 * because the symbol error count will increment wildly if there
52898cfa0ad2SJack F Vogel 	 * is no link.
52908cfa0ad2SJack F Vogel 	 */
52918cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_ich8lan(hw);
52928cfa0ad2SJack F Vogel 
52938cfa0ad2SJack F Vogel 	return ret_val;
52948cfa0ad2SJack F Vogel }
52956ab6bfe3SJack F Vogel 
52968cfa0ad2SJack F Vogel /**
52978cfa0ad2SJack F Vogel  *  e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
52988cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
52998cfa0ad2SJack F Vogel  *
53008cfa0ad2SJack F Vogel  *  Sets/Clears required hardware bits necessary for correctly setting up the
53018cfa0ad2SJack F Vogel  *  hardware for transmit and receive.
53028cfa0ad2SJack F Vogel  **/
53038cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
53048cfa0ad2SJack F Vogel {
53058cfa0ad2SJack F Vogel 	u32 reg;
53068cfa0ad2SJack F Vogel 
53078cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_initialize_hw_bits_ich8lan");
53088cfa0ad2SJack F Vogel 
53098cfa0ad2SJack F Vogel 	/* Extended Device Control */
53108cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
53118cfa0ad2SJack F Vogel 	reg |= (1 << 22);
53129d81738fSJack F Vogel 	/* Enable PHY low-power state when MAC is at D3 w/o WoL */
53139d81738fSJack F Vogel 	if (hw->mac.type >= e1000_pchlan)
53149d81738fSJack F Vogel 		reg |= E1000_CTRL_EXT_PHYPDEN;
53158cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
53168cfa0ad2SJack F Vogel 
53178cfa0ad2SJack F Vogel 	/* Transmit Descriptor Control 0 */
53188cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
53198cfa0ad2SJack F Vogel 	reg |= (1 << 22);
53208cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
53218cfa0ad2SJack F Vogel 
53228cfa0ad2SJack F Vogel 	/* Transmit Descriptor Control 1 */
53238cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
53248cfa0ad2SJack F Vogel 	reg |= (1 << 22);
53258cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
53268cfa0ad2SJack F Vogel 
53278cfa0ad2SJack F Vogel 	/* Transmit Arbitration Control 0 */
53288cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TARC(0));
53298cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan)
53308cfa0ad2SJack F Vogel 		reg |= (1 << 28) | (1 << 29);
53318cfa0ad2SJack F Vogel 	reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
53328cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TARC(0), reg);
53338cfa0ad2SJack F Vogel 
53348cfa0ad2SJack F Vogel 	/* Transmit Arbitration Control 1 */
53358cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TARC(1));
53368cfa0ad2SJack F Vogel 	if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
53378cfa0ad2SJack F Vogel 		reg &= ~(1 << 28);
53388cfa0ad2SJack F Vogel 	else
53398cfa0ad2SJack F Vogel 		reg |= (1 << 28);
53408cfa0ad2SJack F Vogel 	reg |= (1 << 24) | (1 << 26) | (1 << 30);
53418cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TARC(1), reg);
53428cfa0ad2SJack F Vogel 
53438cfa0ad2SJack F Vogel 	/* Device Status */
53448cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan) {
53458cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_STATUS);
53468f07d847SEitan Adler 		reg &= ~(1U << 31);
53478cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_STATUS, reg);
53488cfa0ad2SJack F Vogel 	}
53498cfa0ad2SJack F Vogel 
53506ab6bfe3SJack F Vogel 	/* work-around descriptor data corruption issue during nfs v2 udp
53518ec87fc5SJack F Vogel 	 * traffic, just disable the nfs filtering capability
53528ec87fc5SJack F Vogel 	 */
53538ec87fc5SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_RFCTL);
53548ec87fc5SJack F Vogel 	reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS);
53557609433eSJack F Vogel 
53566ab6bfe3SJack F Vogel 	/* Disable IPv6 extension header parsing because some malformed
53576ab6bfe3SJack F Vogel 	 * IPv6 headers can hang the Rx.
53586ab6bfe3SJack F Vogel 	 */
53596ab6bfe3SJack F Vogel 	if (hw->mac.type == e1000_ich8lan)
53606ab6bfe3SJack F Vogel 		reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS);
53618ec87fc5SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RFCTL, reg);
53628ec87fc5SJack F Vogel 
53636ab6bfe3SJack F Vogel 	/* Enable ECC on Lynxpoint */
5364295df609SEric Joyner 	if (hw->mac.type >= e1000_pch_lpt) {
53656ab6bfe3SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_PBECCSTS);
53666ab6bfe3SJack F Vogel 		reg |= E1000_PBECCSTS_ECC_ENABLE;
53676ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBECCSTS, reg);
53686ab6bfe3SJack F Vogel 
53696ab6bfe3SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_CTRL);
53706ab6bfe3SJack F Vogel 		reg |= E1000_CTRL_MEHE;
53716ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, reg);
53726ab6bfe3SJack F Vogel 	}
53736ab6bfe3SJack F Vogel 
53748cfa0ad2SJack F Vogel 	return;
53758cfa0ad2SJack F Vogel }
53768cfa0ad2SJack F Vogel 
53778cfa0ad2SJack F Vogel /**
53788cfa0ad2SJack F Vogel  *  e1000_setup_link_ich8lan - Setup flow control and link settings
53798cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
53808cfa0ad2SJack F Vogel  *
53818cfa0ad2SJack F Vogel  *  Determines which flow control settings to use, then configures flow
53828cfa0ad2SJack F Vogel  *  control.  Calls the appropriate media-specific link configuration
53838cfa0ad2SJack F Vogel  *  function.  Assuming the adapter has a valid link partner, a valid link
53848cfa0ad2SJack F Vogel  *  should be established.  Assumes the hardware has previously been reset
53858cfa0ad2SJack F Vogel  *  and the transmitter and receiver are not enabled.
53868cfa0ad2SJack F Vogel  **/
53878cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
53888cfa0ad2SJack F Vogel {
53896ab6bfe3SJack F Vogel 	s32 ret_val;
53908cfa0ad2SJack F Vogel 
53918cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_link_ich8lan");
53928cfa0ad2SJack F Vogel 
53936ab6bfe3SJack F Vogel 	/* ICH parts do not have a word in the NVM to determine
53948cfa0ad2SJack F Vogel 	 * the default flow control setting, so we explicitly
53958cfa0ad2SJack F Vogel 	 * set it to full.
53968cfa0ad2SJack F Vogel 	 */
5397daf9197cSJack F Vogel 	if (hw->fc.requested_mode == e1000_fc_default)
5398daf9197cSJack F Vogel 		hw->fc.requested_mode = e1000_fc_full;
53998cfa0ad2SJack F Vogel 
54006ab6bfe3SJack F Vogel 	/* Save off the requested flow control mode for use later.  Depending
5401daf9197cSJack F Vogel 	 * on the link partner's capabilities, we may or may not use this mode.
5402daf9197cSJack F Vogel 	 */
5403daf9197cSJack F Vogel 	hw->fc.current_mode = hw->fc.requested_mode;
54048cfa0ad2SJack F Vogel 
5405daf9197cSJack F Vogel 	DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
5406daf9197cSJack F Vogel 		hw->fc.current_mode);
54078cfa0ad2SJack F Vogel 
540851569bd7SEric Joyner 	if (!hw->phy.ops.check_reset_block(hw)) {
54098cfa0ad2SJack F Vogel 		/* Continue to configure the copper link. */
54108cfa0ad2SJack F Vogel 		ret_val = hw->mac.ops.setup_physical_interface(hw);
54118cfa0ad2SJack F Vogel 		if (ret_val)
54126ab6bfe3SJack F Vogel 			return ret_val;
541351569bd7SEric Joyner 	}
54148cfa0ad2SJack F Vogel 
54158cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
54169d81738fSJack F Vogel 	if ((hw->phy.type == e1000_phy_82578) ||
54177d9119bdSJack F Vogel 	    (hw->phy.type == e1000_phy_82579) ||
54186ab6bfe3SJack F Vogel 	    (hw->phy.type == e1000_phy_i217) ||
54199d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577)) {
54207d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FCRTV_PCH, hw->fc.refresh_time);
54217d9119bdSJack F Vogel 
54229d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw,
54239d81738fSJack F Vogel 					     PHY_REG(BM_PORT_CTRL_PAGE, 27),
54249d81738fSJack F Vogel 					     hw->fc.pause_time);
54259d81738fSJack F Vogel 		if (ret_val)
54266ab6bfe3SJack F Vogel 			return ret_val;
54279d81738fSJack F Vogel 	}
54288cfa0ad2SJack F Vogel 
54296ab6bfe3SJack F Vogel 	return e1000_set_fc_watermarks_generic(hw);
54308cfa0ad2SJack F Vogel }
54318cfa0ad2SJack F Vogel 
54328cfa0ad2SJack F Vogel /**
54338cfa0ad2SJack F Vogel  *  e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
54348cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
54358cfa0ad2SJack F Vogel  *
54368cfa0ad2SJack F Vogel  *  Configures the kumeran interface to the PHY to wait the appropriate time
54378cfa0ad2SJack F Vogel  *  when polling the PHY, then call the generic setup_copper_link to finish
54388cfa0ad2SJack F Vogel  *  configuring the copper link.
54398cfa0ad2SJack F Vogel  **/
54408cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
54418cfa0ad2SJack F Vogel {
54428cfa0ad2SJack F Vogel 	u32 ctrl;
54438cfa0ad2SJack F Vogel 	s32 ret_val;
54448cfa0ad2SJack F Vogel 	u16 reg_data;
54458cfa0ad2SJack F Vogel 
54468cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_copper_link_ich8lan");
54478cfa0ad2SJack F Vogel 
54488cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
54498cfa0ad2SJack F Vogel 	ctrl |= E1000_CTRL_SLU;
54508cfa0ad2SJack F Vogel 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
54518cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
54528cfa0ad2SJack F Vogel 
54536ab6bfe3SJack F Vogel 	/* Set the mac to wait the maximum time between each iteration
54548cfa0ad2SJack F Vogel 	 * and increase the max iterations when polling the phy;
54558cfa0ad2SJack F Vogel 	 * this fixes erroneous timeouts at 10Mbps.
54568cfa0ad2SJack F Vogel 	 */
54574edd8523SJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_TIMEOUTS,
54588cfa0ad2SJack F Vogel 					       0xFFFF);
54598cfa0ad2SJack F Vogel 	if (ret_val)
54606ab6bfe3SJack F Vogel 		return ret_val;
54619d81738fSJack F Vogel 	ret_val = e1000_read_kmrn_reg_generic(hw,
54629d81738fSJack F Vogel 					      E1000_KMRNCTRLSTA_INBAND_PARAM,
54638cfa0ad2SJack F Vogel 					      &reg_data);
54648cfa0ad2SJack F Vogel 	if (ret_val)
54656ab6bfe3SJack F Vogel 		return ret_val;
54668cfa0ad2SJack F Vogel 	reg_data |= 0x3F;
54679d81738fSJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
54689d81738fSJack F Vogel 					       E1000_KMRNCTRLSTA_INBAND_PARAM,
54698cfa0ad2SJack F Vogel 					       reg_data);
54708cfa0ad2SJack F Vogel 	if (ret_val)
54716ab6bfe3SJack F Vogel 		return ret_val;
54728cfa0ad2SJack F Vogel 
5473d035aa2dSJack F Vogel 	switch (hw->phy.type) {
5474d035aa2dSJack F Vogel 	case e1000_phy_igp_3:
54758cfa0ad2SJack F Vogel 		ret_val = e1000_copper_link_setup_igp(hw);
54768cfa0ad2SJack F Vogel 		if (ret_val)
54776ab6bfe3SJack F Vogel 			return ret_val;
5478d035aa2dSJack F Vogel 		break;
5479d035aa2dSJack F Vogel 	case e1000_phy_bm:
54809d81738fSJack F Vogel 	case e1000_phy_82578:
54818cfa0ad2SJack F Vogel 		ret_val = e1000_copper_link_setup_m88(hw);
54828cfa0ad2SJack F Vogel 		if (ret_val)
54836ab6bfe3SJack F Vogel 			return ret_val;
5484d035aa2dSJack F Vogel 		break;
54859d81738fSJack F Vogel 	case e1000_phy_82577:
54867d9119bdSJack F Vogel 	case e1000_phy_82579:
54879d81738fSJack F Vogel 		ret_val = e1000_copper_link_setup_82577(hw);
54889d81738fSJack F Vogel 		if (ret_val)
54896ab6bfe3SJack F Vogel 			return ret_val;
54909d81738fSJack F Vogel 		break;
5491d035aa2dSJack F Vogel 	case e1000_phy_ife:
54928cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL,
54938cfa0ad2SJack F Vogel 					       &reg_data);
54948cfa0ad2SJack F Vogel 		if (ret_val)
54956ab6bfe3SJack F Vogel 			return ret_val;
54968cfa0ad2SJack F Vogel 
54978cfa0ad2SJack F Vogel 		reg_data &= ~IFE_PMC_AUTO_MDIX;
54988cfa0ad2SJack F Vogel 
54998cfa0ad2SJack F Vogel 		switch (hw->phy.mdix) {
55008cfa0ad2SJack F Vogel 		case 1:
55018cfa0ad2SJack F Vogel 			reg_data &= ~IFE_PMC_FORCE_MDIX;
55028cfa0ad2SJack F Vogel 			break;
55038cfa0ad2SJack F Vogel 		case 2:
55048cfa0ad2SJack F Vogel 			reg_data |= IFE_PMC_FORCE_MDIX;
55058cfa0ad2SJack F Vogel 			break;
55068cfa0ad2SJack F Vogel 		case 0:
55078cfa0ad2SJack F Vogel 		default:
55088cfa0ad2SJack F Vogel 			reg_data |= IFE_PMC_AUTO_MDIX;
55098cfa0ad2SJack F Vogel 			break;
55108cfa0ad2SJack F Vogel 		}
55118cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL,
55128cfa0ad2SJack F Vogel 						reg_data);
55138cfa0ad2SJack F Vogel 		if (ret_val)
55146ab6bfe3SJack F Vogel 			return ret_val;
5515d035aa2dSJack F Vogel 		break;
5516d035aa2dSJack F Vogel 	default:
5517d035aa2dSJack F Vogel 		break;
55188cfa0ad2SJack F Vogel 	}
55198cfa0ad2SJack F Vogel 
55206ab6bfe3SJack F Vogel 	return e1000_setup_copper_link_generic(hw);
55216ab6bfe3SJack F Vogel }
55226ab6bfe3SJack F Vogel 
55236ab6bfe3SJack F Vogel /**
55246ab6bfe3SJack F Vogel  *  e1000_setup_copper_link_pch_lpt - Configure MAC/PHY interface
55256ab6bfe3SJack F Vogel  *  @hw: pointer to the HW structure
55266ab6bfe3SJack F Vogel  *
55276ab6bfe3SJack F Vogel  *  Calls the PHY specific link setup function and then calls the
55286ab6bfe3SJack F Vogel  *  generic setup_copper_link to finish configuring the link for
55296ab6bfe3SJack F Vogel  *  Lynxpoint PCH devices
55306ab6bfe3SJack F Vogel  **/
55316ab6bfe3SJack F Vogel static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw)
55326ab6bfe3SJack F Vogel {
55336ab6bfe3SJack F Vogel 	u32 ctrl;
55346ab6bfe3SJack F Vogel 	s32 ret_val;
55356ab6bfe3SJack F Vogel 
55366ab6bfe3SJack F Vogel 	DEBUGFUNC("e1000_setup_copper_link_pch_lpt");
55376ab6bfe3SJack F Vogel 
55386ab6bfe3SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
55396ab6bfe3SJack F Vogel 	ctrl |= E1000_CTRL_SLU;
55406ab6bfe3SJack F Vogel 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
55416ab6bfe3SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
55426ab6bfe3SJack F Vogel 
55436ab6bfe3SJack F Vogel 	ret_val = e1000_copper_link_setup_82577(hw);
55446ab6bfe3SJack F Vogel 	if (ret_val)
55458cfa0ad2SJack F Vogel 		return ret_val;
55466ab6bfe3SJack F Vogel 
55476ab6bfe3SJack F Vogel 	return e1000_setup_copper_link_generic(hw);
55488cfa0ad2SJack F Vogel }
55498cfa0ad2SJack F Vogel 
55508cfa0ad2SJack F Vogel /**
55518cfa0ad2SJack F Vogel  *  e1000_get_link_up_info_ich8lan - Get current link speed and duplex
55528cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
55538cfa0ad2SJack F Vogel  *  @speed: pointer to store current link speed
55548cfa0ad2SJack F Vogel  *  @duplex: pointer to store the current link duplex
55558cfa0ad2SJack F Vogel  *
55568cfa0ad2SJack F Vogel  *  Calls the generic get_speed_and_duplex to retrieve the current link
55578cfa0ad2SJack F Vogel  *  information and then calls the Kumeran lock loss workaround for links at
55588cfa0ad2SJack F Vogel  *  gigabit speeds.
55598cfa0ad2SJack F Vogel  **/
55608cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
55618cfa0ad2SJack F Vogel 					  u16 *duplex)
55628cfa0ad2SJack F Vogel {
55638cfa0ad2SJack F Vogel 	s32 ret_val;
55648cfa0ad2SJack F Vogel 
55658cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_link_up_info_ich8lan");
55668cfa0ad2SJack F Vogel 
55678cfa0ad2SJack F Vogel 	ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
55688cfa0ad2SJack F Vogel 	if (ret_val)
55696ab6bfe3SJack F Vogel 		return ret_val;
55708cfa0ad2SJack F Vogel 
55718cfa0ad2SJack F Vogel 	if ((hw->mac.type == e1000_ich8lan) &&
55728cfa0ad2SJack F Vogel 	    (hw->phy.type == e1000_phy_igp_3) &&
55738cfa0ad2SJack F Vogel 	    (*speed == SPEED_1000)) {
55748cfa0ad2SJack F Vogel 		ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
55758cfa0ad2SJack F Vogel 	}
55768cfa0ad2SJack F Vogel 
55778cfa0ad2SJack F Vogel 	return ret_val;
55788cfa0ad2SJack F Vogel }
55798cfa0ad2SJack F Vogel 
55808cfa0ad2SJack F Vogel /**
55818cfa0ad2SJack F Vogel  *  e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
55828cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
55838cfa0ad2SJack F Vogel  *
55848cfa0ad2SJack F Vogel  *  Work-around for 82566 Kumeran PCS lock loss:
55858cfa0ad2SJack F Vogel  *  On link status change (i.e. PCI reset, speed change) and link is up and
55868cfa0ad2SJack F Vogel  *  speed is gigabit-
55878cfa0ad2SJack F Vogel  *    0) if workaround is optionally disabled do nothing
55888cfa0ad2SJack F Vogel  *    1) wait 1ms for Kumeran link to come up
55898cfa0ad2SJack F Vogel  *    2) check Kumeran Diagnostic register PCS lock loss bit
55908cfa0ad2SJack F Vogel  *    3) if not set the link is locked (all is good), otherwise...
55918cfa0ad2SJack F Vogel  *    4) reset the PHY
55928cfa0ad2SJack F Vogel  *    5) repeat up to 10 times
55938cfa0ad2SJack F Vogel  *  Note: this is only called for IGP3 copper when speed is 1gb.
55948cfa0ad2SJack F Vogel  **/
55958cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
55968cfa0ad2SJack F Vogel {
5597daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
55988cfa0ad2SJack F Vogel 	u32 phy_ctrl;
55996ab6bfe3SJack F Vogel 	s32 ret_val;
56008cfa0ad2SJack F Vogel 	u16 i, data;
56018cfa0ad2SJack F Vogel 	bool link;
56028cfa0ad2SJack F Vogel 
56038cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan");
56048cfa0ad2SJack F Vogel 
5605730d3130SJack F Vogel 	if (!dev_spec->kmrn_lock_loss_workaround_enabled)
56066ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
56078cfa0ad2SJack F Vogel 
56086ab6bfe3SJack F Vogel 	/* Make sure link is up before proceeding.  If not just return.
56098cfa0ad2SJack F Vogel 	 * Attempting this while link is negotiating fouled up link
56108cfa0ad2SJack F Vogel 	 * stability
56118cfa0ad2SJack F Vogel 	 */
56128cfa0ad2SJack F Vogel 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
56136ab6bfe3SJack F Vogel 	if (!link)
56146ab6bfe3SJack F Vogel 		return E1000_SUCCESS;
56158cfa0ad2SJack F Vogel 
56168cfa0ad2SJack F Vogel 	for (i = 0; i < 10; i++) {
56178cfa0ad2SJack F Vogel 		/* read once to clear */
56188cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
56198cfa0ad2SJack F Vogel 		if (ret_val)
56206ab6bfe3SJack F Vogel 			return ret_val;
56218cfa0ad2SJack F Vogel 		/* and again to get new status */
56228cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
56238cfa0ad2SJack F Vogel 		if (ret_val)
56246ab6bfe3SJack F Vogel 			return ret_val;
56258cfa0ad2SJack F Vogel 
56268cfa0ad2SJack F Vogel 		/* check for PCS lock */
56276ab6bfe3SJack F Vogel 		if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS))
56286ab6bfe3SJack F Vogel 			return E1000_SUCCESS;
56298cfa0ad2SJack F Vogel 
56308cfa0ad2SJack F Vogel 		/* Issue PHY reset */
56318cfa0ad2SJack F Vogel 		hw->phy.ops.reset(hw);
56328cfa0ad2SJack F Vogel 		msec_delay_irq(5);
56338cfa0ad2SJack F Vogel 	}
56348cfa0ad2SJack F Vogel 	/* Disable GigE link negotiation */
56358cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
56368cfa0ad2SJack F Vogel 	phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
56378cfa0ad2SJack F Vogel 		     E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
56388cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
56398cfa0ad2SJack F Vogel 
56406ab6bfe3SJack F Vogel 	/* Call gig speed drop workaround on Gig disable before accessing
56418cfa0ad2SJack F Vogel 	 * any PHY registers
56428cfa0ad2SJack F Vogel 	 */
56438cfa0ad2SJack F Vogel 	e1000_gig_downshift_workaround_ich8lan(hw);
56448cfa0ad2SJack F Vogel 
56458cfa0ad2SJack F Vogel 	/* unable to acquire PCS lock */
56466ab6bfe3SJack F Vogel 	return -E1000_ERR_PHY;
56478cfa0ad2SJack F Vogel }
56488cfa0ad2SJack F Vogel 
56498cfa0ad2SJack F Vogel /**
56508cfa0ad2SJack F Vogel  *  e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
56518cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
56528cfa0ad2SJack F Vogel  *  @state: boolean value used to set the current Kumeran workaround state
56538cfa0ad2SJack F Vogel  *
56548cfa0ad2SJack F Vogel  *  If ICH8, set the current Kumeran workaround state (enabled - TRUE
56558cfa0ad2SJack F Vogel  *  /disabled - FALSE).
56568cfa0ad2SJack F Vogel  **/
56578cfa0ad2SJack F Vogel void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
56588cfa0ad2SJack F Vogel 						 bool state)
56598cfa0ad2SJack F Vogel {
5660daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
56618cfa0ad2SJack F Vogel 
56628cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan");
56638cfa0ad2SJack F Vogel 
56648cfa0ad2SJack F Vogel 	if (hw->mac.type != e1000_ich8lan) {
56658cfa0ad2SJack F Vogel 		DEBUGOUT("Workaround applies to ICH8 only.\n");
5666daf9197cSJack F Vogel 		return;
56678cfa0ad2SJack F Vogel 	}
56688cfa0ad2SJack F Vogel 
56698cfa0ad2SJack F Vogel 	dev_spec->kmrn_lock_loss_workaround_enabled = state;
56708cfa0ad2SJack F Vogel 
56718cfa0ad2SJack F Vogel 	return;
56728cfa0ad2SJack F Vogel }
56738cfa0ad2SJack F Vogel 
56748cfa0ad2SJack F Vogel /**
56758cfa0ad2SJack F Vogel  *  e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
56768cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
56778cfa0ad2SJack F Vogel  *
56788cfa0ad2SJack F Vogel  *  Workaround for 82566 power-down on D3 entry:
56798cfa0ad2SJack F Vogel  *    1) disable gigabit link
56808cfa0ad2SJack F Vogel  *    2) write VR power-down enable
56818cfa0ad2SJack F Vogel  *    3) read it back
56828cfa0ad2SJack F Vogel  *  Continue if successful, else issue LCD reset and repeat
56838cfa0ad2SJack F Vogel  **/
56848cfa0ad2SJack F Vogel void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
56858cfa0ad2SJack F Vogel {
56868cfa0ad2SJack F Vogel 	u32 reg;
56878cfa0ad2SJack F Vogel 	u16 data;
56888cfa0ad2SJack F Vogel 	u8  retry = 0;
56898cfa0ad2SJack F Vogel 
56908cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan");
56918cfa0ad2SJack F Vogel 
56928cfa0ad2SJack F Vogel 	if (hw->phy.type != e1000_phy_igp_3)
56936ab6bfe3SJack F Vogel 		return;
56948cfa0ad2SJack F Vogel 
56958cfa0ad2SJack F Vogel 	/* Try the workaround twice (if needed) */
56968cfa0ad2SJack F Vogel 	do {
56978cfa0ad2SJack F Vogel 		/* Disable link */
56988cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
56998cfa0ad2SJack F Vogel 		reg |= (E1000_PHY_CTRL_GBE_DISABLE |
57008cfa0ad2SJack F Vogel 			E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
57018cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg);
57028cfa0ad2SJack F Vogel 
57036ab6bfe3SJack F Vogel 		/* Call gig speed drop workaround on Gig disable before
57048cfa0ad2SJack F Vogel 		 * accessing any PHY registers
57058cfa0ad2SJack F Vogel 		 */
57068cfa0ad2SJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
57078cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
57088cfa0ad2SJack F Vogel 
57098cfa0ad2SJack F Vogel 		/* Write VR power-down enable */
57108cfa0ad2SJack F Vogel 		hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
57118cfa0ad2SJack F Vogel 		data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
5712daf9197cSJack F Vogel 		hw->phy.ops.write_reg(hw, IGP3_VR_CTRL,
57138cfa0ad2SJack F Vogel 				      data | IGP3_VR_CTRL_MODE_SHUTDOWN);
57148cfa0ad2SJack F Vogel 
57158cfa0ad2SJack F Vogel 		/* Read it back and test */
57168cfa0ad2SJack F Vogel 		hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
57178cfa0ad2SJack F Vogel 		data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
57188cfa0ad2SJack F Vogel 		if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
57198cfa0ad2SJack F Vogel 			break;
57208cfa0ad2SJack F Vogel 
57218cfa0ad2SJack F Vogel 		/* Issue PHY reset and repeat at most one more time */
57228cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_CTRL);
57238cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST);
57248cfa0ad2SJack F Vogel 		retry++;
57258cfa0ad2SJack F Vogel 	} while (retry);
57268cfa0ad2SJack F Vogel }
57278cfa0ad2SJack F Vogel 
57288cfa0ad2SJack F Vogel /**
57298cfa0ad2SJack F Vogel  *  e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working
57308cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
57318cfa0ad2SJack F Vogel  *
57328cfa0ad2SJack F Vogel  *  Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
57338cfa0ad2SJack F Vogel  *  LPLU, Gig disable, MDIC PHY reset):
57348cfa0ad2SJack F Vogel  *    1) Set Kumeran Near-end loopback
57358cfa0ad2SJack F Vogel  *    2) Clear Kumeran Near-end loopback
57364dab5c37SJack F Vogel  *  Should only be called for ICH8[m] devices with any 1G Phy.
57378cfa0ad2SJack F Vogel  **/
57388cfa0ad2SJack F Vogel void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
57398cfa0ad2SJack F Vogel {
57406ab6bfe3SJack F Vogel 	s32 ret_val;
5741*fc7682b1SKevin Bowling 	u16 reg_data = 0;
57428cfa0ad2SJack F Vogel 
57438cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan");
57448cfa0ad2SJack F Vogel 
57458cfa0ad2SJack F Vogel 	if ((hw->mac.type != e1000_ich8lan) ||
57464dab5c37SJack F Vogel 	    (hw->phy.type == e1000_phy_ife))
57476ab6bfe3SJack F Vogel 		return;
57488cfa0ad2SJack F Vogel 
57498cfa0ad2SJack F Vogel 	ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
57508cfa0ad2SJack F Vogel 					      &reg_data);
57518cfa0ad2SJack F Vogel 	if (ret_val)
57526ab6bfe3SJack F Vogel 		return;
57538cfa0ad2SJack F Vogel 	reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
57548cfa0ad2SJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
57558cfa0ad2SJack F Vogel 					       E1000_KMRNCTRLSTA_DIAG_OFFSET,
57568cfa0ad2SJack F Vogel 					       reg_data);
57578cfa0ad2SJack F Vogel 	if (ret_val)
57588cfa0ad2SJack F Vogel 		return;
57596ab6bfe3SJack F Vogel 	reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
57606ab6bfe3SJack F Vogel 	e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
57616ab6bfe3SJack F Vogel 				     reg_data);
57628cfa0ad2SJack F Vogel }
57638cfa0ad2SJack F Vogel 
57648cfa0ad2SJack F Vogel /**
57654dab5c37SJack F Vogel  *  e1000_suspend_workarounds_ich8lan - workarounds needed during S0->Sx
57668cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
57678cfa0ad2SJack F Vogel  *
57688cfa0ad2SJack F Vogel  *  During S0 to Sx transition, it is possible the link remains at gig
57698cfa0ad2SJack F Vogel  *  instead of negotiating to a lower speed.  Before going to Sx, set
57704dab5c37SJack F Vogel  *  'Gig Disable' to force link speed negotiation to a lower speed based on
57714dab5c37SJack F Vogel  *  the LPLU setting in the NVM or custom setting.  For PCH and newer parts,
57724dab5c37SJack F Vogel  *  the OEM bits PHY register (LED, GbE disable and LPLU configurations) also
57734dab5c37SJack F Vogel  *  needs to be written.
57746ab6bfe3SJack F Vogel  *  Parts that support (and are linked to a partner which support) EEE in
57756ab6bfe3SJack F Vogel  *  100Mbps should disable LPLU since 100Mbps w/ EEE requires less power
57766ab6bfe3SJack F Vogel  *  than 10Mbps w/o EEE.
57778cfa0ad2SJack F Vogel  **/
57784dab5c37SJack F Vogel void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
57798cfa0ad2SJack F Vogel {
57806ab6bfe3SJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
57818cfa0ad2SJack F Vogel 	u32 phy_ctrl;
57827d9119bdSJack F Vogel 	s32 ret_val;
57838cfa0ad2SJack F Vogel 
57844dab5c37SJack F Vogel 	DEBUGFUNC("e1000_suspend_workarounds_ich8lan");
57857d9119bdSJack F Vogel 
57868cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
57874dab5c37SJack F Vogel 	phy_ctrl |= E1000_PHY_CTRL_GBE_DISABLE;
57886ab6bfe3SJack F Vogel 
57896ab6bfe3SJack F Vogel 	if (hw->phy.type == e1000_phy_i217) {
57906ab6bfe3SJack F Vogel 		u16 phy_reg, device_id = hw->device_id;
57916ab6bfe3SJack F Vogel 
57926ab6bfe3SJack F Vogel 		if ((device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
57938cc64f1eSJack F Vogel 		    (device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) ||
57948cc64f1eSJack F Vogel 		    (device_id == E1000_DEV_ID_PCH_I218_LM3) ||
5795c80429ceSEric Joyner 		    (device_id == E1000_DEV_ID_PCH_I218_V3) ||
5796295df609SEric Joyner 		    (hw->mac.type >= e1000_pch_spt)) {
57976ab6bfe3SJack F Vogel 			u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6);
57986ab6bfe3SJack F Vogel 
57996ab6bfe3SJack F Vogel 			E1000_WRITE_REG(hw, E1000_FEXTNVM6,
58006ab6bfe3SJack F Vogel 					fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK);
58016ab6bfe3SJack F Vogel 		}
58026ab6bfe3SJack F Vogel 
58036ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
58046ab6bfe3SJack F Vogel 		if (ret_val)
58056ab6bfe3SJack F Vogel 			goto out;
58066ab6bfe3SJack F Vogel 
58076ab6bfe3SJack F Vogel 		if (!dev_spec->eee_disable) {
58086ab6bfe3SJack F Vogel 			u16 eee_advert;
58096ab6bfe3SJack F Vogel 
58106ab6bfe3SJack F Vogel 			ret_val =
58116ab6bfe3SJack F Vogel 			    e1000_read_emi_reg_locked(hw,
58126ab6bfe3SJack F Vogel 						      I217_EEE_ADVERTISEMENT,
58136ab6bfe3SJack F Vogel 						      &eee_advert);
58146ab6bfe3SJack F Vogel 			if (ret_val)
58156ab6bfe3SJack F Vogel 				goto release;
58166ab6bfe3SJack F Vogel 
58176ab6bfe3SJack F Vogel 			/* Disable LPLU if both link partners support 100BaseT
58186ab6bfe3SJack F Vogel 			 * EEE and 100Full is advertised on both ends of the
58197609433eSJack F Vogel 			 * link, and enable Auto Enable LPI since there will
58207609433eSJack F Vogel 			 * be no driver to enable LPI while in Sx.
58216ab6bfe3SJack F Vogel 			 */
58226ab6bfe3SJack F Vogel 			if ((eee_advert & I82579_EEE_100_SUPPORTED) &&
58236ab6bfe3SJack F Vogel 			    (dev_spec->eee_lp_ability &
58246ab6bfe3SJack F Vogel 			     I82579_EEE_100_SUPPORTED) &&
58257609433eSJack F Vogel 			    (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)) {
58266ab6bfe3SJack F Vogel 				phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU |
58276ab6bfe3SJack F Vogel 					      E1000_PHY_CTRL_NOND0A_LPLU);
58287609433eSJack F Vogel 
58297609433eSJack F Vogel 				/* Set Auto Enable LPI after link up */
58307609433eSJack F Vogel 				hw->phy.ops.read_reg_locked(hw,
58317609433eSJack F Vogel 							    I217_LPI_GPIO_CTRL,
58327609433eSJack F Vogel 							    &phy_reg);
58337609433eSJack F Vogel 				phy_reg |= I217_LPI_GPIO_CTRL_AUTO_EN_LPI;
58347609433eSJack F Vogel 				hw->phy.ops.write_reg_locked(hw,
58357609433eSJack F Vogel 							     I217_LPI_GPIO_CTRL,
58367609433eSJack F Vogel 							     phy_reg);
58377609433eSJack F Vogel 			}
58386ab6bfe3SJack F Vogel 		}
58396ab6bfe3SJack F Vogel 
58406ab6bfe3SJack F Vogel 		/* For i217 Intel Rapid Start Technology support,
58416ab6bfe3SJack F Vogel 		 * when the system is going into Sx and no manageability engine
58426ab6bfe3SJack F Vogel 		 * is present, the driver must configure proxy to reset only on
58436ab6bfe3SJack F Vogel 		 * power good.  LPI (Low Power Idle) state must also reset only
58446ab6bfe3SJack F Vogel 		 * on power good, as well as the MTA (Multicast table array).
58456ab6bfe3SJack F Vogel 		 * The SMBus release must also be disabled on LCD reset.
58466ab6bfe3SJack F Vogel 		 */
58476ab6bfe3SJack F Vogel 		if (!(E1000_READ_REG(hw, E1000_FWSM) &
58486ab6bfe3SJack F Vogel 		      E1000_ICH_FWSM_FW_VALID)) {
58496ab6bfe3SJack F Vogel 			/* Enable proxy to reset only on power good. */
58506ab6bfe3SJack F Vogel 			hw->phy.ops.read_reg_locked(hw, I217_PROXY_CTRL,
58516ab6bfe3SJack F Vogel 						    &phy_reg);
58526ab6bfe3SJack F Vogel 			phy_reg |= I217_PROXY_CTRL_AUTO_DISABLE;
58536ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_PROXY_CTRL,
58546ab6bfe3SJack F Vogel 						     phy_reg);
58556ab6bfe3SJack F Vogel 
58566ab6bfe3SJack F Vogel 			/* Set bit enable LPI (EEE) to reset only on
58576ab6bfe3SJack F Vogel 			 * power good.
58586ab6bfe3SJack F Vogel 			*/
58596ab6bfe3SJack F Vogel 			hw->phy.ops.read_reg_locked(hw, I217_SxCTRL, &phy_reg);
58606ab6bfe3SJack F Vogel 			phy_reg |= I217_SxCTRL_ENABLE_LPI_RESET;
58616ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_SxCTRL, phy_reg);
58626ab6bfe3SJack F Vogel 
58636ab6bfe3SJack F Vogel 			/* Disable the SMB release on LCD reset. */
58646ab6bfe3SJack F Vogel 			hw->phy.ops.read_reg_locked(hw, I217_MEMPWR, &phy_reg);
58656ab6bfe3SJack F Vogel 			phy_reg &= ~I217_MEMPWR_DISABLE_SMB_RELEASE;
58666ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_MEMPWR, phy_reg);
58676ab6bfe3SJack F Vogel 		}
58686ab6bfe3SJack F Vogel 
58696ab6bfe3SJack F Vogel 		/* Enable MTA to reset for Intel Rapid Start Technology
58706ab6bfe3SJack F Vogel 		 * Support
58716ab6bfe3SJack F Vogel 		 */
58726ab6bfe3SJack F Vogel 		hw->phy.ops.read_reg_locked(hw, I217_CGFREG, &phy_reg);
58736ab6bfe3SJack F Vogel 		phy_reg |= I217_CGFREG_ENABLE_MTA_RESET;
58746ab6bfe3SJack F Vogel 		hw->phy.ops.write_reg_locked(hw, I217_CGFREG, phy_reg);
58756ab6bfe3SJack F Vogel 
58766ab6bfe3SJack F Vogel release:
58776ab6bfe3SJack F Vogel 		hw->phy.ops.release(hw);
58786ab6bfe3SJack F Vogel 	}
58796ab6bfe3SJack F Vogel out:
58808cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
58816ab6bfe3SJack F Vogel 
58824dab5c37SJack F Vogel 	if (hw->mac.type == e1000_ich8lan)
58834dab5c37SJack F Vogel 		e1000_gig_downshift_workaround_ich8lan(hw);
58849d81738fSJack F Vogel 
58857d9119bdSJack F Vogel 	if (hw->mac.type >= e1000_pchlan) {
58867d9119bdSJack F Vogel 		e1000_oem_bits_config_ich8lan(hw, FALSE);
58876ab6bfe3SJack F Vogel 
58886ab6bfe3SJack F Vogel 		/* Reset PHY to activate OEM bits on 82577/8 */
58896ab6bfe3SJack F Vogel 		if (hw->mac.type == e1000_pchlan)
58906ab6bfe3SJack F Vogel 			e1000_phy_hw_reset_generic(hw);
58916ab6bfe3SJack F Vogel 
58927d9119bdSJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
58937d9119bdSJack F Vogel 		if (ret_val)
58947d9119bdSJack F Vogel 			return;
58957d9119bdSJack F Vogel 		e1000_write_smbus_addr(hw);
58967d9119bdSJack F Vogel 		hw->phy.ops.release(hw);
58978cfa0ad2SJack F Vogel 	}
58988cfa0ad2SJack F Vogel 
58998cfa0ad2SJack F Vogel 	return;
59008cfa0ad2SJack F Vogel }
59018cfa0ad2SJack F Vogel 
59028cfa0ad2SJack F Vogel /**
59034dab5c37SJack F Vogel  *  e1000_resume_workarounds_pchlan - workarounds needed during Sx->S0
59044dab5c37SJack F Vogel  *  @hw: pointer to the HW structure
59054dab5c37SJack F Vogel  *
59064dab5c37SJack F Vogel  *  During Sx to S0 transitions on non-managed devices or managed devices
59074dab5c37SJack F Vogel  *  on which PHY resets are not blocked, if the PHY registers cannot be
59084dab5c37SJack F Vogel  *  accessed properly by the s/w toggle the LANPHYPC value to power cycle
59094dab5c37SJack F Vogel  *  the PHY.
59106ab6bfe3SJack F Vogel  *  On i217, setup Intel Rapid Start Technology.
59114dab5c37SJack F Vogel  **/
5912c80429ceSEric Joyner u32 e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
59134dab5c37SJack F Vogel {
59144dab5c37SJack F Vogel 	s32 ret_val;
59154dab5c37SJack F Vogel 
59164dab5c37SJack F Vogel 	DEBUGFUNC("e1000_resume_workarounds_pchlan");
59176ab6bfe3SJack F Vogel 	if (hw->mac.type < e1000_pch2lan)
5918c80429ceSEric Joyner 		return E1000_SUCCESS;
59194dab5c37SJack F Vogel 
59206ab6bfe3SJack F Vogel 	ret_val = e1000_init_phy_workarounds_pchlan(hw);
59214dab5c37SJack F Vogel 	if (ret_val) {
59226ab6bfe3SJack F Vogel 		DEBUGOUT1("Failed to init PHY flow ret_val=%d\n", ret_val);
5923c80429ceSEric Joyner 		return ret_val;
59244dab5c37SJack F Vogel 	}
59254dab5c37SJack F Vogel 
59266ab6bfe3SJack F Vogel 	/* For i217 Intel Rapid Start Technology support when the system
59276ab6bfe3SJack F Vogel 	 * is transitioning from Sx and no manageability engine is present
59286ab6bfe3SJack F Vogel 	 * configure SMBus to restore on reset, disable proxy, and enable
59296ab6bfe3SJack F Vogel 	 * the reset on MTA (Multicast table array).
59306ab6bfe3SJack F Vogel 	 */
59316ab6bfe3SJack F Vogel 	if (hw->phy.type == e1000_phy_i217) {
59326ab6bfe3SJack F Vogel 		u16 phy_reg;
59334dab5c37SJack F Vogel 
59346ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
59356ab6bfe3SJack F Vogel 		if (ret_val) {
59366ab6bfe3SJack F Vogel 			DEBUGOUT("Failed to setup iRST\n");
5937c80429ceSEric Joyner 			return ret_val;
59386ab6bfe3SJack F Vogel 		}
59394dab5c37SJack F Vogel 
59407609433eSJack F Vogel 		/* Clear Auto Enable LPI after link up */
59417609433eSJack F Vogel 		hw->phy.ops.read_reg_locked(hw, I217_LPI_GPIO_CTRL, &phy_reg);
59427609433eSJack F Vogel 		phy_reg &= ~I217_LPI_GPIO_CTRL_AUTO_EN_LPI;
59437609433eSJack F Vogel 		hw->phy.ops.write_reg_locked(hw, I217_LPI_GPIO_CTRL, phy_reg);
59447609433eSJack F Vogel 
59456ab6bfe3SJack F Vogel 		if (!(E1000_READ_REG(hw, E1000_FWSM) &
59466ab6bfe3SJack F Vogel 		    E1000_ICH_FWSM_FW_VALID)) {
59476ab6bfe3SJack F Vogel 			/* Restore clear on SMB if no manageability engine
59486ab6bfe3SJack F Vogel 			 * is present
59496ab6bfe3SJack F Vogel 			 */
59506ab6bfe3SJack F Vogel 			ret_val = hw->phy.ops.read_reg_locked(hw, I217_MEMPWR,
59516ab6bfe3SJack F Vogel 							      &phy_reg);
59526ab6bfe3SJack F Vogel 			if (ret_val)
59536ab6bfe3SJack F Vogel 				goto release;
59546ab6bfe3SJack F Vogel 			phy_reg |= I217_MEMPWR_DISABLE_SMB_RELEASE;
59556ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_MEMPWR, phy_reg);
59566ab6bfe3SJack F Vogel 
59576ab6bfe3SJack F Vogel 			/* Disable Proxy */
59586ab6bfe3SJack F Vogel 			hw->phy.ops.write_reg_locked(hw, I217_PROXY_CTRL, 0);
59596ab6bfe3SJack F Vogel 		}
59606ab6bfe3SJack F Vogel 		/* Enable reset on MTA */
59616ab6bfe3SJack F Vogel 		ret_val = hw->phy.ops.read_reg_locked(hw, I217_CGFREG,
59626ab6bfe3SJack F Vogel 						      &phy_reg);
59636ab6bfe3SJack F Vogel 		if (ret_val)
59646ab6bfe3SJack F Vogel 			goto release;
59656ab6bfe3SJack F Vogel 		phy_reg &= ~I217_CGFREG_ENABLE_MTA_RESET;
59666ab6bfe3SJack F Vogel 		hw->phy.ops.write_reg_locked(hw, I217_CGFREG, phy_reg);
59674dab5c37SJack F Vogel release:
59686ab6bfe3SJack F Vogel 		if (ret_val)
59696ab6bfe3SJack F Vogel 			DEBUGOUT1("Error %d in resume workarounds\n", ret_val);
59704dab5c37SJack F Vogel 		hw->phy.ops.release(hw);
5971c80429ceSEric Joyner 		return ret_val;
59726ab6bfe3SJack F Vogel 	}
5973c80429ceSEric Joyner 	return E1000_SUCCESS;
59744dab5c37SJack F Vogel }
59754dab5c37SJack F Vogel 
59764dab5c37SJack F Vogel /**
59778cfa0ad2SJack F Vogel  *  e1000_cleanup_led_ich8lan - Restore the default LED operation
59788cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
59798cfa0ad2SJack F Vogel  *
59808cfa0ad2SJack F Vogel  *  Return the LED back to the default configuration.
59818cfa0ad2SJack F Vogel  **/
59828cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
59838cfa0ad2SJack F Vogel {
59848cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_cleanup_led_ich8lan");
59858cfa0ad2SJack F Vogel 
59868cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
5987a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
59888cfa0ad2SJack F Vogel 					     0);
59898cfa0ad2SJack F Vogel 
5990a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
5991a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
59928cfa0ad2SJack F Vogel }
59938cfa0ad2SJack F Vogel 
59948cfa0ad2SJack F Vogel /**
59958cfa0ad2SJack F Vogel  *  e1000_led_on_ich8lan - Turn LEDs on
59968cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
59978cfa0ad2SJack F Vogel  *
59988cfa0ad2SJack F Vogel  *  Turn on the LEDs.
59998cfa0ad2SJack F Vogel  **/
60008cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw)
60018cfa0ad2SJack F Vogel {
60028cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_led_on_ich8lan");
60038cfa0ad2SJack F Vogel 
60048cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
6005a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
60068cfa0ad2SJack F Vogel 				(IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
60078cfa0ad2SJack F Vogel 
6008a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
6009a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
60108cfa0ad2SJack F Vogel }
60118cfa0ad2SJack F Vogel 
60128cfa0ad2SJack F Vogel /**
60138cfa0ad2SJack F Vogel  *  e1000_led_off_ich8lan - Turn LEDs off
60148cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
60158cfa0ad2SJack F Vogel  *
60168cfa0ad2SJack F Vogel  *  Turn off the LEDs.
60178cfa0ad2SJack F Vogel  **/
60188cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
60198cfa0ad2SJack F Vogel {
60208cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_led_off_ich8lan");
60218cfa0ad2SJack F Vogel 
60228cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
6023a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
60248cfa0ad2SJack F Vogel 			       (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
60258cfa0ad2SJack F Vogel 
6026a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
6027a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
60288cfa0ad2SJack F Vogel }
60298cfa0ad2SJack F Vogel 
60308cfa0ad2SJack F Vogel /**
60319d81738fSJack F Vogel  *  e1000_setup_led_pchlan - Configures SW controllable LED
60329d81738fSJack F Vogel  *  @hw: pointer to the HW structure
60339d81738fSJack F Vogel  *
60349d81738fSJack F Vogel  *  This prepares the SW controllable LED for use.
60359d81738fSJack F Vogel  **/
60369d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw)
60379d81738fSJack F Vogel {
60389d81738fSJack F Vogel 	DEBUGFUNC("e1000_setup_led_pchlan");
60399d81738fSJack F Vogel 
60409d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
60419d81738fSJack F Vogel 				     (u16)hw->mac.ledctl_mode1);
60429d81738fSJack F Vogel }
60439d81738fSJack F Vogel 
60449d81738fSJack F Vogel /**
60459d81738fSJack F Vogel  *  e1000_cleanup_led_pchlan - Restore the default LED operation
60469d81738fSJack F Vogel  *  @hw: pointer to the HW structure
60479d81738fSJack F Vogel  *
60489d81738fSJack F Vogel  *  Return the LED back to the default configuration.
60499d81738fSJack F Vogel  **/
60509d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw)
60519d81738fSJack F Vogel {
60529d81738fSJack F Vogel 	DEBUGFUNC("e1000_cleanup_led_pchlan");
60539d81738fSJack F Vogel 
60549d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
60559d81738fSJack F Vogel 				     (u16)hw->mac.ledctl_default);
60569d81738fSJack F Vogel }
60579d81738fSJack F Vogel 
60589d81738fSJack F Vogel /**
60599d81738fSJack F Vogel  *  e1000_led_on_pchlan - Turn LEDs on
60609d81738fSJack F Vogel  *  @hw: pointer to the HW structure
60619d81738fSJack F Vogel  *
60629d81738fSJack F Vogel  *  Turn on the LEDs.
60639d81738fSJack F Vogel  **/
60649d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw)
60659d81738fSJack F Vogel {
60669d81738fSJack F Vogel 	u16 data = (u16)hw->mac.ledctl_mode2;
60679d81738fSJack F Vogel 	u32 i, led;
60689d81738fSJack F Vogel 
60699d81738fSJack F Vogel 	DEBUGFUNC("e1000_led_on_pchlan");
60709d81738fSJack F Vogel 
60716ab6bfe3SJack F Vogel 	/* If no link, then turn LED on by setting the invert bit
60729d81738fSJack F Vogel 	 * for each LED that's mode is "link_up" in ledctl_mode2.
60739d81738fSJack F Vogel 	 */
60749d81738fSJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
60759d81738fSJack F Vogel 		for (i = 0; i < 3; i++) {
60769d81738fSJack F Vogel 			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
60779d81738fSJack F Vogel 			if ((led & E1000_PHY_LED0_MODE_MASK) !=
60789d81738fSJack F Vogel 			    E1000_LEDCTL_MODE_LINK_UP)
60799d81738fSJack F Vogel 				continue;
60809d81738fSJack F Vogel 			if (led & E1000_PHY_LED0_IVRT)
60819d81738fSJack F Vogel 				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
60829d81738fSJack F Vogel 			else
60839d81738fSJack F Vogel 				data |= (E1000_PHY_LED0_IVRT << (i * 5));
60849d81738fSJack F Vogel 		}
60859d81738fSJack F Vogel 	}
60869d81738fSJack F Vogel 
60879d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
60889d81738fSJack F Vogel }
60899d81738fSJack F Vogel 
60909d81738fSJack F Vogel /**
60919d81738fSJack F Vogel  *  e1000_led_off_pchlan - Turn LEDs off
60929d81738fSJack F Vogel  *  @hw: pointer to the HW structure
60939d81738fSJack F Vogel  *
60949d81738fSJack F Vogel  *  Turn off the LEDs.
60959d81738fSJack F Vogel  **/
60969d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw)
60979d81738fSJack F Vogel {
60989d81738fSJack F Vogel 	u16 data = (u16)hw->mac.ledctl_mode1;
60999d81738fSJack F Vogel 	u32 i, led;
61009d81738fSJack F Vogel 
61019d81738fSJack F Vogel 	DEBUGFUNC("e1000_led_off_pchlan");
61029d81738fSJack F Vogel 
61036ab6bfe3SJack F Vogel 	/* If no link, then turn LED off by clearing the invert bit
61049d81738fSJack F Vogel 	 * for each LED that's mode is "link_up" in ledctl_mode1.
61059d81738fSJack F Vogel 	 */
61069d81738fSJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
61079d81738fSJack F Vogel 		for (i = 0; i < 3; i++) {
61089d81738fSJack F Vogel 			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
61099d81738fSJack F Vogel 			if ((led & E1000_PHY_LED0_MODE_MASK) !=
61109d81738fSJack F Vogel 			    E1000_LEDCTL_MODE_LINK_UP)
61119d81738fSJack F Vogel 				continue;
61129d81738fSJack F Vogel 			if (led & E1000_PHY_LED0_IVRT)
61139d81738fSJack F Vogel 				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
61149d81738fSJack F Vogel 			else
61159d81738fSJack F Vogel 				data |= (E1000_PHY_LED0_IVRT << (i * 5));
61169d81738fSJack F Vogel 		}
61179d81738fSJack F Vogel 	}
61189d81738fSJack F Vogel 
61199d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
61209d81738fSJack F Vogel }
61219d81738fSJack F Vogel 
61229d81738fSJack F Vogel /**
61237d9119bdSJack F Vogel  *  e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset
61248cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
61258cfa0ad2SJack F Vogel  *
61267d9119bdSJack F Vogel  *  Read appropriate register for the config done bit for completion status
61277d9119bdSJack F Vogel  *  and configure the PHY through s/w for EEPROM-less parts.
61287d9119bdSJack F Vogel  *
61297d9119bdSJack F Vogel  *  NOTE: some silicon which is EEPROM-less will fail trying to read the
61307d9119bdSJack F Vogel  *  config done bit, so only an error is logged and continues.  If we were
61317d9119bdSJack F Vogel  *  to return with error, EEPROM-less silicon would not be able to be reset
61327d9119bdSJack F Vogel  *  or change link.
61338cfa0ad2SJack F Vogel  **/
61348cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
61358cfa0ad2SJack F Vogel {
61368cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
61378cfa0ad2SJack F Vogel 	u32 bank = 0;
61387d9119bdSJack F Vogel 	u32 status;
61398cfa0ad2SJack F Vogel 
61407d9119bdSJack F Vogel 	DEBUGFUNC("e1000_get_cfg_done_ich8lan");
61419d81738fSJack F Vogel 
61428cfa0ad2SJack F Vogel 	e1000_get_cfg_done_generic(hw);
61438cfa0ad2SJack F Vogel 
61447d9119bdSJack F Vogel 	/* Wait for indication from h/w that it has completed basic config */
61457d9119bdSJack F Vogel 	if (hw->mac.type >= e1000_ich10lan) {
61467d9119bdSJack F Vogel 		e1000_lan_init_done_ich8lan(hw);
61477d9119bdSJack F Vogel 	} else {
61487d9119bdSJack F Vogel 		ret_val = e1000_get_auto_rd_done_generic(hw);
61497d9119bdSJack F Vogel 		if (ret_val) {
61506ab6bfe3SJack F Vogel 			/* When auto config read does not complete, do not
61517d9119bdSJack F Vogel 			 * return with an error. This can happen in situations
61527d9119bdSJack F Vogel 			 * where there is no eeprom and prevents getting link.
61537d9119bdSJack F Vogel 			 */
61547d9119bdSJack F Vogel 			DEBUGOUT("Auto Read Done did not complete\n");
61557d9119bdSJack F Vogel 			ret_val = E1000_SUCCESS;
61567d9119bdSJack F Vogel 		}
61577d9119bdSJack F Vogel 	}
61587d9119bdSJack F Vogel 
61597d9119bdSJack F Vogel 	/* Clear PHY Reset Asserted bit */
61607d9119bdSJack F Vogel 	status = E1000_READ_REG(hw, E1000_STATUS);
61617d9119bdSJack F Vogel 	if (status & E1000_STATUS_PHYRA)
61627d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_STATUS, status & ~E1000_STATUS_PHYRA);
61637d9119bdSJack F Vogel 	else
61647d9119bdSJack F Vogel 		DEBUGOUT("PHY Reset Asserted not set - needs delay\n");
61657d9119bdSJack F Vogel 
61668cfa0ad2SJack F Vogel 	/* If EEPROM is not marked present, init the IGP 3 PHY manually */
61674edd8523SJack F Vogel 	if (hw->mac.type <= e1000_ich9lan) {
61686ab6bfe3SJack F Vogel 		if (!(E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) &&
61698cfa0ad2SJack F Vogel 		    (hw->phy.type == e1000_phy_igp_3)) {
61708cfa0ad2SJack F Vogel 			e1000_phy_init_script_igp3(hw);
61718cfa0ad2SJack F Vogel 		}
61728cfa0ad2SJack F Vogel 	} else {
61738cfa0ad2SJack F Vogel 		if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
6174daf9197cSJack F Vogel 			/* Maybe we should do a basic PHY config */
61758cfa0ad2SJack F Vogel 			DEBUGOUT("EEPROM not present\n");
61768cfa0ad2SJack F Vogel 			ret_val = -E1000_ERR_CONFIG;
61778cfa0ad2SJack F Vogel 		}
61788cfa0ad2SJack F Vogel 	}
61798cfa0ad2SJack F Vogel 
61808cfa0ad2SJack F Vogel 	return ret_val;
61818cfa0ad2SJack F Vogel }
61828cfa0ad2SJack F Vogel 
61838cfa0ad2SJack F Vogel /**
61848cfa0ad2SJack F Vogel  * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down
61858cfa0ad2SJack F Vogel  * @hw: pointer to the HW structure
61868cfa0ad2SJack F Vogel  *
61878cfa0ad2SJack F Vogel  * In the case of a PHY power down to save power, or to turn off link during a
61888cfa0ad2SJack F Vogel  * driver unload, or wake on lan is not enabled, remove the link.
61898cfa0ad2SJack F Vogel  **/
61908cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
61918cfa0ad2SJack F Vogel {
61928cfa0ad2SJack F Vogel 	/* If the management interface is not enabled, then power down */
6193daf9197cSJack F Vogel 	if (!(hw->mac.ops.check_mng_mode(hw) ||
6194daf9197cSJack F Vogel 	      hw->phy.ops.check_reset_block(hw)))
61958cfa0ad2SJack F Vogel 		e1000_power_down_phy_copper(hw);
61968cfa0ad2SJack F Vogel 
61978cfa0ad2SJack F Vogel 	return;
61988cfa0ad2SJack F Vogel }
61998cfa0ad2SJack F Vogel 
62008cfa0ad2SJack F Vogel /**
62018cfa0ad2SJack F Vogel  *  e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
62028cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
62038cfa0ad2SJack F Vogel  *
62048cfa0ad2SJack F Vogel  *  Clears hardware counters specific to the silicon family and calls
62058cfa0ad2SJack F Vogel  *  clear_hw_cntrs_generic to clear all general purpose counters.
62068cfa0ad2SJack F Vogel  **/
62078cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
62088cfa0ad2SJack F Vogel {
62099d81738fSJack F Vogel 	u16 phy_data;
62104dab5c37SJack F Vogel 	s32 ret_val;
62119d81738fSJack F Vogel 
62128cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan");
62138cfa0ad2SJack F Vogel 
62148cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_base_generic(hw);
62158cfa0ad2SJack F Vogel 
6216daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ALGNERRC);
6217daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_RXERRC);
6218daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TNCRS);
6219daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_CEXTERR);
6220daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTC);
6221daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTFC);
62228cfa0ad2SJack F Vogel 
6223daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPRC);
6224daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPDC);
6225daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPTC);
62268cfa0ad2SJack F Vogel 
6227daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_IAC);
6228daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ICRXOC);
62299d81738fSJack F Vogel 
62309d81738fSJack F Vogel 	/* Clear PHY statistics registers */
62319d81738fSJack F Vogel 	if ((hw->phy.type == e1000_phy_82578) ||
62327d9119bdSJack F Vogel 	    (hw->phy.type == e1000_phy_82579) ||
62336ab6bfe3SJack F Vogel 	    (hw->phy.type == e1000_phy_i217) ||
62349d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577)) {
62354dab5c37SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
62364dab5c37SJack F Vogel 		if (ret_val)
62374dab5c37SJack F Vogel 			return;
62384dab5c37SJack F Vogel 		ret_val = hw->phy.ops.set_page(hw,
62394dab5c37SJack F Vogel 					       HV_STATS_PAGE << IGP_PAGE_SHIFT);
62404dab5c37SJack F Vogel 		if (ret_val)
62414dab5c37SJack F Vogel 			goto release;
62424dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_SCC_UPPER, &phy_data);
62434dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_SCC_LOWER, &phy_data);
62444dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_ECOL_UPPER, &phy_data);
62454dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_ECOL_LOWER, &phy_data);
62464dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_MCC_UPPER, &phy_data);
62474dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_MCC_LOWER, &phy_data);
62484dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_LATECOL_UPPER, &phy_data);
62494dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_LATECOL_LOWER, &phy_data);
62504dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_COLC_UPPER, &phy_data);
62514dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_COLC_LOWER, &phy_data);
62524dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_DC_UPPER, &phy_data);
62534dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_DC_LOWER, &phy_data);
62544dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_TNCRS_UPPER, &phy_data);
62554dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_TNCRS_LOWER, &phy_data);
62564dab5c37SJack F Vogel release:
62574dab5c37SJack F Vogel 		hw->phy.ops.release(hw);
62589d81738fSJack F Vogel 	}
62598cfa0ad2SJack F Vogel }
62608cfa0ad2SJack F Vogel 
6261*fc7682b1SKevin Bowling /**
6262*fc7682b1SKevin Bowling  *  e1000_configure_k0s_lpt - Configure K0s power state
6263*fc7682b1SKevin Bowling  *  @hw: pointer to the HW structure
6264*fc7682b1SKevin Bowling  *  @entry_latency: Tx idle period for entering K0s - valid values are 0 to 3.
6265*fc7682b1SKevin Bowling  *	0 corresponds to 128ns, each value over 0 doubles the duration.
6266*fc7682b1SKevin Bowling  *  @min_time: Minimum Tx idle period allowed  - valid values are 0 to 4.
6267*fc7682b1SKevin Bowling  *	0 corresponds to 128ns, each value over 0 doubles the duration.
6268*fc7682b1SKevin Bowling  *
6269*fc7682b1SKevin Bowling  *  Configure the K1 power state based on the provided parameter.
6270*fc7682b1SKevin Bowling  *  Assumes semaphore already acquired.
6271*fc7682b1SKevin Bowling  *
6272*fc7682b1SKevin Bowling  *  Success returns 0, Failure returns:
6273*fc7682b1SKevin Bowling  *	-E1000_ERR_PHY (-2) in case of access error
6274*fc7682b1SKevin Bowling  *	-E1000_ERR_PARAM (-4) in case of parameters error
6275*fc7682b1SKevin Bowling  **/
6276*fc7682b1SKevin Bowling s32 e1000_configure_k0s_lpt(struct e1000_hw *hw, u8 entry_latency, u8 min_time)
6277*fc7682b1SKevin Bowling {
6278*fc7682b1SKevin Bowling 	s32 ret_val;
6279*fc7682b1SKevin Bowling 	u16 kmrn_reg = 0;
6280*fc7682b1SKevin Bowling 
6281*fc7682b1SKevin Bowling 	DEBUGFUNC("e1000_configure_k0s_lpt");
6282*fc7682b1SKevin Bowling 
6283*fc7682b1SKevin Bowling 	if (entry_latency > 3 || min_time > 4)
6284*fc7682b1SKevin Bowling 		return -E1000_ERR_PARAM;
6285*fc7682b1SKevin Bowling 
6286*fc7682b1SKevin Bowling 	ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K0S_CTRL,
6287*fc7682b1SKevin Bowling 					     &kmrn_reg);
6288*fc7682b1SKevin Bowling 	if (ret_val)
6289*fc7682b1SKevin Bowling 		return ret_val;
6290*fc7682b1SKevin Bowling 
6291*fc7682b1SKevin Bowling 	/* for now don't touch the latency */
6292*fc7682b1SKevin Bowling 	kmrn_reg &= ~(E1000_KMRNCTRLSTA_K0S_CTRL_MIN_TIME_MASK);
6293*fc7682b1SKevin Bowling 	kmrn_reg |= ((min_time << E1000_KMRNCTRLSTA_K0S_CTRL_MIN_TIME_SHIFT));
6294*fc7682b1SKevin Bowling 
6295*fc7682b1SKevin Bowling 	ret_val = e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K0S_CTRL,
6296*fc7682b1SKevin Bowling 					      kmrn_reg);
6297*fc7682b1SKevin Bowling 	if (ret_val)
6298*fc7682b1SKevin Bowling 		return ret_val;
6299*fc7682b1SKevin Bowling 
6300*fc7682b1SKevin Bowling 	return E1000_SUCCESS;
6301*fc7682b1SKevin Bowling }
6302