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;