From owner-freebsd-net@FreeBSD.ORG Thu Oct 20 14:02:04 2005 Return-Path: X-Original-To: net@FreeBSD.org Delivered-To: freebsd-net@FreeBSD.ORG Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 1D92516A41F for ; Thu, 20 Oct 2005 14:02:04 +0000 (GMT) (envelope-from glebius@FreeBSD.org) Received: from cell.sick.ru (cell.sick.ru [217.72.144.68]) by mx1.FreeBSD.org (Postfix) with ESMTP id 2ED1C43D69 for ; Thu, 20 Oct 2005 14:02:02 +0000 (GMT) (envelope-from glebius@FreeBSD.org) Received: from cell.sick.ru (glebius@localhost [127.0.0.1]) by cell.sick.ru (8.13.3/8.13.3) with ESMTP id j9KE20s9002900 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Thu, 20 Oct 2005 18:02:01 +0400 (MSD) (envelope-from glebius@FreeBSD.org) Received: (from glebius@localhost) by cell.sick.ru (8.13.3/8.13.1/Submit) id j9KE20ts002899 for net@FreeBSD.org; Thu, 20 Oct 2005 18:02:00 +0400 (MSD) (envelope-from glebius@FreeBSD.org) X-Authentication-Warning: cell.sick.ru: glebius set sender to glebius@FreeBSD.org using -f Date: Thu, 20 Oct 2005 18:02:00 +0400 From: Gleb Smirnoff To: net@FreeBSD.org Message-ID: <20051020140200.GL59364@cell.sick.ru> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="ZJcv+A0YCCLh2VIg" Content-Disposition: inline User-Agent: Mutt/1.5.6i Cc: Subject: em(4) patch for test X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 20 Oct 2005 14:02:04 -0000 --ZJcv+A0YCCLh2VIg Content-Type: text/plain; charset=koi8-r Content-Disposition: inline Colleagues, since the if_em problem was taken as a late showstopper for 6.0-RELEASE, I am asking you to help with testing of the fixes made in HEAD. Does your em(4) interface wedge for some time? Do you see a lot of errors in 'netstat -i' output? Does these errors increase not monotonously but they have peaks? If the answer is yes, then the attached patch is likely to fix your problem. If the answer is no, then you are still encouraged to help with testing and install the patch to check that no regressions are introduced. If you skip this, then you may encounter regressions after release, so you have been warned. So, in short: please test! Thanks in advance! The patch is against fresh RELENG_6. -- Totus tuus, Glebius. GLEBIUS-RIPN GLEB-RIPE --ZJcv+A0YCCLh2VIg Content-Type: text/plain; charset=koi8-r Content-Disposition: attachment; filename="if_em.HEAD-RELENG_6.diff" Index: if_em.c =================================================================== RCS file: /home/ncvs/src/sys/dev/em/if_em.c,v retrieving revision 1.65.2.5 retrieving revision 1.81 diff -u -r1.65.2.5 -r1.81 --- if_em.c 7 Oct 2005 14:00:03 -0000 1.65.2.5 +++ if_em.c 20 Oct 2005 09:55:49 -0000 1.81 @@ -31,7 +31,7 @@ ***************************************************************************/ -/*$FreeBSD: src/sys/dev/em/if_em.c,v 1.65.2.5 2005/10/07 14:00:03 glebius Exp $*/ +/*$FreeBSD: src/sys/dev/em/if_em.c,v 1.81 2005/10/20 09:55:49 glebius Exp $*/ #ifdef HAVE_KERNEL_OPTION_HEADERS #include "opt_device_polling.h" @@ -45,13 +45,6 @@ int em_display_debug_stats = 0; /********************************************************************* - * Linked list of board private structures for all NICs found - *********************************************************************/ - -struct adapter *em_adapter_list = NULL; - - -/********************************************************************* * Driver version *********************************************************************/ @@ -326,11 +319,6 @@ adapter->unit = device_get_unit(dev); EM_LOCK_INIT(adapter, device_get_nameunit(dev)); - if (em_adapter_list != NULL) - em_adapter_list->prev = adapter; - adapter->next = em_adapter_list; - em_adapter_list = adapter; - /* SYSCTL stuff */ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), @@ -511,6 +499,7 @@ err_tx_desc: err_pci: em_free_pci_resources(adapter); + EM_LOCK_DESTROY(adapter); return(error); } @@ -543,14 +532,11 @@ em_stop(adapter); em_phy_hw_reset(&adapter->hw); EM_UNLOCK(adapter); -#if __FreeBSD_version < 500000 - ether_ifdetach(adapter->ifp, ETHER_BPF_SUPPORTED); -#else ether_ifdetach(adapter->ifp); - if_free(ifp); -#endif + em_free_pci_resources(adapter); bus_generic_detach(dev); + if_free(ifp); /* Free Transmit Descriptor ring */ if (adapter->tx_desc_base) { @@ -564,19 +550,8 @@ adapter->rx_desc_base = NULL; } - /* Remove from the adapter list */ - if (em_adapter_list == adapter) - em_adapter_list = adapter->next; - if (adapter->next != NULL) - adapter->next->prev = adapter->prev; - if (adapter->prev != NULL) - adapter->prev->next = adapter->next; - EM_LOCK_DESTROY(adapter); - ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); - ifp->if_timer = 0; - return(0); } @@ -637,12 +612,7 @@ } /* Send a copy of the frame to the BPF listener */ -#if __FreeBSD_version < 500000 - if (ifp->if_bpf) - bpf_mtap(ifp, m_head); -#else BPF_MTAP(ifp, m_head); -#endif /* Set timeout in case hardware has problems transmitting */ ifp->if_timer = EM_TX_TIMEOUT; @@ -797,11 +767,13 @@ struct adapter * adapter; adapter = ifp->if_softc; + EM_LOCK(adapter); /* If we are in this routine because of pause frames, then * don't reset the hardware. */ if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF) { ifp->if_timer = EM_TX_TIMEOUT; + EM_UNLOCK(adapter); return; } @@ -809,11 +781,10 @@ printf("em%d: watchdog timeout -- resetting\n", adapter->unit); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - - em_init(adapter); - ifp->if_oerrors++; - return; + + em_init_locked(adapter); + EM_UNLOCK(adapter); } /********************************************************************* @@ -996,51 +967,57 @@ static void em_intr(void *arg) { - u_int32_t loop_cnt = EM_MAX_INTR; - u_int32_t reg_icr; - struct ifnet *ifp; - struct adapter *adapter = arg; + struct adapter *adapter = arg; + struct ifnet *ifp; + uint32_t reg_icr; + int wantinit = 0; EM_LOCK(adapter); - ifp = adapter->ifp; + ifp = adapter->ifp; #ifdef DEVICE_POLLING - if (ifp->if_capenable & IFCAP_POLLING) { + if (ifp->if_capenable & IFCAP_POLLING) { EM_UNLOCK(adapter); - return; + return; } #endif /* DEVICE_POLLING */ - reg_icr = E1000_READ_REG(&adapter->hw, ICR); - if (!reg_icr) { - EM_UNLOCK(adapter); - return; - } - - /* Link status change */ - if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { - callout_stop(&adapter->timer); - adapter->hw.get_link_status = 1; - em_check_for_link(&adapter->hw); - em_print_link_status(adapter); - callout_reset(&adapter->timer, hz, em_local_timer, adapter); - } + for (;;) { + reg_icr = E1000_READ_REG(&adapter->hw, ICR); + if (reg_icr == 0) + break; - while (loop_cnt > 0) { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - em_process_receive_interrupts(adapter, -1); - em_clean_transmit_interrupts(adapter); - } - loop_cnt--; - } + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + em_process_receive_interrupts(adapter, -1); + em_clean_transmit_interrupts(adapter); + } - if (ifp->if_drv_flags & IFF_DRV_RUNNING && + /* Link status change */ + if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + callout_stop(&adapter->timer); + adapter->hw.get_link_status = 1; + em_check_for_link(&adapter->hw); + em_print_link_status(adapter); + callout_reset(&adapter->timer, hz, em_local_timer, + adapter); + } + + if (reg_icr & E1000_ICR_RXO) { + log(LOG_WARNING, "%s: RX overrun\n", ifp->if_xname); + wantinit = 1; + } + } +#if 0 + if (wantinit) + em_init_locked(adapter); +#endif + if (ifp->if_drv_flags & IFF_DRV_RUNNING && !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - em_start_locked(ifp); + em_start_locked(ifp); EM_UNLOCK(adapter); - return; + return; } @@ -1095,11 +1072,7 @@ ifmr->ifm_active |= IFM_100_TX; break; case 1000: -#if __FreeBSD_version < 500000 - ifmr->ifm_active |= IFM_1000_TX; -#else ifmr->ifm_active |= IFM_1000_T; -#endif break; } if (adapter->link_duplex == FULL_DUPLEX) @@ -1135,11 +1108,7 @@ adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; break; case IFM_1000_SX: -#if __FreeBSD_version < 500000 - case IFM_1000_TX: -#else case IFM_1000_T: -#endif adapter->hw.autoneg = DO_AUTO_NEG; adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; break; @@ -1193,12 +1162,7 @@ DESC_ARRAY desc_array; u_int32_t array_elements; u_int32_t counter; - -#if __FreeBSD_version < 500000 - struct ifvlan *ifv = NULL; -#else struct m_tag *mtag; -#endif bus_dma_segment_t segs[EM_MAX_SCATTER]; bus_dmamap_t map; int nsegs; @@ -1251,14 +1215,7 @@ /* Find out if we are in vlan mode */ -#if __FreeBSD_version < 500000 - if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && - m_head->m_pkthdr.rcvif != NULL && - m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN) - ifv = m_head->m_pkthdr.rcvif->if_softc; -#else mtag = VLAN_OUTPUT_TAG(ifp, m_head); -#endif /* * When operating in promiscuous mode, hardware encapsulation for @@ -1361,15 +1318,9 @@ adapter->num_tx_desc_avail -= nsegs; } -#if __FreeBSD_version < 500000 - if (ifv != NULL) { - /* Set the vlan id */ - current_tx_desc->upper.fields.special = htole16(ifv->ifv_tag); -#else if (mtag != NULL) { /* Set the vlan id */ current_tx_desc->upper.fields.special = htole16(VLAN_TAG_VALUE(mtag)); -#endif /* Tell hardware to add tag */ current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_VLE); @@ -1611,11 +1562,7 @@ } IF_ADDR_LOCK(ifp); -#if __FreeBSD_version < 500000 - LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { -#else TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { -#endif if (ifma->ifma_addr->sa_family != AF_LINK) continue; @@ -1729,6 +1676,7 @@ mtx_assert(&adapter->mtx, MA_OWNED); INIT_DEBUGOUT("em_stop: begin"); + em_disable_intr(adapter); em_reset_hw(&adapter->hw); callout_stop(&adapter->timer); @@ -1960,11 +1908,7 @@ ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 1; IFQ_SET_READY(&ifp->if_snd); -#if __FreeBSD_version < 500000 - ether_ifattach(ifp, ETHER_BPF_SUPPORTED); -#else ether_ifattach(ifp, adapter->hw.mac_addr); -#endif ifp->if_capabilities = ifp->if_capenable = 0; @@ -1977,10 +1921,8 @@ * Tell the upper layer(s) we support long frames. */ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); -#if __FreeBSD_version >= 500000 ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; ifp->if_capenable |= IFCAP_VLAN_MTU; -#endif #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; @@ -2005,15 +1947,9 @@ 0, NULL); ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL); -#if __FreeBSD_version < 500000 - ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX | IFM_FDX, - 0, NULL); - ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX, 0, NULL); -#else ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); -#endif } ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); @@ -2139,7 +2075,6 @@ goto fail_3; } - dma->dma_size = size; return (0); fail_3: @@ -2545,7 +2480,8 @@ } rx_buffer->m_head = mp; adapter->rx_desc_base[i].buffer_addr = htole64(paddr); - bus_dmamap_sync(adapter->rxtag, rx_buffer->map, BUS_DMASYNC_PREREAD); + bus_dmamap_sync(adapter->rxtag, rx_buffer->map, BUS_DMASYNC_PREREAD | + BUS_DMASYNC_PREWRITE); return(0); } @@ -2786,9 +2722,6 @@ { struct ifnet *ifp; struct mbuf *mp; -#if __FreeBSD_version < 500000 - struct ether_header *eh; -#endif u_int8_t accept_frame = 0; u_int8_t eop = 0; u_int16_t len, desc_len, prev_len_adj; @@ -2809,7 +2742,10 @@ return; } - while ((current_desc->status & E1000_RXD_STAT_DD) && (count != 0)) { + while ((current_desc->status & E1000_RXD_STAT_DD) && + (count != 0) && + (ifp->if_drv_flags & IFF_DRV_RUNNING)) { + struct mbuf *m = NULL; mp = adapter->rx_buffer_area[i].m_head; bus_dmamap_sync(adapter->rxtag, adapter->rx_buffer_area[i].map, @@ -2893,22 +2829,7 @@ if (eop) { adapter->fmp->m_pkthdr.rcvif = ifp; - ifp->if_ipackets++; - -#if __FreeBSD_version < 500000 - eh = mtod(adapter->fmp, struct ether_header *); - /* Remove ethernet header from mbuf */ - m_adj(adapter->fmp, sizeof(struct ether_header)); - em_receive_checksum(adapter, current_desc, - adapter->fmp); - if (current_desc->status & E1000_RXD_STAT_VP) - VLAN_INPUT_TAG(eh, adapter->fmp, - (current_desc->special & - E1000_RXD_SPC_VLAN_MASK)); - else - ether_input(ifp, eh, adapter->fmp); -#else - + ifp->if_ipackets++; em_receive_checksum(adapter, current_desc, adapter->fmp); if (current_desc->status & E1000_RXD_STAT_VP) @@ -2916,17 +2837,10 @@ (current_desc->special & E1000_RXD_SPC_VLAN_MASK), adapter->fmp = NULL); - - if (adapter->fmp != NULL) { - struct mbuf *m = adapter->fmp; - adapter->fmp = NULL; - EM_UNLOCK(adapter); - (*ifp->if_input)(ifp, m); - EM_LOCK(adapter); - } -#endif - adapter->lmp = NULL; + m = adapter->fmp; + adapter->fmp = NULL; + adapter->lmp = NULL; } } else { adapter->dropped_pkts++; @@ -2939,19 +2853,24 @@ /* Zero out the receive descriptors status */ current_desc->status = 0; + bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ E1000_WRITE_REG(&adapter->hw, RDT, i); /* Advance our pointers to the next descriptor */ - if (++i == adapter->num_rx_desc) { - i = 0; - current_desc = adapter->rx_desc_base; - } else - current_desc++; + if (++i == adapter->num_rx_desc) + i = 0; + if (m != NULL) { + adapter->next_rx_desc_to_check = i; + EM_UNLOCK(adapter); + (*ifp->if_input)(ifp, m); + EM_LOCK(adapter); + i = adapter->next_rx_desc_to_check; + } + current_desc = &adapter->rx_desc_base[i]; } - bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); adapter->next_rx_desc_to_check = i; return; } @@ -3255,10 +3174,6 @@ } ifp = adapter->ifp; - /* Fill out the OS statistics structure */ - ifp->if_ibytes = adapter->stats.gorcl; - ifp->if_obytes = adapter->stats.gotcl; - ifp->if_imcasts = adapter->stats.mprc; ifp->if_collisions = adapter->stats.colc; /* Rx Errors */ @@ -3420,10 +3335,8 @@ int error; int usecs; int ticks; - int s; info = (struct em_int_delay_info *)arg1; - adapter = info->adapter; usecs = info->value; error = sysctl_handle_int(oidp, &usecs, 0, req); if (error != 0 || req->newptr == NULL) @@ -3432,8 +3345,10 @@ return EINVAL; info->value = usecs; ticks = E1000_USECS_TO_TICKS(usecs); + + adapter = info->adapter; - s = splimp(); + EM_LOCK(adapter); regval = E1000_READ_OFFSET(&adapter->hw, info->offset); regval = (regval & ~0xffff) | (ticks & 0xffff); /* Handle a few special cases. */ @@ -3453,7 +3368,7 @@ break; } E1000_WRITE_OFFSET(&adapter->hw, info->offset, regval); - splx(s); + EM_UNLOCK(adapter); return 0; } Index: if_em.h =================================================================== RCS file: /home/ncvs/src/sys/dev/em/if_em.h,v retrieving revision 1.32 retrieving revision 1.35 diff -u -r1.32 -r1.35 --- if_em.h 10 Jun 2005 16:49:07 -0000 1.32 +++ if_em.h 20 Oct 2005 09:55:49 -0000 1.35 @@ -31,7 +31,7 @@ ***************************************************************************/ -/*$FreeBSD: src/sys/dev/em/if_em.h,v 1.32 2005/06/10 16:49:07 brooks Exp $*/ +/*$FreeBSD: src/sys/dev/em/if_em.h,v 1.35 2005/10/20 09:55:49 glebius Exp $*/ #ifndef _EM_H_DEFINED_ #define _EM_H_DEFINED_ @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -75,7 +76,6 @@ #include #include #include -#include "opt_bdg.h" #include @@ -164,14 +164,6 @@ */ #define EM_RADV 64 - -/* - * This parameter controls the maximum no of times the driver will loop - * in the isr. - * Minimum Value = 1 - */ -#define EM_MAX_INTR 3 - /* * Inform the stack about transmit checksum offload capabilities. */ @@ -290,7 +282,6 @@ bus_dma_tag_t dma_tag; bus_dmamap_t dma_map; bus_dma_segment_t dma_seg; - bus_size_t dma_size; int dma_nseg; }; @@ -323,8 +314,6 @@ /* Our adapter structure */ struct adapter { struct ifnet *ifp; - struct adapter *next; - struct adapter *prev; struct em_hw hw; /* FreeBSD operating-system-specific structures */ Index: if_em_hw.h =================================================================== RCS file: /home/ncvs/src/sys/dev/em/if_em_hw.h,v retrieving revision 1.15 retrieving revision 1.16 diff -u -r1.15 -r1.16 --- if_em_hw.h 26 May 2005 23:32:02 -0000 1.15 +++ if_em_hw.h 20 Oct 2005 08:46:43 -0000 1.16 @@ -31,7 +31,7 @@ *******************************************************************************/ -/*$FreeBSD: src/sys/dev/em/if_em_hw.h,v 1.15 2005/05/26 23:32:02 tackerman Exp $*/ +/*$FreeBSD: src/sys/dev/em/if_em_hw.h,v 1.16 2005/10/20 08:46:43 glebius Exp $*/ /* if_em_hw.h * Structures, enums, and macros for the MAC */ @@ -556,6 +556,7 @@ E1000_IMS_TXDW | \ E1000_IMS_RXDMT0 | \ E1000_IMS_RXSEQ | \ + E1000_IMS_RXO | \ E1000_IMS_LSC) --ZJcv+A0YCCLh2VIg--