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
166735Scc210113 * 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.57 v3-1-10-1_2009-9-18_Release14-6
284919Sxy150489 */
296735Scc210113
304919Sxy150489 /*
318479SChenlu.Chen@Sun.COM * 82540EM Gigabit Ethernet Controller
328479SChenlu.Chen@Sun.COM * 82540EP Gigabit Ethernet Controller
338479SChenlu.Chen@Sun.COM * 82545EM Gigabit Ethernet Controller (Copper)
348479SChenlu.Chen@Sun.COM * 82545EM Gigabit Ethernet Controller (Fiber)
358479SChenlu.Chen@Sun.COM * 82545GM Gigabit Ethernet Controller
368479SChenlu.Chen@Sun.COM * 82546EB Gigabit Ethernet Controller (Copper)
378479SChenlu.Chen@Sun.COM * 82546EB Gigabit Ethernet Controller (Fiber)
388479SChenlu.Chen@Sun.COM * 82546GB Gigabit Ethernet Controller
394919Sxy150489 */
404919Sxy150489
414919Sxy150489 #include "e1000_api.h"
424919Sxy150489
434919Sxy150489 static s32 e1000_init_phy_params_82540(struct e1000_hw *hw);
444919Sxy150489 static s32 e1000_init_nvm_params_82540(struct e1000_hw *hw);
454919Sxy150489 static s32 e1000_init_mac_params_82540(struct e1000_hw *hw);
464919Sxy150489 static s32 e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw);
474919Sxy150489 static void e1000_clear_hw_cntrs_82540(struct e1000_hw *hw);
484919Sxy150489 static s32 e1000_init_hw_82540(struct e1000_hw *hw);
494919Sxy150489 static s32 e1000_reset_hw_82540(struct e1000_hw *hw);
504919Sxy150489 static s32 e1000_set_phy_mode_82540(struct e1000_hw *hw);
514919Sxy150489 static s32 e1000_set_vco_speed_82540(struct e1000_hw *hw);
524919Sxy150489 static s32 e1000_setup_copper_link_82540(struct e1000_hw *hw);
534919Sxy150489 static s32 e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw);
546735Scc210113 static void e1000_power_down_phy_copper_82540(struct e1000_hw *hw);
5510680SMin.Xu@Sun.COM static s32 e1000_read_mac_addr_82540(struct e1000_hw *hw);
564919Sxy150489
574919Sxy150489 /*
584919Sxy150489 * e1000_init_phy_params_82540 - Init PHY func ptrs.
594919Sxy150489 * @hw: pointer to the HW structure
604919Sxy150489 */
614919Sxy150489 static s32
e1000_init_phy_params_82540(struct e1000_hw * hw)624919Sxy150489 e1000_init_phy_params_82540(struct e1000_hw *hw)
634919Sxy150489 {
644919Sxy150489 struct e1000_phy_info *phy = &hw->phy;
654919Sxy150489 s32 ret_val = E1000_SUCCESS;
664919Sxy150489
674919Sxy150489 phy->addr = 1;
684919Sxy150489 phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
694919Sxy150489 phy->reset_delay_us = 10000;
704919Sxy150489 phy->type = e1000_phy_m88;
714919Sxy150489
724919Sxy150489 /* Function Pointers */
736735Scc210113 phy->ops.check_polarity = e1000_check_polarity_m88;
746735Scc210113 phy->ops.commit = e1000_phy_sw_reset_generic;
756735Scc210113 phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
766735Scc210113 phy->ops.get_cable_length = e1000_get_cable_length_m88;
776735Scc210113 phy->ops.get_cfg_done = e1000_get_cfg_done_generic;
786735Scc210113 phy->ops.read_reg = e1000_read_phy_reg_m88;
796735Scc210113 phy->ops.reset = e1000_phy_hw_reset_generic;
806735Scc210113 phy->ops.write_reg = e1000_write_phy_reg_m88;
816735Scc210113 phy->ops.get_info = e1000_get_phy_info_m88;
826735Scc210113 phy->ops.power_up = e1000_power_up_phy_copper;
836735Scc210113 phy->ops.power_down = e1000_power_down_phy_copper_82540;
844919Sxy150489
854919Sxy150489 ret_val = e1000_get_phy_id(hw);
864919Sxy150489 if (ret_val)
874919Sxy150489 goto out;
884919Sxy150489
894919Sxy150489 /* Verify phy id */
904919Sxy150489 switch (hw->mac.type) {
914919Sxy150489 case e1000_82540:
924919Sxy150489 case e1000_82545:
934919Sxy150489 case e1000_82545_rev_3:
944919Sxy150489 case e1000_82546:
954919Sxy150489 case e1000_82546_rev_3:
964919Sxy150489 if (phy->id == M88E1011_I_PHY_ID)
974919Sxy150489 break;
984919Sxy150489 /* Fall Through */
994919Sxy150489 default:
1004919Sxy150489 ret_val = -E1000_ERR_PHY;
1014919Sxy150489 goto out;
1024919Sxy150489 }
1034919Sxy150489
1044919Sxy150489 out:
1054919Sxy150489 return (ret_val);
1064919Sxy150489 }
1074919Sxy150489
1084919Sxy150489 /*
1094919Sxy150489 * e1000_init_nvm_params_82540 - Init NVM func ptrs.
1104919Sxy150489 * @hw: pointer to the HW structure
1114919Sxy150489 */
1124919Sxy150489 static s32
e1000_init_nvm_params_82540(struct e1000_hw * hw)1134919Sxy150489 e1000_init_nvm_params_82540(struct e1000_hw *hw)
1144919Sxy150489 {
1154919Sxy150489 struct e1000_nvm_info *nvm = &hw->nvm;
1164919Sxy150489 u32 eecd = E1000_READ_REG(hw, E1000_EECD);
1174919Sxy150489
1184919Sxy150489 DEBUGFUNC("e1000_init_nvm_params_82540");
1194919Sxy150489
1204919Sxy150489 nvm->type = e1000_nvm_eeprom_microwire;
1214919Sxy150489 nvm->delay_usec = 50;
1224919Sxy150489 nvm->opcode_bits = 3;
1234919Sxy150489 switch (nvm->override) {
1244919Sxy150489 case e1000_nvm_override_microwire_large:
1254919Sxy150489 nvm->address_bits = 8;
1264919Sxy150489 nvm->word_size = 256;
1274919Sxy150489 break;
1284919Sxy150489 case e1000_nvm_override_microwire_small:
1294919Sxy150489 nvm->address_bits = 6;
1304919Sxy150489 nvm->word_size = 64;
1314919Sxy150489 break;
1324919Sxy150489 default:
1334919Sxy150489 nvm->address_bits = eecd & E1000_EECD_SIZE ? 8 : 6;
1344919Sxy150489 nvm->word_size = eecd & E1000_EECD_SIZE ? 256 : 64;
1354919Sxy150489 break;
1364919Sxy150489 }
1374919Sxy150489
1384919Sxy150489 /* Function Pointers */
1396735Scc210113 nvm->ops.acquire = e1000_acquire_nvm_generic;
1406735Scc210113 nvm->ops.read = e1000_read_nvm_microwire;
1416735Scc210113 nvm->ops.release = e1000_release_nvm_generic;
1426735Scc210113 nvm->ops.update = e1000_update_nvm_checksum_generic;
1436735Scc210113 nvm->ops.valid_led_default = e1000_valid_led_default_generic;
1446735Scc210113 nvm->ops.validate = e1000_validate_nvm_checksum_generic;
1456735Scc210113 nvm->ops.write = e1000_write_nvm_microwire;
1464919Sxy150489
1474919Sxy150489 return (E1000_SUCCESS);
1484919Sxy150489 }
1494919Sxy150489
1504919Sxy150489 /*
1514919Sxy150489 * e1000_init_mac_params_82540 - Init MAC func ptrs.
1524919Sxy150489 * @hw: pointer to the HW structure
1534919Sxy150489 */
1544919Sxy150489 static s32
e1000_init_mac_params_82540(struct e1000_hw * hw)1554919Sxy150489 e1000_init_mac_params_82540(struct e1000_hw *hw)
1564919Sxy150489 {
1574919Sxy150489 struct e1000_mac_info *mac = &hw->mac;
1584919Sxy150489 s32 ret_val = E1000_SUCCESS;
1594919Sxy150489
1604919Sxy150489 DEBUGFUNC("e1000_init_mac_params_82540");
1614919Sxy150489
1624919Sxy150489 /* Set media type */
1634919Sxy150489 switch (hw->device_id) {
1644919Sxy150489 case E1000_DEV_ID_82545EM_FIBER:
1654919Sxy150489 case E1000_DEV_ID_82545GM_FIBER:
1664919Sxy150489 case E1000_DEV_ID_82546EB_FIBER:
1674919Sxy150489 case E1000_DEV_ID_82546GB_FIBER:
1686735Scc210113 hw->phy.media_type = e1000_media_type_fiber;
1694919Sxy150489 break;
1704919Sxy150489 case E1000_DEV_ID_82545GM_SERDES:
1714919Sxy150489 case E1000_DEV_ID_82546GB_SERDES:
1726735Scc210113 hw->phy.media_type = e1000_media_type_internal_serdes;
1734919Sxy150489 break;
1744919Sxy150489 default:
1756735Scc210113 hw->phy.media_type = e1000_media_type_copper;
1764919Sxy150489 break;
1774919Sxy150489 }
1784919Sxy150489
1794919Sxy150489 /* Set mta register count */
1804919Sxy150489 mac->mta_reg_count = 128;
1814919Sxy150489 /* Set rar entry count */
1824919Sxy150489 mac->rar_entry_count = E1000_RAR_ENTRIES;
1834919Sxy150489
1844919Sxy150489 /* Function pointers */
1854919Sxy150489
1864919Sxy150489 /* bus type/speed/width */
1876735Scc210113 mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
18810680SMin.Xu@Sun.COM /* function id */
18910680SMin.Xu@Sun.COM mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci;
1904919Sxy150489 /* reset */
1916735Scc210113 mac->ops.reset_hw = e1000_reset_hw_82540;
1924919Sxy150489 /* hw initialization */
1936735Scc210113 mac->ops.init_hw = e1000_init_hw_82540;
1944919Sxy150489 /* link setup */
1956735Scc210113 mac->ops.setup_link = e1000_setup_link_generic;
1964919Sxy150489 /* physical interface setup */
1976735Scc210113 mac->ops.setup_physical_interface =
1986735Scc210113 (hw->phy.media_type == e1000_media_type_copper)
1994919Sxy150489 ? e1000_setup_copper_link_82540
2004919Sxy150489 : e1000_setup_fiber_serdes_link_82540;
2014919Sxy150489 /* check for link */
2026735Scc210113 switch (hw->phy.media_type) {
2034919Sxy150489 case e1000_media_type_copper:
2046735Scc210113 mac->ops.check_for_link = e1000_check_for_copper_link_generic;
2054919Sxy150489 break;
2064919Sxy150489 case e1000_media_type_fiber:
2076735Scc210113 mac->ops.check_for_link = e1000_check_for_fiber_link_generic;
2084919Sxy150489 break;
2094919Sxy150489 case e1000_media_type_internal_serdes:
2106735Scc210113 mac->ops.check_for_link = e1000_check_for_serdes_link_generic;
2114919Sxy150489 break;
2124919Sxy150489 default:
2134919Sxy150489 ret_val = -E1000_ERR_CONFIG;
2144919Sxy150489 goto out;
2154919Sxy150489 }
2164919Sxy150489 /* link info */
2176735Scc210113 mac->ops.get_link_up_info =
2186735Scc210113 (hw->phy.media_type == e1000_media_type_copper)
2194919Sxy150489 ? e1000_get_speed_and_duplex_copper_generic
2204919Sxy150489 : e1000_get_speed_and_duplex_fiber_serdes_generic;
2214919Sxy150489 /* multicast address update */
2226735Scc210113 mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
2234919Sxy150489 /* writing VFTA */
2246735Scc210113 mac->ops.write_vfta = e1000_write_vfta_generic;
2254919Sxy150489 /* clearing VFTA */
2266735Scc210113 mac->ops.clear_vfta = e1000_clear_vfta_generic;
2274919Sxy150489 /* setting MTA */
2286735Scc210113 mac->ops.mta_set = e1000_mta_set_generic;
22910680SMin.Xu@Sun.COM /* ID LED init */
23010680SMin.Xu@Sun.COM mac->ops.id_led_init = e1000_id_led_init_generic;
2314919Sxy150489 /* setup LED */
2326735Scc210113 mac->ops.setup_led = e1000_setup_led_generic;
23310680SMin.Xu@Sun.COM /* read mac address */
23410680SMin.Xu@Sun.COM mac->ops.read_mac_addr = e1000_read_mac_addr_82540;
2354919Sxy150489 /* cleanup LED */
2366735Scc210113 mac->ops.cleanup_led = e1000_cleanup_led_generic;
2374919Sxy150489 /* turn on/off LED */
2386735Scc210113 mac->ops.led_on = e1000_led_on_generic;
2396735Scc210113 mac->ops.led_off = e1000_led_off_generic;
2404919Sxy150489 /* clear hardware counters */
2416735Scc210113 mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82540;
2424919Sxy150489
2434919Sxy150489 out:
2444919Sxy150489 return (ret_val);
2454919Sxy150489 }
2464919Sxy150489
2474919Sxy150489 /*
2484919Sxy150489 * e1000_init_function_pointers_82540 - Init func ptrs.
2494919Sxy150489 * @hw: pointer to the HW structure
2504919Sxy150489 *
2518479SChenlu.Chen@Sun.COM * Called to initialize all function pointers and parameters.
2524919Sxy150489 */
2534919Sxy150489 void
e1000_init_function_pointers_82540(struct e1000_hw * hw)2544919Sxy150489 e1000_init_function_pointers_82540(struct e1000_hw *hw)
2554919Sxy150489 {
2564919Sxy150489 DEBUGFUNC("e1000_init_function_pointers_82540");
2574919Sxy150489
2586735Scc210113 hw->mac.ops.init_params = e1000_init_mac_params_82540;
2596735Scc210113 hw->nvm.ops.init_params = e1000_init_nvm_params_82540;
2606735Scc210113 hw->phy.ops.init_params = e1000_init_phy_params_82540;
2614919Sxy150489 }
2624919Sxy150489
2634919Sxy150489 /*
26410680SMin.Xu@Sun.COM * e1000_reset_hw_82540 - Reset hardware
26510680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
2664919Sxy150489 *
26710680SMin.Xu@Sun.COM * This resets the hardware into a known state.
2684919Sxy150489 */
2694919Sxy150489 static s32
e1000_reset_hw_82540(struct e1000_hw * hw)2704919Sxy150489 e1000_reset_hw_82540(struct e1000_hw *hw)
2714919Sxy150489 {
2727426SChenliang.Xu@Sun.COM u32 ctrl, manc;
2734919Sxy150489 s32 ret_val = E1000_SUCCESS;
2744919Sxy150489
2754919Sxy150489 DEBUGFUNC("e1000_reset_hw_82540");
2764919Sxy150489
2774919Sxy150489 DEBUGOUT("Masking off all interrupts\n");
2784919Sxy150489 E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
2794919Sxy150489
2804919Sxy150489 E1000_WRITE_REG(hw, E1000_RCTL, 0);
2814919Sxy150489 E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
2824919Sxy150489 E1000_WRITE_FLUSH(hw);
2834919Sxy150489
2844919Sxy150489 /*
2854919Sxy150489 * Delay to allow any outstanding PCI transactions to complete
2864919Sxy150489 * before resetting the device.
2874919Sxy150489 */
2884919Sxy150489 msec_delay(10);
2894919Sxy150489
2904919Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL);
2914919Sxy150489
2924919Sxy150489 DEBUGOUT("Issuing a global reset to 82540/82545/82546 MAC\n");
2934919Sxy150489 switch (hw->mac.type) {
2944919Sxy150489 case e1000_82545_rev_3:
2954919Sxy150489 case e1000_82546_rev_3:
2964919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL_DUP, ctrl | E1000_CTRL_RST);
2974919Sxy150489 break;
2984919Sxy150489 default:
2994919Sxy150489 /*
3004919Sxy150489 * These controllers can't ack the 64-bit write when
3014919Sxy150489 * issuing the reset, so we use IO-mapping as a
3024919Sxy150489 * workaround to issue the reset.
3034919Sxy150489 */
3044919Sxy150489 E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
3054919Sxy150489 break;
3064919Sxy150489 }
3074919Sxy150489
3084919Sxy150489 /* Wait for EEPROM reload */
3094919Sxy150489 msec_delay(5);
3104919Sxy150489
3114919Sxy150489 /* Disable HW ARPs on ASF enabled adapters */
3124919Sxy150489 manc = E1000_READ_REG(hw, E1000_MANC);
3134919Sxy150489 manc &= ~E1000_MANC_ARP_EN;
3144919Sxy150489 E1000_WRITE_REG(hw, E1000_MANC, manc);
3154919Sxy150489
3164919Sxy150489 E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
3177426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_ICR);
3184919Sxy150489
3194919Sxy150489 return (ret_val);
3204919Sxy150489 }
3214919Sxy150489
3224919Sxy150489 /*
32310680SMin.Xu@Sun.COM * e1000_init_hw_82540 - Initialize hardware
32410680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
3254919Sxy150489 *
32610680SMin.Xu@Sun.COM * This inits the hardware readying it for operation.
3274919Sxy150489 */
3284919Sxy150489 static s32
e1000_init_hw_82540(struct e1000_hw * hw)3294919Sxy150489 e1000_init_hw_82540(struct e1000_hw *hw)
3304919Sxy150489 {
3314919Sxy150489 struct e1000_mac_info *mac = &hw->mac;
3324919Sxy150489 u32 txdctl, ctrl_ext;
3334919Sxy150489 s32 ret_val = E1000_SUCCESS;
3344919Sxy150489 u16 i;
3354919Sxy150489
3364919Sxy150489 DEBUGFUNC("e1000_init_hw_82540");
3374919Sxy150489
3384919Sxy150489 /* Initialize identification LED */
33910680SMin.Xu@Sun.COM ret_val = mac->ops.id_led_init(hw);
3404919Sxy150489 if (ret_val) {
341*11143SGuoqing.Zhu@Sun.COM /* EMPTY */
3424919Sxy150489 DEBUGOUT("Error initializing identification LED\n");
3436735Scc210113 /* This is not fatal and we should not stop init due to this */
3444919Sxy150489 }
3454919Sxy150489
3464919Sxy150489 /* Disabling VLAN filtering */
3474919Sxy150489 DEBUGOUT("Initializing the IEEE VLAN\n");
3484919Sxy150489 if (mac->type < e1000_82545_rev_3)
3494919Sxy150489 E1000_WRITE_REG(hw, E1000_VET, 0);
3504919Sxy150489
3516735Scc210113 mac->ops.clear_vfta(hw);
3524919Sxy150489
3534919Sxy150489 /* Setup the receive address. */
3544919Sxy150489 e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
3554919Sxy150489
3564919Sxy150489 /* Zero out the Multicast HASH table */
3574919Sxy150489 DEBUGOUT("Zeroing the MTA\n");
3584919Sxy150489 for (i = 0; i < mac->mta_reg_count; i++) {
3594919Sxy150489 E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
3604919Sxy150489 /*
3614919Sxy150489 * Avoid back to back register writes by adding the register
3624919Sxy150489 * read (flush). This is to protect against some strange
3634919Sxy150489 * bridge configurations that may issue Memory Write Block
3644919Sxy150489 * (MWB) to our register space. The *_rev_3 hardware at
3654919Sxy150489 * least doesn't respond correctly to every other dword in an
3664919Sxy150489 * MWB to our register space.
3674919Sxy150489 */
3684919Sxy150489 E1000_WRITE_FLUSH(hw);
3694919Sxy150489 }
3704919Sxy150489
3714919Sxy150489 if (mac->type < e1000_82545_rev_3)
3724919Sxy150489 e1000_pcix_mmrbc_workaround_generic(hw);
3734919Sxy150489
3744919Sxy150489 /* Setup link and flow control */
3756735Scc210113 ret_val = mac->ops.setup_link(hw);
3764919Sxy150489
3776735Scc210113 txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
3784919Sxy150489 txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
3794919Sxy150489 E1000_TXDCTL_FULL_TX_DESC_WB;
3806735Scc210113 E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
3814919Sxy150489
3824919Sxy150489 /*
3834919Sxy150489 * Clear all of the statistics registers (clear on read). It is
3844919Sxy150489 * important that we do this after we have tried to establish link
3854919Sxy150489 * because the symbol error count will increment wildly if there
3864919Sxy150489 * is no link.
3874919Sxy150489 */
3884919Sxy150489 e1000_clear_hw_cntrs_82540(hw);
3894919Sxy150489
3904919Sxy150489 if ((hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER) ||
3914919Sxy150489 (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3)) {
3924919Sxy150489 ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
3934919Sxy150489 /*
3944919Sxy150489 * Relaxed ordering must be disabled to avoid a parity
3954919Sxy150489 * error crash in a PCI slot.
3964919Sxy150489 */
3974919Sxy150489 ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
3984919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
3994919Sxy150489 }
4004919Sxy150489 return (ret_val);
4014919Sxy150489 }
4024919Sxy150489
4034919Sxy150489 /*
40410680SMin.Xu@Sun.COM * e1000_setup_copper_link_82540 - Configure copper link settings
40510680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
4064919Sxy150489 *
40710680SMin.Xu@Sun.COM * Calls the appropriate function to configure the link for auto-neg or forced
40810680SMin.Xu@Sun.COM * speed and duplex. Then we check for link, once link is established calls
40910680SMin.Xu@Sun.COM * to configure collision distance and flow control are called. If link is
41010680SMin.Xu@Sun.COM * not established, we return -E1000_ERR_PHY (-2).
4114919Sxy150489 */
4124919Sxy150489 static s32
e1000_setup_copper_link_82540(struct e1000_hw * hw)4134919Sxy150489 e1000_setup_copper_link_82540(struct e1000_hw *hw)
4144919Sxy150489 {
4154919Sxy150489 u32 ctrl;
4164919Sxy150489 s32 ret_val = E1000_SUCCESS;
4174919Sxy150489 u16 data;
4184919Sxy150489
4194919Sxy150489 DEBUGFUNC("e1000_setup_copper_link_82540");
4204919Sxy150489
4214919Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL);
4224919Sxy150489 ctrl |= E1000_CTRL_SLU;
4234919Sxy150489 ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
4244919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
4254919Sxy150489
4264919Sxy150489 ret_val = e1000_set_phy_mode_82540(hw);
4274919Sxy150489 if (ret_val)
4284919Sxy150489 goto out;
4294919Sxy150489
4304919Sxy150489 if (hw->mac.type == e1000_82545_rev_3 ||
4314919Sxy150489 hw->mac.type == e1000_82546_rev_3) {
4326735Scc210113 ret_val =
4336735Scc210113 hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &data);
4344919Sxy150489 if (ret_val)
4354919Sxy150489 goto out;
4364919Sxy150489 data |= 0x00000008;
4376735Scc210113 ret_val =
4386735Scc210113 hw->phy.ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, data);
4394919Sxy150489 if (ret_val)
4404919Sxy150489 goto out;
4414919Sxy150489 }
4424919Sxy150489 ret_val = e1000_copper_link_setup_m88(hw);
4434919Sxy150489 if (ret_val)
4444919Sxy150489 goto out;
4454919Sxy150489
4464919Sxy150489 ret_val = e1000_setup_copper_link_generic(hw);
4474919Sxy150489
4484919Sxy150489 out:
4494919Sxy150489 return (ret_val);
4504919Sxy150489 }
4514919Sxy150489
4524919Sxy150489 /*
45310680SMin.Xu@Sun.COM * e1000_setup_fiber_serdes_link_82540 - Setup link for fiber/serdes
45410680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
4554919Sxy150489 *
45610680SMin.Xu@Sun.COM * Set the output amplitude to the value in the EEPROM and adjust the VCO
45710680SMin.Xu@Sun.COM * speed to improve Bit Error Rate (BER) performance. Configures collision
45810680SMin.Xu@Sun.COM * distance and flow control for fiber and serdes links. Upon successful
45910680SMin.Xu@Sun.COM * setup, poll for link.
4604919Sxy150489 */
4614919Sxy150489 static s32
e1000_setup_fiber_serdes_link_82540(struct e1000_hw * hw)4624919Sxy150489 e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw)
4634919Sxy150489 {
4644919Sxy150489 struct e1000_mac_info *mac = &hw->mac;
4654919Sxy150489 s32 ret_val = E1000_SUCCESS;
4664919Sxy150489
4674919Sxy150489 DEBUGFUNC("e1000_setup_fiber_serdes_link_82540");
4684919Sxy150489
4694919Sxy150489 switch (mac->type) {
4704919Sxy150489 case e1000_82545_rev_3:
4714919Sxy150489 case e1000_82546_rev_3:
4726735Scc210113 if (hw->phy.media_type == e1000_media_type_internal_serdes) {
4734919Sxy150489 /*
4744919Sxy150489 * If we're on serdes media, adjust the output
4754919Sxy150489 * amplitude to value set in the EEPROM.
4764919Sxy150489 */
4774919Sxy150489 ret_val = e1000_adjust_serdes_amplitude_82540(hw);
4784919Sxy150489 if (ret_val)
4794919Sxy150489 goto out;
4804919Sxy150489 }
4814919Sxy150489 /* Adjust VCO speed to improve BER performance */
4824919Sxy150489 ret_val = e1000_set_vco_speed_82540(hw);
4834919Sxy150489 if (ret_val)
4844919Sxy150489 goto out;
4854919Sxy150489 default:
4864919Sxy150489 break;
4874919Sxy150489 }
4884919Sxy150489
4894919Sxy150489 ret_val = e1000_setup_fiber_serdes_link_generic(hw);
4904919Sxy150489
4914919Sxy150489 out:
4924919Sxy150489 return (ret_val);
4934919Sxy150489 }
4944919Sxy150489
4954919Sxy150489 /*
49610680SMin.Xu@Sun.COM * e1000_adjust_serdes_amplitude_82540 - Adjust amplitude based on EEPROM
49710680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
4984919Sxy150489 *
49910680SMin.Xu@Sun.COM * Adjust the SERDES output amplitude based on the EEPROM settings.
5004919Sxy150489 */
5014919Sxy150489 static s32
e1000_adjust_serdes_amplitude_82540(struct e1000_hw * hw)5024919Sxy150489 e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw)
5034919Sxy150489 {
5044919Sxy150489 s32 ret_val = E1000_SUCCESS;
5054919Sxy150489 u16 nvm_data;
5064919Sxy150489
5074919Sxy150489 DEBUGFUNC("e1000_adjust_serdes_amplitude_82540");
5084919Sxy150489
5096735Scc210113 ret_val = hw->nvm.ops.read(hw, NVM_SERDES_AMPLITUDE, 1, &nvm_data);
5104919Sxy150489 if (ret_val)
5114919Sxy150489 goto out;
5124919Sxy150489
5134919Sxy150489 if (nvm_data != NVM_RESERVED_WORD) {
5144919Sxy150489 /* Adjust serdes output amplitude only. */
5154919Sxy150489 nvm_data &= NVM_SERDES_AMPLITUDE_MASK;
5166735Scc210113 ret_val = hw->phy.ops.write_reg(hw,
5174919Sxy150489 M88E1000_PHY_EXT_CTRL,
5184919Sxy150489 nvm_data);
5194919Sxy150489 if (ret_val)
5204919Sxy150489 goto out;
5214919Sxy150489 }
5224919Sxy150489 out:
5234919Sxy150489 return (ret_val);
5244919Sxy150489 }
5254919Sxy150489
5264919Sxy150489 /*
52710680SMin.Xu@Sun.COM * e1000_set_vco_speed_82540 - Set VCO speed for better performance
52810680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
5294919Sxy150489 *
53010680SMin.Xu@Sun.COM * Set the VCO speed to improve Bit Error Rate (BER) performance.
5314919Sxy150489 */
5324919Sxy150489 static s32
e1000_set_vco_speed_82540(struct e1000_hw * hw)5334919Sxy150489 e1000_set_vco_speed_82540(struct e1000_hw *hw)
5344919Sxy150489 {
5354919Sxy150489 s32 ret_val = E1000_SUCCESS;
5364919Sxy150489 u16 default_page = 0;
5374919Sxy150489 u16 phy_data;
5384919Sxy150489
5394919Sxy150489 DEBUGFUNC("e1000_set_vco_speed_82540");
5404919Sxy150489
5414919Sxy150489 /* Set PHY register 30, page 5, bit 8 to 0 */
5424919Sxy150489
5436735Scc210113 ret_val = hw->phy.ops.read_reg(hw,
5444919Sxy150489 M88E1000_PHY_PAGE_SELECT,
5454919Sxy150489 &default_page);
5464919Sxy150489 if (ret_val)
5474919Sxy150489 goto out;
5484919Sxy150489
5496735Scc210113 ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005);
5504919Sxy150489 if (ret_val)
5514919Sxy150489 goto out;
5524919Sxy150489
5536735Scc210113 ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
5544919Sxy150489 if (ret_val)
5554919Sxy150489 goto out;
5564919Sxy150489
5574919Sxy150489 phy_data &= ~M88E1000_PHY_VCO_REG_BIT8;
5586735Scc210113 ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
5594919Sxy150489 if (ret_val)
5604919Sxy150489 goto out;
5614919Sxy150489
5624919Sxy150489 /* Set PHY register 30, page 4, bit 11 to 1 */
5634919Sxy150489
5646735Scc210113 ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004);
5654919Sxy150489 if (ret_val)
5664919Sxy150489 goto out;
5674919Sxy150489
5686735Scc210113 ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
5694919Sxy150489 if (ret_val)
5704919Sxy150489 goto out;
5714919Sxy150489
5724919Sxy150489 phy_data |= M88E1000_PHY_VCO_REG_BIT11;
5736735Scc210113 ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
5744919Sxy150489 if (ret_val)
5754919Sxy150489 goto out;
5764919Sxy150489
5776735Scc210113 ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT,
5784919Sxy150489 default_page);
5794919Sxy150489
5804919Sxy150489 out:
5814919Sxy150489 return (ret_val);
5824919Sxy150489 }
5834919Sxy150489
5844919Sxy150489 /*
58510680SMin.Xu@Sun.COM * e1000_set_phy_mode_82540 - Set PHY to class A mode
58610680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
5874919Sxy150489 *
58810680SMin.Xu@Sun.COM * Sets the PHY to class A mode and assumes the following operations will
58910680SMin.Xu@Sun.COM * follow to enable the new class mode:
59010680SMin.Xu@Sun.COM * 1. Do a PHY soft reset.
59110680SMin.Xu@Sun.COM * 2. Restart auto-negotiation or force link.
5924919Sxy150489 */
5934919Sxy150489 static s32
e1000_set_phy_mode_82540(struct e1000_hw * hw)5944919Sxy150489 e1000_set_phy_mode_82540(struct e1000_hw *hw)
5954919Sxy150489 {
5964919Sxy150489 struct e1000_phy_info *phy = &hw->phy;
5974919Sxy150489 s32 ret_val = E1000_SUCCESS;
5984919Sxy150489 u16 nvm_data;
5994919Sxy150489
6004919Sxy150489 DEBUGFUNC("e1000_set_phy_mode_82540");
6014919Sxy150489
6024919Sxy150489 if (hw->mac.type != e1000_82545_rev_3)
6034919Sxy150489 goto out;
6044919Sxy150489
6056735Scc210113 ret_val = hw->nvm.ops.read(hw, NVM_PHY_CLASS_WORD, 1, &nvm_data);
6064919Sxy150489 if (ret_val) {
6074919Sxy150489 ret_val = -E1000_ERR_PHY;
6084919Sxy150489 goto out;
6094919Sxy150489 }
6104919Sxy150489
6114919Sxy150489 if ((nvm_data != NVM_RESERVED_WORD) && (nvm_data & NVM_PHY_CLASS_A)) {
6126735Scc210113 ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT,
6134919Sxy150489 0x000B);
6144919Sxy150489 if (ret_val) {
6154919Sxy150489 ret_val = -E1000_ERR_PHY;
6164919Sxy150489 goto out;
6174919Sxy150489 }
6186735Scc210113 ret_val = hw->phy.ops.write_reg(hw,
6194919Sxy150489 M88E1000_PHY_GEN_CONTROL,
6204919Sxy150489 0x8104);
6214919Sxy150489 if (ret_val) {
6224919Sxy150489 ret_val = -E1000_ERR_PHY;
6234919Sxy150489 goto out;
6244919Sxy150489 }
6254919Sxy150489
6267607STed.You@Sun.COM phy->reset_disable = false;
6274919Sxy150489 }
6284919Sxy150489
6294919Sxy150489 out:
6304919Sxy150489 return (ret_val);
6314919Sxy150489 }
6324919Sxy150489
6334919Sxy150489 /*
6346735Scc210113 * e1000_power_down_phy_copper_82540 - Remove link in case of PHY power down
6354919Sxy150489 * @hw: pointer to the HW structure
6364919Sxy150489 *
6376735Scc210113 * In the case of a PHY power down to save power, or to turn off link during a
6386735Scc210113 * driver unload, or wake on lan is not enabled, remove the link.
6396735Scc210113 */
6406735Scc210113 static void
e1000_power_down_phy_copper_82540(struct e1000_hw * hw)6416735Scc210113 e1000_power_down_phy_copper_82540(struct e1000_hw *hw)
6426735Scc210113 {
6436735Scc210113 /* If the management interface is not enabled, then power down */
6446735Scc210113 if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN))
6456735Scc210113 e1000_power_down_phy_copper(hw);
6466735Scc210113 }
6476735Scc210113
6486735Scc210113 /*
64910680SMin.Xu@Sun.COM * e1000_clear_hw_cntrs_82540 - Clear device specific hardware counters
65010680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
6516735Scc210113 *
65210680SMin.Xu@Sun.COM * Clears the hardware counters by reading the counter registers.
6534919Sxy150489 */
6544919Sxy150489 static void
e1000_clear_hw_cntrs_82540(struct e1000_hw * hw)6554919Sxy150489 e1000_clear_hw_cntrs_82540(struct e1000_hw *hw)
6564919Sxy150489 {
6574919Sxy150489 DEBUGFUNC("e1000_clear_hw_cntrs_82540");
6584919Sxy150489
6594919Sxy150489 e1000_clear_hw_cntrs_base_generic(hw);
6604919Sxy150489
6617426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC64);
6627426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC127);
6637426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC255);
6647426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC511);
6657426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC1023);
6667426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PRC1522);
6677426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC64);
6687426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC127);
6697426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC255);
6707426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC511);
6717426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC1023);
6727426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_PTC1522);
6734919Sxy150489
6747426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_ALGNERRC);
6757426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_RXERRC);
6767426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_TNCRS);
6777426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_CEXTERR);
6787426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_TSCTC);
6797426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_TSCTFC);
6804919Sxy150489
6817426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_MGTPRC);
6827426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_MGTPDC);
6837426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_MGTPTC);
6844919Sxy150489 }
68510680SMin.Xu@Sun.COM
68610680SMin.Xu@Sun.COM /*
68710680SMin.Xu@Sun.COM * e1000_read_mac_addr_82540 - Read device MAC address
68810680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
68910680SMin.Xu@Sun.COM *
69010680SMin.Xu@Sun.COM * Reads the device MAC address from the EEPROM and stores the value.
69110680SMin.Xu@Sun.COM * Since devices with two ports use the same EEPROM, we increment the
69210680SMin.Xu@Sun.COM * last bit in the MAC address for the second port.
69310680SMin.Xu@Sun.COM *
69410680SMin.Xu@Sun.COM * This version is being used over generic because of customer issues
69510680SMin.Xu@Sun.COM * with VmWare and Virtual Box when using generic. It seems in
69610680SMin.Xu@Sun.COM * the emulated 82545, RAR[0] does NOT have a valid address after a
69710680SMin.Xu@Sun.COM * reset, this older method works and using this breaks nothing for
69810680SMin.Xu@Sun.COM * these legacy adapters.
69910680SMin.Xu@Sun.COM */
70010680SMin.Xu@Sun.COM s32
e1000_read_mac_addr_82540(struct e1000_hw * hw)70110680SMin.Xu@Sun.COM e1000_read_mac_addr_82540(struct e1000_hw *hw)
70210680SMin.Xu@Sun.COM {
70310680SMin.Xu@Sun.COM s32 ret_val = E1000_SUCCESS;
70410680SMin.Xu@Sun.COM u16 offset, nvm_data, i;
70510680SMin.Xu@Sun.COM
70610680SMin.Xu@Sun.COM DEBUGFUNC("e1000_read_mac_addr");
70710680SMin.Xu@Sun.COM
70810680SMin.Xu@Sun.COM for (i = 0; i < ETH_ADDR_LEN; i += 2) {
70910680SMin.Xu@Sun.COM offset = i >> 1;
71010680SMin.Xu@Sun.COM ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
71110680SMin.Xu@Sun.COM if (ret_val) {
71210680SMin.Xu@Sun.COM DEBUGOUT("NVM Read Error\n");
71310680SMin.Xu@Sun.COM goto out;
71410680SMin.Xu@Sun.COM }
71510680SMin.Xu@Sun.COM hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
71610680SMin.Xu@Sun.COM hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
71710680SMin.Xu@Sun.COM }
71810680SMin.Xu@Sun.COM
71910680SMin.Xu@Sun.COM /* Flip last bit of mac address if we're on second port */
72010680SMin.Xu@Sun.COM if (hw->bus.func == E1000_FUNC_1)
72110680SMin.Xu@Sun.COM hw->mac.perm_addr[5] ^= 1;
72210680SMin.Xu@Sun.COM
72310680SMin.Xu@Sun.COM for (i = 0; i < ETH_ADDR_LEN; i++)
72410680SMin.Xu@Sun.COM hw->mac.addr[i] = hw->mac.perm_addr[i];
72510680SMin.Xu@Sun.COM
72610680SMin.Xu@Sun.COM out:
72710680SMin.Xu@Sun.COM return (ret_val);
72810680SMin.Xu@Sun.COM }
729