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>