Only reset the phy when it is absolutely required.

This should fix the issues with long *init* times when
you do ifconfig em0 alias.

MFC after:	3 days
This commit is contained in:
Prafulla Deuskar 2004-02-10 21:31:09 +00:00
parent a9c2bfa8e9
commit b81490427d
3 changed files with 113 additions and 59 deletions

View File

@ -51,7 +51,7 @@ struct adapter *em_adapter_list = NULL;
* Driver version
*********************************************************************/
char em_driver_version[] = "1.7.19";
char em_driver_version[] = "1.7.25";
/*********************************************************************
@ -539,7 +539,8 @@ em_detach(device_t dev)
ether_ifdetach(&adapter->interface_data.ac_if);
#endif
em_free_pci_resources(adapter);
bus_generic_detach(dev);
/* Free Transmit Descriptor ring */
if (adapter->tx_desc_base) {
em_dma_free(adapter, &adapter->txdma);
@ -764,7 +765,8 @@ em_watchdog(struct ifnet *ifp)
return;
}
printf("em%d: watchdog timeout -- resetting\n", adapter->unit);
if (em_check_for_link(&adapter->hw))
printf("em%d: watchdog timeout -- resetting\n", adapter->unit);
ifp->if_flags &= ~IFF_RUNNING;
@ -857,6 +859,9 @@ em_init_locked(struct adapter * adapter)
#endif /* DEVICE_POLLING */
em_enable_intr(adapter);
/* Don't reset the phy next time init gets called */
adapter->hw.phy_reset_disable = TRUE;
return;
}
@ -1098,6 +1103,11 @@ em_media_change(struct ifnet *ifp)
printf("em%d: Unsupported media type\n", adapter->unit);
}
/* As the speed/duplex settings my have changed we need to
* reset the PHY.
*/
adapter->hw.phy_reset_disable = FALSE;
em_init(adapter);
return(0);
@ -1516,7 +1526,7 @@ em_set_multi(struct adapter * adapter)
reg_rctl |= E1000_RCTL_MPE;
E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
} else
em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0);
em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0, 1);
if (adapter->hw.mac_type == em_82542_rev2_0) {
reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
@ -2952,13 +2962,13 @@ em_pci_clear_mwi(struct em_hw *hw)
}
uint32_t
em_io_read(struct em_hw *hw, uint32_t port)
em_io_read(struct em_hw *hw, unsigned long port)
{
return(inl(port));
}
void
em_io_write(struct em_hw *hw, uint32_t port, uint32_t value)
em_io_write(struct em_hw *hw, unsigned long port, uint32_t value)
{
outl(port, value);
return;
@ -3136,6 +3146,15 @@ static void
em_print_debug_info(struct adapter *adapter)
{
int unit = adapter->unit;
uint8_t *hw_addr = adapter->hw.hw_addr;
printf("em%d: Adapter hardware address = %p \n", unit, hw_addr);
printf("em%d:tx_int_delay = %d, tx_abs_int_delay = %d\n", unit,
E1000_READ_REG(&adapter->hw, TIDV),
E1000_READ_REG(&adapter->hw, TADV));
printf("em%d:rx_int_delay = %d, rx_abs_int_delay = %d\n", unit,
E1000_READ_REG(&adapter->hw, RDTR),
E1000_READ_REG(&adapter->hw, RADV));
#ifdef DBG_STATS
printf("em%d: Packets not Avail = %ld\n", unit,

View File

@ -104,8 +104,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;
@ -156,7 +162,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;
@ -1493,8 +1498,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;
@ -1541,6 +1546,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;
}
@ -1924,7 +1948,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");
@ -2004,24 +2027,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.
if(hw->tbi_compatibility_en) {
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. */
@ -2089,6 +2105,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;
}
@ -2489,8 +2528,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;
}
@ -3506,10 +3545,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);
@ -3727,12 +3768,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;
@ -3751,22 +3789,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");
@ -3783,6 +3812,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
@ -3793,11 +3823,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");
@ -4531,8 +4561,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);
@ -4551,8 +4581,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);

View File

@ -41,6 +41,9 @@
#include <dev/em/if_em_osdep.h>
#ifndef NO_VERSION_CONTROL
#ident "@(#)$RCSfile: if_em_hw.h,v $$Revision: 1.37 $$Date: 2003/12/20 00:14:51 $"
#endif
/* Forward declarations of structures used by the shared code */
struct em_hw;
@ -297,7 +300,7 @@ int32_t em_read_mac_addr(struct em_hw * hw);
/* Filters (multicast, vlan, receive) */
void em_init_rx_addrs(struct em_hw *hw);
void em_mc_addr_list_update(struct em_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad);
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 rar_used_count);
uint32_t em_hash_mc_addr(struct em_hw *hw, uint8_t * mc_addr);
void em_mta_set(struct em_hw *hw, uint32_t hash_value);
void em_rar_set(struct em_hw *hw, uint8_t * mc_addr, uint32_t rar_index);
@ -323,9 +326,9 @@ void em_pci_clear_mwi(struct em_hw *hw);
void em_read_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value);
void em_write_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value);
/* Port I/O is only supported on 82544 and newer */
uint32_t em_io_read(struct em_hw *hw, uint32_t port);
uint32_t em_io_read(struct em_hw *hw, unsigned long port);
uint32_t em_read_reg_io(struct em_hw *hw, uint32_t offset);
void em_io_write(struct em_hw *hw, uint32_t port, uint32_t value);
void em_io_write(struct em_hw *hw, unsigned long port, uint32_t value);
void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value);
int32_t em_config_dsp_after_link_change(struct em_hw *hw, boolean_t link_up);
int32_t em_set_d3_lplu_state(struct em_hw *hw, boolean_t active);
@ -984,7 +987,7 @@ struct em_hw {
em_ms_type master_slave;
em_ms_type original_master_slave;
em_ffe_config ffe_config_state;
uint32_t io_base;
unsigned long io_base;
uint32_t phy_id;
uint32_t phy_revision;
uint32_t phy_addr;
@ -1027,6 +1030,7 @@ struct em_hw {
boolean_t speed_downgraded;
em_dsp_config dsp_config_state;
boolean_t get_link_status;
boolean_t serdes_link_down;
boolean_t tbi_compatibility_en;
boolean_t tbi_compatibility_on;
boolean_t phy_reset_disable;
@ -1316,6 +1320,7 @@ struct em_hw {
#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */
#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */
#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */
#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
/* Receive Descriptor */
#define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */