From b9110d86fa4ff96f3a7ecee0729f111149acc805 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Fri, 10 Jul 2026 16:14:32 +0900 Subject: [PATCH] gpu: host1x: Add option for disabling context stealing Add kernel module parameter to allow disabling context stealing in cases where reliability and consistency is preferred. Signed-off-by: Mikko Perttunen Signed-off-by: Thierry Reding Link: https://patch.msgid.link/20260710-b4-host1x-ctxsteal-v1-2-b1f8f6b37cc5@nvidia.com --- drivers/gpu/host1x/context.c | 62 +++++++++++++++++++++++++++--------- include/linux/host1x.h | 1 + 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/host1x/context.c b/drivers/gpu/host1x/context.c index 776bd4fbb554..c2c8a9bb5896 100644 --- a/drivers/gpu/host1x/context.c +++ b/drivers/gpu/host1x/context.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,10 @@ #include "context.h" #include "dev.h" +static bool static_context_alloc; +module_param(static_context_alloc, bool, 0644); +MODULE_PARM_DESC(static_context_alloc, "If enabled, memory contexts are allocated immediately on channel open and cannot be relinquished while a channel is open"); + static void host1x_memory_context_release(struct device *dev) { /* context device is freed in host1x_memory_context_list_free() */ @@ -168,7 +173,7 @@ host1x_memory_context_alloc_hw_locked(struct host1x *host1x, struct device *dev, /* Steal */ - if (!can_steal) + if (!can_steal || static_context_alloc) return ERR_PTR(-EBUSY); list_for_each_entry(ctx, &can_steal->owners, entry) { @@ -222,6 +227,7 @@ struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x, { struct host1x_memory_context_list *cdl = &host1x->context_list; struct host1x_memory_context *ctx; + int err; if (!cdl->len) return ERR_PTR(-EOPNOTSUPP); @@ -237,6 +243,17 @@ struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x, refcount_set(&ctx->ref, 1); INIT_LIST_HEAD(&ctx->mappings); + if (static_context_alloc) { + err = host1x_memory_context_active(ctx); + if (err) { + put_pid(ctx->pid); + kfree(ctx); + return ERR_PTR(err); + } + + ctx->static_alloc = true; + } + return ctx; } EXPORT_SYMBOL_GPL(host1x_memory_context_alloc); @@ -282,6 +299,11 @@ retry: hw = host1x_memory_context_alloc_hw_locked(ctx->host, ctx->dev, ctx->pid); if (PTR_ERR(hw) == -EBUSY) { /* All contexts busy. Wait for free context. */ + if (static_context_alloc) { + dev_warn(ctx->dev, "%s: all memory contexts are busy\n", current->comm); + err = -EBUSY; + goto unlock; + } if (!retrying) dev_warn(ctx->dev, "%s: all memory contexts are busy, waiting\n", current->comm); @@ -419,24 +441,11 @@ void host1x_memory_context_unmap(struct host1x_context_mapping *m) } EXPORT_SYMBOL_GPL(host1x_memory_context_unmap); -/** - * host1x_memory_context_inactive() - mark a memory context as no longer in use - * @ctx: memory context - * - * Drop one active reference taken by host1x_memory_context_active(). When the - * last active reference is dropped, the backing hardware context becomes - * eligible to be stolen by another context, and any waiters are woken. - * - * Must be called exactly once for each successful - * host1x_memory_context_active(). - */ -void host1x_memory_context_inactive(struct host1x_memory_context *ctx) +static void host1x_memory_context_inactive_locked(struct host1x_memory_context *ctx) { struct host1x_memory_context_list *cdl = &ctx->host->context_list; struct hw_alloc_waiter *waiter; - mutex_lock(&cdl->lock); - if (refcount_dec_and_test(&ctx->hw->active)) { /* Hardware context becomes eligible for stealing */ list_for_each_entry(waiter, &cdl->waiters, entry) { @@ -451,6 +460,26 @@ void host1x_memory_context_inactive(struct host1x_memory_context *ctx) */ } } +} + +/** + * host1x_memory_context_inactive() - mark a memory context as no longer in use + * @ctx: memory context + * + * Drop one active reference taken by host1x_memory_context_active(). When the + * last active reference is dropped, the backing hardware context becomes + * eligible to be stolen by another context, and any waiters are woken. + * + * Must be called exactly once for each successful + * host1x_memory_context_active(). + */ +void host1x_memory_context_inactive(struct host1x_memory_context *ctx) +{ + struct host1x_memory_context_list *cdl = &ctx->host->context_list; + + mutex_lock(&cdl->lock); + + host1x_memory_context_inactive_locked(ctx); mutex_unlock(&cdl->lock); } @@ -479,6 +508,9 @@ void host1x_memory_context_put(struct host1x_memory_context *ctx) struct host1x_memory_context_list *cdl = &ctx->host->context_list; if (refcount_dec_and_mutex_lock(&ctx->ref, &cdl->lock)) { + if (ctx->static_alloc) + host1x_memory_context_inactive_locked(ctx); + if (ctx->hw) { list_del(&ctx->entry); diff --git a/include/linux/host1x.h b/include/linux/host1x.h index 223345fdb1ab..8ebfb0d6f684 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -469,6 +469,7 @@ struct host1x_memory_context { struct pid *pid; refcount_t ref; + bool static_alloc; struct host1x_hw_memory_context *hw; struct list_head entry; /* Entry in hw_memory_context's list */ -- knotmirror 0.0.1