* case we opt to forcibly kill off all remaining requests on
         * context close.
         */
-       if (!i915_modparams.enable_hangcheck)
+       if (!i915_gem_context_is_persistent(ctx) ||
+           !i915_modparams.enable_hangcheck)
                kill_context(ctx);
 
        i915_gem_context_put(ctx);
 }
 
+static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
+{
+       if (i915_gem_context_is_persistent(ctx) == state)
+               return 0;
+
+       if (state) {
+               /*
+                * Only contexts that are short-lived [that will expire or be
+                * reset] are allowed to survive past termination. We require
+                * hangcheck to ensure that the persistent requests are healthy.
+                */
+               if (!i915_modparams.enable_hangcheck)
+                       return -EINVAL;
+
+               i915_gem_context_set_persistence(ctx);
+       } else {
+               /* To cancel a context we use "preempt-to-idle" */
+               if (!(ctx->i915->caps.scheduler & I915_SCHEDULER_CAP_PREEMPTION))
+                       return -ENODEV;
+
+               i915_gem_context_clear_persistence(ctx);
+       }
+
+       return 0;
+}
+
 static struct i915_gem_context *
 __create_context(struct drm_i915_private *i915)
 {
 
        i915_gem_context_set_bannable(ctx);
        i915_gem_context_set_recoverable(ctx);
+       __context_set_persistence(ctx, true /* cgroup hook? */);
 
        for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
                ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
                return ctx;
 
        i915_gem_context_clear_bannable(ctx);
+       i915_gem_context_set_persistence(ctx);
        ctx->sched.priority = I915_USER_PRIORITY(prio);
 
        GEM_BUG_ON(!i915_gem_context_is_kernel(ctx));
        return err;
 }
 
+static int
+set_persistence(struct i915_gem_context *ctx,
+               const struct drm_i915_gem_context_param *args)
+{
+       if (args->size)
+               return -EINVAL;
+
+       return __context_set_persistence(ctx, args->value);
+}
+
 static int ctx_setparam(struct drm_i915_file_private *fpriv,
                        struct i915_gem_context *ctx,
                        struct drm_i915_gem_context_param *args)
                ret = set_engines(ctx, args);
                break;
 
+       case I915_CONTEXT_PARAM_PERSISTENCE:
+               ret = set_persistence(ctx, args);
+               break;
+
        case I915_CONTEXT_PARAM_BAN_PERIOD:
        default:
                ret = -EINVAL;
                ret = get_engines(ctx, args);
                break;
 
+       case I915_CONTEXT_PARAM_PERSISTENCE:
+               args->size = 0;
+               args->value = i915_gem_context_is_persistent(ctx);
+               break;
+
        case I915_CONTEXT_PARAM_BAN_PERIOD:
        default:
                ret = -EINVAL;
 
        clear_bit(UCONTEXT_RECOVERABLE, &ctx->user_flags);
 }
 
+static inline bool i915_gem_context_is_persistent(const struct i915_gem_context *ctx)
+{
+       return test_bit(UCONTEXT_PERSISTENCE, &ctx->user_flags);
+}
+
+static inline void i915_gem_context_set_persistence(struct i915_gem_context *ctx)
+{
+       set_bit(UCONTEXT_PERSISTENCE, &ctx->user_flags);
+}
+
+static inline void i915_gem_context_clear_persistence(struct i915_gem_context *ctx)
+{
+       clear_bit(UCONTEXT_PERSISTENCE, &ctx->user_flags);
+}
+
 static inline bool i915_gem_context_is_banned(const struct i915_gem_context *ctx)
 {
        return test_bit(CONTEXT_BANNED, &ctx->flags);
 
  *   i915_context_engines_bond (I915_CONTEXT_ENGINES_EXT_BOND)
  */
 #define I915_CONTEXT_PARAM_ENGINES     0xa
+
+/*
+ * I915_CONTEXT_PARAM_PERSISTENCE:
+ *
+ * Allow the context and active rendering to survive the process until
+ * completion. Persistence allows fire-and-forget clients to queue up a
+ * bunch of work, hand the output over to a display server and then quit.
+ * If the context is marked as not persistent, upon closing (either via
+ * an explicit DRM_I915_GEM_CONTEXT_DESTROY or implicitly from file closure
+ * or process termination), the context and any outstanding requests will be
+ * cancelled (and exported fences for cancelled requests marked as -EIO).
+ *
+ * By default, new contexts allow persistence.
+ */
+#define I915_CONTEXT_PARAM_PERSISTENCE 0xb
 /* Must be kept compact -- no holes and well documented */
 
        __u64 value;