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