On 02/07/2021 15:32, Boris Brezillon wrote:
Needed to keep VkQueues isolated from each other.
v3:
- Limit the number of submitqueue per context to 16
- Fix a deadlock
Signed-off-by: Boris Brezillon boris.brezillon@collabora.com
16 ought to be enough for anyone ;)
Reviewed-by: Steven Price steven.price@arm.com
drivers/gpu/drm/panfrost/Makefile | 3 +- drivers/gpu/drm/panfrost/panfrost_device.h | 2 +- drivers/gpu/drm/panfrost/panfrost_drv.c | 69 +++++++-- drivers/gpu/drm/panfrost/panfrost_job.c | 47 ++---- drivers/gpu/drm/panfrost/panfrost_job.h | 9 +- .../gpu/drm/panfrost/panfrost_submitqueue.c | 136 ++++++++++++++++++ .../gpu/drm/panfrost/panfrost_submitqueue.h | 27 ++++ include/uapi/drm/panfrost_drm.h | 17 +++ 8 files changed, 264 insertions(+), 46 deletions(-) create mode 100644 drivers/gpu/drm/panfrost/panfrost_submitqueue.c create mode 100644 drivers/gpu/drm/panfrost/panfrost_submitqueue.h
diff --git a/drivers/gpu/drm/panfrost/Makefile b/drivers/gpu/drm/panfrost/Makefile index b71935862417..e99192b66ec9 100644 --- a/drivers/gpu/drm/panfrost/Makefile +++ b/drivers/gpu/drm/panfrost/Makefile @@ -9,6 +9,7 @@ panfrost-y := \ panfrost_gpu.o \ panfrost_job.o \ panfrost_mmu.o \
- panfrost_perfcnt.o
- panfrost_perfcnt.o \
- panfrost_submitqueue.o
obj-$(CONFIG_DRM_PANFROST) += panfrost.o diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h index 8b25278f34c8..51c0ba4e50f5 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.h +++ b/drivers/gpu/drm/panfrost/panfrost_device.h @@ -137,7 +137,7 @@ struct panfrost_mmu { struct panfrost_file_priv { struct panfrost_device *pfdev;
- struct drm_sched_entity sched_entity[NUM_JOB_SLOTS];
struct idr queues;
struct panfrost_mmu *mmu;
}; diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index b6b5997c9366..6529e5972b47 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -19,6 +19,7 @@ #include "panfrost_job.h" #include "panfrost_gpu.h" #include "panfrost_perfcnt.h" +#include "panfrost_submitqueue.h"
static bool unstable_ioctls; module_param_unsafe(unstable_ioctls, bool, 0600); @@ -250,6 +251,7 @@ static int panfrost_ioctl_submit(struct drm_device *dev, void *data, struct panfrost_device *pfdev = dev->dev_private; struct drm_panfrost_submit *args = data; struct drm_syncobj *sync_out = NULL;
- struct panfrost_submitqueue *queue; struct panfrost_job *job; int ret = 0;
@@ -259,10 +261,16 @@ static int panfrost_ioctl_submit(struct drm_device *dev, void *data, if (args->requirements && args->requirements != PANFROST_JD_REQ_FS) return -EINVAL;
- queue = panfrost_submitqueue_get(file->driver_priv, 0);
- if (IS_ERR(queue))
return PTR_ERR(queue);
- if (args->out_sync > 0) { sync_out = drm_syncobj_find(file, args->out_sync);
if (!sync_out)
return -ENODEV;
if (!sync_out) {
ret = -ENODEV;
goto fail_put_queue;
}
}
job = kzalloc(sizeof(*job), GFP_KERNEL);
@@ -289,7 +297,7 @@ static int panfrost_ioctl_submit(struct drm_device *dev, void *data, if (ret) goto fail_job;
- ret = panfrost_job_push(job);
- ret = panfrost_job_push(queue, job); if (ret) goto fail_job;
@@ -302,6 +310,8 @@ static int panfrost_ioctl_submit(struct drm_device *dev, void *data, fail_out_sync: if (sync_out) drm_syncobj_put(sync_out); +fail_put_queue:
panfrost_submitqueue_put(queue);
return ret;
} @@ -451,6 +461,36 @@ static int panfrost_ioctl_madvise(struct drm_device *dev, void *data, return ret; }
+static int +panfrost_ioctl_create_submitqueue(struct drm_device *dev, void *data,
struct drm_file *file_priv)
+{
- struct panfrost_file_priv *priv = file_priv->driver_priv;
- struct drm_panfrost_create_submitqueue *args = data;
- struct panfrost_submitqueue *queue;
- queue = panfrost_submitqueue_create(priv, args->priority, args->flags);
- if (IS_ERR(queue))
return PTR_ERR(queue);
- args->id = queue->id;
- return 0;
+}
+static int +panfrost_ioctl_destroy_submitqueue(struct drm_device *dev, void *data,
struct drm_file *file_priv)
+{
- struct panfrost_file_priv *priv = file_priv->driver_priv;
- u32 id = *((u32 *)data);
- /* Default queue can't be destroyed. */
- if (!id)
return -ENOENT;
- return panfrost_submitqueue_destroy(priv, id);
+}
int panfrost_unstable_ioctl_check(void) { if (!unstable_ioctls) @@ -465,6 +505,7 @@ panfrost_open(struct drm_device *dev, struct drm_file *file) int ret; struct panfrost_device *pfdev = dev->dev_private; struct panfrost_file_priv *panfrost_priv;
struct panfrost_submitqueue *defaultqueue;
panfrost_priv = kzalloc(sizeof(*panfrost_priv), GFP_KERNEL); if (!panfrost_priv)
@@ -479,13 +520,19 @@ panfrost_open(struct drm_device *dev, struct drm_file *file) goto err_free; }
- ret = panfrost_job_open(panfrost_priv);
- if (ret)
goto err_job;
idr_init(&panfrost_priv->queues);
defaultqueue = panfrost_submitqueue_create(panfrost_priv,
PANFROST_SUBMITQUEUE_PRIORITY_MEDIUM,
0);
if (IS_ERR(defaultqueue)) {
ret = PTR_ERR(defaultqueue);
goto err_destroy_idr;
}
return 0;
-err_job: +err_destroy_idr:
- idr_destroy(&panfrost_priv->queues); panfrost_mmu_ctx_put(panfrost_priv->mmu);
err_free: kfree(panfrost_priv); @@ -496,11 +543,15 @@ static void panfrost_postclose(struct drm_device *dev, struct drm_file *file) { struct panfrost_file_priv *panfrost_priv = file->driver_priv;
u32 id;
panfrost_perfcnt_close(file);
- panfrost_job_close(panfrost_priv);
for (id = 0; idr_get_next(&panfrost_priv->queues, &id); id++)
panfrost_submitqueue_destroy(panfrost_priv, id);
panfrost_mmu_ctx_put(panfrost_priv->mmu);
idr_destroy(&panfrost_priv->queues); kfree(panfrost_priv);
}
@@ -517,6 +568,8 @@ static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = { PANFROST_IOCTL(PERFCNT_ENABLE, perfcnt_enable, DRM_RENDER_ALLOW), PANFROST_IOCTL(PERFCNT_DUMP, perfcnt_dump, DRM_RENDER_ALLOW), PANFROST_IOCTL(MADVISE, madvise, DRM_RENDER_ALLOW),
- PANFROST_IOCTL(CREATE_SUBMITQUEUE, create_submitqueue, DRM_RENDER_ALLOW),
- PANFROST_IOCTL(DESTROY_SUBMITQUEUE, destroy_submitqueue, DRM_RENDER_ALLOW),
};
DEFINE_DRM_GEM_FOPS(panfrost_drm_driver_fops); diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c index 152245b122be..56ae89272e19 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -20,6 +20,7 @@ #include "panfrost_regs.h" #include "panfrost_gpu.h" #include "panfrost_mmu.h" +#include "panfrost_submitqueue.h"
#define JOB_TIMEOUT_MS 500
@@ -276,15 +277,15 @@ static void panfrost_attach_object_fences(struct panfrost_job *job) } }
-int panfrost_job_push(struct panfrost_job *job) +int panfrost_job_push(struct panfrost_submitqueue *queue,
struct panfrost_job *job)
{ struct panfrost_device *pfdev = job->pfdev; int slot = panfrost_job_get_slot(job);
- struct drm_sched_entity *entity = &job->file_priv->sched_entity[slot];
- struct drm_sched_entity *entity = &queue->sched_entity[slot]; struct ww_acquire_ctx acquire_ctx; int ret = 0;
- ret = drm_gem_lock_reservations(job->bos, job->bo_count, &acquire_ctx); if (ret)
@@ -881,43 +882,18 @@ void panfrost_job_fini(struct panfrost_device *pfdev) destroy_workqueue(pfdev->reset.wq); }
-int panfrost_job_open(struct panfrost_file_priv *panfrost_priv) +void panfrost_job_kill_queue(struct panfrost_submitqueue *queue) {
- struct panfrost_device *pfdev = panfrost_priv->pfdev;
- struct panfrost_job_slot *js = pfdev->js;
- struct drm_gpu_scheduler *sched;
- int ret, i;
- struct panfrost_device *pfdev = queue->pfdev;
- int i, j;
- for (i = 0; i < NUM_JOB_SLOTS; i++) {
sched = &js->queue[i].sched;
ret = drm_sched_entity_init(&panfrost_priv->sched_entity[i],
DRM_SCHED_PRIORITY_NORMAL, &sched,
1, NULL);
if (WARN_ON(ret))
return ret;
- }
- return 0;
-}
-void panfrost_job_close(struct panfrost_file_priv *panfrost_priv) -{
struct panfrost_device *pfdev = panfrost_priv->pfdev;
int i;
for (i = 0; i < NUM_JOB_SLOTS; i++)
drm_sched_entity_destroy(&panfrost_priv->sched_entity[i]);
/* Kill in-flight jobs */ spin_lock(&pfdev->js->job_lock); for (i = 0; i < NUM_JOB_SLOTS; i++) {
struct drm_sched_entity *entity = &panfrost_priv->sched_entity[i];
int j;
for (j = ARRAY_SIZE(pfdev->jobs[0]) - 1; j >= 0; j--) { struct panfrost_job *job = pfdev->jobs[i][j]; u32 cmd;
if (!job || job->base.entity != entity)
if (!job || job->base.entity != &queue->sched_entity[i]) continue; if (j == 1) {
@@ -936,7 +912,6 @@ void panfrost_job_close(struct panfrost_file_priv *panfrost_priv) } else { cmd = JS_COMMAND_HARD_STOP; }
} }job_write(pfdev, JS_COMMAND(i), cmd);
@@ -956,3 +931,9 @@ int panfrost_job_is_idle(struct panfrost_device *pfdev)
return true; }
+struct drm_gpu_scheduler * +panfrost_job_get_sched(struct panfrost_device *pfdev, unsigned int js) +{
- return &pfdev->js->queue[js].sched;
+} diff --git a/drivers/gpu/drm/panfrost/panfrost_job.h b/drivers/gpu/drm/panfrost/panfrost_job.h index 1cbc3621b663..5c228bb431c0 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.h +++ b/drivers/gpu/drm/panfrost/panfrost_job.h @@ -10,6 +10,7 @@ struct panfrost_device; struct panfrost_gem_object; struct panfrost_file_priv; +struct panfrost_submitqueue;
struct panfrost_job { struct drm_sched_job base; @@ -41,11 +42,13 @@ struct panfrost_job {
int panfrost_job_init(struct panfrost_device *pfdev); void panfrost_job_fini(struct panfrost_device *pfdev); -int panfrost_job_open(struct panfrost_file_priv *panfrost_priv); -void panfrost_job_close(struct panfrost_file_priv *panfrost_priv); -int panfrost_job_push(struct panfrost_job *job); +int panfrost_job_push(struct panfrost_submitqueue *queue,
struct panfrost_job *job);
void panfrost_job_put(struct panfrost_job *job); void panfrost_job_enable_interrupts(struct panfrost_device *pfdev); int panfrost_job_is_idle(struct panfrost_device *pfdev); +void panfrost_job_kill_queue(struct panfrost_submitqueue *queue); +struct drm_gpu_scheduler * +panfrost_job_get_sched(struct panfrost_device *pfdev, unsigned int js);
#endif diff --git a/drivers/gpu/drm/panfrost/panfrost_submitqueue.c b/drivers/gpu/drm/panfrost/panfrost_submitqueue.c new file mode 100644 index 000000000000..c16fe110a264 --- /dev/null +++ b/drivers/gpu/drm/panfrost/panfrost_submitqueue.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright 2021 Collabora ltd. */
+#include <linux/idr.h>
+#include "panfrost_device.h" +#include "panfrost_job.h" +#include "panfrost_submitqueue.h"
+#define PAN_MAX_SUBMITQUEUES 16
+static enum drm_sched_priority +to_sched_prio(enum panfrost_submitqueue_priority priority) +{
- switch (priority) {
- case PANFROST_SUBMITQUEUE_PRIORITY_LOW:
return DRM_SCHED_PRIORITY_MIN;
- case PANFROST_SUBMITQUEUE_PRIORITY_MEDIUM:
return DRM_SCHED_PRIORITY_NORMAL;
- case PANFROST_SUBMITQUEUE_PRIORITY_HIGH:
return DRM_SCHED_PRIORITY_HIGH;
- default:
break;
- }
- return DRM_SCHED_PRIORITY_UNSET;
+}
+static void +panfrost_submitqueue_cleanup(struct kref *ref) +{
- struct panfrost_submitqueue *queue;
- unsigned int i;
- queue = container_of(ref, struct panfrost_submitqueue, refcount);
- for (i = 0; i < NUM_JOB_SLOTS; i++)
drm_sched_entity_destroy(&queue->sched_entity[i]);
- /* Kill in-flight jobs */
- panfrost_job_kill_queue(queue);
- kfree(queue);
+}
+void panfrost_submitqueue_put(struct panfrost_submitqueue *queue) +{
- if (!IS_ERR_OR_NULL(queue))
kref_put(&queue->refcount, panfrost_submitqueue_cleanup);
+}
+struct panfrost_submitqueue * +panfrost_submitqueue_create(struct panfrost_file_priv *ctx,
enum panfrost_submitqueue_priority priority,
u32 flags)
+{
- struct panfrost_submitqueue *queue;
- enum drm_sched_priority sched_prio;
- int ret, i;
- if (flags || priority >= PANFROST_SUBMITQUEUE_PRIORITY_COUNT)
return ERR_PTR(-EINVAL);
- queue = kzalloc(sizeof(*queue), GFP_KERNEL);
- if (!queue)
return ERR_PTR(-ENOMEM);
- queue->pfdev = ctx->pfdev;
- sched_prio = to_sched_prio(priority);
- for (i = 0; i < NUM_JOB_SLOTS; i++) {
struct drm_gpu_scheduler *sched;
sched = panfrost_job_get_sched(ctx->pfdev, i);
ret = drm_sched_entity_init(&queue->sched_entity[i],
sched_prio, &sched, 1, NULL);
if (ret)
break;
- }
- if (ret) {
for (i--; i >= 0; i--)
drm_sched_entity_destroy(&queue->sched_entity[i]);
return ERR_PTR(ret);
- }
- kref_init(&queue->refcount);
- idr_preload(GFP_KERNEL);
- idr_lock(&ctx->queues);
- ret = idr_alloc(&ctx->queues, queue, 0, PAN_MAX_SUBMITQUEUES,
GFP_NOWAIT);
- if (ret >= 0)
queue->id = ret;
- idr_unlock(&ctx->queues);
- idr_preload_end();
- if (ret < 0) {
panfrost_submitqueue_put(queue);
return ERR_PTR(ret);
- }
- return queue;
+}
+int panfrost_submitqueue_destroy(struct panfrost_file_priv *ctx, u32 id) +{
- struct panfrost_submitqueue *queue;
- idr_lock(&ctx->queues);
- queue = idr_remove(&ctx->queues, id);
- idr_unlock(&ctx->queues);
- if (!queue)
return -ENOENT;
- panfrost_submitqueue_put(queue);
- return 0;
+}
+struct panfrost_submitqueue * +panfrost_submitqueue_get(struct panfrost_file_priv *ctx, u32 id) +{
- struct panfrost_submitqueue *queue;
- idr_lock(&ctx->queues);
- queue = idr_find(&ctx->queues, id);
- if (queue)
kref_get(&queue->refcount);
- idr_unlock(&ctx->queues);
- if (!queue)
return ERR_PTR(-ENOENT);
- return queue;
+} diff --git a/drivers/gpu/drm/panfrost/panfrost_submitqueue.h b/drivers/gpu/drm/panfrost/panfrost_submitqueue.h new file mode 100644 index 000000000000..cde736d97cf6 --- /dev/null +++ b/drivers/gpu/drm/panfrost/panfrost_submitqueue.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright 2032 Collabora ltd. */
+#ifndef __PANFROST_SUBMITQUEUE_H__ +#define __PANFROST_SUBMITQUEUE_H__
+#include <drm/panfrost_drm.h>
+struct panfrost_submitqueue {
- struct kref refcount;
- struct panfrost_device *pfdev;
- u32 id;
- struct drm_sched_entity sched_entity[NUM_JOB_SLOTS];
+};
+struct panfrost_file_priv;
+struct panfrost_submitqueue * +panfrost_submitqueue_create(struct panfrost_file_priv *ctx,
enum panfrost_submitqueue_priority priority,
u32 flags);
+int panfrost_submitqueue_destroy(struct panfrost_file_priv *ctx, u32 id); +struct panfrost_submitqueue * +panfrost_submitqueue_get(struct panfrost_file_priv *ctx, u32 id); +void panfrost_submitqueue_put(struct panfrost_submitqueue *queue);
+#endif diff --git a/include/uapi/drm/panfrost_drm.h b/include/uapi/drm/panfrost_drm.h index 45d6c600475c..7ee02fd1ac75 100644 --- a/include/uapi/drm/panfrost_drm.h +++ b/include/uapi/drm/panfrost_drm.h @@ -21,6 +21,8 @@ extern "C" { #define DRM_PANFROST_PERFCNT_ENABLE 0x06 #define DRM_PANFROST_PERFCNT_DUMP 0x07 #define DRM_PANFROST_MADVISE 0x08 +#define DRM_PANFROST_CREATE_SUBMITQUEUE 0x09 +#define DRM_PANFROST_DESTROY_SUBMITQUEUE 0x0a
#define DRM_IOCTL_PANFROST_SUBMIT DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_SUBMIT, struct drm_panfrost_submit) #define DRM_IOCTL_PANFROST_WAIT_BO DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_WAIT_BO, struct drm_panfrost_wait_bo) @@ -29,6 +31,8 @@ extern "C" { #define DRM_IOCTL_PANFROST_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_GET_PARAM, struct drm_panfrost_get_param) #define DRM_IOCTL_PANFROST_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_GET_BO_OFFSET, struct drm_panfrost_get_bo_offset) #define DRM_IOCTL_PANFROST_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_MADVISE, struct drm_panfrost_madvise) +#define DRM_IOCTL_PANFROST_CREATE_SUBMITQUEUE DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_CREATE_SUBMITQUEUE, struct drm_panfrost_create_submitqueue) +#define DRM_IOCTL_PANFROST_DESTROY_SUBMITQUEUE DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_DESTROY_SUBMITQUEUE, __u32)
/*
- Unstable ioctl(s): only exposed when the unsafe unstable_ioctls module
@@ -224,6 +228,19 @@ struct drm_panfrost_madvise { __u32 retained; /* out, whether backing store still exists */ };
+enum panfrost_submitqueue_priority {
- PANFROST_SUBMITQUEUE_PRIORITY_LOW = 0,
- PANFROST_SUBMITQUEUE_PRIORITY_MEDIUM,
- PANFROST_SUBMITQUEUE_PRIORITY_HIGH,
- PANFROST_SUBMITQUEUE_PRIORITY_COUNT,
+};
+struct drm_panfrost_create_submitqueue {
- __u32 flags; /* in, PANFROST_SUBMITQUEUE_x */
- __u32 priority; /* in, enum panfrost_submitqueue_priority */
- __u32 id; /* out, identifier */
+};
#define PANFROST_BO_REF_EXCLUSIVE 0x1
#if defined(__cplusplus)