This is a port of the em(4) IPL_MPSAFE changes made by kettenis@ to ix(4). Seems to work for me but don't expect any miracles.
Please test -- :wq Claudio Index: if_ix.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_ix.c,v retrieving revision 1.124 diff -u -p -r1.124 if_ix.c --- if_ix.c 2 Sep 2015 16:08:49 -0000 1.124 +++ if_ix.c 8 Sep 2015 16:36:21 -0000 @@ -210,6 +210,8 @@ ixgbe_attach(struct device *parent, stru sc->osdep.os_sc = sc; sc->osdep.os_pa = *pa; + mtx_init(&sc->rx_mtx, IPL_NET); + /* Set up the timer callout */ timeout_set(&sc->timer, ixgbe_local_timer, sc); timeout_set(&sc->rx_refill, ixgbe_rxrefill, sc); @@ -866,10 +868,29 @@ ixgbe_intr(void *arg) reg_eicr = IXGBE_READ_REG(&sc->hw, IXGBE_EICR); if (reg_eicr == 0) { + KERNEL_LOCK(); /* XXX SHOULD NOT BE NEEDED */ ixgbe_enable_intr(sc); + KERNEL_UNLOCK(); return (0); } + if (ifp->if_flags & IFF_RUNNING) { + ixgbe_rxeof(que); + ixgbe_txeof(txr); + refill = 1; + } + + KERNEL_LOCK(); + + if (refill) { + if (ixgbe_rxfill(que->rxr)) { + /* Advance the Rx Queue "Tail Pointer" */ + IXGBE_WRITE_REG(&sc->hw, IXGBE_RDT(que->rxr->me), + que->rxr->last_desc_filled); + } else + timeout_add(&sc->rx_refill, 1); + } + /* Link status change */ if (reg_eicr & IXGBE_EICR_LSC) ixgbe_update_link_status(sc); @@ -903,27 +924,14 @@ ixgbe_intr(void *arg) IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); } - if (ifp->if_flags & IFF_RUNNING) { - ixgbe_rxeof(que); - ixgbe_txeof(txr); - refill = 1; - } - - if (refill) { - if (ixgbe_rxfill(que->rxr)) { - /* Advance the Rx Queue "Tail Pointer" */ - IXGBE_WRITE_REG(&sc->hw, IXGBE_RDT(que->rxr->me), - que->rxr->last_desc_filled); - } else - timeout_add(&sc->rx_refill, 1); - } - if (ifp->if_flags & IFF_RUNNING && !IFQ_IS_EMPTY(&ifp->if_snd)) ixgbe_start(ifp); for (i = 0; i < sc->num_queues; i++, que++) ixgbe_enable_queue(sc, que->msix); + KERNEL_UNLOCK(); + return (1); } @@ -1449,7 +1457,7 @@ ixgbe_allocate_legacy(struct ix_softc *s #endif intrstr = pci_intr_string(pc, ih); - sc->tag = pci_intr_establish(pc, ih, IPL_NET, + sc->tag = pci_intr_establish(pc, ih, IPL_NET | IPL_MPSAFE, ixgbe_intr, sc, sc->dev.dv_xname); if (sc->tag == NULL) { printf(": couldn't establish interrupt"); @@ -2338,14 +2346,18 @@ ixgbe_txeof(struct tx_ring *txr) return FALSE; } + KERNEL_LOCK(); + processed = 0; first = txr->next_to_clean; tx_buffer = &txr->tx_buffers[first]; /* For cleanup we just use legacy struct */ tx_desc = (struct ixgbe_legacy_tx_desc *)&txr->tx_base[first]; last = tx_buffer->eop_index; - if (last == -1) + if (last == -1) { + KERNEL_UNLOCK(); return FALSE; + } eop_desc = (struct ixgbe_legacy_tx_desc *)&txr->tx_base[last]; /* @@ -2422,6 +2434,7 @@ ixgbe_txeof(struct tx_ring *txr) if (txr->tx_avail == sc->num_tx_desc) { ifp->if_timer = 0; txr->watchdog_timer = 0; + KERNEL_UNLOCK(); return FALSE; } /* Some were cleaned, so reset timer */ @@ -2431,6 +2444,8 @@ ixgbe_txeof(struct tx_ring *txr) } } + KERNEL_UNLOCK(); + return TRUE; } @@ -2580,6 +2595,8 @@ ixgbe_rxfill(struct rx_ring *rxr) u_int slots; int i; + mtx_enter(&sc->rx_mtx); + i = rxr->last_desc_filled; for (slots = if_rxr_get(&rxr->rx_ring, sc->num_rx_desc); slots > 0; slots--) { @@ -2595,6 +2612,8 @@ ixgbe_rxfill(struct rx_ring *rxr) if_rxr_put(&rxr->rx_ring, slots); + mtx_leave(&sc->rx_mtx); + return (post); } @@ -2762,8 +2781,10 @@ ixgbe_free_receive_structures(struct ix_ struct rx_ring *rxr = sc->rx_rings; int i; + mtx_enter(&sc->rx_mtx); for (i = 0; i < sc->num_queues; i++, rxr++) ixgbe_free_receive_buffers(rxr); + mtx_leave(&sc->rx_mtx); } /********************************************************************* @@ -2814,6 +2835,7 @@ ixgbe_rxeof(struct ix_queue *que) struct rx_ring *rxr = que->rxr; struct ifnet *ifp = &sc->arpcom.ac_if; struct mbuf_list ml = MBUF_LIST_INITIALIZER(); + struct mbuf_list free_ml = MBUF_LIST_INITIALIZER(); struct mbuf *mp, *sendmp; uint8_t eop = 0; uint16_t len, vtag; @@ -2826,6 +2848,7 @@ ixgbe_rxeof(struct ix_queue *que) if (!ISSET(ifp->if_flags, IFF_RUNNING)) return FALSE; + mtx_enter(&sc->rx_mtx); i = rxr->next_to_check; while (if_rxr_inuse(&rxr->rx_ring) > 0) { bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, @@ -2860,11 +2883,11 @@ ixgbe_rxeof(struct ix_queue *que) sc->dropped_pkts++; if (rxbuf->fmp) { - m_freem(rxbuf->fmp); + ml_enqueue(&free_ml, rxbuf->fmp); rxbuf->fmp = NULL; } - m_freem(mp); + ml_enqueue(&free_ml, mp); rxbuf->buf = NULL; goto next_desc; } @@ -2942,6 +2965,10 @@ next_desc: i = 0; } rxr->next_to_check = i; + mtx_leave(&sc->rx_mtx); + + while ((mp = ml_dequeue(&free_ml))) + m_freem(mp); if_input(ifp, &ml); Index: if_ix.h =================================================================== RCS file: /cvs/src/sys/dev/pci/if_ix.h,v retrieving revision 1.27 diff -u -p -r1.27 if_ix.h --- if_ix.h 12 Nov 2014 16:06:47 -0000 1.27 +++ if_ix.h 31 Aug 2015 20:09:32 -0000 @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ix.h,v 1.27 2014/11/12 16:06:47 mikeb Exp $ */ +/* $OpenBSD: if_ix.h,v 1.26 2014/11/10 15:58:32 mikeb Exp $ */ /****************************************************************************** @@ -277,6 +277,7 @@ struct ix_softc { * Receive rings: * Allocated at run time, an array of rings. */ + struct mutex rx_mtx; struct rx_ring *rx_rings; uint64_t que_mask; int num_rx_desc;