xref: /freebsd/sys/dev/e1000/e1000_ich8lan.c (revision 8ec87fc5149977b627672979fb2e593310e8bbae)
18cfa0ad2SJack F Vogel /******************************************************************************
28cfa0ad2SJack F Vogel 
3a69ed8dfSJack F Vogel   Copyright (c) 2001-2010, 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
618cfa0ad2SJack F Vogel  */
628cfa0ad2SJack F Vogel 
638cfa0ad2SJack F Vogel #include "e1000_api.h"
648cfa0ad2SJack F Vogel 
658cfa0ad2SJack F Vogel static s32  e1000_init_phy_params_ich8lan(struct e1000_hw *hw);
669d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw);
678cfa0ad2SJack F Vogel static s32  e1000_init_nvm_params_ich8lan(struct e1000_hw *hw);
688cfa0ad2SJack F Vogel static s32  e1000_init_mac_params_ich8lan(struct e1000_hw *hw);
698cfa0ad2SJack F Vogel static s32  e1000_acquire_swflag_ich8lan(struct e1000_hw *hw);
708cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw);
714edd8523SJack F Vogel static s32  e1000_acquire_nvm_ich8lan(struct e1000_hw *hw);
724edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw);
738cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
748cfa0ad2SJack F Vogel static s32  e1000_check_reset_block_ich8lan(struct e1000_hw *hw);
758cfa0ad2SJack F Vogel static s32  e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw);
764edd8523SJack F Vogel static s32  e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active);
778cfa0ad2SJack F Vogel static s32  e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
788cfa0ad2SJack F Vogel                                             bool active);
798cfa0ad2SJack F Vogel static s32  e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
808cfa0ad2SJack F Vogel                                             bool active);
818cfa0ad2SJack F Vogel static s32  e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
828cfa0ad2SJack F Vogel                                    u16 words, u16 *data);
838cfa0ad2SJack F Vogel static s32  e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
848cfa0ad2SJack F Vogel                                     u16 words, u16 *data);
858cfa0ad2SJack F Vogel static s32  e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw);
868cfa0ad2SJack F Vogel static s32  e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
878cfa0ad2SJack F Vogel static s32  e1000_valid_led_default_ich8lan(struct e1000_hw *hw,
888cfa0ad2SJack F Vogel                                             u16 *data);
899d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw);
908cfa0ad2SJack F Vogel static s32  e1000_get_bus_info_ich8lan(struct e1000_hw *hw);
918cfa0ad2SJack F Vogel static s32  e1000_reset_hw_ich8lan(struct e1000_hw *hw);
928cfa0ad2SJack F Vogel static s32  e1000_init_hw_ich8lan(struct e1000_hw *hw);
938cfa0ad2SJack F Vogel static s32  e1000_setup_link_ich8lan(struct e1000_hw *hw);
948cfa0ad2SJack F Vogel static s32  e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
958cfa0ad2SJack F Vogel static s32  e1000_get_link_up_info_ich8lan(struct e1000_hw *hw,
968cfa0ad2SJack F Vogel                                            u16 *speed, u16 *duplex);
978cfa0ad2SJack F Vogel static s32  e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
988cfa0ad2SJack F Vogel static s32  e1000_led_on_ich8lan(struct e1000_hw *hw);
998cfa0ad2SJack F Vogel static s32  e1000_led_off_ich8lan(struct e1000_hw *hw);
1004edd8523SJack F Vogel static s32  e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
1019d81738fSJack F Vogel static s32  e1000_setup_led_pchlan(struct e1000_hw *hw);
1029d81738fSJack F Vogel static s32  e1000_cleanup_led_pchlan(struct e1000_hw *hw);
1039d81738fSJack F Vogel static s32  e1000_led_on_pchlan(struct e1000_hw *hw);
1049d81738fSJack F Vogel static s32  e1000_led_off_pchlan(struct e1000_hw *hw);
1058cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
1068cfa0ad2SJack F Vogel static s32  e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
1078cfa0ad2SJack F Vogel static s32  e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout);
1088cfa0ad2SJack F Vogel static s32  e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw);
1098cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
1108cfa0ad2SJack F Vogel static s32  e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
1118cfa0ad2SJack F Vogel static s32  e1000_read_flash_byte_ich8lan(struct e1000_hw *hw,
1128cfa0ad2SJack F Vogel                                           u32 offset, u8 *data);
1138cfa0ad2SJack F Vogel static s32  e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
1148cfa0ad2SJack F Vogel                                           u8 size, u16 *data);
1158cfa0ad2SJack F Vogel static s32  e1000_read_flash_word_ich8lan(struct e1000_hw *hw,
1168cfa0ad2SJack F Vogel                                           u32 offset, u16 *data);
1178cfa0ad2SJack F Vogel static s32  e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
1188cfa0ad2SJack F Vogel                                                  u32 offset, u8 byte);
1198cfa0ad2SJack F Vogel static s32  e1000_write_flash_byte_ich8lan(struct e1000_hw *hw,
1208cfa0ad2SJack F Vogel                                            u32 offset, u8 data);
1218cfa0ad2SJack F Vogel static s32  e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
1228cfa0ad2SJack F Vogel                                            u8 size, u16 data);
1238cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
1248cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
1254edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw);
1264edd8523SJack F Vogel static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw);
1274edd8523SJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw);
128a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
1298cfa0ad2SJack F Vogel 
1308cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
1318cfa0ad2SJack F Vogel /* Offset 04h HSFSTS */
1328cfa0ad2SJack F Vogel union ich8_hws_flash_status {
1338cfa0ad2SJack F Vogel 	struct ich8_hsfsts {
1348cfa0ad2SJack F Vogel 		u16 flcdone    :1; /* bit 0 Flash Cycle Done */
1358cfa0ad2SJack F Vogel 		u16 flcerr     :1; /* bit 1 Flash Cycle Error */
1368cfa0ad2SJack F Vogel 		u16 dael       :1; /* bit 2 Direct Access error Log */
1378cfa0ad2SJack F Vogel 		u16 berasesz   :2; /* bit 4:3 Sector Erase Size */
1388cfa0ad2SJack F Vogel 		u16 flcinprog  :1; /* bit 5 flash cycle in Progress */
1398cfa0ad2SJack F Vogel 		u16 reserved1  :2; /* bit 13:6 Reserved */
1408cfa0ad2SJack F Vogel 		u16 reserved2  :6; /* bit 13:6 Reserved */
1418cfa0ad2SJack F Vogel 		u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */
1428cfa0ad2SJack F Vogel 		u16 flockdn    :1; /* bit 15 Flash Config Lock-Down */
1438cfa0ad2SJack F Vogel 	} hsf_status;
1448cfa0ad2SJack F Vogel 	u16 regval;
1458cfa0ad2SJack F Vogel };
1468cfa0ad2SJack F Vogel 
1478cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
1488cfa0ad2SJack F Vogel /* Offset 06h FLCTL */
1498cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl {
1508cfa0ad2SJack F Vogel 	struct ich8_hsflctl {
1518cfa0ad2SJack F Vogel 		u16 flcgo      :1;   /* 0 Flash Cycle Go */
1528cfa0ad2SJack F Vogel 		u16 flcycle    :2;   /* 2:1 Flash Cycle */
1538cfa0ad2SJack F Vogel 		u16 reserved   :5;   /* 7:3 Reserved  */
1548cfa0ad2SJack F Vogel 		u16 fldbcount  :2;   /* 9:8 Flash Data Byte Count */
1558cfa0ad2SJack F Vogel 		u16 flockdn    :6;   /* 15:10 Reserved */
1568cfa0ad2SJack F Vogel 	} hsf_ctrl;
1578cfa0ad2SJack F Vogel 	u16 regval;
1588cfa0ad2SJack F Vogel };
1598cfa0ad2SJack F Vogel 
1608cfa0ad2SJack F Vogel /* ICH Flash Region Access Permissions */
1618cfa0ad2SJack F Vogel union ich8_hws_flash_regacc {
1628cfa0ad2SJack F Vogel 	struct ich8_flracc {
1638cfa0ad2SJack F Vogel 		u32 grra      :8; /* 0:7 GbE region Read Access */
1648cfa0ad2SJack F Vogel 		u32 grwa      :8; /* 8:15 GbE region Write Access */
1658cfa0ad2SJack F Vogel 		u32 gmrag     :8; /* 23:16 GbE Master Read Access Grant */
1668cfa0ad2SJack F Vogel 		u32 gmwag     :8; /* 31:24 GbE Master Write Access Grant */
1678cfa0ad2SJack F Vogel 	} hsf_flregacc;
1688cfa0ad2SJack F Vogel 	u16 regval;
1698cfa0ad2SJack F Vogel };
1708cfa0ad2SJack F Vogel 
1718cfa0ad2SJack F Vogel /**
1729d81738fSJack F Vogel  *  e1000_init_phy_params_pchlan - Initialize PHY function pointers
1739d81738fSJack F Vogel  *  @hw: pointer to the HW structure
1749d81738fSJack F Vogel  *
1759d81738fSJack F Vogel  *  Initialize family-specific PHY parameters and function pointers.
1769d81738fSJack F Vogel  **/
1779d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
1789d81738fSJack F Vogel {
1799d81738fSJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
1808ec87fc5SJack F Vogel 	u32 ctrl;
1819d81738fSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
1829d81738fSJack F Vogel 
1839d81738fSJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_pchlan");
1849d81738fSJack F Vogel 
1859d81738fSJack F Vogel 	phy->addr                     = 1;
1869d81738fSJack F Vogel 	phy->reset_delay_us           = 100;
1879d81738fSJack F Vogel 
1889d81738fSJack F Vogel 	phy->ops.acquire              = e1000_acquire_swflag_ich8lan;
1899d81738fSJack F Vogel 	phy->ops.check_reset_block    = e1000_check_reset_block_ich8lan;
1909d81738fSJack F Vogel 	phy->ops.get_cfg_done         = e1000_get_cfg_done_ich8lan;
1919d81738fSJack F Vogel 	phy->ops.read_reg             = e1000_read_phy_reg_hv;
1924edd8523SJack F Vogel 	phy->ops.read_reg_locked      = e1000_read_phy_reg_hv_locked;
1939d81738fSJack F Vogel 	phy->ops.release              = e1000_release_swflag_ich8lan;
1949d81738fSJack F Vogel 	phy->ops.reset                = e1000_phy_hw_reset_ich8lan;
1954edd8523SJack F Vogel 	phy->ops.set_d0_lplu_state    = e1000_set_lplu_state_pchlan;
1964edd8523SJack F Vogel 	phy->ops.set_d3_lplu_state    = e1000_set_lplu_state_pchlan;
1979d81738fSJack F Vogel 	phy->ops.write_reg            = e1000_write_phy_reg_hv;
1984edd8523SJack F Vogel 	phy->ops.write_reg_locked     = e1000_write_phy_reg_hv_locked;
1999d81738fSJack F Vogel 	phy->ops.power_up             = e1000_power_up_phy_copper;
2009d81738fSJack F Vogel 	phy->ops.power_down           = e1000_power_down_phy_copper_ich8lan;
2019d81738fSJack F Vogel 	phy->autoneg_mask             = AUTONEG_ADVERTISE_SPEED_DEFAULT;
2029d81738fSJack F Vogel 
2038ec87fc5SJack F Vogel 	if ((hw->mac.type == e1000_pchlan) &&
2048ec87fc5SJack F Vogel 	    (!(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))) {
2058ec87fc5SJack F Vogel 
2068ec87fc5SJack F Vogel 		/*
2078ec87fc5SJack F Vogel 		 * The MAC-PHY interconnect may still be in SMBus mode
2088ec87fc5SJack F Vogel 		 * after Sx->S0.  Toggle the LANPHYPC Value bit to force
2098ec87fc5SJack F Vogel 		 * the interconnect to PCIe mode, but only if there is no
2108ec87fc5SJack F Vogel 		 * firmware present otherwise firmware will have done it.
2118ec87fc5SJack F Vogel 		 */
2128ec87fc5SJack F Vogel 		ctrl = E1000_READ_REG(hw, E1000_CTRL);
2138ec87fc5SJack F Vogel 		ctrl |=  E1000_CTRL_LANPHYPC_OVERRIDE;
2148ec87fc5SJack F Vogel 		ctrl &= ~E1000_CTRL_LANPHYPC_VALUE;
2158ec87fc5SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
2168ec87fc5SJack F Vogel 		usec_delay(10);
2178ec87fc5SJack F Vogel 		ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
2188ec87fc5SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
2198ec87fc5SJack F Vogel 		msec_delay(50);
2208ec87fc5SJack F Vogel 	}
2218ec87fc5SJack F Vogel 
2228ec87fc5SJack F Vogel 	/*
2238ec87fc5SJack F Vogel 	 * Reset the PHY before any acccess to it.  Doing so, ensures that
2248ec87fc5SJack F Vogel 	 * the PHY is in a known good state before we read/write PHY registers.
2258ec87fc5SJack F Vogel 	 * The generic reset is sufficient here, because we haven't determined
2268ec87fc5SJack F Vogel 	 * the PHY type yet.
2278ec87fc5SJack F Vogel 	 */
2288ec87fc5SJack F Vogel 	ret_val = e1000_phy_hw_reset_generic(hw);
2298ec87fc5SJack F Vogel 	if (ret_val)
2308ec87fc5SJack F Vogel 		goto out;
2318ec87fc5SJack F Vogel 
2329d81738fSJack F Vogel 	phy->id = e1000_phy_unknown;
233a69ed8dfSJack F Vogel 	ret_val = e1000_get_phy_id(hw);
234a69ed8dfSJack F Vogel 	if (ret_val)
235a69ed8dfSJack F Vogel 		goto out;
236a69ed8dfSJack F Vogel 	if ((phy->id == 0) || (phy->id == PHY_REVISION_MASK)) {
237a69ed8dfSJack F Vogel 		/*
238a69ed8dfSJack F Vogel 		 * In case the PHY needs to be in mdio slow mode (eg. 82577),
239a69ed8dfSJack F Vogel 		 * set slow mode and try to get the PHY id again.
240a69ed8dfSJack F Vogel 		 */
241a69ed8dfSJack F Vogel 		ret_val = e1000_set_mdio_slow_mode_hv(hw);
242a69ed8dfSJack F Vogel 		if (ret_val)
243a69ed8dfSJack F Vogel 			goto out;
244a69ed8dfSJack F Vogel 		ret_val = e1000_get_phy_id(hw);
245a69ed8dfSJack F Vogel 		if (ret_val)
246a69ed8dfSJack F Vogel 			goto out;
247a69ed8dfSJack F Vogel 	}
2489d81738fSJack F Vogel 	phy->type = e1000_get_phy_type_from_id(phy->id);
2499d81738fSJack F Vogel 
2504edd8523SJack F Vogel 	switch (phy->type) {
2514edd8523SJack F Vogel 	case e1000_phy_82577:
2529d81738fSJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_82577;
2539d81738fSJack F Vogel 		phy->ops.force_speed_duplex =
2549d81738fSJack F Vogel 			e1000_phy_force_speed_duplex_82577;
2559d81738fSJack F Vogel 		phy->ops.get_cable_length = e1000_get_cable_length_82577;
2569d81738fSJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_82577;
2579d81738fSJack F Vogel 		phy->ops.commit = e1000_phy_sw_reset_generic;
2588ec87fc5SJack F Vogel 		break;
2594edd8523SJack F Vogel 	case e1000_phy_82578:
2604edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_m88;
2614edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
2624edd8523SJack F Vogel 		phy->ops.get_cable_length = e1000_get_cable_length_m88;
2634edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_m88;
2644edd8523SJack F Vogel 		break;
2654edd8523SJack F Vogel 	default:
2664edd8523SJack F Vogel 		ret_val = -E1000_ERR_PHY;
2674edd8523SJack F Vogel 		break;
2689d81738fSJack F Vogel 	}
2699d81738fSJack F Vogel 
270a69ed8dfSJack F Vogel out:
2719d81738fSJack F Vogel 	return ret_val;
2729d81738fSJack F Vogel }
2739d81738fSJack F Vogel 
2749d81738fSJack F Vogel /**
2758cfa0ad2SJack F Vogel  *  e1000_init_phy_params_ich8lan - Initialize PHY function pointers
2768cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
2778cfa0ad2SJack F Vogel  *
2788cfa0ad2SJack F Vogel  *  Initialize family-specific PHY parameters and function pointers.
2798cfa0ad2SJack F Vogel  **/
2808cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
2818cfa0ad2SJack F Vogel {
2828cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
2838cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
2848cfa0ad2SJack F Vogel 	u16 i = 0;
2858cfa0ad2SJack F Vogel 
2868cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_ich8lan");
2878cfa0ad2SJack F Vogel 
2888cfa0ad2SJack F Vogel 	phy->addr                     = 1;
2898cfa0ad2SJack F Vogel 	phy->reset_delay_us           = 100;
2908cfa0ad2SJack F Vogel 
2918cfa0ad2SJack F Vogel 	phy->ops.acquire              = e1000_acquire_swflag_ich8lan;
2928cfa0ad2SJack F Vogel 	phy->ops.check_reset_block    = e1000_check_reset_block_ich8lan;
2938cfa0ad2SJack F Vogel 	phy->ops.get_cable_length     = e1000_get_cable_length_igp_2;
2948cfa0ad2SJack F Vogel 	phy->ops.get_cfg_done         = e1000_get_cfg_done_ich8lan;
2958cfa0ad2SJack F Vogel 	phy->ops.read_reg             = e1000_read_phy_reg_igp;
2968cfa0ad2SJack F Vogel 	phy->ops.release              = e1000_release_swflag_ich8lan;
2978cfa0ad2SJack F Vogel 	phy->ops.reset                = e1000_phy_hw_reset_ich8lan;
2988cfa0ad2SJack F Vogel 	phy->ops.set_d0_lplu_state    = e1000_set_d0_lplu_state_ich8lan;
2998cfa0ad2SJack F Vogel 	phy->ops.set_d3_lplu_state    = e1000_set_d3_lplu_state_ich8lan;
3008cfa0ad2SJack F Vogel 	phy->ops.write_reg            = e1000_write_phy_reg_igp;
3018cfa0ad2SJack F Vogel 	phy->ops.power_up             = e1000_power_up_phy_copper;
3028cfa0ad2SJack F Vogel 	phy->ops.power_down           = e1000_power_down_phy_copper_ich8lan;
3038cfa0ad2SJack F Vogel 
3048cfa0ad2SJack F Vogel 	/*
3058cfa0ad2SJack F Vogel 	 * We may need to do this twice - once for IGP and if that fails,
3068cfa0ad2SJack F Vogel 	 * we'll set BM func pointers and try again
3078cfa0ad2SJack F Vogel 	 */
3088cfa0ad2SJack F Vogel 	ret_val = e1000_determine_phy_address(hw);
3098cfa0ad2SJack F Vogel 	if (ret_val) {
3108cfa0ad2SJack F Vogel 		phy->ops.write_reg = e1000_write_phy_reg_bm;
3118cfa0ad2SJack F Vogel 		phy->ops.read_reg  = e1000_read_phy_reg_bm;
3128cfa0ad2SJack F Vogel 		ret_val = e1000_determine_phy_address(hw);
3138cfa0ad2SJack F Vogel 		if (ret_val) {
314d035aa2dSJack F Vogel 			DEBUGOUT("Cannot determine PHY addr. Erroring out\n");
3158cfa0ad2SJack F Vogel 			goto out;
3168cfa0ad2SJack F Vogel 		}
3178cfa0ad2SJack F Vogel 	}
3188cfa0ad2SJack F Vogel 
3198cfa0ad2SJack F Vogel 	phy->id = 0;
3208cfa0ad2SJack F Vogel 	while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) &&
3218cfa0ad2SJack F Vogel 	       (i++ < 100)) {
3228cfa0ad2SJack F Vogel 		msec_delay(1);
3238cfa0ad2SJack F Vogel 		ret_val = e1000_get_phy_id(hw);
3248cfa0ad2SJack F Vogel 		if (ret_val)
3258cfa0ad2SJack F Vogel 			goto out;
3268cfa0ad2SJack F Vogel 	}
3278cfa0ad2SJack F Vogel 
3288cfa0ad2SJack F Vogel 	/* Verify phy id */
3298cfa0ad2SJack F Vogel 	switch (phy->id) {
3308cfa0ad2SJack F Vogel 	case IGP03E1000_E_PHY_ID:
3318cfa0ad2SJack F Vogel 		phy->type = e1000_phy_igp_3;
3328cfa0ad2SJack F Vogel 		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
3334edd8523SJack F Vogel 		phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked;
3344edd8523SJack F Vogel 		phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked;
3354edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_igp;
3364edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_igp;
3374edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
3388cfa0ad2SJack F Vogel 		break;
3398cfa0ad2SJack F Vogel 	case IFE_E_PHY_ID:
3408cfa0ad2SJack F Vogel 	case IFE_PLUS_E_PHY_ID:
3418cfa0ad2SJack F Vogel 	case IFE_C_E_PHY_ID:
3428cfa0ad2SJack F Vogel 		phy->type = e1000_phy_ife;
3438cfa0ad2SJack F Vogel 		phy->autoneg_mask = E1000_ALL_NOT_GIG;
3444edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_ife;
3454edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_ife;
3464edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife;
3478cfa0ad2SJack F Vogel 		break;
3488cfa0ad2SJack F Vogel 	case BME1000_E_PHY_ID:
3498cfa0ad2SJack F Vogel 		phy->type = e1000_phy_bm;
3508cfa0ad2SJack F Vogel 		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
3518cfa0ad2SJack F Vogel 		phy->ops.read_reg = e1000_read_phy_reg_bm;
3528cfa0ad2SJack F Vogel 		phy->ops.write_reg = e1000_write_phy_reg_bm;
3538cfa0ad2SJack F Vogel 		phy->ops.commit = e1000_phy_sw_reset_generic;
3544edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_m88;
3554edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_m88;
3564edd8523SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
3578cfa0ad2SJack F Vogel 		break;
3588cfa0ad2SJack F Vogel 	default:
3598cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_PHY;
3608cfa0ad2SJack F Vogel 		goto out;
3618cfa0ad2SJack F Vogel 	}
3628cfa0ad2SJack F Vogel 
3638cfa0ad2SJack F Vogel out:
3648cfa0ad2SJack F Vogel 	return ret_val;
3658cfa0ad2SJack F Vogel }
3668cfa0ad2SJack F Vogel 
3678cfa0ad2SJack F Vogel /**
3688cfa0ad2SJack F Vogel  *  e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
3698cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
3708cfa0ad2SJack F Vogel  *
3718cfa0ad2SJack F Vogel  *  Initialize family-specific NVM parameters and function
3728cfa0ad2SJack F Vogel  *  pointers.
3738cfa0ad2SJack F Vogel  **/
3748cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
3758cfa0ad2SJack F Vogel {
3768cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
377daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
3788cfa0ad2SJack F Vogel 	u32 gfpreg, sector_base_addr, sector_end_addr;
3798cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
3808cfa0ad2SJack F Vogel 	u16 i;
3818cfa0ad2SJack F Vogel 
3828cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_nvm_params_ich8lan");
3838cfa0ad2SJack F Vogel 
3848cfa0ad2SJack F Vogel 	/* Can't read flash registers if the register set isn't mapped. */
3858cfa0ad2SJack F Vogel 	if (!hw->flash_address) {
3868cfa0ad2SJack F Vogel 		DEBUGOUT("ERROR: Flash registers not mapped\n");
3878cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
3888cfa0ad2SJack F Vogel 		goto out;
3898cfa0ad2SJack F Vogel 	}
3908cfa0ad2SJack F Vogel 
3918cfa0ad2SJack F Vogel 	nvm->type = e1000_nvm_flash_sw;
3928cfa0ad2SJack F Vogel 
3938cfa0ad2SJack F Vogel 	gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG);
3948cfa0ad2SJack F Vogel 
3958cfa0ad2SJack F Vogel 	/*
3968cfa0ad2SJack F Vogel 	 * sector_X_addr is a "sector"-aligned address (4096 bytes)
3978cfa0ad2SJack F Vogel 	 * Add 1 to sector_end_addr since this sector is included in
3988cfa0ad2SJack F Vogel 	 * the overall size.
3998cfa0ad2SJack F Vogel 	 */
4008cfa0ad2SJack F Vogel 	sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
4018cfa0ad2SJack F Vogel 	sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
4028cfa0ad2SJack F Vogel 
4038cfa0ad2SJack F Vogel 	/* flash_base_addr is byte-aligned */
4048cfa0ad2SJack F Vogel 	nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
4058cfa0ad2SJack F Vogel 
4068cfa0ad2SJack F Vogel 	/*
4078cfa0ad2SJack F Vogel 	 * find total size of the NVM, then cut in half since the total
4088cfa0ad2SJack F Vogel 	 * size represents two separate NVM banks.
4098cfa0ad2SJack F Vogel 	 */
4108cfa0ad2SJack F Vogel 	nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
4118cfa0ad2SJack F Vogel 	                          << FLASH_SECTOR_ADDR_SHIFT;
4128cfa0ad2SJack F Vogel 	nvm->flash_bank_size /= 2;
4138cfa0ad2SJack F Vogel 	/* Adjust to word count */
4148cfa0ad2SJack F Vogel 	nvm->flash_bank_size /= sizeof(u16);
4158cfa0ad2SJack F Vogel 
4168cfa0ad2SJack F Vogel 	nvm->word_size = E1000_SHADOW_RAM_WORDS;
4178cfa0ad2SJack F Vogel 
4188cfa0ad2SJack F Vogel 	/* Clear shadow ram */
4198cfa0ad2SJack F Vogel 	for (i = 0; i < nvm->word_size; i++) {
4208cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].modified = FALSE;
4218cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].value    = 0xFFFF;
4228cfa0ad2SJack F Vogel 	}
4238cfa0ad2SJack F Vogel 
4244edd8523SJack F Vogel 	E1000_MUTEX_INIT(&dev_spec->nvm_mutex);
4254edd8523SJack F Vogel 	E1000_MUTEX_INIT(&dev_spec->swflag_mutex);
4264edd8523SJack F Vogel 
4278cfa0ad2SJack F Vogel 	/* Function Pointers */
4284edd8523SJack F Vogel 	nvm->ops.acquire       = e1000_acquire_nvm_ich8lan;
4294edd8523SJack F Vogel 	nvm->ops.release       = e1000_release_nvm_ich8lan;
4308cfa0ad2SJack F Vogel 	nvm->ops.read          = e1000_read_nvm_ich8lan;
4318cfa0ad2SJack F Vogel 	nvm->ops.update        = e1000_update_nvm_checksum_ich8lan;
4328cfa0ad2SJack F Vogel 	nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan;
4338cfa0ad2SJack F Vogel 	nvm->ops.validate      = e1000_validate_nvm_checksum_ich8lan;
4348cfa0ad2SJack F Vogel 	nvm->ops.write         = e1000_write_nvm_ich8lan;
4358cfa0ad2SJack F Vogel 
4368cfa0ad2SJack F Vogel out:
4378cfa0ad2SJack F Vogel 	return ret_val;
4388cfa0ad2SJack F Vogel }
4398cfa0ad2SJack F Vogel 
4408cfa0ad2SJack F Vogel /**
4418cfa0ad2SJack F Vogel  *  e1000_init_mac_params_ich8lan - Initialize MAC function pointers
4428cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
4438cfa0ad2SJack F Vogel  *
4448cfa0ad2SJack F Vogel  *  Initialize family-specific MAC parameters and function
4458cfa0ad2SJack F Vogel  *  pointers.
4468cfa0ad2SJack F Vogel  **/
4478cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
4488cfa0ad2SJack F Vogel {
4498cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
450d035aa2dSJack F Vogel 	u16 pci_cfg;
4518cfa0ad2SJack F Vogel 
4528cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_mac_params_ich8lan");
4538cfa0ad2SJack F Vogel 
4548cfa0ad2SJack F Vogel 	/* Set media type function pointer */
4558cfa0ad2SJack F Vogel 	hw->phy.media_type = e1000_media_type_copper;
4568cfa0ad2SJack F Vogel 
4578cfa0ad2SJack F Vogel 	/* Set mta register count */
4588cfa0ad2SJack F Vogel 	mac->mta_reg_count = 32;
4598cfa0ad2SJack F Vogel 	/* Set rar entry count */
4608cfa0ad2SJack F Vogel 	mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
4618cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
4628cfa0ad2SJack F Vogel 		mac->rar_entry_count--;
4638cfa0ad2SJack F Vogel 	/* Set if part includes ASF firmware */
4648cfa0ad2SJack F Vogel 	mac->asf_firmware_present = TRUE;
4658ec87fc5SJack F Vogel 	/* FWSM register */
4668ec87fc5SJack F Vogel 	mac->has_fwsm = TRUE;
4678ec87fc5SJack F Vogel 	/* ARC subsystem not supported */
4688ec87fc5SJack F Vogel 	mac->arc_subsystem_valid = FALSE;
4694edd8523SJack F Vogel 	/* Adaptive IFS supported */
4704edd8523SJack F Vogel 	mac->adaptive_ifs = TRUE;
4718cfa0ad2SJack F Vogel 
4728cfa0ad2SJack F Vogel 	/* Function pointers */
4738cfa0ad2SJack F Vogel 
4748cfa0ad2SJack F Vogel 	/* bus type/speed/width */
4758cfa0ad2SJack F Vogel 	mac->ops.get_bus_info = e1000_get_bus_info_ich8lan;
476daf9197cSJack F Vogel 	/* function id */
477daf9197cSJack F Vogel 	mac->ops.set_lan_id = e1000_set_lan_id_single_port;
4788cfa0ad2SJack F Vogel 	/* reset */
4798cfa0ad2SJack F Vogel 	mac->ops.reset_hw = e1000_reset_hw_ich8lan;
4808cfa0ad2SJack F Vogel 	/* hw initialization */
4818cfa0ad2SJack F Vogel 	mac->ops.init_hw = e1000_init_hw_ich8lan;
4828cfa0ad2SJack F Vogel 	/* link setup */
4838cfa0ad2SJack F Vogel 	mac->ops.setup_link = e1000_setup_link_ich8lan;
4848cfa0ad2SJack F Vogel 	/* physical interface setup */
4858cfa0ad2SJack F Vogel 	mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan;
4868cfa0ad2SJack F Vogel 	/* check for link */
4874edd8523SJack F Vogel 	mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan;
4888cfa0ad2SJack F Vogel 	/* check management mode */
4898cfa0ad2SJack F Vogel 	mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
4908cfa0ad2SJack F Vogel 	/* link info */
4918cfa0ad2SJack F Vogel 	mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan;
4928cfa0ad2SJack F Vogel 	/* multicast address update */
4938cfa0ad2SJack F Vogel 	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
494d035aa2dSJack F Vogel 	/* clear hardware counters */
495d035aa2dSJack F Vogel 	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan;
496d035aa2dSJack F Vogel 
497d035aa2dSJack F Vogel 	/* LED operations */
498d035aa2dSJack F Vogel 	switch (mac->type) {
499d035aa2dSJack F Vogel 	case e1000_ich8lan:
500d035aa2dSJack F Vogel 	case e1000_ich9lan:
501d035aa2dSJack F Vogel 	case e1000_ich10lan:
502d035aa2dSJack F Vogel 		/* ID LED init */
503d035aa2dSJack F Vogel 		mac->ops.id_led_init = e1000_id_led_init_generic;
5048cfa0ad2SJack F Vogel 		/* blink LED */
5058cfa0ad2SJack F Vogel 		mac->ops.blink_led = e1000_blink_led_generic;
5068cfa0ad2SJack F Vogel 		/* setup LED */
5078cfa0ad2SJack F Vogel 		mac->ops.setup_led = e1000_setup_led_generic;
5088cfa0ad2SJack F Vogel 		/* cleanup LED */
5098cfa0ad2SJack F Vogel 		mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
5108cfa0ad2SJack F Vogel 		/* turn on/off LED */
5118cfa0ad2SJack F Vogel 		mac->ops.led_on = e1000_led_on_ich8lan;
5128cfa0ad2SJack F Vogel 		mac->ops.led_off = e1000_led_off_ich8lan;
513d035aa2dSJack F Vogel 		break;
5149d81738fSJack F Vogel 	case e1000_pchlan:
5159d81738fSJack F Vogel 		/* save PCH revision_id */
5169d81738fSJack F Vogel 		e1000_read_pci_cfg(hw, 0x2, &pci_cfg);
5179d81738fSJack F Vogel 		hw->revision_id = (u8)(pci_cfg &= 0x000F);
5189d81738fSJack F Vogel 		/* ID LED init */
5199d81738fSJack F Vogel 		mac->ops.id_led_init = e1000_id_led_init_pchlan;
5209d81738fSJack F Vogel 		/* setup LED */
5219d81738fSJack F Vogel 		mac->ops.setup_led = e1000_setup_led_pchlan;
5229d81738fSJack F Vogel 		/* cleanup LED */
5239d81738fSJack F Vogel 		mac->ops.cleanup_led = e1000_cleanup_led_pchlan;
5249d81738fSJack F Vogel 		/* turn on/off LED */
5259d81738fSJack F Vogel 		mac->ops.led_on = e1000_led_on_pchlan;
5269d81738fSJack F Vogel 		mac->ops.led_off = e1000_led_off_pchlan;
5279d81738fSJack F Vogel 		break;
528d035aa2dSJack F Vogel 	default:
529d035aa2dSJack F Vogel 		break;
530d035aa2dSJack F Vogel 	}
5318cfa0ad2SJack F Vogel 
5328cfa0ad2SJack F Vogel 	/* Enable PCS Lock-loss workaround for ICH8 */
5338cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
5348cfa0ad2SJack F Vogel 		e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE);
5358cfa0ad2SJack F Vogel 
536daf9197cSJack F Vogel 	return E1000_SUCCESS;
5378cfa0ad2SJack F Vogel }
5388cfa0ad2SJack F Vogel 
5398cfa0ad2SJack F Vogel /**
5404edd8523SJack F Vogel  *  e1000_check_for_copper_link_ich8lan - Check for link (Copper)
5414edd8523SJack F Vogel  *  @hw: pointer to the HW structure
5424edd8523SJack F Vogel  *
5434edd8523SJack F Vogel  *  Checks to see of the link status of the hardware has changed.  If a
5444edd8523SJack F Vogel  *  change in link status has been detected, then we read the PHY registers
5454edd8523SJack F Vogel  *  to get the current speed/duplex if link exists.
5464edd8523SJack F Vogel  **/
5474edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
5484edd8523SJack F Vogel {
5494edd8523SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
5504edd8523SJack F Vogel 	s32 ret_val;
5514edd8523SJack F Vogel 	bool link;
5524edd8523SJack F Vogel 
5534edd8523SJack F Vogel 	DEBUGFUNC("e1000_check_for_copper_link_ich8lan");
5544edd8523SJack F Vogel 
5554edd8523SJack F Vogel 	/*
5564edd8523SJack F Vogel 	 * We only want to go out to the PHY registers to see if Auto-Neg
5574edd8523SJack F Vogel 	 * has completed and/or if our link status has changed.  The
5584edd8523SJack F Vogel 	 * get_link_status flag is set upon receiving a Link Status
5594edd8523SJack F Vogel 	 * Change or Rx Sequence Error interrupt.
5604edd8523SJack F Vogel 	 */
5614edd8523SJack F Vogel 	if (!mac->get_link_status) {
5624edd8523SJack F Vogel 		ret_val = E1000_SUCCESS;
5634edd8523SJack F Vogel 		goto out;
5644edd8523SJack F Vogel 	}
5654edd8523SJack F Vogel 
5664edd8523SJack F Vogel 	/*
5674edd8523SJack F Vogel 	 * First we want to see if the MII Status Register reports
5684edd8523SJack F Vogel 	 * link.  If so, then we want to get the current speed/duplex
5694edd8523SJack F Vogel 	 * of the PHY.
5704edd8523SJack F Vogel 	 */
5714edd8523SJack F Vogel 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
5724edd8523SJack F Vogel 	if (ret_val)
5734edd8523SJack F Vogel 		goto out;
5744edd8523SJack F Vogel 
5754edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan) {
5764edd8523SJack F Vogel 		ret_val = e1000_k1_gig_workaround_hv(hw, link);
5774edd8523SJack F Vogel 		if (ret_val)
5784edd8523SJack F Vogel 			goto out;
5794edd8523SJack F Vogel 	}
5804edd8523SJack F Vogel 
5814edd8523SJack F Vogel 	if (!link)
5824edd8523SJack F Vogel 		goto out; /* No link detected */
5834edd8523SJack F Vogel 
5844edd8523SJack F Vogel 	mac->get_link_status = FALSE;
5854edd8523SJack F Vogel 
5864edd8523SJack F Vogel 	if (hw->phy.type == e1000_phy_82578) {
5874edd8523SJack F Vogel 		ret_val = e1000_link_stall_workaround_hv(hw);
5884edd8523SJack F Vogel 		if (ret_val)
5894edd8523SJack F Vogel 			goto out;
5904edd8523SJack F Vogel 	}
5914edd8523SJack F Vogel 
5924edd8523SJack F Vogel 	/*
5934edd8523SJack F Vogel 	 * Check if there was DownShift, must be checked
5944edd8523SJack F Vogel 	 * immediately after link-up
5954edd8523SJack F Vogel 	 */
5964edd8523SJack F Vogel 	e1000_check_downshift_generic(hw);
5974edd8523SJack F Vogel 
5984edd8523SJack F Vogel 	/*
5994edd8523SJack F Vogel 	 * If we are forcing speed/duplex, then we simply return since
6004edd8523SJack F Vogel 	 * we have already determined whether we have link or not.
6014edd8523SJack F Vogel 	 */
6024edd8523SJack F Vogel 	if (!mac->autoneg) {
6034edd8523SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
6044edd8523SJack F Vogel 		goto out;
6054edd8523SJack F Vogel 	}
6064edd8523SJack F Vogel 
6074edd8523SJack F Vogel 	/*
6084edd8523SJack F Vogel 	 * Auto-Neg is enabled.  Auto Speed Detection takes care
6094edd8523SJack F Vogel 	 * of MAC speed/duplex configuration.  So we only need to
6104edd8523SJack F Vogel 	 * configure Collision Distance in the MAC.
6114edd8523SJack F Vogel 	 */
6124edd8523SJack F Vogel 	e1000_config_collision_dist_generic(hw);
6134edd8523SJack F Vogel 
6144edd8523SJack F Vogel 	/*
6154edd8523SJack F Vogel 	 * Configure Flow Control now that Auto-Neg has completed.
6164edd8523SJack F Vogel 	 * First, we need to restore the desired flow control
6174edd8523SJack F Vogel 	 * settings because we may have had to re-autoneg with a
6184edd8523SJack F Vogel 	 * different link partner.
6194edd8523SJack F Vogel 	 */
6204edd8523SJack F Vogel 	ret_val = e1000_config_fc_after_link_up_generic(hw);
6214edd8523SJack F Vogel 	if (ret_val)
6224edd8523SJack F Vogel 		DEBUGOUT("Error configuring flow control\n");
6234edd8523SJack F Vogel 
6244edd8523SJack F Vogel out:
6254edd8523SJack F Vogel 	return ret_val;
6264edd8523SJack F Vogel }
6274edd8523SJack F Vogel 
6284edd8523SJack F Vogel /**
6298cfa0ad2SJack F Vogel  *  e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers
6308cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
6318cfa0ad2SJack F Vogel  *
6328cfa0ad2SJack F Vogel  *  Initialize family-specific function pointers for PHY, MAC, and NVM.
6338cfa0ad2SJack F Vogel  **/
6348cfa0ad2SJack F Vogel void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw)
6358cfa0ad2SJack F Vogel {
6368cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_function_pointers_ich8lan");
6378cfa0ad2SJack F Vogel 
6388cfa0ad2SJack F Vogel 	hw->mac.ops.init_params = e1000_init_mac_params_ich8lan;
6398cfa0ad2SJack F Vogel 	hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan;
6409d81738fSJack F Vogel 	switch (hw->mac.type) {
6419d81738fSJack F Vogel 	case e1000_ich8lan:
6429d81738fSJack F Vogel 	case e1000_ich9lan:
6439d81738fSJack F Vogel 	case e1000_ich10lan:
6448cfa0ad2SJack F Vogel 		hw->phy.ops.init_params = e1000_init_phy_params_ich8lan;
6459d81738fSJack F Vogel 		break;
6469d81738fSJack F Vogel 	case e1000_pchlan:
6479d81738fSJack F Vogel 		hw->phy.ops.init_params = e1000_init_phy_params_pchlan;
6489d81738fSJack F Vogel 		break;
6499d81738fSJack F Vogel 	default:
6509d81738fSJack F Vogel 		break;
6519d81738fSJack F Vogel 	}
6528cfa0ad2SJack F Vogel }
6538cfa0ad2SJack F Vogel 
6548cfa0ad2SJack F Vogel /**
6554edd8523SJack F Vogel  *  e1000_acquire_nvm_ich8lan - Acquire NVM mutex
6564edd8523SJack F Vogel  *  @hw: pointer to the HW structure
6574edd8523SJack F Vogel  *
6584edd8523SJack F Vogel  *  Acquires the mutex for performing NVM operations.
6594edd8523SJack F Vogel  **/
6604edd8523SJack F Vogel static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
6614edd8523SJack F Vogel {
6624edd8523SJack F Vogel 	DEBUGFUNC("e1000_acquire_nvm_ich8lan");
6634edd8523SJack F Vogel 
6644edd8523SJack F Vogel 	E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.nvm_mutex);
6654edd8523SJack F Vogel 
6664edd8523SJack F Vogel 	return E1000_SUCCESS;
6674edd8523SJack F Vogel }
6684edd8523SJack F Vogel 
6694edd8523SJack F Vogel /**
6704edd8523SJack F Vogel  *  e1000_release_nvm_ich8lan - Release NVM mutex
6714edd8523SJack F Vogel  *  @hw: pointer to the HW structure
6724edd8523SJack F Vogel  *
6734edd8523SJack F Vogel  *  Releases the mutex used while performing NVM operations.
6744edd8523SJack F Vogel  **/
6754edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
6764edd8523SJack F Vogel {
6774edd8523SJack F Vogel 	DEBUGFUNC("e1000_release_nvm_ich8lan");
6784edd8523SJack F Vogel 
6794edd8523SJack F Vogel 	E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.nvm_mutex);
6804edd8523SJack F Vogel 
6814edd8523SJack F Vogel 	return;
6824edd8523SJack F Vogel }
6834edd8523SJack F Vogel 
6844edd8523SJack F Vogel /**
6858cfa0ad2SJack F Vogel  *  e1000_acquire_swflag_ich8lan - Acquire software control flag
6868cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
6878cfa0ad2SJack F Vogel  *
6884edd8523SJack F Vogel  *  Acquires the software control flag for performing PHY and select
6894edd8523SJack F Vogel  *  MAC CSR accesses.
6908cfa0ad2SJack F Vogel  **/
6918cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
6928cfa0ad2SJack F Vogel {
6938cfa0ad2SJack F Vogel 	u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
6948cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
6958cfa0ad2SJack F Vogel 
6968cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_acquire_swflag_ich8lan");
6978cfa0ad2SJack F Vogel 
6984edd8523SJack F Vogel 	E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.swflag_mutex);
6994edd8523SJack F Vogel 
7008cfa0ad2SJack F Vogel 	while (timeout) {
7018cfa0ad2SJack F Vogel 		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
7024edd8523SJack F Vogel 		if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG))
7038cfa0ad2SJack F Vogel 			break;
7044edd8523SJack F Vogel 
7058cfa0ad2SJack F Vogel 		msec_delay_irq(1);
7068cfa0ad2SJack F Vogel 		timeout--;
7078cfa0ad2SJack F Vogel 	}
7088cfa0ad2SJack F Vogel 
7098cfa0ad2SJack F Vogel 	if (!timeout) {
7109d81738fSJack F Vogel 		DEBUGOUT("SW/FW/HW has locked the resource for too long.\n");
7114edd8523SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
7124edd8523SJack F Vogel 		goto out;
7134edd8523SJack F Vogel 	}
7144edd8523SJack F Vogel 
7154edd8523SJack F Vogel 	timeout = SW_FLAG_TIMEOUT;
7164edd8523SJack F Vogel 
7174edd8523SJack F Vogel 	extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
7184edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
7194edd8523SJack F Vogel 
7204edd8523SJack F Vogel 	while (timeout) {
7214edd8523SJack F Vogel 		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
7224edd8523SJack F Vogel 		if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
7234edd8523SJack F Vogel 			break;
7244edd8523SJack F Vogel 
7254edd8523SJack F Vogel 		msec_delay_irq(1);
7264edd8523SJack F Vogel 		timeout--;
7274edd8523SJack F Vogel 	}
7284edd8523SJack F Vogel 
7294edd8523SJack F Vogel 	if (!timeout) {
7304edd8523SJack F Vogel 		DEBUGOUT("Failed to acquire the semaphore.\n");
7318cfa0ad2SJack F Vogel 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
7328cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
7338cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
7348cfa0ad2SJack F Vogel 		goto out;
7358cfa0ad2SJack F Vogel 	}
7368cfa0ad2SJack F Vogel 
7378cfa0ad2SJack F Vogel out:
7384edd8523SJack F Vogel 	if (ret_val)
7394edd8523SJack F Vogel 		E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
7404edd8523SJack F Vogel 
7418cfa0ad2SJack F Vogel 	return ret_val;
7428cfa0ad2SJack F Vogel }
7438cfa0ad2SJack F Vogel 
7448cfa0ad2SJack F Vogel /**
7458cfa0ad2SJack F Vogel  *  e1000_release_swflag_ich8lan - Release software control flag
7468cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
7478cfa0ad2SJack F Vogel  *
7484edd8523SJack F Vogel  *  Releases the software control flag for performing PHY and select
7494edd8523SJack F Vogel  *  MAC CSR accesses.
7508cfa0ad2SJack F Vogel  **/
7518cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
7528cfa0ad2SJack F Vogel {
7538cfa0ad2SJack F Vogel 	u32 extcnf_ctrl;
7548cfa0ad2SJack F Vogel 
7558cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_release_swflag_ich8lan");
7568cfa0ad2SJack F Vogel 
7578cfa0ad2SJack F Vogel 	extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
7588cfa0ad2SJack F Vogel 	extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
7598cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
7608cfa0ad2SJack F Vogel 
7614edd8523SJack F Vogel 	E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
7624edd8523SJack F Vogel 
7638cfa0ad2SJack F Vogel 	return;
7648cfa0ad2SJack F Vogel }
7658cfa0ad2SJack F Vogel 
7668cfa0ad2SJack F Vogel /**
7678cfa0ad2SJack F Vogel  *  e1000_check_mng_mode_ich8lan - Checks management mode
7688cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
7698cfa0ad2SJack F Vogel  *
7708cfa0ad2SJack F Vogel  *  This checks if the adapter has manageability enabled.
7718cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by read/write
7728cfa0ad2SJack F Vogel  *  routines for the PHY and NVM parts.
7738cfa0ad2SJack F Vogel  **/
7748cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
7758cfa0ad2SJack F Vogel {
7768cfa0ad2SJack F Vogel 	u32 fwsm;
7778cfa0ad2SJack F Vogel 
7788cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_mng_mode_ich8lan");
7798cfa0ad2SJack F Vogel 
7808cfa0ad2SJack F Vogel 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
7818cfa0ad2SJack F Vogel 
782daf9197cSJack F Vogel 	return (fwsm & E1000_FWSM_MODE_MASK) ==
783daf9197cSJack F Vogel 	        (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
7848cfa0ad2SJack F Vogel }
7858cfa0ad2SJack F Vogel 
7868cfa0ad2SJack F Vogel /**
7878cfa0ad2SJack F Vogel  *  e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
7888cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
7898cfa0ad2SJack F Vogel  *
7908cfa0ad2SJack F Vogel  *  Checks if firmware is blocking the reset of the PHY.
7918cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
7928cfa0ad2SJack F Vogel  *  reset routines.
7938cfa0ad2SJack F Vogel  **/
7948cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
7958cfa0ad2SJack F Vogel {
7968cfa0ad2SJack F Vogel 	u32 fwsm;
7978cfa0ad2SJack F Vogel 
7988cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_reset_block_ich8lan");
7998cfa0ad2SJack F Vogel 
8008ec87fc5SJack F Vogel 	if (hw->phy.reset_disable)
8018ec87fc5SJack F Vogel 		return E1000_BLK_PHY_RESET;
8028ec87fc5SJack F Vogel 
8038cfa0ad2SJack F Vogel 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
8048cfa0ad2SJack F Vogel 
8058cfa0ad2SJack F Vogel 	return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS
8068cfa0ad2SJack F Vogel 	                                        : E1000_BLK_PHY_RESET;
8078cfa0ad2SJack F Vogel }
8088cfa0ad2SJack F Vogel 
8098cfa0ad2SJack F Vogel /**
8104edd8523SJack F Vogel  *  e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration
8114edd8523SJack F Vogel  *  @hw:   pointer to the HW structure
8124edd8523SJack F Vogel  *
8134edd8523SJack F Vogel  *  SW should configure the LCD from the NVM extended configuration region
8144edd8523SJack F Vogel  *  as a workaround for certain parts.
8154edd8523SJack F Vogel  **/
8164edd8523SJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
8174edd8523SJack F Vogel {
8184edd8523SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
8194edd8523SJack F Vogel 	u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
820a69ed8dfSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
8214edd8523SJack F Vogel 	u16 word_addr, reg_data, reg_addr, phy_page = 0;
8224edd8523SJack F Vogel 
823a69ed8dfSJack F Vogel 	if (!(hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) &&
824a69ed8dfSJack F Vogel 		!(hw->mac.type == e1000_pchlan))
825a69ed8dfSJack F Vogel 		return ret_val;
826a69ed8dfSJack F Vogel 
8274edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
8284edd8523SJack F Vogel 	if (ret_val)
8294edd8523SJack F Vogel 		return ret_val;
8304edd8523SJack F Vogel 
8314edd8523SJack F Vogel 	/*
8324edd8523SJack F Vogel 	 * Initialize the PHY from the NVM on ICH platforms.  This
8334edd8523SJack F Vogel 	 * is needed due to an issue where the NVM configuration is
8344edd8523SJack F Vogel 	 * not properly autoloaded after power transitions.
8354edd8523SJack F Vogel 	 * Therefore, after each PHY reset, we will load the
8364edd8523SJack F Vogel 	 * configuration data out of the NVM manually.
8374edd8523SJack F Vogel 	 */
8384edd8523SJack F Vogel 	if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
8394edd8523SJack F Vogel 	    (hw->device_id == E1000_DEV_ID_ICH8_IGP_M) ||
8404edd8523SJack F Vogel 	    (hw->mac.type == e1000_pchlan))
8414edd8523SJack F Vogel 		sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
8424edd8523SJack F Vogel 	else
8434edd8523SJack F Vogel 		sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
8444edd8523SJack F Vogel 
8454edd8523SJack F Vogel 	data = E1000_READ_REG(hw, E1000_FEXTNVM);
8464edd8523SJack F Vogel 	if (!(data & sw_cfg_mask))
8474edd8523SJack F Vogel 		goto out;
8484edd8523SJack F Vogel 
8494edd8523SJack F Vogel 	/* Wait for basic configuration completes before proceeding */
8504edd8523SJack F Vogel 	e1000_lan_init_done_ich8lan(hw);
8514edd8523SJack F Vogel 
8524edd8523SJack F Vogel 	/*
8534edd8523SJack F Vogel 	 * Make sure HW does not configure LCD from PHY
8544edd8523SJack F Vogel 	 * extended configuration before SW configuration
8554edd8523SJack F Vogel 	 */
8564edd8523SJack F Vogel 	data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
8574edd8523SJack F Vogel 	if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
8584edd8523SJack F Vogel 		goto out;
8594edd8523SJack F Vogel 
8604edd8523SJack F Vogel 	cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE);
8614edd8523SJack F Vogel 	cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
8624edd8523SJack F Vogel 	cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
8634edd8523SJack F Vogel 	if (!cnf_size)
8644edd8523SJack F Vogel 		goto out;
8654edd8523SJack F Vogel 
8664edd8523SJack F Vogel 	cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
8674edd8523SJack F Vogel 	cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
8684edd8523SJack F Vogel 
8694edd8523SJack F Vogel 	if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
8704edd8523SJack F Vogel 	    (hw->mac.type == e1000_pchlan)) {
8714edd8523SJack F Vogel 		/*
8724edd8523SJack F Vogel 		 * HW configures the SMBus address and LEDs when the
8734edd8523SJack F Vogel 		 * OEM and LCD Write Enable bits are set in the NVM.
8744edd8523SJack F Vogel 		 * When both NVM bits are cleared, SW will configure
8754edd8523SJack F Vogel 		 * them instead.
8764edd8523SJack F Vogel 		 */
8774edd8523SJack F Vogel 		data = E1000_READ_REG(hw, E1000_STRAP);
8784edd8523SJack F Vogel 		data &= E1000_STRAP_SMBUS_ADDRESS_MASK;
8794edd8523SJack F Vogel 		reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT;
8804edd8523SJack F Vogel 		reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
8814edd8523SJack F Vogel 		ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR,
8824edd8523SJack F Vogel 							reg_data);
8834edd8523SJack F Vogel 		if (ret_val)
8844edd8523SJack F Vogel 			goto out;
8854edd8523SJack F Vogel 
8864edd8523SJack F Vogel 		data = E1000_READ_REG(hw, E1000_LEDCTL);
887a69ed8dfSJack F Vogel 		ret_val = e1000_write_phy_reg_hv_locked(hw, HV_LED_CONFIG,
8884edd8523SJack F Vogel 							(u16)data);
8894edd8523SJack F Vogel 		if (ret_val)
8904edd8523SJack F Vogel 			goto out;
8914edd8523SJack F Vogel 	}
8924edd8523SJack F Vogel 
8934edd8523SJack F Vogel 	/* Configure LCD from extended configuration region. */
8944edd8523SJack F Vogel 
8954edd8523SJack F Vogel 	/* cnf_base_addr is in DWORD */
8964edd8523SJack F Vogel 	word_addr = (u16)(cnf_base_addr << 1);
8974edd8523SJack F Vogel 
8984edd8523SJack F Vogel 	for (i = 0; i < cnf_size; i++) {
8994edd8523SJack F Vogel 		ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1,
9004edd8523SJack F Vogel 					   &reg_data);
9014edd8523SJack F Vogel 		if (ret_val)
9024edd8523SJack F Vogel 			goto out;
9034edd8523SJack F Vogel 
9044edd8523SJack F Vogel 		ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1),
9054edd8523SJack F Vogel 					   1, &reg_addr);
9064edd8523SJack F Vogel 		if (ret_val)
9074edd8523SJack F Vogel 			goto out;
9084edd8523SJack F Vogel 
9094edd8523SJack F Vogel 		/* Save off the PHY page for future writes. */
9104edd8523SJack F Vogel 		if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
9114edd8523SJack F Vogel 			phy_page = reg_data;
9124edd8523SJack F Vogel 			continue;
9134edd8523SJack F Vogel 		}
9144edd8523SJack F Vogel 
9154edd8523SJack F Vogel 		reg_addr &= PHY_REG_MASK;
9164edd8523SJack F Vogel 		reg_addr |= phy_page;
9174edd8523SJack F Vogel 
9184edd8523SJack F Vogel 		ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr,
9194edd8523SJack F Vogel 						    reg_data);
9204edd8523SJack F Vogel 		if (ret_val)
9214edd8523SJack F Vogel 			goto out;
9224edd8523SJack F Vogel 	}
9234edd8523SJack F Vogel 
9244edd8523SJack F Vogel out:
9254edd8523SJack F Vogel 	hw->phy.ops.release(hw);
9264edd8523SJack F Vogel 	return ret_val;
9274edd8523SJack F Vogel }
9284edd8523SJack F Vogel 
9294edd8523SJack F Vogel /**
9304edd8523SJack F Vogel  *  e1000_k1_gig_workaround_hv - K1 Si workaround
9314edd8523SJack F Vogel  *  @hw:   pointer to the HW structure
9324edd8523SJack F Vogel  *  @link: link up bool flag
9334edd8523SJack F Vogel  *
9344edd8523SJack F Vogel  *  If K1 is enabled for 1Gbps, the MAC might stall when transitioning
9354edd8523SJack F Vogel  *  from a lower speed.  This workaround disables K1 whenever link is at 1Gig
9364edd8523SJack F Vogel  *  If link is down, the function will restore the default K1 setting located
9374edd8523SJack F Vogel  *  in the NVM.
9384edd8523SJack F Vogel  **/
9394edd8523SJack F Vogel static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
9404edd8523SJack F Vogel {
9414edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
9424edd8523SJack F Vogel 	u16 status_reg = 0;
9434edd8523SJack F Vogel 	bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled;
9444edd8523SJack F Vogel 
9454edd8523SJack F Vogel 	DEBUGFUNC("e1000_k1_gig_workaround_hv");
9464edd8523SJack F Vogel 
9474edd8523SJack F Vogel 	if (hw->mac.type != e1000_pchlan)
9484edd8523SJack F Vogel 		goto out;
9494edd8523SJack F Vogel 
9504edd8523SJack F Vogel 	/* Wrap the whole flow with the sw flag */
9514edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
9524edd8523SJack F Vogel 	if (ret_val)
9534edd8523SJack F Vogel 		goto out;
9544edd8523SJack F Vogel 
9554edd8523SJack F Vogel 	/* Disable K1 when link is 1Gbps, otherwise use the NVM setting */
9564edd8523SJack F Vogel 	if (link) {
9574edd8523SJack F Vogel 		if (hw->phy.type == e1000_phy_82578) {
9584edd8523SJack F Vogel 			ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS,
9594edd8523SJack F Vogel 			                                      &status_reg);
9604edd8523SJack F Vogel 			if (ret_val)
9614edd8523SJack F Vogel 				goto release;
9624edd8523SJack F Vogel 
9634edd8523SJack F Vogel 			status_reg &= BM_CS_STATUS_LINK_UP |
9644edd8523SJack F Vogel 			              BM_CS_STATUS_RESOLVED |
9654edd8523SJack F Vogel 			              BM_CS_STATUS_SPEED_MASK;
9664edd8523SJack F Vogel 
9674edd8523SJack F Vogel 			if (status_reg == (BM_CS_STATUS_LINK_UP |
9684edd8523SJack F Vogel 			                   BM_CS_STATUS_RESOLVED |
9694edd8523SJack F Vogel 			                   BM_CS_STATUS_SPEED_1000))
9704edd8523SJack F Vogel 				k1_enable = FALSE;
9714edd8523SJack F Vogel 		}
9724edd8523SJack F Vogel 
9734edd8523SJack F Vogel 		if (hw->phy.type == e1000_phy_82577) {
9744edd8523SJack F Vogel 			ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS,
9754edd8523SJack F Vogel 			                                      &status_reg);
9764edd8523SJack F Vogel 			if (ret_val)
9774edd8523SJack F Vogel 				goto release;
9784edd8523SJack F Vogel 
9794edd8523SJack F Vogel 			status_reg &= HV_M_STATUS_LINK_UP |
9804edd8523SJack F Vogel 			              HV_M_STATUS_AUTONEG_COMPLETE |
9814edd8523SJack F Vogel 			              HV_M_STATUS_SPEED_MASK;
9824edd8523SJack F Vogel 
9834edd8523SJack F Vogel 			if (status_reg == (HV_M_STATUS_LINK_UP |
9844edd8523SJack F Vogel 			                   HV_M_STATUS_AUTONEG_COMPLETE |
9854edd8523SJack F Vogel 			                   HV_M_STATUS_SPEED_1000))
9864edd8523SJack F Vogel 				k1_enable = FALSE;
9874edd8523SJack F Vogel 		}
9884edd8523SJack F Vogel 
9894edd8523SJack F Vogel 		/* Link stall fix for link up */
9904edd8523SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
9914edd8523SJack F Vogel 		                                       0x0100);
9924edd8523SJack F Vogel 		if (ret_val)
9934edd8523SJack F Vogel 			goto release;
9944edd8523SJack F Vogel 
9954edd8523SJack F Vogel 	} else {
9964edd8523SJack F Vogel 		/* Link stall fix for link down */
9974edd8523SJack F Vogel 		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
9984edd8523SJack F Vogel 		                                       0x4100);
9994edd8523SJack F Vogel 		if (ret_val)
10004edd8523SJack F Vogel 			goto release;
10014edd8523SJack F Vogel 	}
10024edd8523SJack F Vogel 
10034edd8523SJack F Vogel 	ret_val = e1000_configure_k1_ich8lan(hw, k1_enable);
10044edd8523SJack F Vogel 
10054edd8523SJack F Vogel release:
10064edd8523SJack F Vogel 	hw->phy.ops.release(hw);
10074edd8523SJack F Vogel out:
10084edd8523SJack F Vogel 	return ret_val;
10094edd8523SJack F Vogel }
10104edd8523SJack F Vogel 
10114edd8523SJack F Vogel /**
10124edd8523SJack F Vogel  *  e1000_configure_k1_ich8lan - Configure K1 power state
10134edd8523SJack F Vogel  *  @hw: pointer to the HW structure
10144edd8523SJack F Vogel  *  @enable: K1 state to configure
10154edd8523SJack F Vogel  *
10164edd8523SJack F Vogel  *  Configure the K1 power state based on the provided parameter.
10174edd8523SJack F Vogel  *  Assumes semaphore already acquired.
10184edd8523SJack F Vogel  *
10194edd8523SJack F Vogel  *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
10204edd8523SJack F Vogel  **/
10214edd8523SJack F Vogel s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
10224edd8523SJack F Vogel {
10234edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
10244edd8523SJack F Vogel 	u32 ctrl_reg = 0;
10254edd8523SJack F Vogel 	u32 ctrl_ext = 0;
10264edd8523SJack F Vogel 	u32 reg = 0;
10274edd8523SJack F Vogel 	u16 kmrn_reg = 0;
10284edd8523SJack F Vogel 
10294edd8523SJack F Vogel 	ret_val = e1000_read_kmrn_reg_locked(hw,
10304edd8523SJack F Vogel 	                                     E1000_KMRNCTRLSTA_K1_CONFIG,
10314edd8523SJack F Vogel 	                                     &kmrn_reg);
10324edd8523SJack F Vogel 	if (ret_val)
10334edd8523SJack F Vogel 		goto out;
10344edd8523SJack F Vogel 
10354edd8523SJack F Vogel 	if (k1_enable)
10364edd8523SJack F Vogel 		kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE;
10374edd8523SJack F Vogel 	else
10384edd8523SJack F Vogel 		kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE;
10394edd8523SJack F Vogel 
10404edd8523SJack F Vogel 	ret_val = e1000_write_kmrn_reg_locked(hw,
10414edd8523SJack F Vogel 	                                      E1000_KMRNCTRLSTA_K1_CONFIG,
10424edd8523SJack F Vogel 	                                      kmrn_reg);
10434edd8523SJack F Vogel 	if (ret_val)
10444edd8523SJack F Vogel 		goto out;
10454edd8523SJack F Vogel 
10464edd8523SJack F Vogel 	usec_delay(20);
10474edd8523SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
10484edd8523SJack F Vogel 	ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
10494edd8523SJack F Vogel 
10504edd8523SJack F Vogel 	reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
10514edd8523SJack F Vogel 	reg |= E1000_CTRL_FRCSPD;
10524edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, reg);
10534edd8523SJack F Vogel 
10544edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
10554edd8523SJack F Vogel 	usec_delay(20);
10564edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
10574edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
10584edd8523SJack F Vogel 	usec_delay(20);
10594edd8523SJack F Vogel 
10604edd8523SJack F Vogel out:
10614edd8523SJack F Vogel 	return ret_val;
10624edd8523SJack F Vogel }
10634edd8523SJack F Vogel 
10644edd8523SJack F Vogel /**
10654edd8523SJack F Vogel  *  e1000_oem_bits_config_ich8lan - SW-based LCD Configuration
10664edd8523SJack F Vogel  *  @hw:       pointer to the HW structure
10674edd8523SJack F Vogel  *  @d0_state: boolean if entering d0 or d3 device state
10684edd8523SJack F Vogel  *
10694edd8523SJack F Vogel  *  SW will configure Gbe Disable and LPLU based on the NVM. The four bits are
10704edd8523SJack F Vogel  *  collectively called OEM bits.  The OEM Write Enable bit and SW Config bit
10714edd8523SJack F Vogel  *  in NVM determines whether HW should configure LPLU and Gbe Disable.
10724edd8523SJack F Vogel  **/
10734edd8523SJack F Vogel s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
10744edd8523SJack F Vogel {
10754edd8523SJack F Vogel 	s32 ret_val = 0;
10764edd8523SJack F Vogel 	u32 mac_reg;
10774edd8523SJack F Vogel 	u16 oem_reg;
10784edd8523SJack F Vogel 
10794edd8523SJack F Vogel 	if (hw->mac.type != e1000_pchlan)
10804edd8523SJack F Vogel 		return ret_val;
10814edd8523SJack F Vogel 
10824edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
10834edd8523SJack F Vogel 	if (ret_val)
10844edd8523SJack F Vogel 		return ret_val;
10854edd8523SJack F Vogel 
10864edd8523SJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
10874edd8523SJack F Vogel 	if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
10884edd8523SJack F Vogel 		goto out;
10894edd8523SJack F Vogel 
10904edd8523SJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM);
10914edd8523SJack F Vogel 	if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
10924edd8523SJack F Vogel 		goto out;
10934edd8523SJack F Vogel 
10944edd8523SJack F Vogel 	mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
10954edd8523SJack F Vogel 
10964edd8523SJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg);
10974edd8523SJack F Vogel 	if (ret_val)
10984edd8523SJack F Vogel 		goto out;
10994edd8523SJack F Vogel 
11004edd8523SJack F Vogel 	oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU);
11014edd8523SJack F Vogel 
11024edd8523SJack F Vogel 	if (d0_state) {
11034edd8523SJack F Vogel 		if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE)
11044edd8523SJack F Vogel 			oem_reg |= HV_OEM_BITS_GBE_DIS;
11054edd8523SJack F Vogel 
11064edd8523SJack F Vogel 		if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
11074edd8523SJack F Vogel 			oem_reg |= HV_OEM_BITS_LPLU;
11084edd8523SJack F Vogel 	} else {
11094edd8523SJack F Vogel 		if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE)
11104edd8523SJack F Vogel 			oem_reg |= HV_OEM_BITS_GBE_DIS;
11114edd8523SJack F Vogel 
11124edd8523SJack F Vogel 		if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU)
11134edd8523SJack F Vogel 			oem_reg |= HV_OEM_BITS_LPLU;
11144edd8523SJack F Vogel 	}
11154edd8523SJack F Vogel 	/* Restart auto-neg to activate the bits */
11164edd8523SJack F Vogel 	if (!hw->phy.ops.check_reset_block(hw))
11174edd8523SJack F Vogel 		oem_reg |= HV_OEM_BITS_RESTART_AN;
11184edd8523SJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg);
11194edd8523SJack F Vogel 
11204edd8523SJack F Vogel out:
11214edd8523SJack F Vogel 	hw->phy.ops.release(hw);
11224edd8523SJack F Vogel 
11234edd8523SJack F Vogel 	return ret_val;
11244edd8523SJack F Vogel }
11254edd8523SJack F Vogel 
11264edd8523SJack F Vogel 
11274edd8523SJack F Vogel /**
11289d81738fSJack F Vogel  *  e1000_hv_phy_powerdown_workaround_ich8lan - Power down workaround on Sx
11299d81738fSJack F Vogel  *  @hw: pointer to the HW structure
11309d81738fSJack F Vogel  **/
11319d81738fSJack F Vogel s32 e1000_hv_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
11329d81738fSJack F Vogel {
11339d81738fSJack F Vogel 	if ((hw->phy.type != e1000_phy_82577) || (hw->revision_id > 2))
11349d81738fSJack F Vogel 		return E1000_SUCCESS;
11359d81738fSJack F Vogel 
11369d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0444);
11379d81738fSJack F Vogel }
11389d81738fSJack F Vogel 
11399d81738fSJack F Vogel /**
1140a69ed8dfSJack F Vogel  *  e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode
1141a69ed8dfSJack F Vogel  *  @hw:   pointer to the HW structure
1142a69ed8dfSJack F Vogel  **/
1143a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw)
1144a69ed8dfSJack F Vogel {
1145a69ed8dfSJack F Vogel 	s32 ret_val;
1146a69ed8dfSJack F Vogel 	u16 data;
1147a69ed8dfSJack F Vogel 
1148a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, HV_KMRN_MODE_CTRL, &data);
1149a69ed8dfSJack F Vogel 	if (ret_val)
1150a69ed8dfSJack F Vogel 		return ret_val;
1151a69ed8dfSJack F Vogel 
1152a69ed8dfSJack F Vogel 	data |= HV_KMRN_MDIO_SLOW;
1153a69ed8dfSJack F Vogel 
1154a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_MODE_CTRL, data);
1155a69ed8dfSJack F Vogel 
1156a69ed8dfSJack F Vogel 	return ret_val;
1157a69ed8dfSJack F Vogel }
1158a69ed8dfSJack F Vogel 
1159a69ed8dfSJack F Vogel /**
11609d81738fSJack F Vogel  *  e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
11619d81738fSJack F Vogel  *  done after every PHY reset.
11629d81738fSJack F Vogel  **/
11639d81738fSJack F Vogel static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
11649d81738fSJack F Vogel {
11659d81738fSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
1166a69ed8dfSJack F Vogel 	u16 phy_data;
11679d81738fSJack F Vogel 
11689d81738fSJack F Vogel 	if (hw->mac.type != e1000_pchlan)
11694edd8523SJack F Vogel 		goto out;
11709d81738fSJack F Vogel 
1171a69ed8dfSJack F Vogel 	/* Set MDIO slow mode before any other MDIO access */
1172a69ed8dfSJack F Vogel 	if (hw->phy.type == e1000_phy_82577) {
1173a69ed8dfSJack F Vogel 		ret_val = e1000_set_mdio_slow_mode_hv(hw);
1174a69ed8dfSJack F Vogel 		if (ret_val)
1175a69ed8dfSJack F Vogel 			goto out;
1176a69ed8dfSJack F Vogel 	}
1177a69ed8dfSJack F Vogel 
11789d81738fSJack F Vogel 	/* Hanksville M Phy init for IEEE. */
11799d81738fSJack F Vogel 	if ((hw->revision_id == 2) &&
11809d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577) &&
11819d81738fSJack F Vogel 	    ((hw->phy.revision == 2) || (hw->phy.revision == 3))) {
11829d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x8823);
11839d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0018);
11849d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x8824);
11859d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0016);
11869d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x8825);
11879d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x001A);
11889d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x888C);
11899d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0007);
11909d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x888D);
11919d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0007);
11929d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x888E);
11939d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0007);
11949d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x8827);
11959d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0001);
11969d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x8835);
11979d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0001);
11989d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x8834);
11999d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0001);
12009d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x8833);
12019d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0002);
12029d81738fSJack F Vogel 	}
12039d81738fSJack F Vogel 
12049d81738fSJack F Vogel 	if (((hw->phy.type == e1000_phy_82577) &&
12059d81738fSJack F Vogel 	     ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
12069d81738fSJack F Vogel 	    ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
12079d81738fSJack F Vogel 		/* Disable generation of early preamble */
12089d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
12099d81738fSJack F Vogel 		if (ret_val)
12104edd8523SJack F Vogel 			goto out;
12119d81738fSJack F Vogel 
12129d81738fSJack F Vogel 		/* Preamble tuning for SSC */
12139d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204);
12149d81738fSJack F Vogel 		if (ret_val)
12154edd8523SJack F Vogel 			goto out;
12169d81738fSJack F Vogel 	}
12179d81738fSJack F Vogel 
12189d81738fSJack F Vogel 	if (hw->phy.type == e1000_phy_82578) {
12199d81738fSJack F Vogel 		if (hw->revision_id < 3) {
12209d81738fSJack F Vogel 			/* PHY config */
12219d81738fSJack F Vogel 			ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x29,
12229d81738fSJack F Vogel 			                                0x66C0);
12239d81738fSJack F Vogel 			if (ret_val)
12244edd8523SJack F Vogel 				goto out;
12259d81738fSJack F Vogel 
12269d81738fSJack F Vogel 			/* PHY config */
12279d81738fSJack F Vogel 			ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x1E,
12289d81738fSJack F Vogel 			                                0xFFFF);
12299d81738fSJack F Vogel 			if (ret_val)
12304edd8523SJack F Vogel 				goto out;
12319d81738fSJack F Vogel 		}
12329d81738fSJack F Vogel 
12339d81738fSJack F Vogel 		/*
12349d81738fSJack F Vogel 		 * Return registers to default by doing a soft reset then
12359d81738fSJack F Vogel 		 * writing 0x3140 to the control register.
12369d81738fSJack F Vogel 		 */
12379d81738fSJack F Vogel 		if (hw->phy.revision < 2) {
12389d81738fSJack F Vogel 			e1000_phy_sw_reset_generic(hw);
12399d81738fSJack F Vogel 			ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL,
12409d81738fSJack F Vogel 			                                0x3140);
12419d81738fSJack F Vogel 		}
12429d81738fSJack F Vogel 	}
12439d81738fSJack F Vogel 
12449d81738fSJack F Vogel 	if ((hw->revision_id == 2) &&
12459d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577) &&
12469d81738fSJack F Vogel 	    ((hw->phy.revision == 2) || (hw->phy.revision == 3))) {
12479d81738fSJack F Vogel 		/*
12489d81738fSJack F Vogel 		 * Workaround for OEM (GbE) not operating after reset -
12499d81738fSJack F Vogel 		 * restart AN (twice)
12509d81738fSJack F Vogel 		 */
12519d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0400);
12529d81738fSJack F Vogel 		if (ret_val)
12534edd8523SJack F Vogel 			goto out;
12549d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0400);
12559d81738fSJack F Vogel 		if (ret_val)
12564edd8523SJack F Vogel 			goto out;
12579d81738fSJack F Vogel 	}
12589d81738fSJack F Vogel 
12599d81738fSJack F Vogel 	/* Select page 0 */
12609d81738fSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
12619d81738fSJack F Vogel 	if (ret_val)
12624edd8523SJack F Vogel 		goto out;
12634edd8523SJack F Vogel 
12649d81738fSJack F Vogel 	hw->phy.addr = 1;
12654edd8523SJack F Vogel 	ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
1266a69ed8dfSJack F Vogel 	hw->phy.ops.release(hw);
12674edd8523SJack F Vogel 	if (ret_val)
12684edd8523SJack F Vogel 		goto out;
12699d81738fSJack F Vogel 
12704edd8523SJack F Vogel 	/*
12714edd8523SJack F Vogel 	 * Configure the K1 Si workaround during phy reset assuming there is
12724edd8523SJack F Vogel 	 * link so that it disables K1 if link is in 1Gbps.
12734edd8523SJack F Vogel 	 */
12744edd8523SJack F Vogel 	ret_val = e1000_k1_gig_workaround_hv(hw, TRUE);
1275a69ed8dfSJack F Vogel 	if (ret_val)
1276a69ed8dfSJack F Vogel 		goto out;
12774edd8523SJack F Vogel 
1278a69ed8dfSJack F Vogel 	/* Workaround for link disconnects on a busy hub in half duplex */
1279a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
1280a69ed8dfSJack F Vogel 	if (ret_val)
1281a69ed8dfSJack F Vogel 		goto out;
1282a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.read_reg_locked(hw,
1283a69ed8dfSJack F Vogel 	                                      PHY_REG(BM_PORT_CTRL_PAGE, 17),
1284a69ed8dfSJack F Vogel 	                                      &phy_data);
1285a69ed8dfSJack F Vogel 	if (ret_val)
1286a69ed8dfSJack F Vogel 		goto release;
1287a69ed8dfSJack F Vogel 	ret_val = hw->phy.ops.write_reg_locked(hw,
1288a69ed8dfSJack F Vogel 	                                       PHY_REG(BM_PORT_CTRL_PAGE, 17),
1289a69ed8dfSJack F Vogel 	                                       phy_data & 0x00FF);
1290a69ed8dfSJack F Vogel release:
1291a69ed8dfSJack F Vogel 	hw->phy.ops.release(hw);
12924edd8523SJack F Vogel out:
12939d81738fSJack F Vogel 	return ret_val;
12949d81738fSJack F Vogel }
12959d81738fSJack F Vogel 
12969d81738fSJack F Vogel /**
12979d81738fSJack F Vogel  *  e1000_lan_init_done_ich8lan - Check for PHY config completion
12988cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
12998cfa0ad2SJack F Vogel  *
13009d81738fSJack F Vogel  *  Check the appropriate indication the MAC has finished configuring the
13019d81738fSJack F Vogel  *  PHY after a software reset.
13028cfa0ad2SJack F Vogel  **/
13039d81738fSJack F Vogel static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw)
13048cfa0ad2SJack F Vogel {
13059d81738fSJack F Vogel 	u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT;
13068cfa0ad2SJack F Vogel 
13079d81738fSJack F Vogel 	DEBUGFUNC("e1000_lan_init_done_ich8lan");
13088cfa0ad2SJack F Vogel 
13099d81738fSJack F Vogel 	/* Wait for basic configuration completes before proceeding */
13109d81738fSJack F Vogel 	do {
13119d81738fSJack F Vogel 		data = E1000_READ_REG(hw, E1000_STATUS);
13129d81738fSJack F Vogel 		data &= E1000_STATUS_LAN_INIT_DONE;
13139d81738fSJack F Vogel 		usec_delay(100);
13149d81738fSJack F Vogel 	} while ((!data) && --loop);
13158cfa0ad2SJack F Vogel 
13169d81738fSJack F Vogel 	/*
13179d81738fSJack F Vogel 	 * If basic configuration is incomplete before the above loop
13189d81738fSJack F Vogel 	 * count reaches 0, loading the configuration from NVM will
13199d81738fSJack F Vogel 	 * leave the PHY in a bad state possibly resulting in no link.
13209d81738fSJack F Vogel 	 */
13219d81738fSJack F Vogel 	if (loop == 0)
13229d81738fSJack F Vogel 		DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n");
13238cfa0ad2SJack F Vogel 
13249d81738fSJack F Vogel 	/* Clear the Init Done bit for the next init event */
13259d81738fSJack F Vogel 	data = E1000_READ_REG(hw, E1000_STATUS);
13269d81738fSJack F Vogel 	data &= ~E1000_STATUS_LAN_INIT_DONE;
13279d81738fSJack F Vogel 	E1000_WRITE_REG(hw, E1000_STATUS, data);
13288cfa0ad2SJack F Vogel }
13298cfa0ad2SJack F Vogel 
13308cfa0ad2SJack F Vogel /**
13318cfa0ad2SJack F Vogel  *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
13328cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
13338cfa0ad2SJack F Vogel  *
13348cfa0ad2SJack F Vogel  *  Resets the PHY
13358cfa0ad2SJack F Vogel  *  This is a function pointer entry point called by drivers
13368cfa0ad2SJack F Vogel  *  or other shared routines.
13378cfa0ad2SJack F Vogel  **/
13388cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
13398cfa0ad2SJack F Vogel {
13404edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
13414edd8523SJack F Vogel 	u16 reg;
13428cfa0ad2SJack F Vogel 
13438cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
13448cfa0ad2SJack F Vogel 
13458cfa0ad2SJack F Vogel 	ret_val = e1000_phy_hw_reset_generic(hw);
13468cfa0ad2SJack F Vogel 	if (ret_val)
13478cfa0ad2SJack F Vogel 		goto out;
13488cfa0ad2SJack F Vogel 
13499d81738fSJack F Vogel 	/* Allow time for h/w to get to a quiescent state after reset */
13509d81738fSJack F Vogel 	msec_delay(10);
13519d81738fSJack F Vogel 
1352a69ed8dfSJack F Vogel 	/* Perform any necessary post-reset workarounds */
1353a69ed8dfSJack F Vogel 	switch (hw->mac.type) {
1354a69ed8dfSJack F Vogel 	case e1000_pchlan:
13559d81738fSJack F Vogel 		ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
13569d81738fSJack F Vogel 		if (ret_val)
13579d81738fSJack F Vogel 			goto out;
1358a69ed8dfSJack F Vogel 		break;
1359a69ed8dfSJack F Vogel 	default:
1360a69ed8dfSJack F Vogel 		break;
13619d81738fSJack F Vogel 	}
13629d81738fSJack F Vogel 
13634edd8523SJack F Vogel 	/* Dummy read to clear the phy wakeup bit after lcd reset */
13644edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan)
13654edd8523SJack F Vogel 		hw->phy.ops.read_reg(hw, BM_WUC, &reg);
13668cfa0ad2SJack F Vogel 
13674edd8523SJack F Vogel 	/* Configure the LCD with the extended configuration region in NVM */
13684edd8523SJack F Vogel 	ret_val = e1000_sw_lcd_config_ich8lan(hw);
13698cfa0ad2SJack F Vogel 	if (ret_val)
13708cfa0ad2SJack F Vogel 		goto out;
13718cfa0ad2SJack F Vogel 
13724edd8523SJack F Vogel 	/* Configure the LCD with the OEM bits in NVM */
13734edd8523SJack F Vogel 	ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE);
13748cfa0ad2SJack F Vogel 
13758cfa0ad2SJack F Vogel out:
13768cfa0ad2SJack F Vogel 	return ret_val;
13778cfa0ad2SJack F Vogel }
13788cfa0ad2SJack F Vogel 
13798cfa0ad2SJack F Vogel /**
13804edd8523SJack F Vogel  *  e1000_set_lplu_state_pchlan - Set Low Power Link Up state
13818cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
13824edd8523SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
13838cfa0ad2SJack F Vogel  *
13844edd8523SJack F Vogel  *  Sets the LPLU state according to the active flag.  For PCH, if OEM write
13854edd8523SJack F Vogel  *  bit are disabled in the NVM, writing the LPLU bits in the MAC will not set
13864edd8523SJack F Vogel  *  the phy speed. This function will manually set the LPLU bit and restart
13874edd8523SJack F Vogel  *  auto-neg as hw would do. D3 and D0 LPLU will call the same function
13884edd8523SJack F Vogel  *  since it configures the same bit.
13898cfa0ad2SJack F Vogel  **/
13904edd8523SJack F Vogel static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
13918cfa0ad2SJack F Vogel {
13924edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
13934edd8523SJack F Vogel 	u16 oem_reg;
13948cfa0ad2SJack F Vogel 
13954edd8523SJack F Vogel 	DEBUGFUNC("e1000_set_lplu_state_pchlan");
13968cfa0ad2SJack F Vogel 
13974edd8523SJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg);
13988cfa0ad2SJack F Vogel 	if (ret_val)
13998cfa0ad2SJack F Vogel 		goto out;
14008cfa0ad2SJack F Vogel 
14014edd8523SJack F Vogel 	if (active)
14024edd8523SJack F Vogel 		oem_reg |= HV_OEM_BITS_LPLU;
14034edd8523SJack F Vogel 	else
14044edd8523SJack F Vogel 		oem_reg &= ~HV_OEM_BITS_LPLU;
14058cfa0ad2SJack F Vogel 
14064edd8523SJack F Vogel 	oem_reg |= HV_OEM_BITS_RESTART_AN;
14074edd8523SJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg);
14088cfa0ad2SJack F Vogel 
14098cfa0ad2SJack F Vogel out:
14108cfa0ad2SJack F Vogel 	return ret_val;
14118cfa0ad2SJack F Vogel }
14128cfa0ad2SJack F Vogel 
14138cfa0ad2SJack F Vogel /**
14148cfa0ad2SJack F Vogel  *  e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
14158cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
14168cfa0ad2SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
14178cfa0ad2SJack F Vogel  *
14188cfa0ad2SJack F Vogel  *  Sets the LPLU D0 state according to the active flag.  When
14198cfa0ad2SJack F Vogel  *  activating LPLU this function also disables smart speed
14208cfa0ad2SJack F Vogel  *  and vice versa.  LPLU will not be activated unless the
14218cfa0ad2SJack F Vogel  *  device autonegotiation advertisement meets standards of
14228cfa0ad2SJack F Vogel  *  either 10 or 10/100 or 10/100/1000 at all duplexes.
14238cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
14248cfa0ad2SJack F Vogel  *  PHY setup routines.
14258cfa0ad2SJack F Vogel  **/
1426daf9197cSJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
14278cfa0ad2SJack F Vogel {
14288cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
14298cfa0ad2SJack F Vogel 	u32 phy_ctrl;
14308cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
14318cfa0ad2SJack F Vogel 	u16 data;
14328cfa0ad2SJack F Vogel 
14338cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan");
14348cfa0ad2SJack F Vogel 
14358cfa0ad2SJack F Vogel 	if (phy->type == e1000_phy_ife)
14368cfa0ad2SJack F Vogel 		goto out;
14378cfa0ad2SJack F Vogel 
14388cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
14398cfa0ad2SJack F Vogel 
14408cfa0ad2SJack F Vogel 	if (active) {
14418cfa0ad2SJack F Vogel 		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
14428cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
14438cfa0ad2SJack F Vogel 
14449d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
14459d81738fSJack F Vogel 			goto out;
14469d81738fSJack F Vogel 
14478cfa0ad2SJack F Vogel 		/*
14488cfa0ad2SJack F Vogel 		 * Call gig speed drop workaround on LPLU before accessing
14498cfa0ad2SJack F Vogel 		 * any PHY registers
14508cfa0ad2SJack F Vogel 		 */
14519d81738fSJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
14528cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
14538cfa0ad2SJack F Vogel 
14548cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
14558cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw,
14568cfa0ad2SJack F Vogel 		                            IGP01E1000_PHY_PORT_CONFIG,
14578cfa0ad2SJack F Vogel 		                            &data);
14588cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
14598cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
14608cfa0ad2SJack F Vogel 		                             IGP01E1000_PHY_PORT_CONFIG,
14618cfa0ad2SJack F Vogel 		                             data);
14628cfa0ad2SJack F Vogel 		if (ret_val)
14638cfa0ad2SJack F Vogel 			goto out;
14648cfa0ad2SJack F Vogel 	} else {
14658cfa0ad2SJack F Vogel 		phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
14668cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
14678cfa0ad2SJack F Vogel 
14689d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
14699d81738fSJack F Vogel 			goto out;
14709d81738fSJack F Vogel 
14718cfa0ad2SJack F Vogel 		/*
14728cfa0ad2SJack F Vogel 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
14738cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
14748cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
14758cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
14768cfa0ad2SJack F Vogel 		 */
14778cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
14788cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
14798cfa0ad2SJack F Vogel 			                            IGP01E1000_PHY_PORT_CONFIG,
14808cfa0ad2SJack F Vogel 			                            &data);
14818cfa0ad2SJack F Vogel 			if (ret_val)
14828cfa0ad2SJack F Vogel 				goto out;
14838cfa0ad2SJack F Vogel 
14848cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
14858cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
14868cfa0ad2SJack F Vogel 			                             IGP01E1000_PHY_PORT_CONFIG,
14878cfa0ad2SJack F Vogel 			                             data);
14888cfa0ad2SJack F Vogel 			if (ret_val)
14898cfa0ad2SJack F Vogel 				goto out;
14908cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
14918cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
14928cfa0ad2SJack F Vogel 			                            IGP01E1000_PHY_PORT_CONFIG,
14938cfa0ad2SJack F Vogel 			                            &data);
14948cfa0ad2SJack F Vogel 			if (ret_val)
14958cfa0ad2SJack F Vogel 				goto out;
14968cfa0ad2SJack F Vogel 
14978cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
14988cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
14998cfa0ad2SJack F Vogel 			                             IGP01E1000_PHY_PORT_CONFIG,
15008cfa0ad2SJack F Vogel 			                             data);
15018cfa0ad2SJack F Vogel 			if (ret_val)
15028cfa0ad2SJack F Vogel 				goto out;
15038cfa0ad2SJack F Vogel 		}
15048cfa0ad2SJack F Vogel 	}
15058cfa0ad2SJack F Vogel 
15068cfa0ad2SJack F Vogel out:
15078cfa0ad2SJack F Vogel 	return ret_val;
15088cfa0ad2SJack F Vogel }
15098cfa0ad2SJack F Vogel 
15108cfa0ad2SJack F Vogel /**
15118cfa0ad2SJack F Vogel  *  e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
15128cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
15138cfa0ad2SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
15148cfa0ad2SJack F Vogel  *
15158cfa0ad2SJack F Vogel  *  Sets the LPLU D3 state according to the active flag.  When
15168cfa0ad2SJack F Vogel  *  activating LPLU this function also disables smart speed
15178cfa0ad2SJack F Vogel  *  and vice versa.  LPLU will not be activated unless the
15188cfa0ad2SJack F Vogel  *  device autonegotiation advertisement meets standards of
15198cfa0ad2SJack F Vogel  *  either 10 or 10/100 or 10/100/1000 at all duplexes.
15208cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
15218cfa0ad2SJack F Vogel  *  PHY setup routines.
15228cfa0ad2SJack F Vogel  **/
1523daf9197cSJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
15248cfa0ad2SJack F Vogel {
15258cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
15268cfa0ad2SJack F Vogel 	u32 phy_ctrl;
15278cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
15288cfa0ad2SJack F Vogel 	u16 data;
15298cfa0ad2SJack F Vogel 
15308cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan");
15318cfa0ad2SJack F Vogel 
15328cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
15338cfa0ad2SJack F Vogel 
15348cfa0ad2SJack F Vogel 	if (!active) {
15358cfa0ad2SJack F Vogel 		phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
15368cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
15379d81738fSJack F Vogel 
15389d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
15399d81738fSJack F Vogel 			goto out;
15409d81738fSJack F Vogel 
15418cfa0ad2SJack F Vogel 		/*
15428cfa0ad2SJack F Vogel 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
15438cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
15448cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
15458cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
15468cfa0ad2SJack F Vogel 		 */
15478cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
15488cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
15498cfa0ad2SJack F Vogel 			                            IGP01E1000_PHY_PORT_CONFIG,
15508cfa0ad2SJack F Vogel 			                            &data);
15518cfa0ad2SJack F Vogel 			if (ret_val)
15528cfa0ad2SJack F Vogel 				goto out;
15538cfa0ad2SJack F Vogel 
15548cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
15558cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
15568cfa0ad2SJack F Vogel 			                             IGP01E1000_PHY_PORT_CONFIG,
15578cfa0ad2SJack F Vogel 			                             data);
15588cfa0ad2SJack F Vogel 			if (ret_val)
15598cfa0ad2SJack F Vogel 				goto out;
15608cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
15618cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
15628cfa0ad2SJack F Vogel 			                            IGP01E1000_PHY_PORT_CONFIG,
15638cfa0ad2SJack F Vogel 			                            &data);
15648cfa0ad2SJack F Vogel 			if (ret_val)
15658cfa0ad2SJack F Vogel 				goto out;
15668cfa0ad2SJack F Vogel 
15678cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
15688cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
15698cfa0ad2SJack F Vogel 			                             IGP01E1000_PHY_PORT_CONFIG,
15708cfa0ad2SJack F Vogel 			                             data);
15718cfa0ad2SJack F Vogel 			if (ret_val)
15728cfa0ad2SJack F Vogel 				goto out;
15738cfa0ad2SJack F Vogel 		}
15748cfa0ad2SJack F Vogel 	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
15758cfa0ad2SJack F Vogel 	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
15768cfa0ad2SJack F Vogel 	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
15778cfa0ad2SJack F Vogel 		phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
15788cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
15798cfa0ad2SJack F Vogel 
15809d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
15819d81738fSJack F Vogel 			goto out;
15829d81738fSJack F Vogel 
15838cfa0ad2SJack F Vogel 		/*
15848cfa0ad2SJack F Vogel 		 * Call gig speed drop workaround on LPLU before accessing
15858cfa0ad2SJack F Vogel 		 * any PHY registers
15868cfa0ad2SJack F Vogel 		 */
15879d81738fSJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
15888cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
15898cfa0ad2SJack F Vogel 
15908cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
15918cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw,
15928cfa0ad2SJack F Vogel 		                            IGP01E1000_PHY_PORT_CONFIG,
15938cfa0ad2SJack F Vogel 		                            &data);
15948cfa0ad2SJack F Vogel 		if (ret_val)
15958cfa0ad2SJack F Vogel 			goto out;
15968cfa0ad2SJack F Vogel 
15978cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
15988cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
15998cfa0ad2SJack F Vogel 		                             IGP01E1000_PHY_PORT_CONFIG,
16008cfa0ad2SJack F Vogel 		                             data);
16018cfa0ad2SJack F Vogel 	}
16028cfa0ad2SJack F Vogel 
16038cfa0ad2SJack F Vogel out:
16048cfa0ad2SJack F Vogel 	return ret_val;
16058cfa0ad2SJack F Vogel }
16068cfa0ad2SJack F Vogel 
16078cfa0ad2SJack F Vogel /**
16088cfa0ad2SJack F Vogel  *  e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
16098cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
16108cfa0ad2SJack F Vogel  *  @bank:  pointer to the variable that returns the active bank
16118cfa0ad2SJack F Vogel  *
16128cfa0ad2SJack F Vogel  *  Reads signature byte from the NVM using the flash access registers.
1613d035aa2dSJack F Vogel  *  Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
16148cfa0ad2SJack F Vogel  **/
16158cfa0ad2SJack F Vogel static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
16168cfa0ad2SJack F Vogel {
1617d035aa2dSJack F Vogel 	u32 eecd;
16188cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
16198cfa0ad2SJack F Vogel 	u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
16208cfa0ad2SJack F Vogel 	u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
1621d035aa2dSJack F Vogel 	u8 sig_byte = 0;
1622d035aa2dSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
16238cfa0ad2SJack F Vogel 
1624d035aa2dSJack F Vogel 	switch (hw->mac.type) {
1625d035aa2dSJack F Vogel 	case e1000_ich8lan:
1626d035aa2dSJack F Vogel 	case e1000_ich9lan:
1627d035aa2dSJack F Vogel 		eecd = E1000_READ_REG(hw, E1000_EECD);
1628d035aa2dSJack F Vogel 		if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
1629d035aa2dSJack F Vogel 		    E1000_EECD_SEC1VAL_VALID_MASK) {
1630d035aa2dSJack F Vogel 			if (eecd & E1000_EECD_SEC1VAL)
16318cfa0ad2SJack F Vogel 				*bank = 1;
16328cfa0ad2SJack F Vogel 			else
16338cfa0ad2SJack F Vogel 				*bank = 0;
1634d035aa2dSJack F Vogel 
1635d035aa2dSJack F Vogel 			goto out;
1636d035aa2dSJack F Vogel 		}
1637d035aa2dSJack F Vogel 		DEBUGOUT("Unable to determine valid NVM bank via EEC - "
1638d035aa2dSJack F Vogel 		         "reading flash signature\n");
1639d035aa2dSJack F Vogel 		/* fall-thru */
1640d035aa2dSJack F Vogel 	default:
1641d035aa2dSJack F Vogel 		/* set bank to 0 in case flash read fails */
16428cfa0ad2SJack F Vogel 		*bank = 0;
16438cfa0ad2SJack F Vogel 
1644d035aa2dSJack F Vogel 		/* Check bank 0 */
1645d035aa2dSJack F Vogel 		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
1646d035aa2dSJack F Vogel 		                                        &sig_byte);
1647d035aa2dSJack F Vogel 		if (ret_val)
1648d035aa2dSJack F Vogel 			goto out;
1649d035aa2dSJack F Vogel 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
1650d035aa2dSJack F Vogel 		    E1000_ICH_NVM_SIG_VALUE) {
1651d035aa2dSJack F Vogel 			*bank = 0;
1652d035aa2dSJack F Vogel 			goto out;
1653d035aa2dSJack F Vogel 		}
1654d035aa2dSJack F Vogel 
1655d035aa2dSJack F Vogel 		/* Check bank 1 */
1656d035aa2dSJack F Vogel 		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
1657d035aa2dSJack F Vogel 		                                        bank1_offset,
1658d035aa2dSJack F Vogel 		                                        &sig_byte);
1659d035aa2dSJack F Vogel 		if (ret_val)
1660d035aa2dSJack F Vogel 			goto out;
1661d035aa2dSJack F Vogel 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
1662d035aa2dSJack F Vogel 		    E1000_ICH_NVM_SIG_VALUE) {
16638cfa0ad2SJack F Vogel 			*bank = 1;
1664d035aa2dSJack F Vogel 			goto out;
16658cfa0ad2SJack F Vogel 		}
16668cfa0ad2SJack F Vogel 
1667d035aa2dSJack F Vogel 		DEBUGOUT("ERROR: No valid NVM bank present\n");
1668d035aa2dSJack F Vogel 		ret_val = -E1000_ERR_NVM;
1669d035aa2dSJack F Vogel 		break;
1670d035aa2dSJack F Vogel 	}
1671d035aa2dSJack F Vogel out:
16728cfa0ad2SJack F Vogel 	return ret_val;
16738cfa0ad2SJack F Vogel }
16748cfa0ad2SJack F Vogel 
16758cfa0ad2SJack F Vogel /**
16768cfa0ad2SJack F Vogel  *  e1000_read_nvm_ich8lan - Read word(s) from the NVM
16778cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
16788cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the word(s) to read.
16798cfa0ad2SJack F Vogel  *  @words: Size of data to read in words
16808cfa0ad2SJack F Vogel  *  @data: Pointer to the word(s) to read at offset.
16818cfa0ad2SJack F Vogel  *
16828cfa0ad2SJack F Vogel  *  Reads a word(s) from the NVM using the flash access registers.
16838cfa0ad2SJack F Vogel  **/
16848cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
16858cfa0ad2SJack F Vogel                                   u16 *data)
16868cfa0ad2SJack F Vogel {
16878cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
1688daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
16898cfa0ad2SJack F Vogel 	u32 act_offset;
16908cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
16918cfa0ad2SJack F Vogel 	u32 bank = 0;
16928cfa0ad2SJack F Vogel 	u16 i, word;
16938cfa0ad2SJack F Vogel 
16948cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_nvm_ich8lan");
16958cfa0ad2SJack F Vogel 
16968cfa0ad2SJack F Vogel 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
16978cfa0ad2SJack F Vogel 	    (words == 0)) {
16988cfa0ad2SJack F Vogel 		DEBUGOUT("nvm parameter(s) out of bounds\n");
16998cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
17008cfa0ad2SJack F Vogel 		goto out;
17018cfa0ad2SJack F Vogel 	}
17028cfa0ad2SJack F Vogel 
17034edd8523SJack F Vogel 	nvm->ops.acquire(hw);
17048cfa0ad2SJack F Vogel 
17058cfa0ad2SJack F Vogel 	ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
17064edd8523SJack F Vogel 	if (ret_val != E1000_SUCCESS) {
17074edd8523SJack F Vogel 		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
17084edd8523SJack F Vogel 		bank = 0;
17094edd8523SJack F Vogel 	}
17108cfa0ad2SJack F Vogel 
17118cfa0ad2SJack F Vogel 	act_offset = (bank) ? nvm->flash_bank_size : 0;
17128cfa0ad2SJack F Vogel 	act_offset += offset;
17138cfa0ad2SJack F Vogel 
17144edd8523SJack F Vogel 	ret_val = E1000_SUCCESS;
17158cfa0ad2SJack F Vogel 	for (i = 0; i < words; i++) {
17168cfa0ad2SJack F Vogel 		if ((dev_spec->shadow_ram) &&
17178cfa0ad2SJack F Vogel 		    (dev_spec->shadow_ram[offset+i].modified)) {
17188cfa0ad2SJack F Vogel 			data[i] = dev_spec->shadow_ram[offset+i].value;
17198cfa0ad2SJack F Vogel 		} else {
17208cfa0ad2SJack F Vogel 			ret_val = e1000_read_flash_word_ich8lan(hw,
17218cfa0ad2SJack F Vogel 			                                        act_offset + i,
17228cfa0ad2SJack F Vogel 			                                        &word);
17238cfa0ad2SJack F Vogel 			if (ret_val)
17248cfa0ad2SJack F Vogel 				break;
17258cfa0ad2SJack F Vogel 			data[i] = word;
17268cfa0ad2SJack F Vogel 		}
17278cfa0ad2SJack F Vogel 	}
17288cfa0ad2SJack F Vogel 
17298cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
17308cfa0ad2SJack F Vogel 
17318cfa0ad2SJack F Vogel out:
1732d035aa2dSJack F Vogel 	if (ret_val)
1733d035aa2dSJack F Vogel 		DEBUGOUT1("NVM read error: %d\n", ret_val);
1734d035aa2dSJack F Vogel 
17358cfa0ad2SJack F Vogel 	return ret_val;
17368cfa0ad2SJack F Vogel }
17378cfa0ad2SJack F Vogel 
17388cfa0ad2SJack F Vogel /**
17398cfa0ad2SJack F Vogel  *  e1000_flash_cycle_init_ich8lan - Initialize flash
17408cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
17418cfa0ad2SJack F Vogel  *
17428cfa0ad2SJack F Vogel  *  This function does initial flash setup so that a new read/write/erase cycle
17438cfa0ad2SJack F Vogel  *  can be started.
17448cfa0ad2SJack F Vogel  **/
17458cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
17468cfa0ad2SJack F Vogel {
17478cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
17488cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
17498cfa0ad2SJack F Vogel 	s32 i = 0;
17508cfa0ad2SJack F Vogel 
17518cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_flash_cycle_init_ich8lan");
17528cfa0ad2SJack F Vogel 
17538cfa0ad2SJack F Vogel 	hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
17548cfa0ad2SJack F Vogel 
17558cfa0ad2SJack F Vogel 	/* Check if the flash descriptor is valid */
17568cfa0ad2SJack F Vogel 	if (hsfsts.hsf_status.fldesvalid == 0) {
17578cfa0ad2SJack F Vogel 		DEBUGOUT("Flash descriptor invalid.  "
17588cfa0ad2SJack F Vogel 		         "SW Sequencing must be used.");
17598cfa0ad2SJack F Vogel 		goto out;
17608cfa0ad2SJack F Vogel 	}
17618cfa0ad2SJack F Vogel 
17628cfa0ad2SJack F Vogel 	/* Clear FCERR and DAEL in hw status by writing 1 */
17638cfa0ad2SJack F Vogel 	hsfsts.hsf_status.flcerr = 1;
17648cfa0ad2SJack F Vogel 	hsfsts.hsf_status.dael = 1;
17658cfa0ad2SJack F Vogel 
17668cfa0ad2SJack F Vogel 	E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
17678cfa0ad2SJack F Vogel 
17688cfa0ad2SJack F Vogel 	/*
17698cfa0ad2SJack F Vogel 	 * Either we should have a hardware SPI cycle in progress
17708cfa0ad2SJack F Vogel 	 * bit to check against, in order to start a new cycle or
17718cfa0ad2SJack F Vogel 	 * FDONE bit should be changed in the hardware so that it
17728cfa0ad2SJack F Vogel 	 * is 1 after hardware reset, which can then be used as an
17738cfa0ad2SJack F Vogel 	 * indication whether a cycle is in progress or has been
17748cfa0ad2SJack F Vogel 	 * completed.
17758cfa0ad2SJack F Vogel 	 */
17768cfa0ad2SJack F Vogel 
17778cfa0ad2SJack F Vogel 	if (hsfsts.hsf_status.flcinprog == 0) {
17788cfa0ad2SJack F Vogel 		/*
17798cfa0ad2SJack F Vogel 		 * There is no cycle running at present,
17808cfa0ad2SJack F Vogel 		 * so we can start a cycle.
17818cfa0ad2SJack F Vogel 		 * Begin by setting Flash Cycle Done.
17828cfa0ad2SJack F Vogel 		 */
17838cfa0ad2SJack F Vogel 		hsfsts.hsf_status.flcdone = 1;
17848cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
17858cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
17868cfa0ad2SJack F Vogel 	} else {
17878cfa0ad2SJack F Vogel 		/*
17888cfa0ad2SJack F Vogel 		 * Otherwise poll for sometime so the current
17898cfa0ad2SJack F Vogel 		 * cycle has a chance to end before giving up.
17908cfa0ad2SJack F Vogel 		 */
17918cfa0ad2SJack F Vogel 		for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
17928cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
17938cfa0ad2SJack F Vogel 			                                      ICH_FLASH_HSFSTS);
17948cfa0ad2SJack F Vogel 			if (hsfsts.hsf_status.flcinprog == 0) {
17958cfa0ad2SJack F Vogel 				ret_val = E1000_SUCCESS;
17968cfa0ad2SJack F Vogel 				break;
17978cfa0ad2SJack F Vogel 			}
17988cfa0ad2SJack F Vogel 			usec_delay(1);
17998cfa0ad2SJack F Vogel 		}
18008cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS) {
18018cfa0ad2SJack F Vogel 			/*
18028cfa0ad2SJack F Vogel 			 * Successful in waiting for previous cycle to timeout,
18038cfa0ad2SJack F Vogel 			 * now set the Flash Cycle Done.
18048cfa0ad2SJack F Vogel 			 */
18058cfa0ad2SJack F Vogel 			hsfsts.hsf_status.flcdone = 1;
1806daf9197cSJack F Vogel 			E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
18078cfa0ad2SJack F Vogel 			                        hsfsts.regval);
18088cfa0ad2SJack F Vogel 		} else {
18098cfa0ad2SJack F Vogel 			DEBUGOUT("Flash controller busy, cannot get access");
18108cfa0ad2SJack F Vogel 		}
18118cfa0ad2SJack F Vogel 	}
18128cfa0ad2SJack F Vogel 
18138cfa0ad2SJack F Vogel out:
18148cfa0ad2SJack F Vogel 	return ret_val;
18158cfa0ad2SJack F Vogel }
18168cfa0ad2SJack F Vogel 
18178cfa0ad2SJack F Vogel /**
18188cfa0ad2SJack F Vogel  *  e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
18198cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
18208cfa0ad2SJack F Vogel  *  @timeout: maximum time to wait for completion
18218cfa0ad2SJack F Vogel  *
18228cfa0ad2SJack F Vogel  *  This function starts a flash cycle and waits for its completion.
18238cfa0ad2SJack F Vogel  **/
18248cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
18258cfa0ad2SJack F Vogel {
18268cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
18278cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
18288cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
18298cfa0ad2SJack F Vogel 	u32 i = 0;
18308cfa0ad2SJack F Vogel 
18318cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_flash_cycle_ich8lan");
18328cfa0ad2SJack F Vogel 
18338cfa0ad2SJack F Vogel 	/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
18348cfa0ad2SJack F Vogel 	hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
18358cfa0ad2SJack F Vogel 	hsflctl.hsf_ctrl.flcgo = 1;
18368cfa0ad2SJack F Vogel 	E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
18378cfa0ad2SJack F Vogel 
18388cfa0ad2SJack F Vogel 	/* wait till FDONE bit is set to 1 */
18398cfa0ad2SJack F Vogel 	do {
18408cfa0ad2SJack F Vogel 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
18418cfa0ad2SJack F Vogel 		if (hsfsts.hsf_status.flcdone == 1)
18428cfa0ad2SJack F Vogel 			break;
18438cfa0ad2SJack F Vogel 		usec_delay(1);
18448cfa0ad2SJack F Vogel 	} while (i++ < timeout);
18458cfa0ad2SJack F Vogel 
18468cfa0ad2SJack F Vogel 	if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
18478cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
18488cfa0ad2SJack F Vogel 
18498cfa0ad2SJack F Vogel 	return ret_val;
18508cfa0ad2SJack F Vogel }
18518cfa0ad2SJack F Vogel 
18528cfa0ad2SJack F Vogel /**
18538cfa0ad2SJack F Vogel  *  e1000_read_flash_word_ich8lan - Read word from flash
18548cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
18558cfa0ad2SJack F Vogel  *  @offset: offset to data location
18568cfa0ad2SJack F Vogel  *  @data: pointer to the location for storing the data
18578cfa0ad2SJack F Vogel  *
18588cfa0ad2SJack F Vogel  *  Reads the flash word at offset into data.  Offset is converted
18598cfa0ad2SJack F Vogel  *  to bytes before read.
18608cfa0ad2SJack F Vogel  **/
18618cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
18628cfa0ad2SJack F Vogel                                          u16 *data)
18638cfa0ad2SJack F Vogel {
18648cfa0ad2SJack F Vogel 	s32 ret_val;
18658cfa0ad2SJack F Vogel 
18668cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_flash_word_ich8lan");
18678cfa0ad2SJack F Vogel 
18688cfa0ad2SJack F Vogel 	if (!data) {
18698cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
18708cfa0ad2SJack F Vogel 		goto out;
18718cfa0ad2SJack F Vogel 	}
18728cfa0ad2SJack F Vogel 
18738cfa0ad2SJack F Vogel 	/* Must convert offset into bytes. */
18748cfa0ad2SJack F Vogel 	offset <<= 1;
18758cfa0ad2SJack F Vogel 
18768cfa0ad2SJack F Vogel 	ret_val = e1000_read_flash_data_ich8lan(hw, offset, 2, data);
18778cfa0ad2SJack F Vogel 
18788cfa0ad2SJack F Vogel out:
18798cfa0ad2SJack F Vogel 	return ret_val;
18808cfa0ad2SJack F Vogel }
18818cfa0ad2SJack F Vogel 
18828cfa0ad2SJack F Vogel /**
18838cfa0ad2SJack F Vogel  *  e1000_read_flash_byte_ich8lan - Read byte from flash
18848cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
18858cfa0ad2SJack F Vogel  *  @offset: The offset of the byte to read.
18868cfa0ad2SJack F Vogel  *  @data: Pointer to a byte to store the value read.
18878cfa0ad2SJack F Vogel  *
18888cfa0ad2SJack F Vogel  *  Reads a single byte from the NVM using the flash access registers.
18898cfa0ad2SJack F Vogel  **/
18908cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
18918cfa0ad2SJack F Vogel                                          u8 *data)
18928cfa0ad2SJack F Vogel {
18938cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
18948cfa0ad2SJack F Vogel 	u16 word = 0;
18958cfa0ad2SJack F Vogel 
18968cfa0ad2SJack F Vogel 	ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
18978cfa0ad2SJack F Vogel 	if (ret_val)
18988cfa0ad2SJack F Vogel 		goto out;
18998cfa0ad2SJack F Vogel 
19008cfa0ad2SJack F Vogel 	*data = (u8)word;
19018cfa0ad2SJack F Vogel 
19028cfa0ad2SJack F Vogel out:
19038cfa0ad2SJack F Vogel 	return ret_val;
19048cfa0ad2SJack F Vogel }
19058cfa0ad2SJack F Vogel 
19068cfa0ad2SJack F Vogel /**
19078cfa0ad2SJack F Vogel  *  e1000_read_flash_data_ich8lan - Read byte or word from NVM
19088cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
19098cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the byte or word to read.
19108cfa0ad2SJack F Vogel  *  @size: Size of data to read, 1=byte 2=word
19118cfa0ad2SJack F Vogel  *  @data: Pointer to the word to store the value read.
19128cfa0ad2SJack F Vogel  *
19138cfa0ad2SJack F Vogel  *  Reads a byte or word from the NVM using the flash access registers.
19148cfa0ad2SJack F Vogel  **/
19158cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
19168cfa0ad2SJack F Vogel                                          u8 size, u16 *data)
19178cfa0ad2SJack F Vogel {
19188cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
19198cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
19208cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
19218cfa0ad2SJack F Vogel 	u32 flash_data = 0;
19228cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
19238cfa0ad2SJack F Vogel 	u8 count = 0;
19248cfa0ad2SJack F Vogel 
19258cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_flash_data_ich8lan");
19268cfa0ad2SJack F Vogel 
19278cfa0ad2SJack F Vogel 	if (size < 1  || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
19288cfa0ad2SJack F Vogel 		goto out;
19298cfa0ad2SJack F Vogel 
19308cfa0ad2SJack F Vogel 	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
19318cfa0ad2SJack F Vogel 	                    hw->nvm.flash_base_addr;
19328cfa0ad2SJack F Vogel 
19338cfa0ad2SJack F Vogel 	do {
19348cfa0ad2SJack F Vogel 		usec_delay(1);
19358cfa0ad2SJack F Vogel 		/* Steps */
19368cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
19378cfa0ad2SJack F Vogel 		if (ret_val != E1000_SUCCESS)
19388cfa0ad2SJack F Vogel 			break;
19398cfa0ad2SJack F Vogel 
19408cfa0ad2SJack F Vogel 		hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
19418cfa0ad2SJack F Vogel 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
19428cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.fldbcount = size - 1;
19438cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
19448cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
19458cfa0ad2SJack F Vogel 
19468cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
19478cfa0ad2SJack F Vogel 
19488cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_ich8lan(hw,
19498cfa0ad2SJack F Vogel 		                                ICH_FLASH_READ_COMMAND_TIMEOUT);
19508cfa0ad2SJack F Vogel 
19518cfa0ad2SJack F Vogel 		/*
19528cfa0ad2SJack F Vogel 		 * Check if FCERR is set to 1, if set to 1, clear it
19538cfa0ad2SJack F Vogel 		 * and try the whole sequence a few more times, else
19548cfa0ad2SJack F Vogel 		 * read in (shift in) the Flash Data0, the order is
19558cfa0ad2SJack F Vogel 		 * least significant byte first msb to lsb
19568cfa0ad2SJack F Vogel 		 */
19578cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS) {
19588cfa0ad2SJack F Vogel 			flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
1959daf9197cSJack F Vogel 			if (size == 1)
19608cfa0ad2SJack F Vogel 				*data = (u8)(flash_data & 0x000000FF);
1961daf9197cSJack F Vogel 			else if (size == 2)
19628cfa0ad2SJack F Vogel 				*data = (u16)(flash_data & 0x0000FFFF);
19638cfa0ad2SJack F Vogel 			break;
19648cfa0ad2SJack F Vogel 		} else {
19658cfa0ad2SJack F Vogel 			/*
19668cfa0ad2SJack F Vogel 			 * If we've gotten here, then things are probably
19678cfa0ad2SJack F Vogel 			 * completely hosed, but if the error condition is
19688cfa0ad2SJack F Vogel 			 * detected, it won't hurt to give it another try...
19698cfa0ad2SJack F Vogel 			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
19708cfa0ad2SJack F Vogel 			 */
19718cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
19728cfa0ad2SJack F Vogel 			                                      ICH_FLASH_HSFSTS);
19738cfa0ad2SJack F Vogel 			if (hsfsts.hsf_status.flcerr == 1) {
19748cfa0ad2SJack F Vogel 				/* Repeat for some time before giving up. */
19758cfa0ad2SJack F Vogel 				continue;
19768cfa0ad2SJack F Vogel 			} else if (hsfsts.hsf_status.flcdone == 0) {
19778cfa0ad2SJack F Vogel 				DEBUGOUT("Timeout error - flash cycle "
19788cfa0ad2SJack F Vogel 				         "did not complete.");
19798cfa0ad2SJack F Vogel 				break;
19808cfa0ad2SJack F Vogel 			}
19818cfa0ad2SJack F Vogel 		}
19828cfa0ad2SJack F Vogel 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
19838cfa0ad2SJack F Vogel 
19848cfa0ad2SJack F Vogel out:
19858cfa0ad2SJack F Vogel 	return ret_val;
19868cfa0ad2SJack F Vogel }
19878cfa0ad2SJack F Vogel 
19888cfa0ad2SJack F Vogel /**
19898cfa0ad2SJack F Vogel  *  e1000_write_nvm_ich8lan - Write word(s) to the NVM
19908cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
19918cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the word(s) to write.
19928cfa0ad2SJack F Vogel  *  @words: Size of data to write in words
19938cfa0ad2SJack F Vogel  *  @data: Pointer to the word(s) to write at offset.
19948cfa0ad2SJack F Vogel  *
19958cfa0ad2SJack F Vogel  *  Writes a byte or word to the NVM using the flash access registers.
19968cfa0ad2SJack F Vogel  **/
19978cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
19988cfa0ad2SJack F Vogel                                    u16 *data)
19998cfa0ad2SJack F Vogel {
20008cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
2001daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
20028cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
20038cfa0ad2SJack F Vogel 	u16 i;
20048cfa0ad2SJack F Vogel 
20058cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_nvm_ich8lan");
20068cfa0ad2SJack F Vogel 
20078cfa0ad2SJack F Vogel 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
20088cfa0ad2SJack F Vogel 	    (words == 0)) {
20098cfa0ad2SJack F Vogel 		DEBUGOUT("nvm parameter(s) out of bounds\n");
20108cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
20118cfa0ad2SJack F Vogel 		goto out;
20128cfa0ad2SJack F Vogel 	}
20138cfa0ad2SJack F Vogel 
20144edd8523SJack F Vogel 	nvm->ops.acquire(hw);
20158cfa0ad2SJack F Vogel 
20168cfa0ad2SJack F Vogel 	for (i = 0; i < words; i++) {
20178cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[offset+i].modified = TRUE;
20188cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[offset+i].value = data[i];
20198cfa0ad2SJack F Vogel 	}
20208cfa0ad2SJack F Vogel 
20218cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
20228cfa0ad2SJack F Vogel 
20238cfa0ad2SJack F Vogel out:
20248cfa0ad2SJack F Vogel 	return ret_val;
20258cfa0ad2SJack F Vogel }
20268cfa0ad2SJack F Vogel 
20278cfa0ad2SJack F Vogel /**
20288cfa0ad2SJack F Vogel  *  e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
20298cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
20308cfa0ad2SJack F Vogel  *
20318cfa0ad2SJack F Vogel  *  The NVM checksum is updated by calling the generic update_nvm_checksum,
20328cfa0ad2SJack F Vogel  *  which writes the checksum to the shadow ram.  The changes in the shadow
20338cfa0ad2SJack F Vogel  *  ram are then committed to the EEPROM by processing each bank at a time
20348cfa0ad2SJack F Vogel  *  checking for the modified bit and writing only the pending changes.
20358cfa0ad2SJack F Vogel  *  After a successful commit, the shadow ram is cleared and is ready for
20368cfa0ad2SJack F Vogel  *  future writes.
20378cfa0ad2SJack F Vogel  **/
20388cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
20398cfa0ad2SJack F Vogel {
20408cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
2041daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
20428cfa0ad2SJack F Vogel 	u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
20438cfa0ad2SJack F Vogel 	s32 ret_val;
20448cfa0ad2SJack F Vogel 	u16 data;
20458cfa0ad2SJack F Vogel 
20468cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_update_nvm_checksum_ich8lan");
20478cfa0ad2SJack F Vogel 
20488cfa0ad2SJack F Vogel 	ret_val = e1000_update_nvm_checksum_generic(hw);
20498cfa0ad2SJack F Vogel 	if (ret_val)
20508cfa0ad2SJack F Vogel 		goto out;
20518cfa0ad2SJack F Vogel 
20528cfa0ad2SJack F Vogel 	if (nvm->type != e1000_nvm_flash_sw)
20538cfa0ad2SJack F Vogel 		goto out;
20548cfa0ad2SJack F Vogel 
20554edd8523SJack F Vogel 	nvm->ops.acquire(hw);
20568cfa0ad2SJack F Vogel 
20578cfa0ad2SJack F Vogel 	/*
20588cfa0ad2SJack F Vogel 	 * We're writing to the opposite bank so if we're on bank 1,
20598cfa0ad2SJack F Vogel 	 * write to bank 0 etc.  We also need to erase the segment that
20608cfa0ad2SJack F Vogel 	 * is going to be written
20618cfa0ad2SJack F Vogel 	 */
20628cfa0ad2SJack F Vogel 	ret_val =  e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
2063d035aa2dSJack F Vogel 	if (ret_val != E1000_SUCCESS) {
20644edd8523SJack F Vogel 		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
20654edd8523SJack F Vogel 		bank = 0;
2066d035aa2dSJack F Vogel 	}
20678cfa0ad2SJack F Vogel 
20688cfa0ad2SJack F Vogel 	if (bank == 0) {
20698cfa0ad2SJack F Vogel 		new_bank_offset = nvm->flash_bank_size;
20708cfa0ad2SJack F Vogel 		old_bank_offset = 0;
2071d035aa2dSJack F Vogel 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
2072a69ed8dfSJack F Vogel 		if (ret_val)
2073a69ed8dfSJack F Vogel 			goto release;
20748cfa0ad2SJack F Vogel 	} else {
20758cfa0ad2SJack F Vogel 		old_bank_offset = nvm->flash_bank_size;
20768cfa0ad2SJack F Vogel 		new_bank_offset = 0;
2077d035aa2dSJack F Vogel 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
2078a69ed8dfSJack F Vogel 		if (ret_val)
2079a69ed8dfSJack F Vogel 			goto release;
20808cfa0ad2SJack F Vogel 	}
20818cfa0ad2SJack F Vogel 
20828cfa0ad2SJack F Vogel 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
20838cfa0ad2SJack F Vogel 		/*
20848cfa0ad2SJack F Vogel 		 * Determine whether to write the value stored
20858cfa0ad2SJack F Vogel 		 * in the other NVM bank or a modified value stored
20868cfa0ad2SJack F Vogel 		 * in the shadow RAM
20878cfa0ad2SJack F Vogel 		 */
20888cfa0ad2SJack F Vogel 		if (dev_spec->shadow_ram[i].modified) {
20898cfa0ad2SJack F Vogel 			data = dev_spec->shadow_ram[i].value;
20908cfa0ad2SJack F Vogel 		} else {
2091d035aa2dSJack F Vogel 			ret_val = e1000_read_flash_word_ich8lan(hw, i +
2092d035aa2dSJack F Vogel 			                                        old_bank_offset,
20938cfa0ad2SJack F Vogel 			                                        &data);
2094d035aa2dSJack F Vogel 			if (ret_val)
2095d035aa2dSJack F Vogel 				break;
20968cfa0ad2SJack F Vogel 		}
20978cfa0ad2SJack F Vogel 
20988cfa0ad2SJack F Vogel 		/*
20998cfa0ad2SJack F Vogel 		 * If the word is 0x13, then make sure the signature bits
21008cfa0ad2SJack F Vogel 		 * (15:14) are 11b until the commit has completed.
21018cfa0ad2SJack F Vogel 		 * This will allow us to write 10b which indicates the
21028cfa0ad2SJack F Vogel 		 * signature is valid.  We want to do this after the write
21038cfa0ad2SJack F Vogel 		 * has completed so that we don't mark the segment valid
21048cfa0ad2SJack F Vogel 		 * while the write is still in progress
21058cfa0ad2SJack F Vogel 		 */
21068cfa0ad2SJack F Vogel 		if (i == E1000_ICH_NVM_SIG_WORD)
21078cfa0ad2SJack F Vogel 			data |= E1000_ICH_NVM_SIG_MASK;
21088cfa0ad2SJack F Vogel 
21098cfa0ad2SJack F Vogel 		/* Convert offset to bytes. */
21108cfa0ad2SJack F Vogel 		act_offset = (i + new_bank_offset) << 1;
21118cfa0ad2SJack F Vogel 
21128cfa0ad2SJack F Vogel 		usec_delay(100);
21138cfa0ad2SJack F Vogel 		/* Write the bytes to the new bank. */
21148cfa0ad2SJack F Vogel 		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
21158cfa0ad2SJack F Vogel 		                                               act_offset,
21168cfa0ad2SJack F Vogel 		                                               (u8)data);
21178cfa0ad2SJack F Vogel 		if (ret_val)
21188cfa0ad2SJack F Vogel 			break;
21198cfa0ad2SJack F Vogel 
21208cfa0ad2SJack F Vogel 		usec_delay(100);
21218cfa0ad2SJack F Vogel 		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
21228cfa0ad2SJack F Vogel 		                                          act_offset + 1,
21238cfa0ad2SJack F Vogel 		                                          (u8)(data >> 8));
21248cfa0ad2SJack F Vogel 		if (ret_val)
21258cfa0ad2SJack F Vogel 			break;
21268cfa0ad2SJack F Vogel 	}
21278cfa0ad2SJack F Vogel 
21288cfa0ad2SJack F Vogel 	/*
21298cfa0ad2SJack F Vogel 	 * Don't bother writing the segment valid bits if sector
21308cfa0ad2SJack F Vogel 	 * programming failed.
21318cfa0ad2SJack F Vogel 	 */
21328cfa0ad2SJack F Vogel 	if (ret_val) {
21338cfa0ad2SJack F Vogel 		DEBUGOUT("Flash commit failed.\n");
2134a69ed8dfSJack F Vogel 		goto release;
21358cfa0ad2SJack F Vogel 	}
21368cfa0ad2SJack F Vogel 
21378cfa0ad2SJack F Vogel 	/*
21388cfa0ad2SJack F Vogel 	 * Finally validate the new segment by setting bit 15:14
21398cfa0ad2SJack F Vogel 	 * to 10b in word 0x13 , this can be done without an
21408cfa0ad2SJack F Vogel 	 * erase as well since these bits are 11 to start with
21418cfa0ad2SJack F Vogel 	 * and we need to change bit 14 to 0b
21428cfa0ad2SJack F Vogel 	 */
21438cfa0ad2SJack F Vogel 	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
2144d035aa2dSJack F Vogel 	ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
2145a69ed8dfSJack F Vogel 	if (ret_val)
2146a69ed8dfSJack F Vogel 		goto release;
21474edd8523SJack F Vogel 
21488cfa0ad2SJack F Vogel 	data &= 0xBFFF;
21498cfa0ad2SJack F Vogel 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
21508cfa0ad2SJack F Vogel 	                                               act_offset * 2 + 1,
21518cfa0ad2SJack F Vogel 	                                               (u8)(data >> 8));
2152a69ed8dfSJack F Vogel 	if (ret_val)
2153a69ed8dfSJack F Vogel 		goto release;
21548cfa0ad2SJack F Vogel 
21558cfa0ad2SJack F Vogel 	/*
21568cfa0ad2SJack F Vogel 	 * And invalidate the previously valid segment by setting
21578cfa0ad2SJack F Vogel 	 * its signature word (0x13) high_byte to 0b. This can be
21588cfa0ad2SJack F Vogel 	 * done without an erase because flash erase sets all bits
21598cfa0ad2SJack F Vogel 	 * to 1's. We can write 1's to 0's without an erase
21608cfa0ad2SJack F Vogel 	 */
21618cfa0ad2SJack F Vogel 	act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
21628cfa0ad2SJack F Vogel 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
2163a69ed8dfSJack F Vogel 	if (ret_val)
2164a69ed8dfSJack F Vogel 		goto release;
21658cfa0ad2SJack F Vogel 
21668cfa0ad2SJack F Vogel 	/* Great!  Everything worked, we can now clear the cached entries. */
21678cfa0ad2SJack F Vogel 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
21688cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].modified = FALSE;
21698cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].value = 0xFFFF;
21708cfa0ad2SJack F Vogel 	}
21718cfa0ad2SJack F Vogel 
2172a69ed8dfSJack F Vogel release:
21738cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
21748cfa0ad2SJack F Vogel 
21758cfa0ad2SJack F Vogel 	/*
21768cfa0ad2SJack F Vogel 	 * Reload the EEPROM, or else modifications will not appear
21778cfa0ad2SJack F Vogel 	 * until after the next adapter reset.
21788cfa0ad2SJack F Vogel 	 */
2179a69ed8dfSJack F Vogel 	if (!ret_val) {
21808cfa0ad2SJack F Vogel 		nvm->ops.reload(hw);
21818cfa0ad2SJack F Vogel 		msec_delay(10);
2182a69ed8dfSJack F Vogel 	}
21838cfa0ad2SJack F Vogel 
21848cfa0ad2SJack F Vogel out:
2185d035aa2dSJack F Vogel 	if (ret_val)
2186d035aa2dSJack F Vogel 		DEBUGOUT1("NVM update error: %d\n", ret_val);
2187d035aa2dSJack F Vogel 
21888cfa0ad2SJack F Vogel 	return ret_val;
21898cfa0ad2SJack F Vogel }
21908cfa0ad2SJack F Vogel 
21918cfa0ad2SJack F Vogel /**
21928cfa0ad2SJack F Vogel  *  e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
21938cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
21948cfa0ad2SJack F Vogel  *
21958cfa0ad2SJack F Vogel  *  Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
2196daf9197cSJack F Vogel  *  If the bit is 0, that the EEPROM had been modified, but the checksum was not
2197daf9197cSJack F Vogel  *  calculated, in which case we need to calculate the checksum and set bit 6.
21988cfa0ad2SJack F Vogel  **/
21998cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
22008cfa0ad2SJack F Vogel {
22018cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
22028cfa0ad2SJack F Vogel 	u16 data;
22038cfa0ad2SJack F Vogel 
22048cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan");
22058cfa0ad2SJack F Vogel 
22068cfa0ad2SJack F Vogel 	/*
22078cfa0ad2SJack F Vogel 	 * Read 0x19 and check bit 6.  If this bit is 0, the checksum
22088cfa0ad2SJack F Vogel 	 * needs to be fixed.  This bit is an indication that the NVM
22098cfa0ad2SJack F Vogel 	 * was prepared by OEM software and did not calculate the
22108cfa0ad2SJack F Vogel 	 * checksum...a likely scenario.
22118cfa0ad2SJack F Vogel 	 */
22128cfa0ad2SJack F Vogel 	ret_val = hw->nvm.ops.read(hw, 0x19, 1, &data);
22138cfa0ad2SJack F Vogel 	if (ret_val)
22148cfa0ad2SJack F Vogel 		goto out;
22158cfa0ad2SJack F Vogel 
22168cfa0ad2SJack F Vogel 	if ((data & 0x40) == 0) {
22178cfa0ad2SJack F Vogel 		data |= 0x40;
22188cfa0ad2SJack F Vogel 		ret_val = hw->nvm.ops.write(hw, 0x19, 1, &data);
22198cfa0ad2SJack F Vogel 		if (ret_val)
22208cfa0ad2SJack F Vogel 			goto out;
22218cfa0ad2SJack F Vogel 		ret_val = hw->nvm.ops.update(hw);
22228cfa0ad2SJack F Vogel 		if (ret_val)
22238cfa0ad2SJack F Vogel 			goto out;
22248cfa0ad2SJack F Vogel 	}
22258cfa0ad2SJack F Vogel 
22268cfa0ad2SJack F Vogel 	ret_val = e1000_validate_nvm_checksum_generic(hw);
22278cfa0ad2SJack F Vogel 
22288cfa0ad2SJack F Vogel out:
22298cfa0ad2SJack F Vogel 	return ret_val;
22308cfa0ad2SJack F Vogel }
22318cfa0ad2SJack F Vogel 
22328cfa0ad2SJack F Vogel /**
22338cfa0ad2SJack F Vogel  *  e1000_write_flash_data_ich8lan - Writes bytes to the NVM
22348cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
22358cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the byte/word to read.
22368cfa0ad2SJack F Vogel  *  @size: Size of data to read, 1=byte 2=word
22378cfa0ad2SJack F Vogel  *  @data: The byte(s) to write to the NVM.
22388cfa0ad2SJack F Vogel  *
22398cfa0ad2SJack F Vogel  *  Writes one/two bytes to the NVM using the flash access registers.
22408cfa0ad2SJack F Vogel  **/
22418cfa0ad2SJack F Vogel static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
22428cfa0ad2SJack F Vogel                                           u8 size, u16 data)
22438cfa0ad2SJack F Vogel {
22448cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
22458cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
22468cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
22478cfa0ad2SJack F Vogel 	u32 flash_data = 0;
22488cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
22498cfa0ad2SJack F Vogel 	u8 count = 0;
22508cfa0ad2SJack F Vogel 
22518cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_ich8_data");
22528cfa0ad2SJack F Vogel 
22538cfa0ad2SJack F Vogel 	if (size < 1 || size > 2 || data > size * 0xff ||
22548cfa0ad2SJack F Vogel 	    offset > ICH_FLASH_LINEAR_ADDR_MASK)
22558cfa0ad2SJack F Vogel 		goto out;
22568cfa0ad2SJack F Vogel 
22578cfa0ad2SJack F Vogel 	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
22588cfa0ad2SJack F Vogel 	                    hw->nvm.flash_base_addr;
22598cfa0ad2SJack F Vogel 
22608cfa0ad2SJack F Vogel 	do {
22618cfa0ad2SJack F Vogel 		usec_delay(1);
22628cfa0ad2SJack F Vogel 		/* Steps */
22638cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
22648cfa0ad2SJack F Vogel 		if (ret_val != E1000_SUCCESS)
22658cfa0ad2SJack F Vogel 			break;
22668cfa0ad2SJack F Vogel 
22678cfa0ad2SJack F Vogel 		hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
22688cfa0ad2SJack F Vogel 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
22698cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.fldbcount = size - 1;
22708cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
22718cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
22728cfa0ad2SJack F Vogel 
22738cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
22748cfa0ad2SJack F Vogel 
22758cfa0ad2SJack F Vogel 		if (size == 1)
22768cfa0ad2SJack F Vogel 			flash_data = (u32)data & 0x00FF;
22778cfa0ad2SJack F Vogel 		else
22788cfa0ad2SJack F Vogel 			flash_data = (u32)data;
22798cfa0ad2SJack F Vogel 
22808cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data);
22818cfa0ad2SJack F Vogel 
22828cfa0ad2SJack F Vogel 		/*
22838cfa0ad2SJack F Vogel 		 * check if FCERR is set to 1 , if set to 1, clear it
22848cfa0ad2SJack F Vogel 		 * and try the whole sequence a few more times else done
22858cfa0ad2SJack F Vogel 		 */
22868cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_ich8lan(hw,
22878cfa0ad2SJack F Vogel 		                               ICH_FLASH_WRITE_COMMAND_TIMEOUT);
2288daf9197cSJack F Vogel 		if (ret_val == E1000_SUCCESS)
22898cfa0ad2SJack F Vogel 			break;
2290daf9197cSJack F Vogel 
22918cfa0ad2SJack F Vogel 		/*
22928cfa0ad2SJack F Vogel 		 * If we're here, then things are most likely
22938cfa0ad2SJack F Vogel 		 * completely hosed, but if the error condition
22948cfa0ad2SJack F Vogel 		 * is detected, it won't hurt to give it another
22958cfa0ad2SJack F Vogel 		 * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
22968cfa0ad2SJack F Vogel 		 */
2297daf9197cSJack F Vogel 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
22984edd8523SJack F Vogel 		if (hsfsts.hsf_status.flcerr == 1)
22998cfa0ad2SJack F Vogel 			/* Repeat for some time before giving up. */
23008cfa0ad2SJack F Vogel 			continue;
23014edd8523SJack F Vogel 		if (hsfsts.hsf_status.flcdone == 0) {
23028cfa0ad2SJack F Vogel 			DEBUGOUT("Timeout error - flash cycle "
23038cfa0ad2SJack F Vogel 				 "did not complete.");
23048cfa0ad2SJack F Vogel 			break;
23058cfa0ad2SJack F Vogel 		}
23068cfa0ad2SJack F Vogel 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
23078cfa0ad2SJack F Vogel 
23088cfa0ad2SJack F Vogel out:
23098cfa0ad2SJack F Vogel 	return ret_val;
23108cfa0ad2SJack F Vogel }
23118cfa0ad2SJack F Vogel 
23128cfa0ad2SJack F Vogel /**
23138cfa0ad2SJack F Vogel  *  e1000_write_flash_byte_ich8lan - Write a single byte to NVM
23148cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
23158cfa0ad2SJack F Vogel  *  @offset: The index of the byte to read.
23168cfa0ad2SJack F Vogel  *  @data: The byte to write to the NVM.
23178cfa0ad2SJack F Vogel  *
23188cfa0ad2SJack F Vogel  *  Writes a single byte to the NVM using the flash access registers.
23198cfa0ad2SJack F Vogel  **/
23208cfa0ad2SJack F Vogel static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
23218cfa0ad2SJack F Vogel                                           u8 data)
23228cfa0ad2SJack F Vogel {
23238cfa0ad2SJack F Vogel 	u16 word = (u16)data;
23248cfa0ad2SJack F Vogel 
23258cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_flash_byte_ich8lan");
23268cfa0ad2SJack F Vogel 
23278cfa0ad2SJack F Vogel 	return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
23288cfa0ad2SJack F Vogel }
23298cfa0ad2SJack F Vogel 
23308cfa0ad2SJack F Vogel /**
23318cfa0ad2SJack F Vogel  *  e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
23328cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
23338cfa0ad2SJack F Vogel  *  @offset: The offset of the byte to write.
23348cfa0ad2SJack F Vogel  *  @byte: The byte to write to the NVM.
23358cfa0ad2SJack F Vogel  *
23368cfa0ad2SJack F Vogel  *  Writes a single byte to the NVM using the flash access registers.
23378cfa0ad2SJack F Vogel  *  Goes through a retry algorithm before giving up.
23388cfa0ad2SJack F Vogel  **/
23398cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
23408cfa0ad2SJack F Vogel                                                 u32 offset, u8 byte)
23418cfa0ad2SJack F Vogel {
23428cfa0ad2SJack F Vogel 	s32 ret_val;
23438cfa0ad2SJack F Vogel 	u16 program_retries;
23448cfa0ad2SJack F Vogel 
23458cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan");
23468cfa0ad2SJack F Vogel 
23478cfa0ad2SJack F Vogel 	ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
23488cfa0ad2SJack F Vogel 	if (ret_val == E1000_SUCCESS)
23498cfa0ad2SJack F Vogel 		goto out;
23508cfa0ad2SJack F Vogel 
23518cfa0ad2SJack F Vogel 	for (program_retries = 0; program_retries < 100; program_retries++) {
23528cfa0ad2SJack F Vogel 		DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset);
23538cfa0ad2SJack F Vogel 		usec_delay(100);
23548cfa0ad2SJack F Vogel 		ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
23558cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS)
23568cfa0ad2SJack F Vogel 			break;
23578cfa0ad2SJack F Vogel 	}
23588cfa0ad2SJack F Vogel 	if (program_retries == 100) {
23598cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
23608cfa0ad2SJack F Vogel 		goto out;
23618cfa0ad2SJack F Vogel 	}
23628cfa0ad2SJack F Vogel 
23638cfa0ad2SJack F Vogel out:
23648cfa0ad2SJack F Vogel 	return ret_val;
23658cfa0ad2SJack F Vogel }
23668cfa0ad2SJack F Vogel 
23678cfa0ad2SJack F Vogel /**
23688cfa0ad2SJack F Vogel  *  e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
23698cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
23708cfa0ad2SJack F Vogel  *  @bank: 0 for first bank, 1 for second bank, etc.
23718cfa0ad2SJack F Vogel  *
23728cfa0ad2SJack F Vogel  *  Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
23738cfa0ad2SJack F Vogel  *  bank N is 4096 * N + flash_reg_addr.
23748cfa0ad2SJack F Vogel  **/
23758cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
23768cfa0ad2SJack F Vogel {
23778cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
23788cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
23798cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
23808cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
23818cfa0ad2SJack F Vogel 	/* bank size is in 16bit words - adjust to bytes */
23828cfa0ad2SJack F Vogel 	u32 flash_bank_size = nvm->flash_bank_size * 2;
23838cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
23848cfa0ad2SJack F Vogel 	s32 count = 0;
23858cfa0ad2SJack F Vogel 	s32 j, iteration, sector_size;
23868cfa0ad2SJack F Vogel 
23878cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_erase_flash_bank_ich8lan");
23888cfa0ad2SJack F Vogel 
23898cfa0ad2SJack F Vogel 	hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
23908cfa0ad2SJack F Vogel 
23918cfa0ad2SJack F Vogel 	/*
23928cfa0ad2SJack F Vogel 	 * Determine HW Sector size: Read BERASE bits of hw flash status
23938cfa0ad2SJack F Vogel 	 * register
23948cfa0ad2SJack F Vogel 	 * 00: The Hw sector is 256 bytes, hence we need to erase 16
23958cfa0ad2SJack F Vogel 	 *     consecutive sectors.  The start index for the nth Hw sector
23968cfa0ad2SJack F Vogel 	 *     can be calculated as = bank * 4096 + n * 256
23978cfa0ad2SJack F Vogel 	 * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
23988cfa0ad2SJack F Vogel 	 *     The start index for the nth Hw sector can be calculated
23998cfa0ad2SJack F Vogel 	 *     as = bank * 4096
24008cfa0ad2SJack F Vogel 	 * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
24018cfa0ad2SJack F Vogel 	 *     (ich9 only, otherwise error condition)
24028cfa0ad2SJack F Vogel 	 * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
24038cfa0ad2SJack F Vogel 	 */
24048cfa0ad2SJack F Vogel 	switch (hsfsts.hsf_status.berasesz) {
24058cfa0ad2SJack F Vogel 	case 0:
24068cfa0ad2SJack F Vogel 		/* Hw sector size 256 */
24078cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_256;
24088cfa0ad2SJack F Vogel 		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
24098cfa0ad2SJack F Vogel 		break;
24108cfa0ad2SJack F Vogel 	case 1:
24118cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_4K;
24129d81738fSJack F Vogel 		iteration = 1;
24138cfa0ad2SJack F Vogel 		break;
24148cfa0ad2SJack F Vogel 	case 2:
24158cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_8K;
24168bd0025fSJack F Vogel 		iteration = 1;
24178cfa0ad2SJack F Vogel 		break;
24188cfa0ad2SJack F Vogel 	case 3:
24198cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_64K;
24209d81738fSJack F Vogel 		iteration = 1;
24218cfa0ad2SJack F Vogel 		break;
24228cfa0ad2SJack F Vogel 	default:
24238cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
24248cfa0ad2SJack F Vogel 		goto out;
24258cfa0ad2SJack F Vogel 	}
24268cfa0ad2SJack F Vogel 
24278cfa0ad2SJack F Vogel 	/* Start with the base address, then add the sector offset. */
24288cfa0ad2SJack F Vogel 	flash_linear_addr = hw->nvm.flash_base_addr;
24294edd8523SJack F Vogel 	flash_linear_addr += (bank) ? flash_bank_size : 0;
24308cfa0ad2SJack F Vogel 
24318cfa0ad2SJack F Vogel 	for (j = 0; j < iteration ; j++) {
24328cfa0ad2SJack F Vogel 		do {
24338cfa0ad2SJack F Vogel 			/* Steps */
24348cfa0ad2SJack F Vogel 			ret_val = e1000_flash_cycle_init_ich8lan(hw);
24358cfa0ad2SJack F Vogel 			if (ret_val)
24368cfa0ad2SJack F Vogel 				goto out;
24378cfa0ad2SJack F Vogel 
24388cfa0ad2SJack F Vogel 			/*
24398cfa0ad2SJack F Vogel 			 * Write a value 11 (block Erase) in Flash
24408cfa0ad2SJack F Vogel 			 * Cycle field in hw flash control
24418cfa0ad2SJack F Vogel 			 */
24428cfa0ad2SJack F Vogel 			hsflctl.regval = E1000_READ_FLASH_REG16(hw,
24438cfa0ad2SJack F Vogel 			                                      ICH_FLASH_HSFCTL);
24448cfa0ad2SJack F Vogel 			hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
2445daf9197cSJack F Vogel 			E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
24468cfa0ad2SJack F Vogel 			                        hsflctl.regval);
24478cfa0ad2SJack F Vogel 
24488cfa0ad2SJack F Vogel 			/*
24498cfa0ad2SJack F Vogel 			 * Write the last 24 bits of an index within the
24508cfa0ad2SJack F Vogel 			 * block into Flash Linear address field in Flash
24518cfa0ad2SJack F Vogel 			 * Address.
24528cfa0ad2SJack F Vogel 			 */
24538cfa0ad2SJack F Vogel 			flash_linear_addr += (j * sector_size);
2454daf9197cSJack F Vogel 			E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR,
24558cfa0ad2SJack F Vogel 			                      flash_linear_addr);
24568cfa0ad2SJack F Vogel 
24578cfa0ad2SJack F Vogel 			ret_val = e1000_flash_cycle_ich8lan(hw,
24588cfa0ad2SJack F Vogel 			                       ICH_FLASH_ERASE_COMMAND_TIMEOUT);
2459daf9197cSJack F Vogel 			if (ret_val == E1000_SUCCESS)
24608cfa0ad2SJack F Vogel 				break;
2461daf9197cSJack F Vogel 
24628cfa0ad2SJack F Vogel 			/*
24638cfa0ad2SJack F Vogel 			 * Check if FCERR is set to 1.  If 1,
24648cfa0ad2SJack F Vogel 			 * clear it and try the whole sequence
24658cfa0ad2SJack F Vogel 			 * a few more times else Done
24668cfa0ad2SJack F Vogel 			 */
24678cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
24688cfa0ad2SJack F Vogel 						      ICH_FLASH_HSFSTS);
2469daf9197cSJack F Vogel 			if (hsfsts.hsf_status.flcerr == 1)
2470daf9197cSJack F Vogel 				/* repeat for some time before giving up */
24718cfa0ad2SJack F Vogel 				continue;
2472daf9197cSJack F Vogel 			else if (hsfsts.hsf_status.flcdone == 0)
24738cfa0ad2SJack F Vogel 				goto out;
24748cfa0ad2SJack F Vogel 		} while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
24758cfa0ad2SJack F Vogel 	}
24768cfa0ad2SJack F Vogel 
24778cfa0ad2SJack F Vogel out:
24788cfa0ad2SJack F Vogel 	return ret_val;
24798cfa0ad2SJack F Vogel }
24808cfa0ad2SJack F Vogel 
24818cfa0ad2SJack F Vogel /**
24828cfa0ad2SJack F Vogel  *  e1000_valid_led_default_ich8lan - Set the default LED settings
24838cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
24848cfa0ad2SJack F Vogel  *  @data: Pointer to the LED settings
24858cfa0ad2SJack F Vogel  *
24868cfa0ad2SJack F Vogel  *  Reads the LED default settings from the NVM to data.  If the NVM LED
24878cfa0ad2SJack F Vogel  *  settings is all 0's or F's, set the LED default to a valid LED default
24888cfa0ad2SJack F Vogel  *  setting.
24898cfa0ad2SJack F Vogel  **/
24908cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
24918cfa0ad2SJack F Vogel {
24928cfa0ad2SJack F Vogel 	s32 ret_val;
24938cfa0ad2SJack F Vogel 
24948cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_valid_led_default_ich8lan");
24958cfa0ad2SJack F Vogel 
24968cfa0ad2SJack F Vogel 	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
24978cfa0ad2SJack F Vogel 	if (ret_val) {
24988cfa0ad2SJack F Vogel 		DEBUGOUT("NVM Read Error\n");
24998cfa0ad2SJack F Vogel 		goto out;
25008cfa0ad2SJack F Vogel 	}
25018cfa0ad2SJack F Vogel 
25028cfa0ad2SJack F Vogel 	if (*data == ID_LED_RESERVED_0000 ||
25038cfa0ad2SJack F Vogel 	    *data == ID_LED_RESERVED_FFFF)
25048cfa0ad2SJack F Vogel 		*data = ID_LED_DEFAULT_ICH8LAN;
25058cfa0ad2SJack F Vogel 
25068cfa0ad2SJack F Vogel out:
25078cfa0ad2SJack F Vogel 	return ret_val;
25088cfa0ad2SJack F Vogel }
25098cfa0ad2SJack F Vogel 
25108cfa0ad2SJack F Vogel /**
25119d81738fSJack F Vogel  *  e1000_id_led_init_pchlan - store LED configurations
25129d81738fSJack F Vogel  *  @hw: pointer to the HW structure
25139d81738fSJack F Vogel  *
25149d81738fSJack F Vogel  *  PCH does not control LEDs via the LEDCTL register, rather it uses
25159d81738fSJack F Vogel  *  the PHY LED configuration register.
25169d81738fSJack F Vogel  *
25179d81738fSJack F Vogel  *  PCH also does not have an "always on" or "always off" mode which
25189d81738fSJack F Vogel  *  complicates the ID feature.  Instead of using the "on" mode to indicate
25199d81738fSJack F Vogel  *  in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()),
25209d81738fSJack F Vogel  *  use "link_up" mode.  The LEDs will still ID on request if there is no
25219d81738fSJack F Vogel  *  link based on logic in e1000_led_[on|off]_pchlan().
25229d81738fSJack F Vogel  **/
25239d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw)
25249d81738fSJack F Vogel {
25259d81738fSJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
25269d81738fSJack F Vogel 	s32 ret_val;
25279d81738fSJack F Vogel 	const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
25289d81738fSJack F Vogel 	const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
25299d81738fSJack F Vogel 	u16 data, i, temp, shift;
25309d81738fSJack F Vogel 
25319d81738fSJack F Vogel 	DEBUGFUNC("e1000_id_led_init_pchlan");
25329d81738fSJack F Vogel 
25339d81738fSJack F Vogel 	/* Get default ID LED modes */
25349d81738fSJack F Vogel 	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
25359d81738fSJack F Vogel 	if (ret_val)
25369d81738fSJack F Vogel 		goto out;
25379d81738fSJack F Vogel 
25389d81738fSJack F Vogel 	mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
25399d81738fSJack F Vogel 	mac->ledctl_mode1 = mac->ledctl_default;
25409d81738fSJack F Vogel 	mac->ledctl_mode2 = mac->ledctl_default;
25419d81738fSJack F Vogel 
25429d81738fSJack F Vogel 	for (i = 0; i < 4; i++) {
25439d81738fSJack F Vogel 		temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
25449d81738fSJack F Vogel 		shift = (i * 5);
25459d81738fSJack F Vogel 		switch (temp) {
25469d81738fSJack F Vogel 		case ID_LED_ON1_DEF2:
25479d81738fSJack F Vogel 		case ID_LED_ON1_ON2:
25489d81738fSJack F Vogel 		case ID_LED_ON1_OFF2:
25499d81738fSJack F Vogel 			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
25509d81738fSJack F Vogel 			mac->ledctl_mode1 |= (ledctl_on << shift);
25519d81738fSJack F Vogel 			break;
25529d81738fSJack F Vogel 		case ID_LED_OFF1_DEF2:
25539d81738fSJack F Vogel 		case ID_LED_OFF1_ON2:
25549d81738fSJack F Vogel 		case ID_LED_OFF1_OFF2:
25559d81738fSJack F Vogel 			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
25569d81738fSJack F Vogel 			mac->ledctl_mode1 |= (ledctl_off << shift);
25579d81738fSJack F Vogel 			break;
25589d81738fSJack F Vogel 		default:
25599d81738fSJack F Vogel 			/* Do nothing */
25609d81738fSJack F Vogel 			break;
25619d81738fSJack F Vogel 		}
25629d81738fSJack F Vogel 		switch (temp) {
25639d81738fSJack F Vogel 		case ID_LED_DEF1_ON2:
25649d81738fSJack F Vogel 		case ID_LED_ON1_ON2:
25659d81738fSJack F Vogel 		case ID_LED_OFF1_ON2:
25669d81738fSJack F Vogel 			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
25679d81738fSJack F Vogel 			mac->ledctl_mode2 |= (ledctl_on << shift);
25689d81738fSJack F Vogel 			break;
25699d81738fSJack F Vogel 		case ID_LED_DEF1_OFF2:
25709d81738fSJack F Vogel 		case ID_LED_ON1_OFF2:
25719d81738fSJack F Vogel 		case ID_LED_OFF1_OFF2:
25729d81738fSJack F Vogel 			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
25739d81738fSJack F Vogel 			mac->ledctl_mode2 |= (ledctl_off << shift);
25749d81738fSJack F Vogel 			break;
25759d81738fSJack F Vogel 		default:
25769d81738fSJack F Vogel 			/* Do nothing */
25779d81738fSJack F Vogel 			break;
25789d81738fSJack F Vogel 		}
25799d81738fSJack F Vogel 	}
25809d81738fSJack F Vogel 
25819d81738fSJack F Vogel out:
25829d81738fSJack F Vogel 	return ret_val;
25839d81738fSJack F Vogel }
25849d81738fSJack F Vogel 
25859d81738fSJack F Vogel /**
25868cfa0ad2SJack F Vogel  *  e1000_get_bus_info_ich8lan - Get/Set the bus type and width
25878cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
25888cfa0ad2SJack F Vogel  *
25898cfa0ad2SJack F Vogel  *  ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
25908cfa0ad2SJack F Vogel  *  register, so the the bus width is hard coded.
25918cfa0ad2SJack F Vogel  **/
25928cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
25938cfa0ad2SJack F Vogel {
25948cfa0ad2SJack F Vogel 	struct e1000_bus_info *bus = &hw->bus;
25958cfa0ad2SJack F Vogel 	s32 ret_val;
25968cfa0ad2SJack F Vogel 
25978cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_bus_info_ich8lan");
25988cfa0ad2SJack F Vogel 
25998cfa0ad2SJack F Vogel 	ret_val = e1000_get_bus_info_pcie_generic(hw);
26008cfa0ad2SJack F Vogel 
26018cfa0ad2SJack F Vogel 	/*
26028cfa0ad2SJack F Vogel 	 * ICH devices are "PCI Express"-ish.  They have
26038cfa0ad2SJack F Vogel 	 * a configuration space, but do not contain
26048cfa0ad2SJack F Vogel 	 * PCI Express Capability registers, so bus width
26058cfa0ad2SJack F Vogel 	 * must be hardcoded.
26068cfa0ad2SJack F Vogel 	 */
26078cfa0ad2SJack F Vogel 	if (bus->width == e1000_bus_width_unknown)
26088cfa0ad2SJack F Vogel 		bus->width = e1000_bus_width_pcie_x1;
26098cfa0ad2SJack F Vogel 
26108cfa0ad2SJack F Vogel 	return ret_val;
26118cfa0ad2SJack F Vogel }
26128cfa0ad2SJack F Vogel 
26138cfa0ad2SJack F Vogel /**
26148cfa0ad2SJack F Vogel  *  e1000_reset_hw_ich8lan - Reset the hardware
26158cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
26168cfa0ad2SJack F Vogel  *
26178cfa0ad2SJack F Vogel  *  Does a full reset of the hardware which includes a reset of the PHY and
26188cfa0ad2SJack F Vogel  *  MAC.
26198cfa0ad2SJack F Vogel  **/
26208cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
26218cfa0ad2SJack F Vogel {
26224edd8523SJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
26234edd8523SJack F Vogel 	u16 reg;
26248cfa0ad2SJack F Vogel 	u32 ctrl, icr, kab;
26258cfa0ad2SJack F Vogel 	s32 ret_val;
26268cfa0ad2SJack F Vogel 
26278cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_reset_hw_ich8lan");
26288cfa0ad2SJack F Vogel 
26298cfa0ad2SJack F Vogel 	/*
26308cfa0ad2SJack F Vogel 	 * Prevent the PCI-E bus from sticking if there is no TLP connection
26318cfa0ad2SJack F Vogel 	 * on the last TLP read/write transaction when MAC is reset.
26328cfa0ad2SJack F Vogel 	 */
26338cfa0ad2SJack F Vogel 	ret_val = e1000_disable_pcie_master_generic(hw);
2634daf9197cSJack F Vogel 	if (ret_val)
26358cfa0ad2SJack F Vogel 		DEBUGOUT("PCI-E Master disable polling has failed.\n");
26368cfa0ad2SJack F Vogel 
26378cfa0ad2SJack F Vogel 	DEBUGOUT("Masking off all interrupts\n");
26388cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
26398cfa0ad2SJack F Vogel 
26408cfa0ad2SJack F Vogel 	/*
26418cfa0ad2SJack F Vogel 	 * Disable the Transmit and Receive units.  Then delay to allow
26428cfa0ad2SJack F Vogel 	 * any pending transactions to complete before we hit the MAC
26438cfa0ad2SJack F Vogel 	 * with the global reset.
26448cfa0ad2SJack F Vogel 	 */
26458cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RCTL, 0);
26468cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
26478cfa0ad2SJack F Vogel 	E1000_WRITE_FLUSH(hw);
26488cfa0ad2SJack F Vogel 
26498cfa0ad2SJack F Vogel 	msec_delay(10);
26508cfa0ad2SJack F Vogel 
26518cfa0ad2SJack F Vogel 	/* Workaround for ICH8 bit corruption issue in FIFO memory */
26528cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan) {
26538cfa0ad2SJack F Vogel 		/* Set Tx and Rx buffer allocation to 8k apiece. */
26548cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K);
26558cfa0ad2SJack F Vogel 		/* Set Packet Buffer Size to 16k. */
26568cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K);
26578cfa0ad2SJack F Vogel 	}
26588cfa0ad2SJack F Vogel 
26594edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan) {
26604edd8523SJack F Vogel 		/* Save the NVM K1 bit setting*/
26614edd8523SJack F Vogel 		ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, &reg);
26624edd8523SJack F Vogel 		if (ret_val)
26634edd8523SJack F Vogel 			return ret_val;
26644edd8523SJack F Vogel 
26654edd8523SJack F Vogel 		if (reg & E1000_NVM_K1_ENABLE)
26664edd8523SJack F Vogel 			dev_spec->nvm_k1_enabled = TRUE;
26674edd8523SJack F Vogel 		else
26684edd8523SJack F Vogel 			dev_spec->nvm_k1_enabled = FALSE;
26694edd8523SJack F Vogel 	}
26704edd8523SJack F Vogel 
26718cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
26728cfa0ad2SJack F Vogel 
26738cfa0ad2SJack F Vogel 	if (!hw->phy.ops.check_reset_block(hw) && !hw->phy.reset_disable) {
26749d81738fSJack F Vogel 		/* Clear PHY Reset Asserted bit */
26759d81738fSJack F Vogel 		if (hw->mac.type >= e1000_pchlan) {
26769d81738fSJack F Vogel 			u32 status = E1000_READ_REG(hw, E1000_STATUS);
26779d81738fSJack F Vogel 			E1000_WRITE_REG(hw, E1000_STATUS, status &
26789d81738fSJack F Vogel 			                ~E1000_STATUS_PHYRA);
26799d81738fSJack F Vogel 		}
26809d81738fSJack F Vogel 
26818cfa0ad2SJack F Vogel 		/*
26828cfa0ad2SJack F Vogel 		 * PHY HW reset requires MAC CORE reset at the same
26838cfa0ad2SJack F Vogel 		 * time to make sure the interface between MAC and the
26848cfa0ad2SJack F Vogel 		 * external PHY is reset.
26858cfa0ad2SJack F Vogel 		 */
26868cfa0ad2SJack F Vogel 		ctrl |= E1000_CTRL_PHY_RST;
26878cfa0ad2SJack F Vogel 	}
26888cfa0ad2SJack F Vogel 	ret_val = e1000_acquire_swflag_ich8lan(hw);
2689daf9197cSJack F Vogel 	DEBUGOUT("Issuing a global reset to ich8lan\n");
26908cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST));
26918cfa0ad2SJack F Vogel 	msec_delay(20);
26928cfa0ad2SJack F Vogel 
26939d81738fSJack F Vogel 	if (!ret_val)
26949d81738fSJack F Vogel 		e1000_release_swflag_ich8lan(hw);
26959d81738fSJack F Vogel 
2696a69ed8dfSJack F Vogel 	/* Perform any necessary post-reset workarounds */
2697a69ed8dfSJack F Vogel 	switch (hw->mac.type) {
2698a69ed8dfSJack F Vogel 	case e1000_pchlan:
2699a69ed8dfSJack F Vogel 		ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
2700a69ed8dfSJack F Vogel 		if (ret_val)
2701a69ed8dfSJack F Vogel 			goto out;
2702a69ed8dfSJack F Vogel 		break;
2703a69ed8dfSJack F Vogel 	default:
2704a69ed8dfSJack F Vogel 		break;
2705a69ed8dfSJack F Vogel 	}
2706a69ed8dfSJack F Vogel 
27079d81738fSJack F Vogel 	if (ctrl & E1000_CTRL_PHY_RST)
27089d81738fSJack F Vogel 		ret_val = hw->phy.ops.get_cfg_done(hw);
27099d81738fSJack F Vogel 
27109d81738fSJack F Vogel 	if (hw->mac.type >= e1000_ich10lan) {
27119d81738fSJack F Vogel 		e1000_lan_init_done_ich8lan(hw);
27129d81738fSJack F Vogel 	} else {
27138cfa0ad2SJack F Vogel 		ret_val = e1000_get_auto_rd_done_generic(hw);
27148cfa0ad2SJack F Vogel 		if (ret_val) {
27158cfa0ad2SJack F Vogel 			/*
27168cfa0ad2SJack F Vogel 			 * When auto config read does not complete, do not
27178cfa0ad2SJack F Vogel 			 * return with an error. This can happen in situations
27188cfa0ad2SJack F Vogel 			 * where there is no eeprom and prevents getting link.
27198cfa0ad2SJack F Vogel 			 */
27208cfa0ad2SJack F Vogel 			DEBUGOUT("Auto Read Done did not complete\n");
27218cfa0ad2SJack F Vogel 		}
27229d81738fSJack F Vogel 	}
27238ec87fc5SJack F Vogel 	/* Dummy read to clear the phy wakeup bit after lcd reset */
27244edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan)
27254edd8523SJack F Vogel 		hw->phy.ops.read_reg(hw, BM_WUC, &reg);
27264edd8523SJack F Vogel 
27274edd8523SJack F Vogel 	ret_val = e1000_sw_lcd_config_ich8lan(hw);
27284edd8523SJack F Vogel 	if (ret_val)
27294edd8523SJack F Vogel 		goto out;
27304edd8523SJack F Vogel 
27314edd8523SJack F Vogel 	ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE);
27324edd8523SJack F Vogel 	if (ret_val)
27334edd8523SJack F Vogel 		goto out;
27344edd8523SJack F Vogel 	/*
27354edd8523SJack F Vogel 	 * For PCH, this write will make sure that any noise
27364edd8523SJack F Vogel 	 * will be detected as a CRC error and be dropped rather than show up
27374edd8523SJack F Vogel 	 * as a bad packet to the DMA engine.
27384edd8523SJack F Vogel 	 */
27394edd8523SJack F Vogel 	if (hw->mac.type == e1000_pchlan)
27404edd8523SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565);
27418cfa0ad2SJack F Vogel 
27428cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
27438cfa0ad2SJack F Vogel 	icr = E1000_READ_REG(hw, E1000_ICR);
27448cfa0ad2SJack F Vogel 
27458cfa0ad2SJack F Vogel 	kab = E1000_READ_REG(hw, E1000_KABGTXD);
27468cfa0ad2SJack F Vogel 	kab |= E1000_KABGTXD_BGSQLBIAS;
27478cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_KABGTXD, kab);
27488cfa0ad2SJack F Vogel 
27494edd8523SJack F Vogel out:
27508cfa0ad2SJack F Vogel 	return ret_val;
27518cfa0ad2SJack F Vogel }
27528cfa0ad2SJack F Vogel 
27538cfa0ad2SJack F Vogel /**
27548cfa0ad2SJack F Vogel  *  e1000_init_hw_ich8lan - Initialize the hardware
27558cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
27568cfa0ad2SJack F Vogel  *
27578cfa0ad2SJack F Vogel  *  Prepares the hardware for transmit and receive by doing the following:
27588cfa0ad2SJack F Vogel  *   - initialize hardware bits
27598cfa0ad2SJack F Vogel  *   - initialize LED identification
27608cfa0ad2SJack F Vogel  *   - setup receive address registers
27618cfa0ad2SJack F Vogel  *   - setup flow control
27628cfa0ad2SJack F Vogel  *   - setup transmit descriptors
27638cfa0ad2SJack F Vogel  *   - clear statistics
27648cfa0ad2SJack F Vogel  **/
27658cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
27668cfa0ad2SJack F Vogel {
27678cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
27688cfa0ad2SJack F Vogel 	u32 ctrl_ext, txdctl, snoop;
27698cfa0ad2SJack F Vogel 	s32 ret_val;
27708cfa0ad2SJack F Vogel 	u16 i;
27718cfa0ad2SJack F Vogel 
27728cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_hw_ich8lan");
27738cfa0ad2SJack F Vogel 
27748cfa0ad2SJack F Vogel 	e1000_initialize_hw_bits_ich8lan(hw);
27758cfa0ad2SJack F Vogel 
27768cfa0ad2SJack F Vogel 	/* Initialize identification LED */
2777d035aa2dSJack F Vogel 	ret_val = mac->ops.id_led_init(hw);
2778d035aa2dSJack F Vogel 	if (ret_val)
2779d035aa2dSJack F Vogel 		DEBUGOUT("Error initializing identification LED\n");
27804edd8523SJack F Vogel 		/* This is not fatal and we should not stop init due to this */
27818cfa0ad2SJack F Vogel 
27828cfa0ad2SJack F Vogel 	/* Setup the receive address. */
27838cfa0ad2SJack F Vogel 	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
27848cfa0ad2SJack F Vogel 
27858cfa0ad2SJack F Vogel 	/* Zero out the Multicast HASH table */
27868cfa0ad2SJack F Vogel 	DEBUGOUT("Zeroing the MTA\n");
27878cfa0ad2SJack F Vogel 	for (i = 0; i < mac->mta_reg_count; i++)
27888cfa0ad2SJack F Vogel 		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
27898cfa0ad2SJack F Vogel 
27909d81738fSJack F Vogel 	/*
27919d81738fSJack F Vogel 	 * The 82578 Rx buffer will stall if wakeup is enabled in host and
27929d81738fSJack F Vogel 	 * the ME.  Reading the BM_WUC register will clear the host wakeup bit.
27939d81738fSJack F Vogel 	 * Reset the phy after disabling host wakeup to reset the Rx buffer.
27949d81738fSJack F Vogel 	 */
27959d81738fSJack F Vogel 	if (hw->phy.type == e1000_phy_82578) {
27969d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, BM_WUC, &i);
27979d81738fSJack F Vogel 		ret_val = e1000_phy_hw_reset_ich8lan(hw);
27989d81738fSJack F Vogel 		if (ret_val)
27999d81738fSJack F Vogel 			return ret_val;
28009d81738fSJack F Vogel 	}
28019d81738fSJack F Vogel 
28028cfa0ad2SJack F Vogel 	/* Setup link and flow control */
28038cfa0ad2SJack F Vogel 	ret_val = mac->ops.setup_link(hw);
28048cfa0ad2SJack F Vogel 
28058cfa0ad2SJack F Vogel 	/* Set the transmit descriptor write-back policy for both queues */
28068cfa0ad2SJack F Vogel 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
28078cfa0ad2SJack F Vogel 	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
28088cfa0ad2SJack F Vogel 		 E1000_TXDCTL_FULL_TX_DESC_WB;
28098cfa0ad2SJack F Vogel 	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
28108cfa0ad2SJack F Vogel 	         E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
28118cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
28128cfa0ad2SJack F Vogel 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1));
28138cfa0ad2SJack F Vogel 	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
28148cfa0ad2SJack F Vogel 		 E1000_TXDCTL_FULL_TX_DESC_WB;
28158cfa0ad2SJack F Vogel 	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
28168cfa0ad2SJack F Vogel 	         E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
28178cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl);
28188cfa0ad2SJack F Vogel 
28198cfa0ad2SJack F Vogel 	/*
28208cfa0ad2SJack F Vogel 	 * ICH8 has opposite polarity of no_snoop bits.
28218cfa0ad2SJack F Vogel 	 * By default, we should use snoop behavior.
28228cfa0ad2SJack F Vogel 	 */
28238cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
28248cfa0ad2SJack F Vogel 		snoop = PCIE_ICH8_SNOOP_ALL;
28258cfa0ad2SJack F Vogel 	else
28268cfa0ad2SJack F Vogel 		snoop = (u32) ~(PCIE_NO_SNOOP_ALL);
28278cfa0ad2SJack F Vogel 	e1000_set_pcie_no_snoop_generic(hw, snoop);
28288cfa0ad2SJack F Vogel 
28298cfa0ad2SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
28308cfa0ad2SJack F Vogel 	ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
28318cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
28328cfa0ad2SJack F Vogel 
28338cfa0ad2SJack F Vogel 	/*
28348cfa0ad2SJack F Vogel 	 * Clear all of the statistics registers (clear on read).  It is
28358cfa0ad2SJack F Vogel 	 * important that we do this after we have tried to establish link
28368cfa0ad2SJack F Vogel 	 * because the symbol error count will increment wildly if there
28378cfa0ad2SJack F Vogel 	 * is no link.
28388cfa0ad2SJack F Vogel 	 */
28398cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_ich8lan(hw);
28408cfa0ad2SJack F Vogel 
28418cfa0ad2SJack F Vogel 	return ret_val;
28428cfa0ad2SJack F Vogel }
28438cfa0ad2SJack F Vogel /**
28448cfa0ad2SJack F Vogel  *  e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
28458cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
28468cfa0ad2SJack F Vogel  *
28478cfa0ad2SJack F Vogel  *  Sets/Clears required hardware bits necessary for correctly setting up the
28488cfa0ad2SJack F Vogel  *  hardware for transmit and receive.
28498cfa0ad2SJack F Vogel  **/
28508cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
28518cfa0ad2SJack F Vogel {
28528cfa0ad2SJack F Vogel 	u32 reg;
28538cfa0ad2SJack F Vogel 
28548cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_initialize_hw_bits_ich8lan");
28558cfa0ad2SJack F Vogel 
28568cfa0ad2SJack F Vogel 	/* Extended Device Control */
28578cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
28588cfa0ad2SJack F Vogel 	reg |= (1 << 22);
28599d81738fSJack F Vogel 	/* Enable PHY low-power state when MAC is at D3 w/o WoL */
28609d81738fSJack F Vogel 	if (hw->mac.type >= e1000_pchlan)
28619d81738fSJack F Vogel 		reg |= E1000_CTRL_EXT_PHYPDEN;
28628cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
28638cfa0ad2SJack F Vogel 
28648cfa0ad2SJack F Vogel 	/* Transmit Descriptor Control 0 */
28658cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
28668cfa0ad2SJack F Vogel 	reg |= (1 << 22);
28678cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
28688cfa0ad2SJack F Vogel 
28698cfa0ad2SJack F Vogel 	/* Transmit Descriptor Control 1 */
28708cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
28718cfa0ad2SJack F Vogel 	reg |= (1 << 22);
28728cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
28738cfa0ad2SJack F Vogel 
28748cfa0ad2SJack F Vogel 	/* Transmit Arbitration Control 0 */
28758cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TARC(0));
28768cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan)
28778cfa0ad2SJack F Vogel 		reg |= (1 << 28) | (1 << 29);
28788cfa0ad2SJack F Vogel 	reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
28798cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TARC(0), reg);
28808cfa0ad2SJack F Vogel 
28818cfa0ad2SJack F Vogel 	/* Transmit Arbitration Control 1 */
28828cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TARC(1));
28838cfa0ad2SJack F Vogel 	if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
28848cfa0ad2SJack F Vogel 		reg &= ~(1 << 28);
28858cfa0ad2SJack F Vogel 	else
28868cfa0ad2SJack F Vogel 		reg |= (1 << 28);
28878cfa0ad2SJack F Vogel 	reg |= (1 << 24) | (1 << 26) | (1 << 30);
28888cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TARC(1), reg);
28898cfa0ad2SJack F Vogel 
28908cfa0ad2SJack F Vogel 	/* Device Status */
28918cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan) {
28928cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_STATUS);
28938cfa0ad2SJack F Vogel 		reg &= ~(1 << 31);
28948cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_STATUS, reg);
28958cfa0ad2SJack F Vogel 	}
28968cfa0ad2SJack F Vogel 
28978ec87fc5SJack F Vogel 	/*
28988ec87fc5SJack F Vogel 	 * work-around descriptor data corruption issue during nfs v2 udp
28998ec87fc5SJack F Vogel 	 * traffic, just disable the nfs filtering capability
29008ec87fc5SJack F Vogel 	 */
29018ec87fc5SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_RFCTL);
29028ec87fc5SJack F Vogel 	reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS);
29038ec87fc5SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RFCTL, reg);
29048ec87fc5SJack F Vogel 
29058cfa0ad2SJack F Vogel 	return;
29068cfa0ad2SJack F Vogel }
29078cfa0ad2SJack F Vogel 
29088cfa0ad2SJack F Vogel /**
29098cfa0ad2SJack F Vogel  *  e1000_setup_link_ich8lan - Setup flow control and link settings
29108cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
29118cfa0ad2SJack F Vogel  *
29128cfa0ad2SJack F Vogel  *  Determines which flow control settings to use, then configures flow
29138cfa0ad2SJack F Vogel  *  control.  Calls the appropriate media-specific link configuration
29148cfa0ad2SJack F Vogel  *  function.  Assuming the adapter has a valid link partner, a valid link
29158cfa0ad2SJack F Vogel  *  should be established.  Assumes the hardware has previously been reset
29168cfa0ad2SJack F Vogel  *  and the transmitter and receiver are not enabled.
29178cfa0ad2SJack F Vogel  **/
29188cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
29198cfa0ad2SJack F Vogel {
29208cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
29218cfa0ad2SJack F Vogel 
29228cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_link_ich8lan");
29238cfa0ad2SJack F Vogel 
29248cfa0ad2SJack F Vogel 	if (hw->phy.ops.check_reset_block(hw))
29258cfa0ad2SJack F Vogel 		goto out;
29268cfa0ad2SJack F Vogel 
29278cfa0ad2SJack F Vogel 	/*
29288cfa0ad2SJack F Vogel 	 * ICH parts do not have a word in the NVM to determine
29298cfa0ad2SJack F Vogel 	 * the default flow control setting, so we explicitly
29308cfa0ad2SJack F Vogel 	 * set it to full.
29318cfa0ad2SJack F Vogel 	 */
2932daf9197cSJack F Vogel 	if (hw->fc.requested_mode == e1000_fc_default)
2933daf9197cSJack F Vogel 		hw->fc.requested_mode = e1000_fc_full;
29348cfa0ad2SJack F Vogel 
2935daf9197cSJack F Vogel 	/*
2936daf9197cSJack F Vogel 	 * Save off the requested flow control mode for use later.  Depending
2937daf9197cSJack F Vogel 	 * on the link partner's capabilities, we may or may not use this mode.
2938daf9197cSJack F Vogel 	 */
2939daf9197cSJack F Vogel 	hw->fc.current_mode = hw->fc.requested_mode;
29408cfa0ad2SJack F Vogel 
2941daf9197cSJack F Vogel 	DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
2942daf9197cSJack F Vogel 		hw->fc.current_mode);
29438cfa0ad2SJack F Vogel 
29448cfa0ad2SJack F Vogel 	/* Continue to configure the copper link. */
29458cfa0ad2SJack F Vogel 	ret_val = hw->mac.ops.setup_physical_interface(hw);
29468cfa0ad2SJack F Vogel 	if (ret_val)
29478cfa0ad2SJack F Vogel 		goto out;
29488cfa0ad2SJack F Vogel 
29498cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
29509d81738fSJack F Vogel 	if ((hw->phy.type == e1000_phy_82578) ||
29519d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577)) {
29529d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw,
29539d81738fSJack F Vogel 		                             PHY_REG(BM_PORT_CTRL_PAGE, 27),
29549d81738fSJack F Vogel 		                             hw->fc.pause_time);
29559d81738fSJack F Vogel 		if (ret_val)
29569d81738fSJack F Vogel 			goto out;
29579d81738fSJack F Vogel 	}
29588cfa0ad2SJack F Vogel 
29598cfa0ad2SJack F Vogel 	ret_val = e1000_set_fc_watermarks_generic(hw);
29608cfa0ad2SJack F Vogel 
29618cfa0ad2SJack F Vogel out:
29628cfa0ad2SJack F Vogel 	return ret_val;
29638cfa0ad2SJack F Vogel }
29648cfa0ad2SJack F Vogel 
29658cfa0ad2SJack F Vogel /**
29668cfa0ad2SJack F Vogel  *  e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
29678cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
29688cfa0ad2SJack F Vogel  *
29698cfa0ad2SJack F Vogel  *  Configures the kumeran interface to the PHY to wait the appropriate time
29708cfa0ad2SJack F Vogel  *  when polling the PHY, then call the generic setup_copper_link to finish
29718cfa0ad2SJack F Vogel  *  configuring the copper link.
29728cfa0ad2SJack F Vogel  **/
29738cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
29748cfa0ad2SJack F Vogel {
29758cfa0ad2SJack F Vogel 	u32 ctrl;
29768cfa0ad2SJack F Vogel 	s32 ret_val;
29778cfa0ad2SJack F Vogel 	u16 reg_data;
29788cfa0ad2SJack F Vogel 
29798cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_copper_link_ich8lan");
29808cfa0ad2SJack F Vogel 
29818cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
29828cfa0ad2SJack F Vogel 	ctrl |= E1000_CTRL_SLU;
29838cfa0ad2SJack F Vogel 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
29848cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
29858cfa0ad2SJack F Vogel 
29868cfa0ad2SJack F Vogel 	/*
29878cfa0ad2SJack F Vogel 	 * Set the mac to wait the maximum time between each iteration
29888cfa0ad2SJack F Vogel 	 * and increase the max iterations when polling the phy;
29898cfa0ad2SJack F Vogel 	 * this fixes erroneous timeouts at 10Mbps.
29908cfa0ad2SJack F Vogel 	 */
29914edd8523SJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_TIMEOUTS,
29928cfa0ad2SJack F Vogel 	                                       0xFFFF);
29938cfa0ad2SJack F Vogel 	if (ret_val)
29948cfa0ad2SJack F Vogel 		goto out;
29959d81738fSJack F Vogel 	ret_val = e1000_read_kmrn_reg_generic(hw,
29969d81738fSJack F Vogel 	                                      E1000_KMRNCTRLSTA_INBAND_PARAM,
29978cfa0ad2SJack F Vogel 	                                      &reg_data);
29988cfa0ad2SJack F Vogel 	if (ret_val)
29998cfa0ad2SJack F Vogel 		goto out;
30008cfa0ad2SJack F Vogel 	reg_data |= 0x3F;
30019d81738fSJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
30029d81738fSJack F Vogel 	                                       E1000_KMRNCTRLSTA_INBAND_PARAM,
30038cfa0ad2SJack F Vogel 	                                       reg_data);
30048cfa0ad2SJack F Vogel 	if (ret_val)
30058cfa0ad2SJack F Vogel 		goto out;
30068cfa0ad2SJack F Vogel 
3007d035aa2dSJack F Vogel 	switch (hw->phy.type) {
3008d035aa2dSJack F Vogel 	case e1000_phy_igp_3:
30098cfa0ad2SJack F Vogel 		ret_val = e1000_copper_link_setup_igp(hw);
30108cfa0ad2SJack F Vogel 		if (ret_val)
30118cfa0ad2SJack F Vogel 			goto out;
3012d035aa2dSJack F Vogel 		break;
3013d035aa2dSJack F Vogel 	case e1000_phy_bm:
30149d81738fSJack F Vogel 	case e1000_phy_82578:
30158cfa0ad2SJack F Vogel 		ret_val = e1000_copper_link_setup_m88(hw);
30168cfa0ad2SJack F Vogel 		if (ret_val)
30178cfa0ad2SJack F Vogel 			goto out;
3018d035aa2dSJack F Vogel 		break;
30199d81738fSJack F Vogel 	case e1000_phy_82577:
30209d81738fSJack F Vogel 		ret_val = e1000_copper_link_setup_82577(hw);
30219d81738fSJack F Vogel 		if (ret_val)
30229d81738fSJack F Vogel 			goto out;
30239d81738fSJack F Vogel 		break;
3024d035aa2dSJack F Vogel 	case e1000_phy_ife:
30258cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL,
30268cfa0ad2SJack F Vogel 		                               &reg_data);
30278cfa0ad2SJack F Vogel 		if (ret_val)
30288cfa0ad2SJack F Vogel 			goto out;
30298cfa0ad2SJack F Vogel 
30308cfa0ad2SJack F Vogel 		reg_data &= ~IFE_PMC_AUTO_MDIX;
30318cfa0ad2SJack F Vogel 
30328cfa0ad2SJack F Vogel 		switch (hw->phy.mdix) {
30338cfa0ad2SJack F Vogel 		case 1:
30348cfa0ad2SJack F Vogel 			reg_data &= ~IFE_PMC_FORCE_MDIX;
30358cfa0ad2SJack F Vogel 			break;
30368cfa0ad2SJack F Vogel 		case 2:
30378cfa0ad2SJack F Vogel 			reg_data |= IFE_PMC_FORCE_MDIX;
30388cfa0ad2SJack F Vogel 			break;
30398cfa0ad2SJack F Vogel 		case 0:
30408cfa0ad2SJack F Vogel 		default:
30418cfa0ad2SJack F Vogel 			reg_data |= IFE_PMC_AUTO_MDIX;
30428cfa0ad2SJack F Vogel 			break;
30438cfa0ad2SJack F Vogel 		}
30448cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL,
30458cfa0ad2SJack F Vogel 		                                reg_data);
30468cfa0ad2SJack F Vogel 		if (ret_val)
30478cfa0ad2SJack F Vogel 			goto out;
3048d035aa2dSJack F Vogel 		break;
3049d035aa2dSJack F Vogel 	default:
3050d035aa2dSJack F Vogel 		break;
30518cfa0ad2SJack F Vogel 	}
30528cfa0ad2SJack F Vogel 	ret_val = e1000_setup_copper_link_generic(hw);
30538cfa0ad2SJack F Vogel 
30548cfa0ad2SJack F Vogel out:
30558cfa0ad2SJack F Vogel 	return ret_val;
30568cfa0ad2SJack F Vogel }
30578cfa0ad2SJack F Vogel 
30588cfa0ad2SJack F Vogel /**
30598cfa0ad2SJack F Vogel  *  e1000_get_link_up_info_ich8lan - Get current link speed and duplex
30608cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
30618cfa0ad2SJack F Vogel  *  @speed: pointer to store current link speed
30628cfa0ad2SJack F Vogel  *  @duplex: pointer to store the current link duplex
30638cfa0ad2SJack F Vogel  *
30648cfa0ad2SJack F Vogel  *  Calls the generic get_speed_and_duplex to retrieve the current link
30658cfa0ad2SJack F Vogel  *  information and then calls the Kumeran lock loss workaround for links at
30668cfa0ad2SJack F Vogel  *  gigabit speeds.
30678cfa0ad2SJack F Vogel  **/
30688cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
30698cfa0ad2SJack F Vogel                                           u16 *duplex)
30708cfa0ad2SJack F Vogel {
30718cfa0ad2SJack F Vogel 	s32 ret_val;
30728cfa0ad2SJack F Vogel 
30738cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_link_up_info_ich8lan");
30748cfa0ad2SJack F Vogel 
30758cfa0ad2SJack F Vogel 	ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
30768cfa0ad2SJack F Vogel 	if (ret_val)
30778cfa0ad2SJack F Vogel 		goto out;
30788cfa0ad2SJack F Vogel 
30798cfa0ad2SJack F Vogel 	if ((hw->mac.type == e1000_ich8lan) &&
30808cfa0ad2SJack F Vogel 	    (hw->phy.type == e1000_phy_igp_3) &&
30818cfa0ad2SJack F Vogel 	    (*speed == SPEED_1000)) {
30828cfa0ad2SJack F Vogel 		ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
30838cfa0ad2SJack F Vogel 	}
30848cfa0ad2SJack F Vogel 
30858cfa0ad2SJack F Vogel out:
30868cfa0ad2SJack F Vogel 	return ret_val;
30878cfa0ad2SJack F Vogel }
30888cfa0ad2SJack F Vogel 
30898cfa0ad2SJack F Vogel /**
30908cfa0ad2SJack F Vogel  *  e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
30918cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
30928cfa0ad2SJack F Vogel  *
30938cfa0ad2SJack F Vogel  *  Work-around for 82566 Kumeran PCS lock loss:
30948cfa0ad2SJack F Vogel  *  On link status change (i.e. PCI reset, speed change) and link is up and
30958cfa0ad2SJack F Vogel  *  speed is gigabit-
30968cfa0ad2SJack F Vogel  *    0) if workaround is optionally disabled do nothing
30978cfa0ad2SJack F Vogel  *    1) wait 1ms for Kumeran link to come up
30988cfa0ad2SJack F Vogel  *    2) check Kumeran Diagnostic register PCS lock loss bit
30998cfa0ad2SJack F Vogel  *    3) if not set the link is locked (all is good), otherwise...
31008cfa0ad2SJack F Vogel  *    4) reset the PHY
31018cfa0ad2SJack F Vogel  *    5) repeat up to 10 times
31028cfa0ad2SJack F Vogel  *  Note: this is only called for IGP3 copper when speed is 1gb.
31038cfa0ad2SJack F Vogel  **/
31048cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
31058cfa0ad2SJack F Vogel {
3106daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
31078cfa0ad2SJack F Vogel 	u32 phy_ctrl;
31088cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
31098cfa0ad2SJack F Vogel 	u16 i, data;
31108cfa0ad2SJack F Vogel 	bool link;
31118cfa0ad2SJack F Vogel 
31128cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan");
31138cfa0ad2SJack F Vogel 
31148cfa0ad2SJack F Vogel 	if (!(dev_spec->kmrn_lock_loss_workaround_enabled))
31158cfa0ad2SJack F Vogel 		goto out;
31168cfa0ad2SJack F Vogel 
31178cfa0ad2SJack F Vogel 	/*
31188cfa0ad2SJack F Vogel 	 * Make sure link is up before proceeding.  If not just return.
31198cfa0ad2SJack F Vogel 	 * Attempting this while link is negotiating fouled up link
31208cfa0ad2SJack F Vogel 	 * stability
31218cfa0ad2SJack F Vogel 	 */
31228cfa0ad2SJack F Vogel 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
31238cfa0ad2SJack F Vogel 	if (!link) {
31248cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
31258cfa0ad2SJack F Vogel 		goto out;
31268cfa0ad2SJack F Vogel 	}
31278cfa0ad2SJack F Vogel 
31288cfa0ad2SJack F Vogel 	for (i = 0; i < 10; i++) {
31298cfa0ad2SJack F Vogel 		/* read once to clear */
31308cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
31318cfa0ad2SJack F Vogel 		if (ret_val)
31328cfa0ad2SJack F Vogel 			goto out;
31338cfa0ad2SJack F Vogel 		/* and again to get new status */
31348cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
31358cfa0ad2SJack F Vogel 		if (ret_val)
31368cfa0ad2SJack F Vogel 			goto out;
31378cfa0ad2SJack F Vogel 
31388cfa0ad2SJack F Vogel 		/* check for PCS lock */
31398cfa0ad2SJack F Vogel 		if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) {
31408cfa0ad2SJack F Vogel 			ret_val = E1000_SUCCESS;
31418cfa0ad2SJack F Vogel 			goto out;
31428cfa0ad2SJack F Vogel 		}
31438cfa0ad2SJack F Vogel 
31448cfa0ad2SJack F Vogel 		/* Issue PHY reset */
31458cfa0ad2SJack F Vogel 		hw->phy.ops.reset(hw);
31468cfa0ad2SJack F Vogel 		msec_delay_irq(5);
31478cfa0ad2SJack F Vogel 	}
31488cfa0ad2SJack F Vogel 	/* Disable GigE link negotiation */
31498cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
31508cfa0ad2SJack F Vogel 	phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
31518cfa0ad2SJack F Vogel 	             E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
31528cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
31538cfa0ad2SJack F Vogel 
31548cfa0ad2SJack F Vogel 	/*
31558cfa0ad2SJack F Vogel 	 * Call gig speed drop workaround on Gig disable before accessing
31568cfa0ad2SJack F Vogel 	 * any PHY registers
31578cfa0ad2SJack F Vogel 	 */
31588cfa0ad2SJack F Vogel 	e1000_gig_downshift_workaround_ich8lan(hw);
31598cfa0ad2SJack F Vogel 
31608cfa0ad2SJack F Vogel 	/* unable to acquire PCS lock */
31618cfa0ad2SJack F Vogel 	ret_val = -E1000_ERR_PHY;
31628cfa0ad2SJack F Vogel 
31638cfa0ad2SJack F Vogel out:
31648cfa0ad2SJack F Vogel 	return ret_val;
31658cfa0ad2SJack F Vogel }
31668cfa0ad2SJack F Vogel 
31678cfa0ad2SJack F Vogel /**
31688cfa0ad2SJack F Vogel  *  e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
31698cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
31708cfa0ad2SJack F Vogel  *  @state: boolean value used to set the current Kumeran workaround state
31718cfa0ad2SJack F Vogel  *
31728cfa0ad2SJack F Vogel  *  If ICH8, set the current Kumeran workaround state (enabled - TRUE
31738cfa0ad2SJack F Vogel  *  /disabled - FALSE).
31748cfa0ad2SJack F Vogel  **/
31758cfa0ad2SJack F Vogel void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
31768cfa0ad2SJack F Vogel                                                  bool state)
31778cfa0ad2SJack F Vogel {
3178daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
31798cfa0ad2SJack F Vogel 
31808cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan");
31818cfa0ad2SJack F Vogel 
31828cfa0ad2SJack F Vogel 	if (hw->mac.type != e1000_ich8lan) {
31838cfa0ad2SJack F Vogel 		DEBUGOUT("Workaround applies to ICH8 only.\n");
3184daf9197cSJack F Vogel 		return;
31858cfa0ad2SJack F Vogel 	}
31868cfa0ad2SJack F Vogel 
31878cfa0ad2SJack F Vogel 	dev_spec->kmrn_lock_loss_workaround_enabled = state;
31888cfa0ad2SJack F Vogel 
31898cfa0ad2SJack F Vogel 	return;
31908cfa0ad2SJack F Vogel }
31918cfa0ad2SJack F Vogel 
31928cfa0ad2SJack F Vogel /**
31938cfa0ad2SJack F Vogel  *  e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
31948cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
31958cfa0ad2SJack F Vogel  *
31968cfa0ad2SJack F Vogel  *  Workaround for 82566 power-down on D3 entry:
31978cfa0ad2SJack F Vogel  *    1) disable gigabit link
31988cfa0ad2SJack F Vogel  *    2) write VR power-down enable
31998cfa0ad2SJack F Vogel  *    3) read it back
32008cfa0ad2SJack F Vogel  *  Continue if successful, else issue LCD reset and repeat
32018cfa0ad2SJack F Vogel  **/
32028cfa0ad2SJack F Vogel void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
32038cfa0ad2SJack F Vogel {
32048cfa0ad2SJack F Vogel 	u32 reg;
32058cfa0ad2SJack F Vogel 	u16 data;
32068cfa0ad2SJack F Vogel 	u8  retry = 0;
32078cfa0ad2SJack F Vogel 
32088cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan");
32098cfa0ad2SJack F Vogel 
32108cfa0ad2SJack F Vogel 	if (hw->phy.type != e1000_phy_igp_3)
32118cfa0ad2SJack F Vogel 		goto out;
32128cfa0ad2SJack F Vogel 
32138cfa0ad2SJack F Vogel 	/* Try the workaround twice (if needed) */
32148cfa0ad2SJack F Vogel 	do {
32158cfa0ad2SJack F Vogel 		/* Disable link */
32168cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
32178cfa0ad2SJack F Vogel 		reg |= (E1000_PHY_CTRL_GBE_DISABLE |
32188cfa0ad2SJack F Vogel 		        E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
32198cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg);
32208cfa0ad2SJack F Vogel 
32218cfa0ad2SJack F Vogel 		/*
32228cfa0ad2SJack F Vogel 		 * Call gig speed drop workaround on Gig disable before
32238cfa0ad2SJack F Vogel 		 * accessing any PHY registers
32248cfa0ad2SJack F Vogel 		 */
32258cfa0ad2SJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
32268cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
32278cfa0ad2SJack F Vogel 
32288cfa0ad2SJack F Vogel 		/* Write VR power-down enable */
32298cfa0ad2SJack F Vogel 		hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
32308cfa0ad2SJack F Vogel 		data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
3231daf9197cSJack F Vogel 		hw->phy.ops.write_reg(hw, IGP3_VR_CTRL,
32328cfa0ad2SJack F Vogel 		                   data | IGP3_VR_CTRL_MODE_SHUTDOWN);
32338cfa0ad2SJack F Vogel 
32348cfa0ad2SJack F Vogel 		/* Read it back and test */
32358cfa0ad2SJack F Vogel 		hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
32368cfa0ad2SJack F Vogel 		data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
32378cfa0ad2SJack F Vogel 		if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
32388cfa0ad2SJack F Vogel 			break;
32398cfa0ad2SJack F Vogel 
32408cfa0ad2SJack F Vogel 		/* Issue PHY reset and repeat at most one more time */
32418cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_CTRL);
32428cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST);
32438cfa0ad2SJack F Vogel 		retry++;
32448cfa0ad2SJack F Vogel 	} while (retry);
32458cfa0ad2SJack F Vogel 
32468cfa0ad2SJack F Vogel out:
32478cfa0ad2SJack F Vogel 	return;
32488cfa0ad2SJack F Vogel }
32498cfa0ad2SJack F Vogel 
32508cfa0ad2SJack F Vogel /**
32518cfa0ad2SJack F Vogel  *  e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working
32528cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
32538cfa0ad2SJack F Vogel  *
32548cfa0ad2SJack F Vogel  *  Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
32558cfa0ad2SJack F Vogel  *  LPLU, Gig disable, MDIC PHY reset):
32568cfa0ad2SJack F Vogel  *    1) Set Kumeran Near-end loopback
32578cfa0ad2SJack F Vogel  *    2) Clear Kumeran Near-end loopback
32588cfa0ad2SJack F Vogel  *  Should only be called for ICH8[m] devices with IGP_3 Phy.
32598cfa0ad2SJack F Vogel  **/
32608cfa0ad2SJack F Vogel void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
32618cfa0ad2SJack F Vogel {
32628cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
32638cfa0ad2SJack F Vogel 	u16 reg_data;
32648cfa0ad2SJack F Vogel 
32658cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan");
32668cfa0ad2SJack F Vogel 
32678cfa0ad2SJack F Vogel 	if ((hw->mac.type != e1000_ich8lan) ||
32688cfa0ad2SJack F Vogel 	    (hw->phy.type != e1000_phy_igp_3))
32698cfa0ad2SJack F Vogel 		goto out;
32708cfa0ad2SJack F Vogel 
32718cfa0ad2SJack F Vogel 	ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
32728cfa0ad2SJack F Vogel 	                                      &reg_data);
32738cfa0ad2SJack F Vogel 	if (ret_val)
32748cfa0ad2SJack F Vogel 		goto out;
32758cfa0ad2SJack F Vogel 	reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
32768cfa0ad2SJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
32778cfa0ad2SJack F Vogel 	                                       E1000_KMRNCTRLSTA_DIAG_OFFSET,
32788cfa0ad2SJack F Vogel 	                                       reg_data);
32798cfa0ad2SJack F Vogel 	if (ret_val)
32808cfa0ad2SJack F Vogel 		goto out;
32818cfa0ad2SJack F Vogel 	reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
32828cfa0ad2SJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
32838cfa0ad2SJack F Vogel 	                                       E1000_KMRNCTRLSTA_DIAG_OFFSET,
32848cfa0ad2SJack F Vogel 	                                       reg_data);
32858cfa0ad2SJack F Vogel out:
32868cfa0ad2SJack F Vogel 	return;
32878cfa0ad2SJack F Vogel }
32888cfa0ad2SJack F Vogel 
32898cfa0ad2SJack F Vogel /**
32908cfa0ad2SJack F Vogel  *  e1000_disable_gig_wol_ich8lan - disable gig during WoL
32918cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
32928cfa0ad2SJack F Vogel  *
32938cfa0ad2SJack F Vogel  *  During S0 to Sx transition, it is possible the link remains at gig
32948cfa0ad2SJack F Vogel  *  instead of negotiating to a lower speed.  Before going to Sx, set
32958cfa0ad2SJack F Vogel  *  'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
32968cfa0ad2SJack F Vogel  *  to a lower speed.
32978cfa0ad2SJack F Vogel  *
3298d035aa2dSJack F Vogel  *  Should only be called for applicable parts.
32998cfa0ad2SJack F Vogel  **/
33008cfa0ad2SJack F Vogel void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw)
33018cfa0ad2SJack F Vogel {
33028cfa0ad2SJack F Vogel 	u32 phy_ctrl;
33038cfa0ad2SJack F Vogel 
3304d035aa2dSJack F Vogel 	switch (hw->mac.type) {
33054edd8523SJack F Vogel 	case e1000_ich8lan:
3306d035aa2dSJack F Vogel 	case e1000_ich9lan:
3307d035aa2dSJack F Vogel 	case e1000_ich10lan:
33089d81738fSJack F Vogel 	case e1000_pchlan:
33098cfa0ad2SJack F Vogel 		phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
33108cfa0ad2SJack F Vogel 		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
33118cfa0ad2SJack F Vogel 		            E1000_PHY_CTRL_GBE_DISABLE;
33128cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
33139d81738fSJack F Vogel 
33149d81738fSJack F Vogel 		if (hw->mac.type == e1000_pchlan)
33154edd8523SJack F Vogel 			e1000_phy_hw_reset_ich8lan(hw);
3316d035aa2dSJack F Vogel 	default:
3317d035aa2dSJack F Vogel 		break;
33188cfa0ad2SJack F Vogel 	}
33198cfa0ad2SJack F Vogel 
33208cfa0ad2SJack F Vogel 	return;
33218cfa0ad2SJack F Vogel }
33228cfa0ad2SJack F Vogel 
33238cfa0ad2SJack F Vogel /**
33248cfa0ad2SJack F Vogel  *  e1000_cleanup_led_ich8lan - Restore the default LED operation
33258cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
33268cfa0ad2SJack F Vogel  *
33278cfa0ad2SJack F Vogel  *  Return the LED back to the default configuration.
33288cfa0ad2SJack F Vogel  **/
33298cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
33308cfa0ad2SJack F Vogel {
33318cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_cleanup_led_ich8lan");
33328cfa0ad2SJack F Vogel 
33338cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
3334a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
33358cfa0ad2SJack F Vogel 		                             0);
33368cfa0ad2SJack F Vogel 
3337a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
3338a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
33398cfa0ad2SJack F Vogel }
33408cfa0ad2SJack F Vogel 
33418cfa0ad2SJack F Vogel /**
33428cfa0ad2SJack F Vogel  *  e1000_led_on_ich8lan - Turn LEDs on
33438cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
33448cfa0ad2SJack F Vogel  *
33458cfa0ad2SJack F Vogel  *  Turn on the LEDs.
33468cfa0ad2SJack F Vogel  **/
33478cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw)
33488cfa0ad2SJack F Vogel {
33498cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_led_on_ich8lan");
33508cfa0ad2SJack F Vogel 
33518cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
3352a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
33538cfa0ad2SJack F Vogel 		                (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
33548cfa0ad2SJack F Vogel 
3355a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
3356a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
33578cfa0ad2SJack F Vogel }
33588cfa0ad2SJack F Vogel 
33598cfa0ad2SJack F Vogel /**
33608cfa0ad2SJack F Vogel  *  e1000_led_off_ich8lan - Turn LEDs off
33618cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
33628cfa0ad2SJack F Vogel  *
33638cfa0ad2SJack F Vogel  *  Turn off the LEDs.
33648cfa0ad2SJack F Vogel  **/
33658cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
33668cfa0ad2SJack F Vogel {
33678cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_led_off_ich8lan");
33688cfa0ad2SJack F Vogel 
33698cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
3370a69ed8dfSJack F Vogel 		return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
33718cfa0ad2SJack F Vogel 		               (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
33728cfa0ad2SJack F Vogel 
3373a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
3374a69ed8dfSJack F Vogel 	return E1000_SUCCESS;
33758cfa0ad2SJack F Vogel }
33768cfa0ad2SJack F Vogel 
33778cfa0ad2SJack F Vogel /**
33789d81738fSJack F Vogel  *  e1000_setup_led_pchlan - Configures SW controllable LED
33799d81738fSJack F Vogel  *  @hw: pointer to the HW structure
33809d81738fSJack F Vogel  *
33819d81738fSJack F Vogel  *  This prepares the SW controllable LED for use.
33829d81738fSJack F Vogel  **/
33839d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw)
33849d81738fSJack F Vogel {
33859d81738fSJack F Vogel 	DEBUGFUNC("e1000_setup_led_pchlan");
33869d81738fSJack F Vogel 
33879d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
33889d81738fSJack F Vogel 					(u16)hw->mac.ledctl_mode1);
33899d81738fSJack F Vogel }
33909d81738fSJack F Vogel 
33919d81738fSJack F Vogel /**
33929d81738fSJack F Vogel  *  e1000_cleanup_led_pchlan - Restore the default LED operation
33939d81738fSJack F Vogel  *  @hw: pointer to the HW structure
33949d81738fSJack F Vogel  *
33959d81738fSJack F Vogel  *  Return the LED back to the default configuration.
33969d81738fSJack F Vogel  **/
33979d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw)
33989d81738fSJack F Vogel {
33999d81738fSJack F Vogel 	DEBUGFUNC("e1000_cleanup_led_pchlan");
34009d81738fSJack F Vogel 
34019d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
34029d81738fSJack F Vogel 					(u16)hw->mac.ledctl_default);
34039d81738fSJack F Vogel }
34049d81738fSJack F Vogel 
34059d81738fSJack F Vogel /**
34069d81738fSJack F Vogel  *  e1000_led_on_pchlan - Turn LEDs on
34079d81738fSJack F Vogel  *  @hw: pointer to the HW structure
34089d81738fSJack F Vogel  *
34099d81738fSJack F Vogel  *  Turn on the LEDs.
34109d81738fSJack F Vogel  **/
34119d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw)
34129d81738fSJack F Vogel {
34139d81738fSJack F Vogel 	u16 data = (u16)hw->mac.ledctl_mode2;
34149d81738fSJack F Vogel 	u32 i, led;
34159d81738fSJack F Vogel 
34169d81738fSJack F Vogel 	DEBUGFUNC("e1000_led_on_pchlan");
34179d81738fSJack F Vogel 
34189d81738fSJack F Vogel 	/*
34199d81738fSJack F Vogel 	 * If no link, then turn LED on by setting the invert bit
34209d81738fSJack F Vogel 	 * for each LED that's mode is "link_up" in ledctl_mode2.
34219d81738fSJack F Vogel 	 */
34229d81738fSJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
34239d81738fSJack F Vogel 		for (i = 0; i < 3; i++) {
34249d81738fSJack F Vogel 			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
34259d81738fSJack F Vogel 			if ((led & E1000_PHY_LED0_MODE_MASK) !=
34269d81738fSJack F Vogel 			    E1000_LEDCTL_MODE_LINK_UP)
34279d81738fSJack F Vogel 				continue;
34289d81738fSJack F Vogel 			if (led & E1000_PHY_LED0_IVRT)
34299d81738fSJack F Vogel 				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
34309d81738fSJack F Vogel 			else
34319d81738fSJack F Vogel 				data |= (E1000_PHY_LED0_IVRT << (i * 5));
34329d81738fSJack F Vogel 		}
34339d81738fSJack F Vogel 	}
34349d81738fSJack F Vogel 
34359d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
34369d81738fSJack F Vogel }
34379d81738fSJack F Vogel 
34389d81738fSJack F Vogel /**
34399d81738fSJack F Vogel  *  e1000_led_off_pchlan - Turn LEDs off
34409d81738fSJack F Vogel  *  @hw: pointer to the HW structure
34419d81738fSJack F Vogel  *
34429d81738fSJack F Vogel  *  Turn off the LEDs.
34439d81738fSJack F Vogel  **/
34449d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw)
34459d81738fSJack F Vogel {
34469d81738fSJack F Vogel 	u16 data = (u16)hw->mac.ledctl_mode1;
34479d81738fSJack F Vogel 	u32 i, led;
34489d81738fSJack F Vogel 
34499d81738fSJack F Vogel 	DEBUGFUNC("e1000_led_off_pchlan");
34509d81738fSJack F Vogel 
34519d81738fSJack F Vogel 	/*
34529d81738fSJack F Vogel 	 * If no link, then turn LED off by clearing the invert bit
34539d81738fSJack F Vogel 	 * for each LED that's mode is "link_up" in ledctl_mode1.
34549d81738fSJack F Vogel 	 */
34559d81738fSJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
34569d81738fSJack F Vogel 		for (i = 0; i < 3; i++) {
34579d81738fSJack F Vogel 			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
34589d81738fSJack F Vogel 			if ((led & E1000_PHY_LED0_MODE_MASK) !=
34599d81738fSJack F Vogel 			    E1000_LEDCTL_MODE_LINK_UP)
34609d81738fSJack F Vogel 				continue;
34619d81738fSJack F Vogel 			if (led & E1000_PHY_LED0_IVRT)
34629d81738fSJack F Vogel 				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
34639d81738fSJack F Vogel 			else
34649d81738fSJack F Vogel 				data |= (E1000_PHY_LED0_IVRT << (i * 5));
34659d81738fSJack F Vogel 		}
34669d81738fSJack F Vogel 	}
34679d81738fSJack F Vogel 
34689d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
34699d81738fSJack F Vogel }
34709d81738fSJack F Vogel 
34719d81738fSJack F Vogel /**
34728cfa0ad2SJack F Vogel  *  e1000_get_cfg_done_ich8lan - Read config done bit
34738cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
34748cfa0ad2SJack F Vogel  *
34758cfa0ad2SJack F Vogel  *  Read the management control register for the config done bit for
34768cfa0ad2SJack F Vogel  *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
34778cfa0ad2SJack F Vogel  *  to read the config done bit, so an error is *ONLY* logged and returns
34788cfa0ad2SJack F Vogel  *  E1000_SUCCESS.  If we were to return with error, EEPROM-less silicon
34798cfa0ad2SJack F Vogel  *  would not be able to be reset or change link.
34808cfa0ad2SJack F Vogel  **/
34818cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
34828cfa0ad2SJack F Vogel {
34838cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
34848cfa0ad2SJack F Vogel 	u32 bank = 0;
34858cfa0ad2SJack F Vogel 
34869d81738fSJack F Vogel 	if (hw->mac.type >= e1000_pchlan) {
34879d81738fSJack F Vogel 		u32 status = E1000_READ_REG(hw, E1000_STATUS);
34889d81738fSJack F Vogel 
34894edd8523SJack F Vogel 		if (status & E1000_STATUS_PHYRA)
34909d81738fSJack F Vogel 			E1000_WRITE_REG(hw, E1000_STATUS, status &
34919d81738fSJack F Vogel 			                ~E1000_STATUS_PHYRA);
34924edd8523SJack F Vogel 		else
34939d81738fSJack F Vogel 			DEBUGOUT("PHY Reset Asserted not set - needs delay\n");
34949d81738fSJack F Vogel 	}
34959d81738fSJack F Vogel 
34968cfa0ad2SJack F Vogel 	e1000_get_cfg_done_generic(hw);
34978cfa0ad2SJack F Vogel 
34988cfa0ad2SJack F Vogel 	/* If EEPROM is not marked present, init the IGP 3 PHY manually */
34994edd8523SJack F Vogel 	if (hw->mac.type <= e1000_ich9lan) {
35008cfa0ad2SJack F Vogel 		if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
35018cfa0ad2SJack F Vogel 		    (hw->phy.type == e1000_phy_igp_3)) {
35028cfa0ad2SJack F Vogel 			e1000_phy_init_script_igp3(hw);
35038cfa0ad2SJack F Vogel 		}
35048cfa0ad2SJack F Vogel 	} else {
35058cfa0ad2SJack F Vogel 		if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
3506daf9197cSJack F Vogel 			/* Maybe we should do a basic PHY config */
35078cfa0ad2SJack F Vogel 			DEBUGOUT("EEPROM not present\n");
35088cfa0ad2SJack F Vogel 			ret_val = -E1000_ERR_CONFIG;
35098cfa0ad2SJack F Vogel 		}
35108cfa0ad2SJack F Vogel 	}
35118cfa0ad2SJack F Vogel 
35128cfa0ad2SJack F Vogel 	return ret_val;
35138cfa0ad2SJack F Vogel }
35148cfa0ad2SJack F Vogel 
35158cfa0ad2SJack F Vogel /**
35168cfa0ad2SJack F Vogel  * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down
35178cfa0ad2SJack F Vogel  * @hw: pointer to the HW structure
35188cfa0ad2SJack F Vogel  *
35198cfa0ad2SJack F Vogel  * In the case of a PHY power down to save power, or to turn off link during a
35208cfa0ad2SJack F Vogel  * driver unload, or wake on lan is not enabled, remove the link.
35218cfa0ad2SJack F Vogel  **/
35228cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
35238cfa0ad2SJack F Vogel {
35248cfa0ad2SJack F Vogel 	/* If the management interface is not enabled, then power down */
3525daf9197cSJack F Vogel 	if (!(hw->mac.ops.check_mng_mode(hw) ||
3526daf9197cSJack F Vogel 	      hw->phy.ops.check_reset_block(hw)))
35278cfa0ad2SJack F Vogel 		e1000_power_down_phy_copper(hw);
35288cfa0ad2SJack F Vogel 
35298cfa0ad2SJack F Vogel 	return;
35308cfa0ad2SJack F Vogel }
35318cfa0ad2SJack F Vogel 
35328cfa0ad2SJack F Vogel /**
35338cfa0ad2SJack F Vogel  *  e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
35348cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
35358cfa0ad2SJack F Vogel  *
35368cfa0ad2SJack F Vogel  *  Clears hardware counters specific to the silicon family and calls
35378cfa0ad2SJack F Vogel  *  clear_hw_cntrs_generic to clear all general purpose counters.
35388cfa0ad2SJack F Vogel  **/
35398cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
35408cfa0ad2SJack F Vogel {
35419d81738fSJack F Vogel 	u16 phy_data;
35429d81738fSJack F Vogel 
35438cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan");
35448cfa0ad2SJack F Vogel 
35458cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_base_generic(hw);
35468cfa0ad2SJack F Vogel 
3547daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ALGNERRC);
3548daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_RXERRC);
3549daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TNCRS);
3550daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_CEXTERR);
3551daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTC);
3552daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTFC);
35538cfa0ad2SJack F Vogel 
3554daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPRC);
3555daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPDC);
3556daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPTC);
35578cfa0ad2SJack F Vogel 
3558daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_IAC);
3559daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ICRXOC);
35609d81738fSJack F Vogel 
35619d81738fSJack F Vogel 	/* Clear PHY statistics registers */
35629d81738fSJack F Vogel 	if ((hw->phy.type == e1000_phy_82578) ||
35639d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577)) {
35649d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data);
35659d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data);
35669d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_ECOL_UPPER, &phy_data);
35679d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_ECOL_LOWER, &phy_data);
35689d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_MCC_UPPER, &phy_data);
35699d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_MCC_LOWER, &phy_data);
35709d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_LATECOL_UPPER, &phy_data);
35719d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_LATECOL_LOWER, &phy_data);
35729d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_COLC_UPPER, &phy_data);
35739d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_COLC_LOWER, &phy_data);
35749d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_DC_UPPER, &phy_data);
35759d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_DC_LOWER, &phy_data);
35769d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_TNCRS_UPPER, &phy_data);
35779d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_TNCRS_LOWER, &phy_data);
35789d81738fSJack F Vogel 	}
35798cfa0ad2SJack F Vogel }
35808cfa0ad2SJack F Vogel 
3581