Hi,

On Fri, 12 Sept 2025 at 19:20, Daniel Almeida
<[email protected]> wrote:
> +igt_main {
> +       igt_describe("Create a buffer object");
> +       igt_subtest("bo_create") {
> +               struct panthor_bo bo;
> +
> +               igt_panthor_bo_create(fd, &bo, 4096, 0, 0);
> +               igt_assert(bo.handle != 0);

Please - here and everywhere else - use the specific igt_assert_*()
macros. Those print out the actual values, so are much more useful
when debugging.

> +       igt_describe_f("Create a buffer object whose size is not 
> page-aligned, and check "
> +               "that the allocated size is rounded up to the next page size 
> %lu.",
> +               8192UL);
> +       igt_subtest("bo_create_round_size") {
> +               struct panthor_bo bo;
> +               uint64_t expected_size = 8192;

Shouldn't this be based on the actual page size in use?

> +static void
> +issue_store_multiple(u8 *command_stream, uint64_t kernel_va, uint32_t 
> constant)
> +{
> +               uint64_t opcode, reg_num, mov48, store_multiple, flush;
> +               uint64_t sr, src0, register_bitmap, offset;
> +
> +               // MOV48: Load the source register ([r68; r69]) with the 
> kernel address
> +               opcode = 0x1;
> +               reg_num = 68;
> +               mov48 = (opcode << 56) | (reg_num << 48) | kernel_va;
> +               mov48 = htole64(mov48);
> +               memcpy(&command_stream[0], &mov48, sizeof(mov48));
> +
> +               // MOV48: Load a known constant into r70
> +               opcode = 0x1;
> +               reg_num = 70;
> +               mov48 = (opcode << 56) | (reg_num << 48) | constant;
> +               mov48 = htole64(mov48);
> +               memcpy(&command_stream[8], &mov48, sizeof(mov48));
> +
> +               // STORE_MULTIPLE: Store the first register to the address 
> pointed to by [r68; r69]
> +               opcode = 0x15; // STORE_MULTIPLE
> +               sr = 70; // Starting from register r70
> +               src0 = 68; // Address pointed to by [r68; r69]
> +               register_bitmap = 1; // Store the first register
> +               offset = 0; // Offset
> +               store_multiple = (opcode << 56) | (sr << 48) | (src0 << 40) |
> +                                                                             
>    (register_bitmap << 16) | offset;
> +               store_multiple = htole64(store_multiple);
> +               memcpy(&command_stream[16], &store_multiple, 
> sizeof(store_multiple));

// MOV48 r68, 0 on the below?

> +               opcode = 0x1;
> +               reg_num = 68;
> +               mov48 = (opcode << 56) | (reg_num << 48) | 0;
> +               mov48 = htole64(mov48);
> +               memcpy(&command_stream[24], &mov48, sizeof(mov48));

// FLUSH_PAGES?

> +               opcode = 36;
> +               flush = opcode << 56 | 0ull << 48 | reg_num << 40 | 0ull << 
> 16 | 0x233;
> +               flush = htole64(flush);
> +               memcpy(&command_stream[32], &flush, sizeof(flush));
> +}


> +               group_create.queues = queues;
> +               group_create.max_compute_cores = 1;
> +               group_create.max_fragment_cores = 1;
> +               group_create.max_tiler_cores = 1;
> +               group_create.priority = PANTHOR_GROUP_PRIORITY_MEDIUM;
> +               group_create.compute_core_mask = gpu_info.shader_present & 
> 0x1; // Use first core
> +               group_create.fragment_core_mask = gpu_info.shader_present & 
> 0x1; // Use first core
> +               group_create.tiler_core_mask = gpu_info.tiler_present & 0x1; 
> // Use first tiler

This will either be 0 (rejected) or 1 (possibly valid but possibly
not). Did you mean (1 << ffs(...))? Same issue below, so maybe this
wants a little helper.

> +               igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_PANTHOR_GROUP_CREATE, 
> &group_create), 0);
> +               igt_assert(group_create.group_handle != 0);
> +
> +               // Cleanup: Destroy the group and VM

igt does use /* */ rather than // everywhere, if you're respinning anyway.

> +               group_destroy = (struct drm_panthor_group_destroy){
> +                       .group_handle = group_create.group_handle
> +               };
> +               igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_PANTHOR_GROUP_DESTROY, 
> &group_destroy), 0);

do_ioctl() - here and elsewhere.

> +       igt_subtest("group_submit") {
> +               struct drm_panthor_gpu_info gpu_info = {};
> +               struct drm_panthor_vm_create vm_create = {};
> +               struct drm_panthor_group_create group_create = {};
> +               struct drm_panthor_queue_create queue = {};
> +               struct drm_panthor_obj_array queues = {};
> +               struct drm_panthor_group_submit group_submit = {};
> +               struct drm_panthor_queue_submit queue_submit = {};
> +               struct drm_panthor_group_destroy group_destroy = {};
> +               struct drm_panthor_obj_array queue_submits = {};
> +               struct drm_panthor_vm_destroy vm_destroy = {};
> +               struct drm_panthor_bo_create bo_create = {};
> +               struct drm_panthor_vm_bind vm_bind = {};
> +               struct drm_panthor_vm_bind_op vm_bind_op = {};
> +               struct drm_syncobj_wait wait = {};
> +               struct drm_syncobj_create syncobj_create = {};
> +               struct drm_panthor_sync_op sync_op = {};
> +               struct drm_gem_close gem_close = {};
> +               struct drm_syncobj_destroy syncobj_destroy = {};
> +               uint64_t command_stream_gpu_addr;
> +               uint32_t command_stream_size;
> +               uint64_t result_gpu_addr;
> +               uint32_t cmd_buf_bo_handle;
> +               uint32_t result_bo_handle;
> +               uint32_t syncobj_handle;
> +               uint8_t command_stream[64] = {0};
> +               uint8_t *bo_cpu_addr;
> +               uint8_t *result_cpu_addr;
> +               const int INITIAL_VA = 0x1000000;
> +               uint64_t bo_mmap_offset;
> +
> +               igt_panthor_query(fd, DRM_PANTHOR_DEV_QUERY_GPU_INFO,
> +                                 &gpu_info, sizeof(gpu_info), 0);
> +               igt_assert(gpu_info.gpu_id != 0);
> +
> +               vm_create.flags = 0;
> +               igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_PANTHOR_VM_CREATE, 
> &vm_create), 0);
> +               igt_assert(vm_create.id != 0);
> +
> +               bo_create.size = 4096;
> +               bo_create.flags = 0;
> +               bo_create.exclusive_vm_id = vm_create.id;
> +               igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_PANTHOR_BO_CREATE, 
> &bo_create), 0);
> +               igt_assert(bo_create.handle != 0);
> +               cmd_buf_bo_handle = bo_create.handle;

Why not use the helpers here?

> +               wait = (struct drm_syncobj_wait) {
> +                       .handles = (uint64_t)&syncobj_handle,
> +                       .count_handles = 1,
> +                       .timeout_nsec = INT64_MAX,
> +                       .flags = 0,
> +               };
> +
> +               igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &wait), 
> 0);

Similarly, syncobj_create() and syncobj_wait().

Thanks a lot for writing this up. Having more negative cases would be
really nice, but this is a really good start, so I'm happy for it to
land once it's been cleaned up.

Cheers,
Daniel

Reply via email to