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;