Sync with FreeBSD dev/em
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Mon, 17 Oct 2005 06:18:36 +0000 (06:18 +0000)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Mon, 17 Oct 2005 06:18:36 +0000 (06:18 +0000)
if_em.c rev 1.2.2.{20,21,22} 1.47 1.63
if_em.h rev 1.1.2.17
if_em_hw.c rev 1.1.2.12
if_em_hw.h rev 1.1.2.12

- Add support for Intel PRO/1000 GT Desktop Adapter
- Add support for Intel 82546GB dual port PCIE adapter
- Add fix for 82547 which corrects an issue with Jumbo frames larger than 10k
- Add fix for vlan tagged frames not being properly bridged
- Correct TBI workaround
- Correct LED operation issues
- Do not count RNBC (internal buffer full) towards the RX error count,
  since it's not really an error
- Correct a workaround that should only be applied to one adapter.  Workaround
  was causing device hangs when incorrectly applied to other adapters (*)
- Run em_local_timer() once per second instead of running it once per 2 seconds.
  This makes gathering of stats more precise

(*) Detailed problem description is in FreeBSD's PR kern/66634

sys/dev/netif/em/if_em.c
sys/dev/netif/em/if_em.h
sys/dev/netif/em/if_em_hw.c
sys/dev/netif/em/if_em_hw.h

index 4f6e031..1e0385d 100644 (file)
@@ -34,9 +34,9 @@ POSSIBILITY OF SUCH DAMAGE.
 ***************************************************************************/
 
 /*$FreeBSD: src/sys/dev/em/if_em.c,v 1.2.2.15 2003/06/09 22:10:15 pdeuskar Exp $*/
-/*$DragonFly: src/sys/dev/netif/em/if_em.c,v 1.39 2005/10/12 17:35:51 dillon Exp $*/
+/*$DragonFly: src/sys/dev/netif/em/if_em.c,v 1.40 2005/10/17 06:18:36 sephe Exp $*/
 
-#include "if_em.h"
+#include <dev/netif/em/if_em.h>
 #include <net/ifq_var.h>
 
 /*********************************************************************
@@ -48,7 +48,7 @@ int             em_display_debug_stats = 0;
  *  Driver version
  *********************************************************************/
 
-char em_driver_version[] = "1.7.25";
+char em_driver_version[] = "1.7.35";
 
 
 /*********************************************************************
@@ -96,6 +96,8 @@ static em_vendor_info_t em_vendor_info_array[] =
        { 0x8086, 0x1079, PCI_ANY_ID, PCI_ANY_ID, 0},
        { 0x8086, 0x107A, PCI_ANY_ID, PCI_ANY_ID, 0},
        { 0x8086, 0x107B, PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, 0x107C, PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, 0x108A, PCI_ANY_ID, PCI_ANY_ID, 0},
        /* required last entry */
        { 0, 0, 0, 0, 0}
 };
@@ -739,7 +741,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
                }
                break;
        default:
-               IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%x)\n", (int)command);
+               IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%x)", (int)command);
                error = EINVAL;
        }
 
@@ -804,12 +806,45 @@ static void
 em_init_serialized(void *arg)
 {
        struct adapter *adapter = arg;
+       uint32_t pba;
        struct ifnet *ifp = &adapter->interface_data.ac_if;
 
        INIT_DEBUGOUT("em_init: begin");
 
        em_stop(adapter);
 
+       /*
+        * Packet Buffer Allocation (PBA)
+        * Writing PBA sets the receive portion of the buffer
+        * the remainder is used for the transmit buffer.
+        *
+        * Devices before the 82547 had a Packet Buffer of 64K.
+        *   Default allocation: PBA=48K for Rx, leaving 16K for Tx.
+        * After the 82547 the buffer was reduced to 40K.
+        *   Default allocation: PBA=30K for Rx, leaving 10K for Tx.
+        *   Note: default does not leave enough room for Jumbo Frame >10k.
+        */
+       if(adapter->hw.mac_type < em_82547) {
+               /* Total FIFO is 64K */
+               if(adapter->rx_buffer_len > EM_RXBUFFER_8192)
+                       pba = E1000_PBA_40K; /* 40K for Rx, 24K for Tx */
+               else
+                       pba = E1000_PBA_48K; /* 48K for Rx, 16K for Tx */
+       } else {
+               /* Total FIFO is 40K */
+               if(adapter->hw.max_frame_size > EM_RXBUFFER_8192) {
+                       pba = E1000_PBA_22K; /* 22K for Rx, 18K for Tx */
+               } else {
+                       pba = E1000_PBA_30K; /* 30K for Rx, 10K for Tx */
+               }
+               adapter->tx_fifo_head = 0;
+               adapter->tx_head_addr = pba << EM_TX_HEAD_ADDR_SHIFT;
+               adapter->tx_fifo_size =
+                       (E1000_PBA_40K - pba) << EM_PBA_BYTES_SHIFT;
+       }
+       INIT_DEBUGOUT1("em_init: pba=%dK",pba);
+       E1000_WRITE_REG(&adapter->hw, PBA, pba);
+
        /* Get the latest mac address, User can use a LAA */
        bcopy(adapter->interface_data.ac_enaddr, adapter->hw.mac_addr,
              ETHER_ADDR_LEN);
@@ -854,7 +889,7 @@ em_init_serialized(void *arg)
                        ifp->if_hwassist = 0;
        }
 
-       callout_reset(&adapter->timer, 2*hz, em_local_timer, adapter);
+       callout_reset(&adapter->timer, hz, em_local_timer, adapter);
        em_clear_hw_cntrs(&adapter->hw);
        em_enable_intr(adapter);
 
@@ -885,7 +920,7 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
                        adapter->hw.get_link_status = 1;
                        em_check_for_link(&adapter->hw);
                        em_print_link_status(adapter);
-                       callout_reset(&adapter->timer, 2*hz, em_local_timer,
+                       callout_reset(&adapter->timer, hz, em_local_timer,
                                      adapter);
                }
                /* fall through */
@@ -929,7 +964,7 @@ em_intr(void *arg)
                adapter->hw.get_link_status = 1;
                em_check_for_link(&adapter->hw);
                em_print_link_status(adapter);
-               callout_reset(&adapter->timer, 2*hz, em_local_timer, adapter);
+               callout_reset(&adapter->timer, hz, em_local_timer, adapter);
        }
 
        /*
@@ -1082,10 +1117,6 @@ em_tx_cb(void *arg, bus_dma_segment_t *seg, int nsegs, bus_size_t mapsize,
        bcopy(seg, q->segs, nsegs * sizeof(seg[0]));
 }
 
-#define EM_FIFO_HDR              0x10
-#define EM_82547_PKT_THRESH      0x3e0
-#define EM_82547_TX_FIFO_SIZE    0x2800
-#define EM_82547_TX_FIFO_BEGIN   0xf00
 /*********************************************************************
  *
  *  This routine maps the mbufs to tx descriptors.
@@ -1297,7 +1328,7 @@ em_82547_move_tail_serialized(void *arg)
 
                if(eop) {
                        if (em_82547_fifo_workaround(adapter, length)) {
-                               adapter->tx_fifo_wrk++;
+                               adapter->tx_fifo_wrk_cnt++;
                                callout_reset(&adapter->tx_fifo_timer, 1,
                                        em_82547_move_tail, adapter);
                                break;
@@ -1317,7 +1348,7 @@ em_82547_fifo_workaround(struct adapter *adapter, int len)
        fifo_pkt_len = EM_ROUNDUP(len + EM_FIFO_HDR, EM_FIFO_HDR);
 
        if (adapter->link_duplex == HALF_DUPLEX) {
-               fifo_space = EM_82547_TX_FIFO_SIZE - adapter->tx_fifo_head;
+               fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head;
 
                if (fifo_pkt_len >= (EM_82547_PKT_THRESH + fifo_space)) {
                        if (em_82547_tx_fifo_reset(adapter))
@@ -1337,8 +1368,8 @@ em_82547_update_fifo_head(struct adapter *adapter, int len)
 
        /* tx_fifo_head is always 16 byte aligned */
        adapter->tx_fifo_head += fifo_pkt_len;
-       if (adapter->tx_fifo_head >= EM_82547_TX_FIFO_SIZE)
-               adapter->tx_fifo_head -= EM_82547_TX_FIFO_SIZE;
+       if (adapter->tx_fifo_head >= adapter->tx_fifo_size)
+               adapter->tx_fifo_head -= adapter->tx_fifo_size;
 }
 
 static int
@@ -1359,21 +1390,20 @@ em_82547_tx_fifo_reset(struct adapter *adapter)
                E1000_WRITE_REG(&adapter->hw, TCTL, tctl & ~E1000_TCTL_EN);
 
                /* Reset FIFO pointers */
-               E1000_WRITE_REG(&adapter->hw, TDFT, EM_82547_TX_FIFO_BEGIN);
-               E1000_WRITE_REG(&adapter->hw, TDFH, EM_82547_TX_FIFO_BEGIN);
-               E1000_WRITE_REG(&adapter->hw, TDFTS, EM_82547_TX_FIFO_BEGIN);
-               E1000_WRITE_REG(&adapter->hw, TDFHS, EM_82547_TX_FIFO_BEGIN);
+               E1000_WRITE_REG(&adapter->hw, TDFT,  adapter->tx_head_addr);
+               E1000_WRITE_REG(&adapter->hw, TDFH,  adapter->tx_head_addr);
+               E1000_WRITE_REG(&adapter->hw, TDFTS, adapter->tx_head_addr);
+               E1000_WRITE_REG(&adapter->hw, TDFHS, adapter->tx_head_addr);
 
                /* Re-enable TX unit */
                E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
                E1000_WRITE_FLUSH(&adapter->hw);
 
                adapter->tx_fifo_head = 0;
-               adapter->tx_fifo_reset++;
+               adapter->tx_fifo_reset_cnt++;
 
                return(TRUE);
-       }
-       else {
+       } else {
                return(FALSE);
        }
 }
@@ -1381,14 +1411,23 @@ em_82547_tx_fifo_reset(struct adapter *adapter)
 static void
 em_set_promisc(struct adapter *adapter)
 {
-       uint32_t reg_rctl;
+       uint32_t reg_rctl, ctrl;
        struct ifnet *ifp = &adapter->interface_data.ac_if;
 
        reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+       ctrl = E1000_READ_REG(&adapter->hw, CTRL);
 
        if (ifp->if_flags & IFF_PROMISC) {
                reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
                E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+
+               /*
+                * Disable VLAN stripping in promiscous mode.
+                * This enables bridging of vlan tagged frames to occur 
+                * and also allows vlan tags to be seen in tcpdump.
+                */
+               ctrl &= ~E1000_CTRL_VME; 
+               E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
        } else if (ifp->if_flags & IFF_ALLMULTI) {
                reg_rctl |= E1000_RCTL_MPE;
                reg_rctl &= ~E1000_RCTL_UPE;
@@ -1406,6 +1445,8 @@ em_disable_promisc(struct adapter *adapter)
        reg_rctl &=  (~E1000_RCTL_UPE);
        reg_rctl &=  (~E1000_RCTL_MPE);
        E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+
+       em_enable_vlans(adapter);
 }
 
 /*********************************************************************
@@ -1487,7 +1528,7 @@ em_local_timer(void *arg)
                em_print_hw_stats(adapter);
        em_smartspeed(adapter);
 
-       callout_reset(&adapter->timer, 2*hz, em_local_timer, adapter);
+       callout_reset(&adapter->timer, hz, em_local_timer, adapter);
 
        lwkt_serialize_exit(&adapter->serializer);
 }
@@ -2653,8 +2694,21 @@ em_enable_intr(struct adapter *adapter)
 static void
 em_disable_intr(struct adapter *adapter)
 {
-       E1000_WRITE_REG(&adapter->hw, IMC, 
-                       (0xffffffff & ~E1000_IMC_RXSEQ));
+       /*
+        * The first version of 82542 had an errata where when link was
+        * forced it would stay up even up even if the cable was disconnected.
+        * Sequence errors were used to detect the disconnect and then the
+        * driver would unforce the link.  This code in the in the ISR.  For
+        * this to work correctly the Sequence error interrupt had to be
+        * enabled all the time.
+        */
+       if (adapter->hw.mac_type == em_82542_rev2_0) {
+               E1000_WRITE_REG(&adapter->hw, IMC,
+                               (0xffffffff & ~E1000_IMC_RXSEQ));
+       } else {
+               E1000_WRITE_REG(&adapter->hw, IMC, 0xffffffff);
+       }
+
        lwkt_serialize_handler_disable(&adapter->serializer);
 }
 
@@ -2855,8 +2909,7 @@ em_update_stats_counters(struct adapter *adapter)
        /* Rx Errors */
        ifp->if_ierrors = adapter->dropped_pkts + adapter->stats.rxerrc +
            adapter->stats.crcerrs + adapter->stats.algnerrc +
-           adapter->stats.rlec + adapter->stats.rnbc +
-           adapter->stats.mpc + adapter->stats.cexterr;
+           adapter->stats.rlec + adapter->stats.mpc + adapter->stats.cexterr;
 
        /* Tx Errors */
        ifp->if_oerrors = adapter->stats.ecol + adapter->stats.latecol;
@@ -2877,6 +2930,10 @@ em_print_debug_info(struct adapter *adapter)
        uint8_t *hw_addr = adapter->hw.hw_addr;
 
        device_printf(dev, "Adapter hardware address = %p \n", hw_addr);
+       device_printf(dev, "CTRL  = 0x%x\n",
+                     E1000_READ_REG(&adapter->hw, CTRL)); 
+       device_printf(dev, "RCTL  = 0x%x PS=(0x8402)\n",
+                     E1000_READ_REG(&adapter->hw, RCTL)); 
        device_printf(dev, "tx_int_delay = %d, tx_abs_int_delay = %d\n",
                      E1000_READ_REG(&adapter->hw, TIDV),
                      E1000_READ_REG(&adapter->hw, TADV));
@@ -2889,8 +2946,8 @@ em_print_debug_info(struct adapter *adapter)
                      adapter->clean_tx_interrupts);
 #endif
        device_printf(dev, "fifo workaround = %lld, fifo_reset = %lld\n",
-                     (long long)adapter->tx_fifo_wrk,
-                     (long long)adapter->tx_fifo_reset);
+                     (long long)adapter->tx_fifo_wrk_cnt,
+                     (long long)adapter->tx_fifo_reset_cnt);
        device_printf(dev, "hw tdh = %d, hw tdt = %d\n",
                      E1000_READ_REG(&adapter->hw, TDH),
                      E1000_READ_REG(&adapter->hw, TDT));
index 3077cbb..78f0e0b 100644 (file)
@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
 ***************************************************************************/
 
 /*$FreeBSD: src/sys/dev/em/if_em.h,v 1.1.2.13 2003/06/09 21:43:41 pdeuskar Exp $*/
-/*$DragonFly: src/sys/dev/netif/em/if_em.h,v 1.10 2005/05/25 01:44:21 dillon Exp $*/
+/*$DragonFly: src/sys/dev/netif/em/if_em.h,v 1.11 2005/10/17 06:18:36 sephe Exp $*/
 
 #ifndef _EM_H_DEFINED_
 #define _EM_H_DEFINED_
@@ -333,7 +333,7 @@ struct adapter {
        struct arpcom   interface_data;
        struct em_hw    hw;
 
-       /* FreeBSD operating-system-specific structures */
+       /* Operating-system-specific structures */
        struct lwkt_serialize serializer;
        struct em_osdep osdep;
        struct device   *dev;
@@ -398,8 +398,6 @@ struct adapter {
        struct mbuf        *fmp;
        struct mbuf        *lmp;
 
-       u_int16_t          tx_fifo_head;
-
        struct sysctl_ctx_list sysctl_ctx;
         struct sysctl_oid *sysctl_tree;
 
@@ -411,8 +409,20 @@ struct adapter {
        unsigned long   no_tx_desc_avail2;
        unsigned long   no_tx_map_avail;
        unsigned long   no_tx_dma_setup;
-       u_int64_t       tx_fifo_reset;
-       u_int64_t       tx_fifo_wrk;
+
+       /* Used in for 82547 10Mb Half workaround */
+       u_int32_t       tx_fifo_size;
+       u_int32_t       tx_fifo_head;
+       u_int32_t       tx_fifo_head_addr;
+       u_int64_t       tx_fifo_reset_cnt;
+       u_int64_t       tx_fifo_wrk_cnt;
+       u_int32_t       tx_head_addr;
+
+#define EM_PBA_BYTES_SHIFT     0xA
+#define EM_TX_HEAD_ADDR_SHIFT  7
+#define EM_PBA_TX_MASK         0xFFFF0000
+#define EM_FIFO_HDR            0x10
+#define EM_82547_PKT_THRESH    0x3e0
  
        /* For 82544 PCIX Workaround */
        boolean_t pcix_82544;
@@ -421,9 +431,8 @@ struct adapter {
 #ifdef DBG_STATS
        unsigned long   no_pkts_avail;
        unsigned long   clean_tx_interrupts;
-
 #endif
        struct em_hw_stats stats;
 };
 
-#endif                                                  /* _EM_H_DEFINED_ */
+#endif /* !_EM_H_DEFINED_ */
index 4eb6b05..8195f97 100644 (file)
@@ -32,7 +32,7 @@
 *******************************************************************************/
 
 /*$FreeBSD: src/sys/dev/em/if_em_hw.c,v 1.1.2.8 2003/06/09 21:43:41 pdeuskar Exp $*/
-/*$DragonFly: src/sys/dev/netif/em/if_em_hw.c,v 1.6 2004/05/11 14:00:20 joerg Exp $*/
+/*$DragonFly: src/sys/dev/netif/em/if_em_hw.c,v 1.7 2005/10/17 06:18:36 sephe Exp $*/
 /* if_em_hw.c
  * Shared functions for accessing and configuring the MAC
  */
@@ -72,6 +72,7 @@ static void em_release_eeprom(struct em_hw *hw);
 static void em_standby_eeprom(struct em_hw *hw);
 static int32_t em_id_led_init(struct em_hw * hw);
 static int32_t em_set_vco_speed(struct em_hw *hw);
+static int32_t em_set_phy_mode(struct em_hw *hw);
 
 /* IGP cable length table */
 static const
@@ -257,6 +258,7 @@ em_set_mac_type(struct em_hw *hw)
         break;
     case E1000_DEV_ID_82541ER:
     case E1000_DEV_ID_82541GI:
+    case E1000_DEV_ID_82541GI_LF:
     case E1000_DEV_ID_82541GI_MOBILE:
         hw->mac_type = em_82541_rev_2;
         break;
@@ -906,6 +908,23 @@ em_setup_copper_link(struct em_hw *hw)
     }
     DEBUGOUT1("Phy ID = %x \n", hw->phy_id);
 
+    /* Set PHY to class A mode (if necessary) */
+    if ((ret_val = em_set_phy_mode(hw)))
+        return ret_val;
+
+    if((hw->mac_type == em_82545_rev_3) ||
+       (hw->mac_type == em_82546_rev_3)) {
+        ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+        if (ret_val)
+            return ret_val;
+
+        phy_data |= 0x00000008;
+
+        ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+        if (ret_val)
+            return ret_val;
+    }
+
     if(hw->mac_type <= em_82543 ||
        hw->mac_type == em_82541 || hw->mac_type == em_82547 ||
        hw->mac_type == em_82541_rev_2 || hw->mac_type == em_82547_rev_2)
@@ -1544,26 +1563,6 @@ em_phy_force_speed_duplex(struct em_hw *hw)
         if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
                                           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;
 }
@@ -1940,7 +1939,7 @@ em_config_fc_after_link_up(struct em_hw *hw)
 int32_t
 em_check_for_link(struct em_hw *hw)
 {
-    uint32_t rxcw;
+    uint32_t rxcw = 0;
     uint32_t ctrl;
     uint32_t status;
     uint32_t rctl;
@@ -1950,16 +1949,23 @@ em_check_for_link(struct em_hw *hw)
 
     DEBUGFUNC("em_check_for_link");
 
+    ctrl = E1000_READ_REG(hw, CTRL);
+    status = E1000_READ_REG(hw, STATUS);
+
     /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be
      * set when the optics detect a signal. On older adapters, it will be
      * cleared when there is a signal.  This applies to fiber media only.
      */
-    if(hw->media_type == em_media_type_fiber)
-        signal = (hw->mac_type > em_82544) ? E1000_CTRL_SWDPIN1 : 0;
+    if((hw->media_type == em_media_type_fiber) ||
+       (hw->media_type == em_media_type_internal_serdes)) {
+        rxcw = E1000_READ_REG(hw, RXCW);
 
-    ctrl = E1000_READ_REG(hw, CTRL);
-    status = E1000_READ_REG(hw, STATUS);
-    rxcw = E1000_READ_REG(hw, RXCW);
+        if(hw->media_type == em_media_type_fiber) {
+            signal = (hw->mac_type > em_82544) ? E1000_CTRL_SWDPIN1 : 0;
+            if(status & E1000_STATUS_LU)
+                hw->get_link_status = FALSE;
+        }
+    }
 
     /* If we have a copper PHY then we only want to go out to the PHY
      * registers to see if Auto-Neg has completed and/or if our link
@@ -2186,7 +2192,7 @@ em_get_speed_and_duplex(struct em_hw *hw,
         if(!(phy_data & NWAY_ER_LP_NWAY_CAPS))
             *duplex = HALF_DUPLEX;
         else {
-            if((ret_val == em_read_phy_reg(hw, PHY_LP_ABILITY, &phy_data)))
+            if((ret_val = em_read_phy_reg(hw, PHY_LP_ABILITY, &phy_data)))
                 return ret_val;
             if((*speed == SPEED_100 && !(phy_data & NWAY_LPAR_100TX_FD_CAPS)) ||
                (*speed == SPEED_10 && !(phy_data & NWAY_LPAR_10T_FD_CAPS)))
@@ -2907,6 +2913,12 @@ em_validate_mdi_setting(struct em_hw *hw)
 {
     DEBUGFUNC("em_validate_mdi_settings");
 
+#ifdef RK_SV
+    /* Don't disable MDI-X for 82570/1 */
+    if(hw->phy_type == em_phy_igp_2)
+        return E1000_SUCCESS;
+#endif
+
     if(!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) {
         DEBUGOUT("Invalid MDI setting detected\n");
         hw->mdix = 1;
@@ -3351,6 +3363,7 @@ em_spi_eeprom_ready(struct em_hw *hw)
         usec_delay(5);
         retry_count += 5;
 
+        em_standby_eeprom(hw);
     } while(retry_count < EEPROM_MAX_RETRY_SPI);
 
     /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and
@@ -4887,7 +4900,45 @@ em_config_dsp_after_link_change(struct em_hw *hw,
             if((ret_val = em_write_phy_reg(hw, 0x0000,
                                               IGP01E1000_IEEE_RESTART_AUTONEG)))
                 return ret_val;
-        hw->ffe_config_state = em_ffe_config_enabled;
+            hw->ffe_config_state = em_ffe_config_enabled;
+        }
+    }
+    return E1000_SUCCESS;
+}
+
+ /*****************************************************************************
+ * Set PHY to class A mode
+ * Assumes the following operations will follow to enable the new class mode.
+ *  1. Do a PHY soft reset
+ *  2. Restart auto-negotiation or force link.
+ *
+ * hw - Struct containing variables accessed by shared code
+ ****************************************************************************/
+static int32_t
+em_set_phy_mode(struct em_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t eeprom_data;
+
+    DEBUGFUNC("em_set_phy_mode");
+
+    if((hw->mac_type == em_82545_rev_3) &&
+       (hw->media_type == em_media_type_copper)) {
+        ret_val = em_read_eeprom(hw, EEPROM_PHY_CLASS_WORD, 1, &eeprom_data);
+        if(ret_val)
+            return ret_val;
+
+        if((eeprom_data != EEPROM_RESERVED_WORD) &&
+           (eeprom_data & EEPROM_PHY_CLASS_A)) {
+            ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x000B);
+            if(ret_val)
+                return ret_val;
+
+            ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x8104);
+            if(ret_val)
+                return ret_val;
+
+            hw->phy_reset_disable = FALSE;
         }
     }
     return E1000_SUCCESS;
index 8ceb26a..67aebe2 100644 (file)
@@ -32,7 +32,7 @@
 *******************************************************************************/
 
 /*$FreeBSD: src/sys/dev/em/if_em_hw.h,v 1.1.2.8 2003/06/09 21:43:41 pdeuskar Exp $*/
-/*$DragonFly: src/sys/dev/netif/em/if_em_hw.h,v 1.7 2004/05/11 22:55:15 joerg Exp $*/
+/*$DragonFly: src/sys/dev/netif/em/if_em_hw.h,v 1.8 2005/10/17 06:18:36 sephe Exp $*/
 /* if_em_hw.h
  * Structures, enums, and macros for the MAC
  */
@@ -360,6 +360,7 @@ void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value);
 #define E1000_DEV_ID_82541ER             0x1078
 #define E1000_DEV_ID_82547GI             0x1075
 #define E1000_DEV_ID_82541GI             0x1076
+#define E1000_DEV_ID_82541GI_LF          0x107C
 #define E1000_DEV_ID_82541GI_MOBILE      0x1077
 #define E1000_DEV_ID_82546GB_COPPER      0x1079
 #define E1000_DEV_ID_82546GB_FIBER       0x107A
@@ -374,6 +375,9 @@ void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value);
 
 #define E1000_82542_2_0_REV_ID 2
 #define E1000_82542_2_1_REV_ID 3
+#define E1000_REVISION_0       0
+#define E1000_REVISION_1       1
+#define E1000_REVISION_2       2
 
 #define SPEED_10    10
 #define SPEED_100   100
@@ -768,6 +772,7 @@ struct em_ffvt_entry {
 #define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
 #define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
 #define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF  0x08800  /* Host Interface */
 #define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
 #define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
 
@@ -904,6 +909,7 @@ struct em_ffvt_entry {
 #define E1000_82542_TDFT     0x08018
 #define E1000_82542_FFMT     E1000_FFMT
 #define E1000_82542_FFVT     E1000_FFVT
+#define E1000_82542_HOST_IF  E1000_HOST_IF
 
 /* Statistics counters collected by the MAC */
 struct em_hw_stats {
@@ -1440,6 +1446,10 @@ struct em_hw {
 #define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
 #define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
 #define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000 /* Enable MAC address
+                                                    * filtering */
+#define E1000_MANC_EN_MNG2HOST   0x00200000 /* Enable MNG packets to host
+                                             * memory */
 #define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
 #define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
 #define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
@@ -1486,6 +1496,7 @@ struct em_hw {
 #define EEPROM_COMPAT                 0x0003
 #define EEPROM_ID_LED_SETTINGS        0x0004
 #define EEPROM_SERDES_AMPLITUDE       0x0006 /* For SERDES output amplitude adjustment. */
+#define EEPROM_PHY_CLASS_WORD         0x0007
 #define EEPROM_INIT_CONTROL1_REG      0x000A
 #define EEPROM_INIT_CONTROL2_REG      0x000F
 #define EEPROM_INIT_CONTROL3_PORT_B   0x0014
@@ -1519,6 +1530,9 @@ struct em_hw {
 /* Mask bits for SERDES amplitude adjustment in Word 6 of the EEPROM */
 #define EEPROM_SERDES_AMPLITUDE_MASK  0x000F
 
+/* Mask bit for PHY class in Word 7 of the EEPROM */
+#define EEPROM_PHY_CLASS_A   0x8000
+
 /* Mask bits for fields in Word 0x0a of the EEPROM */
 #define EEPROM_WORD0A_ILOS   0x0010
 #define EEPROM_WORD0A_SWDPIO 0x01E0
@@ -1546,7 +1560,7 @@ struct em_hw {
 #define PBA_SIZE 4
 
 /* Collision related configuration parameters */
-#define E1000_COLLISION_THRESHOLD       16
+#define E1000_COLLISION_THRESHOLD       15
 #define E1000_CT_SHIFT                  4
 #define E1000_COLLISION_DISTANCE        64
 #define E1000_FDX_COLLISION_DISTANCE    E1000_COLLISION_DISTANCE
@@ -2012,7 +2026,7 @@ struct em_hw {
 #define IGP01E1000_PSSR_MDIX_SHIFT             0x000B /* shift right 11 */
 
 /* IGP01E1000 Specific Port Control Register - R/W */
-#define IGP01E1000_PSCR_TP_LOOPBACK            0x0001
+#define IGP01E1000_PSCR_TP_LOOPBACK            0x0010
 #define IGP01E1000_PSCR_CORRECT_NC_SCMBLR      0x0200
 #define IGP01E1000_PSCR_TEN_CRS_SELECT         0x0400
 #define IGP01E1000_PSCR_FLIP_CHIP              0x0800
@@ -2022,16 +2036,18 @@ struct em_hw {
 /* IGP01E1000 Specific Port Link Health Register */
 #define IGP01E1000_PLHR_SS_DOWNGRADE           0x8000
 #define IGP01E1000_PLHR_GIG_SCRAMBLER_ERROR    0x4000
+#define IGP01E1000_PLHR_MASTER_FAULT           0x2000
+#define IGP01E1000_PLHR_MASTER_RESOLUTION      0x1000
 #define IGP01E1000_PLHR_GIG_REM_RCVR_NOK       0x0800 /* LH */
 #define IGP01E1000_PLHR_IDLE_ERROR_CNT_OFLOW   0x0400 /* LH */
 #define IGP01E1000_PLHR_DATA_ERR_1             0x0200 /* LH */
 #define IGP01E1000_PLHR_DATA_ERR_0             0x0100
-#define IGP01E1000_PLHR_AUTONEG_FAULT          0x0010
-#define IGP01E1000_PLHR_AUTONEG_ACTIVE         0x0008
-#define IGP01E1000_PLHR_VALID_CHANNEL_D        0x0004
-#define IGP01E1000_PLHR_VALID_CHANNEL_C        0x0002
-#define IGP01E1000_PLHR_VALID_CHANNEL_B        0x0001
-#define IGP01E1000_PLHR_VALID_CHANNEL_A        0x0000
+#define IGP01E1000_PLHR_AUTONEG_FAULT          0x0040
+#define IGP01E1000_PLHR_AUTONEG_ACTIVE         0x0010
+#define IGP01E1000_PLHR_VALID_CHANNEL_D        0x0008
+#define IGP01E1000_PLHR_VALID_CHANNEL_C        0x0004
+#define IGP01E1000_PLHR_VALID_CHANNEL_B        0x0002
+#define IGP01E1000_PLHR_VALID_CHANNEL_A        0x0001
 
 /* IGP01E1000 Channel Quality Register */
 #define IGP01E1000_MSE_CHANNEL_D        0x000F