All of lore.kernel.org
 help / color / mirror / Atom feed
From: Oak Zeng <oak.zeng@intel.com>
To: igt-dev@lists.freedesktop.org
Cc: Thomas.Hellstrom@linux.intel.com, matthew.brost@intel.com,
	kamil.konieczny@intel.com, zbigniew.kempczynski@intel.com,
	ashutosh.dixit@intel.com, juha-pekka.heikkila@intel.com,
	rodrigo.vivi@intel.com
Subject: [i-g-t v3 2/4] lib/xe/xe_util: Introduce helper functions
Date: Tue, 18 Feb 2025 18:57:53 -0500	[thread overview]
Message-ID: <20250218235755.360264-3-oak.zeng@intel.com> (raw)
In-Reply-To: <20250218235755.360264-1-oak.zeng@intel.com>

From: Bommu Krishnaiah <krishnaiah.bommu@intel.com>

Introduce helper functions for buffer creation, binding,
destruction and command submission etc. With those helpers,
writing a xe igt test will be much easier, which will be
showed in a coming example.

v2: use to_user_pointer to cast a pointer (Kamil)
    s/insert_store/xe_insert_store (Kamil)
    s/cmdbuf_fill_func_t/xe_cmdbuf_fill_func_t (Kamil)
v3: refactor command buffer fill interface (Zbigniew)

Signed-off-by: Bommu Krishnaiah <krishnaiah.bommu@intel.com>
Signed-off-by: Oak Zeng <oak.zeng@intel.com>
Cc: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
---
 lib/xe/xe_util.c | 239 +++++++++++++++++++++++++++++++++++++++++++++++
 lib/xe/xe_util.h |  47 ++++++++++
 2 files changed, 286 insertions(+)

diff --git a/lib/xe/xe_util.c b/lib/xe/xe_util.c
index 06b378ce0..891316ecd 100644
--- a/lib/xe/xe_util.c
+++ b/lib/xe/xe_util.c
@@ -13,6 +13,245 @@
 #include "xe/xe_query.h"
 #include "xe/xe_util.h"
 
+/**
+ * xe_cmdbuf_exec_ufence_gpuva:
+ * @cmdbuf Pointer to the xe_cmdbuf structure representing the command buffer.
+ *
+ * Returns the GPU virtual address of the execution user fence located at the
+ * end of the command buffer.
+ */
+static uint64_t xe_cmdbuf_exec_ufence_gpuva(struct xe_cmdbuf *cmdbuf)
+{
+	/* the last 8 bytes of the cmd buffer is used as ufence */
+	return cmdbuf->buf.gpu_addr + cmdbuf->buf.size - UFENCE_LENGTH;
+}
+
+/**
+ * xe_cmdbuf_exec_ufence_cpuva:
+ * @cmdbuf Pointer to the xe_cmdbuf structure representing the command buffer.
+ *
+ * Returns the CPU virtual address of the execution user fence located at the
+ * end of the command buffer.
+ */
+static void *xe_cmdbuf_exec_ufence_cpuva(struct xe_cmdbuf *cmdbuf)
+{
+	/* the last 8 bytes of the cmd buffer is used as ufence */
+	return (char *)cmdbuf->buf.cpu_addr + cmdbuf->buf.size - UFENCE_LENGTH;
+}
+
+
+/**
+ * __xe_submit_cmd:
+ * @cmdbuf Pointer to the command buffer structure
+ *
+ * Submits a command buffer to the GPU, waits for its completion, and verifies
+ * the user fence value
+ *
+ * Return: The result of waiting for the user fence value
+ */
+int64_t __xe_submit_cmd(struct xe_cmdbuf *cmdbuf)
+{
+	int64_t timeout = NSEC_PER_SEC;
+	int ret;
+
+	struct drm_xe_sync sync[1] = {
+		{ .type = DRM_XE_SYNC_TYPE_USER_FENCE,
+			.flags = DRM_XE_SYNC_FLAG_SIGNAL,
+			.timeline_value = USER_FENCE_VALUE,
+			.addr = xe_cmdbuf_exec_ufence_gpuva(cmdbuf),},
+	};
+	struct drm_xe_exec exec = {
+		.num_batch_buffer = 1,
+		.num_syncs = 1,
+		.syncs = to_user_pointer(sync),
+		.exec_queue_id = cmdbuf->exec_queue,
+		.address = cmdbuf->buf.gpu_addr,
+	};
+
+	xe_exec(cmdbuf->buf.fd, &exec);
+	ret = __xe_wait_ufence(cmdbuf->buf.fd,
+			       (uint64_t *)xe_cmdbuf_exec_ufence_cpuva(cmdbuf),
+			       USER_FENCE_VALUE, cmdbuf->exec_queue, &timeout);
+	/* Reset the fence so the exec ufence can be reused */
+	memset((char *)xe_cmdbuf_exec_ufence_cpuva(cmdbuf), 0, UFENCE_LENGTH);
+	return ret;
+}
+
+/**
+ * xe_submit_cmd:
+ * @cmdbuf Pointer to the command buffer structure
+ *
+ * Wrapper function to submit a command buffer and assert its successful
+ * execution.
+ */
+void xe_submit_cmd(struct xe_cmdbuf *cmdbuf)
+{
+	int64_t ret;
+
+	ret = __xe_submit_cmd(cmdbuf);
+	igt_assert_eq(ret, 0);
+}
+
+/**
+ *xe_create_buffer:
+ * @buffer Pointer to the xe_buf structure containing buffer details.
+ *
+ * Creates a buffer, maps it to both CPU and GPU address spaces, and binds it
+ * to a virtual memory (VM) space.
+ */
+void xe_create_buffer(struct xe_buf *buffer)
+{
+	struct drm_xe_sync sync[1] = {
+		{ .type = DRM_XE_SYNC_TYPE_USER_FENCE,
+		  .flags = DRM_XE_SYNC_FLAG_SIGNAL,
+		  .timeline_value = USER_FENCE_VALUE },
+	};
+
+	buffer->bind_queue = xe_bind_exec_queue_create(buffer->fd,
+						       buffer->vm, 0);
+	buffer->bind_ufence = aligned_alloc(xe_get_default_alignment(buffer->fd),
+					    PAGE_ALIGN_UFENCE);
+	sync->addr = to_user_pointer(buffer->bind_ufence);
+
+
+	/* create and bind the buffer->bo */
+	buffer->bo = xe_bo_create(buffer->fd, 0, buffer->size,
+				  buffer->placement, buffer->flag);
+	buffer->cpu_addr = xe_bo_map(buffer->fd, buffer->bo, buffer->size);
+	xe_vm_bind_async(buffer->fd, buffer->vm, buffer->bind_queue,
+			 buffer->bo, 0, buffer->gpu_addr,
+			 buffer->size, sync, 1);
+
+	xe_wait_ufence(buffer->fd, buffer->bind_ufence,
+		       USER_FENCE_VALUE, buffer->bind_queue, NSEC_PER_SEC);
+	memset(buffer->bind_ufence, 0, PAGE_ALIGN_UFENCE);
+}
+
+/**
+ * xe_destroy_buffer:
+ * @buffer Pointer to the xe_buf structure containing buffer details
+ *
+ * Destroys a buffer created by xe_create_buffer and releases associated
+ * resources.
+ */
+void xe_destroy_buffer(struct xe_buf *buffer)
+{
+	struct drm_xe_sync sync[1] = {
+		{ .type = DRM_XE_SYNC_TYPE_USER_FENCE,
+		  .flags = DRM_XE_SYNC_FLAG_SIGNAL,
+		  .timeline_value = USER_FENCE_VALUE },
+	};
+	sync->addr = to_user_pointer(buffer->bind_ufence);
+
+	xe_vm_unbind_async(buffer->fd, buffer->vm, buffer->bind_queue,
+			   0, buffer->gpu_addr, buffer->size, sync, 1);
+	xe_wait_ufence(buffer->fd, buffer->bind_ufence,
+		       USER_FENCE_VALUE, buffer->bind_queue, NSEC_PER_SEC);
+	memset(buffer->bind_ufence, 0, PAGE_ALIGN_UFENCE);
+
+	munmap(buffer->cpu_addr, buffer->size);
+	gem_close(buffer->fd, buffer->bo);
+
+	free(buffer->bind_ufence);
+	xe_exec_queue_destroy(buffer->fd, buffer->bind_queue);
+}
+
+/**
+ * xe_cmdbuf_insert_store:
+ * @cmdbuf: command buffer where commands will be inserted.
+ * @dst_va Destination virtual address to store the value.
+ * @val Value to be stored.
+ *
+ * Inserts a MI_STORE_DWORD_IMM_GEN4 command into a command  buffer, which stores
+ * an immediate value to a given destination virtual address.
+ */
+void xe_cmdbuf_insert_store(struct xe_cmdbuf *cmdbuf,
+			    uint64_t dst_va, uint32_t val)
+{
+	uint32_t *batch = cmdbuf->buf.cpu_addr;
+
+	igt_assert(!cmdbuf->closed);
+
+	batch[cmdbuf->write_index++] = MI_STORE_DWORD_IMM_GEN4;
+	batch[cmdbuf->write_index++] = dst_va;
+	batch[cmdbuf->write_index++] = dst_va >> 32;
+	batch[cmdbuf->write_index++] = val;
+
+	/* Leaves at least one dword for MI_BATCH_BUFFER_END */
+	igt_assert(cmdbuf->write_index <= cmdbuf->cmd_size/sizeof(uint32_t) - 2);
+}
+
+/**
+ * xe_create_cmdbuf:
+ * @cmdbuf Pointer to the xe_cmdbuf structure representing the command buffer.
+ * @eci Pointer to the engine class instance for execution.
+ *
+ * Creates a command buffer, fills it with commands using the provided fill
+ * function, and sets up the execution queue for submission.
+ */
+void xe_create_cmdbuf(struct xe_cmdbuf *cmdbuf,
+		       struct drm_xe_engine_class_instance *eci)
+{
+	struct xe_buf *buf = &cmdbuf->buf;
+	/*
+	 * make some room for a exec_ufence, which will be used to sync the
+	 * submission of this command....
+	 */
+	buf->size = xe_bb_size(buf->fd,
+			       cmdbuf->cmd_size + PAGE_ALIGN_UFENCE);
+	xe_create_buffer(buf);
+	cmdbuf->exec_queue = xe_exec_queue_create(buf->fd, buf->vm, eci, 0);
+	cmdbuf->write_index = 0;
+	cmdbuf->closed = false;
+}
+
+/**
+ * xe_fill_cmdbuf:
+ * @cmdbuf Pointer to the xe_cmdbuf structure representing the command buffer.
+ * @fill_func Pointer to the function that fills the command buffer.
+ * @dst_gpu_va Destination GPU virtual address to store the value.
+ * @val Value to be stored.
+ *
+ * Fills the command buffer with commands using the provided fill function.
+ */
+void xe_fill_cmdbuf(struct xe_cmdbuf *cmdbuf,
+			xe_cmdbuf_fill_func_t fill_func,
+			uint64_t dst_gpu_va, uint32_t val)
+{
+	igt_assert(!cmdbuf->closed);
+	fill_func(cmdbuf, dst_gpu_va, val);
+}
+
+/**
+ * xe_close_cmdbuf:
+ * @cmdbuf command buffer to be closed.
+ *
+ * After this function is called, no more commands can be added to the
+ * command buffer.
+ */
+void xe_close_cmdbuf(struct xe_cmdbuf *cmdbuf)
+{
+	uint32_t *batch = cmdbuf->buf.cpu_addr;
+
+	igt_assert(!cmdbuf->closed);
+	batch[cmdbuf->write_index++] = MI_BATCH_BUFFER_END;
+	cmdbuf->closed = true;
+	igt_assert(cmdbuf->write_index <= cmdbuf->cmd_size/sizeof(uint32_t) - 1);
+}
+
+/**
+ * xe_destroy_cmdbuf:
+ * @cmdbuf Pointer to the xe_buf structure representing the command buffer.
+ *
+ * Destroys a command buffer created by xe_create_cmdbuf and releases
+ * associated resources.
+ */
+void xe_destroy_cmdbuf(struct xe_cmdbuf *cmdbuf)
+{
+	xe_exec_queue_destroy(cmdbuf->buf.fd, cmdbuf->exec_queue);
+	xe_destroy_buffer(&cmdbuf->buf);
+}
+
 static bool __region_belongs_to_regions_type(struct drm_xe_mem_region *region,
 					     uint32_t *mem_regions_type,
 					     int num_regions)
diff --git a/lib/xe/xe_util.h b/lib/xe/xe_util.h
index 06ebd3c2a..26321f957 100644
--- a/lib/xe/xe_util.h
+++ b/lib/xe/xe_util.h
@@ -14,6 +14,53 @@
 
 #include "xe_query.h"
 
+#define USER_FENCE_VALUE        0xdeadbeefdeadbeefull
+#define PAGE_ALIGN_UFENCE	4096
+#define UFENCE_LENGTH		8
+
+struct xe_buf {
+	void *cpu_addr;
+	uint64_t gpu_addr;
+	/*the user fence used to vm bind this buffer*/
+	uint64_t *bind_ufence;
+	uint64_t size;
+	uint32_t flag;
+	uint32_t vm;
+	uint32_t bo;
+	uint32_t placement;
+	uint32_t bind_queue;
+	int fd;
+	bool is_userptr;
+};
+
+struct xe_cmdbuf {
+	struct xe_buf buf;
+	/* command size in bytes, not including exec_ufence */
+	uint64_t cmd_size;
+	uint32_t exec_queue;
+	/* Dword index to writ to command buffer */
+	uint32_t write_index;
+	bool closed;
+};
+
+typedef void (*xe_cmdbuf_fill_func_t) (struct xe_cmdbuf *cmdbuf,
+				       uint64_t dst_gpu_va, uint32_t val);
+
+void xe_create_buffer(struct xe_buf *buffer);
+void xe_destroy_buffer(struct xe_buf *buffer);
+
+void xe_create_cmdbuf(struct xe_cmdbuf *cmdbuf,
+		      struct drm_xe_engine_class_instance *eci);
+void xe_fill_cmdbuf(struct xe_cmdbuf *cmdbuf,
+			xe_cmdbuf_fill_func_t fill_func,
+			uint64_t dst_gpu_va, uint32_t val);
+void xe_close_cmdbuf(struct xe_cmdbuf *cmdbuf);
+void xe_cmdbuf_insert_store(struct xe_cmdbuf *cmdbuf, uint64_t dst_va,
+			    uint32_t val);
+void xe_submit_cmd(struct xe_cmdbuf *cmdbuf);
+int64_t __xe_submit_cmd(struct xe_cmdbuf *cmdbuf);
+void xe_destroy_cmdbuf(struct xe_cmdbuf *cmdbuf);
+
 #define XE_IS_SYSMEM_MEMORY_REGION(fd, region) \
 	(xe_region_class(fd, region) == DRM_XE_MEM_REGION_CLASS_SYSMEM)
 #define XE_IS_VRAM_MEMORY_REGION(fd, region) \
-- 
2.26.3


  parent reply	other threads:[~2025-02-18 23:42 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-18 23:57 [i-g-t v3 0/4] xe: Test scratch page under fault mode Oak Zeng
2025-02-18 23:57 ` [i-g-t v3 1/4] lib/xe: Fix a comment error Oak Zeng
2025-02-18 23:57 ` Oak Zeng [this message]
2025-02-20  7:15   ` [i-g-t v3 2/4] lib/xe/xe_util: Introduce helper functions Zbigniew Kempczyński
2025-02-20 23:29     ` Zeng, Oak
2025-02-18 23:57 ` [i-g-t v3 3/4] tests/intel/xe_vm: Exclude invalid_flags tests from LNL and BMG Oak Zeng
2025-02-18 23:57 ` [i-g-t v3 4/4] tests/intel/xe_exec_fault_mode: Test scratch page under fault mode Oak Zeng
2025-02-19  1:11 ` ✓ i915.CI.BAT: success for xe: Test scratch page under fault mode (rev2) Patchwork
2025-02-19  1:12 ` ✓ Xe.CI.BAT: " Patchwork
2025-02-19  3:23 ` ✗ i915.CI.Full: failure " Patchwork
2025-02-19 22:40 ` ✗ Xe.CI.Full: " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250218235755.360264-3-oak.zeng@intel.com \
    --to=oak.zeng@intel.com \
    --cc=Thomas.Hellstrom@linux.intel.com \
    --cc=ashutosh.dixit@intel.com \
    --cc=igt-dev@lists.freedesktop.org \
    --cc=juha-pekka.heikkila@intel.com \
    --cc=kamil.konieczny@intel.com \
    --cc=matthew.brost@intel.com \
    --cc=rodrigo.vivi@intel.com \
    --cc=zbigniew.kempczynski@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.