iflib(4): Replace admin taskqueue group with per-interface taskqueues

Using one taskqueue group with single thread to execute all admin
tasks may lead to unexpected timeouts when long running task (e.g.
handling a reset after FW update) for one interface prevents
tasks from other interfaces being executed. Taskqueue group API
doesn't let to dynamically add threads, and pre-allocating thread
for each CPU as it's done for traffic queues would be a waste
of resources on systems with small number of interfaces. Replace
global taskqueue group for admin tasks with taskqueue allocated
for each interface to allow independent execution.

Signed-off-by: Krzysztof Galazka <krzysztof.galazka@intel.com>
Reviewed by: imp, jhb
Pull Request: https://github.com/freebsd/freebsd-src/pull/1336
(cherry picked from commit 3ad01642fe9e241124553f2f18fd365ffea5d20b)
This commit is contained in:
Krzysztof Galazka 2024-07-05 13:00:13 +02:00 committed by Warner Losh
parent 54f842ed88
commit 7313d4a3dc
4 changed files with 48 additions and 47 deletions

View file

@ -1091,7 +1091,7 @@ struct bnxt_softc {
struct bnxt_cp_ring def_nq_ring;
struct iflib_dma_info def_cp_ring_mem;
struct iflib_dma_info def_nq_ring_mem;
struct grouptask def_cp_task;
struct task def_cp_task;
int db_size;
int legacy_db_size;
struct bnxt_doorbell_ops db_ops;

View file

@ -230,7 +230,7 @@ static void bnxt_clear_ids(struct bnxt_softc *softc);
static void inline bnxt_do_enable_intr(struct bnxt_cp_ring *cpr);
static void inline bnxt_do_disable_intr(struct bnxt_cp_ring *cpr);
static void bnxt_mark_cpr_invalid(struct bnxt_cp_ring *cpr);
static void bnxt_def_cp_task(void *context);
static void bnxt_def_cp_task(void *context, int pending);
static void bnxt_handle_async_event(struct bnxt_softc *softc,
struct cmpl_base *cmpl);
static uint64_t bnxt_get_baudrate(struct bnxt_link_info *link);
@ -2385,8 +2385,7 @@ bnxt_attach_pre(if_ctx_t ctx)
&softc->def_cp_ring_mem, 0);
softc->def_cp_ring.ring.vaddr = softc->def_cp_ring_mem.idi_vaddr;
softc->def_cp_ring.ring.paddr = softc->def_cp_ring_mem.idi_paddr;
iflib_config_gtask_init(ctx, &softc->def_cp_task, bnxt_def_cp_task,
"dflt_cp");
iflib_config_task_init(ctx, &softc->def_cp_task, bnxt_def_cp_task);
rc = bnxt_init_sysctl_ctx(softc);
if (rc)
@ -2513,7 +2512,6 @@ bnxt_detach(if_ctx_t ctx)
bnxt_free_ctx_mem(softc);
bnxt_clear_ids(softc);
iflib_irq_free(ctx, &softc->def_cp_ring.irq);
iflib_config_gtask_deinit(&softc->def_cp_task);
/* We need to free() these here... */
for (i = softc->nrxqsets-1; i>=0; i--) {
if (BNXT_CHIP_P5(softc))
@ -4349,7 +4347,7 @@ bnxt_handle_def_cp(void *arg)
struct bnxt_softc *softc = arg;
softc->db_ops.bnxt_db_rx_cq(&softc->def_cp_ring, 0);
GROUPTASK_ENQUEUE(&softc->def_cp_task);
iflib_config_task_enqueue(softc->ctx, &softc->def_cp_task);
return FILTER_HANDLED;
}
@ -4609,7 +4607,7 @@ async_event_process_exit:
}
static void
bnxt_def_cp_task(void *context)
bnxt_def_cp_task(void *context, int pending)
{
if_ctx_t ctx = context;
struct bnxt_softc *softc = iflib_get_softc(ctx);

View file

@ -178,8 +178,9 @@ struct iflib_ctx {
struct resource *ifc_msix_mem;
struct if_irq ifc_legacy_irq;
struct grouptask ifc_admin_task;
struct grouptask ifc_vflr_task;
struct task ifc_admin_task;
struct task ifc_vflr_task;
struct taskqueue *ifc_tq;
struct iflib_filter_info ifc_filter_info;
struct ifmedia ifc_media;
struct ifmedia *ifc_mediap;
@ -1640,7 +1641,7 @@ static int
iflib_fast_intr_ctx(void *arg)
{
iflib_filter_info_t info = arg;
struct grouptask *gtask = info->ifi_task;
if_ctx_t ctx = info->ifi_ctx;
int result;
DBG_COUNTER_INC(fast_intrs);
@ -1650,8 +1651,7 @@ iflib_fast_intr_ctx(void *arg)
return (result);
}
if (gtask->gt_taskqueue != NULL)
GROUPTASK_ENQUEUE(gtask);
taskqueue_enqueue(ctx->ifc_tq, &ctx->ifc_admin_task);
return (FILTER_HANDLED);
}
@ -4176,7 +4176,7 @@ skip_rxeof:
}
static void
_task_fn_admin(void *context)
_task_fn_admin(void *context, int pending)
{
if_ctx_t ctx = context;
if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
@ -4227,7 +4227,7 @@ _task_fn_admin(void *context)
}
static void
_task_fn_iov(void *context)
_task_fn_iov(void *context, int pending)
{
if_ctx_t ctx = context;
@ -5200,6 +5200,7 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct
kobj_method_t *kobj_method;
int err, msix, rid;
int num_txd, num_rxd;
char namebuf[TASKQUEUE_NAMELEN];
ctx = malloc(sizeof(*ctx), M_IFLIB, M_WAITOK | M_ZERO);
@ -5290,10 +5291,25 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct
scctx->isc_rss_table_size = 64;
scctx->isc_rss_table_mask = scctx->isc_rss_table_size - 1;
GROUPTASK_INIT(&ctx->ifc_admin_task, 0, _task_fn_admin, ctx);
/* XXX format name */
taskqgroup_attach(qgroup_if_config_tqg, &ctx->ifc_admin_task, ctx,
NULL, NULL, "admin");
/* Create and start admin taskqueue */
snprintf(namebuf, TASKQUEUE_NAMELEN, "if_%s_tq", device_get_nameunit(dev));
ctx->ifc_tq = taskqueue_create_fast(namebuf, M_NOWAIT,
taskqueue_thread_enqueue, &ctx->ifc_tq);
if (ctx->ifc_tq == NULL) {
device_printf(dev, "Unable to create admin taskqueue\n");
return (ENOMEM);
}
err = taskqueue_start_threads(&ctx->ifc_tq, 1, PI_NET, "%s", namebuf);
if (err) {
device_printf(dev,
"Unable to start admin taskqueue threads error: %d\n",
err);
taskqueue_free(ctx->ifc_tq);
return (err);
}
TASK_INIT(&ctx->ifc_admin_task, 0, _task_fn_admin, ctx);
/* Set up cpu set. If it fails, use the set of all CPUs. */
if (bus_get_cpus(dev, INTR_CPUS, sizeof(ctx->ifc_cpus), &ctx->ifc_cpus) != 0) {
@ -5430,6 +5446,7 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct
fail_detach:
ether_ifdetach(ctx->ifc_ifp);
fail_queues:
taskqueue_free(ctx->ifc_tq);
iflib_tqg_detach(ctx);
iflib_tx_structures_free(ctx);
iflib_rx_structures_free(ctx);
@ -5508,6 +5525,9 @@ iflib_device_deregister(if_ctx_t ctx)
IFDI_QUEUES_FREE(ctx);
CTX_UNLOCK(ctx);
taskqueue_free(ctx->ifc_tq);
ctx->ifc_tq = NULL;
/* ether_ifdetach calls if_qflush - lock must be destroy afterwards*/
iflib_free_intr_mem(ctx);
@ -5545,11 +5565,6 @@ iflib_tqg_detach(if_ctx_t ctx)
if (rxq->ifr_task.gt_uniq != NULL)
taskqgroup_detach(tqg, &rxq->ifr_task);
}
tqg = qgroup_if_config_tqg;
if (ctx->ifc_admin_task.gt_uniq != NULL)
taskqgroup_detach(tqg, &ctx->ifc_admin_task);
if (ctx->ifc_vflr_task.gt_uniq != NULL)
taskqgroup_detach(tqg, &ctx->ifc_vflr_task);
}
static void
@ -6324,9 +6339,7 @@ iflib_irq_alloc_generic(if_ctx_t ctx, if_irq_t irq, int rid,
q = ctx;
tqrid = -1;
info = &ctx->ifc_filter_info;
gtask = &ctx->ifc_admin_task;
tqg = qgroup_if_config_tqg;
fn = _task_fn_admin;
gtask = NULL;
intr_fast = iflib_fast_intr_ctx;
break;
default:
@ -6388,12 +6401,8 @@ iflib_softirq_alloc_generic(if_ctx_t ctx, if_irq_t irq, iflib_intr_type_t type,
NET_GROUPTASK_INIT(gtask, 0, fn, q);
break;
case IFLIB_INTR_IOV:
q = ctx;
gtask = &ctx->ifc_vflr_task;
tqg = qgroup_if_config_tqg;
fn = _task_fn_iov;
GROUPTASK_INIT(gtask, 0, fn, q);
break;
TASK_INIT(&ctx->ifc_vflr_task, 0, _task_fn_iov, ctx);
return;
default:
panic("unknown net intr type");
}
@ -6483,15 +6492,14 @@ void
iflib_admin_intr_deferred(if_ctx_t ctx)
{
MPASS(ctx->ifc_admin_task.gt_taskqueue != NULL);
GROUPTASK_ENQUEUE(&ctx->ifc_admin_task);
taskqueue_enqueue(ctx->ifc_tq, &ctx->ifc_admin_task);
}
void
iflib_iov_intr_deferred(if_ctx_t ctx)
{
GROUPTASK_ENQUEUE(&ctx->ifc_vflr_task);
taskqueue_enqueue(ctx->ifc_tq, &ctx->ifc_vflr_task);
}
void
@ -6503,20 +6511,15 @@ iflib_io_tqg_attach(struct grouptask *gt, void *uniq, int cpu, const char *name)
}
void
iflib_config_gtask_init(void *ctx, struct grouptask *gtask, gtask_fn_t *fn,
const char *name)
iflib_config_task_init(if_ctx_t ctx, struct task *config_task, task_fn_t *fn)
{
GROUPTASK_INIT(gtask, 0, fn, ctx);
taskqgroup_attach(qgroup_if_config_tqg, gtask, gtask, NULL, NULL,
name);
TASK_INIT(config_task, 0, fn, ctx);
}
void
iflib_config_gtask_deinit(struct grouptask *gtask)
iflib_config_task_enqueue(if_ctx_t ctx, struct task *config_task)
{
taskqgroup_detach(qgroup_if_config_tqg, gtask);
taskqueue_enqueue(ctx->ifc_tq, config_task);
}
void

View file

@ -470,9 +470,9 @@ void iflib_irq_free(if_ctx_t ctx, if_irq_t irq);
void iflib_io_tqg_attach(struct grouptask *gt, void *uniq, int cpu,
const char *name);
void iflib_config_gtask_init(void *ctx, struct grouptask *gtask,
gtask_fn_t *fn, const char *name);
void iflib_config_gtask_deinit(struct grouptask *gtask);
void iflib_config_task_init(if_ctx_t ctx, struct task *config_task,
task_fn_t *fn);
void iflib_config_task_enqueue(if_ctx_t ctx, struct task *config_task);
void iflib_tx_intr_deferred(if_ctx_t ctx, int txqid);
void iflib_rx_intr_deferred(if_ctx_t ctx, int rxqid);