summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMikko Perttunen <mperttunen@nvidia.com>2026-07-10 16:14:32 +0900
committerThierry Reding <treding@nvidia.com>2026-10-02 01:01:40 +0200
commitb9110d86fa4ff96f3a7ecee0729f111149acc805 (patch)
treeebc6ba86130a724b7632e7fca11c4eeab0f02a65 /drivers
parent6eb92f5520b8c0b97c3317f622a2b69bcde75395 (diff)
downloadlinux-b9110d86fa4ff96f3a7ecee0729f111149acc805.tar.gz
linux-b9110d86fa4ff96f3a7ecee0729f111149acc805.zip
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 <mperttunen@nvidia.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patch.msgid.link/20260710-b4-host1x-ctxsteal-v1-2-b1f8f6b37cc5@nvidia.com
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/host1x/context.c62
1 files changed, 47 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 <linux/host1x_context_bus.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>
@@ -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);