#include "e1000_api.h"
static s32 e1000_init_phy_params_82543(struct e1000_hw *hw);
static s32 e1000_init_nvm_params_82543(struct e1000_hw *hw);
static s32 e1000_init_mac_params_82543(struct e1000_hw *hw);
static s32 e1000_read_phy_reg_82543(struct e1000_hw *hw, u32 offset,
u16 *data);
static s32 e1000_write_phy_reg_82543(struct e1000_hw *hw, u32 offset,
u16 data);
static s32 e1000_phy_force_speed_duplex_82543(struct e1000_hw *hw);
static s32 e1000_phy_hw_reset_82543(struct e1000_hw *hw);
static s32 e1000_reset_hw_82543(struct e1000_hw *hw);
static s32 e1000_init_hw_82543(struct e1000_hw *hw);
static s32 e1000_setup_link_82543(struct e1000_hw *hw);
static s32 e1000_setup_copper_link_82543(struct e1000_hw *hw);
static s32 e1000_setup_fiber_link_82543(struct e1000_hw *hw);
static s32 e1000_check_for_copper_link_82543(struct e1000_hw *hw);
static s32 e1000_check_for_fiber_link_82543(struct e1000_hw *hw);
static s32 e1000_led_on_82543(struct e1000_hw *hw);
static s32 e1000_led_off_82543(struct e1000_hw *hw);
static void e1000_write_vfta_82543(struct e1000_hw *hw, u32 offset,
u32 value);
static void e1000_clear_hw_cntrs_82543(struct e1000_hw *hw);
static s32 e1000_config_mac_to_phy_82543(struct e1000_hw *hw);
static bool e1000_init_phy_disabled_82543(struct e1000_hw *hw);
static void e1000_lower_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl);
static s32 e1000_polarity_reversal_workaround_82543(struct e1000_hw *hw);
static void e1000_raise_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl);
static u16 e1000_shift_in_mdi_bits_82543(struct e1000_hw *hw);
static void e1000_shift_out_mdi_bits_82543(struct e1000_hw *hw, u32 data,
u16 count);
static bool e1000_tbi_compatibility_enabled_82543(struct e1000_hw *hw);
static void e1000_set_tbi_sbp_82543(struct e1000_hw *hw, bool state);
static s32 e1000_read_mac_addr_82543(struct e1000_hw *hw);
static s32 e1000_init_phy_params_82543(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_init_phy_params_82543");
if (hw->phy.media_type != e1000_media_type_copper) {
phy->type = e1000_phy_none;
goto out;
} else {
phy->ops.power_up = e1000_power_up_phy_copper;
phy->ops.power_down = e1000_power_down_phy_copper;
}
phy->addr = 1;
phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
phy->reset_delay_us = 10000;
phy->type = e1000_phy_m88;
phy->ops.check_polarity = e1000_check_polarity_m88;
phy->ops.commit = e1000_phy_sw_reset_generic;
phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_82543;
phy->ops.get_cable_length = e1000_get_cable_length_m88;
phy->ops.get_cfg_done = e1000_get_cfg_done_generic;
phy->ops.read_reg = (hw->mac.type == e1000_82543)
? e1000_read_phy_reg_82543
: e1000_read_phy_reg_m88;
phy->ops.reset = (hw->mac.type == e1000_82543)
? e1000_phy_hw_reset_82543
: e1000_phy_hw_reset_generic;
phy->ops.write_reg = (hw->mac.type == e1000_82543)
? e1000_write_phy_reg_82543
: e1000_write_phy_reg_m88;
phy->ops.get_info = e1000_get_phy_info_m88;
if (!e1000_init_phy_disabled_82543(hw)) {
ret_val = phy->ops.reset(hw);
if (ret_val) {
DEBUGOUT("Resetting PHY during init failed.\n");
goto out;
}
msec_delay(20);
}
ret_val = e1000_get_phy_id(hw);
if (ret_val)
goto out;
switch (hw->mac.type) {
case e1000_82543:
if (phy->id != M88E1000_E_PHY_ID) {
ret_val = -E1000_ERR_PHY;
goto out;
}
break;
case e1000_82544:
if (phy->id != M88E1000_I_PHY_ID) {
ret_val = -E1000_ERR_PHY;
goto out;
}
break;
default:
ret_val = -E1000_ERR_PHY;
goto out;
break;
}
out:
return ret_val;
}
static s32 e1000_init_nvm_params_82543(struct e1000_hw *hw)
{
struct e1000_nvm_info *nvm = &hw->nvm;
DEBUGFUNC("e1000_init_nvm_params_82543");
nvm->type = e1000_nvm_eeprom_microwire;
nvm->word_size = 64;
nvm->delay_usec = 50;
nvm->address_bits = 6;
nvm->opcode_bits = 3;
nvm->ops.read = e1000_read_nvm_microwire;
nvm->ops.update = e1000_update_nvm_checksum_generic;
nvm->ops.valid_led_default = e1000_valid_led_default_generic;
nvm->ops.validate = e1000_validate_nvm_checksum_generic;
nvm->ops.write = e1000_write_nvm_microwire;
return E1000_SUCCESS;
}
static s32 e1000_init_mac_params_82543(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
DEBUGFUNC("e1000_init_mac_params_82543");
switch (hw->device_id) {
case E1000_DEV_ID_82543GC_FIBER:
case E1000_DEV_ID_82544EI_FIBER:
hw->phy.media_type = e1000_media_type_fiber;
break;
default:
hw->phy.media_type = e1000_media_type_copper;
break;
}
mac->mta_reg_count = 128;
mac->rar_entry_count = E1000_RAR_ENTRIES;
mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci;
mac->ops.reset_hw = e1000_reset_hw_82543;
mac->ops.init_hw = e1000_init_hw_82543;
mac->ops.setup_link = e1000_setup_link_82543;
mac->ops.setup_physical_interface =
(hw->phy.media_type == e1000_media_type_copper)
? e1000_setup_copper_link_82543 : e1000_setup_fiber_link_82543;
mac->ops.check_for_link =
(hw->phy.media_type == e1000_media_type_copper)
? e1000_check_for_copper_link_82543
: e1000_check_for_fiber_link_82543;
mac->ops.get_link_up_info =
(hw->phy.media_type == e1000_media_type_copper)
? e1000_get_speed_and_duplex_copper_generic
: e1000_get_speed_and_duplex_fiber_serdes_generic;
mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
mac->ops.write_vfta = e1000_write_vfta_82543;
mac->ops.clear_vfta = e1000_clear_vfta_generic;
mac->ops.read_mac_addr = e1000_read_mac_addr_82543;
mac->ops.led_on = e1000_led_on_82543;
mac->ops.led_off = e1000_led_off_82543;
mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82543;
if ((hw->mac.type != e1000_82543) ||
(hw->phy.media_type == e1000_media_type_fiber))
e1000_set_tbi_compatibility_82543(hw, false);
return E1000_SUCCESS;
}
void e1000_init_function_pointers_82543(struct e1000_hw *hw)
{
DEBUGFUNC("e1000_init_function_pointers_82543");
hw->mac.ops.init_params = e1000_init_mac_params_82543;
hw->nvm.ops.init_params = e1000_init_nvm_params_82543;
hw->phy.ops.init_params = e1000_init_phy_params_82543;
}
static bool e1000_tbi_compatibility_enabled_82543(struct e1000_hw *hw)
{
struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
bool state = false;
DEBUGFUNC("e1000_tbi_compatibility_enabled_82543");
if (hw->mac.type != e1000_82543) {
DEBUGOUT("TBI compatibility workaround for 82543 only.\n");
goto out;
}
state = !!(dev_spec->tbi_compatibility & TBI_COMPAT_ENABLED);
out:
return state;
}
void e1000_set_tbi_compatibility_82543(struct e1000_hw *hw, bool state)
{
struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
DEBUGFUNC("e1000_set_tbi_compatibility_82543");
if (hw->mac.type != e1000_82543) {
DEBUGOUT("TBI compatibility workaround for 82543 only.\n");
goto out;
}
if (state)
dev_spec->tbi_compatibility |= TBI_COMPAT_ENABLED;
else
dev_spec->tbi_compatibility &= ~TBI_COMPAT_ENABLED;
out:
return;
}
bool e1000_tbi_sbp_enabled_82543(struct e1000_hw *hw)
{
struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
bool state = false;
DEBUGFUNC("e1000_tbi_sbp_enabled_82543");
if (hw->mac.type != e1000_82543) {
DEBUGOUT("TBI compatibility workaround for 82543 only.\n");
goto out;
}
state = !!(dev_spec->tbi_compatibility & TBI_SBP_ENABLED);
out:
return state;
}
static void e1000_set_tbi_sbp_82543(struct e1000_hw *hw, bool state)
{
struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
DEBUGFUNC("e1000_set_tbi_sbp_82543");
if (state && e1000_tbi_compatibility_enabled_82543(hw))
dev_spec->tbi_compatibility |= TBI_SBP_ENABLED;
else
dev_spec->tbi_compatibility &= ~TBI_SBP_ENABLED;
return;
}
static bool e1000_init_phy_disabled_82543(struct e1000_hw *hw)
{
struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
bool ret_val;
DEBUGFUNC("e1000_init_phy_disabled_82543");
if (hw->mac.type != e1000_82543) {
ret_val = false;
goto out;
}
ret_val = dev_spec->init_phy_disabled;
out:
return ret_val;
}
void e1000_tbi_adjust_stats_82543(struct e1000_hw *hw,
struct e1000_hw_stats *stats, u32 frame_len,
u8 *mac_addr, u32 max_frame_size)
{
if (!(e1000_tbi_sbp_enabled_82543(hw)))
goto out;
frame_len--;
stats->crcerrs--;
stats->gprc++;
stats->gorc += frame_len;
if ((mac_addr[0] == 0xff) && (mac_addr[1] == 0xff))
stats->bprc++;
else if (*mac_addr & 0x01)
stats->mprc++;
if ((frame_len == max_frame_size) && (stats->roc > 0))
stats->roc--;
if (frame_len == 64) {
stats->prc64++;
stats->prc127--;
} else if (frame_len == 127) {
stats->prc127++;
stats->prc255--;
} else if (frame_len == 255) {
stats->prc255++;
stats->prc511--;
} else if (frame_len == 511) {
stats->prc511++;
stats->prc1023--;
} else if (frame_len == 1023) {
stats->prc1023++;
stats->prc1522--;
} else if (frame_len == 1522) {
stats->prc1522++;
}
out:
return;
}
static s32 e1000_read_phy_reg_82543(struct e1000_hw *hw, u32 offset, u16 *data)
{
u32 mdic;
s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_read_phy_reg_82543");
if (offset > MAX_PHY_REG_ADDRESS) {
DEBUGOUT1("PHY Address %d is out of range\n", offset);
ret_val = -E1000_ERR_PARAM;
goto out;
}
e1000_shift_out_mdi_bits_82543(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
mdic = (offset | (hw->phy.addr << 5) |
(PHY_OP_READ << 10) | (PHY_SOF << 12));
e1000_shift_out_mdi_bits_82543(hw, mdic, 14);
*data = e1000_shift_in_mdi_bits_82543(hw);
out:
return ret_val;
}
static s32 e1000_write_phy_reg_82543(struct e1000_hw *hw, u32 offset, u16 data)
{
u32 mdic;
s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_write_phy_reg_82543");
if (offset > MAX_PHY_REG_ADDRESS) {
DEBUGOUT1("PHY Address %d is out of range\n", offset);
ret_val = -E1000_ERR_PARAM;
goto out;
}
e1000_shift_out_mdi_bits_82543(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
mdic = ((PHY_TURNAROUND) | (offset << 2) | (hw->phy.addr << 7) |
(PHY_OP_WRITE << 12) | (PHY_SOF << 14));
mdic <<= 16;
mdic |= (u32)data;
e1000_shift_out_mdi_bits_82543(hw, mdic, 32);
out:
return ret_val;
}
static void e1000_raise_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl)
{
E1000_WRITE_REG(hw, E1000_CTRL, (*ctrl | E1000_CTRL_MDC));
E1000_WRITE_FLUSH(hw);
usec_delay(10);
}
static void e1000_lower_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl)
{
E1000_WRITE_REG(hw, E1000_CTRL, (*ctrl & ~E1000_CTRL_MDC));
E1000_WRITE_FLUSH(hw);
usec_delay(10);
}
static void e1000_shift_out_mdi_bits_82543(struct e1000_hw *hw, u32 data,
u16 count)
{
u32 ctrl, mask;
mask = 0x01;
mask <<= (count - 1);
ctrl = E1000_READ_REG(hw, E1000_CTRL);
ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
while (mask) {
if (data & mask)
ctrl |= E1000_CTRL_MDIO;
else
ctrl &= ~E1000_CTRL_MDIO;
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
E1000_WRITE_FLUSH(hw);
usec_delay(10);
e1000_raise_mdi_clk_82543(hw, &ctrl);
e1000_lower_mdi_clk_82543(hw, &ctrl);
mask >>= 1;
}
}
static u16 e1000_shift_in_mdi_bits_82543(struct e1000_hw *hw)
{
u32 ctrl;
u16 data = 0;
u8 i;
ctrl = E1000_READ_REG(hw, E1000_CTRL);
ctrl &= ~E1000_CTRL_MDIO_DIR;
ctrl &= ~E1000_CTRL_MDIO;
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
E1000_WRITE_FLUSH(hw);
e1000_raise_mdi_clk_82543(hw, &ctrl);
e1000_lower_mdi_clk_82543(hw, &ctrl);
for (data = 0, i = 0; i < 16; i++) {
data <<= 1;
e1000_raise_mdi_clk_82543(hw, &ctrl);
ctrl = E1000_READ_REG(hw, E1000_CTRL);
if (ctrl & E1000_CTRL_MDIO)
data |= 1;
e1000_lower_mdi_clk_82543(hw, &ctrl);
}
e1000_raise_mdi_clk_82543(hw, &ctrl);
e1000_lower_mdi_clk_82543(hw, &ctrl);
return data;
}
static s32 e1000_phy_force_speed_duplex_82543(struct e1000_hw *hw)
{
s32 ret_val;
DEBUGFUNC("e1000_phy_force_speed_duplex_82543");
ret_val = e1000_phy_force_speed_duplex_m88(hw);
if (ret_val)
goto out;
if (!hw->mac.autoneg && (hw->mac.forced_speed_duplex &
E1000_ALL_10_SPEED))
ret_val = e1000_polarity_reversal_workaround_82543(hw);
out:
return ret_val;
}
static s32 e1000_polarity_reversal_workaround_82543(struct e1000_hw *hw)
{
s32 ret_val = E1000_SUCCESS;
u16 mii_status_reg;
u16 i;
bool link;
if (!(hw->phy.ops.write_reg))
goto out;
ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
if (ret_val)
goto out;
ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF);
if (ret_val)
goto out;
ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
if (ret_val)
goto out;
for (i = PHY_FORCE_TIME; i > 0; i--) {
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
if (ret_val)
goto out;
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
if (ret_val)
goto out;
if (!(mii_status_reg & ~MII_SR_LINK_STATUS))
break;
msec_delay_irq(100);
}
msec_delay_irq(1000);
ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
if (ret_val)
goto out;
msec_delay_irq(50);
ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFF0);
if (ret_val)
goto out;
msec_delay_irq(50);
ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFF00);
if (ret_val)
goto out;
msec_delay_irq(50);
ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x0000);
if (ret_val)
goto out;
ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
if (ret_val)
goto out;
ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_TIME, 100000, &link);
if (ret_val)
goto out;
out:
return ret_val;
}
static s32 e1000_phy_hw_reset_82543(struct e1000_hw *hw)
{
u32 ctrl_ext;
s32 ret_val;
DEBUGFUNC("e1000_phy_hw_reset_82543");
ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
E1000_WRITE_FLUSH(hw);
msec_delay(10);
ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
E1000_WRITE_FLUSH(hw);
usec_delay(150);
if (!(hw->phy.ops.get_cfg_done))
return E1000_SUCCESS;
ret_val = hw->phy.ops.get_cfg_done(hw);
return ret_val;
}
static s32 e1000_reset_hw_82543(struct e1000_hw *hw)
{
u32 ctrl;
s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_reset_hw_82543");
DEBUGOUT("Masking off all interrupts\n");
E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
E1000_WRITE_REG(hw, E1000_RCTL, 0);
E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
E1000_WRITE_FLUSH(hw);
e1000_set_tbi_sbp_82543(hw, false);
msec_delay(10);
ctrl = E1000_READ_REG(hw, E1000_CTRL);
DEBUGOUT("Issuing a global reset to 82543/82544 MAC\n");
if (hw->mac.type == e1000_82543) {
E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
} else {
E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
}
hw->nvm.ops.reload(hw);
msec_delay(2);
E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
E1000_READ_REG(hw, E1000_ICR);
return ret_val;
}
static s32 e1000_init_hw_82543(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
u32 ctrl;
s32 ret_val;
u16 i;
DEBUGFUNC("e1000_init_hw_82543");
E1000_WRITE_REG(hw, E1000_VET, 0);
mac->ops.clear_vfta(hw);
e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
DEBUGOUT("Zeroing the MTA\n");
for (i = 0; i < mac->mta_reg_count; i++) {
E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
E1000_WRITE_FLUSH(hw);
}
if (hw->mac.type == e1000_82543 && dev_spec->dma_fairness) {
ctrl = E1000_READ_REG(hw, E1000_CTRL);
E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PRIOR);
}
e1000_pcix_mmrbc_workaround_generic(hw);
ret_val = mac->ops.setup_link(hw);
e1000_clear_hw_cntrs_82543(hw);
return ret_val;
}
static s32 e1000_setup_link_82543(struct e1000_hw *hw)
{
u32 ctrl_ext;
s32 ret_val;
u16 data;
DEBUGFUNC("e1000_setup_link_82543");
if (hw->mac.type == e1000_82543) {
ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &data);
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
ret_val = -E1000_ERR_NVM;
goto out;
}
ctrl_ext = ((data & NVM_WORD0F_SWPDIO_EXT_MASK) <<
NVM_SWDPIO_EXT_SHIFT);
E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
}
ret_val = e1000_setup_link_generic(hw);
out:
return ret_val;
}
static s32 e1000_setup_copper_link_82543(struct e1000_hw *hw)
{
u32 ctrl;
s32 ret_val;
bool link = true;
DEBUGFUNC("e1000_setup_copper_link_82543");
ctrl = E1000_READ_REG(hw, E1000_CTRL) | E1000_CTRL_SLU;
if (hw->mac.type == e1000_82543) {
ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
ret_val = hw->phy.ops.reset(hw);
if (ret_val)
goto out;
} else {
ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
}
ret_val = e1000_copper_link_setup_m88(hw);
if (ret_val)
goto out;
if (hw->mac.autoneg) {
ret_val = e1000_copper_link_autoneg(hw);
if (ret_val)
goto out;
} else {
DEBUGOUT("Forcing Speed and Duplex\n");
ret_val = e1000_phy_force_speed_duplex_82543(hw);
if (ret_val) {
DEBUGOUT("Error Forcing Speed and Duplex\n");
goto out;
}
}
ret_val = e1000_phy_has_link_generic(hw, COPPER_LINK_UP_LIMIT, 10,
&link);
if (ret_val)
goto out;
if (link) {
DEBUGOUT("Valid link established!!!\n");
if (hw->mac.type == e1000_82544) {
hw->mac.ops.config_collision_dist(hw);
} else {
ret_val = e1000_config_mac_to_phy_82543(hw);
if (ret_val)
goto out;
}
ret_val = e1000_config_fc_after_link_up_generic(hw);
} else {
DEBUGOUT("Unable to establish link!!!\n");
}
out:
return ret_val;
}
static s32 e1000_setup_fiber_link_82543(struct e1000_hw *hw)
{
u32 ctrl;
s32 ret_val;
DEBUGFUNC("e1000_setup_fiber_link_82543");
ctrl = E1000_READ_REG(hw, E1000_CTRL);
ctrl &= ~E1000_CTRL_LRST;
hw->mac.ops.config_collision_dist(hw);
ret_val = e1000_commit_fc_settings_generic(hw);
if (ret_val)
goto out;
DEBUGOUT("Auto-negotiation enabled\n");
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
E1000_WRITE_FLUSH(hw);
msec_delay(1);
if (!(E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1))
ret_val = e1000_poll_fiber_serdes_link_generic(hw);
else
DEBUGOUT("No signal detected\n");
out:
return ret_val;
}
static s32 e1000_check_for_copper_link_82543(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
u32 icr, rctl;
s32 ret_val;
u16 speed, duplex;
bool link;
DEBUGFUNC("e1000_check_for_copper_link_82543");
if (!mac->get_link_status) {
ret_val = E1000_SUCCESS;
goto out;
}
ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
if (ret_val)
goto out;
if (!link)
goto out;
mac->get_link_status = false;
e1000_check_downshift_generic(hw);
if (!mac->autoneg) {
if (mac->forced_speed_duplex & E1000_ALL_10_SPEED) {
E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
ret_val = e1000_polarity_reversal_workaround_82543(hw);
icr = E1000_READ_REG(hw, E1000_ICR);
E1000_WRITE_REG(hw, E1000_ICS, (icr & ~E1000_ICS_LSC));
E1000_WRITE_REG(hw, E1000_IMS, IMS_ENABLE_MASK);
}
ret_val = -E1000_ERR_CONFIG;
goto out;
}
if (mac->type == e1000_82544)
hw->mac.ops.config_collision_dist(hw);
else {
ret_val = e1000_config_mac_to_phy_82543(hw);
if (ret_val) {
DEBUGOUT("Error configuring MAC to PHY settings\n");
goto out;
}
}
ret_val = e1000_config_fc_after_link_up_generic(hw);
if (ret_val)
DEBUGOUT("Error configuring flow control\n");
if (e1000_tbi_compatibility_enabled_82543(hw)) {
ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
if (ret_val) {
DEBUGOUT("Error getting link speed and duplex\n");
return ret_val;
}
if (speed != SPEED_1000) {
if (e1000_tbi_sbp_enabled_82543(hw)) {
e1000_set_tbi_sbp_82543(hw, false);
rctl = E1000_READ_REG(hw, E1000_RCTL);
rctl &= ~E1000_RCTL_SBP;
E1000_WRITE_REG(hw, E1000_RCTL, rctl);
}
} else {
if (!e1000_tbi_sbp_enabled_82543(hw)) {
e1000_set_tbi_sbp_82543(hw, true);
rctl = E1000_READ_REG(hw, E1000_RCTL);
rctl |= E1000_RCTL_SBP;
E1000_WRITE_REG(hw, E1000_RCTL, rctl);
}
}
}
out:
return ret_val;
}
static s32 e1000_check_for_fiber_link_82543(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
u32 rxcw, ctrl, status;
s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_check_for_fiber_link_82543");
ctrl = E1000_READ_REG(hw, E1000_CTRL);
status = E1000_READ_REG(hw, E1000_STATUS);
rxcw = E1000_READ_REG(hw, E1000_RXCW);
if ((!(ctrl & E1000_CTRL_SWDPIN1)) &&
(!(status & E1000_STATUS_LU)) &&
(!(rxcw & E1000_RXCW_C))) {
if (!mac->autoneg_failed) {
mac->autoneg_failed = true;
ret_val = 0;
goto out;
}
DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
ctrl = E1000_READ_REG(hw, E1000_CTRL);
ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
ret_val = e1000_config_fc_after_link_up_generic(hw);
if (ret_val) {
DEBUGOUT("Error configuring flow control\n");
goto out;
}
} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
mac->serdes_has_link = true;
}
out:
return ret_val;
}
static s32 e1000_config_mac_to_phy_82543(struct e1000_hw *hw)
{
u32 ctrl;
s32 ret_val = E1000_SUCCESS;
u16 phy_data;
DEBUGFUNC("e1000_config_mac_to_phy_82543");
if (!(hw->phy.ops.read_reg))
goto out;
ctrl = E1000_READ_REG(hw, E1000_CTRL);
ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS);
ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
if (ret_val)
goto out;
ctrl &= ~E1000_CTRL_FD;
if (phy_data & M88E1000_PSSR_DPLX)
ctrl |= E1000_CTRL_FD;
hw->mac.ops.config_collision_dist(hw);
if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
ctrl |= E1000_CTRL_SPD_1000;
else if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
ctrl |= E1000_CTRL_SPD_100;
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
out:
return ret_val;
}
static void e1000_write_vfta_82543(struct e1000_hw *hw, u32 offset, u32 value)
{
u32 temp;
DEBUGFUNC("e1000_write_vfta_82543");
if ((hw->mac.type == e1000_82544) && (offset & 1)) {
temp = E1000_READ_REG_ARRAY(hw, E1000_VFTA, offset - 1);
E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
E1000_WRITE_FLUSH(hw);
E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset - 1, temp);
E1000_WRITE_FLUSH(hw);
} else {
e1000_write_vfta_generic(hw, offset, value);
}
}
static s32 e1000_led_on_82543(struct e1000_hw *hw)
{
u32 ctrl = E1000_READ_REG(hw, E1000_CTRL);
DEBUGFUNC("e1000_led_on_82543");
if (hw->mac.type == e1000_82544 &&
hw->phy.media_type == e1000_media_type_copper) {
ctrl &= ~E1000_CTRL_SWDPIN0;
ctrl |= E1000_CTRL_SWDPIO0;
} else {
ctrl |= E1000_CTRL_SWDPIN0;
ctrl |= E1000_CTRL_SWDPIO0;
}
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
return E1000_SUCCESS;
}
static s32 e1000_led_off_82543(struct e1000_hw *hw)
{
u32 ctrl = E1000_READ_REG(hw, E1000_CTRL);
DEBUGFUNC("e1000_led_off_82543");
if (hw->mac.type == e1000_82544 &&
hw->phy.media_type == e1000_media_type_copper) {
ctrl |= E1000_CTRL_SWDPIN0;
ctrl |= E1000_CTRL_SWDPIO0;
} else {
ctrl &= ~E1000_CTRL_SWDPIN0;
ctrl |= E1000_CTRL_SWDPIO0;
}
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
return E1000_SUCCESS;
}
static void e1000_clear_hw_cntrs_82543(struct e1000_hw *hw)
{
DEBUGFUNC("e1000_clear_hw_cntrs_82543");
e1000_clear_hw_cntrs_base_generic(hw);
E1000_READ_REG(hw, E1000_PRC64);
E1000_READ_REG(hw, E1000_PRC127);
E1000_READ_REG(hw, E1000_PRC255);
E1000_READ_REG(hw, E1000_PRC511);
E1000_READ_REG(hw, E1000_PRC1023);
E1000_READ_REG(hw, E1000_PRC1522);
E1000_READ_REG(hw, E1000_PTC64);
E1000_READ_REG(hw, E1000_PTC127);
E1000_READ_REG(hw, E1000_PTC255);
E1000_READ_REG(hw, E1000_PTC511);
E1000_READ_REG(hw, E1000_PTC1023);
E1000_READ_REG(hw, E1000_PTC1522);
E1000_READ_REG(hw, E1000_ALGNERRC);
E1000_READ_REG(hw, E1000_RXERRC);
E1000_READ_REG(hw, E1000_TNCRS);
E1000_READ_REG(hw, E1000_CEXTERR);
E1000_READ_REG(hw, E1000_TSCTC);
E1000_READ_REG(hw, E1000_TSCTFC);
}
s32 e1000_read_mac_addr_82543(struct e1000_hw *hw)
{
s32 ret_val = E1000_SUCCESS;
u16 offset, nvm_data, i;
DEBUGFUNC("e1000_read_mac_addr");
for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
offset = i >> 1;
ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
goto out;
}
hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
}
if (hw->bus.func == E1000_FUNC_1)
hw->mac.perm_addr[5] ^= 1;
for (i = 0; i < ETHER_ADDR_LEN; i++)
hw->mac.addr[i] = hw->mac.perm_addr[i];
out:
return ret_val;
}