Igt-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Stone <daniels@collabora.com>
To: igt-dev@lists.freedesktop.org
Cc: boris.brezillon@collabora.com, laura.nao@collabora.com,
	adrian.larumbe@collabora.com, daniel.almeida@collabora.com,
	liviu.dudau@arm.com
Subject: [PATCH 4/4] panthor: Add simple compute-shader test
Date: Thu, 15 Oct 2026 14:05:49 +0100	[thread overview]
Message-ID: <20261015130837.710795-5-daniels@collabora.com> (raw)
In-Reply-To: <20261015130837.710795-1-daniels@collabora.com>

This test launches a compute shader which performs RMW on a memory
array, to check that we can actually launch jobs and see the results.

Signed-off-by: Daniel Stone <daniels@collabora.com>
---
 lib/igt_panthor.h             | 204 +++++++++++++++++++++++++++++
 tests/panthor/panthor_group.c | 240 ++++++++++++++++++++++++++++++++++
 2 files changed, 444 insertions(+)

diff --git a/lib/igt_panthor.h b/lib/igt_panthor.h
index dfeb0ac60..35882fad7 100644
--- a/lib/igt_panthor.h
+++ b/lib/igt_panthor.h
@@ -363,4 +363,208 @@ cs_error_barrier(void)
 	return instr.raw;
 }
 
+struct gpu_src_reg {
+	uint8_t reg;
+	bool last;
+	uint8_t rep;
+};
+
+struct gpu_dst_reg {
+	uint8_t reg;
+};
+
+enum gpu_flow_ctrl {
+	FLOW_NONE = 0,
+	FLOW_WAIT0 = 0x1,
+	FLOW_WAIT1 = 0x2,
+	FLOW_WAIT01 = 0x3,
+	FLOW_WAIT2 = 0x4,
+	FLOW_WAIT02 = 0x5,
+	FLOW_WAIT12 = 0x6,
+	FLOW_WAIT012 = 0x7,
+	FLOW_WAIT0126 = 0x8,
+	FLOW_WAIT = 0x9,
+	FLOW_RECONVERGE = 0xa,
+	FLOW_WAIT_RESOURCE = 0xc,
+	FLOW_DISCARD = 0xd,
+	FLOW_END = 0xf,
+};
+
+enum gpu_reg_width {
+	REG_WIDTH_LO16 = 0x1,
+	REG_WIDTH_HI16 = 0x2,
+	REG_WIDTH_32 = 0x3,
+};
+
+static inline struct gpu_dst_reg
+gpu_dst_reg(uint8_t reg)
+{
+	struct gpu_dst_reg ret = {
+		.reg = reg
+	};
+	return ret;
+}
+
+static inline struct gpu_src_reg
+gpu_src_zero(void)
+{
+	struct gpu_src_reg ret = {
+		.reg = 255, /* architecturally invalid */
+		.last = false,
+		.rep = (0x3 << 6),
+	};
+	return ret;
+}
+
+static inline struct gpu_src_reg
+gpu_src_reg(uint8_t reg)
+{
+	struct gpu_src_reg ret = {
+		.reg = reg,
+		.last = false,
+		.rep = reg,
+	};
+	return ret;
+}
+
+static inline struct gpu_src_reg
+gpu_src_reg_last(uint8_t reg)
+{
+	struct gpu_src_reg ret = {
+		.reg = reg,
+		.last = true,
+		.rep = (reg | (1 << 6)),
+	};
+	return ret;
+}
+
+#define ins(x, v, s) x |= ((uint64_t) v << s)
+
+static inline uint64_t
+gpu_mov_imm_i32(struct gpu_dst_reg dst, int32_t imm, enum gpu_flow_ctrl flow)
+{
+	uint64_t ret = 0;
+	ins(ret, gpu_src_zero().rep, 0);
+	ins(ret, imm, 8);
+	ins(ret, dst.reg, 40);
+	ins(ret, REG_WIDTH_32, 46);
+	ins(ret, 0x0, 48); /* opcode */
+	ins(ret, 0x11, 52); /* class */
+	ins(ret, 0x0, 57); /* FAU */
+	ins(ret, flow, 59);
+	return ret;
+}
+
+static inline uint64_t
+gpu_lshift_or_i32(struct gpu_dst_reg dst, struct gpu_src_reg src,
+		  struct gpu_src_reg shift, struct gpu_src_reg or,
+		  enum gpu_flow_ctrl flow)
+{
+	uint64_t ret = 0;
+	ins(ret, src.rep, 0);
+	ins(ret, shift.rep, 8);
+	ins(ret, or.rep, 16);
+	ins(ret, 0x1, 24); /* logicop = or */
+	ins(ret, 0x4, 26); /* lanes = b0 */
+	ins(ret, 0x0, 30); /* dst.not = false */
+	ins(ret, 0x1, 32); /* shift = left */
+	ins(ret, 0x0, 35); /* src2.not = false */
+	ins(ret, 0x0, 36); /* widen = false */
+	ins(ret, dst.reg, 40);
+	ins(ret, REG_WIDTH_32, 46);
+	ins(ret, 0x4, 48); /* opcode */
+	ins(ret, 0xb, 52); /* class */
+	ins(ret, 0x0, 57); /* FAU */
+	ins(ret, flow, 59);
+	return ret;
+}
+
+static inline uint64_t
+gpu_iadd_u32(struct gpu_dst_reg dst, struct gpu_src_reg left,
+	     struct gpu_src_reg right, enum gpu_flow_ctrl flow)
+{
+	uint64_t ret = 0;
+	ins(ret, left.rep, 0);
+	ins(ret, right.rep, 8);
+	ins(ret, 0x0, 16); /* opcode */
+	ins(ret, 0x0, 26); /* widen1 */
+	ins(ret, 0x0, 30); /* saturate */
+	ins(ret, 0x0, 36); /* widen0 */
+	ins(ret, dst.reg, 40);
+	ins(ret, REG_WIDTH_32, 46);
+	ins(ret, 0x0, 48); /* data type */
+	ins(ret, 0xa, 52); /* class */
+	ins(ret, 0x0, 57); /* FAU */
+	ins(ret, flow, 59);
+	return ret;
+}
+
+static inline uint64_t
+gpu_imul_u32(struct gpu_dst_reg dst, struct gpu_src_reg left,
+	     struct gpu_src_reg right, enum gpu_flow_ctrl flow)
+{
+	uint64_t ret = 0;
+	ins(ret, left.rep, 0);
+	ins(ret, right.rep, 8);
+	ins(ret, 0xa, 16); /* opcode */
+	ins(ret, 0x0, 26); /* widen1 */
+	ins(ret, 0x0, 30); /* saturate */
+	ins(ret, 0x0, 36); /* widen0 */
+	ins(ret, dst.reg, 40);
+	ins(ret, REG_WIDTH_32, 46);
+	ins(ret, 0x0, 48); /* data type */
+	ins(ret, 0xa, 52); /* class */
+	ins(ret, 0x0, 57); /* FAU */
+	ins(ret, flow, 59);
+	return ret;
+}
+
+static inline uint64_t
+gpu_load_i32(struct gpu_dst_reg dst, struct gpu_src_reg addr_lo,
+	     struct gpu_src_reg addr_hi, uint16_t offset,
+	     uint8_t sb_slot, enum gpu_flow_ctrl flow)
+{
+	uint64_t ret = 0;
+	igt_assert_eq(addr_hi.reg, addr_lo.reg + 1);
+	ins(ret, addr_lo.rep, 0);
+	ins(ret, offset, 8);
+	ins(ret, 0x0, 24); /* access mode */
+	ins(ret, REG_WIDTH_32, 27);
+	ins(ret, sb_slot, 30);
+	ins(ret, 0x1, 33); /* staging register count */
+	ins(ret, 0x0, 36); /* load 32 */
+	ins(ret, 0x1, 39); /* no sign extension */
+	ins(ret, dst.reg, 40); /* base staging register */
+	ins(ret, 0x2, 46); /* write staging registers */
+	ins(ret, 0x0, 48); /* opcode */
+	ins(ret, 0x6, 52); /* class */
+	ins(ret, 0x0, 57); /* FAU */
+	ins(ret, flow, 59);
+	return ret;
+}
+
+static inline uint64_t
+gpu_store_i32(struct gpu_src_reg addr_lo, struct gpu_src_reg addr_hi,
+	      struct gpu_src_reg val, uint16_t offset,
+	      uint8_t sb_slot, enum gpu_flow_ctrl flow)
+{
+	uint64_t ret = 0;
+	igt_assert_eq(addr_hi.reg, addr_lo.reg + 1);
+	ins(ret, addr_lo.rep, 0);
+	ins(ret, offset, 8);
+	ins(ret, 0x0, 24); /* access mode */
+	ins(ret, REG_WIDTH_32, 27);
+	ins(ret, sb_slot, 30);
+	ins(ret, 0x1, 33); /* staging register count */
+	ins(ret, val.reg, 40); /* base staging register */
+	ins(ret, 0x1, 46); /* read staging registers */
+	ins(ret, 0x1, 48); /* opcode */
+	ins(ret, 0x6, 52); /* class */
+	ins(ret, 0x0, 57); /* FAU */
+	ins(ret, flow, 59);
+	return ret;
+}
+
+#undef ins
+
 #endif /* IGT_PANTHOR_H */
diff --git a/tests/panthor/panthor_group.c b/tests/panthor/panthor_group.c
index c79f8d629..feca42482 100644
--- a/tests/panthor/panthor_group.c
+++ b/tests/panthor/panthor_group.c
@@ -10,6 +10,133 @@
 #include "igt_syncobj.h"
 #include "panthor_drm.h"
 
+/*
+ * Record a simple compute program:
+ * {
+ *     extern uint32_t shared_buf[num_invocations];
+ *     extern const uint32_t my_invocation_id;
+ *     shared_buf[my_invocation_id] *= my_invocation_id;
+ * }
+ */
+static void
+record_compute_prog(uint8_t *csf_cmdbuf, unsigned int *csf_cmdbuf_size,
+		    uint8_t *gpu_cmdbuf, unsigned int *gpu_cmdbuf_size,
+		    uint32_t srt_gpuva, uint32_t fau_gpuva, uint32_t spd_gpuva,
+		    uint32_t tsd_gpuva, uint32_t data_gpuva)
+{
+	const uint8_t reg_id_global_x = 60; /* preloaded */
+	const uint8_t reg_addr_lo = 0;
+	const uint8_t reg_addr_hi = 1;
+	const uint8_t reg_val = 2;
+	const uint8_t reg_offset = 3;
+	const uint8_t reg_shift = 4;
+	const uint8_t compute_sr_base = 0;
+	const uint8_t zero_reg = 40;
+
+	uint64_t gpu_instrs[] = {
+		/* MOV_IMM.i32 rADDRLO, 0x10000 */
+		gpu_mov_imm_i32(gpu_dst_reg(reg_addr_lo), data_gpuva, FLOW_NONE),
+		/* MOV_IMM.i32 rADDRHI, 0x0 */
+		gpu_mov_imm_i32(gpu_dst_reg(reg_addr_hi), 0x0, FLOW_NONE),
+		/* MOV_IMM.i32 rSHIFT, 0x2 */
+		gpu_mov_imm_i32(gpu_dst_reg(reg_shift), 0x2, FLOW_NONE),
+		/* LSHIFT_OR.i32 rOFFSET, rGLOBALID, rSHIFT^, 0x0 */
+		gpu_lshift_or_i32(gpu_dst_reg(reg_offset),
+				  gpu_src_reg(reg_id_global_x),
+				  gpu_src_reg_last(reg_shift),
+				  gpu_src_zero(),
+				  FLOW_NONE),
+		/* IADD.u32 rADDRLO, rADDRLO^, rOFFSET^ */
+		gpu_iadd_u32(gpu_dst_reg(reg_addr_lo),
+			     gpu_src_reg_last(reg_addr_lo),
+			     gpu_src_reg_last(reg_offset),
+			     FLOW_NONE),
+		/* LOAD.i32.slot0.wait0 @rVAL, [rADDRLO:rADDRHI], offset:0 */
+		gpu_load_i32(gpu_dst_reg(reg_val),
+			     gpu_src_reg(reg_addr_lo),
+			     gpu_src_reg(reg_addr_hi),
+			     0x0,
+			     0, FLOW_WAIT0),
+		/* IMUL_u32 rVAL, rVAL^, rGLOBALID^ */
+		gpu_imul_u32(gpu_dst_reg(reg_val),
+			     gpu_src_reg_last(reg_val),
+			     gpu_src_reg_last(reg_id_global_x),
+			     FLOW_NONE),
+		/* STORE.i32.slot1.end @rVAL, [rADDRLO^:rADDRHI^], offset:0 */
+		gpu_store_i32(gpu_src_reg_last(reg_addr_lo),
+			      gpu_src_reg_last(reg_addr_hi),
+			      gpu_src_reg(reg_val),
+			      0x0,
+			      1, FLOW_END),
+	};
+
+	uint64_t csf_instrs[] = {
+		/* REQ_RESOURCE.compute */
+		cs_req_resource(true, false, false, false),
+		/* MOV32 r40, 0 (always force cache flush/invalidate) */
+		cs_mov32(zero_reg, 0),
+		/* FLUSH_CACHE.clean_invalidate_l2.clean_invalidate_lsc.invalidate_other.sb0 */
+		cs_flush(CS_FLUSH_MODE_CLEAN_AND_INVALIDATE,
+			 CS_FLUSH_MODE_CLEAN_AND_INVALIDATE,
+			 CS_FLUSH_MODE_INVALIDATE,
+			 0, zero_reg, 1),
+		/* WAIT (flush) */
+		cs_wait(0xff, false),
+		/* ShaderResourceTable 0-3 pointers */
+		cs_mov48(compute_sr_base +  0, srt_gpuva),
+		cs_mov48(compute_sr_base +  2, 0x222222222222),
+		cs_mov48(compute_sr_base +  4, 0x333333333333),
+		cs_mov48(compute_sr_base +  6, 0x444444444444),
+		/* FastAccessUniform table 0-3 pointers */
+		cs_mov48(compute_sr_base +  8, fau_gpuva),
+		cs_mov48(compute_sr_base + 10, 0x666666666666),
+		cs_mov48(compute_sr_base + 12, 0x777777777777),
+		cs_mov48(compute_sr_base + 14, 0x888888888888),
+		/* ShaderProgramDescriptor 0-3 pointers */
+		cs_mov48(compute_sr_base + 16, spd_gpuva),
+		cs_mov48(compute_sr_base + 18, 0x999999999999),
+		cs_mov48(compute_sr_base + 20, 0xaaaaaaaaaaaa),
+		cs_mov48(compute_sr_base + 22, 0xbbbbbbbbbbbb),
+		/* ThreadStorageDescriptor 0-3 pointers */
+		cs_mov48(compute_sr_base + 24, tsd_gpuva),
+		cs_mov48(compute_sr_base + 26, 0xdddddddddddd),
+		cs_mov48(compute_sr_base + 28, 0xeeeeeeeeeeee),
+		cs_mov48(compute_sr_base + 30, 0xffffffffffff),
+		/* global ID offset = 0 */
+		cs_mov32(compute_sr_base + 32, 0),
+		/* workgroup size 64x1x1, allow merge */
+		cs_mov32(compute_sr_base + 33, (63 << 0) | (0 << 10) | (0 << 20) | (1 << 31)),
+		/* job offset (x/y/z) = { 0, 0, 0 } */
+		cs_mov32(compute_sr_base + 34, 0),
+		cs_mov32(compute_sr_base + 35, 0),
+		cs_mov32(compute_sr_base + 36, 0),
+		/* job size (x/y/z) = { 64, 1, 1 } */
+		cs_mov32(compute_sr_base + 37, 64),
+		cs_mov32(compute_sr_base + 38, 1),
+		cs_mov32(compute_sr_base + 39, 1),
+		/* SET_SB_ENTRY.async_ep1.other1 */
+		cs_set_sb_entry(1, 1),
+		/* RUN_COMPUTE.increment64.x_axis.no_increment.srt0.spd0.tsd0.fau0 */
+		cs_run_compute(64, CS_TASK_AXIS_X, 0, 0, 0, 0, 0),
+		/* WAIT (RUN_COMPUTE) */
+		cs_wait(0xff, false),
+		/* FLUSH_CACHE.clean_invalidate_l2.clean_invalidate_lsc.invalidate_other.sb0 */
+		cs_flush(CS_FLUSH_MODE_CLEAN_AND_INVALIDATE,
+			 CS_FLUSH_MODE_CLEAN_AND_INVALIDATE,
+			 CS_FLUSH_MODE_INVALIDATE,
+			 0, zero_reg, 1),
+		/* WAIT (flush) */
+		cs_wait(0xff, false),
+		/* ERROR_BARRIER */
+		cs_error_barrier(),
+	};
+
+	memcpy(gpu_cmdbuf, gpu_instrs, sizeof(gpu_instrs));
+	*gpu_cmdbuf_size = sizeof(gpu_instrs);
+	memcpy(csf_cmdbuf, csf_instrs, sizeof(csf_instrs));
+	*csf_cmdbuf_size = sizeof(csf_instrs);
+}
+
 static size_t
 issue_store_multiple(uint8_t *cs, uint64_t kernel_va, uint32_t constant)
 {
@@ -118,6 +245,119 @@ int igt_main() {
 		igt_panthor_free_bo(fd, &result_bo);
 	}
 
+	igt_describe("Submit a simple compute job with memory access.");
+	igt_subtest("simple_compute") {
+		uint32_t vm_id;
+		uint32_t group_handle;
+		struct panthor_bo csf_cmdbuf_bo = {};
+		struct panthor_bo gpu_cmdbuf_bo = {};
+		struct panthor_bo resource_table_bo = {};
+		struct panthor_bo data_bo = {};
+		uint64_t csf_cmdbuf_gpuva;
+		uint32_t csf_cmdbuf_size;
+		uint64_t gpu_cmdbuf_gpuva;
+		uint32_t gpu_cmdbuf_size;
+		uint32_t resource_table_gpuva;
+		uint32_t data_gpuva;
+		uint32_t syncobj_handle;
+		uint32_t srt_offset;
+		uint32_t fau_offset;
+		uint32_t spd_offset;
+		uint32_t *spd_ptr;
+		uint32_t spd_gpuva;
+		uint32_t tsd_offset;
+		uint32_t *tsd_ptr;
+		int arch = igt_panthor_get_arch(fd);
+
+		igt_require(arch < 15);
+
+		igt_panthor_vm_create(fd, &vm_id, 0);
+
+		/* CSF ISA command stream */
+		csf_cmdbuf_gpuva = 0x1000000;
+		igt_panthor_bo_create_mapped(fd, &csf_cmdbuf_bo, 4096, 0, 0);
+		igt_panthor_vm_bind(fd, vm_id, csf_cmdbuf_bo.handle, csf_cmdbuf_gpuva,
+				    csf_cmdbuf_bo.size, DRM_PANTHOR_VM_BIND_OP_TYPE_MAP, 0);
+		memset(csf_cmdbuf_bo.map, 0, csf_cmdbuf_bo.size);
+
+		/* GPU ISA command stream */
+		gpu_cmdbuf_gpuva = 0x2000000;
+		igt_panthor_bo_create_mapped(fd, &gpu_cmdbuf_bo, 4096, 0, 0);
+		igt_panthor_vm_bind(fd, vm_id, gpu_cmdbuf_bo.handle, gpu_cmdbuf_gpuva,
+				    gpu_cmdbuf_bo.size, DRM_PANTHOR_VM_BIND_OP_TYPE_MAP, 0);
+		memset(gpu_cmdbuf_bo.map, 0, gpu_cmdbuf_bo.size);
+
+		/* resource tables passed to RUN_COMPUTE */
+		resource_table_gpuva = 0x3000000;
+		igt_panthor_bo_create_mapped(fd, &resource_table_bo, 4096, 0, 0);
+		igt_panthor_vm_bind(fd, vm_id, resource_table_bo.handle, resource_table_gpuva,
+				    resource_table_bo.size, DRM_PANTHOR_VM_BIND_OP_TYPE_MAP, 0);
+		memset(resource_table_bo.map, 0, resource_table_bo.size);
+		/* ShaderResourceTable descriptor (zeroed) */
+		srt_offset = 0;
+		/* FastAccessUniform descriptor (zeroed) */
+		fau_offset = 128;
+		/* ShaderProgramDescriptor */
+		spd_offset = 256;
+		spd_gpuva = resource_table_gpuva + spd_offset;
+		if (arch == 14)
+			spd_gpuva |= 2; /* register allocation propagated into ptr */
+		spd_ptr = (uint32_t *) ((unsigned char *) resource_table_bo.map + spd_offset);
+		spd_ptr[0] = 0x8 | (0x1 << 4); /* compute shader */
+		spd_ptr[0] |= (0 << 16) | (0 << 17) | (0 << 19); /* no NaN suppress, FTZ, inf suppress */
+		spd_ptr[0] |= (0 << 29) | (2 << 30); /* no JUMP_EX, max 32 registers */
+		spd_ptr[1] |= (1 << 12); /* preload GlobalInvocationID.x into r60 */
+		spd_ptr[2] = gpu_cmdbuf_gpuva; /* initial PC */
+		/* ThreadStorageDescriptor */
+		tsd_offset = 512;
+		tsd_ptr = (uint32_t *) ((unsigned char *) resource_table_bo.map + tsd_offset);
+		tsd_ptr[1] = 0x1f; /* max wls_instances */
+
+		/* CPU<->GPU shared data */
+		data_gpuva = 0x4000000;
+		igt_panthor_bo_create_mapped(fd, &data_bo, 16384, 0, 0);
+		igt_panthor_vm_bind(fd, vm_id, data_bo.handle, data_gpuva,
+				    data_bo.size, DRM_PANTHOR_VM_BIND_OP_TYPE_MAP, 0);
+		for (unsigned int i = 0; i < 64 * 64; i++) {
+			uint32_t *x = data_bo.map + (i * sizeof(uint32_t));
+			*x = i;
+		}
+
+		record_compute_prog(csf_cmdbuf_bo.map, &csf_cmdbuf_size,
+				    gpu_cmdbuf_bo.map, &gpu_cmdbuf_size,
+				    resource_table_gpuva + srt_offset,
+				    resource_table_gpuva + fau_offset,
+				    spd_gpuva,
+				    resource_table_gpuva + tsd_offset,
+				    data_gpuva);
+
+		group_handle = igt_panthor_group_create_simple(fd, vm_id, 0);
+		igt_assert_neq(group_handle, 0);
+
+		syncobj_handle = syncobj_create(fd, 0);
+
+		igt_panthor_group_submit_simple(fd, group_handle, 0,
+						csf_cmdbuf_gpuva, csf_cmdbuf_size,
+						syncobj_handle, 0);
+		igt_assert(syncobj_wait(fd, &syncobj_handle, 1, INT64_MAX, 0, NULL));
+
+		for (unsigned int i = 0; i < 64 * 64; i++) {
+			uint32_t *x = data_bo.map + (i * sizeof(uint32_t));
+			igt_assert_eq(*x, i * i);
+		}
+
+		syncobj_destroy(fd, syncobj_handle);
+
+		igt_panthor_group_destroy(fd, group_handle, 0);
+
+		igt_panthor_vm_destroy(fd, vm_id, 0);
+
+		igt_panthor_free_bo(fd, &data_bo);
+		igt_panthor_free_bo(fd, &resource_table_bo);
+		igt_panthor_free_bo(fd, &gpu_cmdbuf_bo);
+		igt_panthor_free_bo(fd, &csf_cmdbuf_bo);
+	}
+
 	igt_fixture() {
 		drm_close_driver(fd);
 	}
-- 
2.47.3


  parent reply	other threads:[~2026-10-15 13:13 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-15 13:05 [PATCH 0/4] Add Panthor compute-shader test Daniel Stone
2026-10-15 13:05 ` [PATCH 1/4] panthor: Use all available GPU cores Daniel Stone
2026-10-15 15:50   ` Kamil Konieczny
2026-10-15 13:05 ` [PATCH 2/4] panthor: Add igt_panthor_get_arch() helper Daniel Stone
2026-10-15 15:52   ` Kamil Konieczny
2026-10-15 13:05 ` [PATCH 3/4] panthor: Add more CSF instructions Daniel Stone
2026-10-15 15:55   ` Kamil Konieczny
2026-10-15 13:05 ` Daniel Stone [this message]
2026-10-15 16:06   ` [PATCH 4/4] panthor: Add simple compute-shader test Kamil Konieczny

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=20261015130837.710795-5-daniels@collabora.com \
    --to=daniels@collabora.com \
    --cc=adrian.larumbe@collabora.com \
    --cc=boris.brezillon@collabora.com \
    --cc=daniel.almeida@collabora.com \
    --cc=igt-dev@lists.freedesktop.org \
    --cc=laura.nao@collabora.com \
    --cc=liviu.dudau@arm.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox