summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorjfv <jfv@FreeBSD.org>2011-12-10 07:08:52 +0000
committerjfv <jfv@FreeBSD.org>2011-12-10 07:08:52 +0000
commit38b99982d5e48f07d1a8c9b486f101a3ea76fa11 (patch)
tree816fd11d0bea29dba0172e6ababc7f84f266c889 /sys/dev
parent946d57ca9afe5b4a8678110c4fa7bc5913779162 (diff)
downloadFreeBSD-src-38b99982d5e48f07d1a8c9b486f101a3ea76fa11.zip
FreeBSD-src-38b99982d5e48f07d1a8c9b486f101a3ea76fa11.tar.gz
Part 2 of 2 New deltas for the 1G drivers.
There have still been intermittent problems with apparent TX hangs for some customers. These have been problematic to reproduce but I believe these changes will address them. Testing on a number of fronts have been positive. EM: there is an important 'chicken bit' fix for 82574 in the shared code this is supported in the core here. - The TX path has been tightened up to improve performance. In particular UDP with jumbo frames was having problems, and the changes here have improved that. - OACTIVE has been used more carefully on the theory that some hangs may be due to a problem in this interaction - Problems with the RX init code, the "lazy" allocation and ring initialization has been found to cause problems in some newer client systems, and as it really is not that big a win (its not in a hot path) it seems best to remove it. - HWTSO was broken when VLAN HWTAGGING or HWFILTER is used, I found this was due to an error in setting up the descriptors in em_xmit. IGB: - TX is also improved here. With multiqueue I realized its very important to handle OACTIVE only under the CORE lock so there are no races between the queues. - Flow Control handling was broken in a couple ways, I have changed and I hope improved that in this delta. - UDP also had a problem in the TX path here, it was change to improve that. - On some hardware, with the driver static, a weird stray interrupt seems to sometimes fire and cause a panic in the RX mbuf refresh code. This is addressed by setting interrupts late in the init path, and also to set all interrupts bits off at the start of that.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/e1000/if_em.c479
-rw-r--r--sys/dev/e1000/if_em.h7
-rw-r--r--sys/dev/e1000/if_igb.c627
-rw-r--r--sys/dev/e1000/if_igb.h12
-rw-r--r--sys/dev/e1000/if_lem.c62
-rw-r--r--sys/dev/e1000/if_lem.h4
6 files changed, 597 insertions, 594 deletions
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index b02c03c..49ad7b2 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -35,6 +35,7 @@
#ifdef HAVE_KERNEL_OPTION_HEADERS
#include "opt_device_polling.h"
#include "opt_inet.h"
+#include "opt_inet6.h"
#endif
#include <sys/param.h>
@@ -93,7 +94,7 @@ int em_display_debug_stats = 0;
/*********************************************************************
* Driver version:
*********************************************************************/
-char em_driver_version[] = "7.2.3";
+char em_driver_version[] = "7.3.2";
/*********************************************************************
* PCI Device ID Table
@@ -286,6 +287,7 @@ static void em_handle_link(void *context, int pending);
static void em_set_sysctl_value(struct adapter *, const char *,
const char *, int *, int);
+static int em_set_flowcntl(SYSCTL_HANDLER_ARGS);
static __inline void em_rx_discard(struct rx_ring *, int);
@@ -382,13 +384,8 @@ 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);
-SYSCTL_INT(_hw_em, OID_AUTO, fc_setting, CTLFLAG_RDTUN, &em_fc_setting, 0,
- "Flow control");
+ "Maximum number of received packets to process "
+ "at a time, -1 means unlimited");
/* Energy efficient ethernet - default to OFF */
static int eee_setting = 0;
@@ -473,6 +470,11 @@ em_attach(device_t dev)
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;
@@ -489,6 +491,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 */
@@ -560,11 +567,6 @@ em_attach(device_t dev)
"max number of rx packets to process", &adapter->rx_process_limit,
em_rx_process_limit);
- /* Sysctl for setting the interface flow control */
- em_set_sysctl_value(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
@@ -714,7 +716,8 @@ 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));
@@ -847,6 +850,8 @@ em_resume(device_t dev)
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);
EM_CORE_UNLOCK(adapter);
@@ -856,17 +861,15 @@ em_resume(device_t 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)
{
@@ -881,10 +884,6 @@ 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);
@@ -907,10 +906,6 @@ em_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m)
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);
}
@@ -919,6 +914,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);
}
@@ -959,7 +959,6 @@ em_qflush(struct ifnet *ifp)
}
if_qflush(ifp);
}
-
#endif /* EM_MULTIQUEUE */
static void
@@ -995,7 +994,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;
}
@@ -1022,6 +1020,12 @@ em_start(struct ifnet *ifp)
em_start_locked(ifp, txr);
EM_TX_UNLOCK(txr);
}
+ /*
+ ** If we went inactive schedule
+ ** a task to clean up.
+ */
+ if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
+ taskqueue_enqueue(txr->tq, &txr->tx_task);
return;
}
@@ -1038,11 +1042,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);
@@ -1050,23 +1055,22 @@ 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
+ /*
+ ** 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:
@@ -1083,6 +1087,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
case e1000_ich10lan:
case e1000_pch2lan:
case e1000_82574:
+ case e1000_82583:
case e1000_80003es2lan: /* 9K Jumbo Frame size */
max_frame_size = 9234;
break;
@@ -1090,7 +1095,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;
@@ -1145,11 +1149,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)) {
@@ -1208,6 +1207,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)
@@ -1246,7 +1249,6 @@ em_init_locked(struct adapter *adapter)
{
struct ifnet *ifp = adapter->ifp;
device_t dev = adapter->dev;
- u32 pba;
INIT_DEBUGOUT("em_init: begin");
@@ -1255,46 +1257,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);
@@ -1373,6 +1335,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;
@@ -1403,9 +1366,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
@@ -1995,6 +1955,14 @@ retry:
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 */
@@ -2052,15 +2020,13 @@ retry:
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);
@@ -2230,22 +2196,21 @@ em_local_timer(void *arg)
else
trigger = E1000_ICS_RXDMT0;
- /*
- ** Don't do TX watchdog check if we've been paused
- */
- if (adapter->pause_frames) {
- adapter->pause_frames = 0;
- goto out;
- }
/*
** 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 */
@@ -2264,6 +2229,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);
}
@@ -2362,7 +2328,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++) {
@@ -2458,6 +2425,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 */
@@ -2479,11 +2447,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 "
@@ -2500,7 +2474,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
@@ -2692,7 +2667,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
@@ -2712,16 +2686,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 "
@@ -2756,6 +2732,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");
@@ -2771,6 +2748,48 @@ 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->max_frame_size > 4096)
+ pba = E1000_PBA_14K;
+ else
+ 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 */
+ }
+ 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
@@ -2785,11 +2804,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);
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
@@ -2797,15 +2820,22 @@ 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:
hw->fc.high_water = 0x5C20;
hw->fc.low_water = 0x5048;
hw->fc.pause_time = 0x0650;
@@ -2815,13 +2845,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;
@@ -2866,28 +2909,25 @@ em_setup_interface(device_t dev, struct adapter *adapter)
ifp->if_capabilities = ifp->if_capenable = 0;
#ifdef EM_MULTIQUEUE
- /* Multiqueue tx functions */
+ /* Multiqueue stack interface */
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
@@ -3339,11 +3379,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 <<
@@ -3813,9 +3848,12 @@ em_txeof(struct tx_ring *txr)
/*
* 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_MAX_SCATTER)
- ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ if (txr->tx_avail >= EM_MAX_SCATTER)
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
/* Disable watchdog if all clean */
if (txr->tx_avail == adapter->num_tx_desc) {
@@ -3978,26 +4016,31 @@ em_setup_receive_ring(struct rx_ring *rxr)
struct adapter *adapter = rxr->adapter;
struct em_buffer *rxbuf;
bus_dma_segment_t seg[1];
- int i, j, nsegs, error = 0;
+ int rsize, nsegs, error;
/* Clear the ring contents */
EM_RX_LOCK(rxr);
+ rsize = roundup2(adapter->num_rx_desc *
+ sizeof(struct e1000_rx_desc), EM_DBA_ALIGN);
+ bzero((void *)rxr->rx_base, rsize);
- /* Invalidate all descriptors */
- for (i = 0; i < adapter->num_rx_desc; i++) {
- struct e1000_rx_desc* cur;
- cur = &rxr->rx_base[i];
- cur->status = 0;
+ /*
+ ** Free current RX buffer structs and their mbufs
+ */
+ for (int i = 0; i < adapter->num_rx_desc; i++) {
+ rxbuf = &rxr->rx_buffers[i];
+ if (rxbuf->m_head != NULL) {
+ bus_dmamap_sync(rxr->rxtag, rxbuf->map,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(rxr->rxtag, rxbuf->map);
+ m_freem(rxbuf->m_head);
+ }
}
/* Now replenish the mbufs */
- i = j = rxr->next_to_refresh;
- if (++j == adapter->num_rx_desc)
- j = 0;
-
- while (j != rxr->next_to_check) {
- rxbuf = &rxr->rx_buffers[i];
+ for (int j = 0; j != adapter->num_rx_desc; ++j) {
+ rxbuf = &rxr->rx_buffers[j];
rxbuf->m_head = m_getjcl(M_DONTWAIT, MT_DATA,
M_PKTHDR, adapter->rx_mbuf_sz);
if (rxbuf->m_head == NULL) {
@@ -4021,11 +4064,13 @@ em_setup_receive_ring(struct rx_ring *rxr)
rxbuf->map, BUS_DMASYNC_PREREAD);
/* Update descriptor */
- rxr->rx_base[i].buffer_addr = htole64(seg[0].ds_addr);
- i = j;
- if (++j == adapter->num_rx_desc)
- j = 0;
+ rxr->rx_base[j].buffer_addr = htole64(seg[0].ds_addr);
}
+ 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);
+
#ifdef DEV_NETMAP
{
/*
@@ -4079,9 +4124,6 @@ em_setup_receive_ring(struct rx_ring *rxr)
#endif /* DEV_NETMAP */
fail:
- rxr->next_to_refresh = i;
- bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
- BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
EM_RX_UNLOCK(rxr);
return (error);
}
@@ -4108,10 +4150,9 @@ fail:
* the rings that completed, the failing case will have
* cleaned up for itself. 'q' failed, so its the terminus.
*/
- for (int i = 0, n = 0; i < q; ++i) {
+ for (int i = 0; i < q; ++i) {
rxr = &adapter->rx_rings[i];
- n = rxr->next_to_check;
- while(n != rxr->next_to_refresh) {
+ for (int n = 0; n < adapter->num_rx_desc; n++) {
struct em_buffer *rxbuf;
rxbuf = &rxr->rx_buffers[n];
if (rxbuf->m_head != NULL) {
@@ -4121,8 +4162,6 @@ fail:
m_freem(rxbuf->m_head);
rxbuf->m_head = NULL;
}
- if (++n == adapter->num_rx_desc)
- n = 0;
}
rxr->next_to_check = 0;
rxr->next_to_refresh = 0;
@@ -4166,8 +4205,7 @@ em_free_receive_buffers(struct rx_ring *rxr)
INIT_DEBUGOUT("free_receive_buffers: begin");
if (rxr->rx_buffers != NULL) {
- int i = rxr->next_to_check;
- while(i != rxr->next_to_refresh) {
+ for (int i = 0; i < adapter->num_rx_desc; i++) {
rxbuf = &rxr->rx_buffers[i];
if (rxbuf->map != NULL) {
bus_dmamap_sync(rxr->rxtag, rxbuf->map,
@@ -4179,8 +4217,6 @@ em_free_receive_buffers(struct rx_ring *rxr)
m_freem(rxbuf->m_head);
rxbuf->m_head = NULL;
}
- if (++i == adapter->num_rx_desc)
- i = 0;
}
free(rxr->rx_buffers, M_DEVBUF);
rxr->rx_buffers = NULL;
@@ -4221,7 +4257,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);
@@ -4235,14 +4273,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);
@@ -4268,7 +4305,8 @@ em_initialize_receive_unit(struct adapter *adapter)
E1000_WRITE_REG(hw, E1000_RDBAH(i), (u32)(bus_addr >> 32));
E1000_WRITE_REG(hw, E1000_RDBAL(i), (u32)bus_addr);
/* Setup the Head and Tail Descriptor Pointers */
- E1000_WRITE_REG(hw, E1000_RDH(i), rxr->next_to_check);
+ E1000_WRITE_REG(hw, E1000_RDH(i), 0);
+ E1000_WRITE_REG(hw, E1000_RDT(i), adapter->num_rx_desc - 1);
#ifdef DEV_NETMAP
/*
* an init() while a netmap client is active must
@@ -4286,17 +4324,16 @@ em_initialize_receive_unit(struct adapter *adapter)
E1000_WRITE_REG(hw, E1000_RDT(i), t);
} else
#endif /* DEV_NETMAP */
- E1000_WRITE_REG(hw, E1000_RDT(i), rxr->next_to_refresh);
+ 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) {
@@ -4443,10 +4480,6 @@ em_rxeof(struct rx_ring *rxr, int count, int *done)
E1000_RXD_SPC_VLAN_MASK);
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
@@ -4921,7 +4954,7 @@ em_enable_wakeup(device_t dev)
(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_suspend_workarounds_ich8lan(&adapter->hw);
/* Keep the laser running on Fiber adapters */
if (adapter->hw.phy.media_type == e1000_media_type_fiber ||
@@ -5518,7 +5551,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;
@@ -5533,10 +5566,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);
}
@@ -5626,6 +5657,49 @@ em_set_sysctl_value(struct adapter *adapter, const char *name,
OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, limit, value, description);
}
+
+/*
+** 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);
+}
+
+
static int
em_sysctl_debug_info(SYSCTL_HANDLER_ARGS)
{
@@ -5662,10 +5736,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)),
diff --git a/sys/dev/e1000/if_em.h b/sys/dev/e1000/if_em.h
index e25904e..f1afbad 100644
--- a/sys/dev/e1000/if_em.h
+++ b/sys/dev/e1000/if_em.h
@@ -212,7 +212,8 @@
#define EM_BAR_MEM_TYPE_64BIT 0x00000004
#define EM_MSIX_BAR 3 /* On 82575 */
-#if !defined(SYSCTL_ADD_UQUAD)
+/* More backward compatibility */
+#if __FreeBSD_version < 900000
#define SYSCTL_ADD_UQUAD SYSCTL_ADD_QUAD
#endif
@@ -418,11 +419,11 @@ struct adapter {
u32 shadow_vfta[EM_VFTA_SIZE];
/* Info about the interface */
- u8 link_active;
+ u16 link_active;
+ u16 fc;
u16 link_speed;
u16 link_duplex;
u32 smartspeed;
- u32 fc_setting;
struct em_int_delay_info tx_int_delay;
struct em_int_delay_info tx_abs_int_delay;
diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c
index 4e85270..dd9fedf 100644
--- a/sys/dev/e1000/if_igb.c
+++ b/sys/dev/e1000/if_igb.c
@@ -100,7 +100,7 @@ int igb_display_debug_stats = 0;
/*********************************************************************
* Driver version:
*********************************************************************/
-char igb_driver_version[] = "version - 2.2.5";
+char igb_driver_version[] = "version - 2.3.1";
/*********************************************************************
@@ -171,15 +171,13 @@ static int igb_detach(device_t);
static int igb_shutdown(device_t);
static int igb_suspend(device_t);
static int igb_resume(device_t);
+static void igb_start(struct ifnet *);
+static void igb_start_locked(struct tx_ring *, struct ifnet *ifp);
#if __FreeBSD_version >= 800000
static int igb_mq_start(struct ifnet *, struct mbuf *);
static int igb_mq_start_locked(struct ifnet *,
struct tx_ring *, struct mbuf *);
static void igb_qflush(struct ifnet *);
-static void igb_deferred_mq_start(void *, int);
-#else
-static void igb_start(struct ifnet *);
-static void igb_start_locked(struct tx_ring *, struct ifnet *ifp);
#endif
static int igb_ioctl(struct ifnet *, u_long, caddr_t);
static void igb_init(void *);
@@ -226,7 +224,8 @@ static __inline void igb_rx_input(struct rx_ring *,
static bool igb_rxeof(struct igb_queue *, int, int *);
static void igb_rx_checksum(u32, struct mbuf *, u32);
static int igb_tx_ctx_setup(struct tx_ring *, struct mbuf *);
-static bool igb_tso_setup(struct tx_ring *, struct mbuf *, u32 *);
+static bool igb_tso_setup(struct tx_ring *, struct mbuf *, int,
+ struct ip *, struct tcphdr *);
static void igb_set_promisc(struct adapter *);
static void igb_disable_promisc(struct adapter *);
static void igb_set_multi(struct adapter *);
@@ -300,17 +299,11 @@ MODULE_DEPEND(igb, ether, 1, 1, 1);
* Tunable default values.
*********************************************************************/
-static SYSCTL_NODE(_hw, OID_AUTO, igb, CTLFLAG_RD, 0, "IGB driver parameters");
-
/* Descriptor defaults */
static int igb_rxd = IGB_DEFAULT_RXD;
static int igb_txd = IGB_DEFAULT_TXD;
TUNABLE_INT("hw.igb.rxd", &igb_rxd);
TUNABLE_INT("hw.igb.txd", &igb_txd);
-SYSCTL_INT(_hw_igb, OID_AUTO, rxd, CTLFLAG_RDTUN, &igb_rxd, 0,
- "Number of receive descriptors per queue");
-SYSCTL_INT(_hw_igb, OID_AUTO, txd, CTLFLAG_RDTUN, &igb_txd, 0,
- "Number of transmit descriptors per queue");
/*
** AIM: Adaptive Interrupt Moderation
@@ -320,8 +313,6 @@ SYSCTL_INT(_hw_igb, OID_AUTO, txd, CTLFLAG_RDTUN, &igb_txd, 0,
*/
static int igb_enable_aim = TRUE;
TUNABLE_INT("hw.igb.enable_aim", &igb_enable_aim);
-SYSCTL_INT(_hw_igb, OID_AUTO, enable_aim, CTLFLAG_RW, &igb_enable_aim, 0,
- "Enable adaptive interrupt moderation");
/*
* MSIX should be the default for best performance,
@@ -329,16 +320,12 @@ SYSCTL_INT(_hw_igb, OID_AUTO, enable_aim, CTLFLAG_RW, &igb_enable_aim, 0,
*/
static int igb_enable_msix = 1;
TUNABLE_INT("hw.igb.enable_msix", &igb_enable_msix);
-SYSCTL_INT(_hw_igb, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &igb_enable_msix, 0,
- "Enable MSI-X interrupts");
/*
** Tuneable Interrupt rate
*/
static int igb_max_interrupt_rate = 8000;
TUNABLE_INT("hw.igb.max_interrupt_rate", &igb_max_interrupt_rate);
-SYSCTL_INT(_hw_igb, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN,
- &igb_max_interrupt_rate, 0, "Maximum interrupts per second");
/*
** Header split causes the packet header to
@@ -350,8 +337,6 @@ SYSCTL_INT(_hw_igb, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN,
*/
static bool igb_header_split = FALSE;
TUNABLE_INT("hw.igb.hdr_split", &igb_header_split);
-SYSCTL_INT(_hw_igb, OID_AUTO, header_split, CTLFLAG_RDTUN, &igb_header_split, 0,
- "Enable receive mbuf header split");
/*
** This will autoconfigure based on
@@ -359,19 +344,7 @@ SYSCTL_INT(_hw_igb, OID_AUTO, header_split, CTLFLAG_RDTUN, &igb_header_split, 0,
*/
static int igb_num_queues = 0;
TUNABLE_INT("hw.igb.num_queues", &igb_num_queues);
-SYSCTL_INT(_hw_igb, OID_AUTO, num_queues, CTLFLAG_RDTUN, &igb_num_queues, 0,
- "Number of queues to configure, 0 indicates autoconfigure");
-
-/* How many packets rxeof tries to clean at a time */
-static int igb_rx_process_limit = 100;
-TUNABLE_INT("hw.igb.rx_process_limit", &igb_rx_process_limit);
-SYSCTL_INT(_hw_igb, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN,
- &igb_rx_process_limit, 0,
- "Maximum number of received packets to process at a time, -1 means unlimited");
-
-#ifdef DEV_NETMAP /* see ixgbe.c for details */
-#include <dev/netmap/if_igb_netmap.h>
-#endif /* DEV_NETMAP */
+
/*********************************************************************
* Device identification routine
*
@@ -457,9 +430,10 @@ igb_attach(device_t dev)
OID_AUTO, "nvm", CTLTYPE_INT|CTLFLAG_RW, adapter, 0,
igb_sysctl_nvm_info, "I", "NVM Information");
- igb_set_sysctl_value(adapter, "enable_aim",
- "Interrupt Moderation", &adapter->enable_aim,
- igb_enable_aim);
+ SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "enable_aim", CTLTYPE_INT|CTLFLAG_RW,
+ &igb_enable_aim, 1, "Interrupt Moderation");
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
@@ -490,7 +464,7 @@ igb_attach(device_t dev)
/* Sysctl for limiting the amount of work done in the taskqueue */
igb_set_sysctl_value(adapter, "rx_processing_limit",
"max number of rx packets to process",
- &adapter->rx_process_limit, igb_rx_process_limit);
+ &adapter->rx_process_limit, 100);
/*
* Validate number of transmit and receive descriptors. It
@@ -614,16 +588,6 @@ igb_attach(device_t dev)
goto err_late;
}
- /*
- ** Configure Interrupts
- */
- if ((adapter->msix > 1) && (igb_enable_msix))
- error = igb_allocate_msix(adapter);
- else /* MSI or Legacy */
- error = igb_allocate_legacy(adapter);
- if (error)
- goto err_late;
-
/* Setup OS specific network interface */
if (igb_setup_interface(dev, adapter) != 0)
goto err_late;
@@ -662,14 +626,22 @@ igb_attach(device_t dev)
igb_add_hw_stats(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(igb_led_func, adapter,
device_get_nameunit(dev));
-#ifdef DEV_NETMAP
- igb_netmap_attach(adapter);
-#endif /* DEV_NETMAP */
+ /*
+ ** Configure Interrupts
+ */
+ if ((adapter->msix > 1) && (igb_enable_msix))
+ error = igb_allocate_msix(adapter);
+ else /* MSI or Legacy */
+ error = igb_allocate_legacy(adapter);
+ if (error)
+ goto err_late;
+
INIT_DEBUGOUT("igb_attach: end");
return (0);
@@ -679,10 +651,10 @@ err_late:
igb_free_transmit_structures(adapter);
igb_free_receive_structures(adapter);
igb_release_hw_control(adapter);
- if (adapter->ifp != NULL)
- if_free(adapter->ifp);
err_pci:
igb_free_pci_resources(adapter);
+ if (adapter->ifp != NULL)
+ if_free(adapter->ifp);
free(adapter->mta, M_DEVBUF);
IGB_CORE_LOCK_DESTROY(adapter);
@@ -713,8 +685,6 @@ igb_detach(device_t dev)
return (EBUSY);
}
- ether_ifdetach(adapter->ifp);
-
if (adapter->led_dev != NULL)
led_destroy(adapter->led_dev);
@@ -746,11 +716,10 @@ igb_detach(device_t dev)
if (adapter->vlan_detach != NULL)
EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach);
+ ether_ifdetach(adapter->ifp);
+
callout_drain(&adapter->timer);
-#ifdef DEV_NETMAP
- netmap_detach(adapter->ifp);
-#endif /* DEV_NETMAP */
igb_free_pci_resources(adapter);
bus_generic_detach(dev);
if_free(ifp);
@@ -808,27 +777,14 @@ igb_resume(device_t dev)
{
struct adapter *adapter = device_get_softc(dev);
struct ifnet *ifp = adapter->ifp;
-#if __FreeBSD_version >= 800000
- struct tx_ring *txr = adapter->tx_rings;
-#endif
IGB_CORE_LOCK(adapter);
igb_init_locked(adapter);
igb_init_manageability(adapter);
if ((ifp->if_flags & IFF_UP) &&
- (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
-#if __FreeBSD_version < 800000
+ (ifp->if_drv_flags & IFF_DRV_RUNNING))
igb_start(ifp);
-#else
- for (int i = 0; i < adapter->num_queues; i++, txr++) {
- IGB_TX_LOCK(txr);
- if (!drbr_empty(ifp, txr->br))
- igb_mq_start_locked(ifp, txr, NULL);
- IGB_TX_UNLOCK(txr);
- }
-#endif
- }
IGB_CORE_UNLOCK(adapter);
@@ -836,7 +792,6 @@ igb_resume(device_t dev)
}
-#if __FreeBSD_version < 800000
/*********************************************************************
* Transmit entry point
*
@@ -867,7 +822,7 @@ igb_start_locked(struct tx_ring *txr, struct ifnet *ifp)
while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
if (txr->tx_avail <= IGB_MAX_SCATTER) {
- ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ txr->queue_status |= IGB_QUEUE_DEPLETED;
break;
}
IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
@@ -878,10 +833,10 @@ igb_start_locked(struct tx_ring *txr, struct ifnet *ifp)
* NULL on failure. In that event, we can't requeue.
*/
if (igb_xmit(txr, &m_head)) {
- if (m_head == NULL)
- break;
- ifp->if_drv_flags |= IFF_DRV_OACTIVE;
- IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
+ if (m_head != NULL)
+ IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
+ if (txr->tx_avail <= IGB_MAX_SCATTER)
+ txr->queue_status |= IGB_QUEUE_DEPLETED;
break;
}
@@ -890,7 +845,7 @@ igb_start_locked(struct tx_ring *txr, struct ifnet *ifp)
/* Set watchdog on */
txr->watchdog_time = ticks;
- txr->queue_status = IGB_QUEUE_WORKING;
+ txr->queue_status |= IGB_QUEUE_WORKING;
}
}
@@ -913,7 +868,7 @@ igb_start(struct ifnet *ifp)
return;
}
-#else /* __FreeBSD_version >= 800000 */
+#if __FreeBSD_version >= 800000
/*
** Multiqueue Transmit driver
**
@@ -924,21 +879,25 @@ igb_mq_start(struct ifnet *ifp, struct mbuf *m)
struct adapter *adapter = ifp->if_softc;
struct igb_queue *que;
struct tx_ring *txr;
- int i = 0, err = 0;
+ int i, err = 0;
+ bool moveable = TRUE;
/* Which queue to use */
- if ((m->m_flags & M_FLOWID) != 0)
+ if ((m->m_flags & M_FLOWID) != 0) {
i = m->m_pkthdr.flowid % adapter->num_queues;
+ moveable = FALSE;
+ } else
+ i = curcpu % adapter->num_queues;
txr = &adapter->tx_rings[i];
que = &adapter->queues[i];
-
- if (IGB_TX_TRYLOCK(txr)) {
+ if (((txr->queue_status & IGB_QUEUE_DEPLETED) == 0) &&
+ IGB_TX_TRYLOCK(txr)) {
err = igb_mq_start_locked(ifp, txr, m);
IGB_TX_UNLOCK(txr);
} else {
err = drbr_enqueue(ifp, txr->br, m);
- taskqueue_enqueue(que->tq, &txr->txq_task);
+ taskqueue_enqueue(que->tq, &que->que_task);
}
return (err);
@@ -953,8 +912,9 @@ igb_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m)
IGB_TX_LOCK_ASSERT(txr);
- if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
- IFF_DRV_RUNNING || adapter->link_active == 0) {
+ if (((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) ||
+ (txr->queue_status == IGB_QUEUE_DEPLETED) ||
+ adapter->link_active == 0) {
if (m != NULL)
err = drbr_enqueue(ifp, txr->br, m);
return (err);
@@ -982,39 +942,21 @@ igb_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m)
ETHER_BPF_MTAP(ifp, next);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
break;
- if (txr->tx_avail <= IGB_TX_CLEANUP_THRESHOLD)
- igb_txeof(txr);
- if (txr->tx_avail <= IGB_MAX_SCATTER) {
- ifp->if_drv_flags |= IFF_DRV_OACTIVE;
- break;
- }
next = drbr_dequeue(ifp, txr->br);
}
if (enq > 0) {
/* Set the watchdog */
- txr->queue_status = IGB_QUEUE_WORKING;
+ txr->queue_status |= IGB_QUEUE_WORKING;
txr->watchdog_time = ticks;
}
+ if (txr->tx_avail <= IGB_TX_CLEANUP_THRESHOLD)
+ igb_txeof(txr);
+ if (txr->tx_avail <= IGB_MAX_SCATTER)
+ txr->queue_status |= IGB_QUEUE_DEPLETED;
return (err);
}
/*
- * Called from a taskqueue to drain queued transmit packets.
- */
-static void
-igb_deferred_mq_start(void *arg, int pending)
-{
- struct tx_ring *txr = arg;
- struct adapter *adapter = txr->adapter;
- struct ifnet *ifp = adapter->ifp;
-
- IGB_TX_LOCK(txr);
- if (!drbr_empty(ifp, txr->br))
- igb_mq_start_locked(ifp, txr, NULL);
- IGB_TX_UNLOCK(txr);
-}
-
-/*
** Flush all ring buffers
*/
static void
@@ -1032,7 +974,7 @@ igb_qflush(struct ifnet *ifp)
}
if_qflush(ifp);
}
-#endif /* __FreeBSD_version < 800000 */
+#endif /* __FreeBSD_version >= 800000 */
/*********************************************************************
* Ioctl entry point
@@ -1051,8 +993,8 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
#if defined(INET) || defined(INET6)
struct ifaddr *ifa = (struct ifaddr *)data;
#endif
- bool avoid_reset = FALSE;
int error = 0;
+ bool avoid_reset = FALSE;
if (adapter->in_detach)
return (error);
@@ -1063,7 +1005,7 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
if (ifa->ifa_addr->sa_family == AF_INET)
avoid_reset = TRUE;
#endif
-#ifdef INET6
+#ifdef INET
if (ifa->ifa_addr->sa_family == AF_INET6)
avoid_reset = TRUE;
#endif
@@ -1138,11 +1080,6 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
}
break;
case SIOCSIFMEDIA:
- /*
- ** As the speed/duplex settings are being
- ** changed, we need toreset the PHY.
- */
- adapter->hw.phy.reset_disable = FALSE;
/* Check SOL/IDER usage */
IGB_CORE_LOCK(adapter);
if (e1000_check_reset_block(&adapter->hw)) {
@@ -1333,10 +1270,8 @@ igb_init_locked(struct adapter *adapter)
}
/* Set Energy Efficient Ethernet */
- e1000_set_eee_i350(&adapter->hw);
- /* Don't reset the phy next time init gets called */
- adapter->hw.phy.reset_disable = TRUE;
+ e1000_set_eee_i350(&adapter->hw);
}
static void
@@ -1361,18 +1296,21 @@ igb_handle_que(void *context, int pending)
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
bool more;
- more = igb_rxeof(que, -1, NULL);
+ more = igb_rxeof(que, adapter->rx_process_limit, NULL);
IGB_TX_LOCK(txr);
if (igb_txeof(txr))
more = TRUE;
#if __FreeBSD_version >= 800000
- if (!drbr_empty(ifp, txr->br))
+ /* Process the stack queue only if not depleted */
+ if (((txr->queue_status & IGB_QUEUE_DEPLETED) == 0) &&
+ !drbr_empty(ifp, txr->br))
igb_mq_start_locked(ifp, txr, NULL);
#else
igb_start_locked(txr, ifp);
#endif
IGB_TX_UNLOCK(txr);
+ /* Do we need another? */
if (more || (ifp->if_drv_flags & IFF_DRV_OACTIVE)) {
taskqueue_enqueue(que->tq, &que->que_task);
return;
@@ -1503,7 +1441,7 @@ igb_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
/*********************************************************************
*
- * MSIX TX Interrupt Service routine
+ * MSIX Que Interrupt Service routine
*
**********************************************************************/
static void
@@ -1525,7 +1463,7 @@ igb_msix_que(void *arg)
more_rx = igb_rxeof(que, adapter->rx_process_limit, NULL);
- if (adapter->enable_aim == FALSE)
+ if (igb_enable_aim == FALSE)
goto no_calc;
/*
** Do Adaptive Interrupt Moderation:
@@ -1578,8 +1516,7 @@ igb_msix_que(void *arg)
no_calc:
/* Schedule a clean task if needed*/
- if (more_tx || more_rx ||
- (adapter->ifp->if_drv_flags & IFF_DRV_OACTIVE))
+ if (more_tx || more_rx)
taskqueue_enqueue(que->tq, &que->que_task);
else
/* Reenable this interrupt */
@@ -1727,10 +1664,8 @@ igb_media_change(struct ifnet *ifp)
/*********************************************************************
*
* This routine maps the mbufs to Advanced TX descriptors.
- * used by the 82575 adapter.
*
**********************************************************************/
-
static int
igb_xmit(struct tx_ring *txr, struct mbuf **m_headp)
{
@@ -1739,22 +1674,123 @@ igb_xmit(struct tx_ring *txr, struct mbuf **m_headp)
bus_dmamap_t map;
struct igb_tx_buffer *tx_buffer, *tx_buffer_mapped;
union e1000_adv_tx_desc *txd = NULL;
- struct mbuf *m_head;
- u32 olinfo_status = 0, cmd_type_len = 0;
- int nsegs, i, j, error, first, last = 0;
- u32 hdrlen = 0;
-
- m_head = *m_headp;
-
+ struct mbuf *m_head = *m_headp;
+ struct ether_vlan_header *eh = NULL;
+ struct ip *ip = NULL;
+ struct tcphdr *th = NULL;
+ u32 hdrlen, cmd_type_len, olinfo_status = 0;
+ int ehdrlen, poff;
+ int nsegs, i, first, last = 0;
+ int error, do_tso, remap = 1;
/* Set basic descriptor constants */
- cmd_type_len |= E1000_ADVTXD_DTYP_DATA;
+ cmd_type_len = E1000_ADVTXD_DTYP_DATA;
cmd_type_len |= E1000_ADVTXD_DCMD_IFCS | E1000_ADVTXD_DCMD_DEXT;
if (m_head->m_flags & M_VLANTAG)
cmd_type_len |= E1000_ADVTXD_DCMD_VLE;
+retry:
+ m_head = *m_headp;
+ do_tso = ((m_head->m_pkthdr.csum_flags & CSUM_TSO) != 0);
+ hdrlen = ehdrlen = poff = 0;
+
/*
- * Map the packet for DMA.
+ * Intel recommends entire IP/TCP header length reside in a single
+ * buffer. If multiple descriptors are used to describe the IP and
+ * TCP header, each descriptor should describe one or more
+ * complete headers; descriptors referencing only parts of headers
+ * are not supported. If all layer headers are not coalesced into
+ * a single buffer, each buffer should not cross a 4KB boundary,
+ * or be larger than the maximum read request size.
+ * Controller also requires modifing IP/TCP header to make TSO work
+ * so we firstly get a writable mbuf chain then coalesce ethernet/
+ * IP/TCP header into a single buffer to meet the requirement of
+ * controller. This also simplifies IP/TCP/UDP checksum offloading
+ * which also has similiar restrictions.
+ */
+ if (do_tso || m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) {
+ 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_freem(*m_headp);
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ *m_headp = m_head;
+ }
+ }
+ /*
+ * Assume IPv4, we don't have TSO/checksum offload support
+ * for IPv6 yet.
+ */
+ ehdrlen = sizeof(struct ether_header);
+ m_head = m_pullup(m_head, ehdrlen);
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ eh = mtod(m_head, struct ether_vlan_header *);
+ if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
+ ehdrlen = sizeof(struct ether_vlan_header);
+ m_head = m_pullup(m_head, ehdrlen);
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ }
+ m_head = m_pullup(m_head, ehdrlen + sizeof(struct ip));
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ ip = (struct ip *)(mtod(m_head, char *) + ehdrlen);
+ poff = ehdrlen + (ip->ip_hl << 2);
+ if (do_tso) {
+ m_head = m_pullup(m_head, poff + sizeof(struct tcphdr));
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ /*
+ * The pseudo TCP checksum does not include TCP payload
+ * length so driver should recompute the checksum here
+ * what hardware expect to see. This is adherence of
+ * Microsoft's Large Send specification.
+ */
+ th = (struct tcphdr *)(mtod(m_head, char *) + poff);
+ th->th_sum = in_pseudo(ip->ip_src.s_addr,
+ ip->ip_dst.s_addr, htons(IPPROTO_TCP));
+ /* Keep track of the full header length */
+ hdrlen = poff + (th->th_off << 2);
+ } else if (m_head->m_pkthdr.csum_flags & CSUM_TCP) {
+ m_head = m_pullup(m_head, poff + sizeof(struct tcphdr));
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ th = (struct tcphdr *)(mtod(m_head, char *) + poff);
+ m_head = m_pullup(m_head, poff + (th->th_off << 2));
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ ip = (struct ip *)(mtod(m_head, char *) + ehdrlen);
+ th = (struct tcphdr *)(mtod(m_head, char *) + poff);
+ } else if (m_head->m_pkthdr.csum_flags & CSUM_UDP) {
+ m_head = m_pullup(m_head, poff + sizeof(struct udphdr));
+ if (m_head == NULL) {
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ ip = (struct ip *)(mtod(m_head, char *) + ehdrlen);
+ }
+ *m_headp = m_head;
+ }
+
+ /*
+ * Map the packet for DMA
*
* Capture the first descriptor index,
* this descriptor will have the index
@@ -1769,7 +1805,16 @@ igb_xmit(struct tx_ring *txr, struct mbuf **m_headp)
error = bus_dmamap_load_mbuf_sg(txr->txtag, map,
*m_headp, segs, &nsegs, BUS_DMA_NOWAIT);
- if (error == EFBIG) {
+ /*
+ * There are two types of errors we can (try) to handle:
+ * - EFBIG means the mbuf chain was too long and bus_dma ran
+ * out of segments. Defragment the mbuf chain and try again.
+ * - ENOMEM means bus_dma could not obtain enough bounce buffers
+ * at this point in time. Defer sending and try again later.
+ * 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 && remap) {
struct mbuf *m;
m = m_defrag(*m_headp, M_DONTWAIT);
@@ -1781,19 +1826,9 @@ igb_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);
@@ -1804,29 +1839,35 @@ igb_xmit(struct tx_ring *txr, struct mbuf **m_headp)
return (error);
}
- /* Check again to be sure we have enough descriptors */
- if (nsegs > (txr->tx_avail - 2)) {
+ /*
+ ** Make sure we don't overrun the ring,
+ ** we need nsegs descriptors and one for
+ ** the context descriptor used for the
+ ** offloads.
+ */
+ if ((nsegs + 1) > (txr->tx_avail - 2)) {
txr->no_desc_avail++;
bus_dmamap_unload(txr->txtag, map);
return (ENOBUFS);
}
m_head = *m_headp;
- /*
- * Set up the context descriptor:
- * used when any hardware offload is done.
- * This includes CSUM, VLAN, and TSO. It
- * will use the first descriptor.
+ /* Do hardware assists:
+ * Set up the context descriptor, used
+ * when any hardware offload is done.
+ * This includes CSUM, VLAN, and TSO.
+ * It will use the first descriptor.
*/
- if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
- if (igb_tso_setup(txr, m_head, &hdrlen)) {
+
+ if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
+ if (igb_tso_setup(txr, m_head, ehdrlen, ip, th)) {
cmd_type_len |= E1000_ADVTXD_DCMD_TSE;
olinfo_status |= E1000_TXD_POPTS_IXSM << 8;
olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
} else
- return (ENXIO);
+ return (ENXIO);
} else if (igb_tx_ctx_setup(txr, m_head))
- olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
+ olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
/* Calculate payload length */
olinfo_status |= ((m_head->m_pkthdr.len - hdrlen)
@@ -1838,7 +1879,7 @@ igb_xmit(struct tx_ring *txr, struct mbuf **m_headp)
/* Set up our transmit descriptors */
i = txr->next_avail_desc;
- for (j = 0; j < nsegs; j++) {
+ for (int j = 0; j < nsegs; j++) {
bus_size_t seg_len;
bus_addr_t seg_addr;
@@ -1859,8 +1900,14 @@ igb_xmit(struct tx_ring *txr, struct mbuf **m_headp)
txr->next_avail_desc = i;
txr->tx_avail -= nsegs;
-
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);
@@ -1878,6 +1925,7 @@ igb_xmit(struct tx_ring *txr, struct mbuf **m_headp)
*/
tx_buffer = &txr->tx_buffers[first];
tx_buffer->next_eop = last;
+ /* Update the watchdog time early and often */
txr->watchdog_time = ticks;
/*
@@ -1890,9 +1938,7 @@ igb_xmit(struct tx_ring *txr, struct mbuf **m_headp)
++txr->tx_packets;
return (0);
-
}
-
static void
igb_set_promisc(struct adapter *adapter)
{
@@ -1999,7 +2045,10 @@ igb_local_timer(void *arg)
{
struct adapter *adapter = arg;
device_t dev = adapter->dev;
+ struct ifnet *ifp = adapter->ifp;
struct tx_ring *txr = adapter->tx_rings;
+ struct igb_queue *que = adapter->queues;
+ int hung = 0, busy = 0;
IGB_CORE_LOCK_ASSERT(adapter);
@@ -2007,22 +2056,29 @@ igb_local_timer(void *arg)
igb_update_link_status(adapter);
igb_update_stats_counters(adapter);
- /*
- ** If flow control has paused us since last checking
- ** it invalidates the watchdog timing, so dont run it.
- */
- if (adapter->pause_frames) {
- adapter->pause_frames = 0;
- goto out;
- }
-
/*
- ** Watchdog: check for time since any descriptor was cleaned
+ ** Check the TX queues status
+ ** - central locked handling of OACTIVE
+ ** - watchdog only if all queues show hung
*/
- for (int i = 0; i < adapter->num_queues; i++, txr++)
- if (txr->queue_status == IGB_QUEUE_HUNG)
- goto timeout;
-out:
+ for (int i = 0; i < adapter->num_queues; i++, que++, txr++) {
+ if ((txr->queue_status & IGB_QUEUE_HUNG) &&
+ (adapter->pause_frames == 0))
+ ++hung;
+ if (txr->queue_status & IGB_QUEUE_DEPLETED)
+ ++busy;
+ if ((txr->queue_status & IGB_QUEUE_IDLE) == 0)
+ taskqueue_enqueue(que->tq, &que->que_task);
+ }
+ if (hung == adapter->num_queues)
+ goto timeout;
+ if (busy == adapter->num_queues)
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ else if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) &&
+ (busy < adapter->num_queues))
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ adapter->pause_frames = 0;
callout_reset(&adapter->timer, hz, igb_local_timer, adapter);
#ifndef DEVICE_POLLING
/* Schedule all queue interrupts - deadlock protection */
@@ -2115,7 +2171,7 @@ igb_update_link_status(struct adapter *adapter)
adapter->link_active = 0;
/* This can sleep */
if_link_state_change(ifp, LINK_STATE_DOWN);
- /* Turn off watchdogs */
+ /* Reset queue state */
for (int i = 0; i < adapter->num_queues; i++, txr++)
txr->queue_status = IGB_QUEUE_IDLE;
}
@@ -2144,9 +2200,10 @@ igb_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. */
+ /* Disarm watchdog timer. */
for (int i = 0; i < adapter->num_queues; i++, txr++) {
IGB_TX_LOCK(txr);
txr->queue_status = IGB_QUEUE_IDLE;
@@ -2241,7 +2298,6 @@ igb_allocate_legacy(struct adapter *adapter)
{
device_t dev = adapter->dev;
struct igb_queue *que = adapter->queues;
- struct tx_ring *txr = adapter->tx_rings;
int error, rid = 0;
/* Turn off all interrupts */
@@ -2260,10 +2316,6 @@ igb_allocate_legacy(struct adapter *adapter)
return (ENXIO);
}
-#if __FreeBSD_version >= 800000
- TASK_INIT(&txr->txq_task, 0, igb_deferred_mq_start, txr);
-#endif
-
/*
* Try allocating a fast interrupt and the associated deferred
* processing contexts.
@@ -2301,6 +2353,9 @@ igb_allocate_msix(struct adapter *adapter)
struct igb_queue *que = adapter->queues;
int error, rid, vector = 0;
+ /* Be sure to start with all interrupts disabled */
+ E1000_WRITE_REG(&adapter->hw, E1000_IMC, ~0);
+ E1000_WRITE_FLUSH(&adapter->hw);
for (int i = 0; i < adapter->num_queues; i++, vector++, que++) {
rid = vector +1;
@@ -2334,13 +2389,9 @@ igb_allocate_msix(struct adapter *adapter)
*/
if (adapter->num_queues > 1)
bus_bind_intr(dev, que->res, i);
-#if __FreeBSD_version >= 800000
- TASK_INIT(&que->txr->txq_task, 0, igb_deferred_mq_start,
- que->txr);
-#endif
/* Make tasklet for deferred handling */
TASK_INIT(&que->que_task, 0, igb_handle_que, que);
- que->tq = taskqueue_create("igb_que", M_NOWAIT,
+ que->tq = taskqueue_create_fast("igb_que", M_NOWAIT,
taskqueue_thread_enqueue, &que->tq);
taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
device_get_nameunit(adapter->dev));
@@ -2547,24 +2598,13 @@ igb_free_pci_resources(struct adapter *adapter)
else
(adapter->msix != 0) ? (rid = 1):(rid = 0);
- que = adapter->queues;
if (adapter->tag != NULL) {
- taskqueue_drain(que->tq, &adapter->link_task);
bus_teardown_intr(dev, adapter->res, adapter->tag);
adapter->tag = NULL;
}
if (adapter->res != NULL)
bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res);
- for (int i = 0; i < adapter->num_queues; i++, que++) {
- if (que->tq != NULL) {
-#if __FreeBSD_version >= 800000
- taskqueue_drain(que->tq, &que->txr->txq_task);
-#endif
- taskqueue_drain(que->tq, &que->que_task);
- taskqueue_free(que->tq);
- }
- }
mem:
if (adapter->msix)
pci_release_msi(dev);
@@ -2695,7 +2735,6 @@ igb_reset(struct adapter *adapter)
pba = E1000_READ_REG(hw, E1000_RXPBS);
pba = e1000_rxpbs_adjust_82580(pba);
break;
- pba = E1000_PBA_35K;
default:
break;
}
@@ -2750,12 +2789,10 @@ igb_reset(struct adapter *adapter)
fc->pause_time = IGB_FC_PAUSE_TIME;
fc->send_xon = TRUE;
- if (fc->requested_mode)
- fc->current_mode = fc->requested_mode;
+ if (adapter->fc)
+ fc->requested_mode = adapter->fc;
else
- fc->current_mode = e1000_fc_full;
-
- adapter->fc = fc->current_mode;
+ fc->requested_mode = e1000_fc_default;
/* Issue a global reset */
e1000_reset_hw(hw);
@@ -2836,11 +2873,10 @@ igb_setup_interface(device_t dev, struct adapter *adapter)
ifp->if_softc = adapter;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = igb_ioctl;
+ ifp->if_start = igb_start;
#if __FreeBSD_version >= 800000
ifp->if_transmit = igb_mq_start;
ifp->if_qflush = igb_qflush;
-#else
- ifp->if_start = igb_start;
#endif
IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 1);
ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 1;
@@ -3221,16 +3257,9 @@ igb_setup_transmit_ring(struct tx_ring *txr)
struct adapter *adapter = txr->adapter;
struct igb_tx_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 */
IGB_TX_LOCK(txr);
-#ifdef DEV_NETMAP
- slot = netmap_reset(na, NR_TX, txr->me, 0);
-#endif /* DEV_NETMAP */
bzero((void *)txr->tx_base,
(sizeof(union e1000_adv_tx_desc)) * adapter->num_tx_desc);
/* Reset indices */
@@ -3247,17 +3276,6 @@ igb_setup_transmit_ring(struct tx_ring *txr)
m_freem(txbuf->m_head);
txbuf->m_head = NULL;
}
-#ifdef DEV_NETMAP
- if (slot) {
- /* slot si is mapped to the i-th NIC-ring entry */
- int si = i + na->tx_rings[txr->me].nkr_hwofs;
-
- if (si < 0)
- si += na->num_tx_desc;
- netmap_load_map(txr->txtag, txbuf->map,
- NMB(slot + si), na->buff_size);
- }
-#endif /* DEV_NETMAP */
/* clear the watch index */
txbuf->next_eop = -1;
}
@@ -3424,7 +3442,8 @@ igb_free_transmit_buffers(struct tx_ring *txr)
*
**********************************************************************/
static boolean_t
-igb_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *hdrlen)
+igb_tso_setup(struct tx_ring *txr, struct mbuf *mp, int ehdrlen,
+ struct ip *ip, struct tcphdr *th)
{
struct adapter *adapter = txr->adapter;
struct e1000_adv_tx_context_desc *TXD;
@@ -3432,45 +3451,15 @@ igb_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *hdrlen)
u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0;
u32 mss_l4len_idx = 0;
u16 vtag = 0;
- int ctxd, ehdrlen, ip_hlen, tcp_hlen;
- struct ether_vlan_header *eh;
- struct ip *ip;
- struct tcphdr *th;
-
+ int ctxd, ip_hlen, tcp_hlen;
- /*
- * Determine where frame payload starts.
- * Jump over vlan headers if already present
- */
- eh = mtod(mp, struct ether_vlan_header *);
- if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN))
- ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
- else
- ehdrlen = ETHER_HDR_LEN;
-
- /* Ensure we have at least the IP+TCP header in the first mbuf. */
- if (mp->m_len < ehdrlen + sizeof(struct ip) + sizeof(struct tcphdr))
- return FALSE;
-
- /* Only supports IPV4 for now */
ctxd = txr->next_avail_desc;
tx_buffer = &txr->tx_buffers[ctxd];
TXD = (struct e1000_adv_tx_context_desc *) &txr->tx_base[ctxd];
- ip = (struct ip *)(mp->m_data + ehdrlen);
- if (ip->ip_p != IPPROTO_TCP)
- return FALSE; /* 0 */
ip->ip_sum = 0;
ip_hlen = ip->ip_hl << 2;
- th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
- th->th_sum = in_pseudo(ip->ip_src.s_addr,
- ip->ip_dst.s_addr, htons(IPPROTO_TCP));
tcp_hlen = th->th_off << 2;
- /*
- * Calculate header length, this is used
- * in the transmit desc in igb_xmit
- */
- *hdrlen = ehdrlen + ip_hlen + tcp_hlen;
/* VLAN MACLEN IPLEN */
if (mp->m_flags & M_VLANTAG) {
@@ -3653,19 +3642,6 @@ igb_txeof(struct tx_ring *txr)
IGB_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);
- IGB_TX_UNLOCK(txr);
- IGB_CORE_LOCK(adapter);
- selwakeuppri(&na->tx_rings[na->num_queues + 1].si, PI_NET);
- IGB_CORE_UNLOCK(adapter);
- IGB_TX_LOCK(txr);
- return FALSE;
- }
-#endif /* DEV_NETMAP */
if (txr->tx_avail == adapter->num_tx_desc) {
txr->queue_status = IGB_QUEUE_IDLE;
return FALSE;
@@ -3745,20 +3721,20 @@ igb_txeof(struct tx_ring *txr)
** for too long indicates a hang.
*/
if ((!processed) && ((ticks - txr->watchdog_time) > IGB_WATCHDOG))
- txr->queue_status = IGB_QUEUE_HUNG;
-
+ txr->queue_status |= IGB_QUEUE_HUNG;
/*
- * If we have a minimum free, clear IFF_DRV_OACTIVE
- * to tell the stack that it is OK to send packets.
+ * If we have a minimum free,
+ * clear depleted state bit
*/
- if (txr->tx_avail > IGB_TX_CLEANUP_THRESHOLD) {
- ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- /* All clean, turn off the watchdog */
- if (txr->tx_avail == adapter->num_tx_desc) {
- txr->queue_status = IGB_QUEUE_IDLE;
- return (FALSE);
- }
+ if (txr->tx_avail >= IGB_QUEUE_THRESHOLD)
+ txr->queue_status &= ~IGB_QUEUE_DEPLETED;
+
+ /* All clean, turn off the watchdog */
+ if (txr->tx_avail == adapter->num_tx_desc) {
+ txr->queue_status = IGB_QUEUE_IDLE;
+ return (FALSE);
}
+
return (TRUE);
}
@@ -3989,10 +3965,6 @@ igb_setup_receive_ring(struct rx_ring *rxr)
bus_dma_segment_t pseg[1], hseg[1];
struct lro_ctrl *lro = &rxr->lro;
int rsize, nsegs, error = 0;
-#ifdef DEV_NETMAP
- struct netmap_adapter *na = NA(rxr->adapter->ifp);
- struct netmap_slot *slot;
-#endif /* DEV_NETMAP */
adapter = rxr->adapter;
dev = adapter->dev;
@@ -4000,9 +3972,6 @@ igb_setup_receive_ring(struct rx_ring *rxr)
/* Clear the ring contents */
IGB_RX_LOCK(rxr);
-#ifdef DEV_NETMAP
- slot = netmap_reset(na, NR_RX, rxr->me, 0);
-#endif /* DEV_NETMAP */
rsize = roundup2(adapter->num_rx_desc *
sizeof(union e1000_adv_rx_desc), IGB_DBA_ALIGN);
bzero((void *)rxr->rx_base, rsize);
@@ -4021,22 +3990,6 @@ igb_setup_receive_ring(struct rx_ring *rxr)
struct mbuf *mh, *mp;
rxbuf = &rxr->rx_buffers[j];
-#ifdef DEV_NETMAP
- if (slot) {
- /* slot sj is mapped to the i-th NIC-ring entry */
- int sj = j + na->rx_rings[rxr->me].nkr_hwofs;
- void *addr;
-
- if (sj < 0)
- sj += na->num_rx_desc;
- addr = NMB(slot + sj);
- netmap_load_map(rxr->ptag,
- rxbuf->pmap, addr, na->buff_size);
- /* Update descriptor */
- rxr->rx_base[j].read.pkt_addr = htole64(vtophys(addr));
- continue;
- }
-#endif /* DEV_NETMAP */
if (rxr->hdr_split == FALSE)
goto skip_head;
@@ -4321,26 +4274,6 @@ igb_initialize_receive_units(struct adapter *adapter)
for (int i = 0; i < adapter->num_queues; i++) {
rxr = &adapter->rx_rings[i];
E1000_WRITE_REG(hw, E1000_RDH(i), rxr->next_to_check);
-#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
- * somthing different from next_to_refresh
- * (which is not used in netmap mode).
- */
- if (ifp->if_capenable & IFCAP_NETMAP) {
- struct netmap_adapter *na = NA(adapter->ifp);
- struct netmap_kring *kring = &na->rx_rings[i];
- int t = rxr->next_to_refresh - kring->nr_hwavail;
-
- if (t >= adapter->num_rx_desc)
- t -= adapter->num_rx_desc;
- else if (t < 0)
- t += adapter->num_rx_desc;
- E1000_WRITE_REG(hw, E1000_RDT(i), t);
- } else
-#endif /* DEV_NETMAP */
E1000_WRITE_REG(hw, E1000_RDT(i), rxr->next_to_refresh);
}
return;
@@ -4519,19 +4452,6 @@ igb_rxeof(struct igb_queue *que, int count, int *done)
bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
-#ifdef DEV_NETMAP
- if (ifp->if_capenable & IFCAP_NETMAP) {
- struct netmap_adapter *na = NA(ifp);
-
- selwakeuppri(&na->rx_rings[rxr->me].si, PI_NET);
- IGB_RX_UNLOCK(rxr);
- IGB_CORE_LOCK(adapter);
- selwakeuppri(&na->rx_rings[na->num_queues + 1].si, PI_NET);
- IGB_CORE_UNLOCK(adapter);
- return (0);
- }
-#endif /* DEV_NETMAP */
-
/* Main clean loop */
for (i = rxr->next_to_check; count != 0;) {
struct mbuf *sendmp, *mh, *mp;
@@ -4858,8 +4778,8 @@ igb_setup_vlan_hw_support(struct adapter *adapter)
e1000_vfta_set_vf(hw,
adapter->shadow_vfta[i], TRUE);
else
- E1000_WRITE_REG_ARRAY(hw, E1000_VFTA,
- i, adapter->shadow_vfta[i]);
+ e1000_write_vfta(hw,
+ i, adapter->shadow_vfta[i]);
}
}
@@ -5725,23 +5645,26 @@ igb_set_sysctl_value(struct adapter *adapter, const char *name,
static int
igb_set_flowcntl(SYSCTL_HANDLER_ARGS)
{
- int error;
- struct adapter *adapter = (struct adapter *) arg1;
+ int error;
+ static int input = 3; /* default is full */
+ struct adapter *adapter = (struct adapter *) arg1;
- error = sysctl_handle_int(oidp, &adapter->fc, 0, req);
+ error = sysctl_handle_int(oidp, &input, 0, req);
if ((error) || (req->newptr == NULL))
return (error);
- switch (adapter->fc) {
+ switch (input) {
case e1000_fc_rx_pause:
case e1000_fc_tx_pause:
case e1000_fc_full:
- adapter->hw.fc.requested_mode = adapter->fc;
- break;
case e1000_fc_none:
+ adapter->hw.fc.requested_mode = input;
+ adapter->fc = input;
+ break;
default:
- adapter->hw.fc.requested_mode = e1000_fc_none;
+ /* Do nothing */
+ return (error);
}
adapter->hw.fc.current_mode = adapter->hw.fc.requested_mode;
diff --git a/sys/dev/e1000/if_igb.h b/sys/dev/e1000/if_igb.h
index 80abf6e..cef62f9 100644
--- a/sys/dev/e1000/if_igb.h
+++ b/sys/dev/e1000/if_igb.h
@@ -188,9 +188,13 @@
#define IGB_TX_BUFFER_SIZE ((uint32_t) 1514)
#define IGB_FC_PAUSE_TIME 0x0680
#define IGB_EEPROM_APME 0x400;
-#define IGB_QUEUE_IDLE 0
-#define IGB_QUEUE_WORKING 1
-#define IGB_QUEUE_HUNG 2
+/* Queue minimum free for use */
+#define IGB_QUEUE_THRESHOLD (adapter->num_tx_desc / 8)
+/* Queue bit defines */
+#define IGB_QUEUE_IDLE 1
+#define IGB_QUEUE_WORKING 2
+#define IGB_QUEUE_HUNG 4
+#define IGB_QUEUE_DEPLETED 8
/*
* TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be
@@ -297,7 +301,6 @@ struct tx_ring {
struct buf_ring *br;
#endif
bus_dma_tag_t txtag;
- struct task txq_task;
u32 bytes;
u32 packets;
@@ -402,7 +405,6 @@ struct adapter {
u16 link_duplex;
u32 smartspeed;
u32 dmac;
- int enable_aim;
/* Interface queues */
struct igb_queue *queues;
diff --git a/sys/dev/e1000/if_lem.c b/sys/dev/e1000/if_lem.c
index 9b34a2d..5fe24be 100644
--- a/sys/dev/e1000/if_lem.c
+++ b/sys/dev/e1000/if_lem.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2010, Intel Corporation
+ Copyright (c) 2001-2011, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
#ifdef HAVE_KERNEL_OPTION_HEADERS
#include "opt_device_polling.h"
#include "opt_inet.h"
+#include "opt_inet6.h"
#endif
#include <sys/param.h>
@@ -84,7 +85,7 @@
/*********************************************************************
* Legacy Em Driver version:
*********************************************************************/
-char lem_driver_version[] = "1.0.3";
+char lem_driver_version[] = "1.0.4";
/*********************************************************************
* PCI Device ID Table
@@ -390,6 +391,11 @@ lem_attach(device_t dev)
INIT_DEBUGOUT("lem_attach: begin");
+ if (resource_disabled("lem", 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;
EM_CORE_LOCK_INIT(adapter, device_get_nameunit(dev));
@@ -453,7 +459,7 @@ lem_attach(device_t dev)
/* Sysctl for setting the interface flow control */
lem_set_flow_cntrl(adapter, "flow_control",
- "max number of rx packets to process",
+ "flow control setting",
&adapter->fc_setting, lem_fc_setting);
/*
@@ -890,11 +896,12 @@ static int
lem_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);
@@ -902,23 +909,26 @@ lem_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);
- lem_init_locked(adapter);
- EM_CORE_UNLOCK(adapter);
- }
- arp_ifinit(ifp, ifa);
- } else
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+ lem_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:
@@ -1217,9 +1227,6 @@ lem_init_locked(struct adapter *adapter)
/* AMT based hardware can now take control from firmware */
if (adapter->has_manage && adapter->has_amt)
lem_get_hw_control(adapter);
-
- /* Don't reset the phy next time init gets called */
- adapter->hw.phy.reset_disable = TRUE;
}
static void
@@ -1518,11 +1525,6 @@ lem_media_change(struct ifnet *ifp)
device_printf(adapter->dev, "Unsupported media type\n");
}
- /* As the speed/duplex settings my have changed we need to
- * reset the PHY.
- */
- adapter->hw.phy.reset_disable = FALSE;
-
lem_init_locked(adapter);
EM_CORE_UNLOCK(adapter);
diff --git a/sys/dev/e1000/if_lem.h b/sys/dev/e1000/if_lem.h
index 46ebad1..c1973e5 100644
--- a/sys/dev/e1000/if_lem.h
+++ b/sys/dev/e1000/if_lem.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2010, Intel Corporation
+ Copyright (c) 2001-2011, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -217,7 +217,7 @@
#define EM_BAR_MEM_TYPE_64BIT 0x00000004
#define EM_MSIX_BAR 3 /* On 82575 */
-#if !defined(SYSCTL_ADD_UQUAD)
+#if __FreeBSD_version < 900000
#define SYSCTL_ADD_UQUAD SYSCTL_ADD_QUAD
#endif
OpenPOWER on IntegriCloud