#include "e1000_api.h"
static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw);
static void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
static void e1000_config_collision_dist_generic(struct e1000_hw *hw);
void e1000_init_mac_ops_generic(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
DEBUGFUNC("e1000_init_mac_ops_generic");
mac->ops.init_params = e1000_null_ops_generic;
mac->ops.init_hw = e1000_null_ops_generic;
mac->ops.reset_hw = e1000_null_ops_generic;
mac->ops.setup_physical_interface = e1000_null_ops_generic;
mac->ops.get_bus_info = e1000_null_ops_generic;
mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pcie;
mac->ops.read_mac_addr = e1000_read_mac_addr_generic;
mac->ops.config_collision_dist = e1000_config_collision_dist_generic;
mac->ops.clear_hw_cntrs = e1000_null_mac_generic;
mac->ops.cleanup_led = e1000_null_ops_generic;
mac->ops.setup_led = e1000_null_ops_generic;
mac->ops.blink_led = e1000_null_ops_generic;
mac->ops.led_on = e1000_null_ops_generic;
mac->ops.led_off = e1000_null_ops_generic;
mac->ops.setup_link = e1000_null_ops_generic;
mac->ops.get_link_up_info = e1000_null_link_info;
mac->ops.check_for_link = e1000_null_ops_generic;
mac->ops.set_obff_timer = e1000_null_set_obff_timer;
mac->ops.check_mng_mode = e1000_null_mng_mode;
mac->ops.update_mc_addr_list = e1000_null_update_mc;
mac->ops.clear_vfta = e1000_null_mac_generic;
mac->ops.write_vfta = e1000_null_write_vfta;
mac->ops.rar_set = e1000_rar_set_generic;
mac->ops.validate_mdi_setting = e1000_validate_mdi_setting_generic;
}
s32 e1000_null_ops_generic(struct e1000_hw E1000_UNUSEDARG *hw)
{
DEBUGFUNC("e1000_null_ops_generic");
return E1000_SUCCESS;
}
void e1000_null_mac_generic(struct e1000_hw E1000_UNUSEDARG *hw)
{
DEBUGFUNC("e1000_null_mac_generic");
return;
}
s32 e1000_null_link_info(struct e1000_hw E1000_UNUSEDARG *hw,
u16 E1000_UNUSEDARG *s, u16 E1000_UNUSEDARG *d)
{
DEBUGFUNC("e1000_null_link_info");
return E1000_SUCCESS;
}
bool e1000_null_mng_mode(struct e1000_hw E1000_UNUSEDARG *hw)
{
DEBUGFUNC("e1000_null_mng_mode");
return false;
}
void e1000_null_update_mc(struct e1000_hw E1000_UNUSEDARG *hw,
u8 E1000_UNUSEDARG *h, u32 E1000_UNUSEDARG a)
{
DEBUGFUNC("e1000_null_update_mc");
return;
}
void e1000_null_write_vfta(struct e1000_hw E1000_UNUSEDARG *hw,
u32 E1000_UNUSEDARG a, u32 E1000_UNUSEDARG b)
{
DEBUGFUNC("e1000_null_write_vfta");
return;
}
int e1000_null_rar_set(struct e1000_hw E1000_UNUSEDARG *hw,
u8 E1000_UNUSEDARG *h, u32 E1000_UNUSEDARG a)
{
DEBUGFUNC("e1000_null_rar_set");
return E1000_SUCCESS;
}
s32 e1000_null_set_obff_timer(struct e1000_hw E1000_UNUSEDARG *hw,
u32 E1000_UNUSEDARG a)
{
DEBUGFUNC("e1000_null_set_obff_timer");
return E1000_SUCCESS;
}
s32 e1000_get_bus_info_pci_generic(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
struct e1000_bus_info *bus = &hw->bus;
u32 status = E1000_READ_REG(hw, E1000_STATUS);
s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_get_bus_info_pci_generic");
bus->type = (status & E1000_STATUS_PCIX_MODE)
? e1000_bus_type_pcix
: e1000_bus_type_pci;
if (bus->type == e1000_bus_type_pci) {
bus->speed = (status & E1000_STATUS_PCI66)
? e1000_bus_speed_66
: e1000_bus_speed_33;
} else {
switch (status & E1000_STATUS_PCIX_SPEED) {
case E1000_STATUS_PCIX_SPEED_66:
bus->speed = e1000_bus_speed_66;
break;
case E1000_STATUS_PCIX_SPEED_100:
bus->speed = e1000_bus_speed_100;
break;
case E1000_STATUS_PCIX_SPEED_133:
bus->speed = e1000_bus_speed_133;
break;
default:
bus->speed = e1000_bus_speed_reserved;
break;
}
}
bus->width = (status & E1000_STATUS_BUS64)
? e1000_bus_width_64
: e1000_bus_width_32;
mac->ops.set_lan_id(hw);
return ret_val;
}
s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
struct e1000_bus_info *bus = &hw->bus;
s32 ret_val;
u16 pcie_link_status;
DEBUGFUNC("e1000_get_bus_info_pcie_generic");
bus->type = e1000_bus_type_pci_express;
ret_val = e1000_read_pcie_cap_reg(hw, PCIE_LINK_STATUS,
&pcie_link_status);
if (ret_val) {
bus->width = e1000_bus_width_unknown;
bus->speed = e1000_bus_speed_unknown;
} else {
switch (pcie_link_status & PCIE_LINK_SPEED_MASK) {
case PCIE_LINK_SPEED_2500:
bus->speed = e1000_bus_speed_2500;
break;
case PCIE_LINK_SPEED_5000:
bus->speed = e1000_bus_speed_5000;
break;
default:
bus->speed = e1000_bus_speed_unknown;
break;
}
bus->width = (enum e1000_bus_width)((pcie_link_status &
PCIE_LINK_WIDTH_MASK) >> PCIE_LINK_WIDTH_SHIFT);
}
mac->ops.set_lan_id(hw);
return E1000_SUCCESS;
}
static void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw)
{
struct e1000_bus_info *bus = &hw->bus;
u32 reg;
reg = E1000_READ_REG(hw, E1000_STATUS);
bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
}
void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw)
{
struct e1000_bus_info *bus = &hw->bus;
u16 pci_header_type;
u32 status;
e1000_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type);
if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
status = E1000_READ_REG(hw, E1000_STATUS);
bus->func = (status & E1000_STATUS_FUNC_MASK)
>> E1000_STATUS_FUNC_SHIFT;
} else {
bus->func = 0;
}
}
void e1000_set_lan_id_single_port(struct e1000_hw *hw)
{
struct e1000_bus_info *bus = &hw->bus;
bus->func = 0;
}
void e1000_clear_vfta_generic(struct e1000_hw *hw)
{
u32 offset;
DEBUGFUNC("e1000_clear_vfta_generic");
for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0);
E1000_WRITE_FLUSH(hw);
}
}
void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value)
{
DEBUGFUNC("e1000_write_vfta_generic");
E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
E1000_WRITE_FLUSH(hw);
}
void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count)
{
u32 i;
u8 mac_addr[ETHER_ADDR_LEN] = {0};
DEBUGFUNC("e1000_init_rx_addrs_generic");
DEBUGOUT("Programming MAC Address into RAR[0]\n");
hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count-1);
for (i = 1; i < rar_count; i++)
hw->mac.ops.rar_set(hw, mac_addr, i);
}
s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
{
u32 i;
s32 ret_val;
u16 offset, nvm_alt_mac_addr_offset, nvm_data;
u8 alt_mac_addr[ETHER_ADDR_LEN];
DEBUGFUNC("e1000_check_alt_mac_addr_generic");
ret_val = hw->nvm.ops.read(hw, NVM_COMPAT, 1, &nvm_data);
if (ret_val)
return ret_val;
if ((hw->mac.type < e1000_82571) || (hw->mac.type == e1000_82573))
return E1000_SUCCESS;
if (hw->mac.type >= e1000_82580)
return E1000_SUCCESS;
ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1,
&nvm_alt_mac_addr_offset);
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
return ret_val;
}
if ((nvm_alt_mac_addr_offset == 0xFFFF) ||
(nvm_alt_mac_addr_offset == 0x0000))
return E1000_SUCCESS;
if (hw->bus.func == E1000_FUNC_1)
nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
if (hw->bus.func == E1000_FUNC_2)
nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN2;
if (hw->bus.func == E1000_FUNC_3)
nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN3;
for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
offset = nvm_alt_mac_addr_offset + (i >> 1);
ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
return ret_val;
}
alt_mac_addr[i] = (u8)(nvm_data & 0xFF);
alt_mac_addr[i + 1] = (u8)(nvm_data >> 8);
}
if (alt_mac_addr[0] & 0x01) {
DEBUGOUT("Ignoring Alternate Mac Address with MC bit set\n");
return E1000_SUCCESS;
}
hw->mac.ops.rar_set(hw, alt_mac_addr, 0);
return E1000_SUCCESS;
}
int e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index)
{
u32 rar_low, rar_high;
DEBUGFUNC("e1000_rar_set_generic");
rar_low = ((u32) addr[0] | ((u32) addr[1] << 8) |
((u32) addr[2] << 16) | ((u32) addr[3] << 24));
rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
if (rar_low || rar_high)
rar_high |= E1000_RAH_AV;
E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
E1000_WRITE_FLUSH(hw);
E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
E1000_WRITE_FLUSH(hw);
return E1000_SUCCESS;
}
u32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr)
{
u32 hash_value, hash_mask;
u8 bit_shift = 0;
DEBUGFUNC("e1000_hash_mc_addr_generic");
hash_mask = (hw->mac.mta_reg_count * 32) - 1;
while (hash_mask >> bit_shift != 0xFF)
bit_shift++;
switch (hw->mac.mc_filter_type) {
default:
case 0:
break;
case 1:
bit_shift += 1;
break;
case 2:
bit_shift += 2;
break;
case 3:
bit_shift += 4;
break;
}
hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
(((u16) mc_addr[5]) << bit_shift)));
return hash_value;
}
void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
u8 *mc_addr_list, u32 mc_addr_count)
{
u32 hash_value, hash_bit, hash_reg;
int i;
DEBUGFUNC("e1000_update_mc_addr_list_generic");
memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
for (i = 0; (u32) i < mc_addr_count; i++) {
hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list);
hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
hash_bit = hash_value & 0x1F;
hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
mc_addr_list += (ETHER_ADDR_LEN);
}
for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
E1000_WRITE_FLUSH(hw);
}
void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw)
{
u16 cmd_mmrbc;
u16 pcix_cmd;
u16 pcix_stat_hi_word;
u16 stat_mmrbc;
DEBUGFUNC("e1000_pcix_mmrbc_workaround_generic");
if (hw->bus.type != e1000_bus_type_pcix)
return;
e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd);
e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, &pcix_stat_hi_word);
cmd_mmrbc = (pcix_cmd & PCIX_COMMAND_MMRBC_MASK) >>
PCIX_COMMAND_MMRBC_SHIFT;
stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
PCIX_STATUS_HI_MMRBC_SHIFT;
if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
if (cmd_mmrbc > stat_mmrbc) {
pcix_cmd &= ~PCIX_COMMAND_MMRBC_MASK;
pcix_cmd |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd);
}
}
void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw)
{
DEBUGFUNC("e1000_clear_hw_cntrs_base_generic");
E1000_READ_REG(hw, E1000_CRCERRS);
E1000_READ_REG(hw, E1000_SYMERRS);
E1000_READ_REG(hw, E1000_MPC);
E1000_READ_REG(hw, E1000_SCC);
E1000_READ_REG(hw, E1000_ECOL);
E1000_READ_REG(hw, E1000_MCC);
E1000_READ_REG(hw, E1000_LATECOL);
E1000_READ_REG(hw, E1000_COLC);
E1000_READ_REG(hw, E1000_DC);
E1000_READ_REG(hw, E1000_SEC);
E1000_READ_REG(hw, E1000_RLEC);
E1000_READ_REG(hw, E1000_XONRXC);
E1000_READ_REG(hw, E1000_XONTXC);
E1000_READ_REG(hw, E1000_XOFFRXC);
E1000_READ_REG(hw, E1000_XOFFTXC);
E1000_READ_REG(hw, E1000_FCRUC);
E1000_READ_REG(hw, E1000_GPRC);
E1000_READ_REG(hw, E1000_BPRC);
E1000_READ_REG(hw, E1000_MPRC);
E1000_READ_REG(hw, E1000_GPTC);
E1000_READ_REG(hw, E1000_GORCL);
E1000_READ_REG(hw, E1000_GORCH);
E1000_READ_REG(hw, E1000_GOTCL);
E1000_READ_REG(hw, E1000_GOTCH);
E1000_READ_REG(hw, E1000_RNBC);
E1000_READ_REG(hw, E1000_RUC);
E1000_READ_REG(hw, E1000_RFC);
E1000_READ_REG(hw, E1000_ROC);
E1000_READ_REG(hw, E1000_RJC);
E1000_READ_REG(hw, E1000_TORL);
E1000_READ_REG(hw, E1000_TORH);
E1000_READ_REG(hw, E1000_TOTL);
E1000_READ_REG(hw, E1000_TOTH);
E1000_READ_REG(hw, E1000_TPR);
E1000_READ_REG(hw, E1000_TPT);
E1000_READ_REG(hw, E1000_MPTC);
E1000_READ_REG(hw, E1000_BPTC);
}
s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
s32 ret_val;
bool link;
DEBUGFUNC("e1000_check_for_copper_link");
if (!mac->get_link_status)
return E1000_SUCCESS;
ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
if (ret_val)
return ret_val;
if (!link)
return E1000_SUCCESS;
mac->get_link_status = false;
e1000_check_downshift_generic(hw);
if (!mac->autoneg)
return -E1000_ERR_CONFIG;
mac->ops.config_collision_dist(hw);
ret_val = e1000_config_fc_after_link_up_generic(hw);
if (ret_val)
DEBUGOUT("Error configuring flow control\n");
return ret_val;
}
s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
u32 rxcw;
u32 ctrl;
u32 status;
s32 ret_val;
DEBUGFUNC("e1000_check_for_fiber_link_generic");
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;
return E1000_SUCCESS;
}
DEBUGOUT("NOT Rx'ing /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");
return ret_val;
}
} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
DEBUGOUT("Rx'ing /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;
}
return E1000_SUCCESS;
}
s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
u32 rxcw;
u32 ctrl;
u32 status;
s32 ret_val;
DEBUGFUNC("e1000_check_for_serdes_link_generic");
ctrl = E1000_READ_REG(hw, E1000_CTRL);
status = E1000_READ_REG(hw, E1000_STATUS);
rxcw = E1000_READ_REG(hw, E1000_RXCW);
if (!(status & E1000_STATUS_LU) && !(rxcw & E1000_RXCW_C)) {
if (!mac->autoneg_failed) {
mac->autoneg_failed = true;
return E1000_SUCCESS;
}
DEBUGOUT("NOT Rx'ing /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");
return ret_val;
}
} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
DEBUGOUT("Rx'ing /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;
} else if (!(E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW))) {
usec_delay(10);
rxcw = E1000_READ_REG(hw, E1000_RXCW);
if (rxcw & E1000_RXCW_SYNCH) {
if (!(rxcw & E1000_RXCW_IV)) {
mac->serdes_has_link = true;
DEBUGOUT("SERDES: Link up - forced.\n");
}
} else {
mac->serdes_has_link = false;
DEBUGOUT("SERDES: Link down - force failed.\n");
}
}
if (E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW)) {
status = E1000_READ_REG(hw, E1000_STATUS);
if (status & E1000_STATUS_LU) {
usec_delay(10);
rxcw = E1000_READ_REG(hw, E1000_RXCW);
if (rxcw & E1000_RXCW_SYNCH) {
if (!(rxcw & E1000_RXCW_IV)) {
mac->serdes_has_link = true;
DEBUGOUT("SERDES: Link up - autoneg completed successfully.\n");
} else {
mac->serdes_has_link = false;
DEBUGOUT("SERDES: Link down - invalid codewords detected in autoneg.\n");
}
} else {
mac->serdes_has_link = false;
DEBUGOUT("SERDES: Link down - no sync.\n");
}
} else {
mac->serdes_has_link = false;
DEBUGOUT("SERDES: Link down - autoneg failed\n");
}
}
return E1000_SUCCESS;
}
s32 e1000_set_default_fc_generic(struct e1000_hw *hw)
{
s32 ret_val;
u16 nvm_data;
u16 nvm_offset = 0;
DEBUGFUNC("e1000_set_default_fc_generic");
if (hw->mac.type == e1000_i350) {
nvm_offset = NVM_82580_LAN_FUNC_OFFSET(hw->bus.func);
ret_val = hw->nvm.ops.read(hw,
NVM_INIT_CONTROL2_REG +
nvm_offset,
1, &nvm_data);
} else {
ret_val = hw->nvm.ops.read(hw,
NVM_INIT_CONTROL2_REG,
1, &nvm_data);
}
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
return ret_val;
}
if (!(nvm_data & NVM_WORD0F_PAUSE_MASK))
hw->fc.requested_mode = e1000_fc_none;
else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
NVM_WORD0F_ASM_DIR)
hw->fc.requested_mode = e1000_fc_tx_pause;
else
hw->fc.requested_mode = e1000_fc_full;
return E1000_SUCCESS;
}
s32 e1000_setup_link_generic(struct e1000_hw *hw)
{
s32 ret_val;
DEBUGFUNC("e1000_setup_link_generic");
if (hw->phy.ops.check_reset_block && hw->phy.ops.check_reset_block(hw))
return E1000_SUCCESS;
if (hw->fc.requested_mode == e1000_fc_default) {
ret_val = e1000_set_default_fc_generic(hw);
if (ret_val)
return ret_val;
}
hw->fc.current_mode = hw->fc.requested_mode;
DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
hw->fc.current_mode);
ret_val = hw->mac.ops.setup_physical_interface(hw);
if (ret_val)
return ret_val;
DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE);
E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
return e1000_set_fc_watermarks_generic(hw);
}
s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
u32 txcw;
DEBUGFUNC("e1000_commit_fc_settings_generic");
switch (hw->fc.current_mode) {
case e1000_fc_none:
txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
break;
case e1000_fc_rx_pause:
txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
break;
case e1000_fc_tx_pause:
txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
break;
case e1000_fc_full:
txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
break;
default:
DEBUGOUT("Flow control param set incorrectly\n");
return -E1000_ERR_CONFIG;
break;
}
E1000_WRITE_REG(hw, E1000_TXCW, txcw);
mac->txcw = txcw;
return E1000_SUCCESS;
}
s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
u32 i, status;
s32 ret_val;
DEBUGFUNC("e1000_poll_fiber_serdes_link_generic");
for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
msec_delay(10);
status = E1000_READ_REG(hw, E1000_STATUS);
if (status & E1000_STATUS_LU)
break;
}
if (i == FIBER_LINK_UP_LIMIT) {
DEBUGOUT("Never got a valid link from auto-neg!!!\n");
mac->autoneg_failed = true;
ret_val = mac->ops.check_for_link(hw);
if (ret_val) {
DEBUGOUT("Error while checking for link\n");
return ret_val;
}
mac->autoneg_failed = false;
} else {
mac->autoneg_failed = false;
DEBUGOUT("Valid Link Found\n");
}
return E1000_SUCCESS;
}
s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw)
{
u32 ctrl;
s32 ret_val;
DEBUGFUNC("e1000_setup_fiber_serdes_link_generic");
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)
return ret_val;
DEBUGOUT("Auto-negotiation enabled\n");
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
E1000_WRITE_FLUSH(hw);
msec_delay(1);
if (hw->phy.media_type == e1000_media_type_internal_serdes ||
(E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) {
ret_val = e1000_poll_fiber_serdes_link_generic(hw);
} else {
DEBUGOUT("No signal detected\n");
}
return ret_val;
}
static void e1000_config_collision_dist_generic(struct e1000_hw *hw)
{
u32 tctl;
DEBUGFUNC("e1000_config_collision_dist_generic");
tctl = E1000_READ_REG(hw, E1000_TCTL);
tctl &= ~E1000_TCTL_COLD;
tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
E1000_WRITE_REG(hw, E1000_TCTL, tctl);
E1000_WRITE_FLUSH(hw);
}
s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw)
{
u32 fcrtl = 0, fcrth = 0;
DEBUGFUNC("e1000_set_fc_watermarks_generic");
if (hw->fc.current_mode & e1000_fc_tx_pause) {
fcrtl = hw->fc.low_water;
if (hw->fc.send_xon)
fcrtl |= E1000_FCRTL_XONE;
fcrth = hw->fc.high_water;
}
E1000_WRITE_REG(hw, E1000_FCRTL, fcrtl);
E1000_WRITE_REG(hw, E1000_FCRTH, fcrth);
return E1000_SUCCESS;
}
s32 e1000_force_mac_fc_generic(struct e1000_hw *hw)
{
u32 ctrl;
DEBUGFUNC("e1000_force_mac_fc_generic");
ctrl = E1000_READ_REG(hw, E1000_CTRL);
DEBUGOUT1("hw->fc.current_mode = %u\n", hw->fc.current_mode);
switch (hw->fc.current_mode) {
case e1000_fc_none:
ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
break;
case e1000_fc_rx_pause:
ctrl &= (~E1000_CTRL_TFCE);
ctrl |= E1000_CTRL_RFCE;
break;
case e1000_fc_tx_pause:
ctrl &= (~E1000_CTRL_RFCE);
ctrl |= E1000_CTRL_TFCE;
break;
case e1000_fc_full:
ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
break;
default:
DEBUGOUT("Flow control param set incorrectly\n");
return -E1000_ERR_CONFIG;
}
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
return E1000_SUCCESS;
}
s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
s32 ret_val = E1000_SUCCESS;
u32 pcs_status_reg, pcs_adv_reg, pcs_lp_ability_reg, pcs_ctrl_reg;
u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
u16 speed, duplex;
DEBUGFUNC("e1000_config_fc_after_link_up_generic");
if (mac->autoneg_failed) {
if (hw->phy.media_type == e1000_media_type_fiber ||
hw->phy.media_type == e1000_media_type_internal_serdes)
ret_val = e1000_force_mac_fc_generic(hw);
} else {
if (hw->phy.media_type == e1000_media_type_copper)
ret_val = e1000_force_mac_fc_generic(hw);
}
if (ret_val) {
DEBUGOUT("Error forcing flow control settings\n");
return ret_val;
}
if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) {
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
if (ret_val)
return ret_val;
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
if (ret_val)
return ret_val;
if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
DEBUGOUT("Copper PHY and Auto Neg has not completed.\n");
return ret_val;
}
ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
&mii_nway_adv_reg);
if (ret_val)
return ret_val;
ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
&mii_nway_lp_ability_reg);
if (ret_val)
return ret_val;
if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
if (hw->fc.requested_mode == e1000_fc_full) {
hw->fc.current_mode = e1000_fc_full;
DEBUGOUT("Flow Control = FULL.\n");
} else {
hw->fc.current_mode = e1000_fc_rx_pause;
DEBUGOUT("Flow Control = Rx PAUSE frames only.\n");
}
}
else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
hw->fc.current_mode = e1000_fc_tx_pause;
DEBUGOUT("Flow Control = Tx PAUSE frames only.\n");
}
else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
!(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
hw->fc.current_mode = e1000_fc_rx_pause;
DEBUGOUT("Flow Control = Rx PAUSE frames only.\n");
} else {
hw->fc.current_mode = e1000_fc_none;
DEBUGOUT("Flow Control = NONE.\n");
}
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 (duplex == HALF_DUPLEX)
hw->fc.current_mode = e1000_fc_none;
ret_val = e1000_force_mac_fc_generic(hw);
if (ret_val) {
DEBUGOUT("Error forcing flow control settings\n");
return ret_val;
}
}
if ((hw->phy.media_type == e1000_media_type_internal_serdes) &&
mac->autoneg) {
pcs_status_reg = E1000_READ_REG(hw, E1000_PCS_LSTAT);
if (!(pcs_status_reg & E1000_PCS_LSTS_AN_COMPLETE)) {
DEBUGOUT("PCS Auto Neg has not completed.\n");
return ret_val;
}
pcs_adv_reg = E1000_READ_REG(hw, E1000_PCS_ANADV);
pcs_lp_ability_reg = E1000_READ_REG(hw, E1000_PCS_LPAB);
if ((pcs_adv_reg & E1000_TXCW_PAUSE) &&
(pcs_lp_ability_reg & E1000_TXCW_PAUSE)) {
if (hw->fc.requested_mode == e1000_fc_full) {
hw->fc.current_mode = e1000_fc_full;
DEBUGOUT("Flow Control = FULL.\n");
} else {
hw->fc.current_mode = e1000_fc_rx_pause;
DEBUGOUT("Flow Control = Rx PAUSE frames only.\n");
}
}
else if (!(pcs_adv_reg & E1000_TXCW_PAUSE) &&
(pcs_adv_reg & E1000_TXCW_ASM_DIR) &&
(pcs_lp_ability_reg & E1000_TXCW_PAUSE) &&
(pcs_lp_ability_reg & E1000_TXCW_ASM_DIR)) {
hw->fc.current_mode = e1000_fc_tx_pause;
DEBUGOUT("Flow Control = Tx PAUSE frames only.\n");
}
else if ((pcs_adv_reg & E1000_TXCW_PAUSE) &&
(pcs_adv_reg & E1000_TXCW_ASM_DIR) &&
!(pcs_lp_ability_reg & E1000_TXCW_PAUSE) &&
(pcs_lp_ability_reg & E1000_TXCW_ASM_DIR)) {
hw->fc.current_mode = e1000_fc_rx_pause;
DEBUGOUT("Flow Control = Rx PAUSE frames only.\n");
} else {
hw->fc.current_mode = e1000_fc_none;
DEBUGOUT("Flow Control = NONE.\n");
}
pcs_ctrl_reg = E1000_READ_REG(hw, E1000_PCS_LCTL);
pcs_ctrl_reg |= E1000_PCS_LCTL_FORCE_FCTRL;
E1000_WRITE_REG(hw, E1000_PCS_LCTL, pcs_ctrl_reg);
ret_val = e1000_force_mac_fc_generic(hw);
if (ret_val) {
DEBUGOUT("Error forcing flow control settings\n");
return ret_val;
}
}
return E1000_SUCCESS;
}
s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed,
u16 *duplex)
{
u32 status;
DEBUGFUNC("e1000_get_speed_and_duplex_copper_generic");
status = E1000_READ_REG(hw, E1000_STATUS);
if (status & E1000_STATUS_SPEED_1000) {
*speed = SPEED_1000;
DEBUGOUT("1000 Mbs, ");
} else if (status & E1000_STATUS_SPEED_100) {
*speed = SPEED_100;
DEBUGOUT("100 Mbs, ");
} else {
*speed = SPEED_10;
DEBUGOUT("10 Mbs, ");
}
if (status & E1000_STATUS_FD) {
*duplex = FULL_DUPLEX;
DEBUGOUT("Full Duplex\n");
} else {
*duplex = HALF_DUPLEX;
DEBUGOUT("Half Duplex\n");
}
return E1000_SUCCESS;
}
s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw E1000_UNUSEDARG *hw,
u16 *speed, u16 *duplex)
{
DEBUGFUNC("e1000_get_speed_and_duplex_fiber_serdes_generic");
*speed = SPEED_1000;
*duplex = FULL_DUPLEX;
return E1000_SUCCESS;
}
s32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw)
{
s32 i = 0;
DEBUGFUNC("e1000_get_auto_rd_done_generic");
while (i < AUTO_READ_DONE_TIMEOUT) {
if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_AUTO_RD)
break;
msec_delay(1);
i++;
}
if (i == AUTO_READ_DONE_TIMEOUT) {
DEBUGOUT("Auto read by HW from NVM has not completed.\n");
return -E1000_ERR_RESET;
}
return E1000_SUCCESS;
}
s32 e1000_valid_led_default_generic(struct e1000_hw *hw, u16 *data)
{
s32 ret_val;
DEBUGFUNC("e1000_valid_led_default_generic");
ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
return ret_val;
}
if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
*data = ID_LED_DEFAULT;
return E1000_SUCCESS;
}
s32 e1000_id_led_init_generic(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
s32 ret_val;
const u32 ledctl_mask = 0x000000FF;
const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
u16 data, i, temp;
const u16 led_mask = 0x0F;
DEBUGFUNC("e1000_id_led_init_generic");
ret_val = hw->nvm.ops.valid_led_default(hw, &data);
if (ret_val)
return ret_val;
mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
mac->ledctl_mode1 = mac->ledctl_default;
mac->ledctl_mode2 = mac->ledctl_default;
for (i = 0; i < 4; i++) {
temp = (data >> (i << 2)) & led_mask;
switch (temp) {
case ID_LED_ON1_DEF2:
case ID_LED_ON1_ON2:
case ID_LED_ON1_OFF2:
mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
mac->ledctl_mode1 |= ledctl_on << (i << 3);
break;
case ID_LED_OFF1_DEF2:
case ID_LED_OFF1_ON2:
case ID_LED_OFF1_OFF2:
mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
mac->ledctl_mode1 |= ledctl_off << (i << 3);
break;
default:
break;
}
switch (temp) {
case ID_LED_DEF1_ON2:
case ID_LED_ON1_ON2:
case ID_LED_OFF1_ON2:
mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
mac->ledctl_mode2 |= ledctl_on << (i << 3);
break;
case ID_LED_DEF1_OFF2:
case ID_LED_ON1_OFF2:
case ID_LED_OFF1_OFF2:
mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
mac->ledctl_mode2 |= ledctl_off << (i << 3);
break;
default:
break;
}
}
return E1000_SUCCESS;
}
s32 e1000_setup_led_generic(struct e1000_hw *hw)
{
u32 ledctl;
DEBUGFUNC("e1000_setup_led_generic");
if (hw->mac.ops.setup_led != e1000_setup_led_generic)
return -E1000_ERR_CONFIG;
if (hw->phy.media_type == e1000_media_type_fiber) {
ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
hw->mac.ledctl_default = ledctl;
ledctl &= ~(E1000_LEDCTL_LED0_IVRT | E1000_LEDCTL_LED0_BLINK |
E1000_LEDCTL_LED0_MODE_MASK);
ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
E1000_LEDCTL_LED0_MODE_SHIFT);
E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
} else if (hw->phy.media_type == e1000_media_type_copper) {
E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
}
return E1000_SUCCESS;
}
s32 e1000_cleanup_led_generic(struct e1000_hw *hw)
{
DEBUGFUNC("e1000_cleanup_led_generic");
E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
return E1000_SUCCESS;
}
s32 e1000_blink_led_generic(struct e1000_hw *hw)
{
u32 ledctl_blink = 0;
u32 i;
DEBUGFUNC("e1000_blink_led_generic");
if (hw->phy.media_type == e1000_media_type_fiber) {
ledctl_blink = E1000_LEDCTL_LED0_BLINK |
(E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
} else {
ledctl_blink = hw->mac.ledctl_mode2;
for (i = 0; i < 32; i += 8) {
u32 mode = (hw->mac.ledctl_mode2 >> i) &
E1000_LEDCTL_LED0_MODE_MASK;
u32 led_default = hw->mac.ledctl_default >> i;
if ((!(led_default & E1000_LEDCTL_LED0_IVRT) &&
(mode == E1000_LEDCTL_MODE_LED_ON)) ||
((led_default & E1000_LEDCTL_LED0_IVRT) &&
(mode == E1000_LEDCTL_MODE_LED_OFF))) {
ledctl_blink &=
~(E1000_LEDCTL_LED0_MODE_MASK << i);
ledctl_blink |= (E1000_LEDCTL_LED0_BLINK |
E1000_LEDCTL_MODE_LED_ON) << i;
}
}
}
E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl_blink);
return E1000_SUCCESS;
}
s32 e1000_led_on_generic(struct e1000_hw *hw)
{
u32 ctrl;
DEBUGFUNC("e1000_led_on_generic");
switch (hw->phy.media_type) {
case e1000_media_type_fiber:
ctrl = E1000_READ_REG(hw, E1000_CTRL);
ctrl &= ~E1000_CTRL_SWDPIN0;
ctrl |= E1000_CTRL_SWDPIO0;
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
break;
case e1000_media_type_copper:
E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
break;
default:
break;
}
return E1000_SUCCESS;
}
s32 e1000_led_off_generic(struct e1000_hw *hw)
{
u32 ctrl;
DEBUGFUNC("e1000_led_off_generic");
switch (hw->phy.media_type) {
case e1000_media_type_fiber:
ctrl = E1000_READ_REG(hw, E1000_CTRL);
ctrl |= E1000_CTRL_SWDPIN0;
ctrl |= E1000_CTRL_SWDPIO0;
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
break;
case e1000_media_type_copper:
E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
break;
default:
break;
}
return E1000_SUCCESS;
}
void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop)
{
u32 gcr;
DEBUGFUNC("e1000_set_pcie_no_snoop_generic");
if (hw->bus.type != e1000_bus_type_pci_express)
return;
if (no_snoop) {
gcr = E1000_READ_REG(hw, E1000_GCR);
gcr &= ~(PCIE_NO_SNOOP_ALL);
gcr |= no_snoop;
E1000_WRITE_REG(hw, E1000_GCR, gcr);
}
}
s32 e1000_disable_pcie_master_generic(struct e1000_hw *hw)
{
u32 ctrl;
s32 timeout = MASTER_DISABLE_TIMEOUT;
DEBUGFUNC("e1000_disable_pcie_master_generic");
if (hw->bus.type != e1000_bus_type_pci_express)
return E1000_SUCCESS;
ctrl = E1000_READ_REG(hw, E1000_CTRL);
ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
while (timeout) {
if (!(E1000_READ_REG(hw, E1000_STATUS) &
E1000_STATUS_GIO_MASTER_ENABLE) ||
E1000_REMOVED(hw->hw_addr))
break;
usec_delay(100);
timeout--;
}
if (!timeout) {
DEBUGOUT("Master requests are pending.\n");
return -E1000_ERR_MASTER_REQUESTS_PENDING;
}
return E1000_SUCCESS;
}
void e1000_reset_adaptive_generic(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
DEBUGFUNC("e1000_reset_adaptive_generic");
if (!mac->adaptive_ifs) {
DEBUGOUT("Not in Adaptive IFS mode!\n");
return;
}
mac->current_ifs_val = 0;
mac->ifs_min_val = IFS_MIN;
mac->ifs_max_val = IFS_MAX;
mac->ifs_step_size = IFS_STEP;
mac->ifs_ratio = IFS_RATIO;
mac->in_ifs_mode = false;
E1000_WRITE_REG(hw, E1000_AIT, 0);
}
void e1000_update_adaptive_generic(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
DEBUGFUNC("e1000_update_adaptive_generic");
if (!mac->adaptive_ifs) {
DEBUGOUT("Not in Adaptive IFS mode!\n");
return;
}
if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
if (mac->tx_packet_delta > MIN_NUM_XMITS) {
mac->in_ifs_mode = true;
if (mac->current_ifs_val < mac->ifs_max_val) {
if (!mac->current_ifs_val)
mac->current_ifs_val = mac->ifs_min_val;
else
mac->current_ifs_val +=
mac->ifs_step_size;
E1000_WRITE_REG(hw, E1000_AIT,
mac->current_ifs_val);
}
}
} else {
if (mac->in_ifs_mode &&
(mac->tx_packet_delta <= MIN_NUM_XMITS)) {
mac->current_ifs_val = 0;
mac->in_ifs_mode = false;
E1000_WRITE_REG(hw, E1000_AIT, 0);
}
}
}
static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw)
{
DEBUGFUNC("e1000_validate_mdi_setting_generic");
if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) {
DEBUGOUT("Invalid MDI setting detected\n");
hw->phy.mdix = 1;
return -E1000_ERR_CONFIG;
}
return E1000_SUCCESS;
}
s32 e1000_validate_mdi_setting_crossover_generic(struct e1000_hw E1000_UNUSEDARG *hw)
{
DEBUGFUNC("e1000_validate_mdi_setting_crossover_generic");
return E1000_SUCCESS;
}
s32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg,
u32 offset, u8 data)
{
u32 i, regvalue = 0;
DEBUGFUNC("e1000_write_8bit_ctrl_reg_generic");
regvalue = ((u32)data) | (offset << E1000_GEN_CTL_ADDRESS_SHIFT);
E1000_WRITE_REG(hw, reg, regvalue);
for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) {
usec_delay(5);
regvalue = E1000_READ_REG(hw, reg);
if (regvalue & E1000_GEN_CTL_READY)
break;
}
if (!(regvalue & E1000_GEN_CTL_READY)) {
DEBUGOUT1("Reg %08x did not indicate ready\n", reg);
return -E1000_ERR_PHY;
}
return E1000_SUCCESS;
}
s32 e1000_get_hw_semaphore(struct e1000_hw *hw)
{
u32 swsm;
s32 fw_timeout = hw->nvm.word_size + 1;
s32 sw_timeout = hw->nvm.word_size + 1;
s32 i = 0;
DEBUGFUNC("e1000_get_hw_semaphore");
if (hw->dev_spec._82571.smb_counter > 2)
sw_timeout = 1;
while (i < sw_timeout) {
swsm = E1000_READ_REG(hw, E1000_SWSM);
if (!(swsm & E1000_SWSM_SMBI))
break;
usec_delay(50);
i++;
}
if (i == sw_timeout) {
DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
hw->dev_spec._82571.smb_counter++;
}
if (hw->dev_spec._82575.clear_semaphore_once) {
hw->dev_spec._82575.clear_semaphore_once = false;
e1000_put_hw_semaphore(hw);
for (i = 0; i < fw_timeout; i++) {
swsm = E1000_READ_REG(hw, E1000_SWSM);
if (!(swsm & E1000_SWSM_SMBI))
break;
usec_delay(50);
}
}
for (i = 0; i < fw_timeout; i++) {
swsm = E1000_READ_REG(hw, E1000_SWSM);
E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI)
break;
usec_delay(50);
}
if (i == fw_timeout) {
e1000_put_hw_semaphore(hw);
DEBUGOUT("Driver can't access the NVM\n");
return -E1000_ERR_NVM;
}
return E1000_SUCCESS;
}
void e1000_put_hw_semaphore(struct e1000_hw *hw)
{
u32 swsm;
DEBUGFUNC("e1000_put_hw_semaphore");
swsm = E1000_READ_REG(hw, E1000_SWSM);
swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
E1000_WRITE_REG(hw, E1000_SWSM, swsm);
}
s32
e1000_acquire_swfw_sync(struct e1000_hw *hw, u16 mask)
{
u32 swfw_sync;
u32 swmask = mask;
u32 fwmask = mask << 16;
s32 ret_val = E1000_SUCCESS;
s32 i = 0, timeout = 200;
DEBUGFUNC("e1000_acquire_swfw_sync");
ASSERT_NO_LOCKS();
while (i < timeout) {
if (e1000_get_hw_semaphore(hw)) {
ret_val = -E1000_ERR_SWFW_SYNC;
goto out;
}
swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
if (!(swfw_sync & (fwmask | swmask)))
break;
e1000_put_hw_semaphore(hw);
msec_delay_irq(5);
i++;
}
if (i == timeout) {
DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
ret_val = -E1000_ERR_SWFW_SYNC;
goto out;
}
swfw_sync |= swmask;
E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
e1000_put_hw_semaphore(hw);
out:
return ret_val;
}
void
e1000_release_swfw_sync(struct e1000_hw *hw, u16 mask)
{
u32 swfw_sync;
DEBUGFUNC("e1000_release_swfw_sync");
while (e1000_get_hw_semaphore(hw) != E1000_SUCCESS)
;
swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
swfw_sync &= (u32)~mask;
E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
e1000_put_hw_semaphore(hw);
}