[PATCH 2/2] gpu: host1x: Add option for disabling context stealing
From: Mikko Perttunen
Date: Fri Jul 10 2026 - 03:19:33 EST
Add kernel module parameter to allow disabling context stealing in cases
where reliability and consistency is preferred.
Signed-off-by: Mikko Perttunen <mperttunen@xxxxxxxxxx>
---
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 8c159076d0fa..ddc293a5810c 100644
--- a/drivers/gpu/host1x/context.c
+++ b/drivers/gpu/host1x/context.c
@@ -7,6 +7,7 @@
#include <linux/device.h>
#include <linux/kref.h>
#include <linux/list.h>
+#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pid.h>
@@ -15,6 +16,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() */
@@ -167,7 +172,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) {
@@ -221,6 +226,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);
@@ -236,6 +242,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);
@@ -281,6 +298,11 @@ int host1x_memory_context_active(struct host1x_memory_context *ctx)
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);
@@ -418,24 +440,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) {
@@ -450,6 +459,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);
}
@@ -478,6 +507,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 07f7dd6fb4dd..46bb71d23266 100644
--- a/include/linux/host1x.h
+++ b/include/linux/host1x.h
@@ -462,6 +462,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 */
--
2.53.0