socsvn commit: r289857 - soc2015/iateaca/bhyve-ne2000-head/usr.sbin/bhyve
iateaca at FreeBSD.org
iateaca at FreeBSD.org
Tue Aug 18 08:35:39 UTC 2015
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;
More information about the svn-soc-all
mailing list