On 3/11/2012 5:31 AM, Adrian Chadd wrote:
Are you able to post the patch here?
Maybe Jack can look at what's going on and apply it to the latest
intel ethernet driver.
Adrian
Below is the patch for if_em.c (7.2.3). It simply checks driver's
queue status when the link state changes (inactive -> active) and
start transmit task if queue(s) are not empty.
It also contains stuff I have added to compile on 7 plus some code
for test and diagnostics.
Hope it helps.
--- if_em.c.orig 2011-10-27 14:47:20.000000000 +0330
+++ if_em.c 2011-11-19 16:11:54.000000000 +0330
@@ -85,6 +85,14 @@
#include "e1000_82571.h"
#include "if_em.h"
+#if !defined(DISABLE_FIXUPS) && __FreeBSD_version < 800000
+static __inline int
+pci_find_cap(device_t dev, int capability, int *capreg)
+{
+ return (PCI_FIND_EXTCAP(device_get_parent(dev), dev, capability,
capreg));
+}
+#endif
+
/*********************************************************************
* Set this to one to display debug statistics
*********************************************************************/
@@ -93,7 +101,11 @@
/*********************************************************************
* Driver version:
*********************************************************************/
+#ifdef PKG_VERSION
+char em_driver_version[] = "version 7.2.3 (ifdrivers-" PKG_VERSION ")";
+#else
char em_driver_version[] = "7.2.3";
+#endif
/*********************************************************************
* PCI Device ID Table
@@ -293,6 +305,11 @@
static poll_handler_t em_poll;
#endif /* POLLING */
+#ifndef DISABLE_FIXUPS
+static int em_sysctl_snd_ifq_len(SYSCTL_HANDLER_ARGS);
+static int em_sysctl_snd_ifq_drv_len(SYSCTL_HANDLER_ARGS);
+#endif
+
/*********************************************************************
* FreeBSD Device Interface Entry Points
*********************************************************************/
@@ -399,6 +416,23 @@
/* Global used in WOL setup with multiport cards */
static int global_quad_port_a = 0;
+#ifndef DISABLE_FIXUPS
+static int enable_hang_fixup = 1;
+TUNABLE_INT("hw.em.enable_hang_fixup", &enable_hang_fixup);
+SYSCTL_INT(_hw_em, OID_AUTO, enable_hang_fixup, CTLFLAG_RW,
&enable_hang_fixup, 0,
+ "Enable rx/tx hang fixup");
+
+static int em_regard_tx_link_status = 1;
+TUNABLE_INT("hw.em.regard_tx_link_status", &em_regard_tx_link_status);
+SYSCTL_INT(_hw_em, OID_AUTO, regard_tx_link_status, CTLFLAG_RW,
&em_regard_tx_link_status, 0,
+ "Regard tx link status");
+
+static int link_master_slave = e1000_ms_hw_default;
+TUNABLE_INT("hw.em.link_master_slave", &link_master_slave);
+SYSCTL_INT(_hw_em, OID_AUTO, link_master_slave, CTLFLAG_RW, &link_master_slave,
+ 0, "Link negotiation master/slave type");
+#endif
+
/*********************************************************************
* Device identification routine
*
@@ -411,7 +445,11 @@
static int
em_probe(device_t dev)
{
+#ifdef PKG_VERSION
+ char adapter_name[sizeof(em_driver_version) + 60];
+#else
char adapter_name[60];
+#endif
u16 pci_vendor_id = 0;
u16 pci_device_id = 0;
u16 pci_subvendor_id = 0;
@@ -864,7 +902,11 @@
int err = 0, enq = 0;
if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+#ifndef DISABLE_FIXUPS
IFF_DRV_RUNNING || adapter->link_active == 0) {
+#else
+ IFF_DRV_RUNNING || (em_regard_tx_link_status &&
!adapter->link_active)) {
+#endif
if (m != NULL)
err = drbr_enqueue(ifp, txr->br, m);
return (err);
@@ -962,9 +1004,17 @@
if ((ifp->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) !=
IFF_DRV_RUNNING)
return;
+#ifdef _TEST
+ if (adapter->forced_link_status == 0)
+ return;
+#endif
+#ifdef DISABLE_FIXUPS
if (!adapter->link_active)
+#else
+ if (em_regard_tx_link_status && !adapter->link_active)
return;
+#endif
while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
/* Call cleanup if number of TX descriptors low */
@@ -977,6 +1027,17 @@
IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
if (m_head == NULL)
break;
+#ifdef _TEST
+ if (adapter->forced_xmit_error == ENOMEM) {
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
+ break;
+ } else if (adapter->forced_xmit_error != 0) {
+ m_freem(m_head);
+ m_head = NULL;
+ break;
+ } else
+#endif
/*
* Encapsulation can modify our pointer, and or make it
* NULL on failure. In that event, we can't requeue.
@@ -1141,6 +1202,10 @@
adapter->hw.phy.reset_disable = FALSE;
/* Check SOL/IDER usage */
EM_CORE_LOCK(adapter);
+#ifndef DISABLE_FIXUPS
+ if (adapter->hw.phy.media_type == e1000_media_type_copper)
+ adapter->hw.phy.ms_type = link_master_slave;
+#endif
if (e1000_check_reset_block(&adapter->hw)) {
EM_CORE_UNLOCK(adapter);
device_printf(adapter->dev, "Media change is"
@@ -1283,7 +1348,9 @@
INIT_DEBUGOUT1("em_init: pba=%dK",pba);
E1000_WRITE_REG(&adapter->hw, E1000_PBA, pba);
-
+#ifndef DISABLE_FIXUPS
+ device_printf(adapter->dev, "%dK rx packet buffer\n", (int)pba);
+#endif
/* Get the latest mac address, User can use a LAA */
bcopy(IF_LLADDR(adapter->ifp), adapter->hw.mac.addr,
ETHER_ADDR_LEN);
@@ -1395,6 +1462,10 @@
/* Don't reset the phy next time init gets called */
adapter->hw.phy.reset_disable = TRUE;
+#ifdef _TEST
+ adapter->forced_link_status = -1;
+ adapter->forced_xmit_error = 0;
+#endif
}
static void
@@ -1414,7 +1485,11 @@
* Legacy polling routine: note this only works with single queue
*
*********************************************************************/
+#if !defined(DISABLE_FIXUPS) && __FreeBSD_version < 800000
+static void
+#else
static int
+#endif
em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
{
struct adapter *adapter = ifp->if_softc;
@@ -1426,7 +1501,11 @@
EM_CORE_LOCK(adapter);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
EM_CORE_UNLOCK(adapter);
+#if !defined(DISABLE_FIXUPS) && __FreeBSD_version < 800000
+ return;
+#else
return (0);
+#endif
}
if (cmd == POLL_AND_CHECK_STATUS) {
@@ -1452,8 +1531,11 @@
em_start_locked(ifp, txr);
#endif
EM_TX_UNLOCK(txr);
-
+#if !defined(DISABLE_FIXUPS) && __FreeBSD_version < 800000
+ return;
+#else
return (rx_done);
+#endif
}
#endif /* DEVICE_POLLING */
@@ -1525,7 +1607,11 @@
em_start_locked(ifp, txr);
#endif
EM_TX_UNLOCK(txr);
+#ifdef DISABLE_FIXUPS
if (more || (ifp->if_drv_flags & IFF_DRV_OACTIVE)) {
+#else
+ if (more) {
+#endif
taskqueue_enqueue(adapter->tq, &adapter->que_task);
return;
}
@@ -1652,6 +1738,29 @@
EM_CORE_LOCK(adapter);
callout_stop(&adapter->timer);
em_update_link_status(adapter);
+#ifndef DISABLE_FIXUPS
+ /*
+ * Kick off transmission if link has become active and tx
+ * queues are not empty.
+ */
+ if (adapter->link_active && adapter->msix > 1) {
+# ifdef EM_MULTIQUEUE
+ for (int i = 0; i < adapter->num_queues; i++) {
+ struct tx_ring = adapter->tx_rings + i;
+ if (!drbr_empty(ifp, txr->br)) {
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ taskqueue_enqueue(txr->tq, &txr->tx_task);
+ }
+ }
+# else
+ if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
+ struct tx_ring *txr = adapter->tx_rings;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ taskqueue_enqueue(txr->tq, &txr->tx_task);
+ }
+ }
+# endif
+#endif
callout_reset(&adapter->timer, hz, em_local_timer, adapter);
E1000_WRITE_REG(&adapter->hw, E1000_IMS,
EM_MSIX_LINK | E1000_IMS_LSC);
@@ -2212,7 +2321,41 @@
if ((adapter->hw.mac.type == e1000_82571) &&
e1000_get_laa_state_82571(&adapter->hw))
e1000_rar_set(&adapter->hw, adapter->hw.mac.addr, 0);
+#ifdef _TEST
+ adapter->local_timer_runs++;
+#endif
+#ifndef DISABLE_FIXUPS
+ if (enable_hang_fixup) {
+ struct ifnet *ifp = adapter->ifp;
+ struct ifaltq *ifsnd = &ifp->if_snd;
+ for (int i = 0; i < adapter->num_queues; i++) {
+ struct rx_ring *rxr = adapter->rx_rings + i;
+ struct tx_ring *txr = adapter->tx_rings + i;
+ bool rxhung = FALSE;
+ if (rxr->next_to_check == rxr->next_to_refresh) {
+ rxhung = TRUE;
+ adapter->rx_hangs++;
+ if (adapter->msix > 1)
+ taskqueue_enqueue(rxr->tq,
+ &rxr->rx_task);
+ else
+ taskqueue_enqueue(adapter->tq,
+ &adapter->que_task);
+ }
+ if (ifsnd->ifq_len * 2 >= ifsnd->ifq_maxlen) {
+ adapter->tx_hangs++;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ if (adapter->msix > 1)
+ taskqueue_enqueue(txr->tq,
+ &txr->tx_task);
+ else if (!rxhung)
+ taskqueue_enqueue(adapter->tq,
+ &adapter->que_task);
+ }
+ }
+ }
+#endif
/* Mask to use in the irq trigger */
if (adapter->msix_mem)
trigger = rxr->ims; /* RX for 82574 */
@@ -2311,6 +2454,9 @@
((adapter->link_duplex == FULL_DUPLEX) ?
"Full Duplex" : "Half Duplex"));
adapter->link_active = 1;
+#ifndef DISABLE_FIXUPS
+ adapter->link_toggles++;
+#endif
adapter->smartspeed = 0;
ifp->if_baudrate = adapter->link_speed * 1000000;
if_link_state_change(ifp, LINK_STATE_UP);
@@ -2320,6 +2466,9 @@
if (bootverbose)
device_printf(dev, "Link is Down\n");
adapter->link_active = 0;
+#ifndef DISABLE_FIXUPS
+ adapter->link_toggles++;
+#endif
/* Link down, disable watchdog */
for (int i = 0; i < adapter->num_queues; i++, txr++)
txr->queue_status = EM_QUEUE_IDLE;
@@ -3766,7 +3915,7 @@
* If we have a minimum free, clear IFF_DRV_OACTIVE
* to tell the stack that it is OK to send packets.
*/
- if (txr->tx_avail > EM_MAX_SCATTER)
+ if (txr->tx_avail >= EM_MAX_SCATTER)
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
/* Disable watchdog if all clean */
@@ -5131,7 +5280,36 @@
SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_timeouts",
CTLFLAG_RD, &adapter->watchdog_events,
"Watchdog timeouts");
-
+#ifndef DISABLE_FIXUPS
+ SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_toggles",
+ CTLFLAG_RD, &adapter->link_toggles,
+ "Number of link status changes");
+ SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "rx_hangs",
+ CTLFLAG_RD, &adapter->rx_hangs,
+ "Number of rx hangs");
+ SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "tx_hangs",
+ CTLFLAG_RD, &adapter->tx_hangs,
+ "Number of tx hangs");
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "snd_ifq_len",
+ CTLTYPE_INT | CTLFLAG_RD, adapter->ifp,
+ sizeof(adapter->ifp), em_sysctl_snd_ifq_len, "I",
+ "if_snd queue length");
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "snd_ifq_drv_len",
+ CTLTYPE_INT | CTLFLAG_RD, adapter->ifp,
+ sizeof(adapter->ifp), em_sysctl_snd_ifq_drv_len, "I",
+ "if_snd drv queue length");
+#endif
+#ifdef _TEST
+ SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "local_timer_runs",
+ CTLFLAG_RD, &adapter->local_timer_runs,
+ "Local timer runs");
+ SYSCTL_ADD_INT(ctx, child, OID_AUTO, "forced_link_status",
+ CTLFLAG_RW|CTLTYPE_INT, &adapter->forced_link_status,
+ 0, "Forced link status");
+ SYSCTL_ADD_INT(ctx, child, OID_AUTO, "forced_xmit_error",
+ CTLFLAG_RW|CTLTYPE_INT, &adapter->forced_xmit_error,
+ 0, "Forced xmit error");
+#endif
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "device_control",
CTLTYPE_UINT | CTLFLAG_RD, adapter, E1000_CTRL,
em_sysctl_reg_handler, "IU",
@@ -5553,4 +5731,42 @@
rxr->rx_discarded);
device_printf(dev, "RX Next to Check = %d\n", rxr->next_to_check);
device_printf(dev, "RX Next to Refresh = %d\n", rxr->next_to_refresh);
+#ifndef DISABLE_FIXUPS
+ device_printf(dev, "Link state: %s\n",
+ adapter->link_active? "active": "inactive");
+#endif
+}
+
+#ifndef DISABLE_FIXUPS
+static int
+em_sysctl_snd_ifq_len(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+ int v;
+ struct ifnet *ifp = ((struct ifnet *)oidp->oid_arg1);
+
+ if (ifp == NULL)
+ return 0;
+ v = _IF_QLEN(&ifp->if_snd);
+ error = sysctl_handle_int(oidp, &v, 0, req);
+ if (error || !req->newptr)
+ return error;
+ return 0;
}
+
+static int
+em_sysctl_snd_ifq_drv_len(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+ int v;
+ struct ifnet *ifp = ((struct ifnet *)oidp->oid_arg1);
+
+ if (ifp == NULL)
+ return 0;
+ v = ifp->if_snd.ifq_drv_len;
+ error = sysctl_handle_int(oidp, &v, 0, req);
+ if (error || !req->newptr)
+ return error;
+ return 0;
+}
+#endif
_______________________________________________
freebsd-net@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org"