summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/e1000/if_em.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/dev/e1000/if_em.c')
-rw-r--r--freebsd/sys/dev/e1000/if_em.c1054
1 files changed, 666 insertions, 388 deletions
diff --git a/freebsd/sys/dev/e1000/if_em.c b/freebsd/sys/dev/e1000/if_em.c
index c0fffc30..330b67bf 100644
--- a/freebsd/sys/dev/e1000/if_em.c
+++ b/freebsd/sys/dev/e1000/if_em.c
@@ -2,7 +2,7 @@
/******************************************************************************
- Copyright (c) 2001-2010, Intel Corporation
+ Copyright (c) 2001-2013, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -37,6 +37,7 @@
#ifdef HAVE_KERNEL_OPTION_HEADERS
#include <rtems/bsd/local/opt_device_polling.h>
#include <rtems/bsd/local/opt_inet.h>
+#include <rtems/bsd/local/opt_inet6.h>
#endif
#include <rtems/bsd/sys/param.h>
@@ -101,7 +102,7 @@ int em_display_debug_stats = 0;
/*********************************************************************
* Driver version:
*********************************************************************/
-char em_driver_version[] = "7.1.9";
+char em_driver_version[] = "7.3.7";
/*********************************************************************
* PCI Device ID Table
@@ -179,6 +180,12 @@ static em_vendor_info_t em_vendor_info_array[] =
{ 0x8086, E1000_DEV_ID_PCH_D_HV_DC, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_PCH2_LV_LM, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_PCH2_LV_V, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_PCH_LPT_I217_LM, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_PCH_LPT_I217_V, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_PCH_LPTLP_I218_LM,
+ PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_PCH_LPTLP_I218_V,
+ PCI_ANY_ID, PCI_ANY_ID, 0},
/* required last entry */
{ 0, 0, 0, 0, 0}
};
@@ -200,13 +207,14 @@ static int em_detach(device_t);
static int em_shutdown(device_t);
static int em_suspend(device_t);
static int em_resume(device_t);
-static void em_start(struct ifnet *);
-static void em_start_locked(struct ifnet *, struct tx_ring *);
#ifdef EM_MULTIQUEUE
static int em_mq_start(struct ifnet *, struct mbuf *);
static int em_mq_start_locked(struct ifnet *,
struct tx_ring *, struct mbuf *);
static void em_qflush(struct ifnet *);
+#else
+static void em_start(struct ifnet *);
+static void em_start_locked(struct ifnet *, struct tx_ring *);
#endif
static int em_ioctl(struct ifnet *, u_long, caddr_t);
static void em_init(void *);
@@ -241,7 +249,7 @@ static void em_enable_intr(struct adapter *);
static void em_disable_intr(struct adapter *);
static void em_update_stats_counters(struct adapter *);
static void em_add_hw_stats(struct adapter *adapter);
-static bool em_txeof(struct tx_ring *);
+static void em_txeof(struct tx_ring *);
static bool em_rxeof(struct rx_ring *, int, int *);
#ifndef __NO_STRICT_ALIGNMENT
static int em_fixup_rx(struct rx_ring *);
@@ -292,10 +300,10 @@ static void em_handle_tx(void *context, int pending);
static void em_handle_rx(void *context, int pending);
static void em_handle_link(void *context, int pending);
-static void em_add_rx_process_limit(struct adapter *, const char *,
- const char *, int *, int);
-static void em_set_flow_cntrl(struct adapter *, const char *,
+static void em_set_sysctl_value(struct adapter *, const char *,
const char *, int *, int);
+static int em_set_flowcntl(SYSCTL_HANDLER_ARGS);
+static int em_sysctl_eee(SYSCTL_HANDLER_ARGS);
static __inline void em_rx_discard(struct rx_ring *, int);
@@ -315,7 +323,7 @@ static device_method_t em_methods[] = {
DEVMETHOD(device_shutdown, em_shutdown),
DEVMETHOD(device_suspend, em_suspend),
DEVMETHOD(device_resume, em_resume),
- {0, 0}
+ DEVMETHOD_END
};
static driver_t em_driver = {
@@ -340,42 +348,74 @@ MODULE_DEPEND(em, ether, 1, 1, 1);
#define CSUM_TSO 0
#endif
+static SYSCTL_NODE(_hw, OID_AUTO, em, CTLFLAG_RD, 0, "EM driver parameters");
+
static int em_tx_int_delay_dflt = EM_TICKS_TO_USECS(EM_TIDV);
static int em_rx_int_delay_dflt = EM_TICKS_TO_USECS(EM_RDTR);
TUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt);
TUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt);
+SYSCTL_INT(_hw_em, OID_AUTO, tx_int_delay, CTLFLAG_RDTUN, &em_tx_int_delay_dflt,
+ 0, "Default transmit interrupt delay in usecs");
+SYSCTL_INT(_hw_em, OID_AUTO, rx_int_delay, CTLFLAG_RDTUN, &em_rx_int_delay_dflt,
+ 0, "Default receive interrupt delay in usecs");
static int em_tx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_TADV);
static int em_rx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_RADV);
TUNABLE_INT("hw.em.tx_abs_int_delay", &em_tx_abs_int_delay_dflt);
TUNABLE_INT("hw.em.rx_abs_int_delay", &em_rx_abs_int_delay_dflt);
+SYSCTL_INT(_hw_em, OID_AUTO, tx_abs_int_delay, CTLFLAG_RDTUN,
+ &em_tx_abs_int_delay_dflt, 0,
+ "Default transmit interrupt delay limit in usecs");
+SYSCTL_INT(_hw_em, OID_AUTO, rx_abs_int_delay, CTLFLAG_RDTUN,
+ &em_rx_abs_int_delay_dflt, 0,
+ "Default receive interrupt delay limit in usecs");
static int em_rxd = EM_DEFAULT_RXD;
static int em_txd = EM_DEFAULT_TXD;
TUNABLE_INT("hw.em.rxd", &em_rxd);
TUNABLE_INT("hw.em.txd", &em_txd);
+SYSCTL_INT(_hw_em, OID_AUTO, rxd, CTLFLAG_RDTUN, &em_rxd, 0,
+ "Number of receive descriptors per queue");
+SYSCTL_INT(_hw_em, OID_AUTO, txd, CTLFLAG_RDTUN, &em_txd, 0,
+ "Number of transmit descriptors per queue");
static int em_smart_pwr_down = FALSE;
TUNABLE_INT("hw.em.smart_pwr_down", &em_smart_pwr_down);
+SYSCTL_INT(_hw_em, OID_AUTO, smart_pwr_down, CTLFLAG_RDTUN, &em_smart_pwr_down,
+ 0, "Set to true to leave smart power down enabled on newer adapters");
/* Controls whether promiscuous also shows bad packets */
static int em_debug_sbp = FALSE;
TUNABLE_INT("hw.em.sbp", &em_debug_sbp);
+SYSCTL_INT(_hw_em, OID_AUTO, sbp, CTLFLAG_RDTUN, &em_debug_sbp, 0,
+ "Show bad packets in promiscuous mode");
static int em_enable_msix = TRUE;
TUNABLE_INT("hw.em.enable_msix", &em_enable_msix);
+SYSCTL_INT(_hw_em, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &em_enable_msix, 0,
+ "Enable MSI-X interrupts");
/* How many packets rxeof tries to clean at a time */
static int em_rx_process_limit = 100;
TUNABLE_INT("hw.em.rx_process_limit", &em_rx_process_limit);
+SYSCTL_INT(_hw_em, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN,
+ &em_rx_process_limit, 0,
+ "Maximum number of received packets to process "
+ "at a time, -1 means unlimited");
-/* Flow control setting - default to FULL */
-static int em_fc_setting = e1000_fc_full;
-TUNABLE_INT("hw.em.fc_setting", &em_fc_setting);
+/* Energy efficient ethernet - default to OFF */
+static int eee_setting = 1;
+TUNABLE_INT("hw.em.eee_setting", &eee_setting);
+SYSCTL_INT(_hw_em, OID_AUTO, eee_setting, CTLFLAG_RDTUN, &eee_setting, 0,
+ "Enable Energy Efficient Ethernet");
/* Global used in WOL setup with multiport cards */
static int global_quad_port_a = 0;
+#ifdef DEV_NETMAP /* see ixgbe.c for details */
+#include <dev/netmap/if_em_netmap.h>
+#endif /* DEV_NETMAP */
+
/*********************************************************************
* Device identification routine
*
@@ -441,12 +481,19 @@ static int
em_attach(device_t dev)
{
struct adapter *adapter;
+ struct e1000_hw *hw;
int error = 0;
INIT_DEBUGOUT("em_attach: begin");
+ if (resource_disabled("em", device_get_unit(dev))) {
+ device_printf(dev, "Disabled by device hint\n");
+ return (ENXIO);
+ }
+
adapter = device_get_softc(dev);
adapter->dev = adapter->osdep.dev = dev;
+ hw = &adapter->hw;
EM_CORE_LOCK_INIT(adapter, device_get_nameunit(dev));
/* SYSCTL stuff */
@@ -460,6 +507,11 @@ em_attach(device_t dev)
OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, adapter, 0,
em_sysctl_debug_info, "I", "Debug Information");
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "fc", CTLTYPE_INT|CTLFLAG_RW, adapter, 0,
+ em_set_flowcntl, "I", "Flow Control");
+
callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0);
/* Determine hardware and mac info */
@@ -478,11 +530,12 @@ em_attach(device_t dev)
** 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_pchlan) ||
- (adapter->hw.mac.type == e1000_pch2lan)) {
+ if ((hw->mac.type == e1000_ich8lan) ||
+ (hw->mac.type == e1000_ich9lan) ||
+ (hw->mac.type == e1000_ich10lan) ||
+ (hw->mac.type == e1000_pchlan) ||
+ (hw->mac.type == e1000_pch2lan) ||
+ (hw->mac.type == e1000_pch_lpt)) {
int rid = EM_BAR_TYPE_FLASH;
adapter->flash = bus_alloc_resource_any(dev,
SYS_RES_MEMORY, &rid, RF_ACTIVE);
@@ -492,7 +545,7 @@ em_attach(device_t dev)
goto err_pci;
}
/* This is used in the shared code */
- adapter->hw.flash_address = (u8 *)adapter->flash;
+ hw->flash_address = (u8 *)adapter->flash;
adapter->osdep.flash_bus_space_tag =
rman_get_bustag(adapter->flash);
adapter->osdep.flash_bus_space_handle =
@@ -500,42 +553,37 @@ em_attach(device_t dev)
}
/* Do Shared Code initialization */
- if (e1000_setup_init_funcs(&adapter->hw, TRUE)) {
+ if (e1000_setup_init_funcs(hw, TRUE)) {
device_printf(dev, "Setup of Shared code failed\n");
error = ENXIO;
goto err_pci;
}
- e1000_get_bus_info(&adapter->hw);
+ e1000_get_bus_info(hw);
/* Set up some sysctls for the tunable interrupt delays */
em_add_int_delay_sysctl(adapter, "rx_int_delay",
"receive interrupt delay in usecs", &adapter->rx_int_delay,
- E1000_REGISTER(&adapter->hw, E1000_RDTR), em_rx_int_delay_dflt);
+ E1000_REGISTER(hw, E1000_RDTR), em_rx_int_delay_dflt);
em_add_int_delay_sysctl(adapter, "tx_int_delay",
"transmit interrupt delay in usecs", &adapter->tx_int_delay,
- E1000_REGISTER(&adapter->hw, E1000_TIDV), em_tx_int_delay_dflt);
+ E1000_REGISTER(hw, E1000_TIDV), em_tx_int_delay_dflt);
em_add_int_delay_sysctl(adapter, "rx_abs_int_delay",
"receive interrupt delay limit in usecs",
&adapter->rx_abs_int_delay,
- E1000_REGISTER(&adapter->hw, E1000_RADV),
+ E1000_REGISTER(hw, E1000_RADV),
em_rx_abs_int_delay_dflt);
em_add_int_delay_sysctl(adapter, "tx_abs_int_delay",
"transmit interrupt delay limit in usecs",
&adapter->tx_abs_int_delay,
- E1000_REGISTER(&adapter->hw, E1000_TADV),
+ E1000_REGISTER(hw, E1000_TADV),
em_tx_abs_int_delay_dflt);
/* Sysctl for limiting the amount of work done in the taskqueue */
- em_add_rx_process_limit(adapter, "rx_processing_limit",
+ em_set_sysctl_value(adapter, "rx_processing_limit",
"max number of rx packets to process", &adapter->rx_process_limit,
em_rx_process_limit);
- /* Sysctl for setting the interface flow control */
- em_set_flow_cntrl(adapter, "flow_control",
- "configure flow control",
- &adapter->fc_setting, em_fc_setting);
-
/*
* Validate number of transmit and receive descriptors. It
* must not exceed hardware maximum, and must be multiple
@@ -557,29 +605,29 @@ em_attach(device_t dev)
} else
adapter->num_rx_desc = em_rxd;
- adapter->hw.mac.autoneg = DO_AUTO_NEG;
- adapter->hw.phy.autoneg_wait_to_complete = FALSE;
- adapter->hw.phy.autoneg_advertised = AUTONEG_ADV_DEFAULT;
+ hw->mac.autoneg = DO_AUTO_NEG;
+ hw->phy.autoneg_wait_to_complete = FALSE;
+ hw->phy.autoneg_advertised = AUTONEG_ADV_DEFAULT;
/* Copper options */
- if (adapter->hw.phy.media_type == e1000_media_type_copper) {
- adapter->hw.phy.mdix = AUTO_ALL_MODES;
- adapter->hw.phy.disable_polarity_correction = FALSE;
- adapter->hw.phy.ms_type = EM_MASTER_SLAVE;
+ if (hw->phy.media_type == e1000_media_type_copper) {
+ hw->phy.mdix = AUTO_ALL_MODES;
+ hw->phy.disable_polarity_correction = FALSE;
+ hw->phy.ms_type = EM_MASTER_SLAVE;
}
/*
* Set the frame limits assuming
* standard ethernet sized frames.
*/
- adapter->max_frame_size = ETHERMTU + ETHER_HDR_LEN + ETHERNET_FCS_SIZE;
- adapter->min_frame_size = ETH_ZLEN + ETHERNET_FCS_SIZE;
+ adapter->hw.mac.max_frame_size =
+ ETHERMTU + ETHER_HDR_LEN + ETHERNET_FCS_SIZE;
/*
* This controls when hardware reports transmit completion
* status.
*/
- adapter->hw.mac.report_tx_early = 1;
+ hw->mac.report_tx_early = 1;
/*
** Get queue/ring memory
@@ -599,25 +647,34 @@ em_attach(device_t dev)
}
/* Check SOL/IDER usage */
- if (e1000_check_reset_block(&adapter->hw))
+ if (e1000_check_reset_block(hw))
device_printf(dev, "PHY reset is blocked"
" due to SOL/IDER session.\n");
+ /* Sysctl for setting Energy Efficient Ethernet */
+ hw->dev_spec.ich8lan.eee_disable = eee_setting;
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "eee_control", CTLTYPE_INT|CTLFLAG_RW,
+ adapter, 0, em_sysctl_eee, "I",
+ "Disable Energy Efficient Ethernet");
+
/*
** Start from a known state, this is
** important in reading the nvm and
** mac from that.
*/
- e1000_reset_hw(&adapter->hw);
+ e1000_reset_hw(hw);
+
/* Make sure we have a good EEPROM before we read from it */
- if (e1000_validate_nvm_checksum(&adapter->hw) < 0) {
+ if (e1000_validate_nvm_checksum(hw) < 0) {
/*
** Some PCI-E parts fail the first check due to
** the link being in sleep state, call it again,
** if it fails a second time its a real issue.
*/
- if (e1000_validate_nvm_checksum(&adapter->hw) < 0) {
+ if (e1000_validate_nvm_checksum(hw) < 0) {
device_printf(dev,
"The EEPROM Checksum Is Not Valid\n");
error = EIO;
@@ -626,14 +683,14 @@ em_attach(device_t dev)
}
/* Copy the permanent MAC address out of the EEPROM */
- if (e1000_read_mac_addr(&adapter->hw) < 0) {
+ if (e1000_read_mac_addr(hw) < 0) {
device_printf(dev, "EEPROM read error while reading MAC"
" address\n");
error = EIO;
goto err_late;
}
- if (!em_is_valid_ether_addr(adapter->hw.mac.addr)) {
+ if (!em_is_valid_ether_addr(hw->mac.addr)) {
device_printf(dev, "Invalid MAC address\n");
error = EIO;
goto err_late;
@@ -663,7 +720,7 @@ em_attach(device_t dev)
/* Initialize statistics */
em_update_stats_counters(adapter);
- adapter->hw.mac.get_link_status = 1;
+ hw->mac.get_link_status = 1;
em_update_link_status(adapter);
/* Register for VLAN events */
@@ -679,10 +736,14 @@ em_attach(device_t dev)
em_get_hw_control(adapter);
/* Tell the stack that the interface is not active */
- adapter->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+ adapter->ifp->if_drv_flags |= IFF_DRV_OACTIVE;
adapter->led_dev = led_create(em_led_func, adapter,
device_get_nameunit(dev));
+#ifdef DEV_NETMAP
+ em_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
INIT_DEBUGOUT("em_attach: end");
@@ -754,6 +815,10 @@ em_detach(device_t dev)
ether_ifdetach(adapter->ifp);
callout_drain(&adapter->timer);
+#ifdef DEV_NETMAP
+ netmap_detach(ifp);
+#endif /* DEV_NETMAP */
+
em_free_pci_resources(adapter);
bus_generic_detach(dev);
if_free(ifp);
@@ -802,29 +867,44 @@ static int
em_resume(device_t dev)
{
struct adapter *adapter = device_get_softc(dev);
+ struct tx_ring *txr = adapter->tx_rings;
struct ifnet *ifp = adapter->ifp;
EM_CORE_LOCK(adapter);
+ if (adapter->hw.mac.type == e1000_pch2lan)
+ e1000_resume_workarounds_pchlan(&adapter->hw);
em_init_locked(adapter);
em_init_manageability(adapter);
+
+ if ((ifp->if_flags & IFF_UP) &&
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) && adapter->link_active) {
+ for (int i = 0; i < adapter->num_queues; i++, txr++) {
+ EM_TX_LOCK(txr);
+#ifdef EM_MULTIQUEUE
+ if (!drbr_empty(ifp, txr->br))
+ em_mq_start_locked(ifp, txr, NULL);
+#else
+ if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+ em_start_locked(ifp, txr);
+#endif
+ EM_TX_UNLOCK(txr);
+ }
+ }
EM_CORE_UNLOCK(adapter);
- em_start(ifp);
return bus_generic_resume(dev);
}
+#ifdef EM_MULTIQUEUE
/*********************************************************************
- * Transmit entry point
+ * Multiqueue Transmit routines
*
- * em_start is called by the stack to initiate a transmit.
- * The driver will remain in this routine as long as there are
- * packets to transmit and transmit resources are available.
- * In case resources are not available stack is notified and
- * the packet is requeued.
+ * em_mq_start is called by the stack to initiate a transmit.
+ * however, if busy the driver can queue the request rather
+ * than do an immediate send. It is this that is an advantage
+ * in this driver, rather than also having multiple tx queues.
**********************************************************************/
-
-#ifdef EM_MULTIQUEUE
static int
em_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m)
{
@@ -839,37 +919,30 @@ em_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m)
return (err);
}
- /* Call cleanup if number of TX descriptors low */
- if (txr->tx_avail <= EM_TX_CLEANUP_THRESHOLD)
- em_txeof(txr);
-
enq = 0;
- if (m == NULL) {
- next = drbr_dequeue(ifp, txr->br);
- } else if (drbr_needs_enqueue(ifp, txr->br)) {
- if ((err = drbr_enqueue(ifp, txr->br, m)) != 0)
+ if (m != NULL) {
+ err = drbr_enqueue(ifp, txr->br, m);
+ if (err)
return (err);
- next = drbr_dequeue(ifp, txr->br);
- } else
- next = m;
+ }
/* Process the queue */
- while (next != NULL) {
+ while ((next = drbr_peek(ifp, txr->br)) != NULL) {
if ((err = em_xmit(txr, &next)) != 0) {
- if (next != NULL)
- err = drbr_enqueue(ifp, txr->br, next);
- break;
+ if (next == NULL)
+ drbr_advance(ifp, txr->br);
+ else
+ drbr_putback(ifp, txr->br, next);
+ break;
}
+ drbr_advance(ifp, txr->br);
enq++;
- drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags);
+ ifp->if_obytes += next->m_pkthdr.len;
+ if (next->m_flags & M_MCAST)
+ ifp->if_omcasts++;
ETHER_BPF_MTAP(ifp, next);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
break;
- if (txr->tx_avail < EM_MAX_SCATTER) {
- ifp->if_drv_flags |= IFF_DRV_OACTIVE;
- break;
- }
- next = drbr_dequeue(ifp, txr->br);
}
if (enq > 0) {
@@ -877,6 +950,11 @@ em_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m)
txr->queue_status = EM_QUEUE_WORKING;
txr->watchdog_time = ticks;
}
+
+ if (txr->tx_avail < EM_MAX_SCATTER)
+ em_txeof(txr);
+ if (txr->tx_avail < EM_MAX_SCATTER)
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
return (err);
}
@@ -917,8 +995,7 @@ em_qflush(struct ifnet *ifp)
}
if_qflush(ifp);
}
-
-#endif /* EM_MULTIQUEUE */
+#else /* !EM_MULTIQUEUE */
static void
em_start_locked(struct ifnet *ifp, struct tx_ring *txr)
@@ -935,11 +1012,10 @@ em_start_locked(struct ifnet *ifp, struct tx_ring *txr)
if (!adapter->link_active)
return;
- /* Call cleanup if number of TX descriptors low */
- if (txr->tx_avail <= EM_TX_CLEANUP_THRESHOLD)
- em_txeof(txr);
-
while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
+ /* Call cleanup if number of TX descriptors low */
+ if (txr->tx_avail <= EM_TX_CLEANUP_THRESHOLD)
+ em_txeof(txr);
if (txr->tx_avail < EM_MAX_SCATTER) {
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
break;
@@ -954,7 +1030,6 @@ em_start_locked(struct ifnet *ifp, struct tx_ring *txr)
if (em_xmit(txr, &m_head)) {
if (m_head == NULL)
break;
- ifp->if_drv_flags |= IFF_DRV_OACTIVE;
IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
break;
}
@@ -983,6 +1058,7 @@ em_start(struct ifnet *ifp)
}
return;
}
+#endif /* EM_MULTIQUEUE */
/*********************************************************************
* Ioctl entry point
@@ -997,11 +1073,12 @@ static int
em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
{
struct adapter *adapter = ifp->if_softc;
- struct ifreq *ifr = (struct ifreq *)data;
-#ifdef INET
- struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ifreq *ifr = (struct ifreq *)data;
+#if defined(INET) || defined(INET6)
+ struct ifaddr *ifa = (struct ifaddr *)data;
#endif
- int error = 0;
+ bool avoid_reset = FALSE;
+ int error = 0;
if (adapter->in_detach)
return (error);
@@ -1009,23 +1086,26 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
switch (command) {
case SIOCSIFADDR:
#ifdef INET
- if (ifa->ifa_addr->sa_family == AF_INET) {
- /*
- * XXX
- * Since resetting hardware takes a very long time
- * and results in link renegotiation we only
- * initialize the hardware only when it is absolutely
- * required.
- */
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ avoid_reset = TRUE;
+#endif
+#ifdef INET6
+ if (ifa->ifa_addr->sa_family == AF_INET6)
+ avoid_reset = TRUE;
+#endif
+ /*
+ ** Calling init results in link renegotiation,
+ ** so we avoid doing it when possible.
+ */
+ if (avoid_reset) {
ifp->if_flags |= IFF_UP;
- if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
- EM_CORE_LOCK(adapter);
- em_init_locked(adapter);
- EM_CORE_UNLOCK(adapter);
- }
- arp_ifinit(ifp, ifa);
- } else
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+ em_init(adapter);
+#ifdef INET
+ if (!(ifp->if_flags & IFF_NOARP))
+ arp_ifinit(ifp, ifa);
#endif
+ } else
error = ether_ioctl(ifp, command, data);
break;
case SIOCSIFMTU:
@@ -1041,7 +1121,9 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
case e1000_ich9lan:
case e1000_ich10lan:
case e1000_pch2lan:
+ case e1000_pch_lpt:
case e1000_82574:
+ case e1000_82583:
case e1000_80003es2lan: /* 9K Jumbo Frame size */
max_frame_size = 9234;
break;
@@ -1049,7 +1131,6 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
max_frame_size = 4096;
break;
/* Adapters that do not support jumbo frames */
- case e1000_82583:
case e1000_ich8lan:
max_frame_size = ETHER_MAX_LEN;
break;
@@ -1064,7 +1145,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
}
ifp->if_mtu = ifr->ifr_mtu;
- adapter->max_frame_size =
+ adapter->hw.mac.max_frame_size =
ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
em_init_locked(adapter);
EM_CORE_UNLOCK(adapter);
@@ -1104,11 +1185,6 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
}
break;
case SIOCSIFMEDIA:
- /*
- ** As the speed/duplex settings are being
- ** changed, we need to reset the PHY.
- */
- adapter->hw.phy.reset_disable = FALSE;
/* Check SOL/IDER usage */
EM_CORE_LOCK(adapter);
if (e1000_check_reset_block(&adapter->hw)) {
@@ -1167,6 +1243,10 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
reinit = 1;
}
+ if (mask & IFCAP_VLAN_HWTSO) {
+ ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
+ reinit = 1;
+ }
if ((mask & IFCAP_WOL) &&
(ifp->if_capabilities & IFCAP_WOL) != 0) {
if (mask & IFCAP_WOL_MCAST)
@@ -1205,7 +1285,6 @@ em_init_locked(struct adapter *adapter)
{
struct ifnet *ifp = adapter->ifp;
device_t dev = adapter->dev;
- u32 pba;
INIT_DEBUGOUT("em_init: begin");
@@ -1214,46 +1293,6 @@ em_init_locked(struct adapter *adapter)
em_disable_intr(adapter);
callout_stop(&adapter->timer);
- /*
- * Packet Buffer Allocation (PBA)
- * Writing PBA sets the receive portion of the buffer
- * the remainder is used for the transmit buffer.
- */
- switch (adapter->hw.mac.type) {
- /* Total Packet Buffer on these is 48K */
- case e1000_82571:
- case e1000_82572:
- case e1000_80003es2lan:
- pba = E1000_PBA_32K; /* 32K for Rx, 16K for Tx */
- break;
- case e1000_82573: /* 82573: Total Packet Buffer is 32K */
- pba = E1000_PBA_12K; /* 12K for Rx, 20K for Tx */
- 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:
- pba = E1000_PBA_10K;
- break;
- case e1000_pchlan:
- case e1000_pch2lan:
- pba = E1000_PBA_26K;
- break;
- default:
- if (adapter->max_frame_size > 8192)
- pba = E1000_PBA_40K; /* 40K for Rx, 24K for Tx */
- else
- pba = E1000_PBA_48K; /* 48K for Rx, 16K for Tx */
- }
-
- INIT_DEBUGOUT1("em_init: pba=%dK",pba);
- E1000_WRITE_REG(&adapter->hw, E1000_PBA, pba);
-
/* Get the latest mac address, User can use a LAA */
bcopy(IF_LLADDR(adapter->ifp), adapter->hw.mac.addr,
ETHER_ADDR_LEN);
@@ -1301,9 +1340,9 @@ em_init_locked(struct adapter *adapter)
** Figure out the desired mbuf
** pool for doing jumbos
*/
- if (adapter->max_frame_size <= 2048)
+ if (adapter->hw.mac.max_frame_size <= 2048)
adapter->rx_mbuf_sz = MCLBYTES;
- else if (adapter->max_frame_size <= 4096)
+ else if (adapter->hw.mac.max_frame_size <= 4096)
adapter->rx_mbuf_sz = MJUMPAGESIZE;
else
adapter->rx_mbuf_sz = MJUM9BYTES;
@@ -1332,6 +1371,7 @@ em_init_locked(struct adapter *adapter)
/* Don't lose promiscuous settings */
em_set_promisc(adapter);
+ /* Set the interface as ACTIVE */
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
@@ -1362,9 +1402,6 @@ em_init_locked(struct adapter *adapter)
/* AMT based hardware can now take control from firmware */
if (adapter->has_manage && adapter->has_amt)
em_get_hw_control(adapter);
-
- /* Don't reset the phy next time init gets called */
- adapter->hw.phy.reset_disable = TRUE;
}
static void
@@ -1483,12 +1520,10 @@ em_handle_que(void *context, int pending)
struct ifnet *ifp = adapter->ifp;
struct tx_ring *txr = adapter->tx_rings;
struct rx_ring *rxr = adapter->rx_rings;
- bool more;
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- more = em_rxeof(rxr, adapter->rx_process_limit, NULL);
-
+ bool more = em_rxeof(rxr, adapter->rx_process_limit, NULL);
EM_TX_LOCK(txr);
em_txeof(txr);
#ifdef EM_MULTIQUEUE
@@ -1498,7 +1533,6 @@ em_handle_que(void *context, int pending)
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
em_start_locked(ifp, txr);
#endif
- em_txeof(txr);
EM_TX_UNLOCK(txr);
if (more) {
taskqueue_enqueue(adapter->tq, &adapter->que_task);
@@ -1521,17 +1555,21 @@ em_msix_tx(void *arg)
{
struct tx_ring *txr = arg;
struct adapter *adapter = txr->adapter;
- bool more;
+ struct ifnet *ifp = adapter->ifp;
++txr->tx_irq;
EM_TX_LOCK(txr);
- more = em_txeof(txr);
+ em_txeof(txr);
+#ifdef EM_MULTIQUEUE
+ if (!drbr_empty(ifp, txr->br))
+ em_mq_start_locked(ifp, txr, NULL);
+#else
+ if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+ em_start_locked(ifp, txr);
+#endif
+ /* Reenable this interrupt */
+ E1000_WRITE_REG(&adapter->hw, E1000_IMS, txr->ims);
EM_TX_UNLOCK(txr);
- if (more)
- taskqueue_enqueue(txr->tq, &txr->tx_task);
- else
- /* Reenable this interrupt */
- E1000_WRITE_REG(&adapter->hw, E1000_IMS, txr->ims);
return;
}
@@ -1549,6 +1587,8 @@ em_msix_rx(void *arg)
bool more;
++rxr->rx_irq;
+ if (!(adapter->ifp->if_drv_flags & IFF_DRV_RUNNING))
+ return;
more = em_rxeof(rxr, adapter->rx_process_limit, NULL);
if (more)
taskqueue_enqueue(rxr->tq, &rxr->rx_task);
@@ -1612,7 +1652,6 @@ em_handle_tx(void *context, int pending)
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
em_start_locked(ifp, txr);
#endif
- em_txeof(txr);
E1000_WRITE_REG(&adapter->hw, E1000_IMS, txr->ims);
EM_TX_UNLOCK(txr);
}
@@ -1621,6 +1660,7 @@ static void
em_handle_link(void *context, int pending)
{
struct adapter *adapter = context;
+ struct tx_ring *txr = adapter->tx_rings;
struct ifnet *ifp = adapter->ifp;
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
@@ -1632,6 +1672,19 @@ em_handle_link(void *context, int pending)
callout_reset(&adapter->timer, hz, em_local_timer, adapter);
E1000_WRITE_REG(&adapter->hw, E1000_IMS,
EM_MSIX_LINK | E1000_IMS_LSC);
+ if (adapter->link_active) {
+ for (int i = 0; i < adapter->num_queues; i++, txr++) {
+ EM_TX_LOCK(txr);
+#ifdef EM_MULTIQUEUE
+ if (!drbr_empty(ifp, txr->br))
+ em_mq_start_locked(ifp, txr, NULL);
+#else
+ if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+ em_start_locked(ifp, txr);
+#endif
+ EM_TX_UNLOCK(txr);
+ }
+ }
EM_CORE_UNLOCK(adapter);
}
@@ -1767,8 +1820,9 @@ em_xmit(struct tx_ring *txr, struct mbuf **m_headp)
u32 txd_upper, txd_lower, txd_used, txd_saved;
int ip_off, poff;
int nsegs, i, j, first, last = 0;
- int error, do_tso, tso_desc = 0;
+ int error, do_tso, tso_desc = 0, remap = 1;
+retry:
m_head = *m_headp;
txd_upper = txd_lower = txd_used = txd_saved = 0;
do_tso = ((m_head->m_pkthdr.csum_flags & CSUM_TSO) != 0);
@@ -1792,7 +1846,7 @@ em_xmit(struct tx_ring *txr, struct mbuf **m_headp)
if (do_tso || (m_head->m_next != NULL &&
m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD)) {
if (M_WRITABLE(*m_headp) == 0) {
- m_head = m_dup(*m_headp, M_DONTWAIT);
+ m_head = m_dup(*m_headp, M_NOWAIT);
m_freem(*m_headp);
if (m_head == NULL) {
*m_headp = NULL;
@@ -1906,10 +1960,10 @@ em_xmit(struct tx_ring *txr, struct mbuf **m_headp)
* All other errors, in particular EINVAL, are fatal and prevent the
* mbuf chain from ever going through. Drop it and report error.
*/
- if (error == EFBIG) {
+ if (error == EFBIG && remap) {
struct mbuf *m;
- m = m_defrag(*m_headp, M_DONTWAIT);
+ m = m_defrag(*m_headp, M_NOWAIT);
if (m == NULL) {
adapter->mbuf_alloc_failed++;
m_freem(*m_headp);
@@ -1918,20 +1972,9 @@ em_xmit(struct tx_ring *txr, struct mbuf **m_headp)
}
*m_headp = m;
- /* Try it again */
- error = bus_dmamap_load_mbuf_sg(txr->txtag, map,
- *m_headp, segs, &nsegs, BUS_DMA_NOWAIT);
-
- if (error == ENOMEM) {
- adapter->no_tx_dma_setup++;
- return (error);
- } else if (error != 0) {
- adapter->no_tx_dma_setup++;
- m_freem(*m_headp);
- *m_headp = NULL;
- return (error);
- }
-
+ /* Try it again, but only once */
+ remap = 0;
+ goto retry;
} else if (error == ENOMEM) {
adapter->no_tx_dma_setup++;
return (error);
@@ -1971,6 +2014,14 @@ em_xmit(struct tx_ring *txr, struct mbuf **m_headp)
em_transmit_checksum_setup(txr, m_head,
ip_off, ip, &txd_upper, &txd_lower);
+ if (m_head->m_flags & M_VLANTAG) {
+ /* Set the vlan id. */
+ txd_upper |=
+ (htole16(m_head->m_pkthdr.ether_vtag) << 16);
+ /* Tell hardware to add tag */
+ txd_lower |= htole32(E1000_TXD_CMD_VLE);
+ }
+
i = txr->next_avail_desc;
/* Set up our transmit descriptors */
@@ -2028,15 +2079,13 @@ em_xmit(struct tx_ring *txr, struct mbuf **m_headp)
if (tso_desc) /* TSO used an extra for sentinel */
txr->tx_avail -= txd_used;
- if (m_head->m_flags & M_VLANTAG) {
- /* Set the vlan id. */
- ctxd->upper.fields.special =
- htole16(m_head->m_pkthdr.ether_vtag);
- /* Tell hardware to add tag */
- ctxd->lower.data |= htole32(E1000_TXD_CMD_VLE);
- }
-
tx_buffer->m_head = m_head;
+ /*
+ ** Here we swap the map so the last descriptor,
+ ** which gets the completion interrupt has the
+ ** real map, and the first descriptor gets the
+ ** unused map from this descriptor.
+ */
tx_buffer_mapped->map = tx_buffer->map;
tx_buffer->map = map;
bus_dmamap_sync(txr->txtag, map, BUS_DMASYNC_PREWRITE);
@@ -2187,6 +2236,8 @@ em_local_timer(void *arg)
struct adapter *adapter = arg;
struct ifnet *ifp = adapter->ifp;
struct tx_ring *txr = adapter->tx_rings;
+ struct rx_ring *rxr = adapter->rx_rings;
+ u32 trigger;
EM_CORE_LOCK_ASSERT(adapter);
@@ -2198,23 +2249,32 @@ em_local_timer(void *arg)
e1000_get_laa_state_82571(&adapter->hw))
e1000_rar_set(&adapter->hw, adapter->hw.mac.addr, 0);
- /*
- ** Don't do TX watchdog check if we've been paused
- */
- if (adapter->pause_frames) {
- adapter->pause_frames = 0;
- goto out;
- }
+ /* Mask to use in the irq trigger */
+ if (adapter->msix_mem)
+ trigger = rxr->ims; /* RX for 82574 */
+ else
+ trigger = E1000_ICS_RXDMT0;
+
/*
** Check on the state of the TX queue(s), this
** can be done without the lock because its RO
** and the HUNG state will be static if set.
*/
- for (int i = 0; i < adapter->num_queues; i++, txr++)
- if (txr->queue_status == EM_QUEUE_HUNG)
+ for (int i = 0; i < adapter->num_queues; i++, txr++) {
+ if ((txr->queue_status == EM_QUEUE_HUNG) &&
+ (adapter->pause_frames == 0))
goto hung;
-out:
+ /* Schedule a TX tasklet if needed */
+ if (txr->tx_avail <= EM_MAX_SCATTER)
+ taskqueue_enqueue(txr->tq, &txr->tx_task);
+ }
+
+ adapter->pause_frames = 0;
callout_reset(&adapter->timer, hz, em_local_timer, adapter);
+#ifndef DEVICE_POLLING
+ /* Trigger an RX interrupt to guarantee mbuf refresh */
+ E1000_WRITE_REG(&adapter->hw, E1000_ICS, trigger);
+#endif
return;
hung:
/* Looks like we're hung */
@@ -2228,6 +2288,7 @@ hung:
txr->me, txr->tx_avail, txr->next_to_clean);
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
adapter->watchdog_events++;
+ adapter->pause_frames = 0;
em_init_locked(adapter);
}
@@ -2326,7 +2387,8 @@ em_stop(void *arg)
callout_stop(&adapter->timer);
/* Tell the stack that the interface is no longer active */
- ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
/* Unarm watchdog timer. */
for (int i = 0; i < adapter->num_queues; i++, txr++) {
@@ -2422,6 +2484,7 @@ int
em_allocate_legacy(struct adapter *adapter)
{
device_t dev = adapter->dev;
+ struct tx_ring *txr = adapter->tx_rings;
int error, rid = 0;
/* Manually turn off all interrupts */
@@ -2443,11 +2506,17 @@ em_allocate_legacy(struct adapter *adapter)
* deferred processing contexts.
*/
TASK_INIT(&adapter->que_task, 0, em_handle_que, adapter);
- TASK_INIT(&adapter->link_task, 0, em_handle_link, adapter);
adapter->tq = taskqueue_create_fast("em_taskq", M_NOWAIT,
taskqueue_thread_enqueue, &adapter->tq);
- taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s taskq",
+ taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s que",
device_get_nameunit(adapter->dev));
+ /* Use a TX only tasklet for local timer */
+ TASK_INIT(&txr->tx_task, 0, em_handle_tx, txr);
+ txr->tq = taskqueue_create_fast("em_txq", M_NOWAIT,
+ taskqueue_thread_enqueue, &txr->tq);
+ taskqueue_start_threads(&txr->tq, 1, PI_NET, "%s txq",
+ device_get_nameunit(adapter->dev));
+ TASK_INIT(&adapter->link_task, 0, em_handle_link, adapter);
if ((error = bus_setup_intr(dev, adapter->res, INTR_TYPE_NET,
em_irq_fast, NULL, adapter, &adapter->tag)) != 0) {
device_printf(dev, "Failed to register fast interrupt "
@@ -2464,7 +2533,8 @@ em_allocate_legacy(struct adapter *adapter)
*
* Setup the MSIX Interrupt handlers
* This is not really Multiqueue, rather
- * its just multiple interrupt vectors.
+ * its just seperate interrupt vectors
+ * for TX, RX, and Link.
*
**********************************************************************/
int
@@ -2656,7 +2726,6 @@ em_setup_msix(struct adapter *adapter)
device_t dev = adapter->dev;
int val = 0;
-
/*
** Setup MSI/X for Hartwell: tests have shown
** use of two queues to be unstable, and to
@@ -2676,16 +2745,18 @@ em_setup_msix(struct adapter *adapter)
goto msi;
}
val = pci_msix_count(dev);
- if (val < 3) {
+ /* We only need 3 vectors */
+ if (val > 3)
+ val = 3;
+ if ((val != 3) && (val != 5)) {
bus_release_resource(dev, SYS_RES_MEMORY,
PCIR_BAR(EM_MSIX_BAR), adapter->msix_mem);
adapter->msix_mem = NULL;
device_printf(adapter->dev,
- "MSIX: insufficient vectors, using MSI\n");
+ "MSIX: incorrect vectors, using MSI\n");
goto msi;
}
- val = 3;
- adapter->num_queues = 1;
+
if (pci_alloc_msix(dev, &val) == 0) {
device_printf(adapter->dev,
"Using MSIX interrupts "
@@ -2720,6 +2791,7 @@ em_reset(struct adapter *adapter)
struct ifnet *ifp = adapter->ifp;
struct e1000_hw *hw = &adapter->hw;
u16 rx_buffer_size;
+ u32 pba;
INIT_DEBUGOUT("em_reset: begin");
@@ -2735,6 +2807,49 @@ em_reset(struct adapter *adapter)
}
/*
+ * Packet Buffer Allocation (PBA)
+ * Writing PBA sets the receive portion of the buffer
+ * the remainder is used for the transmit buffer.
+ */
+ switch (hw->mac.type) {
+ /* Total Packet Buffer on these is 48K */
+ case e1000_82571:
+ case e1000_82572:
+ case e1000_80003es2lan:
+ pba = E1000_PBA_32K; /* 32K for Rx, 16K for Tx */
+ break;
+ case e1000_82573: /* 82573: Total Packet Buffer is 32K */
+ pba = E1000_PBA_12K; /* 12K for Rx, 20K for Tx */
+ 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:
+ /* Boost Receive side for jumbo frames */
+ if (adapter->hw.mac.max_frame_size > 4096)
+ pba = E1000_PBA_14K;
+ else
+ pba = E1000_PBA_10K;
+ break;
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ case e1000_pch_lpt:
+ pba = E1000_PBA_26K;
+ break;
+ default:
+ if (adapter->hw.mac.max_frame_size > 8192)
+ pba = E1000_PBA_40K; /* 40K for Rx, 24K for Tx */
+ else
+ pba = E1000_PBA_48K; /* 48K for Rx, 16K for Tx */
+ }
+ E1000_WRITE_REG(&adapter->hw, E1000_PBA, pba);
+
+ /*
* These parameters control the automatic generation (Tx) and
* response (Rx) to Ethernet PAUSE frames.
* - High water mark should allow for at least two frames to be
@@ -2749,11 +2864,15 @@ em_reset(struct adapter *adapter)
* - The pause time is fairly large at 1000 x 512ns = 512 usec.
*/
rx_buffer_size = ((E1000_READ_REG(hw, E1000_PBA) & 0xffff) << 10 );
-
hw->fc.high_water = rx_buffer_size -
- roundup2(adapter->max_frame_size, 1024);
+ roundup2(adapter->hw.mac.max_frame_size, 1024);
hw->fc.low_water = hw->fc.high_water - 1500;
+ if (adapter->fc) /* locally set flow control value? */
+ hw->fc.requested_mode = adapter->fc;
+ else
+ hw->fc.requested_mode = e1000_fc_full;
+
if (hw->mac.type == e1000_80003es2lan)
hw->fc.pause_time = 0xFFFF;
else
@@ -2761,15 +2880,23 @@ em_reset(struct adapter *adapter)
hw->fc.send_xon = TRUE;
- /* Set Flow control, use the tunable location if sane */
- hw->fc.requested_mode = adapter->fc_setting;
-
- /* Workaround: no TX flow ctrl for PCH */
- if (hw->mac.type == e1000_pchlan)
+ /* Device specific overrides/settings */
+ switch (hw->mac.type) {
+ case e1000_pchlan:
+ /* Workaround: no TX flow ctrl for PCH */
hw->fc.requested_mode = e1000_fc_rx_pause;
-
- /* Override - settings for PCH2LAN, ya its magic :) */
- if (hw->mac.type == e1000_pch2lan) {
+ hw->fc.pause_time = 0xFFFF; /* override */
+ if (ifp->if_mtu > ETHERMTU) {
+ hw->fc.high_water = 0x3500;
+ hw->fc.low_water = 0x1500;
+ } else {
+ hw->fc.high_water = 0x5000;
+ hw->fc.low_water = 0x3000;
+ }
+ hw->fc.refresh_time = 0x1000;
+ break;
+ case e1000_pch2lan:
+ case e1000_pch_lpt:
hw->fc.high_water = 0x5C20;
hw->fc.low_water = 0x5048;
hw->fc.pause_time = 0x0650;
@@ -2779,13 +2906,26 @@ em_reset(struct adapter *adapter)
E1000_WRITE_REG(hw, E1000_PBA, 12);
else
E1000_WRITE_REG(hw, E1000_PBA, 26);
+ break;
+ case e1000_ich9lan:
+ case e1000_ich10lan:
+ if (ifp->if_mtu > ETHERMTU) {
+ hw->fc.high_water = 0x2800;
+ hw->fc.low_water = hw->fc.high_water - 8;
+ break;
+ }
+ /* else fall thru */
+ default:
+ if (hw->mac.type == e1000_80003es2lan)
+ hw->fc.pause_time = 0xFFFF;
+ break;
}
/* Issue a global reset */
e1000_reset_hw(hw);
E1000_WRITE_REG(hw, E1000_WUC, 0);
em_disable_aspm(adapter);
-
+ /* and a re-init */
if (e1000_init_hw(hw) < 0) {
device_printf(dev, "Hardware Initialization Failed\n");
return;
@@ -2815,43 +2955,40 @@ em_setup_interface(device_t dev, struct adapter *adapter)
return (-1);
}
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
- ifp->if_mtu = ETHERMTU;
ifp->if_init = em_init;
ifp->if_softc = adapter;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = em_ioctl;
+#ifdef EM_MULTIQUEUE
+ /* Multiqueue stack interface */
+ ifp->if_transmit = em_mq_start;
+ ifp->if_qflush = em_qflush;
+#else
ifp->if_start = em_start;
IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 1);
ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 1;
IFQ_SET_READY(&ifp->if_snd);
+#endif
ether_ifattach(ifp, adapter->hw.mac.addr);
ifp->if_capabilities = ifp->if_capenable = 0;
-#ifdef EM_MULTIQUEUE
- /* Multiqueue tx functions */
- ifp->if_transmit = em_mq_start;
- ifp->if_qflush = em_qflush;
-#endif
ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM;
- ifp->if_capenable |= IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM;
-
- /* Enable TSO by default, can disable with ifconfig */
ifp->if_capabilities |= IFCAP_TSO4;
- ifp->if_capenable |= IFCAP_TSO4;
-
/*
* Tell the upper layer(s) we
* support full VLAN capability
*/
ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
- ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
- ifp->if_capenable |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
+ ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING
+ | IFCAP_VLAN_HWTSO
+ | IFCAP_VLAN_MTU;
+ ifp->if_capenable = ifp->if_capabilities;
/*
- ** Dont turn this on by default, if vlans are
+ ** Don't turn this on by default, if vlans are
** created on another pseudo device (eg. lagg)
** then vlan events are not passed thru, breaking
** operation, but with HW FILTER off it works. If
@@ -3188,9 +3325,17 @@ em_setup_transmit_ring(struct tx_ring *txr)
struct adapter *adapter = txr->adapter;
struct em_buffer *txbuf;
int i;
+#ifdef DEV_NETMAP
+ struct netmap_adapter *na = NA(adapter->ifp);
+ struct netmap_slot *slot;
+#endif /* DEV_NETMAP */
/* Clear the old descriptor contents */
EM_TX_LOCK(txr);
+#ifdef DEV_NETMAP
+ slot = netmap_reset(na, NR_TX, txr->me, 0);
+#endif /* DEV_NETMAP */
+
bzero((void *)txr->tx_base,
(sizeof(struct e1000_tx_desc)) * adapter->num_tx_desc);
/* Reset indices */
@@ -3207,6 +3352,19 @@ em_setup_transmit_ring(struct tx_ring *txr)
m_freem(txbuf->m_head);
txbuf->m_head = NULL;
}
+#ifdef DEV_NETMAP
+ if (slot) {
+ int si = netmap_idx_n2k(&na->tx_rings[txr->me], i);
+ uint64_t paddr;
+ void *addr;
+
+ addr = PNMB(slot + si, &paddr);
+ txr->tx_base[i].buffer_addr = htole64(paddr);
+ /* reload the map for netmap mode */
+ netmap_load_map(txr->txtag, txbuf->map, addr);
+ }
+#endif /* DEV_NETMAP */
+
/* clear the watch index */
txbuf->next_eop = -1;
}
@@ -3279,11 +3437,6 @@ em_initialize_transmit_unit(struct adapter *adapter)
/* Set the default values for the Tx Inter Packet Gap timer */
switch (adapter->hw.mac.type) {
- case e1000_82542:
- tipg = DEFAULT_82542_TIPG_IPGT;
- tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
- tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
- break;
case e1000_80003es2lan:
tipg = DEFAULT_82543_TIPG_IPGR1;
tipg |= DEFAULT_80003ES2LAN_TIPG_IPGR2 <<
@@ -3647,7 +3800,7 @@ em_tso_setup(struct tx_ring *txr, struct mbuf *mp, int ip_off,
* tx_buffer is put back on the free queue.
*
**********************************************************************/
-static bool
+static void
em_txeof(struct tx_ring *txr)
{
struct adapter *adapter = txr->adapter;
@@ -3657,11 +3810,24 @@ em_txeof(struct tx_ring *txr)
struct ifnet *ifp = adapter->ifp;
EM_TX_LOCK_ASSERT(txr);
+#ifdef DEV_NETMAP
+ if (ifp->if_capenable & IFCAP_NETMAP) {
+ struct netmap_adapter *na = NA(ifp);
+
+ selwakeuppri(&na->tx_rings[txr->me].si, PI_NET);
+ EM_TX_UNLOCK(txr);
+ EM_CORE_LOCK(adapter);
+ selwakeuppri(&na->tx_si, PI_NET);
+ EM_CORE_UNLOCK(adapter);
+ EM_TX_LOCK(txr);
+ return;
+ }
+#endif /* DEV_NETMAP */
/* No work, make sure watchdog is off */
if (txr->tx_avail == adapter->num_tx_desc) {
txr->queue_status = EM_QUEUE_IDLE;
- return (FALSE);
+ return;
}
processed = 0;
@@ -3738,19 +3904,19 @@ em_txeof(struct tx_ring *txr)
txr->queue_status = EM_QUEUE_HUNG;
/*
- * If we have enough room, clear IFF_DRV_OACTIVE
+ * If we have a minimum free, clear IFF_DRV_OACTIVE
* to tell the stack that it is OK to send packets.
+ * Notice that all writes of OACTIVE happen under the
+ * TX lock which, with a single queue, guarantees
+ * sanity.
*/
- if (txr->tx_avail > EM_TX_CLEANUP_THRESHOLD) {
- ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- /* Disable watchdog if all clean */
- if (txr->tx_avail == adapter->num_tx_desc) {
- txr->queue_status = EM_QUEUE_IDLE;
- return (FALSE);
- }
- }
+ if (txr->tx_avail >= EM_MAX_SCATTER)
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- return (TRUE);
+ /* Disable watchdog if all clean */
+ if (txr->tx_avail == adapter->num_tx_desc) {
+ txr->queue_status = EM_QUEUE_IDLE;
+ }
}
@@ -3766,14 +3932,22 @@ em_refresh_mbufs(struct rx_ring *rxr, int limit)
struct mbuf *m;
bus_dma_segment_t segs[1];
struct em_buffer *rxbuf;
- int i, error, nsegs, cleaned;
+ int i, j, error, nsegs;
+ bool cleaned = FALSE;
+
+ i = j = rxr->next_to_refresh;
+ /*
+ ** Get one descriptor beyond
+ ** our work mark to control
+ ** the loop.
+ */
+ if (++j == adapter->num_rx_desc)
+ j = 0;
- i = rxr->next_to_refresh;
- cleaned = -1;
- while (i != limit) {
+ while (j != limit) {
rxbuf = &rxr->rx_buffers[i];
if (rxbuf->m_head == NULL) {
- m = m_getjcl(M_DONTWAIT, MT_DATA,
+ m = m_getjcl(M_NOWAIT, MT_DATA,
M_PKTHDR, adapter->rx_mbuf_sz);
/*
** If we have a temporary resource shortage
@@ -3804,21 +3978,22 @@ em_refresh_mbufs(struct rx_ring *rxr, int limit)
bus_dmamap_sync(rxr->rxtag,
rxbuf->map, BUS_DMASYNC_PREREAD);
rxr->rx_base[i].buffer_addr = htole64(segs[0].ds_addr);
+ cleaned = TRUE;
- cleaned = i;
- /* Calculate next index */
- if (++i == adapter->num_rx_desc)
- i = 0;
+ i = j; /* Next is precalulated for us */
rxr->next_to_refresh = i;
+ /* Calculate next controlling index */
+ if (++j == adapter->num_rx_desc)
+ j = 0;
}
update:
/*
** Update the tail pointer only if,
** and as far as we have refreshed.
*/
- if (cleaned != -1) /* Update tail index */
+ if (cleaned)
E1000_WRITE_REG(&adapter->hw,
- E1000_RDT(rxr->me), cleaned);
+ E1000_RDT(rxr->me), rxr->next_to_refresh);
return;
}
@@ -3896,7 +4071,11 @@ em_setup_receive_ring(struct rx_ring *rxr)
struct adapter *adapter = rxr->adapter;
struct em_buffer *rxbuf;
bus_dma_segment_t seg[1];
- int rsize, nsegs, error;
+ int rsize, nsegs, error = 0;
+#ifdef DEV_NETMAP
+ struct netmap_adapter *na = NA(adapter->ifp);
+ struct netmap_slot *slot;
+#endif
/* Clear the ring contents */
@@ -3904,6 +4083,9 @@ em_setup_receive_ring(struct rx_ring *rxr)
rsize = roundup2(adapter->num_rx_desc *
sizeof(struct e1000_rx_desc), EM_DBA_ALIGN);
bzero((void *)rxr->rx_base, rsize);
+#ifdef DEV_NETMAP
+ slot = netmap_reset(na, NR_RX, 0, 0);
+#endif
/*
** Free current RX buffer structs and their mbufs
@@ -3915,17 +4097,32 @@ em_setup_receive_ring(struct rx_ring *rxr)
BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(rxr->rxtag, rxbuf->map);
m_freem(rxbuf->m_head);
+ rxbuf->m_head = NULL; /* mark as freed */
}
}
/* Now replenish the mbufs */
- for (int j = 0; j != adapter->num_rx_desc; ++j) {
-
+ for (int j = 0; j != adapter->num_rx_desc; ++j) {
rxbuf = &rxr->rx_buffers[j];
- rxbuf->m_head = m_getjcl(M_DONTWAIT, MT_DATA,
+#ifdef DEV_NETMAP
+ if (slot) {
+ int si = netmap_idx_n2k(&na->rx_rings[rxr->me], j);
+ uint64_t paddr;
+ void *addr;
+
+ addr = PNMB(slot + si, &paddr);
+ netmap_load_map(rxr->rxtag, rxbuf->map, addr);
+ /* Update descriptor */
+ rxr->rx_base[j].buffer_addr = htole64(paddr);
+ continue;
+ }
+#endif /* DEV_NETMAP */
+ rxbuf->m_head = m_getjcl(M_NOWAIT, MT_DATA,
M_PKTHDR, adapter->rx_mbuf_sz);
- if (rxbuf->m_head == NULL)
- return (ENOBUFS);
+ if (rxbuf->m_head == NULL) {
+ error = ENOBUFS;
+ goto fail;
+ }
rxbuf->m_head->m_len = adapter->rx_mbuf_sz;
rxbuf->m_head->m_flags &= ~M_HASFCS; /* we strip it */
rxbuf->m_head->m_pkthdr.len = adapter->rx_mbuf_sz;
@@ -3937,7 +4134,7 @@ em_setup_receive_ring(struct rx_ring *rxr)
if (error != 0) {
m_freem(rxbuf->m_head);
rxbuf->m_head = NULL;
- return (error);
+ goto fail;
}
bus_dmamap_sync(rxr->rxtag,
rxbuf->map, BUS_DMASYNC_PREREAD);
@@ -3945,17 +4142,14 @@ em_setup_receive_ring(struct rx_ring *rxr)
/* Update descriptor */
rxr->rx_base[j].buffer_addr = htole64(seg[0].ds_addr);
}
-
-
- /* Setup our descriptor indices */
rxr->next_to_check = 0;
rxr->next_to_refresh = 0;
-
bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+fail:
EM_RX_UNLOCK(rxr);
- return (0);
+ return (error);
}
/*********************************************************************
@@ -3967,9 +4161,9 @@ static int
em_setup_receive_structures(struct adapter *adapter)
{
struct rx_ring *rxr = adapter->rx_rings;
- int j;
+ int q;
- for (j = 0; j < adapter->num_queues; j++, rxr++)
+ for (q = 0; q < adapter->num_queues; q++, rxr++)
if (em_setup_receive_ring(rxr))
goto fail;
@@ -3978,9 +4172,9 @@ fail:
/*
* Free RX buffers allocated so far, we will only handle
* the rings that completed, the failing case will have
- * cleaned up for itself. 'j' failed, so its the terminus.
+ * cleaned up for itself. 'q' failed, so its the terminus.
*/
- for (int i = 0; i < j; ++i) {
+ for (int i = 0; i < q; ++i) {
rxr = &adapter->rx_rings[i];
for (int n = 0; n < adapter->num_rx_desc; n++) {
struct em_buffer *rxbuf;
@@ -3993,6 +4187,8 @@ fail:
rxbuf->m_head = NULL;
}
}
+ rxr->next_to_check = 0;
+ rxr->next_to_refresh = 0;
}
return (ENOBUFS);
@@ -4048,6 +4244,8 @@ em_free_receive_buffers(struct rx_ring *rxr)
}
free(rxr->rx_buffers, M_DEVBUF);
rxr->rx_buffers = NULL;
+ rxr->next_to_check = 0;
+ rxr->next_to_refresh = 0;
}
if (rxr->rxtag != NULL) {
@@ -4083,7 +4281,9 @@ em_initialize_receive_unit(struct adapter *adapter)
* up the descriptor ring
*/
rctl = E1000_READ_REG(hw, E1000_RCTL);
- E1000_WRITE_REG(hw, E1000_RCTL, rctl & ~E1000_RCTL_EN);
+ /* Do not disable if ever enabled on this hardware */
+ if ((hw->mac.type != e1000_82574) && (hw->mac.type != e1000_82583))
+ E1000_WRITE_REG(hw, E1000_RCTL, rctl & ~E1000_RCTL_EN);
E1000_WRITE_REG(&adapter->hw, E1000_RADV,
adapter->rx_abs_int_delay.value);
@@ -4097,14 +4297,13 @@ em_initialize_receive_unit(struct adapter *adapter)
** When using MSIX interrupts we need to throttle
** using the EITR register (82574 only)
*/
- if (hw->mac.type == e1000_82574)
+ if (hw->mac.type == e1000_82574) {
for (int i = 0; i < 4; i++)
E1000_WRITE_REG(hw, E1000_EITR_82574(i),
DEFAULT_ITR);
-
- /* Disable accelerated ackknowledge */
- if (adapter->hw.mac.type == e1000_82574)
+ /* Disable accelerated acknowledge */
E1000_WRITE_REG(hw, E1000_RFCTL, E1000_RFCTL_ACK_DIS);
+ }
if (ifp->if_capenable & IFCAP_RXCSUM) {
rxcsum = E1000_READ_REG(hw, E1000_RXCSUM);
@@ -4131,20 +4330,34 @@ em_initialize_receive_unit(struct adapter *adapter)
E1000_WRITE_REG(hw, E1000_RDBAL(i), (u32)bus_addr);
/* Setup the Head and Tail Descriptor Pointers */
E1000_WRITE_REG(hw, E1000_RDH(i), 0);
+#ifdef DEV_NETMAP
+ /*
+ * an init() while a netmap client is active must
+ * preserve the rx buffers passed to userspace.
+ * In this driver it means we adjust RDT to
+ * something different from na->num_rx_desc - 1.
+ */
+ if (ifp->if_capenable & IFCAP_NETMAP) {
+ struct netmap_adapter *na = NA(adapter->ifp);
+ struct netmap_kring *kring = &na->rx_rings[i];
+ int t = na->num_rx_desc - 1 - kring->nr_hwavail;
+
+ E1000_WRITE_REG(hw, E1000_RDT(i), t);
+ } else
+#endif /* DEV_NETMAP */
E1000_WRITE_REG(hw, E1000_RDT(i), adapter->num_rx_desc - 1);
}
- /* Set early receive threshold on appropriate hw */
+ /* Set PTHRESH for improved jumbo performance */
if (((adapter->hw.mac.type == e1000_ich9lan) ||
(adapter->hw.mac.type == e1000_pch2lan) ||
(adapter->hw.mac.type == e1000_ich10lan)) &&
(ifp->if_mtu > ETHERMTU)) {
u32 rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(0));
E1000_WRITE_REG(hw, E1000_RXDCTL(0), rxdctl | 3);
- E1000_WRITE_REG(hw, E1000_ERT, 0x100 | (1 << 13));
}
- if (adapter->hw.mac.type == e1000_pch2lan) {
+ if (adapter->hw.mac.type >= e1000_pch2lan) {
if (ifp->if_mtu > ETHERMTU)
e1000_lv_jumbo_workaround_ich8lan(hw, TRUE);
else
@@ -4208,6 +4421,20 @@ em_rxeof(struct rx_ring *rxr, int count, int *done)
EM_RX_LOCK(rxr);
+#ifdef DEV_NETMAP
+ if (ifp->if_capenable & IFCAP_NETMAP) {
+ struct netmap_adapter *na = NA(ifp);
+
+ na->rx_rings[rxr->me].nr_kflags |= NKR_PENDINTR;
+ selwakeuppri(&na->rx_rings[rxr->me].si, PI_NET);
+ EM_RX_UNLOCK(rxr);
+ EM_CORE_LOCK(adapter);
+ selwakeuppri(&na->rx_si, PI_NET);
+ EM_CORE_UNLOCK(adapter);
+ return (0);
+ }
+#endif /* DEV_NETMAP */
+
for (i = rxr->next_to_check, processed = 0; count != 0;) {
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
@@ -4228,7 +4455,7 @@ em_rxeof(struct rx_ring *rxr, int count, int *done)
if ((cur->errors & E1000_RXD_ERR_FRAME_ERR_MASK) ||
(rxr->discard == TRUE)) {
- ifp->if_ierrors++;
+ adapter->dropped_pkts++;
++rxr->rx_discarded;
if (!eop) /* Catch subsequent segs */
rxr->discard = TRUE;
@@ -4264,21 +4491,16 @@ em_rxeof(struct rx_ring *rxr, int count, int *done)
ifp->if_ipackets++;
em_receive_checksum(cur, sendmp);
#ifndef __NO_STRICT_ALIGNMENT
- if (adapter->max_frame_size >
+ if (adapter->hw.mac.max_frame_size >
(MCLBYTES - ETHER_ALIGN) &&
em_fixup_rx(rxr) != 0)
goto skip;
#endif
if (status & E1000_RXD_STAT_VP) {
sendmp->m_pkthdr.ether_vtag =
- (le16toh(cur->special) &
- E1000_RXD_SPC_VLAN_MASK);
+ le16toh(cur->special);
sendmp->m_flags |= M_VLANTAG;
}
-#ifdef EM_MULTIQUEUE
- sendmp->m_pkthdr.flowid = rxr->msix;
- sendmp->m_flags |= M_FLOWID;
-#endif
#ifndef __NO_STRICT_ALIGNMENT
skip:
#endif
@@ -4311,7 +4533,8 @@ next_desc:
}
/* Catch any remaining refresh work */
- em_refresh_mbufs(rxr, i);
+ if (e1000_rx_unrefreshed(rxr))
+ em_refresh_mbufs(rxr, i);
rxr->next_to_check = i;
if (done != NULL)
@@ -4373,7 +4596,7 @@ em_fixup_rx(struct rx_ring *rxr)
bcopy(m->m_data, m->m_data + ETHER_HDR_LEN, m->m_len);
m->m_data += ETHER_HDR_LEN;
} else {
- MGETHDR(n, M_DONTWAIT, MT_DATA);
+ MGETHDR(n, M_NOWAIT, MT_DATA);
if (n != NULL) {
bcopy(m->m_data, n->m_data, ETHER_HDR_LEN);
m->m_data += ETHER_HDR_LEN;
@@ -4739,7 +4962,7 @@ em_enable_wakeup(device_t dev)
u32 pmc, ctrl, ctrl_ext, rctl;
u16 status;
- if ((pci_find_extcap(dev, PCIY_PMG, &pmc) != 0))
+ if ((pci_find_cap(dev, PCIY_PMG, &pmc) != 0))
return;
/* Advertise the wakeup capability */
@@ -4751,10 +4974,8 @@ em_enable_wakeup(device_t dev)
if ((adapter->hw.mac.type == e1000_ich8lan) ||
(adapter->hw.mac.type == e1000_pchlan) ||
(adapter->hw.mac.type == e1000_ich9lan) ||
- (adapter->hw.mac.type == e1000_ich10lan)) {
- e1000_disable_gig_wol_ich8lan(&adapter->hw);
- e1000_hv_phy_powerdown_workaround_ich8lan(&adapter->hw);
- }
+ (adapter->hw.mac.type == e1000_ich10lan))
+ e1000_suspend_workarounds_ich8lan(&adapter->hw);
/* Keep the laser running on Fiber adapters */
if (adapter->hw.phy.media_type == e1000_media_type_fiber ||
@@ -4909,15 +5130,15 @@ em_disable_aspm(struct adapter *adapter)
default:
return;
}
- if (pci_find_extcap(dev, PCIY_EXPRESS, &base) != 0)
+ if (pci_find_cap(dev, PCIY_EXPRESS, &base) != 0)
return;
- reg = base + PCIR_EXPRESS_LINK_CAP;
+ reg = base + PCIER_LINK_CAP;
link_cap = pci_read_config(dev, reg, 2);
- if ((link_cap & PCIM_LINK_CAP_ASPM) == 0)
+ if ((link_cap & PCIEM_LINK_CAP_ASPM) == 0)
return;
- reg = base + PCIR_EXPRESS_LINK_CTL;
+ reg = base + PCIER_LINK_CTL;
link_ctrl = pci_read_config(dev, reg, 2);
- link_ctrl &= 0xFFFC; /* turn off bit 1 and 2 */
+ link_ctrl &= ~PCIEM_LINK_CTL_ASPMC;
pci_write_config(dev, reg, link_ctrl, 2);
return;
}
@@ -5072,8 +5293,8 @@ em_add_hw_stats(struct adapter *adapter)
char namebuf[QUEUE_NAME_LEN];
/* Driver Statistics */
- SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "link_irq",
- CTLFLAG_RD, &adapter->link_irq, 0,
+ SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq",
+ CTLFLAG_RD, &adapter->link_irq,
"Link MSIX IRQ Handled");
SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_alloc_fail",
CTLFLAG_RD, &adapter->mbuf_alloc_failed,
@@ -5095,11 +5316,11 @@ em_add_hw_stats(struct adapter *adapter)
"Watchdog timeouts");
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "device_control",
- CTLFLAG_RD, adapter, E1000_CTRL,
+ CTLTYPE_UINT | CTLFLAG_RD, adapter, E1000_CTRL,
em_sysctl_reg_handler, "IU",
"Device Control Register");
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_control",
- CTLFLAG_RD, adapter, E1000_RCTL,
+ CTLTYPE_UINT | CTLFLAG_RD, adapter, E1000_RCTL,
em_sysctl_reg_handler, "IU",
"Receiver Control Register");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "fc_high_water",
@@ -5116,11 +5337,13 @@ em_add_hw_stats(struct adapter *adapter)
queue_list = SYSCTL_CHILDREN(queue_node);
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head",
- CTLFLAG_RD, adapter, E1000_TDH(txr->me),
+ CTLTYPE_UINT | CTLFLAG_RD, adapter,
+ E1000_TDH(txr->me),
em_sysctl_reg_handler, "IU",
"Transmit Descriptor Head");
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail",
- CTLFLAG_RD, adapter, E1000_TDT(txr->me),
+ CTLTYPE_UINT | CTLFLAG_RD, adapter,
+ E1000_TDT(txr->me),
em_sysctl_reg_handler, "IU",
"Transmit Descriptor Tail");
SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tx_irq",
@@ -5131,11 +5354,13 @@ em_add_hw_stats(struct adapter *adapter)
"Queue No Descriptor Available");
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head",
- CTLFLAG_RD, adapter, E1000_RDH(rxr->me),
+ CTLTYPE_UINT | CTLFLAG_RD, adapter,
+ E1000_RDH(rxr->me),
em_sysctl_reg_handler, "IU",
"Receive Descriptor Head");
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail",
- CTLFLAG_RD, adapter, E1000_RDT(rxr->me),
+ CTLTYPE_UINT | CTLFLAG_RD, adapter,
+ E1000_RDT(rxr->me),
em_sysctl_reg_handler, "IU",
"Receive Descriptor Tail");
SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "rx_irq",
@@ -5149,147 +5374,147 @@ em_add_hw_stats(struct adapter *adapter)
CTLFLAG_RD, NULL, "Statistics");
stat_list = SYSCTL_CHILDREN(stat_node);
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "excess_coll",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "excess_coll",
CTLFLAG_RD, &stats->ecol,
"Excessive collisions");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "single_coll",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "single_coll",
CTLFLAG_RD, &stats->scc,
"Single collisions");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "multiple_coll",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "multiple_coll",
CTLFLAG_RD, &stats->mcc,
"Multiple collisions");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "late_coll",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "late_coll",
CTLFLAG_RD, &stats->latecol,
"Late collisions");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "collision_count",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "collision_count",
CTLFLAG_RD, &stats->colc,
"Collision Count");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "symbol_errors",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "symbol_errors",
CTLFLAG_RD, &adapter->stats.symerrs,
"Symbol Errors");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "sequence_errors",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "sequence_errors",
CTLFLAG_RD, &adapter->stats.sec,
"Sequence Errors");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "defer_count",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "defer_count",
CTLFLAG_RD, &adapter->stats.dc,
"Defer Count");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "missed_packets",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "missed_packets",
CTLFLAG_RD, &adapter->stats.mpc,
"Missed Packets");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_no_buff",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_no_buff",
CTLFLAG_RD, &adapter->stats.rnbc,
"Receive No Buffers");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_undersize",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersize",
CTLFLAG_RD, &adapter->stats.ruc,
"Receive Undersize");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_fragmented",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented",
CTLFLAG_RD, &adapter->stats.rfc,
"Fragmented Packets Received ");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_oversize",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversize",
CTLFLAG_RD, &adapter->stats.roc,
"Oversized Packets Received");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_jabber",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabber",
CTLFLAG_RD, &adapter->stats.rjc,
"Recevied Jabber");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_errs",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_errs",
CTLFLAG_RD, &adapter->stats.rxerrc,
"Receive Errors");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "crc_errs",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs",
CTLFLAG_RD, &adapter->stats.crcerrs,
"CRC errors");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "alignment_errs",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "alignment_errs",
CTLFLAG_RD, &adapter->stats.algnerrc,
"Alignment Errors");
/* On 82575 these are collision counts */
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "coll_ext_errs",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "coll_ext_errs",
CTLFLAG_RD, &adapter->stats.cexterr,
"Collision/Carrier extension errors");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "xon_recvd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd",
CTLFLAG_RD, &adapter->stats.xonrxc,
"XON Received");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "xon_txd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd",
CTLFLAG_RD, &adapter->stats.xontxc,
"XON Transmitted");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "xoff_recvd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd",
CTLFLAG_RD, &adapter->stats.xoffrxc,
"XOFF Received");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "xoff_txd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd",
CTLFLAG_RD, &adapter->stats.xofftxc,
"XOFF Transmitted");
/* Packet Reception Stats */
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "total_pkts_recvd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_recvd",
CTLFLAG_RD, &adapter->stats.tpr,
"Total Packets Received ");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_pkts_recvd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_recvd",
CTLFLAG_RD, &adapter->stats.gprc,
"Good Packets Received");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_recvd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_recvd",
CTLFLAG_RD, &adapter->stats.bprc,
"Broadcast Packets Received");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_recvd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_recvd",
CTLFLAG_RD, &adapter->stats.mprc,
"Multicast Packets Received");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_64",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64",
CTLFLAG_RD, &adapter->stats.prc64,
"64 byte frames received ");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127",
CTLFLAG_RD, &adapter->stats.prc127,
"65-127 byte frames received");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255",
CTLFLAG_RD, &adapter->stats.prc255,
"128-255 byte frames received");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511",
CTLFLAG_RD, &adapter->stats.prc511,
"256-511 byte frames received");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023",
CTLFLAG_RD, &adapter->stats.prc1023,
"512-1023 byte frames received");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522",
CTLFLAG_RD, &adapter->stats.prc1522,
"1023-1522 byte frames received");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octets_recvd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_recvd",
CTLFLAG_RD, &adapter->stats.gorc,
"Good Octets Received");
/* Packet Transmission Stats */
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octets_txd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd",
CTLFLAG_RD, &adapter->stats.gotc,
"Good Octets Transmitted");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd",
CTLFLAG_RD, &adapter->stats.tpt,
"Total Packets Transmitted");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd",
CTLFLAG_RD, &adapter->stats.gptc,
"Good Packets Transmitted");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd",
CTLFLAG_RD, &adapter->stats.bptc,
"Broadcast Packets Transmitted");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd",
CTLFLAG_RD, &adapter->stats.mptc,
"Multicast Packets Transmitted");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_64",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64",
CTLFLAG_RD, &adapter->stats.ptc64,
"64 byte frames transmitted ");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127",
CTLFLAG_RD, &adapter->stats.ptc127,
"65-127 byte frames transmitted");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255",
CTLFLAG_RD, &adapter->stats.ptc255,
"128-255 byte frames transmitted");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511",
CTLFLAG_RD, &adapter->stats.ptc511,
"256-511 byte frames transmitted");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023",
CTLFLAG_RD, &adapter->stats.ptc1023,
"512-1023 byte frames transmitted");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522",
CTLFLAG_RD, &adapter->stats.ptc1522,
"1024-1522 byte frames transmitted");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tso_txd",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tso_txd",
CTLFLAG_RD, &adapter->stats.tsctc,
"TSO Contexts Transmitted");
- SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tso_ctx_fail",
+ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tso_ctx_fail",
CTLFLAG_RD, &adapter->stats.tsctfc,
"TSO Contexts Failed");
@@ -5300,39 +5525,39 @@ em_add_hw_stats(struct adapter *adapter)
CTLFLAG_RD, NULL, "Interrupt Statistics");
int_list = SYSCTL_CHILDREN(int_node);
- SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "asserts",
+ SYSCTL_ADD_UQUAD(ctx, int_list, OID_AUTO, "asserts",
CTLFLAG_RD, &adapter->stats.iac,
"Interrupt Assertion Count");
- SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "rx_pkt_timer",
+ SYSCTL_ADD_UQUAD(ctx, int_list, OID_AUTO, "rx_pkt_timer",
CTLFLAG_RD, &adapter->stats.icrxptc,
"Interrupt Cause Rx Pkt Timer Expire Count");
- SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "rx_abs_timer",
+ SYSCTL_ADD_UQUAD(ctx, int_list, OID_AUTO, "rx_abs_timer",
CTLFLAG_RD, &adapter->stats.icrxatc,
"Interrupt Cause Rx Abs Timer Expire Count");
- SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "tx_pkt_timer",
+ SYSCTL_ADD_UQUAD(ctx, int_list, OID_AUTO, "tx_pkt_timer",
CTLFLAG_RD, &adapter->stats.ictxptc,
"Interrupt Cause Tx Pkt Timer Expire Count");
- SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "tx_abs_timer",
+ SYSCTL_ADD_UQUAD(ctx, int_list, OID_AUTO, "tx_abs_timer",
CTLFLAG_RD, &adapter->stats.ictxatc,
"Interrupt Cause Tx Abs Timer Expire Count");
- SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "tx_queue_empty",
+ SYSCTL_ADD_UQUAD(ctx, int_list, OID_AUTO, "tx_queue_empty",
CTLFLAG_RD, &adapter->stats.ictxqec,
"Interrupt Cause Tx Queue Empty Count");
- SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "tx_queue_min_thresh",
+ SYSCTL_ADD_UQUAD(ctx, int_list, OID_AUTO, "tx_queue_min_thresh",
CTLFLAG_RD, &adapter->stats.ictxqmtc,
"Interrupt Cause Tx Queue Min Thresh Count");
- SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "rx_desc_min_thresh",
+ SYSCTL_ADD_UQUAD(ctx, int_list, OID_AUTO, "rx_desc_min_thresh",
CTLFLAG_RD, &adapter->stats.icrxdmtc,
"Interrupt Cause Rx Desc Min Thresh Count");
- SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "rx_overrun",
+ SYSCTL_ADD_UQUAD(ctx, int_list, OID_AUTO, "rx_overrun",
CTLFLAG_RD, &adapter->stats.icrxoc,
"Interrupt Cause Receiver Overrun Count");
}
@@ -5347,7 +5572,7 @@ em_add_hw_stats(struct adapter *adapter)
static int
em_sysctl_nvm_info(SYSCTL_HANDLER_ARGS)
{
- struct adapter *adapter;
+ struct adapter *adapter = (struct adapter *)arg1;
int error;
int result;
@@ -5362,10 +5587,8 @@ em_sysctl_nvm_info(SYSCTL_HANDLER_ARGS)
* first 32 16-bit words of the EEPROM to
* the screen.
*/
- if (result == 1) {
- adapter = (struct adapter *)arg1;
+ if (result == 1)
em_print_nvm_info(adapter);
- }
return (error);
}
@@ -5446,7 +5669,7 @@ em_add_int_delay_sysctl(struct adapter *adapter, const char *name,
}
static void
-em_add_rx_process_limit(struct adapter *adapter, const char *name,
+em_set_sysctl_value(struct adapter *adapter, const char *name,
const char *description, int *limit, int value)
{
*limit = value;
@@ -5455,14 +5678,68 @@ em_add_rx_process_limit(struct adapter *adapter, const char *name,
OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, limit, value, description);
}
-static void
-em_set_flow_cntrl(struct adapter *adapter, const char *name,
- const char *description, int *limit, int value)
+
+/*
+** Set flow control using sysctl:
+** Flow control values:
+** 0 - off
+** 1 - rx pause
+** 2 - tx pause
+** 3 - full
+*/
+static int
+em_set_flowcntl(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+ static int input = 3; /* default is full */
+ struct adapter *adapter = (struct adapter *) arg1;
+
+ error = sysctl_handle_int(oidp, &input, 0, req);
+
+ if ((error) || (req->newptr == NULL))
+ return (error);
+
+ if (input == adapter->fc) /* no change? */
+ return (error);
+
+ switch (input) {
+ case e1000_fc_rx_pause:
+ case e1000_fc_tx_pause:
+ case e1000_fc_full:
+ case e1000_fc_none:
+ adapter->hw.fc.requested_mode = input;
+ adapter->fc = input;
+ break;
+ default:
+ /* Do nothing */
+ return (error);
+ }
+
+ adapter->hw.fc.current_mode = adapter->hw.fc.requested_mode;
+ e1000_force_mac_fc(&adapter->hw);
+ return (error);
+}
+
+/*
+** Manage Energy Efficient Ethernet:
+** Control values:
+** 0/1 - enabled/disabled
+*/
+static int
+em_sysctl_eee(SYSCTL_HANDLER_ARGS)
{
- *limit = value;
- SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)),
- OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, limit, value, description);
+ struct adapter *adapter = (struct adapter *) arg1;
+ int error, value;
+
+ value = adapter->hw.dev_spec.ich8lan.eee_disable;
+ error = sysctl_handle_int(oidp, &value, 0, req);
+ if (error || req->newptr == NULL)
+ return (error);
+ EM_CORE_LOCK(adapter);
+ adapter->hw.dev_spec.ich8lan.eee_disable = (value != 0);
+ em_init_locked(adapter);
+ EM_CORE_UNLOCK(adapter);
+ return (0);
}
static int
@@ -5501,10 +5778,11 @@ em_print_debug_info(struct adapter *adapter)
printf("Interface is RUNNING ");
else
printf("Interface is NOT RUNNING\n");
+
if (adapter->ifp->if_drv_flags & IFF_DRV_OACTIVE)
- printf("and ACTIVE\n");
- else
printf("and INACTIVE\n");
+ else
+ printf("and ACTIVE\n");
device_printf(dev, "hw tdh = %d, hw tdt = %d\n",
E1000_READ_REG(&adapter->hw, E1000_TDH(0)),