Some state the kernel keeps has to be applied to values the GPU produces
by itself, the first case being the always-on counter that restarts
across a GPU power collapse. A GET_PARAM can't carry it, as command
streams need the value at the time they execute.

Allocate one page in the global GPU address space, read-only to the GPU
and not privileged, so the command streams of every context can read
it, and report its address. Start it with a flags word so that fields
appended later can be announced.

Signed-off-by: Dmitry Baryshkov <[email protected]>
---
 drivers/gpu/drm/msm/adreno/adreno_gpu.c |  3 +++
 drivers/gpu/drm/msm/msm_gpu.c           | 15 +++++++++++++++
 drivers/gpu/drm/msm/msm_gpu.h           |  5 +++++
 include/uapi/drm/msm_drm.h              |  9 +++++++++
 4 files changed, 32 insertions(+)

diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c 
b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index dadfe4c69438..0adf56fb9563 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -404,6 +404,9 @@ int adreno_get_param(struct msm_gpu *gpu, struct 
msm_context *ctx,
                        return 0;
                }
                return -EINVAL;
+       case MSM_PARAM_VDSO_IOVA:
+               *value = gpu->vdso_iova;
+               return 0;
        case MSM_PARAM_PRIORITIES:
                *value = gpu->nr_rings * NR_SCHED_PRIORITIES;
                return 0;
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 0c2c35636251..747cd90e329a 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -989,6 +989,19 @@ int msm_gpu_init(struct drm_device *drm, struct 
platform_device *pdev,
 
        msm_gem_object_set_name(gpu->memptrs_bo, "memptrs");
 
+       gpu->vdso = msm_gem_kernel_new(drm, PAGE_SIZE,
+               MSM_BO_WC | MSM_BO_GPU_READONLY, gpu->vm, &gpu->vdso_bo,
+               &gpu->vdso_iova);
+
+       if (IS_ERR(gpu->vdso)) {
+               ret = PTR_ERR(gpu->vdso);
+               gpu->vdso = NULL;
+               DRM_DEV_ERROR(drm->dev, "could not allocate vdso: %d\n", ret);
+               goto fail;
+       }
+
+       msm_gem_object_set_name(gpu->vdso_bo, "vdso");
+
        if (nr_rings > ARRAY_SIZE(gpu->rb)) {
                DRM_DEV_INFO_ONCE(drm->dev, "Only creating %zu ringbuffers\n",
                        ARRAY_SIZE(gpu->rb));
@@ -1033,6 +1046,7 @@ int msm_gpu_init(struct drm_device *drm, struct 
platform_device *pdev,
                gpu->rb[i] = NULL;
        }
 
+       msm_gem_kernel_put(gpu->vdso_bo, gpu->vm);
        msm_gem_kernel_put(gpu->memptrs_bo, gpu->vm);
 
        platform_set_drvdata(pdev, NULL);
@@ -1050,6 +1064,7 @@ void msm_gpu_cleanup(struct msm_gpu *gpu)
                gpu->rb[i] = NULL;
        }
 
+       msm_gem_kernel_put(gpu->vdso_bo, gpu->vm);
        msm_gem_kernel_put(gpu->memptrs_bo, gpu->vm);
 
        if (!IS_ERR_OR_NULL(gpu->vm)) {
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index d27d54bdb7a7..f78f3bc62977 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -252,6 +252,11 @@ struct msm_gpu {
 
        struct drm_gem_object *memptrs_bo;
 
+       /* page of kernel state shared read-only with the GPU: */
+       struct drm_gem_object *vdso_bo;
+       struct drm_msm_vdso *vdso;
+       uint64_t vdso_iova;
+
        struct msm_gpu_devfreq devfreq;
 
        uint32_t suspend_count;
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index 3d363f12f66a..f8bf48fdc339 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -118,6 +118,7 @@ struct drm_msm_timespec {
  */
 #define MSM_PARAM_EN_VM_BIND 0x16  /* WO, once */
 #define MSM_PARAM_AQE       0x17  /* RO */
+#define MSM_PARAM_VDSO_IOVA  0x18  /* RO: GPU address of struct drm_msm_vdso */
 
 /* For backwards compat.  The original support for preemption was based on
  * a single ring per priority level so # of priority levels equals the #
@@ -127,6 +128,14 @@ struct drm_msm_timespec {
  */
 #define MSM_PARAM_NR_RINGS   MSM_PARAM_PRIORITIES
 
+/* A page of kernel state that the GPU can read, at MSM_PARAM_VDSO_IOVA, for
+ * command streams to use.  New fields are only ever appended, and the kernel
+ * sets a bit in @flags for each one that needs announcing.
+ */
+struct drm_msm_vdso {
+       __u64 flags;
+};
+
 struct drm_msm_param {
        __u32 pipe;           /* in, MSM_PIPE_x */
        __u32 param;          /* in, MSM_PARAM_x */

-- 
2.47.3

Reply via email to