diff --git a/sys/dev/oce/oce_if.c b/sys/dev/oce/oce_if.c index 48f85e6..c295b80 100644 --- a/sys/dev/oce/oce_if.c +++ b/sys/dev/oce/oce_if.c @@ -142,6 +142,7 @@ static int oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index); static void oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq); static void oce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, uint32_t status); +static void oce_tx_clean(POCE_SOFTC sc); static int oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq); @@ -563,9 +564,6 @@ oce_multiq_start(struct ifnet *ifp, struct mbuf *m) int queue_index = 0; int status = 0; - if (!sc->link_status) - return ENXIO; - if ((m->m_flags & M_FLOWID) != 0) queue_index = m->m_pkthdr.flowid % sc->nwqs; @@ -588,8 +586,10 @@ oce_multiq_flush(struct ifnet *ifp) int i = 0; for (i = 0; i < sc->nwqs; i++) { + LOCK(&sc->wq[i]->tx_lock); while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL) m_freem(m); + UNLOCK(&sc->wq[i]->tx_lock); } if_qflush(ifp); } @@ -1055,6 +1055,19 @@ oce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, uint32_t status) } } +static void +oce_tx_clean(POCE_SOFTC sc) { + int i = 0; + struct oce_wq *wq; + + for_all_wq_queues(sc, wq, i) { + LOCK(&wq->tx_lock); + while (wq->pkt_desc_tail != wq->pkt_desc_head) { + oce_tx_complete(wq, 0, 0); + } + UNLOCK(&wq->tx_lock); + } +} static void oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq) @@ -1216,6 +1229,8 @@ oce_wq_handler(void *arg) struct oce_nic_tx_cqe *cqe; int num_cqes = 0; + LOCK(&wq->tx_lock); + bus_dmamap_sync(cq->ring->dma.tag, cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); @@ -1240,6 +1255,8 @@ oce_wq_handler(void *arg) if (num_cqes) oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); + UNLOCK(&wq->tx_lock); + return 0; } @@ -1274,7 +1291,6 @@ oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq) drbr_putback(ifp, br, next); wq->tx_stats.tx_stops ++; ifp->if_drv_flags |= IFF_DRV_OACTIVE; - status = drbr_enqueue(ifp, br, next); } break; } @@ -1285,7 +1301,7 @@ oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq) ETHER_BPF_MTAP(ifp, next); } - return status; + return 0; } @@ -2091,6 +2107,9 @@ oce_if_deactivate(POCE_SOFTC sc) /* Delete RX queue in card with flush param */ oce_stop_rx(sc); + /* Flush the mbufs that are still in TX queues */ + oce_tx_clean(sc); + /* Invalidate any pending cq and eq entries*/ for_all_evnt_queues(sc, eq, i) oce_drain_eq(eq); diff --git a/sys/dev/oce/oce_queue.c b/sys/dev/oce/oce_queue.c index 308c16d..161011b 100644 --- a/sys/dev/oce/oce_queue.c +++ b/sys/dev/oce/oce_queue.c @@ -969,7 +969,9 @@ oce_start_rq(struct oce_rq *rq) int oce_start_wq(struct oce_wq *wq) { + LOCK(&wq->tx_lock); /* XXX: maybe not necessary */ oce_arm_cq(wq->parent, wq->cq->cq_id, 0, TRUE); + UNLOCK(&wq->tx_lock); return 0; } @@ -1076,6 +1078,8 @@ oce_drain_wq_cq(struct oce_wq *wq) struct oce_nic_tx_cqe *cqe; int num_cqes = 0; + LOCK(&wq->tx_lock); /* XXX: maybe not necessary */ + bus_dmamap_sync(cq->ring->dma.tag, cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); @@ -1093,6 +1097,7 @@ oce_drain_wq_cq(struct oce_wq *wq) oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); + UNLOCK(&wq->tx_lock); }