From owner-svn-soc-all@freebsd.org Tue Aug 18 08:35:39 2015 Return-Path: Delivered-To: svn-soc-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id B33D49BB4D5 for ; Tue, 18 Aug 2015 08:35:39 +0000 (UTC) (envelope-from iateaca@FreeBSD.org) Received: from socsvn.freebsd.org (socsvn.freebsd.org [IPv6:2001:1900:2254:206a::50:2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id A2EEE1604 for ; Tue, 18 Aug 2015 08:35:39 +0000 (UTC) (envelope-from iateaca@FreeBSD.org) Received: from socsvn.freebsd.org ([127.0.1.124]) by socsvn.freebsd.org (8.15.2/8.15.2) with ESMTP id t7I8ZdBc080903 for ; Tue, 18 Aug 2015 08:35:39 GMT (envelope-from iateaca@FreeBSD.org) Received: (from www@localhost) by socsvn.freebsd.org (8.15.2/8.15.2/Submit) id t7I8ZdZX080841 for svn-soc-all@FreeBSD.org; Tue, 18 Aug 2015 08:35:39 GMT (envelope-from iateaca@FreeBSD.org) Date: Tue, 18 Aug 2015 08:35:39 GMT Message-Id: <201508180835.t7I8ZdZX080841@socsvn.freebsd.org> X-Authentication-Warning: socsvn.freebsd.org: www set sender to iateaca@FreeBSD.org using -f From: iateaca@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r289857 - soc2015/iateaca/bhyve-ne2000-head/usr.sbin/bhyve MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 18 Aug 2015 08:35:39 -0000 Author: iateaca Date: Tue Aug 18 08:35:38 2015 New Revision: 289857 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=289857 Log: implement the software reset workaround, and the software reset routine Modified: soc2015/iateaca/bhyve-ne2000-head/usr.sbin/bhyve/pci_ne2000.c Modified: soc2015/iateaca/bhyve-ne2000-head/usr.sbin/bhyve/pci_ne2000.c ============================================================================== --- soc2015/iateaca/bhyve-ne2000-head/usr.sbin/bhyve/pci_ne2000.c Tue Aug 18 06:28:37 2015 (r289856) +++ soc2015/iateaca/bhyve-ne2000-head/usr.sbin/bhyve/pci_ne2000.c Tue Aug 18 08:35:38 2015 (r289857) @@ -286,13 +286,18 @@ /* clear the Receiver Status Register */ ne2000_set_reg_by_offset(sc, NE2000_P0_RO, ED_P0_RSR, 0x00); + if (!ne2000_receive_ring_is_valid(sc)) { + DPRINTF("Drop the packet: the ring is not valid"); + return 0; + } + if (!ne2000_ether_frame_is_valid(sc)) { - DPRINTF("Drop the packet since the ether frame did not match"); + DPRINTF("Drop the packet: the ether frame did not match"); return 0; } if (ne2000_receive_ring_is_full(sc)) { - DPRINTF("Drop the packet since the ring is full"); + DPRINTF("Drop the packet: the ring is full"); return 0; } @@ -367,12 +372,20 @@ static int ne2000_receive_ring_is_valid(struct pci_ne2000_softc *sc) { + uint8_t cr = 0; + uint8_t pstart = 0; uint8_t pstop = 0; uint8_t curr = 0; uint8_t bnry = 0; + cr = ne2000_get_reg_by_offset(sc, NE2000_P0, ED_P0_CR); + if (cr & ED_CR_STP) { + DPRINTF("Ring is not valid: the NIC is Stopped"); + return 0; + } + pstart = ne2000_get_reg_by_offset(sc, NE2000_P0, ED_P0_PSTART); pstop = ne2000_get_reg_by_offset(sc, NE2000_P0, ED_P0_PSTOP); @@ -772,6 +785,8 @@ uint16_t tbcr = 0; uint8_t tpsr = 0; + uint8_t old_cr = 0; + /* check is not selected a new page */ switch (value & (ED_CR_PS0 | ED_CR_PS1)) { case ED_CR_PAGE_0: @@ -789,10 +804,14 @@ break; } + old_cr = ne2000_get_reg_by_offset(sc, NE2000_P0, ED_P0_CR); + /* emulate any command specified in the CR register */ - if (value & ED_CR_STP) { - err = ne2000_software_reset(sc); - assert(err == 0); + if (value & ED_CR_STA) { + if ((old_cr & ED_CR_STA) == 0) { + ne2000_set_field_by_offset(sc, NE2000_P0, ED_P0_ISR, + ED_ISR_RST, 0); + } } if (value & ED_CR_RD2) assert(!(sc->remote_read || sc->remote_write)); @@ -910,6 +929,18 @@ static int ne2000_software_reset(struct pci_ne2000_softc *sc) { + DPRINTF("The NIC is in Software Reset State"); + + /* reset the Receive Ring Registers */ + ne2000_set_reg_by_offset(sc, NE2000_P0, ED_P0_PSTART, 0); + ne2000_set_reg_by_offset(sc, NE2000_P0, ED_P0_PSTOP, 0); + ne2000_set_reg_by_offset(sc, NE2000_P1, ED_P1_CURR, 0); + ne2000_set_reg_by_offset(sc, NE2000_P0, ED_P0_BNRY, 0); + + /* disable the interrupts */ + ne2000_set_reg_by_offset(sc, NE2000_P0, ED_P0_IMR, 0); + + /* the NIC enters the reset state */ ne2000_set_field_by_offset(sc, NE2000_P0, ED_P0_ISR, ED_ISR_RST, ED_ISR_RST); @@ -952,7 +983,9 @@ static uint8_t ne2000_read_nic(struct pci_ne2000_softc *sc, uint8_t offset) { + int err; uint8_t value = 0; + uint8_t cr = 0; /* * check is either a RTL8029 Register Defined in Page0 @@ -980,6 +1013,21 @@ /* read a read-only register from page 0 */ value = ne2000_get_reg_by_offset(sc, NE2000_P0_RO, offset); break; + case ED_P0_ISR: + /* + * Software Reset Workaround: the NIC enters the reset state + * in about 5us after the STP bit was set. Because of this + * we don't reset it every time the STP bit is set, but only + * when the ED driver polls the ISR register looking for + * the RST bit. + */ + cr = ne2000_get_reg_by_offset(sc, NE2000_P0, ED_P0_CR); + if (cr & ED_CR_STP) { + err = ne2000_software_reset(sc); + assert(err == 0); + } + value = ne2000_get_reg_by_offset(sc, NE2000_P0, ED_P0_ISR); + break; default: value = ne2000_get_reg_by_offset(sc, NE2000_P0, offset); break;