summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpdeuskar <pdeuskar@FreeBSD.org>2004-02-10 21:31:09 +0000
committerpdeuskar <pdeuskar@FreeBSD.org>2004-02-10 21:31:09 +0000
commit6dd3d6f0952471c0803183cbba084b9b7d569191 (patch)
tree78ffc6dd4a392215917280ee3b03ac141ee2081a
parenta96542610a6d885712cc0b71ed39380529d212d6 (diff)
downloadFreeBSD-src-6dd3d6f0952471c0803183cbba084b9b7d569191.zip
FreeBSD-src-6dd3d6f0952471c0803183cbba084b9b7d569191.tar.gz
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
-rw-r--r--sys/dev/em/if_em.c31
-rw-r--r--sys/dev/em/if_em_hw.c128
-rw-r--r--sys/dev/em/if_em_hw.h13
3 files changed, 113 insertions, 59 deletions
diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c
index db9fd18..c643228 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 fab8004..2b45905 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 d745012..5157bee 100644
--- a/sys/dev/em/if_em_hw.h
+++ b/sys/dev/em/if_em_hw.h
@@ -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) */
OpenPOWER on IntegriCloud