Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 11 Mar 2012 11:17:07 +0330
From:      Hooman Fazaeli <hoomanfazaeli@gmail.com>
To:        Adrian Chadd <adrian@freebsd.org>
Cc:        freebsd-net@freebsd.org, Jason Wolfe <nitroboost@gmail.com>
Subject:   Re: Intel 82574L interface wedging - em7.3.2/8.2-STABLE
Message-ID:  <4F5C587B.6010004@gmail.com>
In-Reply-To: <CAJ-Vmo=2BWQd3an3TT9-YZrLPYDoHs7ZJET360HMQijOWPavOQ@mail.gmail.com>
References:  <CAAAm0r3Qj%2B2rf8cx54bcyAXGQezcE8J=xXYPq4W-jDy75r8qew@mail.gmail.com>	<CAAAm0r281Bs-yKbf6ZjCTGPLf0voh=T10GpBc3e-e%2B=10AvU9g@mail.gmail.com>	<4F5B2E0E.10201@gmail.com> <CAJ-Vmo=2BWQd3an3TT9-YZrLPYDoHs7ZJET360HMQijOWPavOQ@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4F5C587B.6010004>