@@ -9,6 +9,7 @@ panthor-y := \
panthor_gpu.o \
panthor_heap.o \
panthor_mmu.o \
- panthor_sched.o
+ panthor_sched.o \
+ panthor_syncobj.o
obj-$(CONFIG_DRM_PANTHOR) += panthor.o
@@ -31,6 +31,7 @@
#include "panthor_mmu.h"
#include "panthor_regs.h"
#include "panthor_sched.h"
+#include "panthor_syncobj.h"
/**
* DOC: Scheduler
@@ -318,39 +319,6 @@ struct panthor_scheduler {
} reset;
};
-/**
- * struct panthor_syncobj_32b - 32-bit FW synchronization object
- */
-struct panthor_syncobj_32b {
- /** @seqno: Sequence number. */
- u32 seqno;
-
- /**
- * @status: Status.
- *
- * Not zero on failure.
- */
- u32 status;
-};
-
-/**
- * struct panthor_syncobj_64b - 64-bit FW synchronization object
- */
-struct panthor_syncobj_64b {
- /** @seqno: Sequence number. */
- u64 seqno;
-
- /**
- * @status: Status.
- *
- * Not zero on failure.
- */
- u32 status;
-
- /** @pad: MBZ. */
- u32 pad;
-};
-
/**
* struct panthor_queue - Execution queue
*/
@@ -445,17 +413,8 @@ struct panthor_queue {
/** @sync64: True if this is a 64-bit sync object. */
bool sync64;
- /** @bo: Buffer object holding the synchronization object. */
- struct drm_gem_object *obj;
-
- /** @offset: Offset of the synchronization object inside @bo. */
- u64 offset;
-
- /**
- * @kmap: Kernel mapping of the buffer object holding the
- * synchronization object.
- */
- void *kmap;
+ /** @syncobj: Wrapper for the syncobj in memory */
+ struct panthor_syncobj *syncobj;
} syncwait;
/** @fence_ctx: Fence context fields. */
@@ -794,53 +753,6 @@ struct panthor_job {
struct dma_fence *done_fence;
};
-static void
-panthor_queue_put_syncwait_obj(struct panthor_queue *queue)
-{
- if (queue->syncwait.kmap) {
- struct iosys_map map = IOSYS_MAP_INIT_VADDR(queue->syncwait.kmap);
-
- drm_gem_vunmap_unlocked(queue->syncwait.obj, &map);
- queue->syncwait.kmap = NULL;
- }
-
- drm_gem_object_put(queue->syncwait.obj);
- queue->syncwait.obj = NULL;
-}
-
-static void *
-panthor_queue_get_syncwait_obj(struct panthor_group *group, struct panthor_queue *queue)
-{
- struct panthor_device *ptdev = group->ptdev;
- struct panthor_gem_object *bo;
- struct iosys_map map;
- int ret;
-
- if (queue->syncwait.kmap)
- return queue->syncwait.kmap + queue->syncwait.offset;
-
- bo = panthor_vm_get_bo_for_va(group->vm,
- queue->syncwait.gpu_va,
- &queue->syncwait.offset);
- if (drm_WARN_ON(&ptdev->base, IS_ERR_OR_NULL(bo)))
- goto err_put_syncwait_obj;
-
- queue->syncwait.obj = &bo->base.base;
- ret = drm_gem_vmap_unlocked(queue->syncwait.obj, &map);
- if (drm_WARN_ON(&ptdev->base, ret))
- goto err_put_syncwait_obj;
-
- queue->syncwait.kmap = map.vaddr;
- if (drm_WARN_ON(&ptdev->base, !queue->syncwait.kmap))
- goto err_put_syncwait_obj;
-
- return queue->syncwait.kmap + queue->syncwait.offset;
-
-err_put_syncwait_obj:
- panthor_queue_put_syncwait_obj(queue);
- return NULL;
-}
-
static void group_free_queue(struct panthor_group *group, struct panthor_queue *queue)
{
if (IS_ERR_OR_NULL(queue))
@@ -852,7 +764,7 @@ static void group_free_queue(struct panthor_group *group, struct panthor_queue *
if (queue->scheduler.ops)
drm_sched_fini(&queue->scheduler);
- panthor_queue_put_syncwait_obj(queue);
+ panthor_syncobj_release(queue->syncwait.syncobj);
if (queue->ringbuf_offset)
drm_vma_node_revoke(&queue->ringbuf->obj->vma_node, group->pfile->drm_file);
@@ -2065,7 +1977,6 @@ group_term_post_processing(struct panthor_group *group)
cookie = dma_fence_begin_signalling();
for (i = 0; i < group->queue_count; i++) {
struct panthor_queue *queue = group->queues[i];
- struct panthor_syncobj_64b *syncobj;
int err;
if (group->fatal_queues & BIT(i))
@@ -2086,12 +1997,13 @@ group_term_post_processing(struct panthor_group *group)
}
spin_unlock(&queue->fence_ctx.lock);
- if (!group->user_submit) {
+ if (!group->user_submit)
/* Manually update the syncobj seqno to unblock waiters. */
- syncobj = group->syncobjs->kmap + (i * sizeof(*syncobj));
- syncobj->status = ~0;
- syncobj->seqno = atomic64_read(&queue->fence_ctx.seqno);
- }
+ panthor_syncobj_ptr64_signal_with_error(
+ group->syncobjs->kmap + (i * PANTHOR_SYNCOBJ64_SIZE),
+ atomic64_read(&queue->fence_ctx.seqno),
+ ~0);
+
sched_queue_work(group->ptdev->scheduler, sync_upd);
}
dma_fence_end_signalling(cookie);
@@ -2461,28 +2373,32 @@ static void tick_work(struct work_struct *work)
static int panthor_queue_eval_syncwait(struct panthor_group *group, u8 queue_idx)
{
struct panthor_queue *queue = group->queues[queue_idx];
- union {
- struct panthor_syncobj_64b sync64;
- struct panthor_syncobj_32b sync32;
- } *syncobj;
+ struct panthor_syncobj *syncobj;
bool result;
u64 value;
- syncobj = panthor_queue_get_syncwait_obj(group, queue);
- if (!syncobj)
- return -EINVAL;
+ if (!queue->syncwait.syncobj) {
+ syncobj = panthor_syncobj_create(group->ptdev,
+ group->vm,
+ queue->syncwait.gpu_va,
+ queue->syncwait.sync64);
+ if (IS_ERR_OR_NULL(syncobj))
+ return PTR_ERR(syncobj);
- value = queue->syncwait.sync64 ?
- syncobj->sync64.seqno :
- syncobj->sync32.seqno;
+ queue->syncwait.syncobj = syncobj;
+ }
+
+ value = panthor_syncobj_get_value(queue->syncwait.syncobj);
if (queue->syncwait.gt)
result = value > queue->syncwait.ref;
else
result = value <= queue->syncwait.ref;
- if (result)
- panthor_queue_put_syncwait_obj(queue);
+ if (result) {
+ panthor_syncobj_release(queue->syncwait.syncobj);
+ queue->syncwait.syncobj = NULL;
+ }
return result;
}
@@ -2887,16 +2803,22 @@ static void group_sync_upd_work(struct work_struct *work)
cookie = dma_fence_begin_signalling();
for (queue_idx = 0; queue_idx < group->queue_count; queue_idx++) {
struct panthor_queue *queue = group->queues[queue_idx];
- struct panthor_syncobj_64b *syncobj;
+ void *syncobj;
if (!queue)
continue;
- syncobj = group->syncobjs->kmap + (queue_idx * sizeof(*syncobj));
+ syncobj = group->syncobjs->kmap + (queue_idx * PANTHOR_SYNCOBJ64_SIZE);
spin_lock(&queue->fence_ctx.lock);
list_for_each_entry_safe(job, job_tmp, &queue->fence_ctx.in_flight_jobs, node) {
- if (syncobj->seqno < job->done_fence->seqno)
+ u64 value;
+
+ if (!job->call_info.size)
+ continue;
+
+ value = panthor_syncobj_ptr64_get_value(syncobj);
+ if (value < job->done_fence->seqno)
break;
list_move_tail(&job->node, &done_jobs);
@@ -2928,7 +2850,7 @@ queue_run_job(struct drm_sched_job *sched_job)
ptdev->csif_info.unpreserved_cs_reg_count;
u64 val_reg = addr_reg + 2;
u64 sync_addr = panthor_kernel_bo_gpuva(group->syncobjs) +
- job->queue_idx * sizeof(struct panthor_syncobj_64b);
+ job->queue_idx * PANTHOR_SYNCOBJ64_SIZE;
u32 waitall_mask = GENMASK(sched->sb_slot_count - 1, 0);
struct dma_fence *done_fence;
int ret;
@@ -3289,7 +3211,7 @@ int panthor_group_create(struct panthor_file *pfile,
if (!group->user_submit) {
group->syncobjs = panthor_kernel_bo_create(ptdev, group->vm,
group_args->queues.count *
- sizeof(struct panthor_syncobj_64b),
+ PANTHOR_SYNCOBJ64_SIZE,
DRM_PANTHOR_BO_NO_MMAP,
DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC |
DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED,
@@ -3304,7 +3226,7 @@ int panthor_group_create(struct panthor_file *pfile,
goto err_put_group;
memset(group->syncobjs->kmap, 0,
- group_args->queues.count * sizeof(struct panthor_syncobj_64b));
+ group_args->queues.count * PANTHOR_SYNCOBJ64_SIZE);
}
for (i = 0; i < group_args->queues.count; i++) {
new file mode 100644
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0 or MIT
+/* Copyright 2024 ARM Limited. All rights reserved. */
+
+#include <linux/iosys-map.h>
+
+#include "panthor_device.h"
+#include "panthor_gem.h"
+#include "panthor_mmu.h"
+#include "panthor_syncobj.h"
+
+/**
+ * struct panthor_syncobj_32b - 32-bit FW synchronization object
+ */
+struct panthor_syncobj_32b {
+ /** @value: Value field. */
+ u32 value;
+
+ /**
+ * @error: Error status.
+ *
+ * Not zero on failure.
+ */
+ u32 error;
+};
+
+/**
+ * struct panthor_syncobj_64b - 64-bit FW synchronization object
+ */
+struct panthor_syncobj_64b {
+ /** @value: Value field. */
+ u64 value;
+
+ /**
+ * @error: Error status.
+ *
+ * Not zero on failure.
+ */
+ u32 error;
+
+ /** @pad: MBZ. */
+ u32 pad;
+};
+
+struct panthor_syncobj {
+ /** @bo: Buffer object holding the synchronization object. */
+ struct drm_gem_object *bo;
+
+ /** @offset: Offset of the synchronization object inside @bo. */
+ u64 offset;
+
+ /**
+ * @kmap: Kernel mapping of the buffer object holding the
+ * synchronization object.
+ */
+ void *kmap;
+
+ /** @ptr: CPU ptr to synchronization object */
+ union {
+ struct panthor_syncobj_64b sync64;
+ struct panthor_syncobj_32b sync32;
+ } *ptr;
+
+ /** @sync64: true for 64-bit synchronization object, otherwise 32-bit */
+ bool sync64;
+};
+
+
+
+struct panthor_syncobj *panthor_syncobj_create(struct panthor_device *ptdev,
+ struct panthor_vm *vm, u64 gpu_va,
+ bool sync64)
+{
+ struct panthor_gem_object *bo;
+ struct iosys_map map;
+ struct panthor_syncobj *syncobj;
+ int err;
+
+ syncobj = kzalloc(sizeof(*syncobj), GFP_KERNEL);
+ if (!syncobj) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ bo = panthor_vm_get_bo_for_va(vm, gpu_va, &syncobj->offset);
+ if (drm_WARN_ON(&ptdev->base, IS_ERR_OR_NULL(bo))) {
+ err = -EINVAL;
+ goto err_free_syncobj;
+ }
+
+ syncobj->bo = &bo->base.base;
+
+ err = drm_gem_vmap_unlocked(syncobj->bo, &map);
+ if (drm_WARN_ON(&ptdev->base, err))
+ goto err_put_gem_object;
+
+ syncobj->kmap = map.vaddr;
+ syncobj->ptr = syncobj->kmap + syncobj->offset;
+ syncobj->sync64 = sync64;
+
+ return syncobj;
+
+err_put_gem_object:
+ drm_gem_object_put(syncobj->bo);
+err_free_syncobj:
+ kfree(syncobj);
+err:
+ return ERR_PTR(err);
+}
+
+void panthor_syncobj_release(struct panthor_syncobj *syncobj)
+{
+ if (syncobj) {
+ struct iosys_map map = IOSYS_MAP_INIT_VADDR(syncobj->kmap);
+
+ drm_gem_vunmap_unlocked(syncobj->bo, &map);
+ drm_gem_object_put(syncobj->bo);
+ kfree(syncobj);
+ }
+}
+
+u64 panthor_syncobj_get_value(struct panthor_syncobj *syncobj)
+{
+ return syncobj->sync64 ?
+ syncobj->ptr->sync64.value :
+ syncobj->ptr->sync32.value;
+}
+
+u32 panthor_syncobj_get_error(struct panthor_syncobj *syncobj)
+{
+ return syncobj->sync64 ?
+ syncobj->ptr->sync64.error :
+ syncobj->ptr->sync32.error;
+}
+
+void panthor_syncobj_signal(struct panthor_syncobj *syncobj, u64 value)
+{
+ if (syncobj->sync64)
+ syncobj->ptr->sync64.value = value;
+ else
+ syncobj->ptr->sync32.value = (u32)value;
+}
+
+void panthor_syncobj_signal_with_error(struct panthor_syncobj *syncobj, u64 value, u32 error)
+{
+ if (syncobj->sync64) {
+ syncobj->ptr->sync64.value = value;
+ syncobj->ptr->sync64.error = error;
+ } else {
+ syncobj->ptr->sync32.value = (u32)value;
+ syncobj->ptr->sync32.error = error;
+ }
+}
+
+u64 panthor_syncobj_ptr64_get_value(void *syncobj_ptr)
+{
+ struct panthor_syncobj_64b *syncobj = syncobj_ptr;
+
+ return syncobj->value;
+}
+
+void panthor_syncobj_ptr64_signal_with_error(void *syncobj_ptr, u64 value, u32 error)
+{
+ struct panthor_syncobj_64b *syncobj = syncobj_ptr;
+
+ syncobj->value = value;
+ syncobj->error = error;
+}
new file mode 100644
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 or MIT */
+/* Copyright 2024 ARM Limited. All rights reserved. */
+
+#ifndef __PANTHOR_SYNCOBJ_H__
+#define __PANTHOR_SYNCOBJ_H__
+
+#define PANTHOR_SYNCOBJ32_SIZE 8
+#define PANTHOR_SYNCOBJ64_SIZE 16
+
+struct panthor_syncobj;
+struct panthor_vm;
+
+struct panthor_syncobj *panthor_syncobj_create(struct panthor_device *ptdev,
+ struct panthor_vm *vm, u64 gpu_va,
+ bool sync64);
+void panthor_syncobj_release(struct panthor_syncobj *syncobj);
+
+u64 panthor_syncobj_get_value(struct panthor_syncobj *syncobj);
+u32 panthor_syncobj_get_error(struct panthor_syncobj *syncobj);
+
+void panthor_syncobj_signal(struct panthor_syncobj *syncobj, u64 value);
+void panthor_syncobj_signal_with_error(struct panthor_syncobj *syncobj, u64 value, u32 error);
+
+u64 panthor_syncobj_ptr64_get_value(void *syncobj_ptr);
+void panthor_syncobj_ptr64_signal_with_error(void *syncobj_ptr, u64 value, u32 error);
+
+#endif