From owner-svn-src-head@FreeBSD.ORG Mon Oct 11 23:07:13 2010 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5B09B106564A; Mon, 11 Oct 2010 23:07:13 +0000 (UTC) (envelope-from yongari@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 2E4598FC08; Mon, 11 Oct 2010 23:07:13 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o9BN7DSG030566; Mon, 11 Oct 2010 23:07:13 GMT (envelope-from yongari@svn.freebsd.org) Received: (from yongari@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o9BN7DL4030564; Mon, 11 Oct 2010 23:07:13 GMT (envelope-from yongari@svn.freebsd.org) Message-Id: <201010112307.o9BN7DL4030564@svn.freebsd.org> From: Pyun YongHyeon Date: Mon, 11 Oct 2010 23:07:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r213711 - head/sys/dev/bge X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Oct 2010 23:07:13 -0000 Author: yongari Date: Mon Oct 11 23:07:12 2010 New Revision: 213711 URL: http://svn.freebsd.org/changeset/base/213711 Log: The IFF_DRV_RUNNING flag is set at the end of bge_init_locked. But before setting the flag, interrupt was already enabled such that interrupt handler could be run before setting IFF_DRV_RUNNING flag. This can lose initial link state change interrupt which in turn make bge(4) think that it still does not have valid link. Fix this race by protecting the taskqueue with a driver lock. While I'm here move reenabling interrupt code after handling of link state chage. Reviewed by: davidch Modified: head/sys/dev/bge/if_bge.c Modified: head/sys/dev/bge/if_bge.c ============================================================================== --- head/sys/dev/bge/if_bge.c Mon Oct 11 22:56:23 2010 (r213710) +++ head/sys/dev/bge/if_bge.c Mon Oct 11 23:07:12 2010 (r213711) @@ -3629,8 +3629,11 @@ bge_intr_task(void *arg, int pending) sc = (struct bge_softc *)arg; ifp = sc->bge_ifp; - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + BGE_LOCK(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + BGE_UNLOCK(sc); return; + } /* Get updated status block. */ bus_dmamap_sync(sc->bge_cdata.bge_status_tag, @@ -3645,26 +3648,27 @@ bge_intr_task(void *arg, int pending) bus_dmamap_sync(sc->bge_cdata.bge_status_tag, sc->bge_cdata.bge_status_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + if ((status & BGE_STATFLAG_LINKSTATE_CHANGED) != 0) + bge_link_upd(sc); + /* Let controller work. */ bge_writembx(sc, BGE_MBX_IRQ0_LO, 0); - if ((status & BGE_STATFLAG_LINKSTATE_CHANGED) != 0) { - BGE_LOCK(sc); - bge_link_upd(sc); - BGE_UNLOCK(sc); - } - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + if (ifp->if_drv_flags & IFF_DRV_RUNNING && + sc->bge_rx_saved_considx != rx_prod) { /* Check RX return ring producer/consumer. */ + BGE_UNLOCK(sc); bge_rxeof(sc, rx_prod, 0); + BGE_LOCK(sc); } if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - BGE_LOCK(sc); /* Check TX ring producer/consumer. */ bge_txeof(sc, tx_cons); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) bge_start_locked(ifp); - BGE_UNLOCK(sc); } + BGE_UNLOCK(sc); } static void