diff options
Diffstat (limited to 'sys/dev/pci/if_em_hw.c')
-rw-r--r-- | sys/dev/pci/if_em_hw.c | 134 |
1 files changed, 84 insertions, 50 deletions
diff --git a/sys/dev/pci/if_em_hw.c b/sys/dev/pci/if_em_hw.c index 9a889d13509..620b57fd85f 100644 --- a/sys/dev/pci/if_em_hw.c +++ b/sys/dev/pci/if_em_hw.c @@ -31,11 +31,15 @@ *******************************************************************************/ -/* $FreeBSD: if_em_hw.c,v 1.12 2003/11/14 18:02:24 pdeuskar Exp $ */ -/* $OpenBSD: if_em_hw.c,v 1.3 2003/12/09 23:37:03 henning Exp $ */ +/* $OpenBSD: if_em_hw.c,v 1.4 2004/04/18 04:15:00 henric Exp $ */ /* if_em_hw.c * Shared functions for accessing and configuring the MAC */ + +#ifdef __FreeBSD__ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: if_em_hw.c,v 1.13 2004/02/10 21:31:09 pdeuskar Exp $"); +#endif #include "bpfilter.h" #include "vlan.h" @@ -142,8 +146,14 @@ em_set_phy_type(struct em_hw *hw) hw->phy_type = em_phy_m88; break; case IGP01E1000_I_PHY_ID: - hw->phy_type = em_phy_igp; - break; + if(hw->mac_type == em_82541 || + hw->mac_type == em_82541_rev_2 || + hw->mac_type == em_82547 || + hw->mac_type == em_82547_rev_2) { + hw->phy_type = em_phy_igp; + break; + } + /* Fall Through */ default: /* Should never have loaded on this device */ hw->phy_type = em_phy_undefined; @@ -194,7 +204,6 @@ em_phy_init_script(struct em_hw *hw) em_write_phy_reg(hw, 0x0000, 0x3300); - if(hw->mac_type == em_82547) { uint16_t fused, fine, coarse; @@ -1531,8 +1540,8 @@ em_phy_force_speed_duplex(struct em_hw *hw) if(mii_status_reg & MII_SR_LINK_STATUS) break; msec_delay(100); } - if(i == 0) { /* We didn't get link */ - /* Reset the DSP and wait again for link. */ + if((i == 0) && (hw->phy_type == em_phy_m88)) { + /* We didn't get link. Reset the DSP and wait again for link. */ if((ret_val = em_phy_reset_dsp(hw))) { DEBUGOUT("Error Resetting PHY DSP\n"); return ret_val; @@ -1579,6 +1588,25 @@ em_phy_force_speed_duplex(struct em_hw *hw) phy_data))) return ret_val; + /* Polarity reversal workaround for forced 10F/10H links. */ + if(hw->mac_type <= em_82544 && + (hw->forced_speed_duplex == em_10_full || + hw->forced_speed_duplex == em_10_half)) { + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, + 0x0019))) + return ret_val; + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, + 0x8F0F))) + return ret_val; + /* IEEE requirement is 150ms */ + msec_delay(200); + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, + 0x0019))) + return ret_val; + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, + 0x8F00))) + return ret_val; + } } return E1000_SUCCESS; } @@ -1962,7 +1990,6 @@ em_check_for_link(struct em_hw *hw) uint32_t signal = 0; int32_t ret_val; uint16_t phy_data; - uint16_t lp_capability; DEBUGFUNC("em_check_for_link"); @@ -2042,24 +2069,17 @@ em_check_for_link(struct em_hw *hw) /* At this point we know that we are on copper and we have * auto-negotiated link. These are conditions for checking the link - * parter capability register. We use the link partner capability to - * determine if TBI Compatibility needs to be turned on or off. If - * the link partner advertises any speed in addition to Gigabit, then - * we assume that they are GMII-based, and TBI compatibility is not - * needed. If no other speeds are advertised, we assume the link - * partner is TBI-based, and we turn on TBI Compatibility. + * partner capability register. We use the link speed to determine if + * TBI compatibility needs to be turned on or off. If the link is not + * at gigabit speed, then TBI compatibility is not needed. If we are + * at gigabit speed, we turn on TBI compatibility. */ if(hw->tbi_compatibility_en) { - if((ret_val = em_read_phy_reg(hw, PHY_LP_ABILITY, - &lp_capability))) - return ret_val; - if(lp_capability & (NWAY_LPAR_10T_HD_CAPS | - NWAY_LPAR_10T_FD_CAPS | - NWAY_LPAR_100TX_HD_CAPS | - NWAY_LPAR_100TX_FD_CAPS | - NWAY_LPAR_100T4_CAPS)) { - /* If our link partner advertises anything in addition to - * gigabit, we do not need to enable TBI compatibility. + uint16_t speed, duplex; + em_get_speed_and_duplex(hw, &speed, &duplex); + if(speed != SPEED_1000) { + /* If link speed is not set to gigabit speed, we do not need + * to enable TBI compatibility. */ if(hw->tbi_compatibility_on) { /* If we previously were in the mode, turn it off. */ @@ -2127,6 +2147,29 @@ em_check_for_link(struct em_hw *hw) DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n"); E1000_WRITE_REG(hw, TXCW, hw->txcw); E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU)); + + hw->serdes_link_down = FALSE; + } + /* If we force link for non-auto-negotiation switch, check link status + * based on MAC synchronization for internal serdes media type. + */ + else if((hw->media_type == em_media_type_internal_serdes) && + !(E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { + /* SYNCH bit and IV bit are sticky. */ + usec_delay(10); + if(E1000_RXCW_SYNCH & E1000_READ_REG(hw, RXCW)) { + if(!(rxcw & E1000_RXCW_IV)) { + hw->serdes_link_down = FALSE; + DEBUGOUT("SERDES: Link is up.\n"); + } + } else { + hw->serdes_link_down = TRUE; + DEBUGOUT("SERDES: Link is down.\n"); + } + } + if((hw->media_type == em_media_type_internal_serdes) && + (E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { + hw->serdes_link_down = !(E1000_STATUS_LU & E1000_READ_REG(hw, STATUS)); } return E1000_SUCCESS; } @@ -2527,8 +2570,8 @@ em_write_phy_reg_ex(struct em_hw *hw, E1000_WRITE_REG(hw, MDIC, mdic); /* Poll the ready bit to see if the MDI read completed */ - for(i = 0; i < 64; i++) { - usec_delay(50); + for(i = 0; i < 640; i++) { + usec_delay(5); mdic = E1000_READ_REG(hw, MDIC); if(mdic & E1000_MDIC_READY) break; } @@ -3544,10 +3587,12 @@ em_write_eeprom(struct em_hw *hw, if (em_acquire_eeprom(hw) != E1000_SUCCESS) return -E1000_ERR_EEPROM; - if(eeprom->type == em_eeprom_microwire) + if(eeprom->type == em_eeprom_microwire) { status = em_write_eeprom_microwire(hw, offset, words, data); - else + } else { status = em_write_eeprom_spi(hw, offset, words, data); + msec_delay(10); + } /* Done with writing */ em_release_eeprom(hw); @@ -3765,12 +3810,9 @@ em_read_mac_addr(struct em_hw * hw) hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8); } if(((hw->mac_type == em_82546) || (hw->mac_type == em_82546_rev_3)) && - (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { - if(hw->perm_mac_addr[5] & 0x01) - hw->perm_mac_addr[5] &= ~(0x01); - else - hw->perm_mac_addr[5] |= 0x01; - } + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) + hw->perm_mac_addr[5] ^= 0x01; + for(i = 0; i < NODE_ADDRESS_SIZE; i++) hw->mac_addr[i] = hw->perm_mac_addr[i]; return E1000_SUCCESS; @@ -3789,22 +3831,13 @@ void em_init_rx_addrs(struct em_hw *hw) { uint32_t i; - uint32_t addr_low; - uint32_t addr_high; DEBUGFUNC("em_init_rx_addrs"); /* Setup the receive address. */ DEBUGOUT("Programming MAC Address into RAR[0]\n"); - addr_low = (hw->mac_addr[0] | - (hw->mac_addr[1] << 8) | - (hw->mac_addr[2] << 16) | (hw->mac_addr[3] << 24)); - - addr_high = (hw->mac_addr[4] | - (hw->mac_addr[5] << 8) | E1000_RAH_AV); - E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low); - E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high); + em_rar_set(hw, hw->mac_addr, 0); /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); @@ -3821,6 +3854,7 @@ em_init_rx_addrs(struct em_hw *hw) * mc_addr_list - the list of new multicast addresses * mc_addr_count - number of addresses * pad - number of bytes between addresses in the list + * rar_used_count - offset where to start adding mc addresses into the RAR's * * The given list replaces any existing list. Clears the last 15 receive * address registers and the multicast table. Uses receive address registers @@ -3831,11 +3865,11 @@ void em_mc_addr_list_update(struct em_hw *hw, uint8_t *mc_addr_list, uint32_t mc_addr_count, - uint32_t pad) + uint32_t pad, + uint32_t rar_used_count) { uint32_t hash_value; uint32_t i; - uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */ DEBUGFUNC("em_mc_addr_list_update"); @@ -4569,8 +4603,8 @@ uint32_t em_read_reg_io(struct em_hw *hw, uint32_t offset) { - uint32_t io_addr = hw->io_base; - uint32_t io_data = hw->io_base + 4; + unsigned long io_addr = hw->io_base; + unsigned long io_data = hw->io_base + 4; em_io_write(hw, io_addr, offset); return em_io_read(hw, io_data); @@ -4589,8 +4623,8 @@ em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value) { - uint32_t io_addr = hw->io_base; - uint32_t io_data = hw->io_base + 4; + unsigned long io_addr = hw->io_base; + unsigned long io_data = hw->io_base + 4; em_io_write(hw, io_addr, offset); em_io_write(hw, io_data, value); |