14919Sxy150489 /*
24919Sxy150489 * This file is provided under a CDDLv1 license. When using or
34919Sxy150489 * redistributing this file, you may do so under this license.
44919Sxy150489 * In redistributing this file this license must be included
54919Sxy150489 * and no other modification of this header file is permitted.
64919Sxy150489 *
74919Sxy150489 * CDDL LICENSE SUMMARY
84919Sxy150489 *
98479SChenlu.Chen@Sun.COM * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
104919Sxy150489 *
114919Sxy150489 * The contents of this file are subject to the terms of Version
124919Sxy150489 * 1.0 of the Common Development and Distribution License (the "License").
134919Sxy150489 *
144919Sxy150489 * You should have received a copy of the License with this software.
154919Sxy150489 * You can obtain a copy of the License at
164919Sxy150489 * http://www.opensolaris.org/os/licensing.
174919Sxy150489 * See the License for the specific language governing permissions
184919Sxy150489 * and limitations under the License.
194919Sxy150489 */
204919Sxy150489
214919Sxy150489 /*
228479SChenlu.Chen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
234919Sxy150489 * Use is subject to license terms of the CDDLv1.
244919Sxy150489 */
254919Sxy150489
264919Sxy150489 /*
2711020SMin.Xu@Sun.COM * IntelVersion: 1.68 v3-1-10-1_2009-9-18_Release14-6
284919Sxy150489 */
296735Scc210113
304919Sxy150489 /*
318479SChenlu.Chen@Sun.COM * 82541EI Gigabit Ethernet Controller
328479SChenlu.Chen@Sun.COM * 82541ER Gigabit Ethernet Controller
338479SChenlu.Chen@Sun.COM * 82541GI Gigabit Ethernet Controller
348479SChenlu.Chen@Sun.COM * 82541PI Gigabit Ethernet Controller
358479SChenlu.Chen@Sun.COM * 82547EI Gigabit Ethernet Controller
368479SChenlu.Chen@Sun.COM * 82547GI Gigabit Ethernet Controller
374919Sxy150489 */
384919Sxy150489
394919Sxy150489 #include "e1000_api.h"
404919Sxy150489
414919Sxy150489 static s32 e1000_init_phy_params_82541(struct e1000_hw *hw);
424919Sxy150489 static s32 e1000_init_nvm_params_82541(struct e1000_hw *hw);
434919Sxy150489 static s32 e1000_init_mac_params_82541(struct e1000_hw *hw);
444919Sxy150489 static s32 e1000_reset_hw_82541(struct e1000_hw *hw);
454919Sxy150489 static s32 e1000_init_hw_82541(struct e1000_hw *hw);
464919Sxy150489 static s32 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed,
474919Sxy150489 u16 *duplex);
484919Sxy150489 static s32 e1000_phy_hw_reset_82541(struct e1000_hw *hw);
494919Sxy150489 static s32 e1000_setup_copper_link_82541(struct e1000_hw *hw);
504919Sxy150489 static s32 e1000_check_for_link_82541(struct e1000_hw *hw);
514919Sxy150489 static s32 e1000_get_cable_length_igp_82541(struct e1000_hw *hw);
524919Sxy150489 static s32 e1000_set_d3_lplu_state_82541(struct e1000_hw *hw,
536735Scc210113 bool active);
544919Sxy150489 static s32 e1000_setup_led_82541(struct e1000_hw *hw);
554919Sxy150489 static s32 e1000_cleanup_led_82541(struct e1000_hw *hw);
564919Sxy150489 static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw);
574919Sxy150489 static s32 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
586735Scc210113 bool link_up);
594919Sxy150489 static s32 e1000_phy_init_script_82541(struct e1000_hw *hw);
606735Scc210113 static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw);
614919Sxy150489
624919Sxy150489 static const u16 e1000_igp_cable_length_table[] =
634919Sxy150489 {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
644919Sxy150489 5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25,
654919Sxy150489 25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40,
664919Sxy150489 40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60,
674919Sxy150489 60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90,
684919Sxy150489 90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
694919Sxy150489 100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
704919Sxy150489 110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120};
714919Sxy150489
724919Sxy150489 #define IGP01E1000_AGC_LENGTH_TABLE_SIZE \
734919Sxy150489 (sizeof (e1000_igp_cable_length_table) / \
744919Sxy150489 sizeof (e1000_igp_cable_length_table[0]))
754919Sxy150489
764919Sxy150489 /*
774919Sxy150489 * e1000_init_phy_params_82541 - Init PHY func ptrs.
784919Sxy150489 * @hw: pointer to the HW structure
794919Sxy150489 */
804919Sxy150489 static s32
e1000_init_phy_params_82541(struct e1000_hw * hw)814919Sxy150489 e1000_init_phy_params_82541(struct e1000_hw *hw)
824919Sxy150489 {
834919Sxy150489 struct e1000_phy_info *phy = &hw->phy;
844919Sxy150489 s32 ret_val = E1000_SUCCESS;
854919Sxy150489
864919Sxy150489 DEBUGFUNC("e1000_init_phy_params_82541");
874919Sxy150489
884919Sxy150489 phy->addr = 1;
894919Sxy150489 phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
904919Sxy150489 phy->reset_delay_us = 10000;
914919Sxy150489 phy->type = e1000_phy_igp;
924919Sxy150489
934919Sxy150489 /* Function Pointers */
946735Scc210113 phy->ops.check_polarity = e1000_check_polarity_igp;
956735Scc210113 phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
966735Scc210113 phy->ops.get_cable_length = e1000_get_cable_length_igp_82541;
976735Scc210113 phy->ops.get_cfg_done = e1000_get_cfg_done_generic;
986735Scc210113 phy->ops.get_info = e1000_get_phy_info_igp;
996735Scc210113 phy->ops.read_reg = e1000_read_phy_reg_igp;
1006735Scc210113 phy->ops.reset = e1000_phy_hw_reset_82541;
1016735Scc210113 phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_82541;
1026735Scc210113 phy->ops.write_reg = e1000_write_phy_reg_igp;
1036735Scc210113 phy->ops.power_up = e1000_power_up_phy_copper;
1046735Scc210113 phy->ops.power_down = e1000_power_down_phy_copper_82541;
1054919Sxy150489
1064919Sxy150489 ret_val = e1000_get_phy_id(hw);
1074919Sxy150489 if (ret_val)
1084919Sxy150489 goto out;
1094919Sxy150489
1104919Sxy150489 /* Verify phy id */
1114919Sxy150489 if (phy->id != IGP01E1000_I_PHY_ID) {
1124919Sxy150489 ret_val = -E1000_ERR_PHY;
1134919Sxy150489 goto out;
1144919Sxy150489 }
11510680SMin.Xu@Sun.COM
1164919Sxy150489 out:
1174919Sxy150489 return (ret_val);
1184919Sxy150489 }
1194919Sxy150489
1204919Sxy150489 /*
1214919Sxy150489 * e1000_init_nvm_params_82541 - Init NVM func ptrs.
1224919Sxy150489 * @hw: pointer to the HW structure
1234919Sxy150489 */
1244919Sxy150489 static s32
e1000_init_nvm_params_82541(struct e1000_hw * hw)1254919Sxy150489 e1000_init_nvm_params_82541(struct e1000_hw *hw)
1264919Sxy150489 {
1274919Sxy150489 struct e1000_nvm_info *nvm = &hw->nvm;
1284919Sxy150489 s32 ret_val = E1000_SUCCESS;
1294919Sxy150489 u32 eecd = E1000_READ_REG(hw, E1000_EECD);
1304919Sxy150489 u16 size;
1314919Sxy150489
1324919Sxy150489 DEBUGFUNC("e1000_init_nvm_params_82541");
1334919Sxy150489
1344919Sxy150489 switch (nvm->override) {
1354919Sxy150489 case e1000_nvm_override_spi_large:
1364919Sxy150489 nvm->type = e1000_nvm_eeprom_spi;
1374919Sxy150489 eecd |= E1000_EECD_ADDR_BITS;
1384919Sxy150489 break;
1394919Sxy150489 case e1000_nvm_override_spi_small:
1404919Sxy150489 nvm->type = e1000_nvm_eeprom_spi;
1414919Sxy150489 eecd &= ~E1000_EECD_ADDR_BITS;
1424919Sxy150489 break;
1434919Sxy150489 case e1000_nvm_override_microwire_large:
1444919Sxy150489 nvm->type = e1000_nvm_eeprom_microwire;
1454919Sxy150489 eecd |= E1000_EECD_SIZE;
1464919Sxy150489 break;
1474919Sxy150489 case e1000_nvm_override_microwire_small:
1484919Sxy150489 nvm->type = e1000_nvm_eeprom_microwire;
1494919Sxy150489 eecd &= ~E1000_EECD_SIZE;
1504919Sxy150489 break;
1514919Sxy150489 default:
1524919Sxy150489 nvm->type = eecd & E1000_EECD_TYPE
1534919Sxy150489 ? e1000_nvm_eeprom_spi
1544919Sxy150489 : e1000_nvm_eeprom_microwire;
1554919Sxy150489 break;
1564919Sxy150489 }
1574919Sxy150489
1584919Sxy150489 if (nvm->type == e1000_nvm_eeprom_spi) {
1594919Sxy150489 nvm->address_bits = (eecd & E1000_EECD_ADDR_BITS)
1604919Sxy150489 ? 16 : 8;
1614919Sxy150489 nvm->delay_usec = 1;
1624919Sxy150489 nvm->opcode_bits = 8;
1634919Sxy150489 nvm->page_size = (eecd & E1000_EECD_ADDR_BITS)
1644919Sxy150489 ? 32 : 8;
1654919Sxy150489
1664919Sxy150489 /* Function Pointers */
1676735Scc210113 nvm->ops.acquire = e1000_acquire_nvm_generic;
1686735Scc210113 nvm->ops.read = e1000_read_nvm_spi;
1696735Scc210113 nvm->ops.release = e1000_release_nvm_generic;
1706735Scc210113 nvm->ops.update = e1000_update_nvm_checksum_generic;
1716735Scc210113 nvm->ops.valid_led_default = e1000_valid_led_default_generic;
1726735Scc210113 nvm->ops.validate = e1000_validate_nvm_checksum_generic;
1736735Scc210113 nvm->ops.write = e1000_write_nvm_spi;
1744919Sxy150489
1754919Sxy150489 /*
1764919Sxy150489 * nvm->word_size must be discovered after the pointers
1774919Sxy150489 * are set so we can verify the size from the nvm image
1784919Sxy150489 * itself. Temporarily set it to a dummy value so the
1794919Sxy150489 * read will work.
1804919Sxy150489 */
1814919Sxy150489 nvm->word_size = 64;
1826735Scc210113 ret_val = nvm->ops.read(hw, NVM_CFG, 1, &size);
1834919Sxy150489 if (ret_val)
1844919Sxy150489 goto out;
1854919Sxy150489 size = (size & NVM_SIZE_MASK) >> NVM_SIZE_SHIFT;
1864919Sxy150489 /*
1874919Sxy150489 * if size != 0, it can be added to a constant and become
1884919Sxy150489 * the left-shift value to set the word_size. Otherwise,
1894919Sxy150489 * word_size stays at 64.
1904919Sxy150489 */
1914919Sxy150489 if (size) {
1924919Sxy150489 size += NVM_WORD_SIZE_BASE_SHIFT_82541;
1934919Sxy150489 nvm->word_size = 1 << size;
1944919Sxy150489 }
1954919Sxy150489 } else {
1964919Sxy150489 nvm->address_bits = (eecd & E1000_EECD_ADDR_BITS)
1974919Sxy150489 ? 8 : 6;
1984919Sxy150489 nvm->delay_usec = 50;
1994919Sxy150489 nvm->opcode_bits = 3;
2004919Sxy150489 nvm->word_size = (eecd & E1000_EECD_ADDR_BITS)
2014919Sxy150489 ? 256 : 64;
2024919Sxy150489
2034919Sxy150489 /* Function Pointers */
2046735Scc210113 nvm->ops.acquire = e1000_acquire_nvm_generic;
2056735Scc210113 nvm->ops.read = e1000_read_nvm_microwire;
2066735Scc210113 nvm->ops.release = e1000_release_nvm_generic;
2076735Scc210113 nvm->ops.update = e1000_update_nvm_checksum_generic;
2086735Scc210113 nvm->ops.valid_led_default = e1000_valid_led_default_generic;
2096735Scc210113 nvm->ops.validate = e1000_validate_nvm_checksum_generic;
2106735Scc210113 nvm->ops.write = e1000_write_nvm_microwire;
2114919Sxy150489 }
2124919Sxy150489
2134919Sxy150489 out:
2144919Sxy150489 return (ret_val);
2154919Sxy150489 }
2164919Sxy150489
2174919Sxy150489 /*
2184919Sxy150489 * e1000_init_mac_params_82541 - Init MAC func ptrs.
2194919Sxy150489 * @hw: pointer to the HW structure
2204919Sxy150489 */
2214919Sxy150489 static s32
e1000_init_mac_params_82541(struct e1000_hw * hw)2224919Sxy150489 e1000_init_mac_params_82541(struct e1000_hw *hw)
2234919Sxy150489 {
2244919Sxy150489 struct e1000_mac_info *mac = &hw->mac;
2254919Sxy150489
2264919Sxy150489 DEBUGFUNC("e1000_init_mac_params_82541");
2274919Sxy150489
2284919Sxy150489 /* Set media type */
2296735Scc210113 hw->phy.media_type = e1000_media_type_copper;
2304919Sxy150489 /* Set mta register count */
2314919Sxy150489 mac->mta_reg_count = 128;
2324919Sxy150489 /* Set rar entry count */
2334919Sxy150489 mac->rar_entry_count = E1000_RAR_ENTRIES;
2344919Sxy150489 /* Set if part includes ASF firmware */
2357607STed.You@Sun.COM mac->asf_firmware_present = true;
2364919Sxy150489
2374919Sxy150489 /* Function Pointers */
2384919Sxy150489
2394919Sxy150489 /* bus type/speed/width */
2406735Scc210113 mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
24110680SMin.Xu@Sun.COM /* function id */
24210680SMin.Xu@Sun.COM mac->ops.set_lan_id = e1000_set_lan_id_single_port;
2434919Sxy150489 /* reset */
2446735Scc210113 mac->ops.reset_hw = e1000_reset_hw_82541;
2454919Sxy150489 /* hw initialization */
2466735Scc210113 mac->ops.init_hw = e1000_init_hw_82541;
2474919Sxy150489 /* link setup */
2486735Scc210113 mac->ops.setup_link = e1000_setup_link_generic;
2494919Sxy150489 /* physical interface link setup */
2506735Scc210113 mac->ops.setup_physical_interface = e1000_setup_copper_link_82541;
2514919Sxy150489 /* check for link */
2526735Scc210113 mac->ops.check_for_link = e1000_check_for_link_82541;
2534919Sxy150489 /* link info */
2546735Scc210113 mac->ops.get_link_up_info = e1000_get_link_up_info_82541;
2554919Sxy150489 /* multicast address update */
2566735Scc210113 mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
2574919Sxy150489 /* writing VFTA */
2586735Scc210113 mac->ops.write_vfta = e1000_write_vfta_generic;
2594919Sxy150489 /* clearing VFTA */
2606735Scc210113 mac->ops.clear_vfta = e1000_clear_vfta_generic;
2614919Sxy150489 /* setting MTA */
2626735Scc210113 mac->ops.mta_set = e1000_mta_set_generic;
26310680SMin.Xu@Sun.COM /* ID LED init */
26410680SMin.Xu@Sun.COM mac->ops.id_led_init = e1000_id_led_init_generic;
2654919Sxy150489 /* setup LED */
2666735Scc210113 mac->ops.setup_led = e1000_setup_led_82541;
2674919Sxy150489 /* cleanup LED */
2686735Scc210113 mac->ops.cleanup_led = e1000_cleanup_led_82541;
2694919Sxy150489 /* turn on/off LED */
2706735Scc210113 mac->ops.led_on = e1000_led_on_generic;
2716735Scc210113 mac->ops.led_off = e1000_led_off_generic;
2724919Sxy150489 /* clear hardware counters */
2736735Scc210113 mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82541;
2744919Sxy150489
2758479SChenlu.Chen@Sun.COM return (E1000_SUCCESS);
2764919Sxy150489 }
2774919Sxy150489
2784919Sxy150489 /*
2794919Sxy150489 * e1000_init_function_pointers_82541 - Init func ptrs.
2804919Sxy150489 * @hw: pointer to the HW structure
2814919Sxy150489 *
2828479SChenlu.Chen@Sun.COM * Called to initialize all function pointers and parameters.
2834919Sxy150489 */
2844919Sxy150489 void
e1000_init_function_pointers_82541(struct e1000_hw * hw)2854919Sxy150489 e1000_init_function_pointers_82541(struct e1000_hw *hw)
2864919Sxy150489 {
2874919Sxy150489 DEBUGFUNC("e1000_init_function_pointers_82541");
2884919Sxy150489
2896735Scc210113 hw->mac.ops.init_params = e1000_init_mac_params_82541;
2906735Scc210113 hw->nvm.ops.init_params = e1000_init_nvm_params_82541;
2916735Scc210113 hw->phy.ops.init_params = e1000_init_phy_params_82541;
2924919Sxy150489 }
2934919Sxy150489
2944919Sxy150489 /*
2954919Sxy150489 * e1000_reset_hw_82541 - Reset hardware
2964919Sxy150489 * @hw: pointer to the HW structure
2974919Sxy150489 *
2988479SChenlu.Chen@Sun.COM * This resets the hardware into a known state.
2994919Sxy150489 */
3004919Sxy150489 static s32
e1000_reset_hw_82541(struct e1000_hw * hw)3014919Sxy150489 e1000_reset_hw_82541(struct e1000_hw *hw)
3024919Sxy150489 {
3038479SChenlu.Chen@Sun.COM struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
3047426SChenliang.Xu@Sun.COM u32 ledctl, ctrl, manc;
3054919Sxy150489
3064919Sxy150489 DEBUGFUNC("e1000_reset_hw_82541");
3074919Sxy150489
3084919Sxy150489 DEBUGOUT("Masking off all interrupts\n");
3094919Sxy150489 E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
3104919Sxy150489
3114919Sxy150489 E1000_WRITE_REG(hw, E1000_RCTL, 0);
3124919Sxy150489 E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
3134919Sxy150489 E1000_WRITE_FLUSH(hw);
3144919Sxy150489
3154919Sxy150489 dev_spec->tx_fifo_head = 0;
3164919Sxy150489
3174919Sxy150489 /*
3184919Sxy150489 * Delay to allow any outstanding PCI transactions to complete
3194919Sxy150489 * before resetting the device.
3204919Sxy150489 */
3214919Sxy150489 msec_delay(10);
3224919Sxy150489
3234919Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL);
3244919Sxy150489
3254919Sxy150489 /* Must reset the Phy before resetting the MAC */
3264919Sxy150489 if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
3274919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_PHY_RST));
3284919Sxy150489 msec_delay(5);
3294919Sxy150489 }
3304919Sxy150489
3314919Sxy150489 DEBUGOUT("Issuing a global reset to 82541/82547 MAC\n");
3324919Sxy150489 switch (hw->mac.type) {
3334919Sxy150489 case e1000_82541:
3344919Sxy150489 case e1000_82541_rev_2:
3354919Sxy150489 /*
3364919Sxy150489 * These controllers can't ack the 64-bit write when
3374919Sxy150489 * issuing the reset, so we use IO-mapping as a
3384919Sxy150489 * workaround to issue the reset.
3394919Sxy150489 */
3404919Sxy150489 E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
3414919Sxy150489 break;
3424919Sxy150489 default:
3434919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
3444919Sxy150489 break;
3454919Sxy150489 }
3464919Sxy150489
3474919Sxy150489 /* Wait for NVM reload */
3484919Sxy150489 msec_delay(20);
3494919Sxy150489
3504919Sxy150489 /* Disable HW ARPs on ASF enabled adapters */
3514919Sxy150489 manc = E1000_READ_REG(hw, E1000_MANC);
3524919Sxy150489 manc &= ~E1000_MANC_ARP_EN;
3534919Sxy150489 E1000_WRITE_REG(hw, E1000_MANC, manc);
3544919Sxy150489
3554919Sxy150489 if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
3567426SChenliang.Xu@Sun.COM (void) e1000_phy_init_script_82541(hw);
3574919Sxy150489
3584919Sxy150489 /* Configure activity LED after Phy reset */
3594919Sxy150489 ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
3604919Sxy150489 ledctl &= IGP_ACTIVITY_LED_MASK;
3614919Sxy150489 ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
3624919Sxy150489 E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
3634919Sxy150489 }
3644919Sxy150489
3654919Sxy150489 /* Once again, mask the interrupts */
3664919Sxy150489 DEBUGOUT("Masking off all interrupts\n");
3674919Sxy150489 E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
3684919Sxy150489
3694919Sxy150489 /* Clear any pending interrupt events. */
3707426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_ICR);
3714919Sxy150489
3724919Sxy150489 return (E1000_SUCCESS);
3734919Sxy150489 }
3744919Sxy150489
3754919Sxy150489 /*
3764919Sxy150489 * e1000_init_hw_82541 - Initialize hardware
3774919Sxy150489 * @hw: pointer to the HW structure
3784919Sxy150489 *
3798479SChenlu.Chen@Sun.COM * This inits the hardware readying it for operation.
3804919Sxy150489 */
3814919Sxy150489 static s32
e1000_init_hw_82541(struct e1000_hw * hw)3824919Sxy150489 e1000_init_hw_82541(struct e1000_hw *hw)
3834919Sxy150489 {
3844919Sxy150489 struct e1000_mac_info *mac = &hw->mac;
3858479SChenlu.Chen@Sun.COM struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
3864919Sxy150489 u32 pba;
3874919Sxy150489 u32 i, txdctl;
3884919Sxy150489 s32 ret_val;
3894919Sxy150489
3904919Sxy150489 DEBUGFUNC("e1000_init_hw_82541");
3914919Sxy150489
3924919Sxy150489 /* Initialize identification LED */
39310680SMin.Xu@Sun.COM ret_val = mac->ops.id_led_init(hw);
3944919Sxy150489 if (ret_val) {
395*11143SGuoqing.Zhu@Sun.COM /* EMPTY */
3964919Sxy150489 DEBUGOUT("Error initializing identification LED\n");
3976735Scc210113 /* This is not fatal and we should not stop init due to this */
3984919Sxy150489 }
3994919Sxy150489
40010680SMin.Xu@Sun.COM /* Storing the Speed Power Down value for later use */
40110680SMin.Xu@Sun.COM ret_val = hw->phy.ops.read_reg(hw,
40210680SMin.Xu@Sun.COM IGP01E1000_GMII_FIFO,
40310680SMin.Xu@Sun.COM &dev_spec->spd_default);
40410680SMin.Xu@Sun.COM if (ret_val)
40510605SMin.Xu@Sun.COM goto out;
40610605SMin.Xu@Sun.COM
4074919Sxy150489 pba = E1000_READ_REG(hw, E1000_PBA);
4084919Sxy150489 dev_spec->tx_fifo_start = (pba & 0x0000FFFF) * E1000_FIFO_MULTIPLIER;
4094919Sxy150489 dev_spec->tx_fifo_size = (pba & 0xFFFF0000) >> 6;
4104919Sxy150489
4114919Sxy150489 /* Disabling VLAN filtering */
4124919Sxy150489 DEBUGOUT("Initializing the IEEE VLAN\n");
4136735Scc210113 mac->ops.clear_vfta(hw);
4144919Sxy150489
4154919Sxy150489 /* Setup the receive address. */
4164919Sxy150489 e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
4174919Sxy150489
4184919Sxy150489 /* Zero out the Multicast HASH table */
4194919Sxy150489 DEBUGOUT("Zeroing the MTA\n");
4204919Sxy150489 for (i = 0; i < mac->mta_reg_count; i++) {
4214919Sxy150489 E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
4224919Sxy150489 /*
4234919Sxy150489 * Avoid back to back register writes by adding the register
4244919Sxy150489 * read (flush). This is to protect against some strange
4254919Sxy150489 * bridge configurations that may issue Memory Write Block
4264919Sxy150489 * (MWB) to our register space.
4274919Sxy150489 */
4284919Sxy150489 E1000_WRITE_FLUSH(hw);
4294919Sxy150489 }
4304919Sxy150489
4314919Sxy150489 /* Setup link and flow control */
4326735Scc210113 ret_val = mac->ops.setup_link(hw);
4334919Sxy150489
4346735Scc210113 txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
4354919Sxy150489 txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
4364919Sxy150489 E1000_TXDCTL_FULL_TX_DESC_WB;
4376735Scc210113 E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
4384919Sxy150489
4394919Sxy150489 /*
4404919Sxy150489 * Clear all of the statistics registers (clear on read). It is
4414919Sxy150489 * important that we do this after we have tried to establish link
4424919Sxy150489 * because the symbol error count will increment wildly if there
4434919Sxy150489 * is no link.
4444919Sxy150489 */
4454919Sxy150489 e1000_clear_hw_cntrs_82541(hw);
4464919Sxy150489
44710605SMin.Xu@Sun.COM out:
4484919Sxy150489 return (ret_val);
4494919Sxy150489 }
4504919Sxy150489
4514919Sxy150489 /*
4524919Sxy150489 * e1000_get_link_up_info_82541 - Report speed and duplex
4534919Sxy150489 * @hw: pointer to the HW structure
4544919Sxy150489 * @speed: pointer to speed buffer
4554919Sxy150489 * @duplex: pointer to duplex buffer
4564919Sxy150489 *
4574919Sxy150489 * Retrieve the current speed and duplex configuration.
4584919Sxy150489 */
4594919Sxy150489 static s32
e1000_get_link_up_info_82541(struct e1000_hw * hw,u16 * speed,u16 * duplex)4604919Sxy150489 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed, u16 *duplex)
4614919Sxy150489 {
4624919Sxy150489 struct e1000_phy_info *phy = &hw->phy;
4634919Sxy150489 s32 ret_val;
4644919Sxy150489 u16 data;
4654919Sxy150489
4664919Sxy150489 DEBUGFUNC("e1000_get_link_up_info_82541");
4674919Sxy150489
4684919Sxy150489 ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
4694919Sxy150489 if (ret_val)
4704919Sxy150489 goto out;
4714919Sxy150489
4724919Sxy150489 if (!phy->speed_downgraded)
4734919Sxy150489 goto out;
4744919Sxy150489
4754919Sxy150489 /*
4764919Sxy150489 * IGP01 PHY may advertise full duplex operation after speed
4774919Sxy150489 * downgrade even if it is operating at half duplex.
4784919Sxy150489 * Here we set the duplex settings to match the duplex in the
4794919Sxy150489 * link partner's capabilities.
4804919Sxy150489 */
4816735Scc210113 ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_EXP, &data);
4824919Sxy150489 if (ret_val)
4834919Sxy150489 goto out;
4844919Sxy150489
4854919Sxy150489 if (!(data & NWAY_ER_LP_NWAY_CAPS)) {
4864919Sxy150489 *duplex = HALF_DUPLEX;
4874919Sxy150489 } else {
4886735Scc210113 ret_val = phy->ops.read_reg(hw, PHY_LP_ABILITY, &data);
4894919Sxy150489 if (ret_val)
4904919Sxy150489 goto out;
4914919Sxy150489
4924919Sxy150489 if (*speed == SPEED_100) {
4934919Sxy150489 if (!(data & NWAY_LPAR_100TX_FD_CAPS))
4944919Sxy150489 *duplex = HALF_DUPLEX;
4954919Sxy150489 } else if (*speed == SPEED_10) {
4964919Sxy150489 if (!(data & NWAY_LPAR_10T_FD_CAPS))
4974919Sxy150489 *duplex = HALF_DUPLEX;
4984919Sxy150489 }
4994919Sxy150489 }
5004919Sxy150489
5014919Sxy150489 out:
5024919Sxy150489 return (ret_val);
5034919Sxy150489 }
5044919Sxy150489
5054919Sxy150489 /*
5064919Sxy150489 * e1000_phy_hw_reset_82541 - PHY hardware reset
5074919Sxy150489 * @hw: pointer to the HW structure
5084919Sxy150489 *
5094919Sxy150489 * Verify the reset block is not blocking us from resetting. Acquire
5104919Sxy150489 * semaphore (if necessary) and read/set/write the device control reset
5114919Sxy150489 * bit in the PHY. Wait the appropriate delay time for the device to
5126735Scc210113 * reset and release the semaphore (if necessary).
5134919Sxy150489 */
5144919Sxy150489 static s32
e1000_phy_hw_reset_82541(struct e1000_hw * hw)5154919Sxy150489 e1000_phy_hw_reset_82541(struct e1000_hw *hw)
5164919Sxy150489 {
5174919Sxy150489 s32 ret_val;
5184919Sxy150489 u32 ledctl;
5194919Sxy150489
5204919Sxy150489 DEBUGFUNC("e1000_phy_hw_reset_82541");
5214919Sxy150489
5224919Sxy150489 ret_val = e1000_phy_hw_reset_generic(hw);
5234919Sxy150489 if (ret_val)
5244919Sxy150489 goto out;
5254919Sxy150489
5267426SChenliang.Xu@Sun.COM (void) e1000_phy_init_script_82541(hw);
5274919Sxy150489
5284919Sxy150489 if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
5294919Sxy150489 /* Configure activity LED after PHY reset */
5304919Sxy150489 ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
5314919Sxy150489 ledctl &= IGP_ACTIVITY_LED_MASK;
5324919Sxy150489 ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
5334919Sxy150489 E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
5344919Sxy150489 }
5354919Sxy150489
5364919Sxy150489 out:
5374919Sxy150489 return (ret_val);
5384919Sxy150489 }
5394919Sxy150489
5404919Sxy150489 /*
5414919Sxy150489 * e1000_setup_copper_link_82541 - Configure copper link settings
5424919Sxy150489 * @hw: pointer to the HW structure
5434919Sxy150489 *
5444919Sxy150489 * Calls the appropriate function to configure the link for auto-neg or forced
5454919Sxy150489 * speed and duplex. Then we check for link, once link is established calls
5464919Sxy150489 * to configure collision distance and flow control are called. If link is
5478479SChenlu.Chen@Sun.COM * not established, we return -E1000_ERR_PHY (-2).
5484919Sxy150489 */
5494919Sxy150489 static s32
e1000_setup_copper_link_82541(struct e1000_hw * hw)5504919Sxy150489 e1000_setup_copper_link_82541(struct e1000_hw *hw)
5514919Sxy150489 {
5524919Sxy150489 struct e1000_phy_info *phy = &hw->phy;
5538479SChenlu.Chen@Sun.COM struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
5544919Sxy150489 s32 ret_val;
5554919Sxy150489 u32 ctrl, ledctl;
5564919Sxy150489
5574919Sxy150489 DEBUGFUNC("e1000_setup_copper_link_82541");
5584919Sxy150489
5594919Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL);
5604919Sxy150489 ctrl |= E1000_CTRL_SLU;
5614919Sxy150489 ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
5624919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
5634919Sxy150489
5647607STed.You@Sun.COM hw->phy.reset_disable = false;
5654919Sxy150489
5664919Sxy150489 /* Earlier revs of the IGP phy require us to force MDI. */
5674919Sxy150489 if (hw->mac.type == e1000_82541 || hw->mac.type == e1000_82547) {
5684919Sxy150489 dev_spec->dsp_config = e1000_dsp_config_disabled;
5694919Sxy150489 phy->mdix = 1;
5704919Sxy150489 } else {
5714919Sxy150489 dev_spec->dsp_config = e1000_dsp_config_enabled;
5724919Sxy150489 }
5734919Sxy150489
5744919Sxy150489 ret_val = e1000_copper_link_setup_igp(hw);
5754919Sxy150489 if (ret_val)
5764919Sxy150489 goto out;
5774919Sxy150489
5784919Sxy150489 if (hw->mac.autoneg) {
5794919Sxy150489 if (dev_spec->ffe_config == e1000_ffe_config_active)
5804919Sxy150489 dev_spec->ffe_config = e1000_ffe_config_enabled;
5814919Sxy150489 }
5824919Sxy150489
5834919Sxy150489 /* Configure activity LED after Phy reset */
5844919Sxy150489 ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
5854919Sxy150489 ledctl &= IGP_ACTIVITY_LED_MASK;
5864919Sxy150489 ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
5874919Sxy150489 E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
5884919Sxy150489
5894919Sxy150489 ret_val = e1000_setup_copper_link_generic(hw);
5904919Sxy150489
5914919Sxy150489 out:
5924919Sxy150489 return (ret_val);
5934919Sxy150489 }
5944919Sxy150489
5954919Sxy150489 /*
5964919Sxy150489 * e1000_check_for_link_82541 - Check/Store link connection
5974919Sxy150489 * @hw: pointer to the HW structure
5984919Sxy150489 *
5994919Sxy150489 * This checks the link condition of the adapter and stores the
6008479SChenlu.Chen@Sun.COM * results in the hw->mac structure.
6014919Sxy150489 */
6024919Sxy150489 static s32
e1000_check_for_link_82541(struct e1000_hw * hw)6034919Sxy150489 e1000_check_for_link_82541(struct e1000_hw *hw)
6044919Sxy150489 {
6054919Sxy150489 struct e1000_mac_info *mac = &hw->mac;
6064919Sxy150489 s32 ret_val;
6076735Scc210113 bool link;
6084919Sxy150489
6094919Sxy150489 DEBUGFUNC("e1000_check_for_link_82541");
6104919Sxy150489
6114919Sxy150489 /*
6124919Sxy150489 * We only want to go out to the PHY registers to see if Auto-Neg
6134919Sxy150489 * has completed and/or if our link status has changed. The
6144919Sxy150489 * get_link_status flag is set upon receiving a Link Status
6154919Sxy150489 * Change or Rx Sequence Error interrupt.
6164919Sxy150489 */
6174919Sxy150489 if (!mac->get_link_status) {
6184919Sxy150489 ret_val = E1000_SUCCESS;
6194919Sxy150489 goto out;
6204919Sxy150489 }
6214919Sxy150489
6224919Sxy150489 /*
6234919Sxy150489 * First we want to see if the MII Status Register reports
6244919Sxy150489 * link. If so, then we want to get the current speed/duplex
6254919Sxy150489 * of the PHY.
6264919Sxy150489 */
6274919Sxy150489 ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
6284919Sxy150489 if (ret_val)
6294919Sxy150489 goto out;
6304919Sxy150489
6314919Sxy150489 if (!link) {
6327607STed.You@Sun.COM ret_val = e1000_config_dsp_after_link_change_82541(hw, false);
6334919Sxy150489 goto out; /* No link detected */
6344919Sxy150489 }
6354919Sxy150489
6367607STed.You@Sun.COM mac->get_link_status = false;
6374919Sxy150489
6384919Sxy150489 /*
6394919Sxy150489 * Check if there was DownShift, must be checked
6404919Sxy150489 * immediately after link-up
6414919Sxy150489 */
6427426SChenliang.Xu@Sun.COM (void) e1000_check_downshift_generic(hw);
6434919Sxy150489
6444919Sxy150489 /*
6454919Sxy150489 * If we are forcing speed/duplex, then we simply return since
6464919Sxy150489 * we have already determined whether we have link or not.
6474919Sxy150489 */
6484919Sxy150489 if (!mac->autoneg) {
6494919Sxy150489 ret_val = -E1000_ERR_CONFIG;
6504919Sxy150489 goto out;
6514919Sxy150489 }
6524919Sxy150489
6537607STed.You@Sun.COM ret_val = e1000_config_dsp_after_link_change_82541(hw, true);
6544919Sxy150489
6554919Sxy150489 /*
6564919Sxy150489 * Auto-Neg is enabled. Auto Speed Detection takes care
6574919Sxy150489 * of MAC speed/duplex configuration. So we only need to
6584919Sxy150489 * configure Collision Distance in the MAC.
6594919Sxy150489 */
6604919Sxy150489 e1000_config_collision_dist_generic(hw);
6614919Sxy150489
6624919Sxy150489 /*
6634919Sxy150489 * Configure Flow Control now that Auto-Neg has completed.
6644919Sxy150489 * First, we need to restore the desired flow control
6654919Sxy150489 * settings because we may have had to re-autoneg with a
6664919Sxy150489 * different link partner.
6674919Sxy150489 */
6684919Sxy150489 ret_val = e1000_config_fc_after_link_up_generic(hw);
6694919Sxy150489 if (ret_val) {
670*11143SGuoqing.Zhu@Sun.COM /* EMPTY */
6714919Sxy150489 DEBUGOUT("Error configuring flow control\n");
6724919Sxy150489 }
6734919Sxy150489
6744919Sxy150489 out:
6754919Sxy150489 return (ret_val);
6764919Sxy150489 }
6774919Sxy150489
6784919Sxy150489 /*
6794919Sxy150489 * e1000_config_dsp_after_link_change_82541 - Config DSP after link
6804919Sxy150489 * @hw: pointer to the HW structure
6814919Sxy150489 * @link_up: boolean flag for link up status
6824919Sxy150489 *
6834919Sxy150489 * Return E1000_ERR_PHY when failing to read/write the PHY, else E1000_SUCCESS
6844919Sxy150489 * at any other case.
6854919Sxy150489 *
6864919Sxy150489 * 82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a
6874919Sxy150489 * gigabit link is achieved to improve link quality.
6884919Sxy150489 */
6894919Sxy150489 static s32
e1000_config_dsp_after_link_change_82541(struct e1000_hw * hw,bool link_up)6904919Sxy150489 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
6916735Scc210113 bool link_up)
6924919Sxy150489 {
6934919Sxy150489 struct e1000_phy_info *phy = &hw->phy;
6948479SChenlu.Chen@Sun.COM struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
6954919Sxy150489 s32 ret_val;
6964919Sxy150489 u32 idle_errs = 0;
6974919Sxy150489 u16 phy_data, phy_saved_data, speed, duplex, i;
6984919Sxy150489 u16 ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;
6994919Sxy150489 u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
7004919Sxy150489 {IGP01E1000_PHY_AGC_PARAM_A,
7014919Sxy150489 IGP01E1000_PHY_AGC_PARAM_B,
7024919Sxy150489 IGP01E1000_PHY_AGC_PARAM_C,
7034919Sxy150489 IGP01E1000_PHY_AGC_PARAM_D};
7044919Sxy150489
7054919Sxy150489 DEBUGFUNC("e1000_config_dsp_after_link_change_82541");
7064919Sxy150489
7074919Sxy150489 if (link_up) {
7086735Scc210113 ret_val = hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
7094919Sxy150489 if (ret_val) {
7104919Sxy150489 DEBUGOUT("Error getting link speed and duplex\n");
7114919Sxy150489 goto out;
7124919Sxy150489 }
7134919Sxy150489
7144919Sxy150489 if (speed != SPEED_1000) {
7154919Sxy150489 ret_val = E1000_SUCCESS;
7164919Sxy150489 goto out;
7174919Sxy150489 }
7184919Sxy150489
7196735Scc210113 ret_val = phy->ops.get_cable_length(hw);
7204919Sxy150489 if (ret_val)
7214919Sxy150489 goto out;
7224919Sxy150489
7234919Sxy150489 if ((dev_spec->dsp_config == e1000_dsp_config_enabled) &&
7244919Sxy150489 phy->min_cable_length >= 50) {
7254919Sxy150489
7264919Sxy150489 for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
7276735Scc210113 ret_val = phy->ops.read_reg(hw,
7284919Sxy150489 dsp_reg_array[i],
7294919Sxy150489 &phy_data);
7304919Sxy150489 if (ret_val)
7314919Sxy150489 goto out;
7324919Sxy150489
7334919Sxy150489 phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
7344919Sxy150489
7356735Scc210113 ret_val = phy->ops.write_reg(hw,
7364919Sxy150489 dsp_reg_array[i],
7374919Sxy150489 phy_data);
7384919Sxy150489 if (ret_val)
7394919Sxy150489 goto out;
7404919Sxy150489 }
7414919Sxy150489 dev_spec->dsp_config = e1000_dsp_config_activated;
7424919Sxy150489 }
7434919Sxy150489
7444919Sxy150489 if ((dev_spec->ffe_config != e1000_ffe_config_enabled) ||
7454919Sxy150489 (phy->min_cable_length >= 50)) {
7464919Sxy150489 ret_val = E1000_SUCCESS;
7474919Sxy150489 goto out;
7484919Sxy150489 }
7494919Sxy150489
7504919Sxy150489 /* clear previous idle error counts */
7516735Scc210113 ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
7524919Sxy150489 if (ret_val)
7534919Sxy150489 goto out;
7544919Sxy150489
7554919Sxy150489 for (i = 0; i < ffe_idle_err_timeout; i++) {
7564919Sxy150489 usec_delay(1000);
7576735Scc210113 ret_val = phy->ops.read_reg(hw,
7584919Sxy150489 PHY_1000T_STATUS,
7594919Sxy150489 &phy_data);
7604919Sxy150489 if (ret_val)
7614919Sxy150489 goto out;
7624919Sxy150489
7634919Sxy150489 idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);
7644919Sxy150489 if (idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
7654919Sxy150489 dev_spec->ffe_config = e1000_ffe_config_active;
7664919Sxy150489
7676735Scc210113 ret_val = phy->ops.write_reg(hw,
7684919Sxy150489 IGP01E1000_PHY_DSP_FFE,
7694919Sxy150489 IGP01E1000_PHY_DSP_FFE_CM_CP);
7704919Sxy150489 if (ret_val)
7714919Sxy150489 goto out;
7724919Sxy150489 break;
7734919Sxy150489 }
7744919Sxy150489
7754919Sxy150489 if (idle_errs)
7764919Sxy150489 ffe_idle_err_timeout =
7774919Sxy150489 FFE_IDLE_ERR_COUNT_TIMEOUT_100;
7784919Sxy150489 }
7794919Sxy150489 } else {
7804919Sxy150489 if (dev_spec->dsp_config == e1000_dsp_config_activated) {
7814919Sxy150489 /*
7824919Sxy150489 * Save off the current value of register 0x2F5B
7834919Sxy150489 * to be restored at the end of the routines.
7844919Sxy150489 */
7856735Scc210113 ret_val = phy->ops.read_reg(hw,
7864919Sxy150489 0x2F5B,
7874919Sxy150489 &phy_saved_data);
7884919Sxy150489 if (ret_val)
7894919Sxy150489 goto out;
7904919Sxy150489
7914919Sxy150489 /* Disable the PHY transmitter */
7926735Scc210113 ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003);
7934919Sxy150489 if (ret_val)
7944919Sxy150489 goto out;
7954919Sxy150489
7964919Sxy150489 msec_delay_irq(20);
7974919Sxy150489
7986735Scc210113 ret_val = phy->ops.write_reg(hw,
7994919Sxy150489 0x0000,
8004919Sxy150489 IGP01E1000_IEEE_FORCE_GIG);
8014919Sxy150489 if (ret_val)
8024919Sxy150489 goto out;
8034919Sxy150489 for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
8046735Scc210113 ret_val = phy->ops.read_reg(hw,
8054919Sxy150489 dsp_reg_array[i],
8064919Sxy150489 &phy_data);
8074919Sxy150489 if (ret_val)
8084919Sxy150489 goto out;
8094919Sxy150489
8104919Sxy150489 phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
8114919Sxy150489 phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;
8124919Sxy150489
8136735Scc210113 ret_val = phy->ops.write_reg(hw,
8144919Sxy150489 dsp_reg_array[i],
8154919Sxy150489 phy_data);
8164919Sxy150489 if (ret_val)
8174919Sxy150489 goto out;
8184919Sxy150489 }
8194919Sxy150489
8206735Scc210113 ret_val = phy->ops.write_reg(hw,
8214919Sxy150489 0x0000,
8224919Sxy150489 IGP01E1000_IEEE_RESTART_AUTONEG);
8234919Sxy150489 if (ret_val)
8244919Sxy150489 goto out;
8254919Sxy150489
8264919Sxy150489 msec_delay_irq(20);
8274919Sxy150489
8284919Sxy150489 /* Now enable the transmitter */
8296735Scc210113 ret_val = phy->ops.write_reg(hw,
8304919Sxy150489 0x2F5B,
8314919Sxy150489 phy_saved_data);
8324919Sxy150489 if (ret_val)
8334919Sxy150489 goto out;
8344919Sxy150489
8354919Sxy150489 dev_spec->dsp_config = e1000_dsp_config_enabled;
8364919Sxy150489 }
8374919Sxy150489
8384919Sxy150489 if (dev_spec->ffe_config != e1000_ffe_config_active) {
8394919Sxy150489 ret_val = E1000_SUCCESS;
8404919Sxy150489 goto out;
8414919Sxy150489 }
8424919Sxy150489
8434919Sxy150489 /*
8444919Sxy150489 * Save off the current value of register 0x2F5B
8454919Sxy150489 * to be restored at the end of the routines.
8464919Sxy150489 */
8476735Scc210113 ret_val = phy->ops.read_reg(hw, 0x2F5B, &phy_saved_data);
8484919Sxy150489 if (ret_val)
8494919Sxy150489 goto out;
8504919Sxy150489
8514919Sxy150489 /* Disable the PHY transmitter */
8526735Scc210113 ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003);
8534919Sxy150489 if (ret_val)
8544919Sxy150489 goto out;
8554919Sxy150489
8564919Sxy150489 msec_delay_irq(20);
8574919Sxy150489
8586735Scc210113 ret_val = phy->ops.write_reg(hw,
8594919Sxy150489 0x0000,
8604919Sxy150489 IGP01E1000_IEEE_FORCE_GIG);
8614919Sxy150489 if (ret_val)
8624919Sxy150489 goto out;
8634919Sxy150489
8646735Scc210113 ret_val = phy->ops.write_reg(hw,
8654919Sxy150489 IGP01E1000_PHY_DSP_FFE,
8664919Sxy150489 IGP01E1000_PHY_DSP_FFE_DEFAULT);
8674919Sxy150489 if (ret_val)
8684919Sxy150489 goto out;
8694919Sxy150489
8706735Scc210113 ret_val = phy->ops.write_reg(hw,
8714919Sxy150489 0x0000,
8724919Sxy150489 IGP01E1000_IEEE_RESTART_AUTONEG);
8734919Sxy150489 if (ret_val)
8744919Sxy150489 goto out;
8754919Sxy150489
8764919Sxy150489 msec_delay_irq(20);
8774919Sxy150489
8784919Sxy150489 /* Now enable the transmitter */
8796735Scc210113 ret_val = phy->ops.write_reg(hw, 0x2F5B, phy_saved_data);
8804919Sxy150489
8814919Sxy150489 if (ret_val)
8824919Sxy150489 goto out;
8834919Sxy150489
8844919Sxy150489 dev_spec->ffe_config = e1000_ffe_config_enabled;
8854919Sxy150489 }
8864919Sxy150489
8874919Sxy150489 out:
8884919Sxy150489 return (ret_val);
8894919Sxy150489 }
8904919Sxy150489
8914919Sxy150489 /*
8924919Sxy150489 * e1000_get_cable_length_igp_82541 - Determine cable length for igp PHY
8934919Sxy150489 * @hw: pointer to the HW structure
8944919Sxy150489 *
8954919Sxy150489 * The automatic gain control (agc) normalizes the amplitude of the
8964919Sxy150489 * received signal, adjusting for the attenuation produced by the
8976735Scc210113 * cable. By reading the AGC registers, which represent the
8986735Scc210113 * combination of coarse and fine gain value, the value can be put
8994919Sxy150489 * into a lookup table to obtain the approximate cable length
9008479SChenlu.Chen@Sun.COM * for each channel.
9014919Sxy150489 */
9024919Sxy150489 static s32
e1000_get_cable_length_igp_82541(struct e1000_hw * hw)9034919Sxy150489 e1000_get_cable_length_igp_82541(struct e1000_hw *hw)
9044919Sxy150489 {
9054919Sxy150489 struct e1000_phy_info *phy = &hw->phy;
9064919Sxy150489 s32 ret_val = E1000_SUCCESS;
9074919Sxy150489 u16 i, data;
9084919Sxy150489 u16 cur_agc_value, agc_value = 0;
9094919Sxy150489 u16 min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
9104919Sxy150489 u16 agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
9114919Sxy150489 {IGP01E1000_PHY_AGC_A,
9124919Sxy150489 IGP01E1000_PHY_AGC_B,
9134919Sxy150489 IGP01E1000_PHY_AGC_C,
9144919Sxy150489 IGP01E1000_PHY_AGC_D};
9154919Sxy150489
9164919Sxy150489 DEBUGFUNC("e1000_get_cable_length_igp_82541");
9174919Sxy150489
9184919Sxy150489 /* Read the AGC registers for all channels */
9194919Sxy150489 for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
9206735Scc210113 ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &data);
9214919Sxy150489 if (ret_val)
9224919Sxy150489 goto out;
9234919Sxy150489
9244919Sxy150489 cur_agc_value = data >> IGP01E1000_AGC_LENGTH_SHIFT;
9254919Sxy150489
9264919Sxy150489 /* Bounds checking */
9274919Sxy150489 if ((cur_agc_value >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
9284919Sxy150489 (cur_agc_value == 0)) {
9294919Sxy150489 ret_val = -E1000_ERR_PHY;
9304919Sxy150489 goto out;
9314919Sxy150489 }
9324919Sxy150489
9334919Sxy150489 agc_value += cur_agc_value;
9344919Sxy150489
9354919Sxy150489 if (min_agc_value > cur_agc_value)
9364919Sxy150489 min_agc_value = cur_agc_value;
9374919Sxy150489 }
9384919Sxy150489
9394919Sxy150489 /* Remove the minimal AGC result for length < 50m */
9404919Sxy150489 if (agc_value < IGP01E1000_PHY_CHANNEL_NUM * 50) {
9414919Sxy150489 agc_value -= min_agc_value;
9424919Sxy150489 /* Average the three remaining channels for the length. */
9434919Sxy150489 agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1);
9444919Sxy150489 } else {
9454919Sxy150489 /* Average the channels for the length. */
9464919Sxy150489 agc_value /= IGP01E1000_PHY_CHANNEL_NUM;
9474919Sxy150489 }
9484919Sxy150489
9494919Sxy150489 phy->min_cable_length = (e1000_igp_cable_length_table[agc_value] >
9504919Sxy150489 IGP01E1000_AGC_RANGE)
9514919Sxy150489 ? (e1000_igp_cable_length_table[agc_value] -
9524919Sxy150489 IGP01E1000_AGC_RANGE)
9534919Sxy150489 : 0;
9544919Sxy150489 phy->max_cable_length = e1000_igp_cable_length_table[agc_value] +
9554919Sxy150489 IGP01E1000_AGC_RANGE;
9564919Sxy150489
9574919Sxy150489 phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
9584919Sxy150489
9594919Sxy150489 out:
9604919Sxy150489 return (ret_val);
9614919Sxy150489 }
9624919Sxy150489
9634919Sxy150489 /*
9644919Sxy150489 * e1000_set_d3_lplu_state_82541 - Sets low power link up state for D3
9654919Sxy150489 * @hw: pointer to the HW structure
9664919Sxy150489 * @active: boolean used to enable/disable lplu
9674919Sxy150489 *
9684919Sxy150489 * Success returns 0, Failure returns 1
9694919Sxy150489 *
9704919Sxy150489 * The low power link up (lplu) state is set to the power management level D3
9714919Sxy150489 * and SmartSpeed is disabled when active is true, else clear lplu for D3
9724919Sxy150489 * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
9734919Sxy150489 * is used during Dx states where the power conservation is most important.
9744919Sxy150489 * During driver activity, SmartSpeed should be enabled so performance is
9758479SChenlu.Chen@Sun.COM * maintained.
9764919Sxy150489 */
9774919Sxy150489 static s32
e1000_set_d3_lplu_state_82541(struct e1000_hw * hw,bool active)9786735Scc210113 e1000_set_d3_lplu_state_82541(struct e1000_hw *hw, bool active)
9794919Sxy150489 {
9804919Sxy150489 struct e1000_phy_info *phy = &hw->phy;
9814919Sxy150489 s32 ret_val;
9824919Sxy150489 u16 data;
9834919Sxy150489
9844919Sxy150489 DEBUGFUNC("e1000_set_d3_lplu_state_82541");
9854919Sxy150489
9864919Sxy150489 switch (hw->mac.type) {
9874919Sxy150489 case e1000_82541_rev_2:
9884919Sxy150489 case e1000_82547_rev_2:
9894919Sxy150489 break;
9904919Sxy150489 default:
9914919Sxy150489 ret_val = e1000_set_d3_lplu_state_generic(hw, active);
9924919Sxy150489 goto out;
9934919Sxy150489 }
9944919Sxy150489
9956735Scc210113 ret_val = phy->ops.read_reg(hw, IGP01E1000_GMII_FIFO, &data);
9964919Sxy150489 if (ret_val)
9974919Sxy150489 goto out;
9984919Sxy150489
9994919Sxy150489 if (!active) {
10004919Sxy150489 data &= ~IGP01E1000_GMII_FLEX_SPD;
10016735Scc210113 ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data);
10024919Sxy150489 if (ret_val)
10034919Sxy150489 goto out;
10044919Sxy150489
10054919Sxy150489 /*
10064919Sxy150489 * LPLU and SmartSpeed are mutually exclusive. LPLU is used
10074919Sxy150489 * during Dx states where the power conservation is most
10084919Sxy150489 * important. During driver activity we should enable
10094919Sxy150489 * SmartSpeed, so performance is maintained.
10104919Sxy150489 */
10114919Sxy150489 if (phy->smart_speed == e1000_smart_speed_on) {
10126735Scc210113 ret_val = phy->ops.read_reg(hw,
10134919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
10144919Sxy150489 &data);
10154919Sxy150489 if (ret_val)
10164919Sxy150489 goto out;
10174919Sxy150489
10184919Sxy150489 data |= IGP01E1000_PSCFR_SMART_SPEED;
10196735Scc210113 ret_val = phy->ops.write_reg(hw,
10204919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
10214919Sxy150489 data);
10224919Sxy150489 if (ret_val)
10234919Sxy150489 goto out;
10244919Sxy150489 } else if (phy->smart_speed == e1000_smart_speed_off) {
10256735Scc210113 ret_val = phy->ops.read_reg(hw,
10264919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
10274919Sxy150489 &data);
10284919Sxy150489 if (ret_val)
10294919Sxy150489 goto out;
10304919Sxy150489
10314919Sxy150489 data &= ~IGP01E1000_PSCFR_SMART_SPEED;
10326735Scc210113 ret_val = phy->ops.write_reg(hw,
10334919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
10344919Sxy150489 data);
10354919Sxy150489 if (ret_val)
10364919Sxy150489 goto out;
10374919Sxy150489 }
10384919Sxy150489 } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
10394919Sxy150489 (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
10404919Sxy150489 (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
10414919Sxy150489 data |= IGP01E1000_GMII_FLEX_SPD;
10426735Scc210113 ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data);
10434919Sxy150489 if (ret_val)
10444919Sxy150489 goto out;
10454919Sxy150489
10464919Sxy150489 /* When LPLU is enabled, we should disable SmartSpeed */
10476735Scc210113 ret_val = phy->ops.read_reg(hw,
10484919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
10494919Sxy150489 &data);
10504919Sxy150489 if (ret_val)
10514919Sxy150489 goto out;
10524919Sxy150489
10534919Sxy150489 data &= ~IGP01E1000_PSCFR_SMART_SPEED;
10546735Scc210113 ret_val = phy->ops.write_reg(hw,
10554919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
10564919Sxy150489 data);
10574919Sxy150489 }
10584919Sxy150489
10594919Sxy150489 out:
10604919Sxy150489 return (ret_val);
10614919Sxy150489 }
10624919Sxy150489
10634919Sxy150489 /*
10644919Sxy150489 * e1000_setup_led_82541 - Configures SW controllable LED
10654919Sxy150489 * @hw: pointer to the HW structure
10664919Sxy150489 *
10674919Sxy150489 * This prepares the SW controllable LED for use and saves the current state
10688479SChenlu.Chen@Sun.COM * of the LED so it can be later restored.
10694919Sxy150489 */
10704919Sxy150489 static s32
e1000_setup_led_82541(struct e1000_hw * hw)10714919Sxy150489 e1000_setup_led_82541(struct e1000_hw *hw)
10724919Sxy150489 {
10738479SChenlu.Chen@Sun.COM struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
10744919Sxy150489 s32 ret_val;
10754919Sxy150489
10764919Sxy150489 DEBUGFUNC("e1000_setup_led_82541");
10774919Sxy150489
10786735Scc210113 ret_val = hw->phy.ops.read_reg(hw,
10794919Sxy150489 IGP01E1000_GMII_FIFO,
10804919Sxy150489 &dev_spec->spd_default);
10814919Sxy150489 if (ret_val)
10824919Sxy150489 goto out;
10834919Sxy150489
10846735Scc210113 ret_val = hw->phy.ops.write_reg(hw,
10854919Sxy150489 IGP01E1000_GMII_FIFO,
10864919Sxy150489 (u16)(dev_spec->spd_default &
10874919Sxy150489 ~IGP01E1000_GMII_SPD));
10884919Sxy150489 if (ret_val)
10894919Sxy150489 goto out;
10904919Sxy150489
10914919Sxy150489 E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
10924919Sxy150489
10934919Sxy150489 out:
10944919Sxy150489 return (ret_val);
10954919Sxy150489 }
10964919Sxy150489
10974919Sxy150489 /*
10984919Sxy150489 * e1000_cleanup_led_82541 - Set LED config to default operation
10994919Sxy150489 * @hw: pointer to the HW structure
11004919Sxy150489 *
11014919Sxy150489 * Remove the current LED configuration and set the LED configuration
11028479SChenlu.Chen@Sun.COM * to the default value, saved from the EEPROM.
11034919Sxy150489 */
11044919Sxy150489 static s32
e1000_cleanup_led_82541(struct e1000_hw * hw)11054919Sxy150489 e1000_cleanup_led_82541(struct e1000_hw *hw)
11064919Sxy150489 {
11078479SChenlu.Chen@Sun.COM struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
11084919Sxy150489 s32 ret_val;
11094919Sxy150489
11104919Sxy150489 DEBUGFUNC("e1000_cleanup_led_82541");
11114919Sxy150489
11126735Scc210113 ret_val = hw->phy.ops.write_reg(hw,
11134919Sxy150489 IGP01E1000_GMII_FIFO,
11144919Sxy150489 dev_spec->spd_default);
11154919Sxy150489 if (ret_val)
11164919Sxy150489 goto out;
11174919Sxy150489
11184919Sxy150489 E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
11194919Sxy150489
11204919Sxy150489 out:
11214919Sxy150489 return (ret_val);
11224919Sxy150489 }
11234919Sxy150489
11244919Sxy150489 /*
11254919Sxy150489 * e1000_phy_init_script_82541 - Initialize GbE PHY
11264919Sxy150489 * @hw: pointer to the HW structure
11274919Sxy150489 *
11284919Sxy150489 * Initializes the IGP PHY.
11294919Sxy150489 */
11304919Sxy150489 static s32
e1000_phy_init_script_82541(struct e1000_hw * hw)11314919Sxy150489 e1000_phy_init_script_82541(struct e1000_hw *hw)
11324919Sxy150489 {
11338479SChenlu.Chen@Sun.COM struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
11344919Sxy150489 u32 ret_val;
11354919Sxy150489 u16 phy_saved_data;
11364919Sxy150489
11374919Sxy150489 DEBUGFUNC("e1000_phy_init_script_82541");
11384919Sxy150489
11394919Sxy150489 if (!dev_spec->phy_init_script) {
11404919Sxy150489 ret_val = E1000_SUCCESS;
11414919Sxy150489 goto out;
11424919Sxy150489 }
11434919Sxy150489
11444919Sxy150489 /* Delay after phy reset to enable NVM configuration to load */
11454919Sxy150489 msec_delay(20);
11464919Sxy150489
11474919Sxy150489 /*
11484919Sxy150489 * Save off the current value of register 0x2F5B to be restored at
11494919Sxy150489 * the end of this routine.
11504919Sxy150489 */
11516735Scc210113 ret_val = hw->phy.ops.read_reg(hw, 0x2F5B, &phy_saved_data);
11524919Sxy150489
11534919Sxy150489 /* Disabled the PHY transmitter */
11546735Scc210113 hw->phy.ops.write_reg(hw, 0x2F5B, 0x0003);
11554919Sxy150489
11564919Sxy150489 msec_delay(20);
11574919Sxy150489
11586735Scc210113 hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
11594919Sxy150489
11604919Sxy150489 msec_delay(5);
11614919Sxy150489
11624919Sxy150489 switch (hw->mac.type) {
11634919Sxy150489 case e1000_82541:
11644919Sxy150489 case e1000_82547:
11656735Scc210113 hw->phy.ops.write_reg(hw, 0x1F95, 0x0001);
11664919Sxy150489
11676735Scc210113 hw->phy.ops.write_reg(hw, 0x1F71, 0xBD21);
11684919Sxy150489
11696735Scc210113 hw->phy.ops.write_reg(hw, 0x1F79, 0x0018);
11704919Sxy150489
11716735Scc210113 hw->phy.ops.write_reg(hw, 0x1F30, 0x1600);
11724919Sxy150489
11736735Scc210113 hw->phy.ops.write_reg(hw, 0x1F31, 0x0014);
11744919Sxy150489
11756735Scc210113 hw->phy.ops.write_reg(hw, 0x1F32, 0x161C);
11764919Sxy150489
11776735Scc210113 hw->phy.ops.write_reg(hw, 0x1F94, 0x0003);
11784919Sxy150489
11796735Scc210113 hw->phy.ops.write_reg(hw, 0x1F96, 0x003F);
11804919Sxy150489
11816735Scc210113 hw->phy.ops.write_reg(hw, 0x2010, 0x0008);
11824919Sxy150489 break;
11834919Sxy150489 case e1000_82541_rev_2:
11844919Sxy150489 case e1000_82547_rev_2:
11856735Scc210113 hw->phy.ops.write_reg(hw, 0x1F73, 0x0099);
11864919Sxy150489 break;
11874919Sxy150489 default:
11884919Sxy150489 break;
11894919Sxy150489 }
11904919Sxy150489
11916735Scc210113 hw->phy.ops.write_reg(hw, 0x0000, 0x3300);
11924919Sxy150489
11934919Sxy150489 msec_delay(20);
11944919Sxy150489
11954919Sxy150489 /* Now enable the transmitter */
11966735Scc210113 hw->phy.ops.write_reg(hw, 0x2F5B, phy_saved_data);
11974919Sxy150489
11984919Sxy150489 if (hw->mac.type == e1000_82547) {
11994919Sxy150489 u16 fused, fine, coarse;
12004919Sxy150489
12014919Sxy150489 /* Move to analog registers page */
12026735Scc210113 hw->phy.ops.read_reg(hw,
12034919Sxy150489 IGP01E1000_ANALOG_SPARE_FUSE_STATUS,
12044919Sxy150489 &fused);
12054919Sxy150489
12064919Sxy150489 if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
12076735Scc210113 hw->phy.ops.read_reg(hw,
12084919Sxy150489 IGP01E1000_ANALOG_FUSE_STATUS,
12094919Sxy150489 &fused);
12104919Sxy150489
12114919Sxy150489 fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
12124919Sxy150489 coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK;
12134919Sxy150489
12144919Sxy150489 if (coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
12154919Sxy150489 coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10;
12164919Sxy150489 fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
12174919Sxy150489 } else if (coarse ==
12184919Sxy150489 IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
12194919Sxy150489 fine -= IGP01E1000_ANALOG_FUSE_FINE_10;
12204919Sxy150489
12214919Sxy150489 fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
12224919Sxy150489 (fine & IGP01E1000_ANALOG_FUSE_FINE_MASK) |
12234919Sxy150489 (coarse & IGP01E1000_ANALOG_FUSE_COARSE_MASK);
12244919Sxy150489
12256735Scc210113 hw->phy.ops.write_reg(hw,
12264919Sxy150489 IGP01E1000_ANALOG_FUSE_CONTROL,
12274919Sxy150489 fused);
12286735Scc210113 hw->phy.ops.write_reg(hw,
12294919Sxy150489 IGP01E1000_ANALOG_FUSE_BYPASS,
12304919Sxy150489 IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL);
12314919Sxy150489 }
12324919Sxy150489 }
12334919Sxy150489
12344919Sxy150489 out:
12354919Sxy150489 return (ret_val);
12364919Sxy150489 }
12374919Sxy150489
12384919Sxy150489 /*
12394919Sxy150489 * e1000_init_script_state_82541 - Enable/Disable PHY init script
12404919Sxy150489 * @hw: pointer to the HW structure
12414919Sxy150489 * @state: boolean value used to enable/disable PHY init script
12424919Sxy150489 *
12434919Sxy150489 * Allows the driver to enable/disable the PHY init script, if the PHY is an
12448479SChenlu.Chen@Sun.COM * IGP PHY.
12454919Sxy150489 */
12464919Sxy150489 void
e1000_init_script_state_82541(struct e1000_hw * hw,bool state)12476735Scc210113 e1000_init_script_state_82541(struct e1000_hw *hw, bool state)
12484919Sxy150489 {
12498479SChenlu.Chen@Sun.COM struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
12504919Sxy150489
12514919Sxy150489 DEBUGFUNC("e1000_init_script_state_82541");
12524919Sxy150489
12534919Sxy150489 if (hw->phy.type != e1000_phy_igp) {
12544919Sxy150489 DEBUGOUT("Initialization script not necessary.\n");
12554919Sxy150489 return;
12564919Sxy150489 }
12574919Sxy150489
12584919Sxy150489 dev_spec->phy_init_script = state;
12594919Sxy150489 }
12604919Sxy150489
12614919Sxy150489 /*
12626735Scc210113 * e1000_fifo_workaround_82547 - Workaround for Tx fifo failure
12634919Sxy150489 * @hw: pointer to the HW structure
12644919Sxy150489 * @length: length of next outgoing frame
12654919Sxy150489 *
12664919Sxy150489 * Returns: E1000_ERR_FIFO_WRAP if the next packet cannot be transmitted yet
12676735Scc210113 * E1000_SUCCESS if the next packet can be transmitted
12684919Sxy150489 *
12696735Scc210113 * Workaround for the 82547 Tx fifo failure.
12704919Sxy150489 */
12714919Sxy150489 s32
e1000_fifo_workaround_82547(struct e1000_hw * hw,u16 length)12724919Sxy150489 e1000_fifo_workaround_82547(struct e1000_hw *hw, u16 length)
12734919Sxy150489 {
12748479SChenlu.Chen@Sun.COM struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
12754919Sxy150489 u32 tctl;
12764919Sxy150489 s32 ret_val = E1000_SUCCESS;
12774919Sxy150489 u16 fifo_pkt_len;
12784919Sxy150489
12794919Sxy150489 DEBUGFUNC("e1000_fifo_workaround_82547");
12804919Sxy150489
12814919Sxy150489 if (hw->mac.type != e1000_82547)
12824919Sxy150489 goto out;
12834919Sxy150489
12844919Sxy150489 /*
12854919Sxy150489 * Get the length as seen by the FIFO of the next real
12864919Sxy150489 * packet to be transmitted.
12874919Sxy150489 */
12884919Sxy150489 fifo_pkt_len = E1000_ROUNDUP(length + E1000_FIFO_HDR_SIZE,
12894919Sxy150489 E1000_FIFO_GRANULARITY);
12904919Sxy150489
12914919Sxy150489 if (fifo_pkt_len <= (E1000_FIFO_PAD_82547 + E1000_FIFO_HDR_SIZE))
12924919Sxy150489 goto out;
12934919Sxy150489
12944919Sxy150489 if ((dev_spec->tx_fifo_head + fifo_pkt_len) <
12954919Sxy150489 (dev_spec->tx_fifo_size + E1000_FIFO_PAD_82547))
12964919Sxy150489 goto out;
12974919Sxy150489
12986735Scc210113 if (E1000_READ_REG(hw, E1000_TDT(0)) !=
12996735Scc210113 E1000_READ_REG(hw, E1000_TDH(0))) {
13004919Sxy150489 ret_val = -E1000_ERR_FIFO_WRAP;
13014919Sxy150489 goto out;
13024919Sxy150489 }
13034919Sxy150489
13044919Sxy150489 if (E1000_READ_REG(hw, E1000_TDFT) != E1000_READ_REG(hw, E1000_TDFH)) {
13054919Sxy150489 ret_val = -E1000_ERR_FIFO_WRAP;
13064919Sxy150489 goto out;
13074919Sxy150489 }
13084919Sxy150489
13094919Sxy150489 if (E1000_READ_REG(hw, E1000_TDFTS) !=
13104919Sxy150489 E1000_READ_REG(hw, E1000_TDFHS)) {
13114919Sxy150489 ret_val = -E1000_ERR_FIFO_WRAP;
13124919Sxy150489 goto out;
13134919Sxy150489 }
13144919Sxy150489
13154919Sxy150489 /* Disable the tx unit to avoid further pointer movement */
13164919Sxy150489 tctl = E1000_READ_REG(hw, E1000_TCTL);
13174919Sxy150489 E1000_WRITE_REG(hw, E1000_TCTL, tctl & ~E1000_TCTL_EN);
13184919Sxy150489
13194919Sxy150489 /* Reset the fifo pointers. */
13204919Sxy150489 E1000_WRITE_REG(hw, E1000_TDFT, dev_spec->tx_fifo_start);
13214919Sxy150489 E1000_WRITE_REG(hw, E1000_TDFH, dev_spec->tx_fifo_start);
13224919Sxy150489 E1000_WRITE_REG(hw, E1000_TDFTS, dev_spec->tx_fifo_start);
13234919Sxy150489 E1000_WRITE_REG(hw, E1000_TDFHS, dev_spec->tx_fifo_start);
13244919Sxy150489
13254919Sxy150489 /* Re-enabling tx unit */
13264919Sxy150489 E1000_WRITE_REG(hw, E1000_TCTL, tctl);
13274919Sxy150489 E1000_WRITE_FLUSH(hw);
13284919Sxy150489
13294919Sxy150489 dev_spec->tx_fifo_head = 0;
13304919Sxy150489
13314919Sxy150489 out:
13324919Sxy150489 return (ret_val);
13334919Sxy150489 }
13344919Sxy150489
13354919Sxy150489 /*
13366735Scc210113 * e1000_update_tx_fifo_head - Update Tx fifo head pointer
13374919Sxy150489 * @hw: pointer to the HW structure
13384919Sxy150489 * @length: length of next outgoing frame
13394919Sxy150489 *
13406735Scc210113 * Updates the SW calculated Tx FIFO head pointer.
13414919Sxy150489 */
13424919Sxy150489 void
e1000_update_tx_fifo_head_82547(struct e1000_hw * hw,u32 length)13434919Sxy150489 e1000_update_tx_fifo_head_82547(struct e1000_hw *hw, u32 length)
13444919Sxy150489 {
13458479SChenlu.Chen@Sun.COM struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
13464919Sxy150489
13474919Sxy150489 DEBUGFUNC("e1000_update_tx_fifo_head_82547");
13484919Sxy150489
13494919Sxy150489 if (hw->mac.type != e1000_82547)
13504919Sxy150489 return;
13514919Sxy150489
13524919Sxy150489 dev_spec->tx_fifo_head += E1000_ROUNDUP(length + E1000_FIFO_HDR_SIZE,
13534919Sxy150489 E1000_FIFO_GRANULARITY);
13544919Sxy150489
13554919Sxy150489 if (dev_spec->tx_fifo_head > dev_spec->tx_fifo_size)
13564919Sxy150489 dev_spec->tx_fifo_head -= dev_spec->tx_fifo_size;
13574919Sxy150489 }
13584919Sxy150489
13594919Sxy150489 /*
13604919Sxy150489 * e1000_set_ttl_workaround_state_82541 - Enable/Disables TTL workaround
13614919Sxy150489 * @hw: pointer to the HW structure
13624919Sxy150489 * @state: boolean to enable/disable TTL workaround
13634919Sxy150489 *
13644919Sxy150489 * For 82541 or 82547 only silicon, allows the driver to enable/disable the
13654919Sxy150489 * TTL workaround.
13664919Sxy150489 */
13674919Sxy150489 void
e1000_set_ttl_workaround_state_82541(struct e1000_hw * hw,bool state)13686735Scc210113 e1000_set_ttl_workaround_state_82541(struct e1000_hw *hw, bool state)
13694919Sxy150489 {
13708479SChenlu.Chen@Sun.COM struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
13714919Sxy150489
13724919Sxy150489 DEBUGFUNC("e1000_set_ttl_workaround_state_82541");
13734919Sxy150489
13744919Sxy150489 if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
13754919Sxy150489 return;
13764919Sxy150489
13774919Sxy150489 dev_spec->ttl_workaround = state;
13784919Sxy150489 }
13794919Sxy150489
13804919Sxy150489 /*
13814919Sxy150489 * e1000_ttl_workaround_enabled_82541 - Returns current TTL workaround status
13824919Sxy150489 * @hw: pointer to the HW structure
13834919Sxy150489 *
13844919Sxy150489 * Returns the current status of the TTL workaround, as to whether the
13854919Sxy150489 * workaround is enabled or disabled.
13864919Sxy150489 */
13876735Scc210113 bool
e1000_ttl_workaround_enabled_82541(struct e1000_hw * hw)13884919Sxy150489 e1000_ttl_workaround_enabled_82541(struct e1000_hw *hw)
13894919Sxy150489 {
13908479SChenlu.Chen@Sun.COM struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
13917607STed.You@Sun.COM bool state = false;
13924919Sxy150489
13934919Sxy150489 DEBUGFUNC("e1000_ttl_workaround_enabled_82541");
13944919Sxy150489
13954919Sxy150489 if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
13964919Sxy150489 goto out;
13974919Sxy150489
13984919Sxy150489 state = dev_spec->ttl_workaround;
13994919Sxy150489
14004919Sxy150489 out:
14014919Sxy150489 return (state);
14024919Sxy150489 }
14034919Sxy150489
14044919Sxy150489 /*
14054919Sxy150489 * e1000_igp_ttl_workaround_82547 - Workaround for long TTL on 100HD hubs
14064919Sxy150489 * @hw: pointer to the HW structure
14074919Sxy150489 *
14084919Sxy150489 * Returns: E1000_ERR_PHY if fail to read/write the PHY
14094919Sxy150489 * E1000_SUCCESS in any other case
14104919Sxy150489 *
14114919Sxy150489 * This function, specific to 82547 hardware only, needs to be called every
14124919Sxy150489 * second. It checks if a parallel detect fault has occurred. If a fault
14134919Sxy150489 * occurred, disable/enable the DSP reset mechanism up to 5 times (once per
14144919Sxy150489 * second). If link is established, stop the workaround and ensure the DSP
14154919Sxy150489 * reset is enabled.
14164919Sxy150489 */
14174919Sxy150489 s32
e1000_igp_ttl_workaround_82547(struct e1000_hw * hw)14184919Sxy150489 e1000_igp_ttl_workaround_82547(struct e1000_hw *hw)
14194919Sxy150489 {
14208479SChenlu.Chen@Sun.COM struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
14214919Sxy150489 s32 ret_val = E1000_SUCCESS;
14224919Sxy150489 u16 phy_data = 0;
14234919Sxy150489 u16 dsp_value = DSP_RESET_ENABLE;
14246735Scc210113 bool link;
14254919Sxy150489
14264919Sxy150489 DEBUGFUNC("e1000_igp_ttl_workaround_82547");
14274919Sxy150489
14284919Sxy150489 /* The workaround needed only for B-0 silicon HW */
14294919Sxy150489 if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
14304919Sxy150489 goto out;
14314919Sxy150489
14324919Sxy150489 if (!(e1000_ttl_workaround_enabled_82541(hw)))
14334919Sxy150489 goto out;
14344919Sxy150489
14354919Sxy150489 /* Check for link first */
14364919Sxy150489 ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
14374919Sxy150489 if (ret_val)
14384919Sxy150489 goto out;
14394919Sxy150489
14404919Sxy150489 if (link) {
14414919Sxy150489 /*
14424919Sxy150489 * If link is established during the workaround,
14434919Sxy150489 * the DSP mechanism must be enabled.
14444919Sxy150489 */
14454919Sxy150489 if (dev_spec->dsp_reset_counter) {
14464919Sxy150489 dev_spec->dsp_reset_counter = 0;
14474919Sxy150489 dsp_value = DSP_RESET_ENABLE;
14484919Sxy150489 } else {
14494919Sxy150489 ret_val = E1000_SUCCESS;
14504919Sxy150489 goto out;
14514919Sxy150489 }
14524919Sxy150489 } else {
14534919Sxy150489 if (dev_spec->dsp_reset_counter == 0) {
14544919Sxy150489 /*
14554919Sxy150489 * Workaround not activated,
14564919Sxy150489 * check if it needs activation
14574919Sxy150489 */
14586735Scc210113 ret_val = hw->phy.ops.read_reg(hw,
14594919Sxy150489 PHY_AUTONEG_EXP,
14604919Sxy150489 &phy_data);
14614919Sxy150489 if (ret_val)
14624919Sxy150489 goto out;
14634919Sxy150489 /*
14644919Sxy150489 * Activate the workaround if there was a
14654919Sxy150489 * parallel detect fault
14664919Sxy150489 */
14674919Sxy150489 if (phy_data & NWAY_ER_PAR_DETECT_FAULT) {
14684919Sxy150489 dev_spec->dsp_reset_counter++;
14694919Sxy150489 } else {
14704919Sxy150489 ret_val = E1000_SUCCESS;
14714919Sxy150489 goto out;
14724919Sxy150489 }
14734919Sxy150489 }
14744919Sxy150489
14754919Sxy150489 /* After 5 times, stop the workaround */
14764919Sxy150489 if (dev_spec->dsp_reset_counter > E1000_MAX_DSP_RESETS) {
14774919Sxy150489 dev_spec->dsp_reset_counter = 0;
14784919Sxy150489 dsp_value = DSP_RESET_ENABLE;
14794919Sxy150489 } else {
14804919Sxy150489 if (dev_spec->dsp_reset_counter) {
14814919Sxy150489 dsp_value = (dev_spec->dsp_reset_counter & 1)
14824919Sxy150489 ? DSP_RESET_DISABLE
14834919Sxy150489 : DSP_RESET_ENABLE;
14844919Sxy150489 dev_spec->dsp_reset_counter++;
14854919Sxy150489 }
14864919Sxy150489 }
14874919Sxy150489 }
14884919Sxy150489
14896735Scc210113 ret_val =
14906735Scc210113 hw->phy.ops.write_reg(hw, IGP01E1000_PHY_DSP_RESET, dsp_value);
14914919Sxy150489
14924919Sxy150489 out:
14934919Sxy150489 return (ret_val);
14944919Sxy150489 }
14954919Sxy150489
14964919Sxy150489 /*
14976735Scc210113 * e1000_power_down_phy_copper_82541 - Remove link in case of PHY power down
14986735Scc210113 * @hw: pointer to the HW structure
14996735Scc210113 *
15006735Scc210113 * In the case of a PHY power down to save power, or to turn off link during a
15016735Scc210113 * driver unload, or wake on lan is not enabled, remove the link.
15026735Scc210113 */
15036735Scc210113 static void
e1000_power_down_phy_copper_82541(struct e1000_hw * hw)15046735Scc210113 e1000_power_down_phy_copper_82541(struct e1000_hw *hw)
15056735Scc210113 {
15066735Scc210113 /* If the management interface is not enabled, then power down */
15076735Scc210113 if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN))
15086735Scc210113 e1000_power_down_phy_copper(hw);
15096735Scc210113 }
15106735Scc210113
15116735Scc210113 /*
15124919Sxy150489 * e1000_clear_hw_cntrs_82541 - Clear device specific hardware counters
15134919Sxy150489 * @hw: pointer to the HW structure
15144919Sxy150489 *
15154919Sxy150489 * Clears the hardware counters by reading the counter registers.
15164919Sxy150489 */
15174919Sxy150489 static void
e1000_clear_hw_cntrs_82541(struct e1000_hw * hw)15184919Sxy150489 e1000_clear_hw_cntrs_82541(struct e1000_hw *hw)
15194919Sxy150489 {
15204919Sxy150489 DEBUGFUNC("e1000_clear_hw_cntrs_82541");
15214919Sxy150489
15224919Sxy150489 e1000_clear_hw_cntrs_base_generic(hw);
15234919Sxy150489
15247426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC64);
15257426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC127);
15267426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC255);
15277426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC511);
15287426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC1023);
15297426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC1522);
15307426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC64);
15317426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC127);
15327426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC255);
15337426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC511);
15347426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC1023);
15357426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC1522);
15364919Sxy150489
15377426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_ALGNERRC);
15387426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_RXERRC);
15397426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_TNCRS);
15407426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_CEXTERR);
15417426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_TSCTC);
15427426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_TSCTFC);
15434919Sxy150489
15447426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_MGTPRC);
15457426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_MGTPDC);
15467426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_MGTPTC);
15474919Sxy150489 }
1548