Module Name:    src
Committed By:   jmcneill
Date:           Fri Nov 30 11:37:11 UTC 2018

Modified Files:
        src/sys/dev/pci: if_ena.c

Log Message:
workqueue and callout fixes


To generate a diff of this commit:
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/pci/if_ena.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/if_ena.c
diff -u src/sys/dev/pci/if_ena.c:1.9 src/sys/dev/pci/if_ena.c:1.10
--- src/sys/dev/pci/if_ena.c:1.9	Wed Nov 28 21:31:32 2018
+++ src/sys/dev/pci/if_ena.c	Fri Nov 30 11:37:11 2018
@@ -31,7 +31,7 @@
 #if 0
 __FBSDID("$FreeBSD: head/sys/dev/ena/ena.c 333456 2018-05-10 09:37:54Z mw $");
 #endif
-__KERNEL_RCSID(0, "$NetBSD: if_ena.c,v 1.9 2018/11/28 21:31:32 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ena.c,v 1.10 2018/11/30 11:37:11 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -641,9 +641,9 @@ ena_setup_tx_resources(struct ena_adapte
 	}
 
 	/* Allocate workqueues */
-	int rc = workqueue_create(&tx_ring->enqueue_tq, "ena_tx_enque",
-	    ena_deferred_mq_start, tx_ring, 0, IPL_NET, 0);
-	if (unlikely(rc == 0)) {
+	int rc = workqueue_create(&tx_ring->enqueue_tq, "ena_tx_enq",
+	    ena_deferred_mq_start, tx_ring, 0, IPL_NET, WQ_PERCPU | WQ_MPSAFE);
+	if (unlikely(rc != 0)) {
 		ena_trace(ENA_ALERT,
 		    "Unable to create workqueue for enqueue task\n");
 		i = tx_ring->ring_size;
@@ -848,8 +848,8 @@ ena_setup_rx_resources(struct ena_adapte
 #endif
 
 	/* Allocate workqueues */
-	int rc = workqueue_create(&rx_ring->cmpl_tq, "ena RX completion",
-	    ena_deferred_rx_cleanup, rx_ring, 0, IPL_NET, 0);
+	int rc = workqueue_create(&rx_ring->cmpl_tq, "ena_rx_comp",
+	    ena_deferred_rx_cleanup, rx_ring, 0, IPL_NET, WQ_PERCPU | WQ_MPSAFE);
 	if (unlikely(rc != 0)) {
 		ena_trace(ENA_ALERT,
 		    "Unable to create workqueue for RX completion task\n");
@@ -1422,7 +1422,8 @@ ena_tx_cleanup(struct ena_ring *tx_ring)
 		ena_com_update_dev_comp_head(io_cq);
 	}
 
-	workqueue_enqueue(tx_ring->enqueue_tq, &tx_ring->enqueue_task, NULL);
+	if (atomic_cas_uint(&tx_ring->task_pending, 0, 1) == 0)
+		workqueue_enqueue(tx_ring->enqueue_tq, &tx_ring->enqueue_task, NULL);
 
 	return (work_done);
 }
@@ -1638,6 +1639,8 @@ ena_deferred_rx_cleanup(struct work *wk,
 	struct ena_ring *rx_ring = arg;
 	int budget = CLEAN_BUDGET;
 
+	atomic_swap_uint(&rx_ring->task_pending, 0);
+
 	ENA_RING_MTX_LOCK(rx_ring);
 	/*
 	 * If deferred task was executed, perform cleanup of all awaiting
@@ -2913,6 +2916,8 @@ ena_deferred_mq_start(struct work *wk, v
 	struct ena_ring *tx_ring = (struct ena_ring *)arg;
 	struct ifnet *ifp = tx_ring->adapter->ifp;
 
+	atomic_swap_uint(&tx_ring->task_pending, 0);
+
 	while (!drbr_empty(ifp, tx_ring->br) &&
 	    (if_getdrvflags(ifp) & IFF_RUNNING) != 0) {
 		ENA_RING_MTX_LOCK(tx_ring);
@@ -2962,8 +2967,9 @@ ena_mq_start(struct ifnet *ifp, struct m
 	is_drbr_empty = drbr_empty(ifp, tx_ring->br);
 	ret = drbr_enqueue(ifp, tx_ring->br, m);
 	if (unlikely(ret != 0)) {
-		workqueue_enqueue(tx_ring->enqueue_tq, &tx_ring->enqueue_task,
-		    curcpu());
+		if (atomic_cas_uint(&tx_ring->task_pending, 0, 1) == 0)
+			workqueue_enqueue(tx_ring->enqueue_tq, &tx_ring->enqueue_task,
+			    curcpu());
 		return (ret);
 	}
 
@@ -2971,8 +2977,9 @@ ena_mq_start(struct ifnet *ifp, struct m
 		ena_start_xmit(tx_ring);
 		ENA_RING_MTX_UNLOCK(tx_ring);
 	} else {
-		workqueue_enqueue(tx_ring->enqueue_tq, &tx_ring->enqueue_task,
-		    curcpu());
+		if (atomic_cas_uint(&tx_ring->task_pending, 0, 1) == 0)
+			workqueue_enqueue(tx_ring->enqueue_tq, &tx_ring->enqueue_task,
+			    curcpu());
 	}
 
 	return (0);
@@ -3494,8 +3501,9 @@ check_for_empty_rx_ring(struct ena_adapt
 				device_printf(adapter->pdev,
 				    "trigger refill for ring %d\n", i);
 
-				workqueue_enqueue(rx_ring->cmpl_tq,
-				    &rx_ring->cmpl_task, curcpu());
+				if (atomic_cas_uint(&rx_ring->task_pending, 0, 1) == 0)
+					workqueue_enqueue(rx_ring->cmpl_tq,
+					    &rx_ring->cmpl_task, curcpu());
 				rx_ring->empty_rx_queue = 0;
 			}
 		} else {
@@ -3765,9 +3773,11 @@ ena_attach(device_t parent, device_t sel
 		goto err_ifp_free;
 	}
 
+	callout_init(&adapter->timer_service, CALLOUT_MPSAFE);
+
 	/* Initialize reset task queue */
-	rc = workqueue_create(&adapter->reset_tq, "ena_reset_enqueue",
-	    ena_reset_task, adapter, 0, IPL_NET, 0);
+	rc = workqueue_create(&adapter->reset_tq, "ena_reset_enq",
+	    ena_reset_task, adapter, 0, IPL_NET, WQ_PERCPU | WQ_MPSAFE);
 	if (unlikely(rc != 0)) {
 		ena_trace(ENA_ALERT,
 		    "Unable to create workqueue for reset task\n");
@@ -3831,6 +3841,7 @@ ena_detach(device_t pdev, int flags)
 
 	/* Free reset task and callout */
 	callout_halt(&adapter->timer_service, &adapter->global_mtx);
+	callout_destroy(&adapter->timer_service);
 	workqueue_wait(adapter->reset_tq, &adapter->reset_task);
 	workqueue_destroy(adapter->reset_tq);
 	adapter->reset_tq = NULL;

Reply via email to