Intel 82574L interface wedging - em7.3.2/8.2-STABLE
Hooman Fazaeli
hoomanfazaeli at gmail.com
Sun Mar 11 07:47:22 UTC 2012
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
More information about the freebsd-net
mailing list