em(4)/emx(4): Update to Intel's 7.1.7
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 28 Jun 2011 05:45:01 +0000 (13:45 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 28 Jun 2011 05:45:01 +0000 (13:45 +0800)
- Restore stock version of e1000_read_mac_addr_generic(); if this function
  is called after hardware reset, it just works as expected.
- For em(4), add 82567/82577/82578/82579/82583, PCH and PCH2 support.
- For em(4) and emx(4)
  o  Reorganize hardware initialization sequence
  o  Fix ITR and EIAC settings for 82574
  o  Fix hardware control support for chips with AMT

sys/dev/netif/em/if_em.c
sys/dev/netif/em/if_em.h
sys/dev/netif/emx/if_emx.c
sys/dev/netif/emx/if_emx.h
sys/dev/netif/ig_hal/e1000_nvm.c

index 744306e..c319d52 100644 (file)
 #include <dev/netif/em/if_em.h>
 
 #define EM_NAME        "Intel(R) PRO/1000 Network Connection "
-#define EM_VER " 6.9.6"
+#define EM_VER " 7.1.7"
 
 #define _EM_DEVICE(id, ret)    \
        { EM_VENDOR_ID, E1000_DEV_ID_##id, ret, EM_NAME #id EM_VER }
@@ -208,6 +208,8 @@ static const struct em_vendor_info em_vendor_info_array[] = {
        EM_EMX_DEVICE(82573E_IAMT),
        EM_EMX_DEVICE(82573L),
 
+       EM_DEVICE(82583V),
+
        EM_EMX_DEVICE(80003ES2LAN_COPPER_SPT),
        EM_EMX_DEVICE(80003ES2LAN_SERDES_SPT),
        EM_EMX_DEVICE(80003ES2LAN_COPPER_DPT),
@@ -220,6 +222,7 @@ static const struct em_vendor_info em_vendor_info_array[] = {
        EM_DEVICE(ICH8_IFE_GT),
        EM_DEVICE(ICH8_IFE_G),
        EM_DEVICE(ICH8_IGP_M),
+       EM_DEVICE(ICH8_82567V_3),
 
        EM_DEVICE(ICH9_IGP_M_AMT),
        EM_DEVICE(ICH9_IGP_AMT),
@@ -232,12 +235,22 @@ static const struct em_vendor_info em_vendor_info_array[] = {
        EM_DEVICE(ICH9_BM),
 
        EM_EMX_DEVICE(82574L),
+       EM_EMX_DEVICE(82574LA),
 
        EM_DEVICE(ICH10_R_BM_LM),
        EM_DEVICE(ICH10_R_BM_LF),
        EM_DEVICE(ICH10_R_BM_V),
        EM_DEVICE(ICH10_D_BM_LM),
        EM_DEVICE(ICH10_D_BM_LF),
+       EM_DEVICE(ICH10_D_BM_V),
+
+       EM_DEVICE(PCH_M_HV_LM),
+       EM_DEVICE(PCH_M_HV_LC),
+       EM_DEVICE(PCH_D_HV_DM),
+       EM_DEVICE(PCH_D_HV_DC),
+
+       EM_DEVICE(PCH2_LV_LM),
+       EM_DEVICE(PCH2_LV_V),
 
        /* required last entry */
        EM_DEVICE_NULL
@@ -291,7 +304,7 @@ static int  em_get_hw_info(struct adapter *);
 static int     em_is_valid_eaddr(const uint8_t *);
 static int     em_alloc_pci_res(struct adapter *);
 static void    em_free_pci_res(struct adapter *);
-static int     em_hw_init(struct adapter *);
+static int     em_reset(struct adapter *);
 static void    em_setup_ifp(struct adapter *);
 static void    em_init_tx_unit(struct adapter *);
 static void    em_init_rx_unit(struct adapter *);
@@ -301,6 +314,7 @@ static void em_disable_promisc(struct adapter *);
 static void    em_set_multi(struct adapter *);
 static void    em_update_link_status(struct adapter *);
 static void    em_smartspeed(struct adapter *);
+static void    em_set_itr(struct adapter *, uint32_t);
 
 /* Hardware workarounds */
 static int     em_82547_fifo_workaround(struct adapter *, int);
@@ -413,7 +427,7 @@ em_attach(device_t dev)
        struct ifnet *ifp = &adapter->arpcom.ac_if;
        int tsize, rsize;
        int error = 0;
-       uint16_t eeprom_data, device_id;
+       uint16_t eeprom_data, device_id, apme_mask;
 
        adapter->dev = adapter->osdep.dev = dev;
 
@@ -439,8 +453,10 @@ em_attach(device_t dev)
         * and this must happen after the MAC is identified.
         */
        if (adapter->hw.mac.type == e1000_ich8lan ||
+           adapter->hw.mac.type == e1000_ich9lan ||
            adapter->hw.mac.type == e1000_ich10lan ||
-           adapter->hw.mac.type == e1000_ich9lan) {
+           adapter->hw.mac.type == e1000_pchlan ||
+           adapter->hw.mac.type == e1000_pch2lan) {
                adapter->flash_rid = EM_BAR_FLASH;
 
                adapter->flash = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
@@ -577,6 +593,22 @@ em_attach(device_t dev)
        }
        adapter->rx_desc_base = adapter->rxdma.dma_vaddr;
 
+       /* Allocate multicast array memory. */
+       adapter->mta = kmalloc(ETH_ADDR_LEN * MAX_NUM_MULTICAST_ADDRESSES,
+           M_DEVBUF, M_WAITOK);
+
+       /* Indicate SOL/IDER usage */
+       if (e1000_check_reset_block(&adapter->hw)) {
+               device_printf(dev,
+                   "PHY reset is blocked due to SOL/IDER session.\n");
+       }
+
+       /*
+        * Start from a known state, this is important in reading the
+        * nvm and mac from that.
+        */
+       e1000_reset_hw(&adapter->hw);
+
        /* Make sure we have a good EEPROM before we read from it */
        if (e1000_validate_nvm_checksum(&adapter->hw) < 0) {
                /*
@@ -592,13 +624,6 @@ em_attach(device_t dev)
                }
        }
 
-       /* Initialize the hardware */
-       error = em_hw_init(adapter);
-       if (error) {
-               device_printf(dev, "Unable to initialize the hardware\n");
-               goto fail;
-       }
-
        /* Copy the permanent MAC address out of the EEPROM */
        if (e1000_read_mac_addr(&adapter->hw) < 0) {
                device_printf(dev, "EEPROM read error while reading MAC"
@@ -629,38 +654,28 @@ em_attach(device_t dev)
        /* Manually turn off all interrupts */
        E1000_WRITE_REG(&adapter->hw, E1000_IMC, 0xffffffff);
 
-       /* Setup OS specific network interface */
-       em_setup_ifp(adapter);
-
-       /* Add sysctl tree, must after em_setup_ifp() */
-       em_add_sysctl(adapter);
-
-       /* Initialize statistics */
-       em_update_stats(adapter);
-
-       adapter->hw.mac.get_link_status = 1;
-       em_update_link_status(adapter);
-
-       /* Indicate SOL/IDER usage */
-       if (e1000_check_reset_block(&adapter->hw)) {
-               device_printf(dev,
-                   "PHY reset is blocked due to SOL/IDER session.\n");
-       }
-
        /* Determine if we have to control management hardware */
        adapter->has_manage = e1000_enable_mng_pass_thru(&adapter->hw);
 
        /*
         * Setup Wake-on-Lan
         */
+       apme_mask = EM_EEPROM_APME;
+       eeprom_data = 0;
        switch (adapter->hw.mac.type) {
        case e1000_82542:
        case e1000_82543:
                break;
 
+       case e1000_82573:
+       case e1000_82583:
+               adapter->has_amt = 1;
+               /* FALL THROUGH */
+
        case e1000_82546:
        case e1000_82546_rev_3:
        case e1000_82571:
+       case e1000_82572:
        case e1000_80003es2lan:
                if (adapter->hw.bus.func == 1) {
                        e1000_read_nvm(&adapter->hw,
@@ -669,17 +684,26 @@ em_attach(device_t dev)
                        e1000_read_nvm(&adapter->hw,
                            NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
                }
-               eeprom_data &= EM_EEPROM_APME;
+               break;
+
+       case e1000_ich8lan:
+       case e1000_ich9lan:
+       case e1000_ich10lan:
+       case e1000_pchlan:
+       case e1000_pch2lan:
+               apme_mask = E1000_WUC_APME;
+               adapter->has_amt = TRUE;
+               eeprom_data = E1000_READ_REG(&adapter->hw, E1000_WUC);
                break;
 
        default:
-               /* APME bit in EEPROM is mapped to WUC.APME */
-               eeprom_data =
-                   E1000_READ_REG(&adapter->hw, E1000_WUC) & E1000_WUC_APME;
+               e1000_read_nvm(&adapter->hw,
+                   NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
                break;
        }
-       if (eeprom_data)
-               adapter->wol = E1000_WUFC_MAG;
+       if (eeprom_data & apme_mask)
+               adapter->wol = E1000_WUFC_MAG | E1000_WUFC_MC;
+
        /*
          * We have the eeprom settings, now apply the special cases
          * where the eeprom may be wrong or the board won't support
@@ -719,6 +743,25 @@ em_attach(device_t dev)
        /* XXX disable wol */
        adapter->wol = 0;
 
+       /* Setup OS specific network interface */
+       em_setup_ifp(adapter);
+
+       /* Add sysctl tree, must after em_setup_ifp() */
+       em_add_sysctl(adapter);
+
+       /* Reset the hardware */
+       error = em_reset(adapter);
+       if (error) {
+               device_printf(dev, "Unable to reset the hardware\n");
+               goto fail;
+       }
+
+       /* Initialize statistics */
+       em_update_stats(adapter);
+
+       adapter->hw.mac.get_link_status = 1;
+       em_update_link_status(adapter);
+
        /* Do we need workaround for 82544 PCI-X adapter? */
        if (adapter->hw.bus.type == e1000_bus_type_pcix &&
            adapter->hw.mac.type == e1000_82544)
@@ -753,6 +796,11 @@ em_attach(device_t dev)
        if (adapter->tx_int_nsegs < adapter->oact_tx_desc)
                adapter->tx_int_nsegs = adapter->oact_tx_desc;
 
+       /* Non-AMT based hardware can now take control from firmware */
+       if (adapter->has_manage && !adapter->has_amt &&
+           adapter->hw.mac.type >= e1000_82571)
+               em_get_hw_control(adapter);
+
        error = bus_setup_intr(dev, adapter->intr_res, INTR_MPSAFE,
                               em_intr, adapter, &adapter->intr_tag,
                               ifp->if_serializer);
@@ -785,13 +833,7 @@ em_detach(device_t dev)
                e1000_phy_hw_reset(&adapter->hw);
 
                em_rel_mgmt(adapter);
-
-               if ((adapter->hw.mac.type == e1000_82573 ||
-                    adapter->hw.mac.type == e1000_ich8lan ||
-                    adapter->hw.mac.type == e1000_ich10lan ||
-                    adapter->hw.mac.type == e1000_ich9lan) &&
-                   e1000_check_mng_mode(&adapter->hw))
-                       em_rel_hw_control(adapter);
+               em_rel_hw_control(adapter);
 
                if (adapter->wol) {
                        E1000_WRITE_REG(&adapter->hw, E1000_WUC,
@@ -805,6 +847,8 @@ em_detach(device_t dev)
                lwkt_serialize_exit(ifp->if_serializer);
 
                ether_ifdetach(ifp);
+       } else {
+               em_rel_hw_control(adapter);
        }
        bus_generic_detach(dev);
 
@@ -849,19 +893,13 @@ em_suspend(device_t dev)
        em_stop(adapter);
 
        em_rel_mgmt(adapter);
+       em_rel_hw_control(adapter);
 
-        if ((adapter->hw.mac.type == e1000_82573 ||
-             adapter->hw.mac.type == e1000_ich8lan ||
-             adapter->hw.mac.type == e1000_ich10lan ||
-             adapter->hw.mac.type == e1000_ich9lan) &&
-            e1000_check_mng_mode(&adapter->hw))
-                em_rel_hw_control(adapter);
-
-        if (adapter->wol) {
+       if (adapter->wol) {
                E1000_WRITE_REG(&adapter->hw, E1000_WUC, E1000_WUC_PME_EN);
                E1000_WRITE_REG(&adapter->hw, E1000_WUFC, adapter->wol);
                em_enable_wol(dev);
-        }
+       }
 
        lwkt_serialize_exit(ifp->if_serializer);
 
@@ -963,13 +1001,19 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
                case e1000_82572:
                case e1000_ich9lan:
                case e1000_ich10lan:
+               case e1000_pch2lan:
                case e1000_82574:
                case e1000_80003es2lan:
                        max_frame_size = 9234;
                        break;
 
+               case e1000_pchlan:
+                       max_frame_size = 4096;
+                       break;
+
                /* Adapters that do not support jumbo frames */
                case e1000_82542:
+               case e1000_82583:
                case e1000_ich8lan:
                        max_frame_size = ETHER_MAX_LEN;
                        break;
@@ -1156,17 +1200,23 @@ em_init(void *xsc)
                break;
 
        case e1000_82574:
+       case e1000_82583:
                pba = E1000_PBA_20K; /* 20K for Rx, 20K for Tx */
                break;
 
+       case e1000_ich8lan:
+               pba = E1000_PBA_8K;
+               break;
+
        case e1000_ich9lan:
        case e1000_ich10lan:
 #define E1000_PBA_10K  0x000A
                pba = E1000_PBA_10K;
                break;
 
-       case e1000_ich8lan:
-               pba = E1000_PBA_8K;
+       case e1000_pchlan:
+       case e1000_pch2lan:
+               pba = E1000_PBA_26K;
                break;
 
        default:
@@ -1196,9 +1246,9 @@ em_init(void *xsc)
                    E1000_RAR_ENTRIES - 1);
        }
 
-       /* Initialize the hardware */
-       if (em_hw_init(adapter)) {
-               device_printf(dev, "Unable to initialize the hardware\n");
+       /* Reset the hardware */
+       if (em_reset(adapter)) {
+               device_printf(dev, "Unable to reset the hardware\n");
                /* XXX em_stop()? */
                return;
        }
@@ -1256,6 +1306,7 @@ em_init(void *xsc)
                tmp |= E1000_CTRL_EXT_PBA_CLR;
                E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, tmp);
                /*
+                * XXX MSIX
                 * Set the IVAR - interrupt vector routing.
                 * Each nibble represents a vector, high bit
                 * is enable, other 3 bits are the MSIX table
@@ -1276,6 +1327,11 @@ em_init(void *xsc)
 #endif /* DEVICE_POLLING */
                em_enable_intr(adapter);
 
+       /* AMT based hardware can now take control from firmware */
+       if (adapter->has_manage && adapter->has_amt &&
+           adapter->hw.mac.type >= e1000_82571)
+               em_get_hw_control(adapter);
+
        /* Don't reset the phy next time init gets called */
        adapter->hw.phy.reset_disable = TRUE;
 }
@@ -1826,9 +1882,12 @@ em_set_multi(struct adapter *adapter)
        struct ifnet *ifp = &adapter->arpcom.ac_if;
        struct ifmultiaddr *ifma;
        uint32_t reg_rctl = 0;
-       uint8_t  mta[512]; /* Largest MTS is 4096 bits */
+       uint8_t *mta;
        int mcnt = 0;
 
+       mta = adapter->mta;
+       bzero(mta, ETH_ADDR_LEN * MAX_NUM_MULTICAST_ADDRESSES);
+
        if (adapter->hw.mac.type == e1000_82542 && 
            adapter->hw.revision_id == E1000_REVISION_2) {
                reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL);
@@ -1945,15 +2004,13 @@ em_update_link_status(struct adapter *adapter)
                 * Check if we should enable/disable SPEED_MODE bit on
                 * 82571/82572
                 */
-               if (hw->mac.type == e1000_82571 ||
-                   hw->mac.type == e1000_82572) {
+               if (adapter->link_speed != SPEED_1000 &&
+                   (hw->mac.type == e1000_82571 ||
+                    hw->mac.type == e1000_82572)) {
                        int tarc0;
 
                        tarc0 = E1000_READ_REG(hw, E1000_TARC(0));
-                       if (adapter->link_speed != SPEED_1000)
-                               tarc0 &= ~SPEED_MODE_BIT;
-                       else
-                               tarc0 |= SPEED_MODE_BIT;
+                       tarc0 &= ~SPEED_MODE_BIT;
                        E1000_WRITE_REG(hw, E1000_TARC(0), tarc0);
                }
                if (bootverbose) {
@@ -2153,22 +2210,11 @@ em_free_pci_res(struct adapter *adapter)
 }
 
 static int
-em_hw_init(struct adapter *adapter)
+em_reset(struct adapter *adapter)
 {
        device_t dev = adapter->dev;
        uint16_t rx_buffer_size;
 
-       /* Issue a global reset */
-       e1000_reset_hw(&adapter->hw);
-
-       /* Get control from any management/hw control */
-       if ((adapter->hw.mac.type == e1000_82573 ||
-            adapter->hw.mac.type == e1000_ich8lan ||
-            adapter->hw.mac.type == e1000_ich10lan ||
-            adapter->hw.mac.type == e1000_ich9lan) &&
-           e1000_check_mng_mode(&adapter->hw))
-               em_get_hw_control(adapter);
-
        /* When hardware is reset, fifo_head is also reset */
        adapter->tx_fifo_head = 0;
 
@@ -2211,14 +2257,41 @@ em_hw_init(struct adapter *adapter)
                adapter->hw.fc.pause_time = 0xFFFF;
        else
                adapter->hw.fc.pause_time = EM_FC_PAUSE_TIME;
+
        adapter->hw.fc.send_xon = TRUE;
+
        adapter->hw.fc.requested_mode = e1000_fc_full;
 
+       /* Workaround: no TX flow ctrl for PCH */
+       if (adapter->hw.mac.type == e1000_pchlan)
+               adapter->hw.fc.requested_mode = e1000_fc_rx_pause;
+
+       /* Override - settings for PCH2LAN, ya its magic :) */
+       if (adapter->hw.mac.type == e1000_pch2lan) {
+               adapter->hw.fc.high_water = 0x5C20;
+               adapter->hw.fc.low_water = 0x5048;
+               adapter->hw.fc.pause_time = 0x0650;
+               adapter->hw.fc.refresh_time = 0x0400;
+
+               /* Jumbos need adjusted PBA */
+               if (adapter->arpcom.ac_if.if_mtu > ETHERMTU)
+                       E1000_WRITE_REG(&adapter->hw, E1000_PBA, 12);
+               else
+                       E1000_WRITE_REG(&adapter->hw, E1000_PBA, 26);
+       }
+
+       /* Issue a global reset */
+       e1000_reset_hw(&adapter->hw);
+       if (adapter->hw.mac.type >= e1000_82544)
+               E1000_WRITE_REG(&adapter->hw, E1000_WUC, 0);
+
        if (e1000_init_hw(&adapter->hw) < 0) {
                device_printf(dev, "Hardware Initialization Failed\n");
                return (EIO);
        }
 
+       E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN);
+       e1000_get_phy_info(&adapter->hw);
        e1000_check_for_link(&adapter->hw);
 
        return (0);
@@ -3030,7 +3103,7 @@ em_init_rx_unit(struct adapter *adapter)
 {
        struct ifnet *ifp = &adapter->arpcom.ac_if;
        uint64_t bus_addr;
-       uint32_t rctl, rxcsum;
+       uint32_t rctl;
 
        /*
         * Make sure receives are disabled while setting
@@ -3040,16 +3113,17 @@ em_init_rx_unit(struct adapter *adapter)
        E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl & ~E1000_RCTL_EN);
 
        if (adapter->hw.mac.type >= e1000_82540) {
+               uint32_t itr;
+
                /*
                 * Set the interrupt throttling rate. Value is calculated
                 * as ITR = 1 / (INT_THROTTLE_CEIL * 256ns)
                 */
-               if (adapter->int_throttle_ceil) {
-                       E1000_WRITE_REG(&adapter->hw, E1000_ITR,
-                               1000000000 / 256 / adapter->int_throttle_ceil);
-               } else {
-                       E1000_WRITE_REG(&adapter->hw, E1000_ITR, 0);
-               }
+               if (adapter->int_throttle_ceil)
+                       itr = 1000000000 / 256 / adapter->int_throttle_ceil;
+               else
+                       itr = 0;
+               em_set_itr(adapter, itr);
        }
 
        /* Disable accelerated ackknowledge */
@@ -3058,7 +3132,30 @@ em_init_rx_unit(struct adapter *adapter)
                    E1000_RFCTL, E1000_RFCTL_ACK_DIS);
        }
 
-       /* Setup the Base and Length of the Rx Descriptor Ring */
+       /* Receive Checksum Offload for TCP and UDP */
+       if (ifp->if_capenable & IFCAP_RXCSUM) {
+               uint32_t rxcsum;
+
+               rxcsum = E1000_READ_REG(&adapter->hw, E1000_RXCSUM);
+               rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL);
+               E1000_WRITE_REG(&adapter->hw, E1000_RXCSUM, rxcsum);
+       }
+
+       /*
+        * XXX TEMPORARY WORKAROUND: on some systems with 82573
+        * long latencies are observed, like Lenovo X60. This
+        * change eliminates the problem, but since having positive
+        * values in RDTR is a known source of problems on other
+        * platforms another solution is being sought.
+        */
+       if (em_82573_workaround && adapter->hw.mac.type == e1000_82573) {
+               E1000_WRITE_REG(&adapter->hw, E1000_RADV, EM_RADV_82573);
+               E1000_WRITE_REG(&adapter->hw, E1000_RDTR, EM_RDTR_82573);
+       }
+
+       /*
+        * Setup the Base and Length of the Rx Descriptor Ring
+        */
        bus_addr = adapter->rxdma.dma_paddr;
        E1000_WRITE_REG(&adapter->hw, E1000_RDLEN(0),
            adapter->num_rx_desc * sizeof(struct e1000_rx_desc));
@@ -3067,6 +3164,31 @@ em_init_rx_unit(struct adapter *adapter)
        E1000_WRITE_REG(&adapter->hw, E1000_RDBAL(0),
            (uint32_t)bus_addr);
 
+       /*
+        * Setup the HW Rx Head and Tail Descriptor Pointers
+        */
+       E1000_WRITE_REG(&adapter->hw, E1000_RDH(0), 0);
+       E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), adapter->num_rx_desc - 1);
+
+       /* Set early receive threshold on appropriate hw */
+       if (((adapter->hw.mac.type == e1000_ich9lan) ||
+           (adapter->hw.mac.type == e1000_pch2lan) ||
+           (adapter->hw.mac.type == e1000_ich10lan)) &&
+           (ifp->if_mtu > ETHERMTU)) {
+               uint32_t rxdctl;
+
+               rxdctl = E1000_READ_REG(&adapter->hw, E1000_RXDCTL(0));
+               E1000_WRITE_REG(&adapter->hw, E1000_RXDCTL(0), rxdctl | 3);
+               E1000_WRITE_REG(&adapter->hw, E1000_ERT, 0x100 | (1 << 13));
+       }
+
+       if (adapter->hw.mac.type == e1000_pch2lan) {
+               if (ifp->if_mtu > ETHERMTU)
+                       e1000_lv_jumbo_workaround_ich8lan(&adapter->hw, TRUE);
+               else
+                       e1000_lv_jumbo_workaround_ich8lan(&adapter->hw, FALSE);
+       }
+
        /* Setup the Receive Control Register */
        rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
        rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO |
@@ -3108,31 +3230,6 @@ em_init_rx_unit(struct adapter *adapter)
        else
                rctl &= ~E1000_RCTL_LPE;
 
-       /* Receive Checksum Offload for TCP and UDP */
-       if (ifp->if_capenable & IFCAP_RXCSUM) {
-               rxcsum = E1000_READ_REG(&adapter->hw, E1000_RXCSUM);
-               rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL);
-               E1000_WRITE_REG(&adapter->hw, E1000_RXCSUM, rxcsum);
-       }
-
-       /*
-        * XXX TEMPORARY WORKAROUND: on some systems with 82573
-        * long latencies are observed, like Lenovo X60. This
-        * change eliminates the problem, but since having positive
-        * values in RDTR is a known source of problems on other
-        * platforms another solution is being sought.
-        */
-       if (em_82573_workaround && adapter->hw.mac.type == e1000_82573) {
-               E1000_WRITE_REG(&adapter->hw, E1000_RADV, EM_RADV_82573);
-               E1000_WRITE_REG(&adapter->hw, E1000_RDTR, EM_RDTR_82573);
-       }
-
-       /*
-        * Setup the HW Rx Head and Tail Descriptor Pointers
-        */
-       E1000_WRITE_REG(&adapter->hw, E1000_RDH(0), 0);
-       E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), adapter->num_rx_desc - 1);
-
        /* Enable Receives */
        E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl);
 }
@@ -3353,8 +3450,18 @@ em_rxcsum(struct adapter *adapter, struct e1000_rx_desc *rx_desc,
 static void
 em_enable_intr(struct adapter *adapter)
 {
+       uint32_t ims_mask = IMS_ENABLE_MASK;
+
        lwkt_serialize_handler_enable(adapter->arpcom.ac_if.if_serializer);
-       E1000_WRITE_REG(&adapter->hw, E1000_IMS, IMS_ENABLE_MASK);
+
+#if 0
+       /* XXX MSIX */
+       if (adapter->hw.mac.type == e1000_82574) {
+               E1000_WRITE_REG(&adapter->hw, EM_EIAC, EM_MSIX_MASK);
+               ims_mask |= EM_MSIX_MASK;
+        }
+#endif
+       E1000_WRITE_REG(&adapter->hw, E1000_IMS, ims_mask);
 }
 
 static void
@@ -3373,6 +3480,8 @@ em_disable_intr(struct adapter *adapter)
        if (adapter->hw.mac.type == e1000_82542 &&
            adapter->hw.revision_id == E1000_REVISION_2)
                clear &= ~E1000_IMC_RXSEQ;
+       else if (adapter->hw.mac.type == e1000_82574)
+               E1000_WRITE_REG(&adapter->hw, EM_EIAC, 0);
 
        E1000_WRITE_REG(&adapter->hw, E1000_IMC, clear);
 
@@ -3439,28 +3548,21 @@ em_rel_mgmt(struct adapter *adapter)
 static void
 em_get_hw_control(struct adapter *adapter)
 {
-       uint32_t ctrl_ext, swsm;
-
        /* Let firmware know the driver has taken over */
-       switch (adapter->hw.mac.type) {
-       case e1000_82573:
+       if (adapter->hw.mac.type == e1000_82573) {
+               uint32_t swsm;
+
                swsm = E1000_READ_REG(&adapter->hw, E1000_SWSM);
                E1000_WRITE_REG(&adapter->hw, E1000_SWSM,
                    swsm | E1000_SWSM_DRV_LOAD);
-               break;
-       case e1000_82571:
-       case e1000_82572:
-       case e1000_80003es2lan:
-       case e1000_ich8lan:
-       case e1000_ich9lan:
-       case e1000_ich10lan:
+       } else {
+               uint32_t ctrl_ext;
+
                ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT);
                E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT,
                    ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
-               break;
-       default:
-               break;
        }
+       adapter->control_hw = 1;
 }
 
 /*
@@ -3472,29 +3574,23 @@ em_get_hw_control(struct adapter *adapter)
 static void
 em_rel_hw_control(struct adapter *adapter)
 {
-       uint32_t ctrl_ext, swsm;
+       if (!adapter->control_hw)
+               return;
+       adapter->control_hw = 0;
 
        /* Let firmware taken over control of h/w */
-       switch (adapter->hw.mac.type) {
-       case e1000_82573:
+       if (adapter->hw.mac.type == e1000_82573) {
+               uint32_t swsm;
+
                swsm = E1000_READ_REG(&adapter->hw, E1000_SWSM);
                E1000_WRITE_REG(&adapter->hw, E1000_SWSM,
                    swsm & ~E1000_SWSM_DRV_LOAD);
-               break;
+       } else {
+               uint32_t ctrl_ext;
 
-       case e1000_82571:
-       case e1000_82572:
-       case e1000_80003es2lan:
-       case e1000_ich8lan:
-       case e1000_ich9lan:
-       case e1000_ich10lan:
                ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT);
                E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT,
                    ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
-               break;
-
-       default:
-               break;
        }
 }
 
@@ -3948,7 +4044,7 @@ em_sysctl_int_throttle(SYSCTL_HANDLER_ARGS)
                adapter->int_throttle_ceil = 0;
 
        if (ifp->if_flags & IFF_RUNNING)
-               E1000_WRITE_REG(&adapter->hw, E1000_ITR, throttle);
+               em_set_itr(adapter, throttle);
 
        lwkt_serialize_exit(ifp->if_serializer);
 
@@ -3995,3 +4091,21 @@ em_sysctl_int_tx_nsegs(SYSCTL_HANDLER_ARGS)
 
        return error;
 }
+
+static void
+em_set_itr(struct adapter *adapter, uint32_t itr)
+{
+       E1000_WRITE_REG(&adapter->hw, E1000_ITR, itr);
+       if (adapter->hw.mac.type == e1000_82574) {
+               int i;
+
+               /*
+                * When using MSIX interrupts we need to
+                * throttle using the EITR register
+                */
+               for (i = 0; i < 4; ++i) {
+                       E1000_WRITE_REG(&adapter->hw,
+                           E1000_EITR_82574(i), itr);
+               }
+       }
+}
index d532e95..a45f801 100644 (file)
@@ -276,6 +276,11 @@ struct adapter {
        /* Management and WOL features */
        int                     wol;
        int                     has_manage;
+       int                     has_amt;
+       int                     control_hw;
+
+       /* Multicast array memory */
+       uint8_t                 *mta;
 
        /* Info about the board itself */
        uint8_t                 link_active;
index fbb631f..a72745c 100644 (file)
@@ -158,6 +158,7 @@ static const struct emx_device {
        EMX_DEVICE(80003ES2LAN_SERDES_DPT),
 
        EMX_DEVICE(82574L),
+       EMX_DEVICE(82574LA),
 
        /* required last entry */
        EMX_DEVICE_NULL
@@ -214,7 +215,7 @@ static int  emx_txcsum(struct emx_softc *, struct mbuf *,
                    uint32_t *, uint32_t *);
 
 static int     emx_is_valid_eaddr(const uint8_t *);
-static int     emx_hw_init(struct emx_softc *);
+static int     emx_reset(struct emx_softc *);
 static void    emx_setup_ifp(struct emx_softc *);
 static void    emx_init_tx_unit(struct emx_softc *);
 static void    emx_init_rx_unit(struct emx_softc *);
@@ -224,6 +225,7 @@ static void emx_disable_promisc(struct emx_softc *);
 static void    emx_set_multi(struct emx_softc *);
 static void    emx_update_link_status(struct emx_softc *);
 static void    emx_smartspeed(struct emx_softc *);
+static void    emx_set_itr(struct emx_softc *, uint32_t);
 
 static void    emx_print_debug_info(struct emx_softc *);
 static void    emx_print_nvm_info(struct emx_softc *);
@@ -397,7 +399,7 @@ emx_attach(device_t dev)
        struct emx_softc *sc = device_get_softc(dev);
        struct ifnet *ifp = &sc->arpcom.ac_if;
        int error = 0, i;
-       uint16_t eeprom_data, device_id;
+       uint16_t eeprom_data, device_id, apme_mask;
 
        lwkt_serialize_init(&sc->main_serialize);
        lwkt_serialize_init(&sc->tx_serialize);
@@ -526,6 +528,22 @@ emx_attach(device_t dev)
        if (error)
                goto fail;
 
+       /* Allocate multicast array memory. */
+       sc->mta = kmalloc(ETH_ADDR_LEN * EMX_MCAST_ADDR_MAX,
+           M_DEVBUF, M_WAITOK);
+
+       /* Indicate SOL/IDER usage */
+       if (e1000_check_reset_block(&sc->hw)) {
+               device_printf(dev,
+                   "PHY reset is blocked due to SOL/IDER session.\n");
+       }
+
+       /*
+        * Start from a known state, this is important in reading the
+        * nvm and mac from that.
+        */
+       e1000_reset_hw(&sc->hw);
+
        /* Make sure we have a good EEPROM before we read from it */
        if (e1000_validate_nvm_checksum(&sc->hw) < 0) {
                /*
@@ -541,13 +559,6 @@ emx_attach(device_t dev)
                }
        }
 
-       /* Initialize the hardware */
-       error = emx_hw_init(sc);
-       if (error) {
-               device_printf(dev, "Unable to initialize the hardware\n");
-               goto fail;
-       }
-
        /* Copy the permanent MAC address out of the EEPROM */
        if (e1000_read_mac_addr(&sc->hw) < 0) {
                device_printf(dev, "EEPROM read error while reading MAC"
@@ -561,35 +572,21 @@ emx_attach(device_t dev)
                goto fail;
        }
 
-       /* Manually turn off all interrupts */
-       E1000_WRITE_REG(&sc->hw, E1000_IMC, 0xffffffff);
-
-       /* Setup OS specific network interface */
-       emx_setup_ifp(sc);
-
-       /* Add sysctl tree, must after emx_setup_ifp() */
-       emx_add_sysctl(sc);
-
-       /* Initialize statistics */
-       emx_update_stats(sc);
-
-       sc->hw.mac.get_link_status = 1;
-       emx_update_link_status(sc);
-
-       /* Indicate SOL/IDER usage */
-       if (e1000_check_reset_block(&sc->hw)) {
-               device_printf(dev,
-                   "PHY reset is blocked due to SOL/IDER session.\n");
-       }
-
        /* Determine if we have to control management hardware */
        sc->has_manage = e1000_enable_mng_pass_thru(&sc->hw);
 
        /*
         * Setup Wake-on-Lan
         */
+       apme_mask = EMX_EEPROM_APME;
+       eeprom_data = 0;
        switch (sc->hw.mac.type) {
+       case e1000_82573:
+               sc->has_amt = 1;
+               /* FALL THROUGH */
+
        case e1000_82571:
+       case e1000_82572:
        case e1000_80003es2lan:
                if (sc->hw.bus.func == 1) {
                        e1000_read_nvm(&sc->hw,
@@ -598,17 +595,16 @@ emx_attach(device_t dev)
                        e1000_read_nvm(&sc->hw,
                            NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
                }
-               eeprom_data &= EMX_EEPROM_APME;
                break;
 
        default:
-               /* APME bit in EEPROM is mapped to WUC.APME */
-               eeprom_data =
-                   E1000_READ_REG(&sc->hw, E1000_WUC) & E1000_WUC_APME;
+               e1000_read_nvm(&sc->hw,
+                   NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
                break;
        }
-       if (eeprom_data)
-               sc->wol = E1000_WUFC_MAG;
+       if (eeprom_data & apme_mask)
+               sc->wol = E1000_WUFC_MAG | E1000_WUFC_MC;
+
        /*
          * We have the eeprom settings, now apply the special cases
          * where the eeprom may be wrong or the board won't support
@@ -641,6 +637,25 @@ emx_attach(device_t dev)
        /* XXX disable wol */
        sc->wol = 0;
 
+       /* Setup OS specific network interface */
+       emx_setup_ifp(sc);
+
+       /* Add sysctl tree, must after em_setup_ifp() */
+       emx_add_sysctl(sc);
+
+       /* Reset the hardware */
+       error = emx_reset(sc);
+       if (error) {
+               device_printf(dev, "Unable to reset the hardware\n");
+               goto fail;
+       }
+
+       /* Initialize statistics */
+       emx_update_stats(sc);
+
+       sc->hw.mac.get_link_status = 1;
+       emx_update_link_status(sc);
+
        sc->spare_tx_desc = EMX_TX_SPARE;
 
        /*
@@ -659,6 +674,10 @@ emx_attach(device_t dev)
        if (sc->tx_int_nsegs < sc->oact_tx_desc)
                sc->tx_int_nsegs = sc->oact_tx_desc;
 
+       /* Non-AMT based hardware can now take control from firmware */
+       if (sc->has_manage && !sc->has_amt)
+               emx_get_hw_control(sc);
+
        error = bus_setup_intr(dev, sc->intr_res, INTR_MPSAFE, emx_intr, sc,
                               &sc->intr_tag, &sc->main_serialize);
        if (error) {
@@ -690,10 +709,7 @@ emx_detach(device_t dev)
                e1000_phy_hw_reset(&sc->hw);
 
                emx_rel_mgmt(sc);
-
-               if (sc->hw.mac.type == e1000_82573 &&
-                   e1000_check_mng_mode(&sc->hw))
-                       emx_rel_hw_control(sc);
+               emx_rel_hw_control(sc);
 
                if (sc->wol) {
                        E1000_WRITE_REG(&sc->hw, E1000_WUC, E1000_WUC_PME_EN);
@@ -706,6 +722,8 @@ emx_detach(device_t dev)
                ifnet_deserialize_all(ifp);
 
                ether_ifdetach(ifp);
+       } else {
+               emx_rel_hw_control(sc);
        }
        bus_generic_detach(dev);
 
@@ -745,16 +763,13 @@ emx_suspend(device_t dev)
        emx_stop(sc);
 
        emx_rel_mgmt(sc);
+       emx_rel_hw_control(sc);
 
-        if (sc->hw.mac.type == e1000_82573 &&
-            e1000_check_mng_mode(&sc->hw))
-                emx_rel_hw_control(sc);
-
-        if (sc->wol) {
+       if (sc->wol) {
                E1000_WRITE_REG(&sc->hw, E1000_WUC, E1000_WUC_PME_EN);
                E1000_WRITE_REG(&sc->hw, E1000_WUFC, sc->wol);
                emx_enable_wol(dev);
-        }
+       }
 
        ifnet_deserialize_all(ifp);
 
@@ -1055,8 +1070,8 @@ emx_init(void *xsc)
        }
 
        /* Initialize the hardware */
-       if (emx_hw_init(sc)) {
-               device_printf(dev, "Unable to initialize the hardware\n");
+       if (emx_reset(sc)) {
+               device_printf(dev, "Unable to reset the hardware\n");
                /* XXX emx_stop()? */
                return;
        }
@@ -1125,6 +1140,7 @@ emx_init(void *xsc)
                tmp |= E1000_CTRL_EXT_PBA_CLR;
                E1000_WRITE_REG(&sc->hw, E1000_CTRL_EXT, tmp);
                /*
+                * XXX MSIX
                 * Set the IVAR - interrupt vector routing.
                 * Each nibble represents a vector, high bit
                 * is enable, other 3 bits are the MSIX table
@@ -1145,6 +1161,10 @@ emx_init(void *xsc)
 #endif /* IFPOLL_ENABLE */
                emx_enable_intr(sc);
 
+       /* AMT based hardware can now take control from firmware */
+       if (sc->has_manage && sc->has_amt)
+               emx_get_hw_control(sc);
+
        /* Don't reset the phy next time init gets called */
        sc->hw.phy.reset_disable = TRUE;
 }
@@ -1491,9 +1511,12 @@ emx_set_multi(struct emx_softc *sc)
        struct ifnet *ifp = &sc->arpcom.ac_if;
        struct ifmultiaddr *ifma;
        uint32_t reg_rctl = 0;
-       uint8_t  mta[512]; /* Largest MTS is 4096 bits */
+       uint8_t *mta;
        int mcnt = 0;
 
+       mta = sc->mta;
+       bzero(mta, ETH_ADDR_LEN * EMX_MCAST_ADDR_MAX);
+
        TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
                if (ifma->ifma_addr->sa_family != AF_LINK)
                        continue;
@@ -1589,15 +1612,13 @@ emx_update_link_status(struct emx_softc *sc)
                 * Check if we should enable/disable SPEED_MODE bit on
                 * 82571EB/82572EI
                 */
-               if (hw->mac.type == e1000_82571 ||
-                   hw->mac.type == e1000_82572) {
+               if (sc->link_speed != SPEED_1000 &&
+                   (hw->mac.type == e1000_82571 ||
+                    hw->mac.type == e1000_82572)) {
                        int tarc0;
 
                        tarc0 = E1000_READ_REG(hw, E1000_TARC(0));
-                       if (sc->link_speed != SPEED_1000)
-                               tarc0 &= ~EMX_TARC_SPEED_MODE;
-                       else
-                               tarc0 |= EMX_TARC_SPEED_MODE;
+                       tarc0 &= ~EMX_TARC_SPEED_MODE;
                        E1000_WRITE_REG(hw, E1000_TARC(0), tarc0);
                }
                if (bootverbose) {
@@ -1676,19 +1697,11 @@ emx_stop(struct emx_softc *sc)
 }
 
 static int
-emx_hw_init(struct emx_softc *sc)
+emx_reset(struct emx_softc *sc)
 {
        device_t dev = sc->dev;
        uint16_t rx_buffer_size;
 
-       /* Issue a global reset */
-       e1000_reset_hw(&sc->hw);
-
-       /* Get control from any management/hw control */
-       if (sc->hw.mac.type == e1000_82573 &&
-           e1000_check_mng_mode(&sc->hw))
-               emx_get_hw_control(sc);
-
        /* Set up smart power down as default off on newer adapters. */
        if (!emx_smart_pwr_down &&
            (sc->hw.mac.type == e1000_82571 ||
@@ -1730,11 +1743,17 @@ emx_hw_init(struct emx_softc *sc)
        sc->hw.fc.send_xon = TRUE;
        sc->hw.fc.requested_mode = e1000_fc_full;
 
+       /* Issue a global reset */
+       e1000_reset_hw(&sc->hw);
+       E1000_WRITE_REG(&sc->hw, E1000_WUC, 0);
+
        if (e1000_init_hw(&sc->hw) < 0) {
                device_printf(dev, "Hardware Initialization Failed\n");
                return (EIO);
        }
 
+       E1000_WRITE_REG(&sc->hw, E1000_VET, ETHERTYPE_VLAN);
+       e1000_get_phy_info(&sc->hw);
        e1000_check_for_link(&sc->hw);
 
        return (0);
@@ -2593,7 +2612,7 @@ emx_init_rx_unit(struct emx_softc *sc)
 {
        struct ifnet *ifp = &sc->arpcom.ac_if;
        uint64_t bus_addr;
-       uint32_t rctl, rxcsum, rfctl;
+       uint32_t rctl, itr, rfctl;
        int i;
 
        /*
@@ -2607,12 +2626,11 @@ emx_init_rx_unit(struct emx_softc *sc)
         * Set the interrupt throttling rate. Value is calculated
         * as ITR = 1 / (INT_THROTTLE_CEIL * 256ns)
         */
-       if (sc->int_throttle_ceil) {
-               E1000_WRITE_REG(&sc->hw, E1000_ITR,
-                       1000000000 / 256 / sc->int_throttle_ceil);
-       } else {
-               E1000_WRITE_REG(&sc->hw, E1000_ITR, 0);
-       }
+       if (sc->int_throttle_ceil)
+               itr = 1000000000 / 256 / sc->int_throttle_ceil;
+       else
+               itr = 0;
+       emx_set_itr(sc, itr);
 
        /* Use extended RX descriptor */
        rfctl = E1000_RFCTL_EXTEN;
@@ -2623,39 +2641,6 @@ emx_init_rx_unit(struct emx_softc *sc)
 
        E1000_WRITE_REG(&sc->hw, E1000_RFCTL, rfctl);
 
-       /* Setup the Base and Length of the Rx Descriptor Ring */
-       for (i = 0; i < sc->rx_ring_inuse; ++i) {
-               struct emx_rxdata *rdata = &sc->rx_data[i];
-
-               bus_addr = rdata->rx_desc_paddr;
-               E1000_WRITE_REG(&sc->hw, E1000_RDLEN(i),
-                   rdata->num_rx_desc * sizeof(emx_rxdesc_t));
-               E1000_WRITE_REG(&sc->hw, E1000_RDBAH(i),
-                   (uint32_t)(bus_addr >> 32));
-               E1000_WRITE_REG(&sc->hw, E1000_RDBAL(i),
-                   (uint32_t)bus_addr);
-       }
-
-       /* Setup the Receive Control Register */
-       rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
-       rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO |
-               E1000_RCTL_RDMTS_HALF | E1000_RCTL_SECRC |
-               (sc->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
-
-       /* Make sure VLAN Filters are off */
-       rctl &= ~E1000_RCTL_VFE;
-
-       /* Don't store bad paket */
-       rctl &= ~E1000_RCTL_SBP;
-
-       /* MCLBYTES */
-       rctl |= E1000_RCTL_SZ_2048;
-
-       if (ifp->if_mtu > ETHERMTU)
-               rctl |= E1000_RCTL_LPE;
-       else
-               rctl &= ~E1000_RCTL_LPE;
-
        /*
         * Receive Checksum Offload for TCP and UDP
         *
@@ -2664,6 +2649,8 @@ emx_init_rx_unit(struct emx_softc *sc)
         * packet type.
         */
        if (ifp->if_capenable & (IFCAP_RSS | IFCAP_RXCSUM)) {
+               uint32_t rxcsum;
+
                rxcsum = E1000_READ_REG(&sc->hw, E1000_RXCSUM);
 
                /*
@@ -2746,15 +2733,48 @@ emx_init_rx_unit(struct emx_softc *sc)
                E1000_WRITE_REG(&sc->hw, E1000_RDTR, EMX_RDTR_82573);
        }
 
-       /*
-        * Setup the HW Rx Head and Tail Descriptor Pointers
-        */
        for (i = 0; i < sc->rx_ring_inuse; ++i) {
+               struct emx_rxdata *rdata = &sc->rx_data[i];
+
+               /*
+                * Setup the Base and Length of the Rx Descriptor Ring
+                */
+               bus_addr = rdata->rx_desc_paddr;
+               E1000_WRITE_REG(&sc->hw, E1000_RDLEN(i),
+                   rdata->num_rx_desc * sizeof(emx_rxdesc_t));
+               E1000_WRITE_REG(&sc->hw, E1000_RDBAH(i),
+                   (uint32_t)(bus_addr >> 32));
+               E1000_WRITE_REG(&sc->hw, E1000_RDBAL(i),
+                   (uint32_t)bus_addr);
+
+               /*
+                * Setup the HW Rx Head and Tail Descriptor Pointers
+                */
                E1000_WRITE_REG(&sc->hw, E1000_RDH(i), 0);
                E1000_WRITE_REG(&sc->hw, E1000_RDT(i),
                    sc->rx_data[i].num_rx_desc - 1);
        }
 
+       /* Setup the Receive Control Register */
+       rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
+       rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO |
+               E1000_RCTL_RDMTS_HALF | E1000_RCTL_SECRC |
+               (sc->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
+
+       /* Make sure VLAN Filters are off */
+       rctl &= ~E1000_RCTL_VFE;
+
+       /* Don't store bad paket */
+       rctl &= ~E1000_RCTL_SBP;
+
+       /* MCLBYTES */
+       rctl |= E1000_RCTL_SZ_2048;
+
+       if (ifp->if_mtu > ETHERMTU)
+               rctl |= E1000_RCTL_LPE;
+       else
+               rctl &= ~E1000_RCTL_LPE;
+
        /* Enable Receives */
        E1000_WRITE_REG(&sc->hw, E1000_RCTL, rctl);
 }
@@ -2934,14 +2954,26 @@ discard:
 static void
 emx_enable_intr(struct emx_softc *sc)
 {
+       uint32_t ims_mask = IMS_ENABLE_MASK;
+
        lwkt_serialize_handler_enable(&sc->main_serialize);
-       E1000_WRITE_REG(&sc->hw, E1000_IMS, IMS_ENABLE_MASK);
+
+#if 0
+       if (sc->hw.mac.type == e1000_82574) {
+               E1000_WRITE_REG(hw, EMX_EIAC, EM_MSIX_MASK);
+               ims_mask |= EM_MSIX_MASK;
+       }
+#endif
+       E1000_WRITE_REG(&sc->hw, E1000_IMS, ims_mask);
 }
 
 static void
 emx_disable_intr(struct emx_softc *sc)
 {
+       if (sc->hw.mac.type == e1000_82574)
+               E1000_WRITE_REG(&sc->hw, EMX_EIAC, 0);
        E1000_WRITE_REG(&sc->hw, E1000_IMC, 0xffffffff);
+
        lwkt_serialize_handler_disable(&sc->main_serialize);
 }
 
@@ -3000,27 +3032,21 @@ emx_rel_mgmt(struct emx_softc *sc)
 static void
 emx_get_hw_control(struct emx_softc *sc)
 {
-       uint32_t ctrl_ext, swsm;
-
        /* Let firmware know the driver has taken over */
-       switch (sc->hw.mac.type) {
-       case e1000_82573:
+       if (sc->hw.mac.type == e1000_82573) {
+               uint32_t swsm;
+
                swsm = E1000_READ_REG(&sc->hw, E1000_SWSM);
                E1000_WRITE_REG(&sc->hw, E1000_SWSM,
                    swsm | E1000_SWSM_DRV_LOAD);
-               break;
+       } else {
+               uint32_t ctrl_ext;
 
-       case e1000_82571:
-       case e1000_82572:
-       case e1000_80003es2lan:
                ctrl_ext = E1000_READ_REG(&sc->hw, E1000_CTRL_EXT);
                E1000_WRITE_REG(&sc->hw, E1000_CTRL_EXT,
                    ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
-               break;
-
-       default:
-               break;
        }
+       sc->control_hw = 1;
 }
 
 /*
@@ -3032,26 +3058,23 @@ emx_get_hw_control(struct emx_softc *sc)
 static void
 emx_rel_hw_control(struct emx_softc *sc)
 {
-       uint32_t ctrl_ext, swsm;
+       if (!sc->control_hw)
+               return;
+       sc->control_hw = 0;
 
        /* Let firmware taken over control of h/w */
-       switch (sc->hw.mac.type) {
-       case e1000_82573:
+       if (sc->hw.mac.type == e1000_82573) {
+               uint32_t swsm;
+
                swsm = E1000_READ_REG(&sc->hw, E1000_SWSM);
                E1000_WRITE_REG(&sc->hw, E1000_SWSM,
                    swsm & ~E1000_SWSM_DRV_LOAD);
-               break;
+       } else {
+               uint32_t ctrl_ext;
 
-       case e1000_82571:
-       case e1000_82572:
-       case e1000_80003es2lan:
                ctrl_ext = E1000_READ_REG(&sc->hw, E1000_CTRL_EXT);
                E1000_WRITE_REG(&sc->hw, E1000_CTRL_EXT,
                    ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
-               break;
-
-       default:
-               break;
        }
 }
 
@@ -3447,7 +3470,7 @@ emx_sysctl_int_throttle(SYSCTL_HANDLER_ARGS)
                sc->int_throttle_ceil = 0;
 
        if (ifp->if_flags & IFF_RUNNING)
-               E1000_WRITE_REG(&sc->hw, E1000_ITR, throttle);
+               emx_set_itr(sc, throttle);
 
        ifnet_deserialize_all(ifp);
 
@@ -3787,3 +3810,19 @@ emx_qpoll(struct ifnet *ifp, struct ifpoll_info *info)
 }
 
 #endif /* IFPOLL_ENABLE */
+
+static void
+emx_set_itr(struct emx_softc *sc, uint32_t itr)
+{
+       E1000_WRITE_REG(&sc->hw, E1000_ITR, itr);
+       if (sc->hw.mac.type == e1000_82574) {
+               int i;
+
+               /*
+                * When using MSIX interrupts we need to
+                * throttle using the EITR register
+                */
+               for (i = 0; i < 4; ++i)
+                       E1000_WRITE_REG(&sc->hw, E1000_EITR_82574(i), itr);
+       }
+}
index 1083ec1..af52c83 100644 (file)
@@ -262,6 +262,11 @@ struct emx_softc {
        /* Management and WOL features */
        int                     wol;
        int                     has_manage;
+       int                     has_amt;
+       int                     control_hw;
+
+       /* Multicast array memory */
+       uint8_t                 *mta;
 
        /* Info about the board itself */
        uint8_t                 link_active;
index f0669e2..ec26671 100644 (file)
@@ -1006,7 +1006,6 @@ out:
  **/
 s32 e1000_read_mac_addr_generic(struct e1000_hw *hw)
 {
-#ifdef foo
        u32 rar_high;
        u32 rar_low;
        u16 i;
@@ -1024,33 +1023,6 @@ s32 e1000_read_mac_addr_generic(struct e1000_hw *hw)
                hw->mac.addr[i] = hw->mac.perm_addr[i];
 
        return E1000_SUCCESS;
-#else
-       s32  ret_val = E1000_SUCCESS;
-       u16 offset, nvm_data, i;
-
-       DEBUGFUNC("e1000_read_mac_addr");
-
-       for (i = 0; i < ETH_ADDR_LEN; i += 2) {
-               offset = i >> 1;
-               ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
-               if (ret_val) {
-                       DEBUGOUT("NVM Read Error\n");
-                       goto out;
-               }
-               hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
-               hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
-       }
-
-       /* Flip last bit of mac address if we're on second port */
-       if (hw->bus.func == E1000_FUNC_1)
-               hw->mac.perm_addr[5] ^= 1;
-
-       for (i = 0; i < ETH_ADDR_LEN; i++)
-               hw->mac.addr[i] = hw->mac.perm_addr[i];
-
-out:
-       return ret_val;
-#endif
 }
 
 /**