diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 99d39b2aefa6..3065cb290aa8 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -28,6 +28,19 @@ config DRM_MSM_REGISTER_LOGGING that can be parsed by envytools demsm tool. If enabled, register logging can be switched on via msm.reglog=y module param. +config DRM_MSM_GPU_SUDO + bool "Enable SUDO flag on submits" + depends on DRM_MSM && EXPERT + default n + help + Enable userspace that has CAP_SYS_RAWIO to submit GPU commands + that are run from RB instead of IB1. This essentially gives + userspace kernel level access, but is useful for firmware + debugging. + + Only use this if you are a driver developer. This should *not* + be enabled for production kernels. If unsure, say N. + config DRM_MSM_HDMI_HDCP bool "Enable HDMI HDCP support in MSM DRM driver" depends on DRM_MSM && QCOM_SCM diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 579c28c8c994..fa08b4897a56 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -140,6 +140,65 @@ static void a5xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring) gpu_write(gpu, REG_A5XX_CP_RB_WPTR, wptr); } +static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit *submit, + struct msm_file_private *ctx) +{ + struct msm_drm_private *priv = gpu->dev->dev_private; + struct msm_ringbuffer *ring = submit->ring; + struct msm_gem_object *obj; + uint32_t *ptr, dwords; + unsigned int i; + + for (i = 0; i < submit->nr_cmds; i++) { + switch (submit->cmd[i].type) { + case MSM_SUBMIT_CMD_IB_TARGET_BUF: + break; + case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: + if (priv->lastctx == ctx) + break; + case MSM_SUBMIT_CMD_BUF: + /* copy commands into RB: */ + obj = submit->bos[submit->cmd[i].idx].obj; + dwords = submit->cmd[i].size; + + ptr = msm_gem_get_vaddr(&obj->base); + + /* _get_vaddr() shouldn't fail at this point, + * since we've already mapped it once in + * submit_reloc() + */ + if (WARN_ON(!ptr)) + return; + + for (i = 0; i < dwords; i++) { + /* normally the OUT_PKTn() would wait + * for space for the packet. But since + * we just OUT_RING() the whole thing, + * need to call adreno_wait_ring() + * ourself: + */ + adreno_wait_ring(ring, 1); + OUT_RING(ring, ptr[i]); + } + + msm_gem_put_vaddr(&obj->base); + + break; + } + } + + a5xx_flush(gpu, ring); + a5xx_preempt_trigger(gpu); + + /* we might not necessarily have a cmd from userspace to + * trigger an event to know that submit has completed, so + * do this manually: + */ + a5xx_idle(gpu, ring); + ring->memptrs->fence = submit->seqno; + msm_gpu_retire(gpu); +} + static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_file_private *ctx) { @@ -149,6 +208,12 @@ static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_ringbuffer *ring = submit->ring; unsigned int i, ibs = 0; + if (IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) && submit->in_rb) { + priv->lastctx = NULL; + a5xx_submit_in_rb(gpu, submit, ctx); + return; + } + OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1); OUT_RING(ring, 0x02); diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 9320e184b48d..c5d9bd3e47a8 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -146,6 +146,7 @@ struct msm_gem_submit { struct msm_gpu_submitqueue *queue; struct pid *pid; /* submitting process */ bool valid; /* true if no cmdstream patching needed */ + bool in_rb; /* "sudo" mode, copy cmds into RB */ struct msm_ringbuffer *ring; unsigned int nr_cmds; unsigned int nr_bos; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index b8dc8f96caf2..7bd83e0afa97 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -430,6 +430,12 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (MSM_PIPE_FLAGS(args->flags) & ~MSM_SUBMIT_FLAGS) return -EINVAL; + if (args->flags & MSM_SUBMIT_SUDO) { + if (!IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) || + !capable(CAP_SYS_RAWIO)) + return -EINVAL; + } + queue = msm_submitqueue_get(ctx, args->queueid); if (!queue) return -ENOENT; @@ -471,6 +477,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, goto out_unlock; } + if (args->flags & MSM_SUBMIT_SUDO) + submit->in_rb = true; + ret = submit_lookup_objects(submit, args, file); if (ret) goto out; diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index bbbaffad772d..c06d0a5bdd80 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -201,10 +201,12 @@ struct drm_msm_gem_submit_bo { #define MSM_SUBMIT_NO_IMPLICIT 0x80000000 /* disable implicit sync */ #define MSM_SUBMIT_FENCE_FD_IN 0x40000000 /* enable input fence_fd */ #define MSM_SUBMIT_FENCE_FD_OUT 0x20000000 /* enable output fence_fd */ +#define MSM_SUBMIT_SUDO 0x10000000 /* run submitted cmds from RB */ #define MSM_SUBMIT_FLAGS ( \ MSM_SUBMIT_NO_IMPLICIT | \ MSM_SUBMIT_FENCE_FD_IN | \ MSM_SUBMIT_FENCE_FD_OUT | \ + MSM_SUBMIT_SUDO | \ 0) /* Each cmdstream submit consists of a table of buffers involved, and