Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 18 Aug 2015 08:35:39 GMT
From:      iateaca@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r289857 - soc2015/iateaca/bhyve-ne2000-head/usr.sbin/bhyve
Message-ID:  <201508180835.t7I8ZdZX080841@socsvn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201508180835.t7I8ZdZX080841>