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"

Reply via email to