Index: if_bce.c =================================================================== --- if_bce.c (revision 248085) +++ if_bce.c (working copy) @@ -5847,6 +5847,9 @@ bce_init_rx_chain(struct bce_softc *sc) DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_LOAD | BCE_VERBOSE_CTX); + /* Signal bce_rx_intr() it has to stop processing descriptors. */ + atomic_set_acq_int(&sc->rx_intr, 0); + /* Initialize the RX producer and consumer indices. */ sc->rx_prod = 0; sc->rx_cons = 0; @@ -5959,6 +5962,9 @@ bce_free_rx_chain(struct bce_softc *sc) DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_UNLOAD); + /* Signal bce_rx_intr() it has to stop processing descriptors. */ + atomic_set_acq_int(&sc->rx_intr, 0); + /* Free any mbufs still in the RX mbuf chain. */ for (i = 0; i < MAX_RX_BD_AVAIL; i++) { if (sc->rx_mbuf_ptr[i] != NULL) { @@ -6578,6 +6584,8 @@ bce_rx_intr(struct bce_softc *sc) "rx_cons = 0x%04X, rx_prod_bseq = 0x%08X\n", __FUNCTION__, sc->rx_prod, sc->rx_cons, sc->rx_prod_bseq); + atomic_set_acq_int(&sc->rx_intr, 1); + /* Prepare the RX chain pages to be accessed by the host CPU. */ for (int i = 0; i < sc->rx_pages; i++) bus_dmamap_sync(sc->rx_bd_chain_tag, @@ -6832,7 +6840,8 @@ bce_rx_intr(struct bce_softc *sc) } /* Attach the VLAN tag. */ - if (status & L2_FHDR_STATUS_L2_VLAN_TAG) { + if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && + !(sc->rx_mode & BCE_EMAC_RX_MODE_KEEP_VLAN_TAG)) { DBRUN(sc->vlan_tagged_frames_rcvd++); if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) { DBRUN(sc->vlan_tagged_frames_stripped++); @@ -6876,17 +6885,17 @@ bce_rx_int_next_rx: /* If we have a packet, pass it up the stack */ if (m0) { - /* Make sure we don't lose our place when we release the lock. */ - sc->rx_cons = sw_rx_cons; - sc->pg_cons = sw_pg_cons; - BCE_UNLOCK(sc); (*ifp->if_input)(ifp, m0); BCE_LOCK(sc); - /* Recover our place. */ - sw_rx_cons = sc->rx_cons; - sw_pg_cons = sc->pg_cons; + /* + * In case the interface was re-initialized or stopped + * while we had dropped the lock, we must stop here in + * order to not corrupt the consumer indices. + */ + if (sc->rx_intr == 0) + goto bce_rx_intr_exit; } /* Refresh hw_cons to see if there's new work */ @@ -6915,6 +6924,9 @@ bce_rx_int_next_rx: sc->pg_bd_chain_map[i], BUS_DMASYNC_PREWRITE); } + atomic_set_rel_int(&sc->rx_intr, 0); + +bce_rx_intr_exit: DBPRINT(sc, BCE_EXTREME_RECV, "%s(exit): rx_prod = 0x%04X, " "rx_cons = 0x%04X, rx_prod_bseq = 0x%08X\n", __FUNCTION__, sc->rx_prod, sc->rx_cons, sc->rx_prod_bseq); @@ -8492,13 +8504,14 @@ bce_tick(void *xsc) bce_stats_update(sc); /* - * ToDo: This is a safety measure. Need to re-evaluate - * high level processing logic and eliminate this code. - */ - /* Top off the receive and page chains. */ - if (bce_hdr_split == TRUE) - bce_fill_pg_chain(sc); - bce_fill_rx_chain(sc); + * Ensure the page and RX chains get refilled in low-memory situations + * but only if bce_rx_intr() isn't fiddling with the consumer indices. + */ + if (sc->rx_intr == 0) { + if (bce_hdr_split == TRUE) + bce_fill_pg_chain(sc); + bce_fill_rx_chain(sc); + } /* Check that chip hasn't hung. */ bce_watchdog(sc); Index: if_bcereg.h =================================================================== --- if_bcereg.h (revision 248078) +++ if_bcereg.h (working copy) @@ -66,6 +66,7 @@ #include #include +#include #include #include #include @@ -6578,6 +6579,9 @@ struct bce_softc /* The device handle for the MII bus child device. */ device_t bce_miibus; + /* RX interrupt in progress */ + volatile int rx_intr; + /* Driver maintained RX chain pointers and byte counter. */ u16 rx_prod; u16 rx_cons;