#include "e1000_api.h"
#define E1000_FIFO_MULTIPLIER 0x80
#define E1000_FIFO_HDR_SIZE 0x10
#define E1000_FIFO_GRANULARITY 0x10
#define E1000_FIFO_PAD_82547 0x3E0
#define E1000_ERR_FIFO_WRAP 8
#define DSP_RESET_ENABLE 0x0
#define DSP_RESET_DISABLE 0x2
#define E1000_MAX_DSP_RESETS 10
#define E1000_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1))
bool
e1000_ttl_workaround_enabled_82541(struct e1000_hw *hw)
{
struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
bool state = false;
DEBUGFUNC("e1000_ttl_workaround_enabled_82541");
if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
goto out;
state = dev_spec->ttl_workaround;
out:
return (state);
}
s32
e1000_fifo_workaround_82547(struct e1000_hw *hw, u16 length)
{
struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
u32 tctl;
s32 ret_val = E1000_SUCCESS;
u16 fifo_pkt_len;
DEBUGFUNC("e1000_fifo_workaround_82547");
if (hw->mac.type != e1000_82547)
goto out;
fifo_pkt_len = E1000_ROUNDUP(length + E1000_FIFO_HDR_SIZE,
E1000_FIFO_GRANULARITY);
if (fifo_pkt_len <= (E1000_FIFO_PAD_82547 + E1000_FIFO_HDR_SIZE))
goto out;
if ((dev_spec->tx_fifo_head + fifo_pkt_len) <
(dev_spec->tx_fifo_size + E1000_FIFO_PAD_82547))
goto out;
if (E1000_READ_REG(hw, E1000_TDT(0)) !=
E1000_READ_REG(hw, E1000_TDH(0))) {
ret_val = -E1000_ERR_FIFO_WRAP;
goto out;
}
if (E1000_READ_REG(hw, E1000_TDFT) != E1000_READ_REG(hw, E1000_TDFH)) {
ret_val = -E1000_ERR_FIFO_WRAP;
goto out;
}
if (E1000_READ_REG(hw, E1000_TDFTS) !=
E1000_READ_REG(hw, E1000_TDFHS)) {
ret_val = -E1000_ERR_FIFO_WRAP;
goto out;
}
tctl = E1000_READ_REG(hw, E1000_TCTL);
E1000_WRITE_REG(hw, E1000_TCTL, tctl & ~E1000_TCTL_EN);
E1000_WRITE_REG(hw, E1000_TDFT, dev_spec->tx_fifo_start);
E1000_WRITE_REG(hw, E1000_TDFH, dev_spec->tx_fifo_start);
E1000_WRITE_REG(hw, E1000_TDFTS, dev_spec->tx_fifo_start);
E1000_WRITE_REG(hw, E1000_TDFHS, dev_spec->tx_fifo_start);
E1000_WRITE_REG(hw, E1000_TCTL, tctl);
E1000_WRITE_FLUSH(hw);
dev_spec->tx_fifo_head = 0;
out:
return (ret_val);
}
void
e1000_update_tx_fifo_head_82547(struct e1000_hw *hw, u32 length)
{
struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
DEBUGFUNC("e1000_update_tx_fifo_head_82547");
if (hw->mac.type != e1000_82547)
return;
dev_spec->tx_fifo_head += E1000_ROUNDUP(length + E1000_FIFO_HDR_SIZE,
E1000_FIFO_GRANULARITY);
if (dev_spec->tx_fifo_head > dev_spec->tx_fifo_size)
dev_spec->tx_fifo_head -= dev_spec->tx_fifo_size;
}
void
e1000_set_ttl_workaround_state_82541(struct e1000_hw *hw, bool state)
{
struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
DEBUGFUNC("e1000_set_ttl_workaround_state_82541");
if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
return;
dev_spec->ttl_workaround = state;
}
s32
e1000_igp_ttl_workaround_82547(struct e1000_hw *hw)
{
struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
s32 ret_val = E1000_SUCCESS;
u16 phy_data = 0;
u16 dsp_value = DSP_RESET_ENABLE;
bool link;
DEBUGFUNC("e1000_igp_ttl_workaround_82547");
if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
goto out;
if (!(e1000_ttl_workaround_enabled_82541(hw)))
goto out;
ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
if (ret_val)
goto out;
if (link) {
if (dev_spec->dsp_reset_counter) {
dev_spec->dsp_reset_counter = 0;
dsp_value = DSP_RESET_ENABLE;
} else {
ret_val = E1000_SUCCESS;
goto out;
}
} else {
if (dev_spec->dsp_reset_counter == 0) {
ret_val = hw->phy.ops.read_reg(hw,
PHY_AUTONEG_EXP,
&phy_data);
if (ret_val)
goto out;
if (phy_data & NWAY_ER_PAR_DETECT_FAULT) {
dev_spec->dsp_reset_counter++;
} else {
ret_val = E1000_SUCCESS;
goto out;
}
}
if (dev_spec->dsp_reset_counter > E1000_MAX_DSP_RESETS) {
dev_spec->dsp_reset_counter = 0;
dsp_value = DSP_RESET_ENABLE;
} else {
if (dev_spec->dsp_reset_counter) {
dsp_value = (dev_spec->dsp_reset_counter & 1)
? DSP_RESET_DISABLE
: DSP_RESET_ENABLE;
dev_spec->dsp_reset_counter++;
}
}
}
ret_val =
hw->phy.ops.write_reg(hw, IGP01E1000_PHY_DSP_RESET, dsp_value);
out:
return (ret_val);
}