*/
 
 #include <drm/drmP.h>
+#include <drm/drm_auth.h>
 #include "amdgpu.h"
 
-static int amdgpu_ctx_init(struct amdgpu_device *adev, struct amdgpu_ctx *ctx)
+static int amdgpu_ctx_priority_permit(struct drm_file *filp,
+                                     enum amd_sched_priority priority)
+{
+       /* NORMAL and below are accessible by everyone */
+       if (priority <= AMD_SCHED_PRIORITY_NORMAL)
+               return 0;
+
+       if (capable(CAP_SYS_NICE))
+               return 0;
+
+       if (drm_is_current_master(filp))
+               return 0;
+
+       return -EACCES;
+}
+
+static int amdgpu_ctx_init(struct amdgpu_device *adev,
+                          enum amd_sched_priority priority,
+                          struct drm_file *filp,
+                          struct amdgpu_ctx *ctx)
 {
        unsigned i, j;
        int r;
 
+       if (priority < 0 || priority >= AMD_SCHED_PRIORITY_MAX)
+               return -EINVAL;
+
+       r = amdgpu_ctx_priority_permit(filp, priority);
+       if (r)
+               return r;
+
        memset(ctx, 0, sizeof(*ctx));
        ctx->adev = adev;
        kref_init(&ctx->refcount);
                struct amdgpu_ring *ring = adev->rings[i];
                struct amd_sched_rq *rq;
 
-               rq = &ring->sched.sched_rq[AMD_SCHED_PRIORITY_NORMAL];
+               rq = &ring->sched.sched_rq[priority];
 
                if (ring == &adev->gfx.kiq.ring)
                        continue;
 
 static int amdgpu_ctx_alloc(struct amdgpu_device *adev,
                            struct amdgpu_fpriv *fpriv,
+                           struct drm_file *filp,
+                           enum amd_sched_priority priority,
                            uint32_t *id)
 {
        struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
                kfree(ctx);
                return r;
        }
+
        *id = (uint32_t)r;
-       r = amdgpu_ctx_init(adev, ctx);
+       r = amdgpu_ctx_init(adev, priority, filp, ctx);
        if (r) {
                idr_remove(&mgr->ctx_handles, *id);
                *id = 0;
        return 0;
 }
 
+static enum amd_sched_priority amdgpu_to_sched_priority(int amdgpu_priority)
+{
+       switch (amdgpu_priority) {
+       case AMDGPU_CTX_PRIORITY_HIGH_HW:
+               return AMD_SCHED_PRIORITY_HIGH_HW;
+       case AMDGPU_CTX_PRIORITY_HIGH_SW:
+               return AMD_SCHED_PRIORITY_HIGH_SW;
+       case AMDGPU_CTX_PRIORITY_NORMAL:
+               return AMD_SCHED_PRIORITY_NORMAL;
+       case AMDGPU_CTX_PRIORITY_LOW_SW:
+       case AMDGPU_CTX_PRIORITY_LOW_HW:
+               return AMD_SCHED_PRIORITY_LOW;
+       default:
+               WARN(1, "Invalid context priority %d\n", amdgpu_priority);
+               return AMD_SCHED_PRIORITY_NORMAL;
+       }
+}
+
 int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
                     struct drm_file *filp)
 {
        int r;
        uint32_t id;
+       enum amd_sched_priority priority;
 
        union drm_amdgpu_ctx *args = data;
        struct amdgpu_device *adev = dev->dev_private;
 
        r = 0;
        id = args->in.ctx_id;
+       priority = amdgpu_to_sched_priority(args->in.priority);
+
+       if (priority >= AMD_SCHED_PRIORITY_MAX)
+               return -EINVAL;
 
        switch (args->in.op) {
        case AMDGPU_CTX_OP_ALLOC_CTX:
-               r = amdgpu_ctx_alloc(adev, fpriv, &id);
+               r = amdgpu_ctx_alloc(adev, fpriv, filp, priority, &id);
                args->out.alloc.ctx_id = id;
                break;
        case AMDGPU_CTX_OP_FREE_CTX:
 
 /* unknown cause */
 #define AMDGPU_CTX_UNKNOWN_RESET       3
 
+/* Context priority level */
+#define AMDGPU_CTX_PRIORITY_LOW_HW      -1023
+#define AMDGPU_CTX_PRIORITY_LOW_SW      -512
+#define AMDGPU_CTX_PRIORITY_NORMAL      0
+/* Selecting a priority above NORMAL requires CAP_SYS_NICE or DRM_MASTER */
+#define AMDGPU_CTX_PRIORITY_HIGH_SW     512
+#define AMDGPU_CTX_PRIORITY_HIGH_HW     1023
+
 struct drm_amdgpu_ctx_in {
        /** AMDGPU_CTX_OP_* */
        __u32   op;
        /** For future use, no flags defined so far */
        __u32   flags;
        __u32   ctx_id;
-       __u32   _pad;
+       __s32   priority;
 };
 
 union drm_amdgpu_ctx_out {