From 6dd3d6f0952471c0803183cbba084b9b7d569191 Mon Sep 17 00:00:00 2001 From: pdeuskar Date: Tue, 10 Feb 2004 21:31:09 +0000 Subject: [PATCH] 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 --- sys/dev/em/if_em.c | 31 ++++++++-- sys/dev/em/if_em_hw.c | 128 ++++++++++++++++++++++++++---------------- sys/dev/em/if_em_hw.h | 13 +++-- 3 files changed, 113 insertions(+), 59 deletions(-) diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c index db9fd18088e1..c64322879761 100644 --- a/sys/dev/em/if_em.c +++ b/sys/dev/em/if_em.c @@ -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, diff --git a/sys/dev/em/if_em_hw.c b/sys/dev/em/if_em_hw.c index fab8004bacdc..2b45905ebddf 100644 --- a/sys/dev/em/if_em_hw.c +++ b/sys/dev/em/if_em_hw.c @@ -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); diff --git a/sys/dev/em/if_em_hw.h b/sys/dev/em/if_em_hw.h index d7450120ef65..5157bee5b669 100644 --- a/sys/dev/em/if_em_hw.h +++ b/sys/dev/em/if_em_hw.h @@ -41,6 +41,9 @@ #include +#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) */