xref: /freebsd/sys/dev/e1000/e1000_ich8lan.c (revision 4dab5c3769d953bed52fdd06bea77a96af745cfd)
18cfa0ad2SJack F Vogel /******************************************************************************
28cfa0ad2SJack F Vogel 
3*4dab5c37SJack F Vogel   Copyright (c) 2001-2011, Intel Corporation
48cfa0ad2SJack F Vogel   All rights reserved.
58cfa0ad2SJack F Vogel 
68cfa0ad2SJack F Vogel   Redistribution and use in source and binary forms, with or without
78cfa0ad2SJack F Vogel   modification, are permitted provided that the following conditions are met:
88cfa0ad2SJack F Vogel 
98cfa0ad2SJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
108cfa0ad2SJack F Vogel       this list of conditions and the following disclaimer.
118cfa0ad2SJack F Vogel 
128cfa0ad2SJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
138cfa0ad2SJack F Vogel       notice, this list of conditions and the following disclaimer in the
148cfa0ad2SJack F Vogel       documentation and/or other materials provided with the distribution.
158cfa0ad2SJack F Vogel 
168cfa0ad2SJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
178cfa0ad2SJack F Vogel       contributors may be used to endorse or promote products derived from
188cfa0ad2SJack F Vogel       this software without specific prior written permission.
198cfa0ad2SJack F Vogel 
208cfa0ad2SJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
218cfa0ad2SJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
228cfa0ad2SJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
238cfa0ad2SJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
248cfa0ad2SJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
258cfa0ad2SJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
268cfa0ad2SJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
278cfa0ad2SJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
288cfa0ad2SJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
298cfa0ad2SJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
308cfa0ad2SJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
318cfa0ad2SJack F Vogel 
328cfa0ad2SJack F Vogel ******************************************************************************/
338cfa0ad2SJack F Vogel /*$FreeBSD$*/
348cfa0ad2SJack F Vogel 
35daf9197cSJack F Vogel /*
36daf9197cSJack 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
638cfa0ad2SJack F Vogel  */
648cfa0ad2SJack F Vogel 
658cfa0ad2SJack F Vogel #include "e1000_api.h"
668cfa0ad2SJack F Vogel 
678cfa0ad2SJack F Vogel static s32  e1000_init_phy_params_ich8lan(struct e1000_hw *hw);
689d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw);
698cfa0ad2SJack F Vogel static s32  e1000_init_nvm_params_ich8lan(struct e1000_hw *hw);
708cfa0ad2SJack F Vogel static s32  e1000_init_mac_params_ich8lan(struct e1000_hw *hw);
718cfa0ad2SJack F Vogel static s32  e1000_acquire_swflag_ich8lan(struct e1000_hw *hw);
728cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw);
734edd8523SJack F Vogel static s32  e1000_acquire_nvm_ich8lan(struct e1000_hw *hw);
744edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw);
758cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
767d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
777d9119bdSJack F Vogel static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index);
78730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw,
79730d3130SJack F Vogel 					      u8 *mc_addr_list,
80730d3130SJack F Vogel 					      u32 mc_addr_count);
818cfa0ad2SJack F Vogel static s32  e1000_check_reset_block_ich8lan(struct e1000_hw *hw);
828cfa0ad2SJack F Vogel static s32  e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw);
834edd8523SJack F Vogel static s32  e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active);
848cfa0ad2SJack F Vogel static s32  e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
858cfa0ad2SJack F Vogel 					    bool active);
868cfa0ad2SJack F Vogel static s32  e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
878cfa0ad2SJack F Vogel 					    bool active);
888cfa0ad2SJack F Vogel static s32  e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
898cfa0ad2SJack F Vogel 				   u16 words, u16 *data);
908cfa0ad2SJack F Vogel static s32  e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
918cfa0ad2SJack F Vogel 				    u16 words, u16 *data);
928cfa0ad2SJack F Vogel static s32  e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw);
938cfa0ad2SJack F Vogel static s32  e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
948cfa0ad2SJack F Vogel static s32  e1000_valid_led_default_ich8lan(struct e1000_hw *hw,
958cfa0ad2SJack F Vogel 					    u16 *data);
969d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw);
978cfa0ad2SJack F Vogel static s32  e1000_get_bus_info_ich8lan(struct e1000_hw *hw);
988cfa0ad2SJack F Vogel static s32  e1000_reset_hw_ich8lan(struct e1000_hw *hw);
998cfa0ad2SJack F Vogel static s32  e1000_init_hw_ich8lan(struct e1000_hw *hw);
1008cfa0ad2SJack F Vogel static s32  e1000_setup_link_ich8lan(struct e1000_hw *hw);
1018cfa0ad2SJack F Vogel static s32  e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
1028cfa0ad2SJack F Vogel static s32  e1000_get_link_up_info_ich8lan(struct e1000_hw *hw,
1038cfa0ad2SJack F Vogel 					   u16 *speed, u16 *duplex);
1048cfa0ad2SJack F Vogel static s32  e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
1058cfa0ad2SJack F Vogel static s32  e1000_led_on_ich8lan(struct e1000_hw *hw);
1068cfa0ad2SJack F Vogel static s32  e1000_led_off_ich8lan(struct e1000_hw *hw);
1074edd8523SJack F Vogel static s32  e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
1089d81738fSJack F Vogel static s32  e1000_setup_led_pchlan(struct e1000_hw *hw);
1099d81738fSJack F Vogel static s32  e1000_cleanup_led_pchlan(struct e1000_hw *hw);
1109d81738fSJack F Vogel static s32  e1000_led_on_pchlan(struct e1000_hw *hw);
1119d81738fSJack F Vogel static s32  e1000_led_off_pchlan(struct e1000_hw *hw);
1128cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
1138cfa0ad2SJack F Vogel static s32  e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
1148cfa0ad2SJack F Vogel static s32  e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout);
1158cfa0ad2SJack F Vogel static s32  e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw);
1168cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
1178cfa0ad2SJack F Vogel static s32  e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
1188cfa0ad2SJack F Vogel static s32  e1000_read_flash_byte_ich8lan(struct e1000_hw *hw,
1198cfa0ad2SJack F Vogel 					  u32 offset, u8 *data);
1208cfa0ad2SJack F Vogel static s32  e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
1218cfa0ad2SJack F Vogel 					  u8 size, u16 *data);
1228cfa0ad2SJack F Vogel static s32  e1000_read_flash_word_ich8lan(struct e1000_hw *hw,
1238cfa0ad2SJack F Vogel 					  u32 offset, u16 *data);
1248cfa0ad2SJack F Vogel static s32  e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
1258cfa0ad2SJack F Vogel 						 u32 offset, u8 byte);
1268cfa0ad2SJack F Vogel static s32  e1000_write_flash_byte_ich8lan(struct e1000_hw *hw,
1278cfa0ad2SJack F Vogel 					   u32 offset, u8 data);
1288cfa0ad2SJack F Vogel static s32  e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
1298cfa0ad2SJack F Vogel 					   u8 size, u16 data);
1308cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
1318cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
1324edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw);
1334edd8523SJack F Vogel static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw);
1344edd8523SJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw);
135a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
1367d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw);
1377d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate);
138*4dab5c37SJack F Vogel #if defined(NAHUM6_HW) && (defined(LTR_SUPPORT) || defined(OBFF_SUPPORT))
139*4dab5c37SJack F Vogel 
140*4dab5c37SJack F Vogel #endif /* NAHUM6_HW && (LTR_SUPPORT || OBFF_SUPPORT) */
1418cfa0ad2SJack F Vogel 
1428cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
1438cfa0ad2SJack F Vogel /* Offset 04h HSFSTS */
1448cfa0ad2SJack F Vogel union ich8_hws_flash_status {
1458cfa0ad2SJack F Vogel 	struct ich8_hsfsts {
1468cfa0ad2SJack F Vogel 		u16 flcdone:1; /* bit 0 Flash Cycle Done */
1478cfa0ad2SJack F Vogel 		u16 flcerr:1; /* bit 1 Flash Cycle Error */
1488cfa0ad2SJack F Vogel 		u16 dael:1; /* bit 2 Direct Access error Log */
1498cfa0ad2SJack F Vogel 		u16 berasesz:2; /* bit 4:3 Sector Erase Size */
1508cfa0ad2SJack F Vogel 		u16 flcinprog:1; /* bit 5 flash cycle in Progress */
1518cfa0ad2SJack F Vogel 		u16 reserved1:2; /* bit 13:6 Reserved */
1528cfa0ad2SJack F Vogel 		u16 reserved2:6; /* bit 13:6 Reserved */
1538cfa0ad2SJack F Vogel 		u16 fldesvalid:1; /* bit 14 Flash Descriptor Valid */
1548cfa0ad2SJack F Vogel 		u16 flockdn:1; /* bit 15 Flash Config Lock-Down */
1558cfa0ad2SJack F Vogel 	} hsf_status;
1568cfa0ad2SJack F Vogel 	u16 regval;
1578cfa0ad2SJack F Vogel };
1588cfa0ad2SJack F Vogel 
1598cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
1608cfa0ad2SJack F Vogel /* Offset 06h FLCTL */
1618cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl {
1628cfa0ad2SJack F Vogel 	struct ich8_hsflctl {
1638cfa0ad2SJack F Vogel 		u16 flcgo:1;   /* 0 Flash Cycle Go */
1648cfa0ad2SJack F Vogel 		u16 flcycle:2;   /* 2:1 Flash Cycle */
1658cfa0ad2SJack F Vogel 		u16 reserved:5;   /* 7:3 Reserved  */
1668cfa0ad2SJack F Vogel 		u16 fldbcount:2;   /* 9:8 Flash Data Byte Count */
1678cfa0ad2SJack F Vogel 		u16 flockdn:6;   /* 15:10 Reserved */
1688cfa0ad2SJack F Vogel 	} hsf_ctrl;
1698cfa0ad2SJack F Vogel 	u16 regval;
1708cfa0ad2SJack F Vogel };
1718cfa0ad2SJack F Vogel 
1728cfa0ad2SJack F Vogel /* ICH Flash Region Access Permissions */
1738cfa0ad2SJack F Vogel union ich8_hws_flash_regacc {
1748cfa0ad2SJack F Vogel 	struct ich8_flracc {
1758cfa0ad2SJack F Vogel 		u32 grra:8; /* 0:7 GbE region Read Access */
1768cfa0ad2SJack F Vogel 		u32 grwa:8; /* 8:15 GbE region Write Access */
1778cfa0ad2SJack F Vogel 		u32 gmrag:8; /* 23:16 GbE Master Read Access Grant */
1788cfa0ad2SJack F Vogel 		u32 gmwag:8; /* 31:24 GbE Master Write Access Grant */
1798cfa0ad2SJack F Vogel 	} hsf_flregacc;
1808cfa0ad2SJack F Vogel 	u16 regval;
1818cfa0ad2SJack F Vogel };
1828cfa0ad2SJack F Vogel 
183*4dab5c37SJack F Vogel static void e1000_toggle_lanphypc_value_ich8lan(struct e1000_hw *hw)
184*4dab5c37SJack F Vogel {
185*4dab5c37SJack F Vogel 	u32 ctrl;
186*4dab5c37SJack F Vogel 
187*4dab5c37SJack F Vogel 	DEBUGFUNC("e1000_toggle_lanphypc_value_ich8lan");
188*4dab5c37SJack F Vogel 
189*4dab5c37SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
190*4dab5c37SJack F Vogel 	ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE;
191*4dab5c37SJack F Vogel 	ctrl &= ~E1000_CTRL_LANPHYPC_VALUE;
192*4dab5c37SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
193*4dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
194*4dab5c37SJack F Vogel 	usec_delay(10);
195*4dab5c37SJack F Vogel 	ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
196*4dab5c37SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
197*4dab5c37SJack F Vogel }
198*4dab5c37SJack F Vogel 
1998cfa0ad2SJack F Vogel /**
2009d81738fSJack F Vogel  *  e1000_init_phy_params_pchlan - Initialize PHY function pointers
2019d81738fSJack F Vogel  *  @hw: pointer to the HW structure
2029d81738fSJack F Vogel  *
2039d81738fSJack F Vogel  *  Initialize family-specific PHY parameters and function pointers.
2049d81738fSJack F Vogel  **/
2059d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
2069d81738fSJack F Vogel {
2079d81738fSJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
2089d81738fSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
2099d81738fSJack F Vogel 
2109d81738fSJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_pchlan");
2119d81738fSJack F Vogel 
2129d81738fSJack F Vogel 	phy->addr		= 1;
2139d81738fSJack F Vogel 	phy->reset_delay_us	= 100;
2149d81738fSJack F Vogel 
2159d81738fSJack F Vogel 	phy->ops.acquire	= e1000_acquire_swflag_ich8lan;
2169d81738fSJack F Vogel 	phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
2179d81738fSJack F Vogel 	phy->ops.get_cfg_done	= e1000_get_cfg_done_ich8lan;
218*4dab5c37SJack F Vogel 	phy->ops.set_page	= e1000_set_page_igp;
2199d81738fSJack F Vogel 	phy->ops.read_reg	= e1000_read_phy_reg_hv;
2204edd8523SJack F Vogel 	phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked;
221*4dab5c37SJack F Vogel 	phy->ops.read_reg_page	= e1000_read_phy_reg_page_hv;
2229d81738fSJack F Vogel 	phy->ops.release	= e1000_release_swflag_ich8lan;
2239d81738fSJack F Vogel 	phy->ops.reset		= e1000_phy_hw_reset_ich8lan;
2244edd8523SJack F Vogel 	phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan;
2254edd8523SJack F Vogel 	phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan;
2269d81738fSJack F Vogel 	phy->ops.write_reg	= e1000_write_phy_reg_hv;
2274edd8523SJack F Vogel 	phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked;
228*4dab5c37SJack F Vogel 	phy->ops.write_reg_page	= e1000_write_phy_reg_page_hv;
2299d81738fSJack F Vogel 	phy->ops.power_up	= e1000_power_up_phy_copper;
2309d81738fSJack F Vogel 	phy->ops.power_down	= e1000_power_down_phy_copper_ich8lan;
2319d81738fSJack F Vogel 	phy->autoneg_mask	= AUTONEG_ADVERTISE_SPEED_DEFAULT;
2329d81738fSJack F Vogel 
233*4dab5c37SJack F Vogel 	if (!hw->phy.ops.check_reset_block(hw)) {
234*4dab5c37SJack F Vogel 		u32 fwsm = E1000_READ_REG(hw, E1000_FWSM);
235*4dab5c37SJack F Vogel 
2368ec87fc5SJack F Vogel 		/*
237*4dab5c37SJack F Vogel 		 * The MAC-PHY interconnect may still be in SMBus mode after
238*4dab5c37SJack F Vogel 		 * Sx->S0.  If resetting the PHY is not blocked, toggle the
239*4dab5c37SJack F Vogel 		 * LANPHYPC Value bit to force the interconnect to PCIe mode.
2408ec87fc5SJack F Vogel 		 */
241*4dab5c37SJack F Vogel 		e1000_toggle_lanphypc_value_ich8lan(hw);
2428ec87fc5SJack F Vogel 		msec_delay(50);
2437d9119bdSJack F Vogel 
2447d9119bdSJack F Vogel 		/*
2457d9119bdSJack F Vogel 		 * Gate automatic PHY configuration by hardware on
2467d9119bdSJack F Vogel 		 * non-managed 82579
2477d9119bdSJack F Vogel 		 */
248*4dab5c37SJack F Vogel 		if ((hw->mac.type == e1000_pch2lan) &&
249*4dab5c37SJack F Vogel 		    !(fwsm & E1000_ICH_FWSM_FW_VALID))
2507d9119bdSJack F Vogel 			e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
2518ec87fc5SJack F Vogel 
2528ec87fc5SJack F Vogel 		/*
253*4dab5c37SJack F Vogel 		 * Reset the PHY before any access to it.  Doing so, ensures
254*4dab5c37SJack F Vogel 		 * that the PHY is in a known good state before we read/write
255*4dab5c37SJack F Vogel 		 * PHY registers.  The generic reset is sufficient here,
256*4dab5c37SJack F Vogel 		 * because we haven't determined the PHY type yet.
2578ec87fc5SJack F Vogel 		 */
2588ec87fc5SJack F Vogel 		ret_val = e1000_phy_hw_reset_generic(hw);
2598ec87fc5SJack F Vogel 		if (ret_val)
2608ec87fc5SJack F Vogel 			goto out;
2618ec87fc5SJack F Vogel 
2627d9119bdSJack F Vogel 		/* Ungate automatic PHY configuration on non-managed 82579 */
2637d9119bdSJack F Vogel 		if ((hw->mac.type == e1000_pch2lan) &&
2647d9119bdSJack F Vogel 		    !(fwsm & E1000_ICH_FWSM_FW_VALID)) {
2657d9119bdSJack F Vogel 			msec_delay(10);
2667d9119bdSJack F Vogel 			e1000_gate_hw_phy_config_ich8lan(hw, FALSE);
2677d9119bdSJack F Vogel 		}
268*4dab5c37SJack F Vogel 	}
2697d9119bdSJack F Vogel 
2709d81738fSJack F Vogel 	phy->id = e1000_phy_unknown;
2717d9119bdSJack F Vogel 	switch (hw->mac.type) {
2727d9119bdSJack F Vogel 	default:
273a69ed8dfSJack F Vogel 		ret_val = e1000_get_phy_id(hw);
274a69ed8dfSJack F Vogel 		if (ret_val)
275a69ed8dfSJack F Vogel 			goto out;
2767d9119bdSJack F Vogel 		if ((phy->id != 0) && (phy->id != PHY_REVISION_MASK))
2777d9119bdSJack F Vogel 			break;
2787d9119bdSJack F Vogel 		/* fall-through */
2797d9119bdSJack F Vogel 	case e1000_pch2lan:
280a69ed8dfSJack F Vogel 		/*
2817d9119bdSJack F Vogel 		 * In case the PHY needs to be in mdio slow mode,
282a69ed8dfSJack F Vogel 		 * set slow mode and try to get the PHY id again.
283a69ed8dfSJack F Vogel 		 */
284a69ed8dfSJack F Vogel 		ret_val = e1000_set_mdio_slow_mode_hv(hw);
285a69ed8dfSJack F Vogel 		if (ret_val)
286a69ed8dfSJack F Vogel 			goto out;
287a69ed8dfSJack F Vogel 		ret_val = e1000_get_phy_id(hw);
288a69ed8dfSJack F Vogel 		if (ret_val)
289a69ed8dfSJack F Vogel 			goto out;
2907d9119bdSJack F Vogel 		break;
291a69ed8dfSJack F Vogel 	}
2929d81738fSJack F Vogel 	phy->type = e1000_get_phy_type_from_id(phy->id);
2939d81738fSJack F Vogel 
2944edd8523SJack F Vogel 	switch (phy->type) {
2954edd8523SJack F Vogel 	case e1000_phy_82577:
2967d9119bdSJack F Vogel 	case e1000_phy_82579:
2979d81738fSJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_82577;
2989d81738fSJack F Vogel 		phy->ops.force_speed_duplex =
2999d81738fSJack F Vogel 			e1000_phy_force_speed_duplex_82577;
3009d81738fSJack F Vogel 		phy->ops.get_cable_length = e1000_get_cable_length_82577;
3019d81738fSJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_82577;
3029d81738fSJack F Vogel 		phy->ops.commit = e1000_phy_sw_reset_generic;
3038ec87fc5SJack F Vogel 		break;
3044edd8523SJack F Vogel 	case e1000_phy_82578:
3054edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_m88;
3064edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
3074edd8523SJack F Vogel 		phy->ops.get_cable_length = e1000_get_cable_length_m88;
3084edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_m88;
3094edd8523SJack F Vogel 		break;
3104edd8523SJack F Vogel 	default:
3114edd8523SJack F Vogel 		ret_val = -E1000_ERR_PHY;
3124edd8523SJack F Vogel 		break;
3139d81738fSJack F Vogel 	}
3149d81738fSJack F Vogel 
315a69ed8dfSJack F Vogel out:
3169d81738fSJack F Vogel 	return ret_val;
3179d81738fSJack F Vogel }
3189d81738fSJack F Vogel 
3199d81738fSJack F Vogel /**
3208cfa0ad2SJack F Vogel  *  e1000_init_phy_params_ich8lan - Initialize PHY function pointers
3218cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
3228cfa0ad2SJack F Vogel  *
3238cfa0ad2SJack F Vogel  *  Initialize family-specific PHY parameters and function pointers.
3248cfa0ad2SJack F Vogel  **/
3258cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
3268cfa0ad2SJack F Vogel {
3278cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
3288cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
3298cfa0ad2SJack F Vogel 	u16 i = 0;
3308cfa0ad2SJack F Vogel 
3318cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_ich8lan");
3328cfa0ad2SJack F Vogel 
3338cfa0ad2SJack F Vogel 	phy->addr		= 1;
3348cfa0ad2SJack F Vogel 	phy->reset_delay_us	= 100;
3358cfa0ad2SJack F Vogel 
3368cfa0ad2SJack F Vogel 	phy->ops.acquire	= e1000_acquire_swflag_ich8lan;
3378cfa0ad2SJack F Vogel 	phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
3388cfa0ad2SJack F Vogel 	phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
3398cfa0ad2SJack F Vogel 	phy->ops.get_cfg_done	= e1000_get_cfg_done_ich8lan;
3408cfa0ad2SJack F Vogel 	phy->ops.read_reg	= e1000_read_phy_reg_igp;
3418cfa0ad2SJack F Vogel 	phy->ops.release	= e1000_release_swflag_ich8lan;
3428cfa0ad2SJack F Vogel 	phy->ops.reset		= e1000_phy_hw_reset_ich8lan;
3438cfa0ad2SJack F Vogel 	phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan;
3448cfa0ad2SJack F Vogel 	phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan;
3458cfa0ad2SJack F Vogel 	phy->ops.write_reg	= e1000_write_phy_reg_igp;
3468cfa0ad2SJack F Vogel 	phy->ops.power_up	= e1000_power_up_phy_copper;
3478cfa0ad2SJack F Vogel 	phy->ops.power_down	= e1000_power_down_phy_copper_ich8lan;
3488cfa0ad2SJack F Vogel 
3498cfa0ad2SJack F Vogel 	/*
3508cfa0ad2SJack F Vogel 	 * We may need to do this twice - once for IGP and if that fails,
3518cfa0ad2SJack F Vogel 	 * we'll set BM func pointers and try again
3528cfa0ad2SJack F Vogel 	 */
3538cfa0ad2SJack F Vogel 	ret_val = e1000_determine_phy_address(hw);
3548cfa0ad2SJack F Vogel 	if (ret_val) {
3558cfa0ad2SJack F Vogel 		phy->ops.write_reg = e1000_write_phy_reg_bm;
3568cfa0ad2SJack F Vogel 		phy->ops.read_reg  = e1000_read_phy_reg_bm;
3578cfa0ad2SJack F Vogel 		ret_val = e1000_determine_phy_address(hw);
3588cfa0ad2SJack F Vogel 		if (ret_val) {
359d035aa2dSJack F Vogel 			DEBUGOUT("Cannot determine PHY addr. Erroring out\n");
3608cfa0ad2SJack F Vogel 			goto out;
3618cfa0ad2SJack F Vogel 		}
3628cfa0ad2SJack F Vogel 	}
3638cfa0ad2SJack F Vogel 
3648cfa0ad2SJack F Vogel 	phy->id = 0;
3658cfa0ad2SJack F Vogel 	while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) &&
3668cfa0ad2SJack F Vogel 	       (i++ < 100)) {
3678cfa0ad2SJack F Vogel 		msec_delay(1);
3688cfa0ad2SJack F Vogel 		ret_val = e1000_get_phy_id(hw);
3698cfa0ad2SJack F Vogel 		if (ret_val)
3708cfa0ad2SJack F Vogel 			goto out;
3718cfa0ad2SJack F Vogel 	}
3728cfa0ad2SJack F Vogel 
3738cfa0ad2SJack F Vogel 	/* Verify phy id */
3748cfa0ad2SJack F Vogel 	switch (phy->id) {
3758cfa0ad2SJack F Vogel 	case IGP03E1000_E_PHY_ID:
3768cfa0ad2SJack F Vogel 		phy->type = e1000_phy_igp_3;
3778cfa0ad2SJack F Vogel 		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
3784edd8523SJack F Vogel 		phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked;
3794edd8523SJack F Vogel 		phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked;
3804edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_igp;
3814edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_igp;
3824edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
3838cfa0ad2SJack F Vogel 		break;
3848cfa0ad2SJack F Vogel 	case IFE_E_PHY_ID:
3858cfa0ad2SJack F Vogel 	case IFE_PLUS_E_PHY_ID:
3868cfa0ad2SJack F Vogel 	case IFE_C_E_PHY_ID:
3878cfa0ad2SJack F Vogel 		phy->type = e1000_phy_ife;
3888cfa0ad2SJack F Vogel 		phy->autoneg_mask = E1000_ALL_NOT_GIG;
3894edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_ife;
3904edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_ife;
3914edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife;
3928cfa0ad2SJack F Vogel 		break;
3938cfa0ad2SJack F Vogel 	case BME1000_E_PHY_ID:
3948cfa0ad2SJack F Vogel 		phy->type = e1000_phy_bm;
3958cfa0ad2SJack F Vogel 		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
3968cfa0ad2SJack F Vogel 		phy->ops.read_reg = e1000_read_phy_reg_bm;
3978cfa0ad2SJack F Vogel 		phy->ops.write_reg = e1000_write_phy_reg_bm;
3988cfa0ad2SJack F Vogel 		phy->ops.commit = e1000_phy_sw_reset_generic;
3994edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_m88;
4004edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_m88;
4014edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
4028cfa0ad2SJack F Vogel 		break;
4038cfa0ad2SJack F Vogel 	default:
4048cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_PHY;
4058cfa0ad2SJack F Vogel 		goto out;
4068cfa0ad2SJack F Vogel 	}
4078cfa0ad2SJack F Vogel 
4088cfa0ad2SJack F Vogel out:
4098cfa0ad2SJack F Vogel 	return ret_val;
4108cfa0ad2SJack F Vogel }
4118cfa0ad2SJack F Vogel 
4128cfa0ad2SJack F Vogel /**
4138cfa0ad2SJack F Vogel  *  e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
4148cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
4158cfa0ad2SJack F Vogel  *
4168cfa0ad2SJack F Vogel  *  Initialize family-specific NVM parameters and function
4178cfa0ad2SJack F Vogel  *  pointers.
4188cfa0ad2SJack F Vogel  **/
4198cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
4208cfa0ad2SJack F Vogel {
4218cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
422daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
4238cfa0ad2SJack F Vogel 	u32 gfpreg, sector_base_addr, sector_end_addr;
4248cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
4258cfa0ad2SJack F Vogel 	u16 i;
4268cfa0ad2SJack F Vogel 
4278cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_nvm_params_ich8lan");
4288cfa0ad2SJack F Vogel 
4298cfa0ad2SJack F Vogel 	/* Can't read flash registers if the register set isn't mapped. */
4308cfa0ad2SJack F Vogel 	if (!hw->flash_address) {
4318cfa0ad2SJack F Vogel 		DEBUGOUT("ERROR: Flash registers not mapped\n");
4328cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
4338cfa0ad2SJack F Vogel 		goto out;
4348cfa0ad2SJack F Vogel 	}
4358cfa0ad2SJack F Vogel 
4368cfa0ad2SJack F Vogel 	nvm->type = e1000_nvm_flash_sw;
4378cfa0ad2SJack F Vogel 
4388cfa0ad2SJack F Vogel 	gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG);
4398cfa0ad2SJack F Vogel 
4408cfa0ad2SJack F Vogel 	/*
4418cfa0ad2SJack F Vogel 	 * sector_X_addr is a "sector"-aligned address (4096 bytes)
4428cfa0ad2SJack F Vogel 	 * Add 1 to sector_end_addr since this sector is included in
4438cfa0ad2SJack F Vogel 	 * the overall size.
4448cfa0ad2SJack F Vogel 	 */
4458cfa0ad2SJack F Vogel 	sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
4468cfa0ad2SJack F Vogel 	sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
4478cfa0ad2SJack F Vogel 
4488cfa0ad2SJack F Vogel 	/* flash_base_addr is byte-aligned */
4498cfa0ad2SJack F Vogel 	nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
4508cfa0ad2SJack F Vogel 
4518cfa0ad2SJack F Vogel 	/*
4528cfa0ad2SJack F Vogel 	 * find total size of the NVM, then cut in half since the total
4538cfa0ad2SJack F Vogel 	 * size represents two separate NVM banks.
4548cfa0ad2SJack F Vogel 	 */
4558cfa0ad2SJack F Vogel 	nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
4568cfa0ad2SJack F Vogel 				<< FLASH_SECTOR_ADDR_SHIFT;
4578cfa0ad2SJack F Vogel 	nvm->flash_bank_size /= 2;
4588cfa0ad2SJack F Vogel 	/* Adjust to word count */
4598cfa0ad2SJack F Vogel 	nvm->flash_bank_size /= sizeof(u16);
4608cfa0ad2SJack F Vogel 
4618cfa0ad2SJack F Vogel 	nvm->word_size = E1000_SHADOW_RAM_WORDS;
4628cfa0ad2SJack F Vogel 
4638cfa0ad2SJack F Vogel 	/* Clear shadow ram */
4648cfa0ad2SJack F Vogel 	for (i = 0; i < nvm->word_size; i++) {
4658cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].modified = FALSE;
4668cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].value    = 0xFFFF;
4678cfa0ad2SJack F Vogel 	}
4688cfa0ad2SJack F Vogel 
4694edd8523SJack F Vogel 	E1000_MUTEX_INIT(&dev_spec->nvm_mutex);
4704edd8523SJack F Vogel 	E1000_MUTEX_INIT(&dev_spec->swflag_mutex);
4714edd8523SJack F Vogel 
4728cfa0ad2SJack F Vogel 	/* Function Pointers */
4734edd8523SJack F Vogel 	nvm->ops.acquire	= e1000_acquire_nvm_ich8lan;
4744edd8523SJack F Vogel 	nvm->ops.release	= e1000_release_nvm_ich8lan;
4758cfa0ad2SJack F Vogel 	nvm->ops.read		= e1000_read_nvm_ich8lan;
4768cfa0ad2SJack F Vogel 	nvm->ops.update		= e1000_update_nvm_checksum_ich8lan;
4778cfa0ad2SJack F Vogel 	nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan;
4788cfa0ad2SJack F Vogel 	nvm->ops.validate	= e1000_validate_nvm_checksum_ich8lan;
4798cfa0ad2SJack F Vogel 	nvm->ops.write		= e1000_write_nvm_ich8lan;
4808cfa0ad2SJack F Vogel 
4818cfa0ad2SJack F Vogel out:
4828cfa0ad2SJack F Vogel 	return ret_val;
4838cfa0ad2SJack F Vogel }
4848cfa0ad2SJack F Vogel 
4858cfa0ad2SJack F Vogel /**
4868cfa0ad2SJack F Vogel  *  e1000_init_mac_params_ich8lan - Initialize MAC function pointers
4878cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
4888cfa0ad2SJack F Vogel  *
4898cfa0ad2SJack F Vogel  *  Initialize family-specific MAC parameters and function
4908cfa0ad2SJack F Vogel  *  pointers.
4918cfa0ad2SJack F Vogel  **/
4928cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
4938cfa0ad2SJack F Vogel {
4948cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
4958cfa0ad2SJack F Vogel 
4968cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_mac_params_ich8lan");
4978cfa0ad2SJack F Vogel 
4988cfa0ad2SJack F Vogel 	/* Set media type function pointer */
4998cfa0ad2SJack F Vogel 	hw->phy.media_type = e1000_media_type_copper;
5008cfa0ad2SJack F Vogel 
5018cfa0ad2SJack F Vogel 	/* Set mta register count */
5028cfa0ad2SJack F Vogel 	mac->mta_reg_count = 32;
5038cfa0ad2SJack F Vogel 	/* Set rar entry count */
5048cfa0ad2SJack F Vogel 	mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
5058cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
5068cfa0ad2SJack F Vogel 		mac->rar_entry_count--;
5078cfa0ad2SJack F Vogel 	/* Set if part includes ASF firmware */
5088cfa0ad2SJack F Vogel 	mac->asf_firmware_present = TRUE;
5098ec87fc5SJack F Vogel 	/* FWSM register */
5108ec87fc5SJack F Vogel 	mac->has_fwsm = TRUE;
5118ec87fc5SJack F Vogel 	/* ARC subsystem not supported */
5128ec87fc5SJack F Vogel 	mac->arc_subsystem_valid = FALSE;
5134edd8523SJack F Vogel 	/* Adaptive IFS supported */
5144edd8523SJack F Vogel 	mac->adaptive_ifs = TRUE;
5158cfa0ad2SJack F Vogel 
5168cfa0ad2SJack F Vogel 	/* Function pointers */
5178cfa0ad2SJack F Vogel 
5188cfa0ad2SJack F Vogel 	/* bus type/speed/width */
5198cfa0ad2SJack F Vogel 	mac->ops.get_bus_info = e1000_get_bus_info_ich8lan;
520daf9197cSJack F Vogel 	/* function id */
521daf9197cSJack F Vogel 	mac->ops.set_lan_id = e1000_set_lan_id_single_port;
5228cfa0ad2SJack F Vogel 	/* reset */
5238cfa0ad2SJack F Vogel 	mac->ops.reset_hw = e1000_reset_hw_ich8lan;
5248cfa0ad2SJack F Vogel 	/* hw initialization */
5258cfa0ad2SJack F Vogel 	mac->ops.init_hw = e1000_init_hw_ich8lan;
5268cfa0ad2SJack F Vogel 	/* link setup */
5278cfa0ad2SJack F Vogel 	mac->ops.setup_link = e1000_setup_link_ich8lan;
5288cfa0ad2SJack F Vogel 	/* physical interface setup */
5298cfa0ad2SJack F Vogel 	mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan;
5308cfa0ad2SJack F Vogel 	/* check for link */
5314edd8523SJack F Vogel 	mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan;
5328cfa0ad2SJack F Vogel 	/* link info */
5338cfa0ad2SJack F Vogel 	mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan;
5348cfa0ad2SJack F Vogel 	/* multicast address update */
5358cfa0ad2SJack F Vogel 	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
536d035aa2dSJack F Vogel 	/* clear hardware counters */
537d035aa2dSJack F Vogel 	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan;
538d035aa2dSJack F Vogel 
539d035aa2dSJack F Vogel 	/* LED operations */
540d035aa2dSJack F Vogel 	switch (mac->type) {
541d035aa2dSJack F Vogel 	case e1000_ich8lan:
542d035aa2dSJack F Vogel 	case e1000_ich9lan:
543d035aa2dSJack F Vogel 	case e1000_ich10lan:
5447d9119bdSJack F Vogel 		/* check management mode */
5457d9119bdSJack F Vogel 		mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
546d035aa2dSJack F Vogel 		/* ID LED init */
547d035aa2dSJack F Vogel 		mac->ops.id_led_init = e1000_id_led_init_generic;
5488cfa0ad2SJack F Vogel 		/* blink LED */
5498cfa0ad2SJack F Vogel 		mac->ops.blink_led = e1000_blink_led_generic;
5508cfa0ad2SJack F Vogel 		/* setup LED */
5518cfa0ad2SJack F Vogel 		mac->ops.setup_led = e1000_setup_led_generic;
5528cfa0ad2SJack F Vogel 		/* cleanup LED */
5538cfa0ad2SJack F Vogel 		mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
5548cfa0ad2SJack F Vogel 		/* turn on/off LED */
5558cfa0ad2SJack F Vogel 		mac->ops.led_on = e1000_led_on_ich8lan;
5568cfa0ad2SJack F Vogel 		mac->ops.led_off = e1000_led_off_ich8lan;
557d035aa2dSJack F Vogel 		break;
5587d9119bdSJack F Vogel 	case e1000_pch2lan:
5597d9119bdSJack F Vogel 		mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES;
5607d9119bdSJack F Vogel 		mac->ops.rar_set = e1000_rar_set_pch2lan;
561730d3130SJack F Vogel 		/* multicast address update for pch2 */
562730d3130SJack F Vogel 		mac->ops.update_mc_addr_list =
563730d3130SJack F Vogel 			e1000_update_mc_addr_list_pch2lan;
5647d9119bdSJack F Vogel 		/* fall-through */
5659d81738fSJack F Vogel 	case e1000_pchlan:
5667d9119bdSJack F Vogel 		/* check management mode */
5677d9119bdSJack F Vogel 		mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
5689d81738fSJack F Vogel 		/* ID LED init */
5699d81738fSJack F Vogel 		mac->ops.id_led_init = e1000_id_led_init_pchlan;
5709d81738fSJack F Vogel 		/* setup LED */
5719d81738fSJack F Vogel 		mac->ops.setup_led = e1000_setup_led_pchlan;
5729d81738fSJack F Vogel 		/* cleanup LED */
5739d81738fSJack F Vogel 		mac->ops.cleanup_led = e1000_cleanup_led_pchlan;
5749d81738fSJack F Vogel 		/* turn on/off LED */
5759d81738fSJack F Vogel 		mac->ops.led_on = e1000_led_on_pchlan;
5769d81738fSJack F Vogel 		mac->ops.led_off = e1000_led_off_pchlan;
5779d81738fSJack F Vogel 		break;
578d035aa2dSJack F Vogel 	default:
579d035aa2dSJack F Vogel 		break;
580d035aa2dSJack F Vogel 	}
5818cfa0ad2SJack F Vogel 
582*4dab5c37SJack F Vogel #if defined(NAHUM6_HW) && (defined(LTR_SUPPORT) || defined(OBFF_SUPPORT))
583*4dab5c37SJack F Vogel 	if (mac->type == e1000_pch_lpt) {
584*4dab5c37SJack F Vogel 	}
585*4dab5c37SJack F Vogel 
586*4dab5c37SJack F Vogel #endif /* NAHUM6_HW && (LTR_SUPPORT || OBFF_SUPPORT) */
5878cfa0ad2SJack F Vogel 	/* Enable PCS Lock-loss workaround for ICH8 */
5888cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
5898cfa0ad2SJack F Vogel 		e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE);
5908cfa0ad2SJack F Vogel 
5917d9119bdSJack F Vogel 	/* Gate automatic PHY configuration by hardware on managed 82579 */
5927d9119bdSJack F Vogel 	if ((mac->type == e1000_pch2lan) &&
5937d9119bdSJack F Vogel 	    (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
5947d9119bdSJack F Vogel 		e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
5957d9119bdSJack F Vogel 
596daf9197cSJack F Vogel 	return E1000_SUCCESS;
5978cfa0ad2SJack F Vogel }
5988cfa0ad2SJack F Vogel 
5998cfa0ad2SJack F Vogel /**
6007d9119bdSJack F Vogel  *  e1000_set_eee_pchlan - Enable/disable EEE support
6017d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
6027d9119bdSJack F Vogel  *
6037d9119bdSJack F Vogel  *  Enable/disable EEE based on setting in dev_spec structure.  The bits in
6047d9119bdSJack F Vogel  *  the LPI Control register will remain set only if/when link is up.
6057d9119bdSJack F Vogel  **/
6067d9119bdSJack F Vogel static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
6077d9119bdSJack F Vogel {
608*4dab5c37SJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
6097d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
6107d9119bdSJack F Vogel 	u16 phy_reg;
6117d9119bdSJack F Vogel 
6127d9119bdSJack F Vogel 	DEBUGFUNC("e1000_set_eee_pchlan");
6137d9119bdSJack F Vogel 
6147d9119bdSJack F Vogel 	if (hw->phy.type != e1000_phy_82579)
6157d9119bdSJack F Vogel 		goto out;
6167d9119bdSJack F Vogel 
6177d9119bdSJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, I82579_LPI_CTRL, &phy_reg);
6187d9119bdSJack F Vogel 	if (ret_val)
6197d9119bdSJack F Vogel 		goto out;
6207d9119bdSJack F Vogel 
621*4dab5c37SJack F Vogel 	if (dev_spec->eee_disable)
6227d9119bdSJack F Vogel 		phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK;
6237d9119bdSJack F Vogel 	else
6247d9119bdSJack F Vogel 		phy_reg |= I82579_LPI_CTRL_ENABLE_MASK;
6257d9119bdSJack F Vogel 
6267d9119bdSJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, I82579_LPI_CTRL, phy_reg);
6277d9119bdSJack F Vogel out:
6287d9119bdSJack F Vogel 	return ret_val;
6297d9119bdSJack F Vogel }
6307d9119bdSJack F Vogel 
6317d9119bdSJack F Vogel /**
6324edd8523SJack F Vogel  *  e1000_check_for_copper_link_ich8lan - Check for link (Copper)
6334edd8523SJack F Vogel  *  @hw: pointer to the HW structure
6344edd8523SJack F Vogel  *
6354edd8523SJack F Vogel  *  Checks to see of the link status of the hardware has changed.  If a
6364edd8523SJack F Vogel  *  change in link status has been detected, then we read the PHY registers
6374edd8523SJack F Vogel  *  to get the current speed/duplex if link exists.
6384edd8523SJack F Vogel  **/
6394edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
6404edd8523SJack F Vogel {
6414edd8523SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
6424edd8523SJack F Vogel 	s32 ret_val;
6434edd8523SJack F Vogel 	bool link;
644*4dab5c37SJack F Vogel 	u16 phy_reg;
6454edd8523SJack F Vogel 
6464edd8523SJack F Vogel 	DEBUGFUNC("e1000_check_for_copper_link_ich8lan");
6474edd8523SJack F Vogel 
6484edd8523SJack F Vogel 	/*
6494edd8523SJack F Vogel 	 * We only want to go out to the PHY registers to see if Auto-Neg
6504edd8523SJack F Vogel 	 * has completed and/or if our link status has changed.  The
6514edd8523SJack F Vogel 	 * get_link_status flag is set upon receiving a Link Status
6524edd8523SJack F Vogel 	 * Change or Rx Sequence Error interrupt.
6534edd8523SJack F Vogel 	 */
6544edd8523SJack F Vogel 	if (!mac->get_link_status) {
6554edd8523SJack F Vogel 		ret_val = E1000_SUCCESS;
6564edd8523SJack F Vogel 		goto out;
6574edd8523SJack F Vogel 	}
6584edd8523SJack F Vogel 
6594edd8523SJack F Vogel 	/*
6604edd8523SJack F Vogel 	 * First we want to see if the MII Status Register reports
6614edd8523SJack F Vogel 	 * link.  If so, then we want to get the current speed/duplex
6624edd8523SJack F Vogel 	 * of the PHY.
6634edd8523SJack F Vogel 	 */
6644edd8523SJack F Vogel 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
6654edd8523SJack F Vogel 	if (ret_val)
6664edd8523SJack F Vogel 		goto out;
6674edd8523SJack F Vogel 
6684edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan) {
6694edd8523SJack F Vogel 		ret_val = e1000_k1_gig_workaround_hv(hw, link);
6704edd8523SJack F Vogel 		if (ret_val)
6714edd8523SJack F Vogel 			goto out;
6724edd8523SJack F Vogel 	}
6734edd8523SJack F Vogel 
674*4dab5c37SJack F Vogel #if defined(NAHUM6_HW) && (defined(LTR_SUPPORT) || defined(OBFF_SUPPORT))
675*4dab5c37SJack F Vogel 	if (hw->mac.type == e1000_pch_lpt) {
676*4dab5c37SJack F Vogel 	}
677*4dab5c37SJack F Vogel 
678*4dab5c37SJack F Vogel #endif /* NAHUM6_HW && (LTR_SUPPORT || OBFF_SUPPORT) */
6794edd8523SJack F Vogel 	if (!link)
6804edd8523SJack F Vogel 		goto out; /* No link detected */
6814edd8523SJack F Vogel 
6824edd8523SJack F Vogel 	mac->get_link_status = FALSE;
6834edd8523SJack F Vogel 
684*4dab5c37SJack F Vogel 	switch (hw->mac.type) {
685*4dab5c37SJack F Vogel 	case e1000_pch2lan:
686*4dab5c37SJack F Vogel 		ret_val = e1000_k1_workaround_lv(hw);
687*4dab5c37SJack F Vogel 		if (ret_val)
688*4dab5c37SJack F Vogel 			goto out;
689*4dab5c37SJack F Vogel 		/* fall-thru */
690*4dab5c37SJack F Vogel 	case e1000_pchlan:
6914edd8523SJack F Vogel 		if (hw->phy.type == e1000_phy_82578) {
6924edd8523SJack F Vogel 			ret_val = e1000_link_stall_workaround_hv(hw);
6934edd8523SJack F Vogel 			if (ret_val)
6944edd8523SJack F Vogel 				goto out;
6954edd8523SJack F Vogel 		}
6964edd8523SJack F Vogel 
697*4dab5c37SJack F Vogel 		/*
698*4dab5c37SJack F Vogel 		 * Workaround for PCHx parts in half-duplex:
699*4dab5c37SJack F Vogel 		 * Set the number of preambles removed from the packet
700*4dab5c37SJack F Vogel 		 * when it is passed from the PHY to the MAC to prevent
701*4dab5c37SJack F Vogel 		 * the MAC from misinterpreting the packet type.
702*4dab5c37SJack F Vogel 		 */
703*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg(hw, HV_KMRN_FIFO_CTRLSTA, &phy_reg);
704*4dab5c37SJack F Vogel 		phy_reg &= ~HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK;
705*4dab5c37SJack F Vogel 
706*4dab5c37SJack F Vogel 		if ((E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_FD) !=
707*4dab5c37SJack F Vogel 		    E1000_STATUS_FD)
708*4dab5c37SJack F Vogel 			phy_reg |= (1 << HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT);
709*4dab5c37SJack F Vogel 
710*4dab5c37SJack F Vogel 		hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA, phy_reg);
711*4dab5c37SJack F Vogel 		break;
712*4dab5c37SJack F Vogel 	default:
713*4dab5c37SJack F Vogel 		break;
7147d9119bdSJack F Vogel 	}
7157d9119bdSJack F Vogel 
7164edd8523SJack F Vogel 	/*
7174edd8523SJack F Vogel 	 * Check if there was DownShift, must be checked
7184edd8523SJack F Vogel 	 * immediately after link-up
7194edd8523SJack F Vogel 	 */
7204edd8523SJack F Vogel 	e1000_check_downshift_generic(hw);
7214edd8523SJack F Vogel 
7227d9119bdSJack F Vogel 	/* Enable/Disable EEE after link up */
7237d9119bdSJack F Vogel 	ret_val = e1000_set_eee_pchlan(hw);
7247d9119bdSJack F Vogel 	if (ret_val)
7257d9119bdSJack F Vogel 		goto out;
7267d9119bdSJack F Vogel 
7274edd8523SJack F Vogel 	/*
7284edd8523SJack F Vogel 	 * If we are forcing speed/duplex, then we simply return since
7294edd8523SJack F Vogel 	 * we have already determined whether we have link or not.
7304edd8523SJack F Vogel 	 */
7314edd8523SJack F Vogel 	if (!mac->autoneg) {
7324edd8523SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
7334edd8523SJack F Vogel 		goto out;
7344edd8523SJack F Vogel 	}
7354edd8523SJack F Vogel 
7364edd8523SJack F Vogel 	/*
7374edd8523SJack F Vogel 	 * Auto-Neg is enabled.  Auto Speed Detection takes care
7384edd8523SJack F Vogel 	 * of MAC speed/duplex configuration.  So we only need to
7394edd8523SJack F Vogel 	 * configure Collision Distance in the MAC.
7404edd8523SJack F Vogel 	 */
7414edd8523SJack F Vogel 	e1000_config_collision_dist_generic(hw);
7424edd8523SJack F Vogel 
7434edd8523SJack F Vogel 	/*
7444edd8523SJack F Vogel 	 * Configure Flow Control now that Auto-Neg has completed.
7454edd8523SJack F Vogel 	 * First, we need to restore the desired flow control
7464edd8523SJack F Vogel 	 * settings because we may have had to re-autoneg with a
7474edd8523SJack F Vogel 	 * different link partner.
7484edd8523SJack F Vogel 	 */
7494edd8523SJack F Vogel 	ret_val = e1000_config_fc_after_link_up_generic(hw);
7504edd8523SJack F Vogel 	if (ret_val)
7514edd8523SJack F Vogel 		DEBUGOUT("Error configuring flow control\n");
7524edd8523SJack F Vogel 
7534edd8523SJack F Vogel out:
7544edd8523SJack F Vogel 	return ret_val;
7554edd8523SJack F Vogel }
7564edd8523SJack F Vogel 
7574edd8523SJack F Vogel /**
7588cfa0ad2SJack F Vogel  *  e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers
7598cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
7608cfa0ad2SJack F Vogel  *
7618cfa0ad2SJack F Vogel  *  Initialize family-specific function pointers for PHY, MAC, and NVM.
7628cfa0ad2SJack F Vogel  **/
7638cfa0ad2SJack F Vogel void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw)
7648cfa0ad2SJack F Vogel {
7658cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_function_pointers_ich8lan");
7668cfa0ad2SJack F Vogel 
7678cfa0ad2SJack F Vogel 	hw->mac.ops.init_params = e1000_init_mac_params_ich8lan;
7688cfa0ad2SJack F Vogel 	hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan;
7699d81738fSJack F Vogel 	switch (hw->mac.type) {
7709d81738fSJack F Vogel 	case e1000_ich8lan:
7719d81738fSJack F Vogel 	case e1000_ich9lan:
7729d81738fSJack F Vogel 	case e1000_ich10lan:
7738cfa0ad2SJack F Vogel 		hw->phy.ops.init_params = e1000_init_phy_params_ich8lan;
7749d81738fSJack F Vogel 		break;
7759d81738fSJack F Vogel 	case e1000_pchlan:
7767d9119bdSJack F Vogel 	case e1000_pch2lan:
7779d81738fSJack F Vogel 		hw->phy.ops.init_params = e1000_init_phy_params_pchlan;
7789d81738fSJack F Vogel 		break;
7799d81738fSJack F Vogel 	default:
7809d81738fSJack F Vogel 		break;
7819d81738fSJack F Vogel 	}
7828cfa0ad2SJack F Vogel }
7838cfa0ad2SJack F Vogel 
7848cfa0ad2SJack F Vogel /**
7854edd8523SJack F Vogel  *  e1000_acquire_nvm_ich8lan - Acquire NVM mutex
7864edd8523SJack F Vogel  *  @hw: pointer to the HW structure
7874edd8523SJack F Vogel  *
7884edd8523SJack F Vogel  *  Acquires the mutex for performing NVM operations.
7894edd8523SJack F Vogel  **/
7904edd8523SJack F Vogel static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
7914edd8523SJack F Vogel {
7924edd8523SJack F Vogel 	DEBUGFUNC("e1000_acquire_nvm_ich8lan");
7934edd8523SJack F Vogel 
7944edd8523SJack F Vogel 	E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.nvm_mutex);
7954edd8523SJack F Vogel 
7964edd8523SJack F Vogel 	return E1000_SUCCESS;
7974edd8523SJack F Vogel }
7984edd8523SJack F Vogel 
7994edd8523SJack F Vogel /**
8004edd8523SJack F Vogel  *  e1000_release_nvm_ich8lan - Release NVM mutex
8014edd8523SJack F Vogel  *  @hw: pointer to the HW structure
8024edd8523SJack F Vogel  *
8034edd8523SJack F Vogel  *  Releases the mutex used while performing NVM operations.
8044edd8523SJack F Vogel  **/
8054edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
8064edd8523SJack F Vogel {
8074edd8523SJack F Vogel 	DEBUGFUNC("e1000_release_nvm_ich8lan");
8084edd8523SJack F Vogel 
8094edd8523SJack F Vogel 	E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.nvm_mutex);
8104edd8523SJack F Vogel 
8114edd8523SJack F Vogel 	return;
8124edd8523SJack F Vogel }
8134edd8523SJack F Vogel 
8144edd8523SJack F Vogel /**
8158cfa0ad2SJack F Vogel  *  e1000_acquire_swflag_ich8lan - Acquire software control flag
8168cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
8178cfa0ad2SJack F Vogel  *
8184edd8523SJack F Vogel  *  Acquires the software control flag for performing PHY and select
8194edd8523SJack F Vogel  *  MAC CSR accesses.
8208cfa0ad2SJack F Vogel  **/
8218cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
8228cfa0ad2SJack F Vogel {
8238cfa0ad2SJack F Vogel 	u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
8248cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
8258cfa0ad2SJack F Vogel 
8268cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_acquire_swflag_ich8lan");
8278cfa0ad2SJack F Vogel 
8284edd8523SJack F Vogel 	E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.swflag_mutex);
8294edd8523SJack F Vogel 
8308cfa0ad2SJack F Vogel 	while (timeout) {
8318cfa0ad2SJack F Vogel 		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
8324edd8523SJack F Vogel 		if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG))
8338cfa0ad2SJack F Vogel 			break;
8344edd8523SJack F Vogel 
8358cfa0ad2SJack F Vogel 		msec_delay_irq(1);
8368cfa0ad2SJack F Vogel 		timeout--;
8378cfa0ad2SJack F Vogel 	}
8388cfa0ad2SJack F Vogel 
8398cfa0ad2SJack F Vogel 	if (!timeout) {
840*4dab5c37SJack F Vogel 		DEBUGOUT("SW has already locked the resource.\n");
8414edd8523SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
8424edd8523SJack F Vogel 		goto out;
8434edd8523SJack F Vogel 	}
8444edd8523SJack F Vogel 
8454edd8523SJack F Vogel 	timeout = SW_FLAG_TIMEOUT;
8464edd8523SJack F Vogel 
8474edd8523SJack F Vogel 	extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
8484edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
8494edd8523SJack F Vogel 
8504edd8523SJack F Vogel 	while (timeout) {
8514edd8523SJack F Vogel 		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
8524edd8523SJack F Vogel 		if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
8534edd8523SJack F Vogel 			break;
8544edd8523SJack F Vogel 
8554edd8523SJack F Vogel 		msec_delay_irq(1);
8564edd8523SJack F Vogel 		timeout--;
8574edd8523SJack F Vogel 	}
8584edd8523SJack F Vogel 
8594edd8523SJack F Vogel 	if (!timeout) {
860*4dab5c37SJack F Vogel 		DEBUGOUT2("Failed to acquire the semaphore, FW or HW has it: FWSM=0x%8.8x EXTCNF_CTRL=0x%8.8x)\n",
861*4dab5c37SJack F Vogel 			  E1000_READ_REG(hw, E1000_FWSM), extcnf_ctrl);
8628cfa0ad2SJack F Vogel 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
8638cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
8648cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
8658cfa0ad2SJack F Vogel 		goto out;
8668cfa0ad2SJack F Vogel 	}
8678cfa0ad2SJack F Vogel 
8688cfa0ad2SJack F Vogel out:
8694edd8523SJack F Vogel 	if (ret_val)
8704edd8523SJack F Vogel 		E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
8714edd8523SJack F Vogel 
8728cfa0ad2SJack F Vogel 	return ret_val;
8738cfa0ad2SJack F Vogel }
8748cfa0ad2SJack F Vogel 
8758cfa0ad2SJack F Vogel /**
8768cfa0ad2SJack F Vogel  *  e1000_release_swflag_ich8lan - Release software control flag
8778cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
8788cfa0ad2SJack F Vogel  *
8794edd8523SJack F Vogel  *  Releases the software control flag for performing PHY and select
8804edd8523SJack F Vogel  *  MAC CSR accesses.
8818cfa0ad2SJack F Vogel  **/
8828cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
8838cfa0ad2SJack F Vogel {
8848cfa0ad2SJack F Vogel 	u32 extcnf_ctrl;
8858cfa0ad2SJack F Vogel 
8868cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_release_swflag_ich8lan");
8878cfa0ad2SJack F Vogel 
8888cfa0ad2SJack F Vogel 	extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
889730d3130SJack F Vogel 
890730d3130SJack F Vogel 	if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) {
8918cfa0ad2SJack F Vogel 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
8928cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
893730d3130SJack F Vogel 	} else {
894730d3130SJack F Vogel 		DEBUGOUT("Semaphore unexpectedly released by sw/fw/hw\n");
895730d3130SJack F Vogel 	}
8968cfa0ad2SJack F Vogel 
8974edd8523SJack F Vogel 	E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
8984edd8523SJack F Vogel 
8998cfa0ad2SJack F Vogel 	return;
9008cfa0ad2SJack F Vogel }
9018cfa0ad2SJack F Vogel 
9028cfa0ad2SJack F Vogel /**
9038cfa0ad2SJack F Vogel  *  e1000_check_mng_mode_ich8lan - Checks management mode
9048cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
9058cfa0ad2SJack F Vogel  *
9067d9119bdSJack F Vogel  *  This checks if the adapter has any manageability enabled.
9078cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by read/write
9088cfa0ad2SJack F Vogel  *  routines for the PHY and NVM parts.
9098cfa0ad2SJack F Vogel  **/
9108cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
9118cfa0ad2SJack F Vogel {
9128cfa0ad2SJack F Vogel 	u32 fwsm;
9138cfa0ad2SJack F Vogel 
9148cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_mng_mode_ich8lan");
9158cfa0ad2SJack F Vogel 
9168cfa0ad2SJack F Vogel 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
9178cfa0ad2SJack F Vogel 
9187d9119bdSJack F Vogel 	return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
9197d9119bdSJack F Vogel 	       ((fwsm & E1000_FWSM_MODE_MASK) ==
9207d9119bdSJack F Vogel 		(E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
9217d9119bdSJack F Vogel }
9227d9119bdSJack F Vogel 
9237d9119bdSJack F Vogel /**
9247d9119bdSJack F Vogel  *  e1000_check_mng_mode_pchlan - Checks management mode
9257d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
9267d9119bdSJack F Vogel  *
9277d9119bdSJack F Vogel  *  This checks if the adapter has iAMT enabled.
9287d9119bdSJack F Vogel  *  This is a function pointer entry point only called by read/write
9297d9119bdSJack F Vogel  *  routines for the PHY and NVM parts.
9307d9119bdSJack F Vogel  **/
9317d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw)
9327d9119bdSJack F Vogel {
9337d9119bdSJack F Vogel 	u32 fwsm;
9347d9119bdSJack F Vogel 
9357d9119bdSJack F Vogel 	DEBUGFUNC("e1000_check_mng_mode_pchlan");
9367d9119bdSJack F Vogel 
9377d9119bdSJack F Vogel 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
9387d9119bdSJack F Vogel 
9397d9119bdSJack F Vogel 	return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
9407d9119bdSJack F Vogel 	       (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
9417d9119bdSJack F Vogel }
9427d9119bdSJack F Vogel 
9437d9119bdSJack F Vogel /**
9447d9119bdSJack F Vogel  *  e1000_rar_set_pch2lan - Set receive address register
9457d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
9467d9119bdSJack F Vogel  *  @addr: pointer to the receive address
9477d9119bdSJack F Vogel  *  @index: receive address array register
9487d9119bdSJack F Vogel  *
9497d9119bdSJack F Vogel  *  Sets the receive address array register at index to the address passed
9507d9119bdSJack F Vogel  *  in by addr.  For 82579, RAR[0] is the base address register that is to
9517d9119bdSJack F Vogel  *  contain the MAC address but RAR[1-6] are reserved for manageability (ME).
9527d9119bdSJack F Vogel  *  Use SHRA[0-3] in place of those reserved for ME.
9537d9119bdSJack F Vogel  **/
9547d9119bdSJack F Vogel static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index)
9557d9119bdSJack F Vogel {
9567d9119bdSJack F Vogel 	u32 rar_low, rar_high;
9577d9119bdSJack F Vogel 
9587d9119bdSJack F Vogel 	DEBUGFUNC("e1000_rar_set_pch2lan");
9597d9119bdSJack F Vogel 
9607d9119bdSJack F Vogel 	/*
9617d9119bdSJack F Vogel 	 * HW expects these in little endian so we reverse the byte order
9627d9119bdSJack F Vogel 	 * from network order (big endian) to little endian
9637d9119bdSJack F Vogel 	 */
9647d9119bdSJack F Vogel 	rar_low = ((u32) addr[0] |
9657d9119bdSJack F Vogel 		   ((u32) addr[1] << 8) |
9667d9119bdSJack F Vogel 		   ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
9677d9119bdSJack F Vogel 
9687d9119bdSJack F Vogel 	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
9697d9119bdSJack F Vogel 
9707d9119bdSJack F Vogel 	/* If MAC address zero, no need to set the AV bit */
9717d9119bdSJack F Vogel 	if (rar_low || rar_high)
9727d9119bdSJack F Vogel 		rar_high |= E1000_RAH_AV;
9737d9119bdSJack F Vogel 
9747d9119bdSJack F Vogel 	if (index == 0) {
9757d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
9767d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
9777d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
9787d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
9797d9119bdSJack F Vogel 		return;
9807d9119bdSJack F Vogel 	}
9817d9119bdSJack F Vogel 
9827d9119bdSJack F Vogel 	if (index < hw->mac.rar_entry_count) {
9837d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_SHRAL(index - 1), rar_low);
9847d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
9857d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_SHRAH(index - 1), rar_high);
9867d9119bdSJack F Vogel 		E1000_WRITE_FLUSH(hw);
9877d9119bdSJack F Vogel 
9887d9119bdSJack F Vogel 		/* verify the register updates */
9897d9119bdSJack F Vogel 		if ((E1000_READ_REG(hw, E1000_SHRAL(index - 1)) == rar_low) &&
9907d9119bdSJack F Vogel 		    (E1000_READ_REG(hw, E1000_SHRAH(index - 1)) == rar_high))
9917d9119bdSJack F Vogel 			return;
9927d9119bdSJack F Vogel 
9937d9119bdSJack F Vogel 		DEBUGOUT2("SHRA[%d] might be locked by ME - FWSM=0x%8.8x\n",
9947d9119bdSJack F Vogel 			 (index - 1), E1000_READ_REG(hw, E1000_FWSM));
9957d9119bdSJack F Vogel 	}
9967d9119bdSJack F Vogel 
9977d9119bdSJack F Vogel 	DEBUGOUT1("Failed to write receive address at index %d\n", index);
9988cfa0ad2SJack F Vogel }
9998cfa0ad2SJack F Vogel 
10008cfa0ad2SJack F Vogel /**
1001730d3130SJack F Vogel  *  e1000_update_mc_addr_list_pch2lan - Update Multicast addresses
1002730d3130SJack F Vogel  *  @hw: pointer to the HW structure
1003730d3130SJack F Vogel  *  @mc_addr_list: array of multicast addresses to program
1004730d3130SJack F Vogel  *  @mc_addr_count: number of multicast addresses to program
1005730d3130SJack F Vogel  *
1006730d3130SJack F Vogel  *  Updates entire Multicast Table Array of the PCH2 MAC and PHY.
1007730d3130SJack F Vogel  *  The caller must have a packed mc_addr_list of multicast addresses.
1008730d3130SJack F Vogel  **/
1009730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw,
1010730d3130SJack F Vogel 					      u8 *mc_addr_list,
1011730d3130SJack F Vogel 					      u32 mc_addr_count)
1012730d3130SJack F Vogel {
1013*4dab5c37SJack F Vogel 	u16 phy_reg = 0;
1014730d3130SJack F Vogel 	int i;
1015*4dab5c37SJack F Vogel 	s32 ret_val;
1016730d3130SJack F Vogel 
1017730d3130SJack F Vogel 	DEBUGFUNC("e1000_update_mc_addr_list_pch2lan");
1018730d3130SJack F Vogel 
1019730d3130SJack F Vogel 	e1000_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count);
1020730d3130SJack F Vogel 
1021*4dab5c37SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
1022*4dab5c37SJack F Vogel 	if (ret_val)
1023*4dab5c37SJack F Vogel 		return;
1024*4dab5c37SJack F Vogel 
1025*4dab5c37SJack F Vogel 	ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg);
1026*4dab5c37SJack F Vogel 	if (ret_val)
1027*4dab5c37SJack F Vogel 		goto release;
1028*4dab5c37SJack F Vogel 
1029730d3130SJack F Vogel 	for (i = 0; i < hw->mac.mta_reg_count; i++) {
1030*4dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_MTA(i),
1031*4dab5c37SJack F Vogel 					   (u16)(hw->mac.mta_shadow[i] &
1032*4dab5c37SJack F Vogel 						 0xFFFF));
1033*4dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, (BM_MTA(i) + 1),
1034730d3130SJack F Vogel 					   (u16)((hw->mac.mta_shadow[i] >> 16) &
1035730d3130SJack F Vogel 						 0xFFFF));
1036730d3130SJack F Vogel 	}
1037*4dab5c37SJack F Vogel 
1038*4dab5c37SJack F Vogel 	e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg);
1039*4dab5c37SJack F Vogel 
1040*4dab5c37SJack F Vogel release:
1041*4dab5c37SJack F Vogel 	hw->phy.ops.release(hw);
1042730d3130SJack F Vogel }
1043730d3130SJack F Vogel 
1044730d3130SJack F Vogel /**
10458cfa0ad2SJack F Vogel  *  e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
10468cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
10478cfa0ad2SJack F Vogel  *
10488cfa0ad2SJack F Vogel  *  Checks if firmware is blocking the reset of the PHY.
10498cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
10508cfa0ad2SJack F Vogel  *  reset routines.
10518cfa0ad2SJack F Vogel  **/
10528cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
10538cfa0ad2SJack F Vogel {
10548cfa0ad2SJack F Vogel 	u32 fwsm;
10558cfa0ad2SJack F Vogel 
10568cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_reset_block_ich8lan");
10578cfa0ad2SJack F Vogel 
10588cfa0ad2SJack F Vogel 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
10598cfa0ad2SJack F Vogel 
10608cfa0ad2SJack F Vogel 	return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS
10618cfa0ad2SJack F Vogel 						: E1000_BLK_PHY_RESET;
10628cfa0ad2SJack F Vogel }
10638cfa0ad2SJack F Vogel 
10648cfa0ad2SJack F Vogel /**
10657d9119bdSJack F Vogel  *  e1000_write_smbus_addr - Write SMBus address to PHY needed during Sx states
10667d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
10677d9119bdSJack F Vogel  *
10687d9119bdSJack F Vogel  *  Assumes semaphore already acquired.
10697d9119bdSJack F Vogel  *
10707d9119bdSJack F Vogel  **/
10717d9119bdSJack F Vogel static s32 e1000_write_smbus_addr(struct e1000_hw *hw)
10727d9119bdSJack F Vogel {
10737d9119bdSJack F Vogel 	u16 phy_data;
10747d9119bdSJack F Vogel 	u32 strap = E1000_READ_REG(hw, E1000_STRAP);
10757d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
10767d9119bdSJack F Vogel 
10777d9119bdSJack F Vogel 	strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
10787d9119bdSJack F Vogel 
10797d9119bdSJack F Vogel 	ret_val = e1000_read_phy_reg_hv_locked(hw, HV_SMB_ADDR, &phy_data);
10807d9119bdSJack F Vogel 	if (ret_val)
10817d9119bdSJack F Vogel 		goto out;
10827d9119bdSJack F Vogel 
10837d9119bdSJack F Vogel 	phy_data &= ~HV_SMB_ADDR_MASK;
10847d9119bdSJack F Vogel 	phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT);
10857d9119bdSJack F Vogel 	phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
10867d9119bdSJack F Vogel 	ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data);
10877d9119bdSJack F Vogel 
10887d9119bdSJack F Vogel out:
10897d9119bdSJack F Vogel 	return ret_val;
10907d9119bdSJack F Vogel }
10917d9119bdSJack F Vogel 
10927d9119bdSJack F Vogel /**
10934edd8523SJack F Vogel  *  e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration
10944edd8523SJack F Vogel  *  @hw:   pointer to the HW structure
10954edd8523SJack F Vogel  *
10964edd8523SJack F Vogel  *  SW should configure the LCD from the NVM extended configuration region
10974edd8523SJack F Vogel  *  as a workaround for certain parts.
10984edd8523SJack F Vogel  **/
10994edd8523SJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
11004edd8523SJack F Vogel {
11014edd8523SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
11024edd8523SJack F Vogel 	u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
1103a69ed8dfSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
11044edd8523SJack F Vogel 	u16 word_addr, reg_data, reg_addr, phy_page = 0;
11054edd8523SJack F Vogel 
11067d9119bdSJack F Vogel 	DEBUGFUNC("e1000_sw_lcd_config_ich8lan");
11074edd8523SJack F Vogel 
11084edd8523SJack F Vogel 	/*
11094edd8523SJack F Vogel 	 * Initialize the PHY from the NVM on ICH platforms.  This
11104edd8523SJack F Vogel 	 * is needed due to an issue where the NVM configuration is
11114edd8523SJack F Vogel 	 * not properly autoloaded after power transitions.
11124edd8523SJack F Vogel 	 * Therefore, after each PHY reset, we will load the
11134edd8523SJack F Vogel 	 * configuration data out of the NVM manually.
11144edd8523SJack F Vogel 	 */
11157d9119bdSJack F Vogel 	switch (hw->mac.type) {
11167d9119bdSJack F Vogel 	case e1000_ich8lan:
11177d9119bdSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
11187d9119bdSJack F Vogel 			return ret_val;
11197d9119bdSJack F Vogel 
11207d9119bdSJack F Vogel 		if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_AMT) ||
11217d9119bdSJack F Vogel 		    (hw->device_id == E1000_DEV_ID_ICH8_IGP_C)) {
11224edd8523SJack F Vogel 			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
11237d9119bdSJack F Vogel 			break;
11247d9119bdSJack F Vogel 		}
11257d9119bdSJack F Vogel 		/* Fall-thru */
11267d9119bdSJack F Vogel 	case e1000_pchlan:
11277d9119bdSJack F Vogel 	case e1000_pch2lan:
11287d9119bdSJack F Vogel 		sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
11297d9119bdSJack F Vogel 		break;
11307d9119bdSJack F Vogel 	default:
11317d9119bdSJack F Vogel 		return ret_val;
11327d9119bdSJack F Vogel 	}
11337d9119bdSJack F Vogel 
11347d9119bdSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
11357d9119bdSJack F Vogel 	if (ret_val)
11367d9119bdSJack F Vogel 		return ret_val;
11374edd8523SJack F Vogel 
11384edd8523SJack F Vogel 	data = E1000_READ_REG(hw, E1000_FEXTNVM);
11394edd8523SJack F Vogel 	if (!(data & sw_cfg_mask))
11404edd8523SJack F Vogel 		goto out;
11414edd8523SJack F Vogel 
11424edd8523SJack F Vogel 	/*
11434edd8523SJack F Vogel 	 * Make sure HW does not configure LCD from PHY
11444edd8523SJack F Vogel 	 * extended configuration before SW configuration
11454edd8523SJack F Vogel 	 */
11464edd8523SJack F Vogel 	data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
11477d9119bdSJack F Vogel 	if (!(hw->mac.type == e1000_pch2lan)) {
11484edd8523SJack F Vogel 		if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
11494edd8523SJack F Vogel 			goto out;
11507d9119bdSJack F Vogel 	}
11514edd8523SJack F Vogel 
11524edd8523SJack F Vogel 	cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE);
11534edd8523SJack F Vogel 	cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
11544edd8523SJack F Vogel 	cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
11554edd8523SJack F Vogel 	if (!cnf_size)
11564edd8523SJack F Vogel 		goto out;
11574edd8523SJack F Vogel 
11584edd8523SJack F Vogel 	cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
11594edd8523SJack F Vogel 	cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
11604edd8523SJack F Vogel 
11617d9119bdSJack F Vogel 	if ((!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
11627d9119bdSJack F Vogel 	    (hw->mac.type == e1000_pchlan)) ||
11637d9119bdSJack F Vogel 	     (hw->mac.type == e1000_pch2lan)) {
11644edd8523SJack F Vogel 		/*
11654edd8523SJack F Vogel 		 * HW configures the SMBus address and LEDs when the
11664edd8523SJack F Vogel 		 * OEM and LCD Write Enable bits are set in the NVM.
11674edd8523SJack F Vogel 		 * When both NVM bits are cleared, SW will configure
11684edd8523SJack F Vogel 		 * them instead.
11694edd8523SJack F Vogel 		 */
11707d9119bdSJack F Vogel 		ret_val = e1000_write_smbus_addr(hw);
11714edd8523SJack F Vogel 		if (ret_val)
11724edd8523SJack F Vogel 			goto out;
11734edd8523SJack F Vogel 
11744edd8523SJack F Vogel 		data = E1000_READ_REG(hw, E1000_LEDCTL);
1175a69ed8dfSJack F Vogel 		ret_val = e1000_write_phy_reg_hv_locked(hw, HV_LED_CONFIG,
11764edd8523SJack F Vogel 							(u16)data);
11774edd8523SJack F Vogel 		if (ret_val)
11784edd8523SJack F Vogel 			goto out;
11794edd8523SJack F Vogel 	}
11804edd8523SJack F Vogel 
11814edd8523SJack F Vogel 	/* Configure LCD from extended configuration region. */
11824edd8523SJack F Vogel 
11834edd8523SJack F Vogel 	/* cnf_base_addr is in DWORD */
11844edd8523SJack F Vogel 	word_addr = (u16)(cnf_base_addr << 1);
11854edd8523SJack F Vogel 
11864edd8523SJack F Vogel 	for (i = 0; i < cnf_size; i++) {
11874edd8523SJack F Vogel 		ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1,
11884edd8523SJack F Vogel 					   &reg_data);
11894edd8523SJack F Vogel 		if (ret_val)
11904edd8523SJack F Vogel 			goto out;
11914edd8523SJack F Vogel 
11924edd8523SJack F Vogel 		ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1),
11934edd8523SJack F Vogel 					   1, &reg_addr);
11944edd8523SJack F Vogel 		if (ret_val)
11954edd8523SJack F Vogel 			goto out;
11964edd8523SJack F Vogel 
11974edd8523SJack F Vogel 		/* Save off the PHY page for future writes. */
11984edd8523SJack F Vogel 		if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
11994edd8523SJack F Vogel 			phy_page = reg_data;
12004edd8523SJack F Vogel 			continue;
12014edd8523SJack F Vogel 		}
12024edd8523SJack F Vogel 
12034edd8523SJack F Vogel 		reg_addr &= PHY_REG_MASK;
12044edd8523SJack F Vogel 		reg_addr |= phy_page;
12054edd8523SJack F Vogel 
12064edd8523SJack F Vogel 		ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr,
12074edd8523SJack F Vogel 						    reg_data);
12084edd8523SJack F Vogel 		if (ret_val)
12094edd8523SJack F Vogel 			goto out;
12104edd8523SJack F Vogel 	}
12114edd8523SJack F Vogel 
12124edd8523SJack F Vogel out:
12134edd8523SJack F Vogel 	hw->phy.ops.release(hw);
12144edd8523SJack F Vogel 	return ret_val;
12154edd8523SJack F Vogel }
12164edd8523SJack F Vogel 
12174edd8523SJack F Vogel /**
12184edd8523SJack F Vogel  *  e1000_k1_gig_workaround_hv - K1 Si workaround
12194edd8523SJack F Vogel  *  @hw:   pointer to the HW structure
12204edd8523SJack F Vogel  *  @link: link up bool flag
12214edd8523SJack F Vogel  *
12224edd8523SJack F Vogel  *  If K1 is enabled for 1Gbps, the MAC might stall when transitioning
12234edd8523SJack F Vogel  *  from a lower speed.  This workaround disables K1 whenever link is at 1Gig
12244edd8523SJack F Vogel  *  If link is down, the function will restore the default K1 setting located
12254edd8523SJack F Vogel  *  in the NVM.
12264edd8523SJack F Vogel  **/
12274edd8523SJack F Vogel static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
12284edd8523SJack F Vogel {
12294edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
12304edd8523SJack F Vogel 	u16 status_reg = 0;
12314edd8523SJack F Vogel 	bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled;
12324edd8523SJack F Vogel 
12334edd8523SJack F Vogel 	DEBUGFUNC("e1000_k1_gig_workaround_hv");
12344edd8523SJack F Vogel 
12354edd8523SJack F Vogel 	if (hw->mac.type != e1000_pchlan)
12364edd8523SJack F Vogel 		goto out;
12374edd8523SJack F Vogel 
12384edd8523SJack F Vogel 	/* Wrap the whole flow with the sw flag */
12394edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
12404edd8523SJack F Vogel 	if (ret_val)
12414edd8523SJack F Vogel 		goto out;
12424edd8523SJack F Vogel 
12434edd8523SJack F Vogel 	/* Disable K1 when link is 1Gbps, otherwise use the NVM setting */
12444edd8523SJack F Vogel 	if (link) {
12454edd8523SJack F Vogel 		if (hw->phy.type == e1000_phy_82578) {
12464edd8523SJack F Vogel 			ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS,
12474edd8523SJack F Vogel 							      &status_reg);
12484edd8523SJack F Vogel 			if (ret_val)
12494edd8523SJack F Vogel 				goto release;
12504edd8523SJack F Vogel 
12514edd8523SJack F Vogel 			status_reg &= BM_CS_STATUS_LINK_UP |
12524edd8523SJack F Vogel 				      BM_CS_STATUS_RESOLVED |
12534edd8523SJack F Vogel 				      BM_CS_STATUS_SPEED_MASK;
12544edd8523SJack F Vogel 
12554edd8523SJack F Vogel 			if (status_reg == (BM_CS_STATUS_LINK_UP |
12564edd8523SJack F Vogel 					   BM_CS_STATUS_RESOLVED |
12574edd8523SJack F Vogel 					   BM_CS_STATUS_SPEED_1000))
12584edd8523SJack F Vogel 				k1_enable = FALSE;
12594edd8523SJack F Vogel 		}
12604edd8523SJack F Vogel 
12614edd8523SJack F Vogel 		if (hw->phy.type == e1000_phy_82577) {
12624edd8523SJack F Vogel 			ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS,
12634edd8523SJack F Vogel 							      &status_reg);
12644edd8523SJack F Vogel 			if (ret_val)
12654edd8523SJack F Vogel 				goto release;
12664edd8523SJack F Vogel 
12674edd8523SJack F Vogel 			status_reg &= HV_M_STATUS_LINK_UP |
12684edd8523SJack F Vogel 				      HV_M_STATUS_AUTONEG_COMPLETE |
12694edd8523SJack F Vogel 				      HV_M_STATUS_SPEED_MASK;
12704edd8523SJack F Vogel 
12714edd8523SJack F Vogel 			if (status_reg == (HV_M_STATUS_LINK_UP |
12724edd8523SJack F Vogel 					   HV_M_STATUS_AUTONEG_COMPLETE |
12734edd8523SJack F Vogel 					   HV_M_STATUS_SPEED_1000))
12744edd8523SJack F Vogel 				k1_enable = FALSE;
12754edd8523SJack F Vogel 		}
12764edd8523SJack F Vogel 
12774edd8523SJack F Vogel 		/* Link stall fix for link up */
12784edd8523SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
12794edd8523SJack F Vogel 						       0x0100);
12804edd8523SJack F Vogel 		if (ret_val)
12814edd8523SJack F Vogel 			goto release;
12824edd8523SJack F Vogel 
12834edd8523SJack F Vogel 	} else {
12844edd8523SJack F Vogel 		/* Link stall fix for link down */
12854edd8523SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
12864edd8523SJack F Vogel 						       0x4100);
12874edd8523SJack F Vogel 		if (ret_val)
12884edd8523SJack F Vogel 			goto release;
12894edd8523SJack F Vogel 	}
12904edd8523SJack F Vogel 
12914edd8523SJack F Vogel 	ret_val = e1000_configure_k1_ich8lan(hw, k1_enable);
12924edd8523SJack F Vogel 
12934edd8523SJack F Vogel release:
12944edd8523SJack F Vogel 	hw->phy.ops.release(hw);
12954edd8523SJack F Vogel out:
12964edd8523SJack F Vogel 	return ret_val;
12974edd8523SJack F Vogel }
12984edd8523SJack F Vogel 
12994edd8523SJack F Vogel /**
13004edd8523SJack F Vogel  *  e1000_configure_k1_ich8lan - Configure K1 power state
13014edd8523SJack F Vogel  *  @hw: pointer to the HW structure
13024edd8523SJack F Vogel  *  @enable: K1 state to configure
13034edd8523SJack F Vogel  *
13044edd8523SJack F Vogel  *  Configure the K1 power state based on the provided parameter.
13054edd8523SJack F Vogel  *  Assumes semaphore already acquired.
13064edd8523SJack F Vogel  *
13074edd8523SJack F Vogel  *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
13084edd8523SJack F Vogel  **/
13094edd8523SJack F Vogel s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
13104edd8523SJack F Vogel {
13114edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
13124edd8523SJack F Vogel 	u32 ctrl_reg = 0;
13134edd8523SJack F Vogel 	u32 ctrl_ext = 0;
13144edd8523SJack F Vogel 	u32 reg = 0;
13154edd8523SJack F Vogel 	u16 kmrn_reg = 0;
13164edd8523SJack F Vogel 
13177d9119bdSJack F Vogel 	DEBUGFUNC("e1000_configure_k1_ich8lan");
13187d9119bdSJack F Vogel 
1319*4dab5c37SJack F Vogel 	ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
13204edd8523SJack F Vogel 					     &kmrn_reg);
13214edd8523SJack F Vogel 	if (ret_val)
13224edd8523SJack F Vogel 		goto out;
13234edd8523SJack F Vogel 
13244edd8523SJack F Vogel 	if (k1_enable)
13254edd8523SJack F Vogel 		kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE;
13264edd8523SJack F Vogel 	else
13274edd8523SJack F Vogel 		kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE;
13284edd8523SJack F Vogel 
1329*4dab5c37SJack F Vogel 	ret_val = e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
13304edd8523SJack F Vogel 					      kmrn_reg);
13314edd8523SJack F Vogel 	if (ret_val)
13324edd8523SJack F Vogel 		goto out;
13334edd8523SJack F Vogel 
13344edd8523SJack F Vogel 	usec_delay(20);
13354edd8523SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
13364edd8523SJack F Vogel 	ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
13374edd8523SJack F Vogel 
13384edd8523SJack F Vogel 	reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
13394edd8523SJack F Vogel 	reg |= E1000_CTRL_FRCSPD;
13404edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, reg);
13414edd8523SJack F Vogel 
13424edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
1343*4dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
13444edd8523SJack F Vogel 	usec_delay(20);
13454edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
13464edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
1347*4dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
13484edd8523SJack F Vogel 	usec_delay(20);
13494edd8523SJack F Vogel 
13504edd8523SJack F Vogel out:
13514edd8523SJack F Vogel 	return ret_val;
13524edd8523SJack F Vogel }
13534edd8523SJack F Vogel 
13544edd8523SJack F Vogel /**
13554edd8523SJack F Vogel  *  e1000_oem_bits_config_ich8lan - SW-based LCD Configuration
13564edd8523SJack F Vogel  *  @hw:       pointer to the HW structure
13574edd8523SJack F Vogel  *  @d0_state: boolean if entering d0 or d3 device state
13584edd8523SJack F Vogel  *
13594edd8523SJack F Vogel  *  SW will configure Gbe Disable and LPLU based on the NVM. The four bits are
13604edd8523SJack F Vogel  *  collectively called OEM bits.  The OEM Write Enable bit and SW Config bit
13614edd8523SJack F Vogel  *  in NVM determines whether HW should configure LPLU and Gbe Disable.
13624edd8523SJack F Vogel  **/
1363*4dab5c37SJack F Vogel static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
13644edd8523SJack F Vogel {
13654edd8523SJack F Vogel 	s32 ret_val = 0;
13664edd8523SJack F Vogel 	u32 mac_reg;
13674edd8523SJack F Vogel 	u16 oem_reg;
13684edd8523SJack F Vogel 
13697d9119bdSJack F Vogel 	DEBUGFUNC("e1000_oem_bits_config_ich8lan");
13707d9119bdSJack F Vogel 
13717d9119bdSJack F Vogel 	if ((hw->mac.type != e1000_pch2lan) && (hw->mac.type != e1000_pchlan))
13724edd8523SJack F Vogel 		return ret_val;
13734edd8523SJack F Vogel 
13744edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
13754edd8523SJack F Vogel 	if (ret_val)
13764edd8523SJack F Vogel 		return ret_val;
13774edd8523SJack F Vogel 
13787d9119bdSJack F Vogel 	if (!(hw->mac.type == e1000_pch2lan)) {
13794edd8523SJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
13804edd8523SJack F Vogel 		if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
13814edd8523SJack F Vogel 			goto out;
13827d9119bdSJack F Vogel 	}
13834edd8523SJack F Vogel 
13844edd8523SJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM);
13854edd8523SJack F Vogel 	if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
13864edd8523SJack F Vogel 		goto out;
13874edd8523SJack F Vogel 
13884edd8523SJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
13894edd8523SJack F Vogel 
13904edd8523SJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg);
13914edd8523SJack F Vogel 	if (ret_val)
13924edd8523SJack F Vogel 		goto out;
13934edd8523SJack F Vogel 
13944edd8523SJack F Vogel 	oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU);
13954edd8523SJack F Vogel 
13964edd8523SJack F Vogel 	if (d0_state) {
13974edd8523SJack F Vogel 		if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE)
13984edd8523SJack F Vogel 			oem_reg |= HV_OEM_BITS_GBE_DIS;
13994edd8523SJack F Vogel 
14004edd8523SJack F Vogel 		if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
14014edd8523SJack F Vogel 			oem_reg |= HV_OEM_BITS_LPLU;
14024edd8523SJack F Vogel 
1403*4dab5c37SJack F Vogel 		/* Set Restart auto-neg to activate the bits */
14044edd8523SJack F Vogel 		if (!hw->phy.ops.check_reset_block(hw))
14054edd8523SJack F Vogel 			oem_reg |= HV_OEM_BITS_RESTART_AN;
1406*4dab5c37SJack F Vogel 	} else {
1407*4dab5c37SJack F Vogel 		if (mac_reg & (E1000_PHY_CTRL_GBE_DISABLE |
1408*4dab5c37SJack F Vogel 		    E1000_PHY_CTRL_NOND0A_GBE_DISABLE))
1409*4dab5c37SJack F Vogel 			oem_reg |= HV_OEM_BITS_GBE_DIS;
1410*4dab5c37SJack F Vogel 
1411*4dab5c37SJack F Vogel 		if (mac_reg & (E1000_PHY_CTRL_D0A_LPLU |
1412*4dab5c37SJack F Vogel 		    E1000_PHY_CTRL_NOND0A_LPLU))
1413*4dab5c37SJack F Vogel 			oem_reg |= HV_OEM_BITS_LPLU;
1414*4dab5c37SJack F Vogel 	}
1415*4dab5c37SJack F Vogel 
14164edd8523SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg);
14174edd8523SJack F Vogel 
14184edd8523SJack F Vogel out:
14194edd8523SJack F Vogel 	hw->phy.ops.release(hw);
14204edd8523SJack F Vogel 
14214edd8523SJack F Vogel 	return ret_val;
14224edd8523SJack F Vogel }
14234edd8523SJack F Vogel 
14244edd8523SJack F Vogel 
14254edd8523SJack F Vogel /**
1426a69ed8dfSJack F Vogel  *  e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode
1427a69ed8dfSJack F Vogel  *  @hw:   pointer to the HW structure
1428a69ed8dfSJack F Vogel  **/
1429a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw)
1430a69ed8dfSJack F Vogel {
1431a69ed8dfSJack F Vogel 	s32 ret_val;
1432a69ed8dfSJack F Vogel 	u16 data;
1433a69ed8dfSJack F Vogel 
14347d9119bdSJack F Vogel 	DEBUGFUNC("e1000_set_mdio_slow_mode_hv");
14357d9119bdSJack F Vogel 
1436a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, HV_KMRN_MODE_CTRL, &data);
1437a69ed8dfSJack F Vogel 	if (ret_val)
1438a69ed8dfSJack F Vogel 		return ret_val;
1439a69ed8dfSJack F Vogel 
1440a69ed8dfSJack F Vogel 	data |= HV_KMRN_MDIO_SLOW;
1441a69ed8dfSJack F Vogel 
1442a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_MODE_CTRL, data);
1443a69ed8dfSJack F Vogel 
1444a69ed8dfSJack F Vogel 	return ret_val;
1445a69ed8dfSJack F Vogel }
1446a69ed8dfSJack F Vogel 
1447a69ed8dfSJack F Vogel /**
14489d81738fSJack F Vogel  *  e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
14499d81738fSJack F Vogel  *  done after every PHY reset.
14509d81738fSJack F Vogel  **/
14519d81738fSJack F Vogel static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
14529d81738fSJack F Vogel {
14539d81738fSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
1454a69ed8dfSJack F Vogel 	u16 phy_data;
14559d81738fSJack F Vogel 
14567d9119bdSJack F Vogel 	DEBUGFUNC("e1000_hv_phy_workarounds_ich8lan");
14577d9119bdSJack F Vogel 
14589d81738fSJack F Vogel 	if (hw->mac.type != e1000_pchlan)
14594edd8523SJack F Vogel 		goto out;
14609d81738fSJack F Vogel 
1461a69ed8dfSJack F Vogel 	/* Set MDIO slow mode before any other MDIO access */
1462a69ed8dfSJack F Vogel 	if (hw->phy.type == e1000_phy_82577) {
1463a69ed8dfSJack F Vogel 		ret_val = e1000_set_mdio_slow_mode_hv(hw);
1464a69ed8dfSJack F Vogel 		if (ret_val)
1465a69ed8dfSJack F Vogel 			goto out;
1466a69ed8dfSJack F Vogel 	}
1467a69ed8dfSJack F Vogel 
14689d81738fSJack F Vogel 	if (((hw->phy.type == e1000_phy_82577) &&
14699d81738fSJack F Vogel 	     ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
14709d81738fSJack F Vogel 	    ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
14719d81738fSJack F Vogel 		/* Disable generation of early preamble */
14729d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
14739d81738fSJack F Vogel 		if (ret_val)
14744edd8523SJack F Vogel 			goto out;
14759d81738fSJack F Vogel 
14769d81738fSJack F Vogel 		/* Preamble tuning for SSC */
1477*4dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA,
1478*4dab5c37SJack F Vogel 						0xA204);
14799d81738fSJack F Vogel 		if (ret_val)
14804edd8523SJack F Vogel 			goto out;
14819d81738fSJack F Vogel 	}
14829d81738fSJack F Vogel 
14839d81738fSJack F Vogel 	if (hw->phy.type == e1000_phy_82578) {
14849d81738fSJack F Vogel 		/*
14859d81738fSJack F Vogel 		 * Return registers to default by doing a soft reset then
14869d81738fSJack F Vogel 		 * writing 0x3140 to the control register.
14879d81738fSJack F Vogel 		 */
14889d81738fSJack F Vogel 		if (hw->phy.revision < 2) {
14899d81738fSJack F Vogel 			e1000_phy_sw_reset_generic(hw);
14909d81738fSJack F Vogel 			ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL,
14919d81738fSJack F Vogel 							0x3140);
14929d81738fSJack F Vogel 		}
14939d81738fSJack F Vogel 	}
14949d81738fSJack F Vogel 
14959d81738fSJack F Vogel 	/* Select page 0 */
14969d81738fSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
14979d81738fSJack F Vogel 	if (ret_val)
14984edd8523SJack F Vogel 		goto out;
14994edd8523SJack F Vogel 
15009d81738fSJack F Vogel 	hw->phy.addr = 1;
15014edd8523SJack F Vogel 	ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
1502a69ed8dfSJack F Vogel 	hw->phy.ops.release(hw);
15034edd8523SJack F Vogel 	if (ret_val)
15044edd8523SJack F Vogel 		goto out;
15059d81738fSJack F Vogel 
15064edd8523SJack F Vogel 	/*
15074edd8523SJack F Vogel 	 * Configure the K1 Si workaround during phy reset assuming there is
15084edd8523SJack F Vogel 	 * link so that it disables K1 if link is in 1Gbps.
15094edd8523SJack F Vogel 	 */
15104edd8523SJack F Vogel 	ret_val = e1000_k1_gig_workaround_hv(hw, TRUE);
1511a69ed8dfSJack F Vogel 	if (ret_val)
1512a69ed8dfSJack F Vogel 		goto out;
15134edd8523SJack F Vogel 
1514a69ed8dfSJack F Vogel 	/* Workaround for link disconnects on a busy hub in half duplex */
1515a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
1516a69ed8dfSJack F Vogel 	if (ret_val)
1517a69ed8dfSJack F Vogel 		goto out;
1518*4dab5c37SJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw, BM_PORT_GEN_CFG, &phy_data);
1519a69ed8dfSJack F Vogel 	if (ret_val)
1520a69ed8dfSJack F Vogel 		goto release;
1521*4dab5c37SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, BM_PORT_GEN_CFG,
1522a69ed8dfSJack F Vogel 					       phy_data & 0x00FF);
1523a69ed8dfSJack F Vogel release:
1524a69ed8dfSJack F Vogel 	hw->phy.ops.release(hw);
15254edd8523SJack F Vogel out:
15269d81738fSJack F Vogel 	return ret_val;
15279d81738fSJack F Vogel }
15289d81738fSJack F Vogel 
15299d81738fSJack F Vogel /**
15307d9119bdSJack F Vogel  *  e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY
15317d9119bdSJack F Vogel  *  @hw:   pointer to the HW structure
15327d9119bdSJack F Vogel  **/
15337d9119bdSJack F Vogel void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
15347d9119bdSJack F Vogel {
15357d9119bdSJack F Vogel 	u32 mac_reg;
1536*4dab5c37SJack F Vogel 	u16 i, phy_reg = 0;
1537*4dab5c37SJack F Vogel 	s32 ret_val;
15387d9119bdSJack F Vogel 
15397d9119bdSJack F Vogel 	DEBUGFUNC("e1000_copy_rx_addrs_to_phy_ich8lan");
15407d9119bdSJack F Vogel 
1541*4dab5c37SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
1542*4dab5c37SJack F Vogel 	if (ret_val)
1543*4dab5c37SJack F Vogel 		return;
1544*4dab5c37SJack F Vogel 	ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg);
1545*4dab5c37SJack F Vogel 	if (ret_val)
1546*4dab5c37SJack F Vogel 		goto release;
1547*4dab5c37SJack F Vogel 
15487d9119bdSJack F Vogel 	/* Copy both RAL/H (rar_entry_count) and SHRAL/H (+4) to PHY */
15497d9119bdSJack F Vogel 	for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
15507d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RAL(i));
1551*4dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_L(i),
1552*4dab5c37SJack F Vogel 					   (u16)(mac_reg & 0xFFFF));
1553*4dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_M(i),
1554*4dab5c37SJack F Vogel 					   (u16)((mac_reg >> 16) & 0xFFFF));
1555*4dab5c37SJack F Vogel 
15567d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RAH(i));
1557*4dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_H(i),
1558*4dab5c37SJack F Vogel 					   (u16)(mac_reg & 0xFFFF));
1559*4dab5c37SJack F Vogel 		hw->phy.ops.write_reg_page(hw, BM_RAR_CTRL(i),
1560*4dab5c37SJack F Vogel 					   (u16)((mac_reg & E1000_RAH_AV)
1561*4dab5c37SJack F Vogel 						 >> 16));
15627d9119bdSJack F Vogel 	}
1563*4dab5c37SJack F Vogel 
1564*4dab5c37SJack F Vogel 	e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg);
1565*4dab5c37SJack F Vogel 
1566*4dab5c37SJack F Vogel release:
1567*4dab5c37SJack F Vogel 	hw->phy.ops.release(hw);
15687d9119bdSJack F Vogel }
15697d9119bdSJack F Vogel 
15707d9119bdSJack F Vogel static u32 e1000_calc_rx_da_crc(u8 mac[])
15717d9119bdSJack F Vogel {
15727d9119bdSJack F Vogel 	u32 poly = 0xEDB88320;	/* Polynomial for 802.3 CRC calculation */
15737d9119bdSJack F Vogel 	u32 i, j, mask, crc;
15747d9119bdSJack F Vogel 
15757d9119bdSJack F Vogel 	DEBUGFUNC("e1000_calc_rx_da_crc");
15767d9119bdSJack F Vogel 
15777d9119bdSJack F Vogel 	crc = 0xffffffff;
15787d9119bdSJack F Vogel 	for (i = 0; i < 6; i++) {
15797d9119bdSJack F Vogel 		crc = crc ^ mac[i];
15807d9119bdSJack F Vogel 		for (j = 8; j > 0; j--) {
15817d9119bdSJack F Vogel 			mask = (crc & 1) * (-1);
15827d9119bdSJack F Vogel 			crc = (crc >> 1) ^ (poly & mask);
15837d9119bdSJack F Vogel 		}
15847d9119bdSJack F Vogel 	}
15857d9119bdSJack F Vogel 	return ~crc;
15867d9119bdSJack F Vogel }
15877d9119bdSJack F Vogel 
15887d9119bdSJack F Vogel /**
15897d9119bdSJack F Vogel  *  e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation
15907d9119bdSJack F Vogel  *  with 82579 PHY
15917d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
15927d9119bdSJack F Vogel  *  @enable: flag to enable/disable workaround when enabling/disabling jumbos
15937d9119bdSJack F Vogel  **/
15947d9119bdSJack F Vogel s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
15957d9119bdSJack F Vogel {
15967d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
15977d9119bdSJack F Vogel 	u16 phy_reg, data;
15987d9119bdSJack F Vogel 	u32 mac_reg;
15997d9119bdSJack F Vogel 	u16 i;
16007d9119bdSJack F Vogel 
16017d9119bdSJack F Vogel 	DEBUGFUNC("e1000_lv_jumbo_workaround_ich8lan");
16027d9119bdSJack F Vogel 
16037d9119bdSJack F Vogel 	if (hw->mac.type != e1000_pch2lan)
16047d9119bdSJack F Vogel 		goto out;
16057d9119bdSJack F Vogel 
16067d9119bdSJack F Vogel 	/* disable Rx path while enabling/disabling workaround */
16077d9119bdSJack F Vogel 	hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg);
1608*4dab5c37SJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20),
1609*4dab5c37SJack F Vogel 					phy_reg | (1 << 14));
16107d9119bdSJack F Vogel 	if (ret_val)
16117d9119bdSJack F Vogel 		goto out;
16127d9119bdSJack F Vogel 
16137d9119bdSJack F Vogel 	if (enable) {
16147d9119bdSJack F Vogel 		/*
16157d9119bdSJack F Vogel 		 * Write Rx addresses (rar_entry_count for RAL/H, +4 for
16167d9119bdSJack F Vogel 		 * SHRAL/H) and initial CRC values to the MAC
16177d9119bdSJack F Vogel 		 */
16187d9119bdSJack F Vogel 		for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
16197d9119bdSJack F Vogel 			u8 mac_addr[ETH_ADDR_LEN] = {0};
16207d9119bdSJack F Vogel 			u32 addr_high, addr_low;
16217d9119bdSJack F Vogel 
16227d9119bdSJack F Vogel 			addr_high = E1000_READ_REG(hw, E1000_RAH(i));
16237d9119bdSJack F Vogel 			if (!(addr_high & E1000_RAH_AV))
16247d9119bdSJack F Vogel 				continue;
16257d9119bdSJack F Vogel 			addr_low = E1000_READ_REG(hw, E1000_RAL(i));
16267d9119bdSJack F Vogel 			mac_addr[0] = (addr_low & 0xFF);
16277d9119bdSJack F Vogel 			mac_addr[1] = ((addr_low >> 8) & 0xFF);
16287d9119bdSJack F Vogel 			mac_addr[2] = ((addr_low >> 16) & 0xFF);
16297d9119bdSJack F Vogel 			mac_addr[3] = ((addr_low >> 24) & 0xFF);
16307d9119bdSJack F Vogel 			mac_addr[4] = (addr_high & 0xFF);
16317d9119bdSJack F Vogel 			mac_addr[5] = ((addr_high >> 8) & 0xFF);
16327d9119bdSJack F Vogel 
16337d9119bdSJack F Vogel 			E1000_WRITE_REG(hw, E1000_PCH_RAICC(i),
16347d9119bdSJack F Vogel 					e1000_calc_rx_da_crc(mac_addr));
16357d9119bdSJack F Vogel 		}
16367d9119bdSJack F Vogel 
16377d9119bdSJack F Vogel 		/* Write Rx addresses to the PHY */
16387d9119bdSJack F Vogel 		e1000_copy_rx_addrs_to_phy_ich8lan(hw);
16397d9119bdSJack F Vogel 
16407d9119bdSJack F Vogel 		/* Enable jumbo frame workaround in the MAC */
16417d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
16427d9119bdSJack F Vogel 		mac_reg &= ~(1 << 14);
16437d9119bdSJack F Vogel 		mac_reg |= (7 << 15);
16447d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
16457d9119bdSJack F Vogel 
16467d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RCTL);
16477d9119bdSJack F Vogel 		mac_reg |= E1000_RCTL_SECRC;
16487d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
16497d9119bdSJack F Vogel 
16507d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
16517d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
16527d9119bdSJack F Vogel 						&data);
16537d9119bdSJack F Vogel 		if (ret_val)
16547d9119bdSJack F Vogel 			goto out;
16557d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
16567d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
16577d9119bdSJack F Vogel 						data | (1 << 0));
16587d9119bdSJack F Vogel 		if (ret_val)
16597d9119bdSJack F Vogel 			goto out;
16607d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
16617d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
16627d9119bdSJack F Vogel 						&data);
16637d9119bdSJack F Vogel 		if (ret_val)
16647d9119bdSJack F Vogel 			goto out;
16657d9119bdSJack F Vogel 		data &= ~(0xF << 8);
16667d9119bdSJack F Vogel 		data |= (0xB << 8);
16677d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
16687d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
16697d9119bdSJack F Vogel 						data);
16707d9119bdSJack F Vogel 		if (ret_val)
16717d9119bdSJack F Vogel 			goto out;
16727d9119bdSJack F Vogel 
16737d9119bdSJack F Vogel 		/* Enable jumbo frame workaround in the PHY */
16747d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
16757d9119bdSJack F Vogel 		data &= ~(0x7F << 5);
16767d9119bdSJack F Vogel 		data |= (0x37 << 5);
16777d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
16787d9119bdSJack F Vogel 		if (ret_val)
16797d9119bdSJack F Vogel 			goto out;
16807d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
16817d9119bdSJack F Vogel 		data &= ~(1 << 13);
16827d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
16837d9119bdSJack F Vogel 		if (ret_val)
16847d9119bdSJack F Vogel 			goto out;
16857d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
16867d9119bdSJack F Vogel 		data &= ~(0x3FF << 2);
16877d9119bdSJack F Vogel 		data |= (0x1A << 2);
16887d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
16897d9119bdSJack F Vogel 		if (ret_val)
16907d9119bdSJack F Vogel 			goto out;
1691*4dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0xF100);
16927d9119bdSJack F Vogel 		if (ret_val)
16937d9119bdSJack F Vogel 			goto out;
16947d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
1695*4dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data |
1696*4dab5c37SJack F Vogel 						(1 << 10));
16977d9119bdSJack F Vogel 		if (ret_val)
16987d9119bdSJack F Vogel 			goto out;
16997d9119bdSJack F Vogel 	} else {
17007d9119bdSJack F Vogel 		/* Write MAC register values back to h/w defaults */
17017d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
17027d9119bdSJack F Vogel 		mac_reg &= ~(0xF << 14);
17037d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
17047d9119bdSJack F Vogel 
17057d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_RCTL);
17067d9119bdSJack F Vogel 		mac_reg &= ~E1000_RCTL_SECRC;
17077d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
17087d9119bdSJack F Vogel 
17097d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
17107d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
17117d9119bdSJack F Vogel 						&data);
17127d9119bdSJack F Vogel 		if (ret_val)
17137d9119bdSJack F Vogel 			goto out;
17147d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
17157d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_CTRL_OFFSET,
17167d9119bdSJack F Vogel 						data & ~(1 << 0));
17177d9119bdSJack F Vogel 		if (ret_val)
17187d9119bdSJack F Vogel 			goto out;
17197d9119bdSJack F Vogel 		ret_val = e1000_read_kmrn_reg_generic(hw,
17207d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
17217d9119bdSJack F Vogel 						&data);
17227d9119bdSJack F Vogel 		if (ret_val)
17237d9119bdSJack F Vogel 			goto out;
17247d9119bdSJack F Vogel 		data &= ~(0xF << 8);
17257d9119bdSJack F Vogel 		data |= (0xB << 8);
17267d9119bdSJack F Vogel 		ret_val = e1000_write_kmrn_reg_generic(hw,
17277d9119bdSJack F Vogel 						E1000_KMRNCTRLSTA_HD_CTRL,
17287d9119bdSJack F Vogel 						data);
17297d9119bdSJack F Vogel 		if (ret_val)
17307d9119bdSJack F Vogel 			goto out;
17317d9119bdSJack F Vogel 
17327d9119bdSJack F Vogel 		/* Write PHY register values back to h/w defaults */
17337d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
17347d9119bdSJack F Vogel 		data &= ~(0x7F << 5);
17357d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
17367d9119bdSJack F Vogel 		if (ret_val)
17377d9119bdSJack F Vogel 			goto out;
17387d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
17397d9119bdSJack F Vogel 		data |= (1 << 13);
17407d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
17417d9119bdSJack F Vogel 		if (ret_val)
17427d9119bdSJack F Vogel 			goto out;
17437d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
17447d9119bdSJack F Vogel 		data &= ~(0x3FF << 2);
17457d9119bdSJack F Vogel 		data |= (0x8 << 2);
17467d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
17477d9119bdSJack F Vogel 		if (ret_val)
17487d9119bdSJack F Vogel 			goto out;
17497d9119bdSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0x7E00);
17507d9119bdSJack F Vogel 		if (ret_val)
17517d9119bdSJack F Vogel 			goto out;
17527d9119bdSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
1753*4dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data &
1754*4dab5c37SJack F Vogel 						~(1 << 10));
17557d9119bdSJack F Vogel 		if (ret_val)
17567d9119bdSJack F Vogel 			goto out;
17577d9119bdSJack F Vogel 	}
17587d9119bdSJack F Vogel 
17597d9119bdSJack F Vogel 	/* re-enable Rx path after enabling/disabling workaround */
1760*4dab5c37SJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg &
1761*4dab5c37SJack F Vogel 					~(1 << 14));
17627d9119bdSJack F Vogel 
17637d9119bdSJack F Vogel out:
17647d9119bdSJack F Vogel 	return ret_val;
17657d9119bdSJack F Vogel }
17667d9119bdSJack F Vogel 
17677d9119bdSJack F Vogel /**
17687d9119bdSJack F Vogel  *  e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be
17697d9119bdSJack F Vogel  *  done after every PHY reset.
17707d9119bdSJack F Vogel  **/
17717d9119bdSJack F Vogel static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw)
17727d9119bdSJack F Vogel {
17737d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
17747d9119bdSJack F Vogel 
17757d9119bdSJack F Vogel 	DEBUGFUNC("e1000_lv_phy_workarounds_ich8lan");
17767d9119bdSJack F Vogel 
17777d9119bdSJack F Vogel 	if (hw->mac.type != e1000_pch2lan)
17787d9119bdSJack F Vogel 		goto out;
17797d9119bdSJack F Vogel 
17807d9119bdSJack F Vogel 	/* Set MDIO slow mode before any other MDIO access */
17817d9119bdSJack F Vogel 	ret_val = e1000_set_mdio_slow_mode_hv(hw);
17827d9119bdSJack F Vogel 
1783*4dab5c37SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
1784*4dab5c37SJack F Vogel 	if (ret_val)
1785*4dab5c37SJack F Vogel 		goto out;
1786*4dab5c37SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR,
1787*4dab5c37SJack F Vogel 					       I82579_MSE_THRESHOLD);
1788*4dab5c37SJack F Vogel 	if (ret_val)
1789*4dab5c37SJack F Vogel 		goto release;
1790*4dab5c37SJack F Vogel 	/* set MSE higher to enable link to stay up when noise is high */
1791*4dab5c37SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_DATA,
1792*4dab5c37SJack F Vogel 					       0x0034);
1793*4dab5c37SJack F Vogel 	if (ret_val)
1794*4dab5c37SJack F Vogel 		goto release;
1795*4dab5c37SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR,
1796*4dab5c37SJack F Vogel 					       I82579_MSE_LINK_DOWN);
1797*4dab5c37SJack F Vogel 	if (ret_val)
1798*4dab5c37SJack F Vogel 		goto release;
1799*4dab5c37SJack F Vogel 	/* drop link after 5 times MSE threshold was reached */
1800*4dab5c37SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_DATA,
1801*4dab5c37SJack F Vogel 					       0x0005);
1802*4dab5c37SJack F Vogel release:
1803*4dab5c37SJack F Vogel 	hw->phy.ops.release(hw);
1804*4dab5c37SJack F Vogel 
18057d9119bdSJack F Vogel out:
18067d9119bdSJack F Vogel 	return ret_val;
18077d9119bdSJack F Vogel }
18087d9119bdSJack F Vogel 
18097d9119bdSJack F Vogel /**
18107d9119bdSJack F Vogel  *  e1000_k1_gig_workaround_lv - K1 Si workaround
18117d9119bdSJack F Vogel  *  @hw:   pointer to the HW structure
18127d9119bdSJack F Vogel  *
18137d9119bdSJack F Vogel  *  Workaround to set the K1 beacon duration for 82579 parts
18147d9119bdSJack F Vogel  **/
18157d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw)
18167d9119bdSJack F Vogel {
18177d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
18187d9119bdSJack F Vogel 	u16 status_reg = 0;
18197d9119bdSJack F Vogel 	u32 mac_reg;
1820*4dab5c37SJack F Vogel 	u16 phy_reg;
18217d9119bdSJack F Vogel 
18227d9119bdSJack F Vogel 	DEBUGFUNC("e1000_k1_workaround_lv");
18237d9119bdSJack F Vogel 
18247d9119bdSJack F Vogel 	if (hw->mac.type != e1000_pch2lan)
18257d9119bdSJack F Vogel 		goto out;
18267d9119bdSJack F Vogel 
18277d9119bdSJack F Vogel 	/* Set K1 beacon duration based on 1Gbps speed or otherwise */
18287d9119bdSJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, HV_M_STATUS, &status_reg);
18297d9119bdSJack F Vogel 	if (ret_val)
18307d9119bdSJack F Vogel 		goto out;
18317d9119bdSJack F Vogel 
18327d9119bdSJack F Vogel 	if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE))
18337d9119bdSJack F Vogel 	    == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) {
18347d9119bdSJack F Vogel 		mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4);
18357d9119bdSJack F Vogel 		mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
18367d9119bdSJack F Vogel 
1837*4dab5c37SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, I82579_LPI_CTRL, &phy_reg);
1838*4dab5c37SJack F Vogel 		if (ret_val)
1839*4dab5c37SJack F Vogel 			goto out;
18407d9119bdSJack F Vogel 
1841*4dab5c37SJack F Vogel 		if (status_reg & HV_M_STATUS_SPEED_1000) {
1842*4dab5c37SJack F Vogel 			mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
1843*4dab5c37SJack F Vogel 			phy_reg &= ~I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT;
1844*4dab5c37SJack F Vogel 		} else {
1845*4dab5c37SJack F Vogel 			mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
1846*4dab5c37SJack F Vogel 			phy_reg |= I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT;
1847*4dab5c37SJack F Vogel 		}
18487d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg);
1849*4dab5c37SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, I82579_LPI_CTRL, phy_reg);
18507d9119bdSJack F Vogel 	}
18517d9119bdSJack F Vogel 
18527d9119bdSJack F Vogel out:
18537d9119bdSJack F Vogel 	return ret_val;
18547d9119bdSJack F Vogel }
18557d9119bdSJack F Vogel 
18567d9119bdSJack F Vogel /**
18577d9119bdSJack F Vogel  *  e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware
18587d9119bdSJack F Vogel  *  @hw:   pointer to the HW structure
1859730d3130SJack F Vogel  *  @gate: boolean set to TRUE to gate, FALSE to ungate
18607d9119bdSJack F Vogel  *
18617d9119bdSJack F Vogel  *  Gate/ungate the automatic PHY configuration via hardware; perform
18627d9119bdSJack F Vogel  *  the configuration via software instead.
18637d9119bdSJack F Vogel  **/
18647d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate)
18657d9119bdSJack F Vogel {
18667d9119bdSJack F Vogel 	u32 extcnf_ctrl;
18677d9119bdSJack F Vogel 
18687d9119bdSJack F Vogel 	DEBUGFUNC("e1000_gate_hw_phy_config_ich8lan");
18697d9119bdSJack F Vogel 
18707d9119bdSJack F Vogel 	if (hw->mac.type != e1000_pch2lan)
18717d9119bdSJack F Vogel 		return;
18727d9119bdSJack F Vogel 
18737d9119bdSJack F Vogel 	extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
18747d9119bdSJack F Vogel 
18757d9119bdSJack F Vogel 	if (gate)
18767d9119bdSJack F Vogel 		extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
18777d9119bdSJack F Vogel 	else
18787d9119bdSJack F Vogel 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG;
18797d9119bdSJack F Vogel 
18807d9119bdSJack F Vogel 	E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
18817d9119bdSJack F Vogel 	return;
18827d9119bdSJack F Vogel }
18837d9119bdSJack F Vogel 
18847d9119bdSJack F Vogel /**
18859d81738fSJack F Vogel  *  e1000_lan_init_done_ich8lan - Check for PHY config completion
18868cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
18878cfa0ad2SJack F Vogel  *
18889d81738fSJack F Vogel  *  Check the appropriate indication the MAC has finished configuring the
18899d81738fSJack F Vogel  *  PHY after a software reset.
18908cfa0ad2SJack F Vogel  **/
18919d81738fSJack F Vogel static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw)
18928cfa0ad2SJack F Vogel {
18939d81738fSJack F Vogel 	u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT;
18948cfa0ad2SJack F Vogel 
18959d81738fSJack F Vogel 	DEBUGFUNC("e1000_lan_init_done_ich8lan");
18968cfa0ad2SJack F Vogel 
18979d81738fSJack F Vogel 	/* Wait for basic configuration completes before proceeding */
18989d81738fSJack F Vogel 	do {
18999d81738fSJack F Vogel 		data = E1000_READ_REG(hw, E1000_STATUS);
19009d81738fSJack F Vogel 		data &= E1000_STATUS_LAN_INIT_DONE;
19019d81738fSJack F Vogel 		usec_delay(100);
19029d81738fSJack F Vogel 	} while ((!data) && --loop);
19038cfa0ad2SJack F Vogel 
19049d81738fSJack F Vogel 	/*
19059d81738fSJack F Vogel 	 * If basic configuration is incomplete before the above loop
19069d81738fSJack F Vogel 	 * count reaches 0, loading the configuration from NVM will
19079d81738fSJack F Vogel 	 * leave the PHY in a bad state possibly resulting in no link.
19089d81738fSJack F Vogel 	 */
19099d81738fSJack F Vogel 	if (loop == 0)
19109d81738fSJack F Vogel 		DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n");
19118cfa0ad2SJack F Vogel 
19129d81738fSJack F Vogel 	/* Clear the Init Done bit for the next init event */
19139d81738fSJack F Vogel 	data = E1000_READ_REG(hw, E1000_STATUS);
19149d81738fSJack F Vogel 	data &= ~E1000_STATUS_LAN_INIT_DONE;
19159d81738fSJack F Vogel 	E1000_WRITE_REG(hw, E1000_STATUS, data);
19168cfa0ad2SJack F Vogel }
19178cfa0ad2SJack F Vogel 
19188cfa0ad2SJack F Vogel /**
19197d9119bdSJack F Vogel  *  e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset
19207d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
19217d9119bdSJack F Vogel  **/
19227d9119bdSJack F Vogel static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
19237d9119bdSJack F Vogel {
19247d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
19257d9119bdSJack F Vogel 	u16 reg;
19267d9119bdSJack F Vogel 
19277d9119bdSJack F Vogel 	DEBUGFUNC("e1000_post_phy_reset_ich8lan");
19287d9119bdSJack F Vogel 
19297d9119bdSJack F Vogel 	if (hw->phy.ops.check_reset_block(hw))
19307d9119bdSJack F Vogel 		goto out;
19317d9119bdSJack F Vogel 
19327d9119bdSJack F Vogel 	/* Allow time for h/w to get to quiescent state after reset */
19337d9119bdSJack F Vogel 	msec_delay(10);
19347d9119bdSJack F Vogel 
19357d9119bdSJack F Vogel 	/* Perform any necessary post-reset workarounds */
19367d9119bdSJack F Vogel 	switch (hw->mac.type) {
19377d9119bdSJack F Vogel 	case e1000_pchlan:
19387d9119bdSJack F Vogel 		ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
19397d9119bdSJack F Vogel 		if (ret_val)
19407d9119bdSJack F Vogel 			goto out;
19417d9119bdSJack F Vogel 		break;
19427d9119bdSJack F Vogel 	case e1000_pch2lan:
19437d9119bdSJack F Vogel 		ret_val = e1000_lv_phy_workarounds_ich8lan(hw);
19447d9119bdSJack F Vogel 		if (ret_val)
19457d9119bdSJack F Vogel 			goto out;
19467d9119bdSJack F Vogel 		break;
19477d9119bdSJack F Vogel 	default:
19487d9119bdSJack F Vogel 		break;
19497d9119bdSJack F Vogel 	}
19507d9119bdSJack F Vogel 
1951*4dab5c37SJack F Vogel 	/* Clear the host wakeup bit after lcd reset */
1952*4dab5c37SJack F Vogel 	if (hw->mac.type >= e1000_pchlan) {
1953*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, &reg);
1954*4dab5c37SJack F Vogel 		reg &= ~BM_WUC_HOST_WU_BIT;
1955*4dab5c37SJack F Vogel 		hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, reg);
19567d9119bdSJack F Vogel 	}
19577d9119bdSJack F Vogel 
19587d9119bdSJack F Vogel 	/* Configure the LCD with the extended configuration region in NVM */
19597d9119bdSJack F Vogel 	ret_val = e1000_sw_lcd_config_ich8lan(hw);
19607d9119bdSJack F Vogel 	if (ret_val)
19617d9119bdSJack F Vogel 		goto out;
19627d9119bdSJack F Vogel 
19637d9119bdSJack F Vogel 	/* Configure the LCD with the OEM bits in NVM */
19647d9119bdSJack F Vogel 	ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE);
19657d9119bdSJack F Vogel 
1966730d3130SJack F Vogel 	if (hw->mac.type == e1000_pch2lan) {
19677d9119bdSJack F Vogel 		/* Ungate automatic PHY configuration on non-managed 82579 */
1968730d3130SJack F Vogel 		if (!(E1000_READ_REG(hw, E1000_FWSM) &
1969730d3130SJack F Vogel 		    E1000_ICH_FWSM_FW_VALID)) {
19707d9119bdSJack F Vogel 			msec_delay(10);
19717d9119bdSJack F Vogel 			e1000_gate_hw_phy_config_ich8lan(hw, FALSE);
19727d9119bdSJack F Vogel 		}
19737d9119bdSJack F Vogel 
1974730d3130SJack F Vogel 		/* Set EEE LPI Update Timer to 200usec */
1975730d3130SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
1976730d3130SJack F Vogel 		if (ret_val)
1977730d3130SJack F Vogel 			goto out;
1978730d3130SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR,
1979730d3130SJack F Vogel 						       I82579_LPI_UPDATE_TIMER);
1980730d3130SJack F Vogel 		if (ret_val)
1981730d3130SJack F Vogel 			goto release;
1982730d3130SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_DATA,
1983730d3130SJack F Vogel 						       0x1387);
1984730d3130SJack F Vogel release:
1985730d3130SJack F Vogel 		hw->phy.ops.release(hw);
1986730d3130SJack F Vogel 	}
1987730d3130SJack F Vogel 
19887d9119bdSJack F Vogel out:
19897d9119bdSJack F Vogel 	return ret_val;
19907d9119bdSJack F Vogel }
19917d9119bdSJack F Vogel 
19927d9119bdSJack F Vogel /**
19938cfa0ad2SJack F Vogel  *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
19948cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
19958cfa0ad2SJack F Vogel  *
19968cfa0ad2SJack F Vogel  *  Resets the PHY
19978cfa0ad2SJack F Vogel  *  This is a function pointer entry point called by drivers
19988cfa0ad2SJack F Vogel  *  or other shared routines.
19998cfa0ad2SJack F Vogel  **/
20008cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
20018cfa0ad2SJack F Vogel {
20024edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
20038cfa0ad2SJack F Vogel 
20048cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
20058cfa0ad2SJack F Vogel 
20067d9119bdSJack F Vogel 	/* Gate automatic PHY configuration by hardware on non-managed 82579 */
20077d9119bdSJack F Vogel 	if ((hw->mac.type == e1000_pch2lan) &&
20087d9119bdSJack F Vogel 	    !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
20097d9119bdSJack F Vogel 		e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
20107d9119bdSJack F Vogel 
20118cfa0ad2SJack F Vogel 	ret_val = e1000_phy_hw_reset_generic(hw);
20128cfa0ad2SJack F Vogel 	if (ret_val)
20138cfa0ad2SJack F Vogel 		goto out;
20148cfa0ad2SJack F Vogel 
20157d9119bdSJack F Vogel 	ret_val = e1000_post_phy_reset_ich8lan(hw);
20168cfa0ad2SJack F Vogel 
20178cfa0ad2SJack F Vogel out:
20188cfa0ad2SJack F Vogel 	return ret_val;
20198cfa0ad2SJack F Vogel }
20208cfa0ad2SJack F Vogel 
20218cfa0ad2SJack F Vogel /**
20224edd8523SJack F Vogel  *  e1000_set_lplu_state_pchlan - Set Low Power Link Up state
20238cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
20244edd8523SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
20258cfa0ad2SJack F Vogel  *
20264edd8523SJack F Vogel  *  Sets the LPLU state according to the active flag.  For PCH, if OEM write
20274edd8523SJack F Vogel  *  bit are disabled in the NVM, writing the LPLU bits in the MAC will not set
20284edd8523SJack F Vogel  *  the phy speed. This function will manually set the LPLU bit and restart
20294edd8523SJack F Vogel  *  auto-neg as hw would do. D3 and D0 LPLU will call the same function
20304edd8523SJack F Vogel  *  since it configures the same bit.
20318cfa0ad2SJack F Vogel  **/
20324edd8523SJack F Vogel static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
20338cfa0ad2SJack F Vogel {
20344edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
20354edd8523SJack F Vogel 	u16 oem_reg;
20368cfa0ad2SJack F Vogel 
20374edd8523SJack F Vogel 	DEBUGFUNC("e1000_set_lplu_state_pchlan");
20388cfa0ad2SJack F Vogel 
20394edd8523SJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg);
20408cfa0ad2SJack F Vogel 	if (ret_val)
20418cfa0ad2SJack F Vogel 		goto out;
20428cfa0ad2SJack F Vogel 
20434edd8523SJack F Vogel 	if (active)
20444edd8523SJack F Vogel 		oem_reg |= HV_OEM_BITS_LPLU;
20454edd8523SJack F Vogel 	else
20464edd8523SJack F Vogel 		oem_reg &= ~HV_OEM_BITS_LPLU;
20478cfa0ad2SJack F Vogel 
2048*4dab5c37SJack F Vogel 	if (!hw->phy.ops.check_reset_block(hw))
20494edd8523SJack F Vogel 		oem_reg |= HV_OEM_BITS_RESTART_AN;
2050*4dab5c37SJack F Vogel 
20514edd8523SJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg);
20528cfa0ad2SJack F Vogel 
20538cfa0ad2SJack F Vogel out:
20548cfa0ad2SJack F Vogel 	return ret_val;
20558cfa0ad2SJack F Vogel }
20568cfa0ad2SJack F Vogel 
20578cfa0ad2SJack F Vogel /**
20588cfa0ad2SJack F Vogel  *  e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
20598cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
20608cfa0ad2SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
20618cfa0ad2SJack F Vogel  *
20628cfa0ad2SJack F Vogel  *  Sets the LPLU D0 state according to the active flag.  When
20638cfa0ad2SJack F Vogel  *  activating LPLU this function also disables smart speed
20648cfa0ad2SJack F Vogel  *  and vice versa.  LPLU will not be activated unless the
20658cfa0ad2SJack F Vogel  *  device autonegotiation advertisement meets standards of
20668cfa0ad2SJack F Vogel  *  either 10 or 10/100 or 10/100/1000 at all duplexes.
20678cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
20688cfa0ad2SJack F Vogel  *  PHY setup routines.
20698cfa0ad2SJack F Vogel  **/
2070daf9197cSJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
20718cfa0ad2SJack F Vogel {
20728cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
20738cfa0ad2SJack F Vogel 	u32 phy_ctrl;
20748cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
20758cfa0ad2SJack F Vogel 	u16 data;
20768cfa0ad2SJack F Vogel 
20778cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan");
20788cfa0ad2SJack F Vogel 
20798cfa0ad2SJack F Vogel 	if (phy->type == e1000_phy_ife)
20808cfa0ad2SJack F Vogel 		goto out;
20818cfa0ad2SJack F Vogel 
20828cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
20838cfa0ad2SJack F Vogel 
20848cfa0ad2SJack F Vogel 	if (active) {
20858cfa0ad2SJack F Vogel 		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
20868cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
20878cfa0ad2SJack F Vogel 
20889d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
20899d81738fSJack F Vogel 			goto out;
20909d81738fSJack F Vogel 
20918cfa0ad2SJack F Vogel 		/*
20928cfa0ad2SJack F Vogel 		 * Call gig speed drop workaround on LPLU before accessing
20938cfa0ad2SJack F Vogel 		 * any PHY registers
20948cfa0ad2SJack F Vogel 		 */
20959d81738fSJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
20968cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
20978cfa0ad2SJack F Vogel 
20988cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
20998cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw,
21008cfa0ad2SJack F Vogel 					    IGP01E1000_PHY_PORT_CONFIG,
21018cfa0ad2SJack F Vogel 					    &data);
21028cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
21038cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
21048cfa0ad2SJack F Vogel 					     IGP01E1000_PHY_PORT_CONFIG,
21058cfa0ad2SJack F Vogel 					     data);
21068cfa0ad2SJack F Vogel 		if (ret_val)
21078cfa0ad2SJack F Vogel 			goto out;
21088cfa0ad2SJack F Vogel 	} else {
21098cfa0ad2SJack F Vogel 		phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
21108cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
21118cfa0ad2SJack F Vogel 
21129d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
21139d81738fSJack F Vogel 			goto out;
21149d81738fSJack F Vogel 
21158cfa0ad2SJack F Vogel 		/*
21168cfa0ad2SJack F Vogel 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
21178cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
21188cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
21198cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
21208cfa0ad2SJack F Vogel 		 */
21218cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
21228cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
21238cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
21248cfa0ad2SJack F Vogel 						    &data);
21258cfa0ad2SJack F Vogel 			if (ret_val)
21268cfa0ad2SJack F Vogel 				goto out;
21278cfa0ad2SJack F Vogel 
21288cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
21298cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
21308cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
21318cfa0ad2SJack F Vogel 						     data);
21328cfa0ad2SJack F Vogel 			if (ret_val)
21338cfa0ad2SJack F Vogel 				goto out;
21348cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
21358cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
21368cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
21378cfa0ad2SJack F Vogel 						    &data);
21388cfa0ad2SJack F Vogel 			if (ret_val)
21398cfa0ad2SJack F Vogel 				goto out;
21408cfa0ad2SJack F Vogel 
21418cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
21428cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
21438cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
21448cfa0ad2SJack F Vogel 						     data);
21458cfa0ad2SJack F Vogel 			if (ret_val)
21468cfa0ad2SJack F Vogel 				goto out;
21478cfa0ad2SJack F Vogel 		}
21488cfa0ad2SJack F Vogel 	}
21498cfa0ad2SJack F Vogel 
21508cfa0ad2SJack F Vogel out:
21518cfa0ad2SJack F Vogel 	return ret_val;
21528cfa0ad2SJack F Vogel }
21538cfa0ad2SJack F Vogel 
21548cfa0ad2SJack F Vogel /**
21558cfa0ad2SJack F Vogel  *  e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
21568cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
21578cfa0ad2SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
21588cfa0ad2SJack F Vogel  *
21598cfa0ad2SJack F Vogel  *  Sets the LPLU D3 state according to the active flag.  When
21608cfa0ad2SJack F Vogel  *  activating LPLU this function also disables smart speed
21618cfa0ad2SJack F Vogel  *  and vice versa.  LPLU will not be activated unless the
21628cfa0ad2SJack F Vogel  *  device autonegotiation advertisement meets standards of
21638cfa0ad2SJack F Vogel  *  either 10 or 10/100 or 10/100/1000 at all duplexes.
21648cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
21658cfa0ad2SJack F Vogel  *  PHY setup routines.
21668cfa0ad2SJack F Vogel  **/
2167daf9197cSJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
21688cfa0ad2SJack F Vogel {
21698cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
21708cfa0ad2SJack F Vogel 	u32 phy_ctrl;
21718cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
21728cfa0ad2SJack F Vogel 	u16 data;
21738cfa0ad2SJack F Vogel 
21748cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan");
21758cfa0ad2SJack F Vogel 
21768cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
21778cfa0ad2SJack F Vogel 
21788cfa0ad2SJack F Vogel 	if (!active) {
21798cfa0ad2SJack F Vogel 		phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
21808cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
21819d81738fSJack F Vogel 
21829d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
21839d81738fSJack F Vogel 			goto out;
21849d81738fSJack F Vogel 
21858cfa0ad2SJack F Vogel 		/*
21868cfa0ad2SJack F Vogel 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
21878cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
21888cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
21898cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
21908cfa0ad2SJack F Vogel 		 */
21918cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
21928cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
21938cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
21948cfa0ad2SJack F Vogel 						    &data);
21958cfa0ad2SJack F Vogel 			if (ret_val)
21968cfa0ad2SJack F Vogel 				goto out;
21978cfa0ad2SJack F Vogel 
21988cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
21998cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
22008cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
22018cfa0ad2SJack F Vogel 						     data);
22028cfa0ad2SJack F Vogel 			if (ret_val)
22038cfa0ad2SJack F Vogel 				goto out;
22048cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
22058cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
22068cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
22078cfa0ad2SJack F Vogel 						    &data);
22088cfa0ad2SJack F Vogel 			if (ret_val)
22098cfa0ad2SJack F Vogel 				goto out;
22108cfa0ad2SJack F Vogel 
22118cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
22128cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
22138cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
22148cfa0ad2SJack F Vogel 						     data);
22158cfa0ad2SJack F Vogel 			if (ret_val)
22168cfa0ad2SJack F Vogel 				goto out;
22178cfa0ad2SJack F Vogel 		}
22188cfa0ad2SJack F Vogel 	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
22198cfa0ad2SJack F Vogel 		   (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
22208cfa0ad2SJack F Vogel 		   (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
22218cfa0ad2SJack F Vogel 		phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
22228cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
22238cfa0ad2SJack F Vogel 
22249d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
22259d81738fSJack F Vogel 			goto out;
22269d81738fSJack F Vogel 
22278cfa0ad2SJack F Vogel 		/*
22288cfa0ad2SJack F Vogel 		 * Call gig speed drop workaround on LPLU before accessing
22298cfa0ad2SJack F Vogel 		 * any PHY registers
22308cfa0ad2SJack F Vogel 		 */
22319d81738fSJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
22328cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
22338cfa0ad2SJack F Vogel 
22348cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
22358cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw,
22368cfa0ad2SJack F Vogel 					    IGP01E1000_PHY_PORT_CONFIG,
22378cfa0ad2SJack F Vogel 					    &data);
22388cfa0ad2SJack F Vogel 		if (ret_val)
22398cfa0ad2SJack F Vogel 			goto out;
22408cfa0ad2SJack F Vogel 
22418cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
22428cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
22438cfa0ad2SJack F Vogel 					     IGP01E1000_PHY_PORT_CONFIG,
22448cfa0ad2SJack F Vogel 					     data);
22458cfa0ad2SJack F Vogel 	}
22468cfa0ad2SJack F Vogel 
22478cfa0ad2SJack F Vogel out:
22488cfa0ad2SJack F Vogel 	return ret_val;
22498cfa0ad2SJack F Vogel }
22508cfa0ad2SJack F Vogel 
22518cfa0ad2SJack F Vogel /**
22528cfa0ad2SJack F Vogel  *  e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
22538cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
22548cfa0ad2SJack F Vogel  *  @bank:  pointer to the variable that returns the active bank
22558cfa0ad2SJack F Vogel  *
22568cfa0ad2SJack F Vogel  *  Reads signature byte from the NVM using the flash access registers.
2257d035aa2dSJack F Vogel  *  Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
22588cfa0ad2SJack F Vogel  **/
22598cfa0ad2SJack F Vogel static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
22608cfa0ad2SJack F Vogel {
2261d035aa2dSJack F Vogel 	u32 eecd;
22628cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
22638cfa0ad2SJack F Vogel 	u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
22648cfa0ad2SJack F Vogel 	u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
2265d035aa2dSJack F Vogel 	u8 sig_byte = 0;
2266d035aa2dSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
22678cfa0ad2SJack F Vogel 
22687d9119bdSJack F Vogel 	DEBUGFUNC("e1000_valid_nvm_bank_detect_ich8lan");
22697d9119bdSJack F Vogel 
2270d035aa2dSJack F Vogel 	switch (hw->mac.type) {
2271d035aa2dSJack F Vogel 	case e1000_ich8lan:
2272d035aa2dSJack F Vogel 	case e1000_ich9lan:
2273d035aa2dSJack F Vogel 		eecd = E1000_READ_REG(hw, E1000_EECD);
2274d035aa2dSJack F Vogel 		if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
2275d035aa2dSJack F Vogel 		    E1000_EECD_SEC1VAL_VALID_MASK) {
2276d035aa2dSJack F Vogel 			if (eecd & E1000_EECD_SEC1VAL)
22778cfa0ad2SJack F Vogel 				*bank = 1;
22788cfa0ad2SJack F Vogel 			else
22798cfa0ad2SJack F Vogel 				*bank = 0;
2280d035aa2dSJack F Vogel 
2281d035aa2dSJack F Vogel 			goto out;
2282d035aa2dSJack F Vogel 		}
2283*4dab5c37SJack F Vogel 		DEBUGOUT("Unable to determine valid NVM bank via EEC - reading flash signature\n");
2284d035aa2dSJack F Vogel 		/* fall-thru */
2285d035aa2dSJack F Vogel 	default:
2286d035aa2dSJack F Vogel 		/* set bank to 0 in case flash read fails */
22878cfa0ad2SJack F Vogel 		*bank = 0;
22888cfa0ad2SJack F Vogel 
2289d035aa2dSJack F Vogel 		/* Check bank 0 */
2290d035aa2dSJack F Vogel 		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
2291d035aa2dSJack F Vogel 							&sig_byte);
2292d035aa2dSJack F Vogel 		if (ret_val)
2293d035aa2dSJack F Vogel 			goto out;
2294d035aa2dSJack F Vogel 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
2295d035aa2dSJack F Vogel 		    E1000_ICH_NVM_SIG_VALUE) {
2296d035aa2dSJack F Vogel 			*bank = 0;
2297d035aa2dSJack F Vogel 			goto out;
2298d035aa2dSJack F Vogel 		}
2299d035aa2dSJack F Vogel 
2300d035aa2dSJack F Vogel 		/* Check bank 1 */
2301d035aa2dSJack F Vogel 		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
2302d035aa2dSJack F Vogel 							bank1_offset,
2303d035aa2dSJack F Vogel 							&sig_byte);
2304d035aa2dSJack F Vogel 		if (ret_val)
2305d035aa2dSJack F Vogel 			goto out;
2306d035aa2dSJack F Vogel 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
2307d035aa2dSJack F Vogel 		    E1000_ICH_NVM_SIG_VALUE) {
23088cfa0ad2SJack F Vogel 			*bank = 1;
2309d035aa2dSJack F Vogel 			goto out;
23108cfa0ad2SJack F Vogel 		}
23118cfa0ad2SJack F Vogel 
2312d035aa2dSJack F Vogel 		DEBUGOUT("ERROR: No valid NVM bank present\n");
2313d035aa2dSJack F Vogel 		ret_val = -E1000_ERR_NVM;
2314d035aa2dSJack F Vogel 		break;
2315d035aa2dSJack F Vogel 	}
2316d035aa2dSJack F Vogel out:
23178cfa0ad2SJack F Vogel 	return ret_val;
23188cfa0ad2SJack F Vogel }
23198cfa0ad2SJack F Vogel 
23208cfa0ad2SJack F Vogel /**
23218cfa0ad2SJack F Vogel  *  e1000_read_nvm_ich8lan - Read word(s) from the NVM
23228cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
23238cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the word(s) to read.
23248cfa0ad2SJack F Vogel  *  @words: Size of data to read in words
23258cfa0ad2SJack F Vogel  *  @data: Pointer to the word(s) to read at offset.
23268cfa0ad2SJack F Vogel  *
23278cfa0ad2SJack F Vogel  *  Reads a word(s) from the NVM using the flash access registers.
23288cfa0ad2SJack F Vogel  **/
23298cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
23308cfa0ad2SJack F Vogel 				  u16 *data)
23318cfa0ad2SJack F Vogel {
23328cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
2333daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
23348cfa0ad2SJack F Vogel 	u32 act_offset;
23358cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
23368cfa0ad2SJack F Vogel 	u32 bank = 0;
23378cfa0ad2SJack F Vogel 	u16 i, word;
23388cfa0ad2SJack F Vogel 
23398cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_nvm_ich8lan");
23408cfa0ad2SJack F Vogel 
23418cfa0ad2SJack F Vogel 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
23428cfa0ad2SJack F Vogel 	    (words == 0)) {
23438cfa0ad2SJack F Vogel 		DEBUGOUT("nvm parameter(s) out of bounds\n");
23448cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
23458cfa0ad2SJack F Vogel 		goto out;
23468cfa0ad2SJack F Vogel 	}
23478cfa0ad2SJack F Vogel 
23484edd8523SJack F Vogel 	nvm->ops.acquire(hw);
23498cfa0ad2SJack F Vogel 
23508cfa0ad2SJack F Vogel 	ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
23514edd8523SJack F Vogel 	if (ret_val != E1000_SUCCESS) {
23524edd8523SJack F Vogel 		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
23534edd8523SJack F Vogel 		bank = 0;
23544edd8523SJack F Vogel 	}
23558cfa0ad2SJack F Vogel 
23568cfa0ad2SJack F Vogel 	act_offset = (bank) ? nvm->flash_bank_size : 0;
23578cfa0ad2SJack F Vogel 	act_offset += offset;
23588cfa0ad2SJack F Vogel 
23594edd8523SJack F Vogel 	ret_val = E1000_SUCCESS;
23608cfa0ad2SJack F Vogel 	for (i = 0; i < words; i++) {
2361*4dab5c37SJack F Vogel 		if (dev_spec->shadow_ram[offset+i].modified) {
23628cfa0ad2SJack F Vogel 			data[i] = dev_spec->shadow_ram[offset+i].value;
23638cfa0ad2SJack F Vogel 		} else {
23648cfa0ad2SJack F Vogel 			ret_val = e1000_read_flash_word_ich8lan(hw,
23658cfa0ad2SJack F Vogel 								act_offset + i,
23668cfa0ad2SJack F Vogel 								&word);
23678cfa0ad2SJack F Vogel 			if (ret_val)
23688cfa0ad2SJack F Vogel 				break;
23698cfa0ad2SJack F Vogel 			data[i] = word;
23708cfa0ad2SJack F Vogel 		}
23718cfa0ad2SJack F Vogel 	}
23728cfa0ad2SJack F Vogel 
23738cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
23748cfa0ad2SJack F Vogel 
23758cfa0ad2SJack F Vogel out:
2376d035aa2dSJack F Vogel 	if (ret_val)
2377d035aa2dSJack F Vogel 		DEBUGOUT1("NVM read error: %d\n", ret_val);
2378d035aa2dSJack F Vogel 
23798cfa0ad2SJack F Vogel 	return ret_val;
23808cfa0ad2SJack F Vogel }
23818cfa0ad2SJack F Vogel 
23828cfa0ad2SJack F Vogel /**
23838cfa0ad2SJack F Vogel  *  e1000_flash_cycle_init_ich8lan - Initialize flash
23848cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
23858cfa0ad2SJack F Vogel  *
23868cfa0ad2SJack F Vogel  *  This function does initial flash setup so that a new read/write/erase cycle
23878cfa0ad2SJack F Vogel  *  can be started.
23888cfa0ad2SJack F Vogel  **/
23898cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
23908cfa0ad2SJack F Vogel {
23918cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
23928cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
23938cfa0ad2SJack F Vogel 
23948cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_flash_cycle_init_ich8lan");
23958cfa0ad2SJack F Vogel 
23968cfa0ad2SJack F Vogel 	hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
23978cfa0ad2SJack F Vogel 
23988cfa0ad2SJack F Vogel 	/* Check if the flash descriptor is valid */
23998cfa0ad2SJack F Vogel 	if (hsfsts.hsf_status.fldesvalid == 0) {
2400*4dab5c37SJack F Vogel 		DEBUGOUT("Flash descriptor invalid.  SW Sequencing must be used.\n");
24018cfa0ad2SJack F Vogel 		goto out;
24028cfa0ad2SJack F Vogel 	}
24038cfa0ad2SJack F Vogel 
24048cfa0ad2SJack F Vogel 	/* Clear FCERR and DAEL in hw status by writing 1 */
24058cfa0ad2SJack F Vogel 	hsfsts.hsf_status.flcerr = 1;
24068cfa0ad2SJack F Vogel 	hsfsts.hsf_status.dael = 1;
24078cfa0ad2SJack F Vogel 
24088cfa0ad2SJack F Vogel 	E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
24098cfa0ad2SJack F Vogel 
24108cfa0ad2SJack F Vogel 	/*
24118cfa0ad2SJack F Vogel 	 * Either we should have a hardware SPI cycle in progress
24128cfa0ad2SJack F Vogel 	 * bit to check against, in order to start a new cycle or
24138cfa0ad2SJack F Vogel 	 * FDONE bit should be changed in the hardware so that it
24148cfa0ad2SJack F Vogel 	 * is 1 after hardware reset, which can then be used as an
24158cfa0ad2SJack F Vogel 	 * indication whether a cycle is in progress or has been
24168cfa0ad2SJack F Vogel 	 * completed.
24178cfa0ad2SJack F Vogel 	 */
24188cfa0ad2SJack F Vogel 
24198cfa0ad2SJack F Vogel 	if (hsfsts.hsf_status.flcinprog == 0) {
24208cfa0ad2SJack F Vogel 		/*
24218cfa0ad2SJack F Vogel 		 * There is no cycle running at present,
24228cfa0ad2SJack F Vogel 		 * so we can start a cycle.
24238cfa0ad2SJack F Vogel 		 * Begin by setting Flash Cycle Done.
24248cfa0ad2SJack F Vogel 		 */
24258cfa0ad2SJack F Vogel 		hsfsts.hsf_status.flcdone = 1;
24268cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
24278cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
24288cfa0ad2SJack F Vogel 	} else {
2429730d3130SJack F Vogel 		s32 i;
2430730d3130SJack F Vogel 
24318cfa0ad2SJack F Vogel 		/*
24328cfa0ad2SJack F Vogel 		 * Otherwise poll for sometime so the current
24338cfa0ad2SJack F Vogel 		 * cycle has a chance to end before giving up.
24348cfa0ad2SJack F Vogel 		 */
24358cfa0ad2SJack F Vogel 		for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
24368cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
24378cfa0ad2SJack F Vogel 							      ICH_FLASH_HSFSTS);
24388cfa0ad2SJack F Vogel 			if (hsfsts.hsf_status.flcinprog == 0) {
24398cfa0ad2SJack F Vogel 				ret_val = E1000_SUCCESS;
24408cfa0ad2SJack F Vogel 				break;
24418cfa0ad2SJack F Vogel 			}
24428cfa0ad2SJack F Vogel 			usec_delay(1);
24438cfa0ad2SJack F Vogel 		}
24448cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS) {
24458cfa0ad2SJack F Vogel 			/*
24468cfa0ad2SJack F Vogel 			 * Successful in waiting for previous cycle to timeout,
24478cfa0ad2SJack F Vogel 			 * now set the Flash Cycle Done.
24488cfa0ad2SJack F Vogel 			 */
24498cfa0ad2SJack F Vogel 			hsfsts.hsf_status.flcdone = 1;
2450daf9197cSJack F Vogel 			E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
24518cfa0ad2SJack F Vogel 						hsfsts.regval);
24528cfa0ad2SJack F Vogel 		} else {
2453*4dab5c37SJack F Vogel 			DEBUGOUT("Flash controller busy, cannot get access\n");
24548cfa0ad2SJack F Vogel 		}
24558cfa0ad2SJack F Vogel 	}
24568cfa0ad2SJack F Vogel 
24578cfa0ad2SJack F Vogel out:
24588cfa0ad2SJack F Vogel 	return ret_val;
24598cfa0ad2SJack F Vogel }
24608cfa0ad2SJack F Vogel 
24618cfa0ad2SJack F Vogel /**
24628cfa0ad2SJack F Vogel  *  e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
24638cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
24648cfa0ad2SJack F Vogel  *  @timeout: maximum time to wait for completion
24658cfa0ad2SJack F Vogel  *
24668cfa0ad2SJack F Vogel  *  This function starts a flash cycle and waits for its completion.
24678cfa0ad2SJack F Vogel  **/
24688cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
24698cfa0ad2SJack F Vogel {
24708cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
24718cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
24728cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
24738cfa0ad2SJack F Vogel 	u32 i = 0;
24748cfa0ad2SJack F Vogel 
24758cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_flash_cycle_ich8lan");
24768cfa0ad2SJack F Vogel 
24778cfa0ad2SJack F Vogel 	/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
24788cfa0ad2SJack F Vogel 	hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
24798cfa0ad2SJack F Vogel 	hsflctl.hsf_ctrl.flcgo = 1;
24808cfa0ad2SJack F Vogel 	E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
24818cfa0ad2SJack F Vogel 
24828cfa0ad2SJack F Vogel 	/* wait till FDONE bit is set to 1 */
24838cfa0ad2SJack F Vogel 	do {
24848cfa0ad2SJack F Vogel 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
24858cfa0ad2SJack F Vogel 		if (hsfsts.hsf_status.flcdone == 1)
24868cfa0ad2SJack F Vogel 			break;
24878cfa0ad2SJack F Vogel 		usec_delay(1);
24888cfa0ad2SJack F Vogel 	} while (i++ < timeout);
24898cfa0ad2SJack F Vogel 
24908cfa0ad2SJack F Vogel 	if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
24918cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
24928cfa0ad2SJack F Vogel 
24938cfa0ad2SJack F Vogel 	return ret_val;
24948cfa0ad2SJack F Vogel }
24958cfa0ad2SJack F Vogel 
24968cfa0ad2SJack F Vogel /**
24978cfa0ad2SJack F Vogel  *  e1000_read_flash_word_ich8lan - Read word from flash
24988cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
24998cfa0ad2SJack F Vogel  *  @offset: offset to data location
25008cfa0ad2SJack F Vogel  *  @data: pointer to the location for storing the data
25018cfa0ad2SJack F Vogel  *
25028cfa0ad2SJack F Vogel  *  Reads the flash word at offset into data.  Offset is converted
25038cfa0ad2SJack F Vogel  *  to bytes before read.
25048cfa0ad2SJack F Vogel  **/
25058cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
25068cfa0ad2SJack F Vogel 					 u16 *data)
25078cfa0ad2SJack F Vogel {
25088cfa0ad2SJack F Vogel 	s32 ret_val;
25098cfa0ad2SJack F Vogel 
25108cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_flash_word_ich8lan");
25118cfa0ad2SJack F Vogel 
25128cfa0ad2SJack F Vogel 	if (!data) {
25138cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
25148cfa0ad2SJack F Vogel 		goto out;
25158cfa0ad2SJack F Vogel 	}
25168cfa0ad2SJack F Vogel 
25178cfa0ad2SJack F Vogel 	/* Must convert offset into bytes. */
25188cfa0ad2SJack F Vogel 	offset <<= 1;
25198cfa0ad2SJack F Vogel 
25208cfa0ad2SJack F Vogel 	ret_val = e1000_read_flash_data_ich8lan(hw, offset, 2, data);
25218cfa0ad2SJack F Vogel 
25228cfa0ad2SJack F Vogel out:
25238cfa0ad2SJack F Vogel 	return ret_val;
25248cfa0ad2SJack F Vogel }
25258cfa0ad2SJack F Vogel 
25268cfa0ad2SJack F Vogel /**
25278cfa0ad2SJack F Vogel  *  e1000_read_flash_byte_ich8lan - Read byte from flash
25288cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
25298cfa0ad2SJack F Vogel  *  @offset: The offset of the byte to read.
25308cfa0ad2SJack F Vogel  *  @data: Pointer to a byte to store the value read.
25318cfa0ad2SJack F Vogel  *
25328cfa0ad2SJack F Vogel  *  Reads a single byte from the NVM using the flash access registers.
25338cfa0ad2SJack F Vogel  **/
25348cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
25358cfa0ad2SJack F Vogel 					 u8 *data)
25368cfa0ad2SJack F Vogel {
25378cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
25388cfa0ad2SJack F Vogel 	u16 word = 0;
25398cfa0ad2SJack F Vogel 
25408cfa0ad2SJack F Vogel 	ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
25418cfa0ad2SJack F Vogel 	if (ret_val)
25428cfa0ad2SJack F Vogel 		goto out;
25438cfa0ad2SJack F Vogel 
25448cfa0ad2SJack F Vogel 	*data = (u8)word;
25458cfa0ad2SJack F Vogel 
25468cfa0ad2SJack F Vogel out:
25478cfa0ad2SJack F Vogel 	return ret_val;
25488cfa0ad2SJack F Vogel }
25498cfa0ad2SJack F Vogel 
25508cfa0ad2SJack F Vogel /**
25518cfa0ad2SJack F Vogel  *  e1000_read_flash_data_ich8lan - Read byte or word from NVM
25528cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
25538cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the byte or word to read.
25548cfa0ad2SJack F Vogel  *  @size: Size of data to read, 1=byte 2=word
25558cfa0ad2SJack F Vogel  *  @data: Pointer to the word to store the value read.
25568cfa0ad2SJack F Vogel  *
25578cfa0ad2SJack F Vogel  *  Reads a byte or word from the NVM using the flash access registers.
25588cfa0ad2SJack F Vogel  **/
25598cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
25608cfa0ad2SJack F Vogel 					 u8 size, u16 *data)
25618cfa0ad2SJack F Vogel {
25628cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
25638cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
25648cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
25658cfa0ad2SJack F Vogel 	u32 flash_data = 0;
25668cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
25678cfa0ad2SJack F Vogel 	u8 count = 0;
25688cfa0ad2SJack F Vogel 
25698cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_flash_data_ich8lan");
25708cfa0ad2SJack F Vogel 
25718cfa0ad2SJack F Vogel 	if (size < 1  || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
25728cfa0ad2SJack F Vogel 		goto out;
25738cfa0ad2SJack F Vogel 
25748cfa0ad2SJack F Vogel 	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
25758cfa0ad2SJack F Vogel 			    hw->nvm.flash_base_addr;
25768cfa0ad2SJack F Vogel 
25778cfa0ad2SJack F Vogel 	do {
25788cfa0ad2SJack F Vogel 		usec_delay(1);
25798cfa0ad2SJack F Vogel 		/* Steps */
25808cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
25818cfa0ad2SJack F Vogel 		if (ret_val != E1000_SUCCESS)
25828cfa0ad2SJack F Vogel 			break;
25838cfa0ad2SJack F Vogel 
25848cfa0ad2SJack F Vogel 		hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
25858cfa0ad2SJack F Vogel 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
25868cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.fldbcount = size - 1;
25878cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
25888cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
25898cfa0ad2SJack F Vogel 
25908cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
25918cfa0ad2SJack F Vogel 
25928cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_ich8lan(hw,
25938cfa0ad2SJack F Vogel 						ICH_FLASH_READ_COMMAND_TIMEOUT);
25948cfa0ad2SJack F Vogel 
25958cfa0ad2SJack F Vogel 		/*
25968cfa0ad2SJack F Vogel 		 * Check if FCERR is set to 1, if set to 1, clear it
25978cfa0ad2SJack F Vogel 		 * and try the whole sequence a few more times, else
25988cfa0ad2SJack F Vogel 		 * read in (shift in) the Flash Data0, the order is
25998cfa0ad2SJack F Vogel 		 * least significant byte first msb to lsb
26008cfa0ad2SJack F Vogel 		 */
26018cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS) {
26028cfa0ad2SJack F Vogel 			flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
2603daf9197cSJack F Vogel 			if (size == 1)
26048cfa0ad2SJack F Vogel 				*data = (u8)(flash_data & 0x000000FF);
2605daf9197cSJack F Vogel 			else if (size == 2)
26068cfa0ad2SJack F Vogel 				*data = (u16)(flash_data & 0x0000FFFF);
26078cfa0ad2SJack F Vogel 			break;
26088cfa0ad2SJack F Vogel 		} else {
26098cfa0ad2SJack F Vogel 			/*
26108cfa0ad2SJack F Vogel 			 * If we've gotten here, then things are probably
26118cfa0ad2SJack F Vogel 			 * completely hosed, but if the error condition is
26128cfa0ad2SJack F Vogel 			 * detected, it won't hurt to give it another try...
26138cfa0ad2SJack F Vogel 			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
26148cfa0ad2SJack F Vogel 			 */
26158cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
26168cfa0ad2SJack F Vogel 							      ICH_FLASH_HSFSTS);
26178cfa0ad2SJack F Vogel 			if (hsfsts.hsf_status.flcerr == 1) {
26188cfa0ad2SJack F Vogel 				/* Repeat for some time before giving up. */
26198cfa0ad2SJack F Vogel 				continue;
26208cfa0ad2SJack F Vogel 			} else if (hsfsts.hsf_status.flcdone == 0) {
2621*4dab5c37SJack F Vogel 				DEBUGOUT("Timeout error - flash cycle did not complete.\n");
26228cfa0ad2SJack F Vogel 				break;
26238cfa0ad2SJack F Vogel 			}
26248cfa0ad2SJack F Vogel 		}
26258cfa0ad2SJack F Vogel 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
26268cfa0ad2SJack F Vogel 
26278cfa0ad2SJack F Vogel out:
26288cfa0ad2SJack F Vogel 	return ret_val;
26298cfa0ad2SJack F Vogel }
26308cfa0ad2SJack F Vogel 
26318cfa0ad2SJack F Vogel /**
26328cfa0ad2SJack F Vogel  *  e1000_write_nvm_ich8lan - Write word(s) to the NVM
26338cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
26348cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the word(s) to write.
26358cfa0ad2SJack F Vogel  *  @words: Size of data to write in words
26368cfa0ad2SJack F Vogel  *  @data: Pointer to the word(s) to write at offset.
26378cfa0ad2SJack F Vogel  *
26388cfa0ad2SJack F Vogel  *  Writes a byte or word to the NVM using the flash access registers.
26398cfa0ad2SJack F Vogel  **/
26408cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
26418cfa0ad2SJack F Vogel 				   u16 *data)
26428cfa0ad2SJack F Vogel {
26438cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
2644daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
26458cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
26468cfa0ad2SJack F Vogel 	u16 i;
26478cfa0ad2SJack F Vogel 
26488cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_nvm_ich8lan");
26498cfa0ad2SJack F Vogel 
26508cfa0ad2SJack F Vogel 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
26518cfa0ad2SJack F Vogel 	    (words == 0)) {
26528cfa0ad2SJack F Vogel 		DEBUGOUT("nvm parameter(s) out of bounds\n");
26538cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
26548cfa0ad2SJack F Vogel 		goto out;
26558cfa0ad2SJack F Vogel 	}
26568cfa0ad2SJack F Vogel 
26574edd8523SJack F Vogel 	nvm->ops.acquire(hw);
26588cfa0ad2SJack F Vogel 
26598cfa0ad2SJack F Vogel 	for (i = 0; i < words; i++) {
26608cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[offset+i].modified = TRUE;
26618cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[offset+i].value = data[i];
26628cfa0ad2SJack F Vogel 	}
26638cfa0ad2SJack F Vogel 
26648cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
26658cfa0ad2SJack F Vogel 
26668cfa0ad2SJack F Vogel out:
26678cfa0ad2SJack F Vogel 	return ret_val;
26688cfa0ad2SJack F Vogel }
26698cfa0ad2SJack F Vogel 
26708cfa0ad2SJack F Vogel /**
26718cfa0ad2SJack F Vogel  *  e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
26728cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
26738cfa0ad2SJack F Vogel  *
26748cfa0ad2SJack F Vogel  *  The NVM checksum is updated by calling the generic update_nvm_checksum,
26758cfa0ad2SJack F Vogel  *  which writes the checksum to the shadow ram.  The changes in the shadow
26768cfa0ad2SJack F Vogel  *  ram are then committed to the EEPROM by processing each bank at a time
26778cfa0ad2SJack F Vogel  *  checking for the modified bit and writing only the pending changes.
26788cfa0ad2SJack F Vogel  *  After a successful commit, the shadow ram is cleared and is ready for
26798cfa0ad2SJack F Vogel  *  future writes.
26808cfa0ad2SJack F Vogel  **/
26818cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
26828cfa0ad2SJack F Vogel {
26838cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
2684daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
26858cfa0ad2SJack F Vogel 	u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
26868cfa0ad2SJack F Vogel 	s32 ret_val;
26878cfa0ad2SJack F Vogel 	u16 data;
26888cfa0ad2SJack F Vogel 
26898cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_update_nvm_checksum_ich8lan");
26908cfa0ad2SJack F Vogel 
26918cfa0ad2SJack F Vogel 	ret_val = e1000_update_nvm_checksum_generic(hw);
26928cfa0ad2SJack F Vogel 	if (ret_val)
26938cfa0ad2SJack F Vogel 		goto out;
26948cfa0ad2SJack F Vogel 
26958cfa0ad2SJack F Vogel 	if (nvm->type != e1000_nvm_flash_sw)
26968cfa0ad2SJack F Vogel 		goto out;
26978cfa0ad2SJack F Vogel 
26984edd8523SJack F Vogel 	nvm->ops.acquire(hw);
26998cfa0ad2SJack F Vogel 
27008cfa0ad2SJack F Vogel 	/*
27018cfa0ad2SJack F Vogel 	 * We're writing to the opposite bank so if we're on bank 1,
27028cfa0ad2SJack F Vogel 	 * write to bank 0 etc.  We also need to erase the segment that
27038cfa0ad2SJack F Vogel 	 * is going to be written
27048cfa0ad2SJack F Vogel 	 */
27058cfa0ad2SJack F Vogel 	ret_val =  e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
2706d035aa2dSJack F Vogel 	if (ret_val != E1000_SUCCESS) {
27074edd8523SJack F Vogel 		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
27084edd8523SJack F Vogel 		bank = 0;
2709d035aa2dSJack F Vogel 	}
27108cfa0ad2SJack F Vogel 
27118cfa0ad2SJack F Vogel 	if (bank == 0) {
27128cfa0ad2SJack F Vogel 		new_bank_offset = nvm->flash_bank_size;
27138cfa0ad2SJack F Vogel 		old_bank_offset = 0;
2714d035aa2dSJack F Vogel 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
2715a69ed8dfSJack F Vogel 		if (ret_val)
2716a69ed8dfSJack F Vogel 			goto release;
27178cfa0ad2SJack F Vogel 	} else {
27188cfa0ad2SJack F Vogel 		old_bank_offset = nvm->flash_bank_size;
27198cfa0ad2SJack F Vogel 		new_bank_offset = 0;
2720d035aa2dSJack F Vogel 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
2721a69ed8dfSJack F Vogel 		if (ret_val)
2722a69ed8dfSJack F Vogel 			goto release;
27238cfa0ad2SJack F Vogel 	}
27248cfa0ad2SJack F Vogel 
27258cfa0ad2SJack F Vogel 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
27268cfa0ad2SJack F Vogel 		/*
27278cfa0ad2SJack F Vogel 		 * Determine whether to write the value stored
27288cfa0ad2SJack F Vogel 		 * in the other NVM bank or a modified value stored
27298cfa0ad2SJack F Vogel 		 * in the shadow RAM
27308cfa0ad2SJack F Vogel 		 */
27318cfa0ad2SJack F Vogel 		if (dev_spec->shadow_ram[i].modified) {
27328cfa0ad2SJack F Vogel 			data = dev_spec->shadow_ram[i].value;
27338cfa0ad2SJack F Vogel 		} else {
2734d035aa2dSJack F Vogel 			ret_val = e1000_read_flash_word_ich8lan(hw, i +
2735d035aa2dSJack F Vogel 								old_bank_offset,
27368cfa0ad2SJack F Vogel 								&data);
2737d035aa2dSJack F Vogel 			if (ret_val)
2738d035aa2dSJack F Vogel 				break;
27398cfa0ad2SJack F Vogel 		}
27408cfa0ad2SJack F Vogel 
27418cfa0ad2SJack F Vogel 		/*
27428cfa0ad2SJack F Vogel 		 * If the word is 0x13, then make sure the signature bits
27438cfa0ad2SJack F Vogel 		 * (15:14) are 11b until the commit has completed.
27448cfa0ad2SJack F Vogel 		 * This will allow us to write 10b which indicates the
27458cfa0ad2SJack F Vogel 		 * signature is valid.  We want to do this after the write
27468cfa0ad2SJack F Vogel 		 * has completed so that we don't mark the segment valid
27478cfa0ad2SJack F Vogel 		 * while the write is still in progress
27488cfa0ad2SJack F Vogel 		 */
27498cfa0ad2SJack F Vogel 		if (i == E1000_ICH_NVM_SIG_WORD)
27508cfa0ad2SJack F Vogel 			data |= E1000_ICH_NVM_SIG_MASK;
27518cfa0ad2SJack F Vogel 
27528cfa0ad2SJack F Vogel 		/* Convert offset to bytes. */
27538cfa0ad2SJack F Vogel 		act_offset = (i + new_bank_offset) << 1;
27548cfa0ad2SJack F Vogel 
27558cfa0ad2SJack F Vogel 		usec_delay(100);
27568cfa0ad2SJack F Vogel 		/* Write the bytes to the new bank. */
27578cfa0ad2SJack F Vogel 		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
27588cfa0ad2SJack F Vogel 							       act_offset,
27598cfa0ad2SJack F Vogel 							       (u8)data);
27608cfa0ad2SJack F Vogel 		if (ret_val)
27618cfa0ad2SJack F Vogel 			break;
27628cfa0ad2SJack F Vogel 
27638cfa0ad2SJack F Vogel 		usec_delay(100);
27648cfa0ad2SJack F Vogel 		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
27658cfa0ad2SJack F Vogel 							  act_offset + 1,
27668cfa0ad2SJack F Vogel 							  (u8)(data >> 8));
27678cfa0ad2SJack F Vogel 		if (ret_val)
27688cfa0ad2SJack F Vogel 			break;
27698cfa0ad2SJack F Vogel 	}
27708cfa0ad2SJack F Vogel 
27718cfa0ad2SJack F Vogel 	/*
27728cfa0ad2SJack F Vogel 	 * Don't bother writing the segment valid bits if sector
27738cfa0ad2SJack F Vogel 	 * programming failed.
27748cfa0ad2SJack F Vogel 	 */
27758cfa0ad2SJack F Vogel 	if (ret_val) {
27768cfa0ad2SJack F Vogel 		DEBUGOUT("Flash commit failed.\n");
2777a69ed8dfSJack F Vogel 		goto release;
27788cfa0ad2SJack F Vogel 	}
27798cfa0ad2SJack F Vogel 
27808cfa0ad2SJack F Vogel 	/*
27818cfa0ad2SJack F Vogel 	 * Finally validate the new segment by setting bit 15:14
27828cfa0ad2SJack F Vogel 	 * to 10b in word 0x13 , this can be done without an
27838cfa0ad2SJack F Vogel 	 * erase as well since these bits are 11 to start with
27848cfa0ad2SJack F Vogel 	 * and we need to change bit 14 to 0b
27858cfa0ad2SJack F Vogel 	 */
27868cfa0ad2SJack F Vogel 	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
2787d035aa2dSJack F Vogel 	ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
2788a69ed8dfSJack F Vogel 	if (ret_val)
2789a69ed8dfSJack F Vogel 		goto release;
27904edd8523SJack F Vogel 
27918cfa0ad2SJack F Vogel 	data &= 0xBFFF;
27928cfa0ad2SJack F Vogel 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
27938cfa0ad2SJack F Vogel 						       act_offset * 2 + 1,
27948cfa0ad2SJack F Vogel 						       (u8)(data >> 8));
2795a69ed8dfSJack F Vogel 	if (ret_val)
2796a69ed8dfSJack F Vogel 		goto release;
27978cfa0ad2SJack F Vogel 
27988cfa0ad2SJack F Vogel 	/*
27998cfa0ad2SJack F Vogel 	 * And invalidate the previously valid segment by setting
28008cfa0ad2SJack F Vogel 	 * its signature word (0x13) high_byte to 0b. This can be
28018cfa0ad2SJack F Vogel 	 * done without an erase because flash erase sets all bits
28028cfa0ad2SJack F Vogel 	 * to 1's. We can write 1's to 0's without an erase
28038cfa0ad2SJack F Vogel 	 */
28048cfa0ad2SJack F Vogel 	act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
28058cfa0ad2SJack F Vogel 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
2806a69ed8dfSJack F Vogel 	if (ret_val)
2807a69ed8dfSJack F Vogel 		goto release;
28088cfa0ad2SJack F Vogel 
28098cfa0ad2SJack F Vogel 	/* Great!  Everything worked, we can now clear the cached entries. */
28108cfa0ad2SJack F Vogel 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
28118cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].modified = FALSE;
28128cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].value = 0xFFFF;
28138cfa0ad2SJack F Vogel 	}
28148cfa0ad2SJack F Vogel 
2815a69ed8dfSJack F Vogel release:
28168cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
28178cfa0ad2SJack F Vogel 
28188cfa0ad2SJack F Vogel 	/*
28198cfa0ad2SJack F Vogel 	 * Reload the EEPROM, or else modifications will not appear
28208cfa0ad2SJack F Vogel 	 * until after the next adapter reset.
28218cfa0ad2SJack F Vogel 	 */
2822a69ed8dfSJack F Vogel 	if (!ret_val) {
28238cfa0ad2SJack F Vogel 		nvm->ops.reload(hw);
28248cfa0ad2SJack F Vogel 		msec_delay(10);
2825a69ed8dfSJack F Vogel 	}
28268cfa0ad2SJack F Vogel 
28278cfa0ad2SJack F Vogel out:
2828d035aa2dSJack F Vogel 	if (ret_val)
2829d035aa2dSJack F Vogel 		DEBUGOUT1("NVM update error: %d\n", ret_val);
2830d035aa2dSJack F Vogel 
28318cfa0ad2SJack F Vogel 	return ret_val;
28328cfa0ad2SJack F Vogel }
28338cfa0ad2SJack F Vogel 
28348cfa0ad2SJack F Vogel /**
28358cfa0ad2SJack F Vogel  *  e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
28368cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
28378cfa0ad2SJack F Vogel  *
28388cfa0ad2SJack F Vogel  *  Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
2839daf9197cSJack F Vogel  *  If the bit is 0, that the EEPROM had been modified, but the checksum was not
2840daf9197cSJack F Vogel  *  calculated, in which case we need to calculate the checksum and set bit 6.
28418cfa0ad2SJack F Vogel  **/
28428cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
28438cfa0ad2SJack F Vogel {
28448cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
28458cfa0ad2SJack F Vogel 	u16 data;
28468cfa0ad2SJack F Vogel 
28478cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan");
28488cfa0ad2SJack F Vogel 
28498cfa0ad2SJack F Vogel 	/*
28508cfa0ad2SJack F Vogel 	 * Read 0x19 and check bit 6.  If this bit is 0, the checksum
28518cfa0ad2SJack F Vogel 	 * needs to be fixed.  This bit is an indication that the NVM
28528cfa0ad2SJack F Vogel 	 * was prepared by OEM software and did not calculate the
28538cfa0ad2SJack F Vogel 	 * checksum...a likely scenario.
28548cfa0ad2SJack F Vogel 	 */
28558cfa0ad2SJack F Vogel 	ret_val = hw->nvm.ops.read(hw, 0x19, 1, &data);
28568cfa0ad2SJack F Vogel 	if (ret_val)
28578cfa0ad2SJack F Vogel 		goto out;
28588cfa0ad2SJack F Vogel 
28598cfa0ad2SJack F Vogel 	if ((data & 0x40) == 0) {
28608cfa0ad2SJack F Vogel 		data |= 0x40;
28618cfa0ad2SJack F Vogel 		ret_val = hw->nvm.ops.write(hw, 0x19, 1, &data);
28628cfa0ad2SJack F Vogel 		if (ret_val)
28638cfa0ad2SJack F Vogel 			goto out;
28648cfa0ad2SJack F Vogel 		ret_val = hw->nvm.ops.update(hw);
28658cfa0ad2SJack F Vogel 		if (ret_val)
28668cfa0ad2SJack F Vogel 			goto out;
28678cfa0ad2SJack F Vogel 	}
28688cfa0ad2SJack F Vogel 
28698cfa0ad2SJack F Vogel 	ret_val = e1000_validate_nvm_checksum_generic(hw);
28708cfa0ad2SJack F Vogel 
28718cfa0ad2SJack F Vogel out:
28728cfa0ad2SJack F Vogel 	return ret_val;
28738cfa0ad2SJack F Vogel }
28748cfa0ad2SJack F Vogel 
28758cfa0ad2SJack F Vogel /**
28768cfa0ad2SJack F Vogel  *  e1000_write_flash_data_ich8lan - Writes bytes to the NVM
28778cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
28788cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the byte/word to read.
28798cfa0ad2SJack F Vogel  *  @size: Size of data to read, 1=byte 2=word
28808cfa0ad2SJack F Vogel  *  @data: The byte(s) to write to the NVM.
28818cfa0ad2SJack F Vogel  *
28828cfa0ad2SJack F Vogel  *  Writes one/two bytes to the NVM using the flash access registers.
28838cfa0ad2SJack F Vogel  **/
28848cfa0ad2SJack F Vogel static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
28858cfa0ad2SJack F Vogel 					  u8 size, u16 data)
28868cfa0ad2SJack F Vogel {
28878cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
28888cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
28898cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
28908cfa0ad2SJack F Vogel 	u32 flash_data = 0;
28918cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
28928cfa0ad2SJack F Vogel 	u8 count = 0;
28938cfa0ad2SJack F Vogel 
28948cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_ich8_data");
28958cfa0ad2SJack F Vogel 
28968cfa0ad2SJack F Vogel 	if (size < 1 || size > 2 || data > size * 0xff ||
28978cfa0ad2SJack F Vogel 	    offset > ICH_FLASH_LINEAR_ADDR_MASK)
28988cfa0ad2SJack F Vogel 		goto out;
28998cfa0ad2SJack F Vogel 
29008cfa0ad2SJack F Vogel 	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
29018cfa0ad2SJack F Vogel 			    hw->nvm.flash_base_addr;
29028cfa0ad2SJack F Vogel 
29038cfa0ad2SJack F Vogel 	do {
29048cfa0ad2SJack F Vogel 		usec_delay(1);
29058cfa0ad2SJack F Vogel 		/* Steps */
29068cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
29078cfa0ad2SJack F Vogel 		if (ret_val != E1000_SUCCESS)
29088cfa0ad2SJack F Vogel 			break;
29098cfa0ad2SJack F Vogel 
29108cfa0ad2SJack F Vogel 		hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
29118cfa0ad2SJack F Vogel 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
29128cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.fldbcount = size - 1;
29138cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
29148cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
29158cfa0ad2SJack F Vogel 
29168cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
29178cfa0ad2SJack F Vogel 
29188cfa0ad2SJack F Vogel 		if (size == 1)
29198cfa0ad2SJack F Vogel 			flash_data = (u32)data & 0x00FF;
29208cfa0ad2SJack F Vogel 		else
29218cfa0ad2SJack F Vogel 			flash_data = (u32)data;
29228cfa0ad2SJack F Vogel 
29238cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data);
29248cfa0ad2SJack F Vogel 
29258cfa0ad2SJack F Vogel 		/*
29268cfa0ad2SJack F Vogel 		 * check if FCERR is set to 1 , if set to 1, clear it
29278cfa0ad2SJack F Vogel 		 * and try the whole sequence a few more times else done
29288cfa0ad2SJack F Vogel 		 */
29298cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_ich8lan(hw,
29308cfa0ad2SJack F Vogel 					       ICH_FLASH_WRITE_COMMAND_TIMEOUT);
2931daf9197cSJack F Vogel 		if (ret_val == E1000_SUCCESS)
29328cfa0ad2SJack F Vogel 			break;
2933daf9197cSJack F Vogel 
29348cfa0ad2SJack F Vogel 		/*
29358cfa0ad2SJack F Vogel 		 * If we're here, then things are most likely
29368cfa0ad2SJack F Vogel 		 * completely hosed, but if the error condition
29378cfa0ad2SJack F Vogel 		 * is detected, it won't hurt to give it another
29388cfa0ad2SJack F Vogel 		 * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
29398cfa0ad2SJack F Vogel 		 */
2940daf9197cSJack F Vogel 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
29414edd8523SJack F Vogel 		if (hsfsts.hsf_status.flcerr == 1)
29428cfa0ad2SJack F Vogel 			/* Repeat for some time before giving up. */
29438cfa0ad2SJack F Vogel 			continue;
29444edd8523SJack F Vogel 		if (hsfsts.hsf_status.flcdone == 0) {
2945*4dab5c37SJack F Vogel 			DEBUGOUT("Timeout error - flash cycle did not complete.\n");
29468cfa0ad2SJack F Vogel 			break;
29478cfa0ad2SJack F Vogel 		}
29488cfa0ad2SJack F Vogel 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
29498cfa0ad2SJack F Vogel 
29508cfa0ad2SJack F Vogel out:
29518cfa0ad2SJack F Vogel 	return ret_val;
29528cfa0ad2SJack F Vogel }
29538cfa0ad2SJack F Vogel 
29548cfa0ad2SJack F Vogel /**
29558cfa0ad2SJack F Vogel  *  e1000_write_flash_byte_ich8lan - Write a single byte to NVM
29568cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
29578cfa0ad2SJack F Vogel  *  @offset: The index of the byte to read.
29588cfa0ad2SJack F Vogel  *  @data: The byte to write to the NVM.
29598cfa0ad2SJack F Vogel  *
29608cfa0ad2SJack F Vogel  *  Writes a single byte to the NVM using the flash access registers.
29618cfa0ad2SJack F Vogel  **/
29628cfa0ad2SJack F Vogel static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
29638cfa0ad2SJack F Vogel 					  u8 data)
29648cfa0ad2SJack F Vogel {
29658cfa0ad2SJack F Vogel 	u16 word = (u16)data;
29668cfa0ad2SJack F Vogel 
29678cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_flash_byte_ich8lan");
29688cfa0ad2SJack F Vogel 
29698cfa0ad2SJack F Vogel 	return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
29708cfa0ad2SJack F Vogel }
29718cfa0ad2SJack F Vogel 
29728cfa0ad2SJack F Vogel /**
29738cfa0ad2SJack F Vogel  *  e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
29748cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
29758cfa0ad2SJack F Vogel  *  @offset: The offset of the byte to write.
29768cfa0ad2SJack F Vogel  *  @byte: The byte to write to the NVM.
29778cfa0ad2SJack F Vogel  *
29788cfa0ad2SJack F Vogel  *  Writes a single byte to the NVM using the flash access registers.
29798cfa0ad2SJack F Vogel  *  Goes through a retry algorithm before giving up.
29808cfa0ad2SJack F Vogel  **/
29818cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
29828cfa0ad2SJack F Vogel 						u32 offset, u8 byte)
29838cfa0ad2SJack F Vogel {
29848cfa0ad2SJack F Vogel 	s32 ret_val;
29858cfa0ad2SJack F Vogel 	u16 program_retries;
29868cfa0ad2SJack F Vogel 
29878cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan");
29888cfa0ad2SJack F Vogel 
29898cfa0ad2SJack F Vogel 	ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
29908cfa0ad2SJack F Vogel 	if (ret_val == E1000_SUCCESS)
29918cfa0ad2SJack F Vogel 		goto out;
29928cfa0ad2SJack F Vogel 
29938cfa0ad2SJack F Vogel 	for (program_retries = 0; program_retries < 100; program_retries++) {
29948cfa0ad2SJack F Vogel 		DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset);
29958cfa0ad2SJack F Vogel 		usec_delay(100);
29968cfa0ad2SJack F Vogel 		ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
29978cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS)
29988cfa0ad2SJack F Vogel 			break;
29998cfa0ad2SJack F Vogel 	}
30008cfa0ad2SJack F Vogel 	if (program_retries == 100) {
30018cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
30028cfa0ad2SJack F Vogel 		goto out;
30038cfa0ad2SJack F Vogel 	}
30048cfa0ad2SJack F Vogel 
30058cfa0ad2SJack F Vogel out:
30068cfa0ad2SJack F Vogel 	return ret_val;
30078cfa0ad2SJack F Vogel }
30088cfa0ad2SJack F Vogel 
30098cfa0ad2SJack F Vogel /**
30108cfa0ad2SJack F Vogel  *  e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
30118cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
30128cfa0ad2SJack F Vogel  *  @bank: 0 for first bank, 1 for second bank, etc.
30138cfa0ad2SJack F Vogel  *
30148cfa0ad2SJack F Vogel  *  Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
30158cfa0ad2SJack F Vogel  *  bank N is 4096 * N + flash_reg_addr.
30168cfa0ad2SJack F Vogel  **/
30178cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
30188cfa0ad2SJack F Vogel {
30198cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
30208cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
30218cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
30228cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
30238cfa0ad2SJack F Vogel 	/* bank size is in 16bit words - adjust to bytes */
30248cfa0ad2SJack F Vogel 	u32 flash_bank_size = nvm->flash_bank_size * 2;
30258cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
30268cfa0ad2SJack F Vogel 	s32 count = 0;
30278cfa0ad2SJack F Vogel 	s32 j, iteration, sector_size;
30288cfa0ad2SJack F Vogel 
30298cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_erase_flash_bank_ich8lan");
30308cfa0ad2SJack F Vogel 
30318cfa0ad2SJack F Vogel 	hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
30328cfa0ad2SJack F Vogel 
30338cfa0ad2SJack F Vogel 	/*
30348cfa0ad2SJack F Vogel 	 * Determine HW Sector size: Read BERASE bits of hw flash status
30358cfa0ad2SJack F Vogel 	 * register
30368cfa0ad2SJack F Vogel 	 * 00: The Hw sector is 256 bytes, hence we need to erase 16
30378cfa0ad2SJack F Vogel 	 *     consecutive sectors.  The start index for the nth Hw sector
30388cfa0ad2SJack F Vogel 	 *     can be calculated as = bank * 4096 + n * 256
30398cfa0ad2SJack F Vogel 	 * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
30408cfa0ad2SJack F Vogel 	 *     The start index for the nth Hw sector can be calculated
30418cfa0ad2SJack F Vogel 	 *     as = bank * 4096
30428cfa0ad2SJack F Vogel 	 * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
30438cfa0ad2SJack F Vogel 	 *     (ich9 only, otherwise error condition)
30448cfa0ad2SJack F Vogel 	 * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
30458cfa0ad2SJack F Vogel 	 */
30468cfa0ad2SJack F Vogel 	switch (hsfsts.hsf_status.berasesz) {
30478cfa0ad2SJack F Vogel 	case 0:
30488cfa0ad2SJack F Vogel 		/* Hw sector size 256 */
30498cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_256;
30508cfa0ad2SJack F Vogel 		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
30518cfa0ad2SJack F Vogel 		break;
30528cfa0ad2SJack F Vogel 	case 1:
30538cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_4K;
30549d81738fSJack F Vogel 		iteration = 1;
30558cfa0ad2SJack F Vogel 		break;
30568cfa0ad2SJack F Vogel 	case 2:
30578cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_8K;
30588bd0025fSJack F Vogel 		iteration = 1;
30598cfa0ad2SJack F Vogel 		break;
30608cfa0ad2SJack F Vogel 	case 3:
30618cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_64K;
30629d81738fSJack F Vogel 		iteration = 1;
30638cfa0ad2SJack F Vogel 		break;
30648cfa0ad2SJack F Vogel 	default:
30658cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
30668cfa0ad2SJack F Vogel 		goto out;
30678cfa0ad2SJack F Vogel 	}
30688cfa0ad2SJack F Vogel 
30698cfa0ad2SJack F Vogel 	/* Start with the base address, then add the sector offset. */
30708cfa0ad2SJack F Vogel 	flash_linear_addr = hw->nvm.flash_base_addr;
30714edd8523SJack F Vogel 	flash_linear_addr += (bank) ? flash_bank_size : 0;
30728cfa0ad2SJack F Vogel 
30738cfa0ad2SJack F Vogel 	for (j = 0; j < iteration ; j++) {
30748cfa0ad2SJack F Vogel 		do {
30758cfa0ad2SJack F Vogel 			/* Steps */
30768cfa0ad2SJack F Vogel 			ret_val = e1000_flash_cycle_init_ich8lan(hw);
30778cfa0ad2SJack F Vogel 			if (ret_val)
30788cfa0ad2SJack F Vogel 				goto out;
30798cfa0ad2SJack F Vogel 
30808cfa0ad2SJack F Vogel 			/*
30818cfa0ad2SJack F Vogel 			 * Write a value 11 (block Erase) in Flash
30828cfa0ad2SJack F Vogel 			 * Cycle field in hw flash control
30838cfa0ad2SJack F Vogel 			 */
30848cfa0ad2SJack F Vogel 			hsflctl.regval = E1000_READ_FLASH_REG16(hw,
30858cfa0ad2SJack F Vogel 							      ICH_FLASH_HSFCTL);
30868cfa0ad2SJack F Vogel 			hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
3087daf9197cSJack F Vogel 			E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
30888cfa0ad2SJack F Vogel 						hsflctl.regval);
30898cfa0ad2SJack F Vogel 
30908cfa0ad2SJack F Vogel 			/*
30918cfa0ad2SJack F Vogel 			 * Write the last 24 bits of an index within the
30928cfa0ad2SJack F Vogel 			 * block into Flash Linear address field in Flash
30938cfa0ad2SJack F Vogel 			 * Address.
30948cfa0ad2SJack F Vogel 			 */
30958cfa0ad2SJack F Vogel 			flash_linear_addr += (j * sector_size);
3096daf9197cSJack F Vogel 			E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR,
30978cfa0ad2SJack F Vogel 					      flash_linear_addr);
30988cfa0ad2SJack F Vogel 
30998cfa0ad2SJack F Vogel 			ret_val = e1000_flash_cycle_ich8lan(hw,
31008cfa0ad2SJack F Vogel 					       ICH_FLASH_ERASE_COMMAND_TIMEOUT);
3101daf9197cSJack F Vogel 			if (ret_val == E1000_SUCCESS)
31028cfa0ad2SJack F Vogel 				break;
3103daf9197cSJack F Vogel 
31048cfa0ad2SJack F Vogel 			/*
31058cfa0ad2SJack F Vogel 			 * Check if FCERR is set to 1.  If 1,
31068cfa0ad2SJack F Vogel 			 * clear it and try the whole sequence
31078cfa0ad2SJack F Vogel 			 * a few more times else Done
31088cfa0ad2SJack F Vogel 			 */
31098cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
31108cfa0ad2SJack F Vogel 						      ICH_FLASH_HSFSTS);
3111daf9197cSJack F Vogel 			if (hsfsts.hsf_status.flcerr == 1)
3112daf9197cSJack F Vogel 				/* repeat for some time before giving up */
31138cfa0ad2SJack F Vogel 				continue;
3114daf9197cSJack F Vogel 			else if (hsfsts.hsf_status.flcdone == 0)
31158cfa0ad2SJack F Vogel 				goto out;
31168cfa0ad2SJack F Vogel 		} while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
31178cfa0ad2SJack F Vogel 	}
31188cfa0ad2SJack F Vogel 
31198cfa0ad2SJack F Vogel out:
31208cfa0ad2SJack F Vogel 	return ret_val;
31218cfa0ad2SJack F Vogel }
31228cfa0ad2SJack F Vogel 
31238cfa0ad2SJack F Vogel /**
31248cfa0ad2SJack F Vogel  *  e1000_valid_led_default_ich8lan - Set the default LED settings
31258cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
31268cfa0ad2SJack F Vogel  *  @data: Pointer to the LED settings
31278cfa0ad2SJack F Vogel  *
31288cfa0ad2SJack F Vogel  *  Reads the LED default settings from the NVM to data.  If the NVM LED
31298cfa0ad2SJack F Vogel  *  settings is all 0's or F's, set the LED default to a valid LED default
31308cfa0ad2SJack F Vogel  *  setting.
31318cfa0ad2SJack F Vogel  **/
31328cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
31338cfa0ad2SJack F Vogel {
31348cfa0ad2SJack F Vogel 	s32 ret_val;
31358cfa0ad2SJack F Vogel 
31368cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_valid_led_default_ich8lan");
31378cfa0ad2SJack F Vogel 
31388cfa0ad2SJack F Vogel 	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
31398cfa0ad2SJack F Vogel 	if (ret_val) {
31408cfa0ad2SJack F Vogel 		DEBUGOUT("NVM Read Error\n");
31418cfa0ad2SJack F Vogel 		goto out;
31428cfa0ad2SJack F Vogel 	}
31438cfa0ad2SJack F Vogel 
3144*4dab5c37SJack F Vogel 	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
31458cfa0ad2SJack F Vogel 		*data = ID_LED_DEFAULT_ICH8LAN;
31468cfa0ad2SJack F Vogel 
31478cfa0ad2SJack F Vogel out:
31488cfa0ad2SJack F Vogel 	return ret_val;
31498cfa0ad2SJack F Vogel }
31508cfa0ad2SJack F Vogel 
31518cfa0ad2SJack F Vogel /**
31529d81738fSJack F Vogel  *  e1000_id_led_init_pchlan - store LED configurations
31539d81738fSJack F Vogel  *  @hw: pointer to the HW structure
31549d81738fSJack F Vogel  *
31559d81738fSJack F Vogel  *  PCH does not control LEDs via the LEDCTL register, rather it uses
31569d81738fSJack F Vogel  *  the PHY LED configuration register.
31579d81738fSJack F Vogel  *
31589d81738fSJack F Vogel  *  PCH also does not have an "always on" or "always off" mode which
31599d81738fSJack F Vogel  *  complicates the ID feature.  Instead of using the "on" mode to indicate
31609d81738fSJack F Vogel  *  in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()),
31619d81738fSJack F Vogel  *  use "link_up" mode.  The LEDs will still ID on request if there is no
31629d81738fSJack F Vogel  *  link based on logic in e1000_led_[on|off]_pchlan().
31639d81738fSJack F Vogel  **/
31649d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw)
31659d81738fSJack F Vogel {
31669d81738fSJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
31679d81738fSJack F Vogel 	s32 ret_val;
31689d81738fSJack F Vogel 	const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
31699d81738fSJack F Vogel 	const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
31709d81738fSJack F Vogel 	u16 data, i, temp, shift;
31719d81738fSJack F Vogel 
31729d81738fSJack F Vogel 	DEBUGFUNC("e1000_id_led_init_pchlan");
31739d81738fSJack F Vogel 
31749d81738fSJack F Vogel 	/* Get default ID LED modes */
31759d81738fSJack F Vogel 	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
31769d81738fSJack F Vogel 	if (ret_val)
31779d81738fSJack F Vogel 		goto out;
31789d81738fSJack F Vogel 
31799d81738fSJack F Vogel 	mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
31809d81738fSJack F Vogel 	mac->ledctl_mode1 = mac->ledctl_default;
31819d81738fSJack F Vogel 	mac->ledctl_mode2 = mac->ledctl_default;
31829d81738fSJack F Vogel 
31839d81738fSJack F Vogel 	for (i = 0; i < 4; i++) {
31849d81738fSJack F Vogel 		temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
31859d81738fSJack F Vogel 		shift = (i * 5);
31869d81738fSJack F Vogel 		switch (temp) {
31879d81738fSJack F Vogel 		case ID_LED_ON1_DEF2:
31889d81738fSJack F Vogel 		case ID_LED_ON1_ON2:
31899d81738fSJack F Vogel 		case ID_LED_ON1_OFF2:
31909d81738fSJack F Vogel 			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
31919d81738fSJack F Vogel 			mac->ledctl_mode1 |= (ledctl_on << shift);
31929d81738fSJack F Vogel 			break;
31939d81738fSJack F Vogel 		case ID_LED_OFF1_DEF2:
31949d81738fSJack F Vogel 		case ID_LED_OFF1_ON2:
31959d81738fSJack F Vogel 		case ID_LED_OFF1_OFF2:
31969d81738fSJack F Vogel 			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
31979d81738fSJack F Vogel 			mac->ledctl_mode1 |= (ledctl_off << shift);
31989d81738fSJack F Vogel 			break;
31999d81738fSJack F Vogel 		default:
32009d81738fSJack F Vogel 			/* Do nothing */
32019d81738fSJack F Vogel 			break;
32029d81738fSJack F Vogel 		}
32039d81738fSJack F Vogel 		switch (temp) {
32049d81738fSJack F Vogel 		case ID_LED_DEF1_ON2:
32059d81738fSJack F Vogel 		case ID_LED_ON1_ON2:
32069d81738fSJack F Vogel 		case ID_LED_OFF1_ON2:
32079d81738fSJack F Vogel 			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
32089d81738fSJack F Vogel 			mac->ledctl_mode2 |= (ledctl_on << shift);
32099d81738fSJack F Vogel 			break;
32109d81738fSJack F Vogel 		case ID_LED_DEF1_OFF2:
32119d81738fSJack F Vogel 		case ID_LED_ON1_OFF2:
32129d81738fSJack F Vogel 		case ID_LED_OFF1_OFF2:
32139d81738fSJack F Vogel 			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
32149d81738fSJack F Vogel 			mac->ledctl_mode2 |= (ledctl_off << shift);
32159d81738fSJack F Vogel 			break;
32169d81738fSJack F Vogel 		default:
32179d81738fSJack F Vogel 			/* Do nothing */
32189d81738fSJack F Vogel 			break;
32199d81738fSJack F Vogel 		}
32209d81738fSJack F Vogel 	}
32219d81738fSJack F Vogel 
32229d81738fSJack F Vogel out:
32239d81738fSJack F Vogel 	return ret_val;
32249d81738fSJack F Vogel }
32259d81738fSJack F Vogel 
32269d81738fSJack F Vogel /**
32278cfa0ad2SJack F Vogel  *  e1000_get_bus_info_ich8lan - Get/Set the bus type and width
32288cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
32298cfa0ad2SJack F Vogel  *
32308cfa0ad2SJack F Vogel  *  ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
3231*4dab5c37SJack F Vogel  *  register, so the the bus width is hard coded.
32328cfa0ad2SJack F Vogel  **/
32338cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
32348cfa0ad2SJack F Vogel {
32358cfa0ad2SJack F Vogel 	struct e1000_bus_info *bus = &hw->bus;
32368cfa0ad2SJack F Vogel 	s32 ret_val;
32378cfa0ad2SJack F Vogel 
32388cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_bus_info_ich8lan");
32398cfa0ad2SJack F Vogel 
32408cfa0ad2SJack F Vogel 	ret_val = e1000_get_bus_info_pcie_generic(hw);
32418cfa0ad2SJack F Vogel 
32428cfa0ad2SJack F Vogel 	/*
32438cfa0ad2SJack F Vogel 	 * ICH devices are "PCI Express"-ish.  They have
32448cfa0ad2SJack F Vogel 	 * a configuration space, but do not contain
32458cfa0ad2SJack F Vogel 	 * PCI Express Capability registers, so bus width
32468cfa0ad2SJack F Vogel 	 * must be hardcoded.
32478cfa0ad2SJack F Vogel 	 */
32488cfa0ad2SJack F Vogel 	if (bus->width == e1000_bus_width_unknown)
32498cfa0ad2SJack F Vogel 		bus->width = e1000_bus_width_pcie_x1;
32508cfa0ad2SJack F Vogel 
32518cfa0ad2SJack F Vogel 	return ret_val;
32528cfa0ad2SJack F Vogel }
32538cfa0ad2SJack F Vogel 
32548cfa0ad2SJack F Vogel /**
32558cfa0ad2SJack F Vogel  *  e1000_reset_hw_ich8lan - Reset the hardware
32568cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
32578cfa0ad2SJack F Vogel  *
32588cfa0ad2SJack F Vogel  *  Does a full reset of the hardware which includes a reset of the PHY and
32598cfa0ad2SJack F Vogel  *  MAC.
32608cfa0ad2SJack F Vogel  **/
32618cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
32628cfa0ad2SJack F Vogel {
32634edd8523SJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
32644edd8523SJack F Vogel 	u16 reg;
3265730d3130SJack F Vogel 	u32 ctrl, kab;
32668cfa0ad2SJack F Vogel 	s32 ret_val;
32678cfa0ad2SJack F Vogel 
32688cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_reset_hw_ich8lan");
32698cfa0ad2SJack F Vogel 
32708cfa0ad2SJack F Vogel 	/*
32718cfa0ad2SJack F Vogel 	 * Prevent the PCI-E bus from sticking if there is no TLP connection
32728cfa0ad2SJack F Vogel 	 * on the last TLP read/write transaction when MAC is reset.
32738cfa0ad2SJack F Vogel 	 */
32748cfa0ad2SJack F Vogel 	ret_val = e1000_disable_pcie_master_generic(hw);
3275daf9197cSJack F Vogel 	if (ret_val)
32768cfa0ad2SJack F Vogel 		DEBUGOUT("PCI-E Master disable polling has failed.\n");
32778cfa0ad2SJack F Vogel 
32788cfa0ad2SJack F Vogel 	DEBUGOUT("Masking off all interrupts\n");
32798cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
32808cfa0ad2SJack F Vogel 
32818cfa0ad2SJack F Vogel 	/*
32828cfa0ad2SJack F Vogel 	 * Disable the Transmit and Receive units.  Then delay to allow
32838cfa0ad2SJack F Vogel 	 * any pending transactions to complete before we hit the MAC
32848cfa0ad2SJack F Vogel 	 * with the global reset.
32858cfa0ad2SJack F Vogel 	 */
32868cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RCTL, 0);
32878cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
32888cfa0ad2SJack F Vogel 	E1000_WRITE_FLUSH(hw);
32898cfa0ad2SJack F Vogel 
32908cfa0ad2SJack F Vogel 	msec_delay(10);
32918cfa0ad2SJack F Vogel 
32928cfa0ad2SJack F Vogel 	/* Workaround for ICH8 bit corruption issue in FIFO memory */
32938cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan) {
32948cfa0ad2SJack F Vogel 		/* Set Tx and Rx buffer allocation to 8k apiece. */
32958cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K);
32968cfa0ad2SJack F Vogel 		/* Set Packet Buffer Size to 16k. */
32978cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K);
32988cfa0ad2SJack F Vogel 	}
32998cfa0ad2SJack F Vogel 
33004edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan) {
33014edd8523SJack F Vogel 		/* Save the NVM K1 bit setting*/
33024edd8523SJack F Vogel 		ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, &reg);
33034edd8523SJack F Vogel 		if (ret_val)
33044edd8523SJack F Vogel 			return ret_val;
33054edd8523SJack F Vogel 
33064edd8523SJack F Vogel 		if (reg & E1000_NVM_K1_ENABLE)
33074edd8523SJack F Vogel 			dev_spec->nvm_k1_enabled = TRUE;
33084edd8523SJack F Vogel 		else
33094edd8523SJack F Vogel 			dev_spec->nvm_k1_enabled = FALSE;
33104edd8523SJack F Vogel 	}
33114edd8523SJack F Vogel 
33128cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
33138cfa0ad2SJack F Vogel 
33147d9119bdSJack F Vogel 	if (!hw->phy.ops.check_reset_block(hw)) {
33158cfa0ad2SJack F Vogel 		/*
33167d9119bdSJack F Vogel 		 * Full-chip reset requires MAC and PHY reset at the same
33178cfa0ad2SJack F Vogel 		 * time to make sure the interface between MAC and the
33188cfa0ad2SJack F Vogel 		 * external PHY is reset.
33198cfa0ad2SJack F Vogel 		 */
33208cfa0ad2SJack F Vogel 		ctrl |= E1000_CTRL_PHY_RST;
33217d9119bdSJack F Vogel 
33227d9119bdSJack F Vogel 		/*
33237d9119bdSJack F Vogel 		 * Gate automatic PHY configuration by hardware on
33247d9119bdSJack F Vogel 		 * non-managed 82579
33257d9119bdSJack F Vogel 		 */
33267d9119bdSJack F Vogel 		if ((hw->mac.type == e1000_pch2lan) &&
33277d9119bdSJack F Vogel 		    !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
33287d9119bdSJack F Vogel 			e1000_gate_hw_phy_config_ich8lan(hw, TRUE);
33298cfa0ad2SJack F Vogel 	}
33308cfa0ad2SJack F Vogel 	ret_val = e1000_acquire_swflag_ich8lan(hw);
3331daf9197cSJack F Vogel 	DEBUGOUT("Issuing a global reset to ich8lan\n");
33328cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST));
3333*4dab5c37SJack F Vogel 	/* cannot issue a flush here because it hangs the hardware */
33348cfa0ad2SJack F Vogel 	msec_delay(20);
33358cfa0ad2SJack F Vogel 
33369d81738fSJack F Vogel 	if (!ret_val)
3337*4dab5c37SJack F Vogel 		E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
33389d81738fSJack F Vogel 
33397d9119bdSJack F Vogel 	if (ctrl & E1000_CTRL_PHY_RST) {
33409d81738fSJack F Vogel 		ret_val = hw->phy.ops.get_cfg_done(hw);
33414edd8523SJack F Vogel 		if (ret_val)
33424edd8523SJack F Vogel 			goto out;
33434edd8523SJack F Vogel 
33447d9119bdSJack F Vogel 		ret_val = e1000_post_phy_reset_ich8lan(hw);
33454edd8523SJack F Vogel 		if (ret_val)
33464edd8523SJack F Vogel 			goto out;
33477d9119bdSJack F Vogel 	}
33487d9119bdSJack F Vogel 
33494edd8523SJack F Vogel 	/*
33504edd8523SJack F Vogel 	 * For PCH, this write will make sure that any noise
33514edd8523SJack F Vogel 	 * will be detected as a CRC error and be dropped rather than show up
33524edd8523SJack F Vogel 	 * as a bad packet to the DMA engine.
33534edd8523SJack F Vogel 	 */
33544edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan)
33554edd8523SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565);
33568cfa0ad2SJack F Vogel 
33578cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
3358730d3130SJack F Vogel 	E1000_READ_REG(hw, E1000_ICR);
33598cfa0ad2SJack F Vogel 
33608cfa0ad2SJack F Vogel 	kab = E1000_READ_REG(hw, E1000_KABGTXD);
33618cfa0ad2SJack F Vogel 	kab |= E1000_KABGTXD_BGSQLBIAS;
33628cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_KABGTXD, kab);
33638cfa0ad2SJack F Vogel 
33644edd8523SJack F Vogel out:
33658cfa0ad2SJack F Vogel 	return ret_val;
33668cfa0ad2SJack F Vogel }
33678cfa0ad2SJack F Vogel 
33688cfa0ad2SJack F Vogel /**
33698cfa0ad2SJack F Vogel  *  e1000_init_hw_ich8lan - Initialize the hardware
33708cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
33718cfa0ad2SJack F Vogel  *
33728cfa0ad2SJack F Vogel  *  Prepares the hardware for transmit and receive by doing the following:
33738cfa0ad2SJack F Vogel  *   - initialize hardware bits
33748cfa0ad2SJack F Vogel  *   - initialize LED identification
33758cfa0ad2SJack F Vogel  *   - setup receive address registers
33768cfa0ad2SJack F Vogel  *   - setup flow control
33778cfa0ad2SJack F Vogel  *   - setup transmit descriptors
33788cfa0ad2SJack F Vogel  *   - clear statistics
33798cfa0ad2SJack F Vogel  **/
33808cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
33818cfa0ad2SJack F Vogel {
33828cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
33838cfa0ad2SJack F Vogel 	u32 ctrl_ext, txdctl, snoop;
33848cfa0ad2SJack F Vogel 	s32 ret_val;
33858cfa0ad2SJack F Vogel 	u16 i;
33868cfa0ad2SJack F Vogel 
33878cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_hw_ich8lan");
33888cfa0ad2SJack F Vogel 
33898cfa0ad2SJack F Vogel 	e1000_initialize_hw_bits_ich8lan(hw);
33908cfa0ad2SJack F Vogel 
33918cfa0ad2SJack F Vogel 	/* Initialize identification LED */
3392d035aa2dSJack F Vogel 	ret_val = mac->ops.id_led_init(hw);
3393d035aa2dSJack F Vogel 	if (ret_val)
3394d035aa2dSJack F Vogel 		DEBUGOUT("Error initializing identification LED\n");
33954edd8523SJack F Vogel 		/* This is not fatal and we should not stop init due to this */
33968cfa0ad2SJack F Vogel 
33978cfa0ad2SJack F Vogel 	/* Setup the receive address. */
33988cfa0ad2SJack F Vogel 	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
33998cfa0ad2SJack F Vogel 
34008cfa0ad2SJack F Vogel 	/* Zero out the Multicast HASH table */
34018cfa0ad2SJack F Vogel 	DEBUGOUT("Zeroing the MTA\n");
34028cfa0ad2SJack F Vogel 	for (i = 0; i < mac->mta_reg_count; i++)
34038cfa0ad2SJack F Vogel 		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
34048cfa0ad2SJack F Vogel 
34059d81738fSJack F Vogel 	/*
34069d81738fSJack F Vogel 	 * The 82578 Rx buffer will stall if wakeup is enabled in host and
3407*4dab5c37SJack F Vogel 	 * the ME.  Disable wakeup by clearing the host wakeup bit.
34089d81738fSJack F Vogel 	 * Reset the phy after disabling host wakeup to reset the Rx buffer.
34099d81738fSJack F Vogel 	 */
34109d81738fSJack F Vogel 	if (hw->phy.type == e1000_phy_82578) {
3411*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, &i);
3412*4dab5c37SJack F Vogel 		i &= ~BM_WUC_HOST_WU_BIT;
3413*4dab5c37SJack F Vogel 		hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, i);
34149d81738fSJack F Vogel 		ret_val = e1000_phy_hw_reset_ich8lan(hw);
34159d81738fSJack F Vogel 		if (ret_val)
34169d81738fSJack F Vogel 			return ret_val;
34179d81738fSJack F Vogel 	}
34189d81738fSJack F Vogel 
34198cfa0ad2SJack F Vogel 	/* Setup link and flow control */
34208cfa0ad2SJack F Vogel 	ret_val = mac->ops.setup_link(hw);
34218cfa0ad2SJack F Vogel 
34228cfa0ad2SJack F Vogel 	/* Set the transmit descriptor write-back policy for both queues */
34238cfa0ad2SJack F Vogel 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
34248cfa0ad2SJack F Vogel 	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
34258cfa0ad2SJack F Vogel 		 E1000_TXDCTL_FULL_TX_DESC_WB;
34268cfa0ad2SJack F Vogel 	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
34278cfa0ad2SJack F Vogel 		 E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
34288cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
34298cfa0ad2SJack F Vogel 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1));
34308cfa0ad2SJack F Vogel 	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
34318cfa0ad2SJack F Vogel 		 E1000_TXDCTL_FULL_TX_DESC_WB;
34328cfa0ad2SJack F Vogel 	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
34338cfa0ad2SJack F Vogel 		 E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
34348cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl);
34358cfa0ad2SJack F Vogel 
34368cfa0ad2SJack F Vogel 	/*
34378cfa0ad2SJack F Vogel 	 * ICH8 has opposite polarity of no_snoop bits.
34388cfa0ad2SJack F Vogel 	 * By default, we should use snoop behavior.
34398cfa0ad2SJack F Vogel 	 */
34408cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
34418cfa0ad2SJack F Vogel 		snoop = PCIE_ICH8_SNOOP_ALL;
34428cfa0ad2SJack F Vogel 	else
34438cfa0ad2SJack F Vogel 		snoop = (u32) ~(PCIE_NO_SNOOP_ALL);
34448cfa0ad2SJack F Vogel 	e1000_set_pcie_no_snoop_generic(hw, snoop);
34458cfa0ad2SJack F Vogel 
34468cfa0ad2SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
34478cfa0ad2SJack F Vogel 	ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
34488cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
34498cfa0ad2SJack F Vogel 
34508cfa0ad2SJack F Vogel 	/*
34518cfa0ad2SJack F Vogel 	 * Clear all of the statistics registers (clear on read).  It is
34528cfa0ad2SJack F Vogel 	 * important that we do this after we have tried to establish link
34538cfa0ad2SJack F Vogel 	 * because the symbol error count will increment wildly if there
34548cfa0ad2SJack F Vogel 	 * is no link.
34558cfa0ad2SJack F Vogel 	 */
34568cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_ich8lan(hw);
34578cfa0ad2SJack F Vogel 
34588cfa0ad2SJack F Vogel 	return ret_val;
34598cfa0ad2SJack F Vogel }
34608cfa0ad2SJack F Vogel /**
34618cfa0ad2SJack F Vogel  *  e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
34628cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
34638cfa0ad2SJack F Vogel  *
34648cfa0ad2SJack F Vogel  *  Sets/Clears required hardware bits necessary for correctly setting up the
34658cfa0ad2SJack F Vogel  *  hardware for transmit and receive.
34668cfa0ad2SJack F Vogel  **/
34678cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
34688cfa0ad2SJack F Vogel {
34698cfa0ad2SJack F Vogel 	u32 reg;
34708cfa0ad2SJack F Vogel 
34718cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_initialize_hw_bits_ich8lan");
34728cfa0ad2SJack F Vogel 
34738cfa0ad2SJack F Vogel 	/* Extended Device Control */
34748cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
34758cfa0ad2SJack F Vogel 	reg |= (1 << 22);
34769d81738fSJack F Vogel 	/* Enable PHY low-power state when MAC is at D3 w/o WoL */
34779d81738fSJack F Vogel 	if (hw->mac.type >= e1000_pchlan)
34789d81738fSJack F Vogel 		reg |= E1000_CTRL_EXT_PHYPDEN;
34798cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
34808cfa0ad2SJack F Vogel 
34818cfa0ad2SJack F Vogel 	/* Transmit Descriptor Control 0 */
34828cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
34838cfa0ad2SJack F Vogel 	reg |= (1 << 22);
34848cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
34858cfa0ad2SJack F Vogel 
34868cfa0ad2SJack F Vogel 	/* Transmit Descriptor Control 1 */
34878cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
34888cfa0ad2SJack F Vogel 	reg |= (1 << 22);
34898cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
34908cfa0ad2SJack F Vogel 
34918cfa0ad2SJack F Vogel 	/* Transmit Arbitration Control 0 */
34928cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TARC(0));
34938cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan)
34948cfa0ad2SJack F Vogel 		reg |= (1 << 28) | (1 << 29);
34958cfa0ad2SJack F Vogel 	reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
34968cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TARC(0), reg);
34978cfa0ad2SJack F Vogel 
34988cfa0ad2SJack F Vogel 	/* Transmit Arbitration Control 1 */
34998cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TARC(1));
35008cfa0ad2SJack F Vogel 	if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
35018cfa0ad2SJack F Vogel 		reg &= ~(1 << 28);
35028cfa0ad2SJack F Vogel 	else
35038cfa0ad2SJack F Vogel 		reg |= (1 << 28);
35048cfa0ad2SJack F Vogel 	reg |= (1 << 24) | (1 << 26) | (1 << 30);
35058cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TARC(1), reg);
35068cfa0ad2SJack F Vogel 
35078cfa0ad2SJack F Vogel 	/* Device Status */
35088cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan) {
35098cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_STATUS);
35108cfa0ad2SJack F Vogel 		reg &= ~(1 << 31);
35118cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_STATUS, reg);
35128cfa0ad2SJack F Vogel 	}
35138cfa0ad2SJack F Vogel 
35148ec87fc5SJack F Vogel 	/*
35158ec87fc5SJack F Vogel 	 * work-around descriptor data corruption issue during nfs v2 udp
35168ec87fc5SJack F Vogel 	 * traffic, just disable the nfs filtering capability
35178ec87fc5SJack F Vogel 	 */
35188ec87fc5SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_RFCTL);
35198ec87fc5SJack F Vogel 	reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS);
35208ec87fc5SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RFCTL, reg);
35218ec87fc5SJack F Vogel 
35228cfa0ad2SJack F Vogel 	return;
35238cfa0ad2SJack F Vogel }
35248cfa0ad2SJack F Vogel 
35258cfa0ad2SJack F Vogel /**
35268cfa0ad2SJack F Vogel  *  e1000_setup_link_ich8lan - Setup flow control and link settings
35278cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
35288cfa0ad2SJack F Vogel  *
35298cfa0ad2SJack F Vogel  *  Determines which flow control settings to use, then configures flow
35308cfa0ad2SJack F Vogel  *  control.  Calls the appropriate media-specific link configuration
35318cfa0ad2SJack F Vogel  *  function.  Assuming the adapter has a valid link partner, a valid link
35328cfa0ad2SJack F Vogel  *  should be established.  Assumes the hardware has previously been reset
35338cfa0ad2SJack F Vogel  *  and the transmitter and receiver are not enabled.
35348cfa0ad2SJack F Vogel  **/
35358cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
35368cfa0ad2SJack F Vogel {
35378cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
35388cfa0ad2SJack F Vogel 
35398cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_link_ich8lan");
35408cfa0ad2SJack F Vogel 
35418cfa0ad2SJack F Vogel 	if (hw->phy.ops.check_reset_block(hw))
35428cfa0ad2SJack F Vogel 		goto out;
35438cfa0ad2SJack F Vogel 
35448cfa0ad2SJack F Vogel 	/*
35458cfa0ad2SJack F Vogel 	 * ICH parts do not have a word in the NVM to determine
35468cfa0ad2SJack F Vogel 	 * the default flow control setting, so we explicitly
35478cfa0ad2SJack F Vogel 	 * set it to full.
35488cfa0ad2SJack F Vogel 	 */
3549daf9197cSJack F Vogel 	if (hw->fc.requested_mode == e1000_fc_default)
3550daf9197cSJack F Vogel 		hw->fc.requested_mode = e1000_fc_full;
35518cfa0ad2SJack F Vogel 
3552daf9197cSJack F Vogel 	/*
3553daf9197cSJack F Vogel 	 * Save off the requested flow control mode for use later.  Depending
3554daf9197cSJack F Vogel 	 * on the link partner's capabilities, we may or may not use this mode.
3555daf9197cSJack F Vogel 	 */
3556daf9197cSJack F Vogel 	hw->fc.current_mode = hw->fc.requested_mode;
35578cfa0ad2SJack F Vogel 
3558daf9197cSJack F Vogel 	DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
3559daf9197cSJack F Vogel 		hw->fc.current_mode);
35608cfa0ad2SJack F Vogel 
35618cfa0ad2SJack F Vogel 	/* Continue to configure the copper link. */
35628cfa0ad2SJack F Vogel 	ret_val = hw->mac.ops.setup_physical_interface(hw);
35638cfa0ad2SJack F Vogel 	if (ret_val)
35648cfa0ad2SJack F Vogel 		goto out;
35658cfa0ad2SJack F Vogel 
35668cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
35679d81738fSJack F Vogel 	if ((hw->phy.type == e1000_phy_82578) ||
35687d9119bdSJack F Vogel 	    (hw->phy.type == e1000_phy_82579) ||
35699d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577)) {
35707d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_FCRTV_PCH, hw->fc.refresh_time);
35717d9119bdSJack F Vogel 
35729d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw,
35739d81738fSJack F Vogel 					     PHY_REG(BM_PORT_CTRL_PAGE, 27),
35749d81738fSJack F Vogel 					     hw->fc.pause_time);
35759d81738fSJack F Vogel 		if (ret_val)
35769d81738fSJack F Vogel 			goto out;
35779d81738fSJack F Vogel 	}
35788cfa0ad2SJack F Vogel 
35798cfa0ad2SJack F Vogel 	ret_val = e1000_set_fc_watermarks_generic(hw);
35808cfa0ad2SJack F Vogel 
35818cfa0ad2SJack F Vogel out:
35828cfa0ad2SJack F Vogel 	return ret_val;
35838cfa0ad2SJack F Vogel }
35848cfa0ad2SJack F Vogel 
35858cfa0ad2SJack F Vogel /**
35868cfa0ad2SJack F Vogel  *  e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
35878cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
35888cfa0ad2SJack F Vogel  *
35898cfa0ad2SJack F Vogel  *  Configures the kumeran interface to the PHY to wait the appropriate time
35908cfa0ad2SJack F Vogel  *  when polling the PHY, then call the generic setup_copper_link to finish
35918cfa0ad2SJack F Vogel  *  configuring the copper link.
35928cfa0ad2SJack F Vogel  **/
35938cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
35948cfa0ad2SJack F Vogel {
35958cfa0ad2SJack F Vogel 	u32 ctrl;
35968cfa0ad2SJack F Vogel 	s32 ret_val;
35978cfa0ad2SJack F Vogel 	u16 reg_data;
35988cfa0ad2SJack F Vogel 
35998cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_copper_link_ich8lan");
36008cfa0ad2SJack F Vogel 
36018cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
36028cfa0ad2SJack F Vogel 	ctrl |= E1000_CTRL_SLU;
36038cfa0ad2SJack F Vogel 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
36048cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
36058cfa0ad2SJack F Vogel 
36068cfa0ad2SJack F Vogel 	/*
36078cfa0ad2SJack F Vogel 	 * Set the mac to wait the maximum time between each iteration
36088cfa0ad2SJack F Vogel 	 * and increase the max iterations when polling the phy;
36098cfa0ad2SJack F Vogel 	 * this fixes erroneous timeouts at 10Mbps.
36108cfa0ad2SJack F Vogel 	 */
36114edd8523SJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_TIMEOUTS,
36128cfa0ad2SJack F Vogel 					       0xFFFF);
36138cfa0ad2SJack F Vogel 	if (ret_val)
36148cfa0ad2SJack F Vogel 		goto out;
36159d81738fSJack F Vogel 	ret_val = e1000_read_kmrn_reg_generic(hw,
36169d81738fSJack F Vogel 					      E1000_KMRNCTRLSTA_INBAND_PARAM,
36178cfa0ad2SJack F Vogel 					      &reg_data);
36188cfa0ad2SJack F Vogel 	if (ret_val)
36198cfa0ad2SJack F Vogel 		goto out;
36208cfa0ad2SJack F Vogel 	reg_data |= 0x3F;
36219d81738fSJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
36229d81738fSJack F Vogel 					       E1000_KMRNCTRLSTA_INBAND_PARAM,
36238cfa0ad2SJack F Vogel 					       reg_data);
36248cfa0ad2SJack F Vogel 	if (ret_val)
36258cfa0ad2SJack F Vogel 		goto out;
36268cfa0ad2SJack F Vogel 
3627d035aa2dSJack F Vogel 	switch (hw->phy.type) {
3628d035aa2dSJack F Vogel 	case e1000_phy_igp_3:
36298cfa0ad2SJack F Vogel 		ret_val = e1000_copper_link_setup_igp(hw);
36308cfa0ad2SJack F Vogel 		if (ret_val)
36318cfa0ad2SJack F Vogel 			goto out;
3632d035aa2dSJack F Vogel 		break;
3633d035aa2dSJack F Vogel 	case e1000_phy_bm:
36349d81738fSJack F Vogel 	case e1000_phy_82578:
36358cfa0ad2SJack F Vogel 		ret_val = e1000_copper_link_setup_m88(hw);
36368cfa0ad2SJack F Vogel 		if (ret_val)
36378cfa0ad2SJack F Vogel 			goto out;
3638d035aa2dSJack F Vogel 		break;
36399d81738fSJack F Vogel 	case e1000_phy_82577:
36407d9119bdSJack F Vogel 	case e1000_phy_82579:
36419d81738fSJack F Vogel 		ret_val = e1000_copper_link_setup_82577(hw);
36429d81738fSJack F Vogel 		if (ret_val)
36439d81738fSJack F Vogel 			goto out;
36449d81738fSJack F Vogel 		break;
3645d035aa2dSJack F Vogel 	case e1000_phy_ife:
36468cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL,
36478cfa0ad2SJack F Vogel 					       &reg_data);
36488cfa0ad2SJack F Vogel 		if (ret_val)
36498cfa0ad2SJack F Vogel 			goto out;
36508cfa0ad2SJack F Vogel 
36518cfa0ad2SJack F Vogel 		reg_data &= ~IFE_PMC_AUTO_MDIX;
36528cfa0ad2SJack F Vogel 
36538cfa0ad2SJack F Vogel 		switch (hw->phy.mdix) {
36548cfa0ad2SJack F Vogel 		case 1:
36558cfa0ad2SJack F Vogel 			reg_data &= ~IFE_PMC_FORCE_MDIX;
36568cfa0ad2SJack F Vogel 			break;
36578cfa0ad2SJack F Vogel 		case 2:
36588cfa0ad2SJack F Vogel 			reg_data |= IFE_PMC_FORCE_MDIX;
36598cfa0ad2SJack F Vogel 			break;
36608cfa0ad2SJack F Vogel 		case 0:
36618cfa0ad2SJack F Vogel 		default:
36628cfa0ad2SJack F Vogel 			reg_data |= IFE_PMC_AUTO_MDIX;
36638cfa0ad2SJack F Vogel 			break;
36648cfa0ad2SJack F Vogel 		}
36658cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL,
36668cfa0ad2SJack F Vogel 						reg_data);
36678cfa0ad2SJack F Vogel 		if (ret_val)
36688cfa0ad2SJack F Vogel 			goto out;
3669d035aa2dSJack F Vogel 		break;
3670d035aa2dSJack F Vogel 	default:
3671d035aa2dSJack F Vogel 		break;
36728cfa0ad2SJack F Vogel 	}
36738cfa0ad2SJack F Vogel 	ret_val = e1000_setup_copper_link_generic(hw);
36748cfa0ad2SJack F Vogel 
36758cfa0ad2SJack F Vogel out:
36768cfa0ad2SJack F Vogel 	return ret_val;
36778cfa0ad2SJack F Vogel }
36788cfa0ad2SJack F Vogel 
36798cfa0ad2SJack F Vogel /**
36808cfa0ad2SJack F Vogel  *  e1000_get_link_up_info_ich8lan - Get current link speed and duplex
36818cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
36828cfa0ad2SJack F Vogel  *  @speed: pointer to store current link speed
36838cfa0ad2SJack F Vogel  *  @duplex: pointer to store the current link duplex
36848cfa0ad2SJack F Vogel  *
36858cfa0ad2SJack F Vogel  *  Calls the generic get_speed_and_duplex to retrieve the current link
36868cfa0ad2SJack F Vogel  *  information and then calls the Kumeran lock loss workaround for links at
36878cfa0ad2SJack F Vogel  *  gigabit speeds.
36888cfa0ad2SJack F Vogel  **/
36898cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
36908cfa0ad2SJack F Vogel 					  u16 *duplex)
36918cfa0ad2SJack F Vogel {
36928cfa0ad2SJack F Vogel 	s32 ret_val;
36938cfa0ad2SJack F Vogel 
36948cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_link_up_info_ich8lan");
36958cfa0ad2SJack F Vogel 
36968cfa0ad2SJack F Vogel 	ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
36978cfa0ad2SJack F Vogel 	if (ret_val)
36988cfa0ad2SJack F Vogel 		goto out;
36998cfa0ad2SJack F Vogel 
37008cfa0ad2SJack F Vogel 	if ((hw->mac.type == e1000_ich8lan) &&
37018cfa0ad2SJack F Vogel 	    (hw->phy.type == e1000_phy_igp_3) &&
37028cfa0ad2SJack F Vogel 	    (*speed == SPEED_1000)) {
37038cfa0ad2SJack F Vogel 		ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
37048cfa0ad2SJack F Vogel 	}
37058cfa0ad2SJack F Vogel 
37068cfa0ad2SJack F Vogel out:
37078cfa0ad2SJack F Vogel 	return ret_val;
37088cfa0ad2SJack F Vogel }
37098cfa0ad2SJack F Vogel 
37108cfa0ad2SJack F Vogel /**
37118cfa0ad2SJack F Vogel  *  e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
37128cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
37138cfa0ad2SJack F Vogel  *
37148cfa0ad2SJack F Vogel  *  Work-around for 82566 Kumeran PCS lock loss:
37158cfa0ad2SJack F Vogel  *  On link status change (i.e. PCI reset, speed change) and link is up and
37168cfa0ad2SJack F Vogel  *  speed is gigabit-
37178cfa0ad2SJack F Vogel  *    0) if workaround is optionally disabled do nothing
37188cfa0ad2SJack F Vogel  *    1) wait 1ms for Kumeran link to come up
37198cfa0ad2SJack F Vogel  *    2) check Kumeran Diagnostic register PCS lock loss bit
37208cfa0ad2SJack F Vogel  *    3) if not set the link is locked (all is good), otherwise...
37218cfa0ad2SJack F Vogel  *    4) reset the PHY
37228cfa0ad2SJack F Vogel  *    5) repeat up to 10 times
37238cfa0ad2SJack F Vogel  *  Note: this is only called for IGP3 copper when speed is 1gb.
37248cfa0ad2SJack F Vogel  **/
37258cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
37268cfa0ad2SJack F Vogel {
3727daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
37288cfa0ad2SJack F Vogel 	u32 phy_ctrl;
37298cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
37308cfa0ad2SJack F Vogel 	u16 i, data;
37318cfa0ad2SJack F Vogel 	bool link;
37328cfa0ad2SJack F Vogel 
37338cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan");
37348cfa0ad2SJack F Vogel 
3735730d3130SJack F Vogel 	if (!dev_spec->kmrn_lock_loss_workaround_enabled)
37368cfa0ad2SJack F Vogel 		goto out;
37378cfa0ad2SJack F Vogel 
37388cfa0ad2SJack F Vogel 	/*
37398cfa0ad2SJack F Vogel 	 * Make sure link is up before proceeding.  If not just return.
37408cfa0ad2SJack F Vogel 	 * Attempting this while link is negotiating fouled up link
37418cfa0ad2SJack F Vogel 	 * stability
37428cfa0ad2SJack F Vogel 	 */
37438cfa0ad2SJack F Vogel 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
37448cfa0ad2SJack F Vogel 	if (!link) {
37458cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
37468cfa0ad2SJack F Vogel 		goto out;
37478cfa0ad2SJack F Vogel 	}
37488cfa0ad2SJack F Vogel 
37498cfa0ad2SJack F Vogel 	for (i = 0; i < 10; i++) {
37508cfa0ad2SJack F Vogel 		/* read once to clear */
37518cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
37528cfa0ad2SJack F Vogel 		if (ret_val)
37538cfa0ad2SJack F Vogel 			goto out;
37548cfa0ad2SJack F Vogel 		/* and again to get new status */
37558cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
37568cfa0ad2SJack F Vogel 		if (ret_val)
37578cfa0ad2SJack F Vogel 			goto out;
37588cfa0ad2SJack F Vogel 
37598cfa0ad2SJack F Vogel 		/* check for PCS lock */
37608cfa0ad2SJack F Vogel 		if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) {
37618cfa0ad2SJack F Vogel 			ret_val = E1000_SUCCESS;
37628cfa0ad2SJack F Vogel 			goto out;
37638cfa0ad2SJack F Vogel 		}
37648cfa0ad2SJack F Vogel 
37658cfa0ad2SJack F Vogel 		/* Issue PHY reset */
37668cfa0ad2SJack F Vogel 		hw->phy.ops.reset(hw);
37678cfa0ad2SJack F Vogel 		msec_delay_irq(5);
37688cfa0ad2SJack F Vogel 	}
37698cfa0ad2SJack F Vogel 	/* Disable GigE link negotiation */
37708cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
37718cfa0ad2SJack F Vogel 	phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
37728cfa0ad2SJack F Vogel 		     E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
37738cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
37748cfa0ad2SJack F Vogel 
37758cfa0ad2SJack F Vogel 	/*
37768cfa0ad2SJack F Vogel 	 * Call gig speed drop workaround on Gig disable before accessing
37778cfa0ad2SJack F Vogel 	 * any PHY registers
37788cfa0ad2SJack F Vogel 	 */
37798cfa0ad2SJack F Vogel 	e1000_gig_downshift_workaround_ich8lan(hw);
37808cfa0ad2SJack F Vogel 
37818cfa0ad2SJack F Vogel 	/* unable to acquire PCS lock */
37828cfa0ad2SJack F Vogel 	ret_val = -E1000_ERR_PHY;
37838cfa0ad2SJack F Vogel 
37848cfa0ad2SJack F Vogel out:
37858cfa0ad2SJack F Vogel 	return ret_val;
37868cfa0ad2SJack F Vogel }
37878cfa0ad2SJack F Vogel 
37888cfa0ad2SJack F Vogel /**
37898cfa0ad2SJack F Vogel  *  e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
37908cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
37918cfa0ad2SJack F Vogel  *  @state: boolean value used to set the current Kumeran workaround state
37928cfa0ad2SJack F Vogel  *
37938cfa0ad2SJack F Vogel  *  If ICH8, set the current Kumeran workaround state (enabled - TRUE
37948cfa0ad2SJack F Vogel  *  /disabled - FALSE).
37958cfa0ad2SJack F Vogel  **/
37968cfa0ad2SJack F Vogel void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
37978cfa0ad2SJack F Vogel 						 bool state)
37988cfa0ad2SJack F Vogel {
3799daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
38008cfa0ad2SJack F Vogel 
38018cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan");
38028cfa0ad2SJack F Vogel 
38038cfa0ad2SJack F Vogel 	if (hw->mac.type != e1000_ich8lan) {
38048cfa0ad2SJack F Vogel 		DEBUGOUT("Workaround applies to ICH8 only.\n");
3805daf9197cSJack F Vogel 		return;
38068cfa0ad2SJack F Vogel 	}
38078cfa0ad2SJack F Vogel 
38088cfa0ad2SJack F Vogel 	dev_spec->kmrn_lock_loss_workaround_enabled = state;
38098cfa0ad2SJack F Vogel 
38108cfa0ad2SJack F Vogel 	return;
38118cfa0ad2SJack F Vogel }
38128cfa0ad2SJack F Vogel 
38138cfa0ad2SJack F Vogel /**
38148cfa0ad2SJack F Vogel  *  e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
38158cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
38168cfa0ad2SJack F Vogel  *
38178cfa0ad2SJack F Vogel  *  Workaround for 82566 power-down on D3 entry:
38188cfa0ad2SJack F Vogel  *    1) disable gigabit link
38198cfa0ad2SJack F Vogel  *    2) write VR power-down enable
38208cfa0ad2SJack F Vogel  *    3) read it back
38218cfa0ad2SJack F Vogel  *  Continue if successful, else issue LCD reset and repeat
38228cfa0ad2SJack F Vogel  **/
38238cfa0ad2SJack F Vogel void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
38248cfa0ad2SJack F Vogel {
38258cfa0ad2SJack F Vogel 	u32 reg;
38268cfa0ad2SJack F Vogel 	u16 data;
38278cfa0ad2SJack F Vogel 	u8  retry = 0;
38288cfa0ad2SJack F Vogel 
38298cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan");
38308cfa0ad2SJack F Vogel 
38318cfa0ad2SJack F Vogel 	if (hw->phy.type != e1000_phy_igp_3)
38328cfa0ad2SJack F Vogel 		goto out;
38338cfa0ad2SJack F Vogel 
38348cfa0ad2SJack F Vogel 	/* Try the workaround twice (if needed) */
38358cfa0ad2SJack F Vogel 	do {
38368cfa0ad2SJack F Vogel 		/* Disable link */
38378cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
38388cfa0ad2SJack F Vogel 		reg |= (E1000_PHY_CTRL_GBE_DISABLE |
38398cfa0ad2SJack F Vogel 			E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
38408cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg);
38418cfa0ad2SJack F Vogel 
38428cfa0ad2SJack F Vogel 		/*
38438cfa0ad2SJack F Vogel 		 * Call gig speed drop workaround on Gig disable before
38448cfa0ad2SJack F Vogel 		 * accessing any PHY registers
38458cfa0ad2SJack F Vogel 		 */
38468cfa0ad2SJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
38478cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
38488cfa0ad2SJack F Vogel 
38498cfa0ad2SJack F Vogel 		/* Write VR power-down enable */
38508cfa0ad2SJack F Vogel 		hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
38518cfa0ad2SJack F Vogel 		data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
3852daf9197cSJack F Vogel 		hw->phy.ops.write_reg(hw, IGP3_VR_CTRL,
38538cfa0ad2SJack F Vogel 				      data | IGP3_VR_CTRL_MODE_SHUTDOWN);
38548cfa0ad2SJack F Vogel 
38558cfa0ad2SJack F Vogel 		/* Read it back and test */
38568cfa0ad2SJack F Vogel 		hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
38578cfa0ad2SJack F Vogel 		data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
38588cfa0ad2SJack F Vogel 		if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
38598cfa0ad2SJack F Vogel 			break;
38608cfa0ad2SJack F Vogel 
38618cfa0ad2SJack F Vogel 		/* Issue PHY reset and repeat at most one more time */
38628cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_CTRL);
38638cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST);
38648cfa0ad2SJack F Vogel 		retry++;
38658cfa0ad2SJack F Vogel 	} while (retry);
38668cfa0ad2SJack F Vogel 
38678cfa0ad2SJack F Vogel out:
38688cfa0ad2SJack F Vogel 	return;
38698cfa0ad2SJack F Vogel }
38708cfa0ad2SJack F Vogel 
38718cfa0ad2SJack F Vogel /**
38728cfa0ad2SJack F Vogel  *  e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working
38738cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
38748cfa0ad2SJack F Vogel  *
38758cfa0ad2SJack F Vogel  *  Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
38768cfa0ad2SJack F Vogel  *  LPLU, Gig disable, MDIC PHY reset):
38778cfa0ad2SJack F Vogel  *    1) Set Kumeran Near-end loopback
38788cfa0ad2SJack F Vogel  *    2) Clear Kumeran Near-end loopback
3879*4dab5c37SJack F Vogel  *  Should only be called for ICH8[m] devices with any 1G Phy.
38808cfa0ad2SJack F Vogel  **/
38818cfa0ad2SJack F Vogel void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
38828cfa0ad2SJack F Vogel {
38838cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
38848cfa0ad2SJack F Vogel 	u16 reg_data;
38858cfa0ad2SJack F Vogel 
38868cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan");
38878cfa0ad2SJack F Vogel 
38888cfa0ad2SJack F Vogel 	if ((hw->mac.type != e1000_ich8lan) ||
3889*4dab5c37SJack F Vogel 	    (hw->phy.type == e1000_phy_ife))
38908cfa0ad2SJack F Vogel 		goto out;
38918cfa0ad2SJack F Vogel 
38928cfa0ad2SJack F Vogel 	ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
38938cfa0ad2SJack F Vogel 					      &reg_data);
38948cfa0ad2SJack F Vogel 	if (ret_val)
38958cfa0ad2SJack F Vogel 		goto out;
38968cfa0ad2SJack F Vogel 	reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
38978cfa0ad2SJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
38988cfa0ad2SJack F Vogel 					       E1000_KMRNCTRLSTA_DIAG_OFFSET,
38998cfa0ad2SJack F Vogel 					       reg_data);
39008cfa0ad2SJack F Vogel 	if (ret_val)
39018cfa0ad2SJack F Vogel 		goto out;
39028cfa0ad2SJack F Vogel 	reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
39038cfa0ad2SJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
39048cfa0ad2SJack F Vogel 					       E1000_KMRNCTRLSTA_DIAG_OFFSET,
39058cfa0ad2SJack F Vogel 					       reg_data);
39068cfa0ad2SJack F Vogel out:
39078cfa0ad2SJack F Vogel 	return;
39088cfa0ad2SJack F Vogel }
39098cfa0ad2SJack F Vogel 
39108cfa0ad2SJack F Vogel /**
3911*4dab5c37SJack F Vogel  *  e1000_suspend_workarounds_ich8lan - workarounds needed during S0->Sx
39128cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
39138cfa0ad2SJack F Vogel  *
39148cfa0ad2SJack F Vogel  *  During S0 to Sx transition, it is possible the link remains at gig
39158cfa0ad2SJack F Vogel  *  instead of negotiating to a lower speed.  Before going to Sx, set
3916*4dab5c37SJack F Vogel  *  'Gig Disable' to force link speed negotiation to a lower speed based on
3917*4dab5c37SJack F Vogel  *  the LPLU setting in the NVM or custom setting.  For PCH and newer parts,
3918*4dab5c37SJack F Vogel  *  the OEM bits PHY register (LED, GbE disable and LPLU configurations) also
3919*4dab5c37SJack F Vogel  *  needs to be written.
39208cfa0ad2SJack F Vogel  **/
3921*4dab5c37SJack F Vogel void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
39228cfa0ad2SJack F Vogel {
39238cfa0ad2SJack F Vogel 	u32 phy_ctrl;
39247d9119bdSJack F Vogel 	s32 ret_val;
39258cfa0ad2SJack F Vogel 
3926*4dab5c37SJack F Vogel 	DEBUGFUNC("e1000_suspend_workarounds_ich8lan");
39277d9119bdSJack F Vogel 
39288cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
3929*4dab5c37SJack F Vogel 	phy_ctrl |= E1000_PHY_CTRL_GBE_DISABLE;
39308cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
3931*4dab5c37SJack F Vogel 	if (hw->mac.type == e1000_ich8lan)
3932*4dab5c37SJack F Vogel 		e1000_gig_downshift_workaround_ich8lan(hw);
39339d81738fSJack F Vogel 
39347d9119bdSJack F Vogel 	if (hw->mac.type >= e1000_pchlan) {
39357d9119bdSJack F Vogel 		e1000_oem_bits_config_ich8lan(hw, FALSE);
3936*4dab5c37SJack F Vogel 		e1000_phy_hw_reset_ich8lan(hw);
39377d9119bdSJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
39387d9119bdSJack F Vogel 		if (ret_val)
39397d9119bdSJack F Vogel 			return;
39407d9119bdSJack F Vogel 		e1000_write_smbus_addr(hw);
39417d9119bdSJack F Vogel 		hw->phy.ops.release(hw);
39428cfa0ad2SJack F Vogel 	}
39438cfa0ad2SJack F Vogel 
39448cfa0ad2SJack F Vogel 	return;
39458cfa0ad2SJack F Vogel }
39468cfa0ad2SJack F Vogel 
39478cfa0ad2SJack F Vogel /**
3948*4dab5c37SJack F Vogel  *  e1000_resume_workarounds_pchlan - workarounds needed during Sx->S0
3949*4dab5c37SJack F Vogel  *  @hw: pointer to the HW structure
3950*4dab5c37SJack F Vogel  *
3951*4dab5c37SJack F Vogel  *  During Sx to S0 transitions on non-managed devices or managed devices
3952*4dab5c37SJack F Vogel  *  on which PHY resets are not blocked, if the PHY registers cannot be
3953*4dab5c37SJack F Vogel  *  accessed properly by the s/w toggle the LANPHYPC value to power cycle
3954*4dab5c37SJack F Vogel  *  the PHY.
3955*4dab5c37SJack F Vogel  **/
3956*4dab5c37SJack F Vogel void e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
3957*4dab5c37SJack F Vogel {
3958*4dab5c37SJack F Vogel 	u16 phy_id1, phy_id2;
3959*4dab5c37SJack F Vogel 	s32 ret_val;
3960*4dab5c37SJack F Vogel 
3961*4dab5c37SJack F Vogel 	DEBUGFUNC("e1000_resume_workarounds_pchlan");
3962*4dab5c37SJack F Vogel 
3963*4dab5c37SJack F Vogel 	if ((hw->mac.type != e1000_pch2lan) ||
3964*4dab5c37SJack F Vogel 	    hw->phy.ops.check_reset_block(hw))
3965*4dab5c37SJack F Vogel 		return;
3966*4dab5c37SJack F Vogel 
3967*4dab5c37SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
3968*4dab5c37SJack F Vogel 	if (ret_val) {
3969*4dab5c37SJack F Vogel 		DEBUGOUT("Failed to acquire PHY semaphore in resume\n");
3970*4dab5c37SJack F Vogel 		return;
3971*4dab5c37SJack F Vogel 	}
3972*4dab5c37SJack F Vogel 
3973*4dab5c37SJack F Vogel 	/* Test access to the PHY registers by reading the ID regs */
3974*4dab5c37SJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID1, &phy_id1);
3975*4dab5c37SJack F Vogel 	if (ret_val)
3976*4dab5c37SJack F Vogel 		goto release;
3977*4dab5c37SJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID2, &phy_id2);
3978*4dab5c37SJack F Vogel 	if (ret_val)
3979*4dab5c37SJack F Vogel 		goto release;
3980*4dab5c37SJack F Vogel 
3981*4dab5c37SJack F Vogel 	if (hw->phy.id == ((u32)(phy_id1 << 16) |
3982*4dab5c37SJack F Vogel 			   (u32)(phy_id2 & PHY_REVISION_MASK)))
3983*4dab5c37SJack F Vogel 		goto release;
3984*4dab5c37SJack F Vogel 
3985*4dab5c37SJack F Vogel 	e1000_toggle_lanphypc_value_ich8lan(hw);
3986*4dab5c37SJack F Vogel 
3987*4dab5c37SJack F Vogel 	hw->phy.ops.release(hw);
3988*4dab5c37SJack F Vogel 	msec_delay(50);
3989*4dab5c37SJack F Vogel 	hw->phy.ops.reset(hw);
3990*4dab5c37SJack F Vogel 	msec_delay(50);
3991*4dab5c37SJack F Vogel 	return;
3992*4dab5c37SJack F Vogel 
3993*4dab5c37SJack F Vogel release:
3994*4dab5c37SJack F Vogel 	hw->phy.ops.release(hw);
3995*4dab5c37SJack F Vogel 
3996*4dab5c37SJack F Vogel 	return;
3997*4dab5c37SJack F Vogel }
3998*4dab5c37SJack F Vogel 
3999*4dab5c37SJack F Vogel /**
40008cfa0ad2SJack F Vogel  *  e1000_cleanup_led_ich8lan - Restore the default LED operation
40018cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
40028cfa0ad2SJack F Vogel  *
40038cfa0ad2SJack F Vogel  *  Return the LED back to the default configuration.
40048cfa0ad2SJack F Vogel  **/
40058cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
40068cfa0ad2SJack F Vogel {
40078cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_cleanup_led_ich8lan");
40088cfa0ad2SJack F Vogel 
40098cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
4010a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
40118cfa0ad2SJack F Vogel 					     0);
40128cfa0ad2SJack F Vogel 
4013a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
4014a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
40158cfa0ad2SJack F Vogel }
40168cfa0ad2SJack F Vogel 
40178cfa0ad2SJack F Vogel /**
40188cfa0ad2SJack F Vogel  *  e1000_led_on_ich8lan - Turn LEDs on
40198cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
40208cfa0ad2SJack F Vogel  *
40218cfa0ad2SJack F Vogel  *  Turn on the LEDs.
40228cfa0ad2SJack F Vogel  **/
40238cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw)
40248cfa0ad2SJack F Vogel {
40258cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_led_on_ich8lan");
40268cfa0ad2SJack F Vogel 
40278cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
4028a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
40298cfa0ad2SJack F Vogel 				(IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
40308cfa0ad2SJack F Vogel 
4031a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
4032a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
40338cfa0ad2SJack F Vogel }
40348cfa0ad2SJack F Vogel 
40358cfa0ad2SJack F Vogel /**
40368cfa0ad2SJack F Vogel  *  e1000_led_off_ich8lan - Turn LEDs off
40378cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
40388cfa0ad2SJack F Vogel  *
40398cfa0ad2SJack F Vogel  *  Turn off the LEDs.
40408cfa0ad2SJack F Vogel  **/
40418cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
40428cfa0ad2SJack F Vogel {
40438cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_led_off_ich8lan");
40448cfa0ad2SJack F Vogel 
40458cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
4046a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
40478cfa0ad2SJack F Vogel 			       (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
40488cfa0ad2SJack F Vogel 
4049a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
4050a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
40518cfa0ad2SJack F Vogel }
40528cfa0ad2SJack F Vogel 
40538cfa0ad2SJack F Vogel /**
40549d81738fSJack F Vogel  *  e1000_setup_led_pchlan - Configures SW controllable LED
40559d81738fSJack F Vogel  *  @hw: pointer to the HW structure
40569d81738fSJack F Vogel  *
40579d81738fSJack F Vogel  *  This prepares the SW controllable LED for use.
40589d81738fSJack F Vogel  **/
40599d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw)
40609d81738fSJack F Vogel {
40619d81738fSJack F Vogel 	DEBUGFUNC("e1000_setup_led_pchlan");
40629d81738fSJack F Vogel 
40639d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
40649d81738fSJack F Vogel 				     (u16)hw->mac.ledctl_mode1);
40659d81738fSJack F Vogel }
40669d81738fSJack F Vogel 
40679d81738fSJack F Vogel /**
40689d81738fSJack F Vogel  *  e1000_cleanup_led_pchlan - Restore the default LED operation
40699d81738fSJack F Vogel  *  @hw: pointer to the HW structure
40709d81738fSJack F Vogel  *
40719d81738fSJack F Vogel  *  Return the LED back to the default configuration.
40729d81738fSJack F Vogel  **/
40739d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw)
40749d81738fSJack F Vogel {
40759d81738fSJack F Vogel 	DEBUGFUNC("e1000_cleanup_led_pchlan");
40769d81738fSJack F Vogel 
40779d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
40789d81738fSJack F Vogel 				     (u16)hw->mac.ledctl_default);
40799d81738fSJack F Vogel }
40809d81738fSJack F Vogel 
40819d81738fSJack F Vogel /**
40829d81738fSJack F Vogel  *  e1000_led_on_pchlan - Turn LEDs on
40839d81738fSJack F Vogel  *  @hw: pointer to the HW structure
40849d81738fSJack F Vogel  *
40859d81738fSJack F Vogel  *  Turn on the LEDs.
40869d81738fSJack F Vogel  **/
40879d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw)
40889d81738fSJack F Vogel {
40899d81738fSJack F Vogel 	u16 data = (u16)hw->mac.ledctl_mode2;
40909d81738fSJack F Vogel 	u32 i, led;
40919d81738fSJack F Vogel 
40929d81738fSJack F Vogel 	DEBUGFUNC("e1000_led_on_pchlan");
40939d81738fSJack F Vogel 
40949d81738fSJack F Vogel 	/*
40959d81738fSJack F Vogel 	 * If no link, then turn LED on by setting the invert bit
40969d81738fSJack F Vogel 	 * for each LED that's mode is "link_up" in ledctl_mode2.
40979d81738fSJack F Vogel 	 */
40989d81738fSJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
40999d81738fSJack F Vogel 		for (i = 0; i < 3; i++) {
41009d81738fSJack F Vogel 			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
41019d81738fSJack F Vogel 			if ((led & E1000_PHY_LED0_MODE_MASK) !=
41029d81738fSJack F Vogel 			    E1000_LEDCTL_MODE_LINK_UP)
41039d81738fSJack F Vogel 				continue;
41049d81738fSJack F Vogel 			if (led & E1000_PHY_LED0_IVRT)
41059d81738fSJack F Vogel 				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
41069d81738fSJack F Vogel 			else
41079d81738fSJack F Vogel 				data |= (E1000_PHY_LED0_IVRT << (i * 5));
41089d81738fSJack F Vogel 		}
41099d81738fSJack F Vogel 	}
41109d81738fSJack F Vogel 
41119d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
41129d81738fSJack F Vogel }
41139d81738fSJack F Vogel 
41149d81738fSJack F Vogel /**
41159d81738fSJack F Vogel  *  e1000_led_off_pchlan - Turn LEDs off
41169d81738fSJack F Vogel  *  @hw: pointer to the HW structure
41179d81738fSJack F Vogel  *
41189d81738fSJack F Vogel  *  Turn off the LEDs.
41199d81738fSJack F Vogel  **/
41209d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw)
41219d81738fSJack F Vogel {
41229d81738fSJack F Vogel 	u16 data = (u16)hw->mac.ledctl_mode1;
41239d81738fSJack F Vogel 	u32 i, led;
41249d81738fSJack F Vogel 
41259d81738fSJack F Vogel 	DEBUGFUNC("e1000_led_off_pchlan");
41269d81738fSJack F Vogel 
41279d81738fSJack F Vogel 	/*
41289d81738fSJack F Vogel 	 * If no link, then turn LED off by clearing the invert bit
41299d81738fSJack F Vogel 	 * for each LED that's mode is "link_up" in ledctl_mode1.
41309d81738fSJack F Vogel 	 */
41319d81738fSJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
41329d81738fSJack F Vogel 		for (i = 0; i < 3; i++) {
41339d81738fSJack F Vogel 			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
41349d81738fSJack F Vogel 			if ((led & E1000_PHY_LED0_MODE_MASK) !=
41359d81738fSJack F Vogel 			    E1000_LEDCTL_MODE_LINK_UP)
41369d81738fSJack F Vogel 				continue;
41379d81738fSJack F Vogel 			if (led & E1000_PHY_LED0_IVRT)
41389d81738fSJack F Vogel 				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
41399d81738fSJack F Vogel 			else
41409d81738fSJack F Vogel 				data |= (E1000_PHY_LED0_IVRT << (i * 5));
41419d81738fSJack F Vogel 		}
41429d81738fSJack F Vogel 	}
41439d81738fSJack F Vogel 
41449d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
41459d81738fSJack F Vogel }
41469d81738fSJack F Vogel 
41479d81738fSJack F Vogel /**
41487d9119bdSJack F Vogel  *  e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset
41498cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
41508cfa0ad2SJack F Vogel  *
41517d9119bdSJack F Vogel  *  Read appropriate register for the config done bit for completion status
41527d9119bdSJack F Vogel  *  and configure the PHY through s/w for EEPROM-less parts.
41537d9119bdSJack F Vogel  *
41547d9119bdSJack F Vogel  *  NOTE: some silicon which is EEPROM-less will fail trying to read the
41557d9119bdSJack F Vogel  *  config done bit, so only an error is logged and continues.  If we were
41567d9119bdSJack F Vogel  *  to return with error, EEPROM-less silicon would not be able to be reset
41577d9119bdSJack F Vogel  *  or change link.
41588cfa0ad2SJack F Vogel  **/
41598cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
41608cfa0ad2SJack F Vogel {
41618cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
41628cfa0ad2SJack F Vogel 	u32 bank = 0;
41637d9119bdSJack F Vogel 	u32 status;
41648cfa0ad2SJack F Vogel 
41657d9119bdSJack F Vogel 	DEBUGFUNC("e1000_get_cfg_done_ich8lan");
41669d81738fSJack F Vogel 
41678cfa0ad2SJack F Vogel 	e1000_get_cfg_done_generic(hw);
41688cfa0ad2SJack F Vogel 
41697d9119bdSJack F Vogel 	/* Wait for indication from h/w that it has completed basic config */
41707d9119bdSJack F Vogel 	if (hw->mac.type >= e1000_ich10lan) {
41717d9119bdSJack F Vogel 		e1000_lan_init_done_ich8lan(hw);
41727d9119bdSJack F Vogel 	} else {
41737d9119bdSJack F Vogel 		ret_val = e1000_get_auto_rd_done_generic(hw);
41747d9119bdSJack F Vogel 		if (ret_val) {
41757d9119bdSJack F Vogel 			/*
41767d9119bdSJack F Vogel 			 * When auto config read does not complete, do not
41777d9119bdSJack F Vogel 			 * return with an error. This can happen in situations
41787d9119bdSJack F Vogel 			 * where there is no eeprom and prevents getting link.
41797d9119bdSJack F Vogel 			 */
41807d9119bdSJack F Vogel 			DEBUGOUT("Auto Read Done did not complete\n");
41817d9119bdSJack F Vogel 			ret_val = E1000_SUCCESS;
41827d9119bdSJack F Vogel 		}
41837d9119bdSJack F Vogel 	}
41847d9119bdSJack F Vogel 
41857d9119bdSJack F Vogel 	/* Clear PHY Reset Asserted bit */
41867d9119bdSJack F Vogel 	status = E1000_READ_REG(hw, E1000_STATUS);
41877d9119bdSJack F Vogel 	if (status & E1000_STATUS_PHYRA)
41887d9119bdSJack F Vogel 		E1000_WRITE_REG(hw, E1000_STATUS, status & ~E1000_STATUS_PHYRA);
41897d9119bdSJack F Vogel 	else
41907d9119bdSJack F Vogel 		DEBUGOUT("PHY Reset Asserted not set - needs delay\n");
41917d9119bdSJack F Vogel 
41928cfa0ad2SJack F Vogel 	/* If EEPROM is not marked present, init the IGP 3 PHY manually */
41934edd8523SJack F Vogel 	if (hw->mac.type <= e1000_ich9lan) {
41948cfa0ad2SJack F Vogel 		if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
41958cfa0ad2SJack F Vogel 		    (hw->phy.type == e1000_phy_igp_3)) {
41968cfa0ad2SJack F Vogel 			e1000_phy_init_script_igp3(hw);
41978cfa0ad2SJack F Vogel 		}
41988cfa0ad2SJack F Vogel 	} else {
41998cfa0ad2SJack F Vogel 		if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
4200daf9197cSJack F Vogel 			/* Maybe we should do a basic PHY config */
42018cfa0ad2SJack F Vogel 			DEBUGOUT("EEPROM not present\n");
42028cfa0ad2SJack F Vogel 			ret_val = -E1000_ERR_CONFIG;
42038cfa0ad2SJack F Vogel 		}
42048cfa0ad2SJack F Vogel 	}
42058cfa0ad2SJack F Vogel 
42068cfa0ad2SJack F Vogel 	return ret_val;
42078cfa0ad2SJack F Vogel }
42088cfa0ad2SJack F Vogel 
42098cfa0ad2SJack F Vogel /**
42108cfa0ad2SJack F Vogel  * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down
42118cfa0ad2SJack F Vogel  * @hw: pointer to the HW structure
42128cfa0ad2SJack F Vogel  *
42138cfa0ad2SJack F Vogel  * In the case of a PHY power down to save power, or to turn off link during a
42148cfa0ad2SJack F Vogel  * driver unload, or wake on lan is not enabled, remove the link.
42158cfa0ad2SJack F Vogel  **/
42168cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
42178cfa0ad2SJack F Vogel {
42188cfa0ad2SJack F Vogel 	/* If the management interface is not enabled, then power down */
4219daf9197cSJack F Vogel 	if (!(hw->mac.ops.check_mng_mode(hw) ||
4220daf9197cSJack F Vogel 	      hw->phy.ops.check_reset_block(hw)))
42218cfa0ad2SJack F Vogel 		e1000_power_down_phy_copper(hw);
42228cfa0ad2SJack F Vogel 
42238cfa0ad2SJack F Vogel 	return;
42248cfa0ad2SJack F Vogel }
42258cfa0ad2SJack F Vogel 
42268cfa0ad2SJack F Vogel /**
42278cfa0ad2SJack F Vogel  *  e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
42288cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
42298cfa0ad2SJack F Vogel  *
42308cfa0ad2SJack F Vogel  *  Clears hardware counters specific to the silicon family and calls
42318cfa0ad2SJack F Vogel  *  clear_hw_cntrs_generic to clear all general purpose counters.
42328cfa0ad2SJack F Vogel  **/
42338cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
42348cfa0ad2SJack F Vogel {
42359d81738fSJack F Vogel 	u16 phy_data;
4236*4dab5c37SJack F Vogel 	s32 ret_val;
42379d81738fSJack F Vogel 
42388cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan");
42398cfa0ad2SJack F Vogel 
42408cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_base_generic(hw);
42418cfa0ad2SJack F Vogel 
4242daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ALGNERRC);
4243daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_RXERRC);
4244daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TNCRS);
4245daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_CEXTERR);
4246daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTC);
4247daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTFC);
42488cfa0ad2SJack F Vogel 
4249daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPRC);
4250daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPDC);
4251daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPTC);
42528cfa0ad2SJack F Vogel 
4253daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_IAC);
4254daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ICRXOC);
42559d81738fSJack F Vogel 
42569d81738fSJack F Vogel 	/* Clear PHY statistics registers */
42579d81738fSJack F Vogel 	if ((hw->phy.type == e1000_phy_82578) ||
42587d9119bdSJack F Vogel 	    (hw->phy.type == e1000_phy_82579) ||
42599d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577)) {
4260*4dab5c37SJack F Vogel 		ret_val = hw->phy.ops.acquire(hw);
4261*4dab5c37SJack F Vogel 		if (ret_val)
4262*4dab5c37SJack F Vogel 			return;
4263*4dab5c37SJack F Vogel 		ret_val = hw->phy.ops.set_page(hw,
4264*4dab5c37SJack F Vogel 					       HV_STATS_PAGE << IGP_PAGE_SHIFT);
4265*4dab5c37SJack F Vogel 		if (ret_val)
4266*4dab5c37SJack F Vogel 			goto release;
4267*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_SCC_UPPER, &phy_data);
4268*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_SCC_LOWER, &phy_data);
4269*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_ECOL_UPPER, &phy_data);
4270*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_ECOL_LOWER, &phy_data);
4271*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_MCC_UPPER, &phy_data);
4272*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_MCC_LOWER, &phy_data);
4273*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_LATECOL_UPPER, &phy_data);
4274*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_LATECOL_LOWER, &phy_data);
4275*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_COLC_UPPER, &phy_data);
4276*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_COLC_LOWER, &phy_data);
4277*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_DC_UPPER, &phy_data);
4278*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_DC_LOWER, &phy_data);
4279*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_TNCRS_UPPER, &phy_data);
4280*4dab5c37SJack F Vogel 		hw->phy.ops.read_reg_page(hw, HV_TNCRS_LOWER, &phy_data);
4281*4dab5c37SJack F Vogel release:
4282*4dab5c37SJack F Vogel 		hw->phy.ops.release(hw);
42839d81738fSJack F Vogel 	}
42848cfa0ad2SJack F Vogel }
42858cfa0ad2SJack F Vogel 
4286