From: Kane Chen via <qemu-arm@nongnu.org>
To: "Cédric Le Goater" <clg@kaod.org>,
"Peter Maydell" <peter.maydell@linaro.org>,
"Steven Lee" <steven_lee@aspeedtech.com>,
"Troy Lee" <leetroy@gmail.com>,
"Jamin Lin" <jamin_lin@aspeedtech.com>,
"Andrew Jeffery" <andrew@codeconstruct.com.au>,
"Joel Stanley" <joel@jms.id.au>,
"open list:ASPEED BMCs" <qemu-arm@nongnu.org>,
"open list:All patches CC here" <qemu-devel@nongnu.org>
Cc: <troy_lee@aspeedtech.com>, Kane-Chen-AS <kane_chen@aspeedtech.com>
Subject: [PATCH v3 1/3] hw/misc/aspeed_otp: Add Aspeed OTP memory device model
Date: Wed, 23 Apr 2025 10:56:49 +0800 [thread overview]
Message-ID: <20250423025651.189702-2-kane_chen@aspeedtech.com> (raw)
In-Reply-To: <20250423025651.189702-1-kane_chen@aspeedtech.com>
From: Kane-Chen-AS <kane_chen@aspeedtech.com>
This introduces a new model for the ASPEED OTP (One-Time Programmable)
memory. The device is implemented as a `SysBusDevice` and provides an
abstracted interface for OTP read, write (program), and default value
initialization.
OTP content is backed by a block device and supports QEMU’s drive
infrastructure via the "drive" property.
Features:
- Enforces irreversible bit programming logic (0->1 or 1->0)
- Provides interface for SoC/secure controller integration
- Validates bounds and bit-level constraints
- Uses QEMU error handling conventions and logging
Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com>
---
hw/misc/aspeed_otpmem.c | 211 ++++++++++++++++++++++++++++++++
hw/misc/meson.build | 1 +
include/hw/misc/aspeed_otpmem.h | 40 ++++++
3 files changed, 252 insertions(+)
create mode 100644 hw/misc/aspeed_otpmem.c
create mode 100644 include/hw/misc/aspeed_otpmem.h
diff --git a/hw/misc/aspeed_otpmem.c b/hw/misc/aspeed_otpmem.c
new file mode 100644
index 0000000000..4f8f2827f7
--- /dev/null
+++ b/hw/misc/aspeed_otpmem.c
@@ -0,0 +1,211 @@
+/*
+ * ASPEED OTP (One-Time Programmable) memory
+ *
+ * Copyright (C) 2025 Aspeed
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/block/block.h"
+#include "hw/block/flash.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "system/block-backend.h"
+#include "qemu/log.h"
+#include "qemu/option.h"
+#include "hw/sysbus.h"
+#include "qemu/error-report.h"
+#include "hw/misc/aspeed_otpmem.h"
+
+static const Property aspeed_otpmem_properties[] = {
+ DEFINE_PROP_DRIVE("drive", AspeedOTPMemState, blk),
+};
+
+static void aspeed_otpmem_read(void *opaque, uint32_t addr,
+ uint32_t *out, Error **errp)
+{
+ AspeedOTPMemState *otp = ASPEED_OTPMEM(opaque);
+
+ assert(otp->blk);
+
+ if (out == NULL) {
+ error_setg(errp, "out is NULL");
+ return;
+ }
+
+ if (addr > (otp->max_size - 4)) {
+ error_setg(errp, "OTP memory 0x%x is exceeded", addr);
+ return;
+ }
+
+ if (blk_pread(otp->blk, (int64_t)addr, sizeof(uint32_t), out, 0) < 0) {
+ error_setg(errp, "Failed to read data 0x%x", addr);
+ return;
+ }
+ return;
+}
+
+static bool valid_program_data(uint32_t otp_addr,
+ uint32_t value, uint32_t prog_bit)
+{
+ uint32_t programmed_bits, has_programmable_bits;
+ bool is_odd = otp_addr & 1;
+
+ /*
+ * prog_bit uses 0s to indicate target bits to program:
+ * - if OTP word is even-indexed, programmed bits flip 0->1
+ * - if odd, bits flip 1->0
+ * Bit programming is one-way only and irreversible.
+ */
+ if (is_odd) {
+ programmed_bits = ~value & prog_bit;
+ } else {
+ programmed_bits = value & (~prog_bit);
+ }
+
+ /* If there is some bit can be programed, to accept the request */
+ has_programmable_bits = value ^ (~prog_bit);
+
+ if (programmed_bits) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Found programmed bits in addr %x\n",
+ __func__, otp_addr);
+ for (int i = 0; i < 32; ++i) {
+ if (programmed_bits & (1U << i)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ " Programmed bit %d\n",
+ i);
+ }
+ }
+ }
+
+ return has_programmable_bits != 0;
+}
+
+static bool program_otpmem_data(void *opaque, uint32_t otp_addr,
+ uint32_t prog_bit, uint32_t *value)
+{
+ AspeedOTPMemState *s = ASPEED_OTPMEM(opaque);
+ bool is_odd = otp_addr & 1;
+ uint32_t otp_offset = otp_addr << 2;
+
+ if (blk_pread(s->blk, (int64_t)otp_offset,
+ sizeof(uint32_t), value, 0) < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Failed to read data 0x%x\n",
+ __func__, otp_offset);
+ return false;
+ }
+
+ if (!valid_program_data(otp_addr, *value, prog_bit)) {
+ return false;
+ }
+
+ if (is_odd) {
+ *value &= ~prog_bit;
+ } else {
+ *value |= ~prog_bit;
+ }
+
+ return true;
+}
+
+static void aspeed_otpmem_prog(void *s, uint32_t otp_addr,
+ uint32_t data, Error **errp)
+{
+ AspeedOTPMemState *otp = ASPEED_OTPMEM(s);
+ uint32_t otp_offset, value;
+
+ assert(otp->blk);
+
+ if (otp_addr > (otp->max_size >> 2)) {
+ error_setg(errp, "OTP memory 0x%x is exceeded", otp_addr);
+ return;
+ }
+
+ otp_offset = otp_addr << 2;
+ if (!program_otpmem_data(s, otp_addr, data, &value)) {
+ error_setg(errp, "Failed to program data");
+ return;
+ }
+
+ if (blk_pwrite(otp->blk, (int64_t)otp_offset,
+ sizeof(value), &value, 0) < 0) {
+ error_setg(errp, "Failed to write data");
+ }
+
+ return;
+}
+
+static void aspeed_otpmem_set_default(void *s, uint32_t otp_offset,
+ uint32_t data, Error **errp)
+{
+ AspeedOTPMemState *otp = ASPEED_OTPMEM(s);
+
+ if ((otp_offset + 4) > otp->max_size) {
+ error_setg(errp, "OTP memory 0x%x is exceeded", otp_offset);
+ return;
+ }
+
+ if (blk_pwrite(otp->blk, (int64_t)otp_offset,
+ sizeof(data), &data, 0) < 0) {
+ error_setg(errp, "Failed to write data");
+ }
+ return;
+}
+
+static AspeedOTPMemOps aspeed_otpmem_ops = {
+ .read = aspeed_otpmem_read,
+ .prog = aspeed_otpmem_prog,
+ .set_default_value = aspeed_otpmem_set_default
+};
+
+static void aspeed_otpmem_realize(DeviceState *dev, Error **errp)
+{
+ AspeedOTPMemState *s = ASPEED_OTPMEM(dev);
+
+ if (!s->blk) {
+ error_setg(&error_fatal, "OTP memory is not initialized");
+ return;
+ }
+
+ s->max_size = blk_getlength(s->blk);
+ if (s->max_size < 0 || (s->max_size % 4)) {
+ error_setg(&error_fatal,
+ "Unexpected OTP memory size: %" PRId64 "",
+ s->max_size);
+ return;
+ }
+
+ s->ops = &aspeed_otpmem_ops;
+
+ return;
+}
+
+static void aspeed_otpmem_system_reset(DeviceState *dev)
+{
+ return;
+}
+
+static void aspeed_otpmem_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ device_class_set_legacy_reset(dc, aspeed_otpmem_system_reset);
+ dc->realize = aspeed_otpmem_realize;
+ device_class_set_props(dc, aspeed_otpmem_properties);
+
+}
+
+static const TypeInfo aspeed_otpmem_types[] = {
+ {
+ .name = TYPE_ASPEED_OTPMEM,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AspeedOTPMemState),
+ .class_init = aspeed_otpmem_class_init,
+ },
+};
+
+DEFINE_TYPES(aspeed_otpmem_types)
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 6d47de482c..ed1eaaa2ad 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -136,6 +136,7 @@ system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
'aspeed_sbc.c',
'aspeed_sdmc.c',
'aspeed_xdma.c',
+ 'aspeed_otpmem.c',
'aspeed_peci.c',
'aspeed_sli.c'))
diff --git a/include/hw/misc/aspeed_otpmem.h b/include/hw/misc/aspeed_otpmem.h
new file mode 100644
index 0000000000..11e2de70b6
--- /dev/null
+++ b/include/hw/misc/aspeed_otpmem.h
@@ -0,0 +1,40 @@
+/*
+ * ASPEED OTP (One-Time Programmable) memory
+ *
+ * Copyright (C) 2025 Aspeed
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef ASPEED_OTPMMEM_H
+#define ASPEED_OTPMMEM_H
+
+#include "hw/sysbus.h"
+#include "qapi/error.h"
+
+#define TYPE_ASPEED_OTPMEM "aspeed.otpmem"
+#define ASPEED_OTPMEM_DRIVE "otpmem"
+
+#define ASPEED_OTPMEM(obj) OBJECT_CHECK(AspeedOTPMemState, (obj), \
+ TYPE_ASPEED_OTPMEM)
+
+typedef struct AspeedOTPMemOps {
+ void (*read)(void *s, uint32_t addr, uint32_t *out, Error **errp);
+ void (*prog)(void *s, uint32_t addr, uint32_t data, Error **errp);
+ void (*set_default_value)(void *s, uint32_t otp_offset,
+ uint32_t data, Error **errp);
+} AspeedOTPMemOps;
+
+typedef struct AspeedOTPMemState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mmio;
+ BlockBackend *blk;
+ int64_t max_size;
+
+ AspeedOTPMemOps *ops;
+} AspeedOTPMemState;
+
+#endif /* ASPEED_OTPMMEM_H */
+
--
2.43.0
WARNING: multiple messages have this Message-ID (diff)
From: Kane Chen via <qemu-devel@nongnu.org>
To: "Cédric Le Goater" <clg@kaod.org>,
"Peter Maydell" <peter.maydell@linaro.org>,
"Steven Lee" <steven_lee@aspeedtech.com>,
"Troy Lee" <leetroy@gmail.com>,
"Jamin Lin" <jamin_lin@aspeedtech.com>,
"Andrew Jeffery" <andrew@codeconstruct.com.au>,
"Joel Stanley" <joel@jms.id.au>,
"open list:ASPEED BMCs" <qemu-arm@nongnu.org>,
"open list:All patches CC here" <qemu-devel@nongnu.org>
Cc: <troy_lee@aspeedtech.com>, Kane-Chen-AS <kane_chen@aspeedtech.com>
Subject: [PATCH v3 1/3] hw/misc/aspeed_otp: Add Aspeed OTP memory device model
Date: Wed, 23 Apr 2025 10:56:49 +0800 [thread overview]
Message-ID: <20250423025651.189702-2-kane_chen@aspeedtech.com> (raw)
In-Reply-To: <20250423025651.189702-1-kane_chen@aspeedtech.com>
From: Kane-Chen-AS <kane_chen@aspeedtech.com>
This introduces a new model for the ASPEED OTP (One-Time Programmable)
memory. The device is implemented as a `SysBusDevice` and provides an
abstracted interface for OTP read, write (program), and default value
initialization.
OTP content is backed by a block device and supports QEMU’s drive
infrastructure via the "drive" property.
Features:
- Enforces irreversible bit programming logic (0->1 or 1->0)
- Provides interface for SoC/secure controller integration
- Validates bounds and bit-level constraints
- Uses QEMU error handling conventions and logging
Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com>
---
hw/misc/aspeed_otpmem.c | 211 ++++++++++++++++++++++++++++++++
hw/misc/meson.build | 1 +
include/hw/misc/aspeed_otpmem.h | 40 ++++++
3 files changed, 252 insertions(+)
create mode 100644 hw/misc/aspeed_otpmem.c
create mode 100644 include/hw/misc/aspeed_otpmem.h
diff --git a/hw/misc/aspeed_otpmem.c b/hw/misc/aspeed_otpmem.c
new file mode 100644
index 0000000000..4f8f2827f7
--- /dev/null
+++ b/hw/misc/aspeed_otpmem.c
@@ -0,0 +1,211 @@
+/*
+ * ASPEED OTP (One-Time Programmable) memory
+ *
+ * Copyright (C) 2025 Aspeed
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/block/block.h"
+#include "hw/block/flash.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "system/block-backend.h"
+#include "qemu/log.h"
+#include "qemu/option.h"
+#include "hw/sysbus.h"
+#include "qemu/error-report.h"
+#include "hw/misc/aspeed_otpmem.h"
+
+static const Property aspeed_otpmem_properties[] = {
+ DEFINE_PROP_DRIVE("drive", AspeedOTPMemState, blk),
+};
+
+static void aspeed_otpmem_read(void *opaque, uint32_t addr,
+ uint32_t *out, Error **errp)
+{
+ AspeedOTPMemState *otp = ASPEED_OTPMEM(opaque);
+
+ assert(otp->blk);
+
+ if (out == NULL) {
+ error_setg(errp, "out is NULL");
+ return;
+ }
+
+ if (addr > (otp->max_size - 4)) {
+ error_setg(errp, "OTP memory 0x%x is exceeded", addr);
+ return;
+ }
+
+ if (blk_pread(otp->blk, (int64_t)addr, sizeof(uint32_t), out, 0) < 0) {
+ error_setg(errp, "Failed to read data 0x%x", addr);
+ return;
+ }
+ return;
+}
+
+static bool valid_program_data(uint32_t otp_addr,
+ uint32_t value, uint32_t prog_bit)
+{
+ uint32_t programmed_bits, has_programmable_bits;
+ bool is_odd = otp_addr & 1;
+
+ /*
+ * prog_bit uses 0s to indicate target bits to program:
+ * - if OTP word is even-indexed, programmed bits flip 0->1
+ * - if odd, bits flip 1->0
+ * Bit programming is one-way only and irreversible.
+ */
+ if (is_odd) {
+ programmed_bits = ~value & prog_bit;
+ } else {
+ programmed_bits = value & (~prog_bit);
+ }
+
+ /* If there is some bit can be programed, to accept the request */
+ has_programmable_bits = value ^ (~prog_bit);
+
+ if (programmed_bits) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Found programmed bits in addr %x\n",
+ __func__, otp_addr);
+ for (int i = 0; i < 32; ++i) {
+ if (programmed_bits & (1U << i)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ " Programmed bit %d\n",
+ i);
+ }
+ }
+ }
+
+ return has_programmable_bits != 0;
+}
+
+static bool program_otpmem_data(void *opaque, uint32_t otp_addr,
+ uint32_t prog_bit, uint32_t *value)
+{
+ AspeedOTPMemState *s = ASPEED_OTPMEM(opaque);
+ bool is_odd = otp_addr & 1;
+ uint32_t otp_offset = otp_addr << 2;
+
+ if (blk_pread(s->blk, (int64_t)otp_offset,
+ sizeof(uint32_t), value, 0) < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Failed to read data 0x%x\n",
+ __func__, otp_offset);
+ return false;
+ }
+
+ if (!valid_program_data(otp_addr, *value, prog_bit)) {
+ return false;
+ }
+
+ if (is_odd) {
+ *value &= ~prog_bit;
+ } else {
+ *value |= ~prog_bit;
+ }
+
+ return true;
+}
+
+static void aspeed_otpmem_prog(void *s, uint32_t otp_addr,
+ uint32_t data, Error **errp)
+{
+ AspeedOTPMemState *otp = ASPEED_OTPMEM(s);
+ uint32_t otp_offset, value;
+
+ assert(otp->blk);
+
+ if (otp_addr > (otp->max_size >> 2)) {
+ error_setg(errp, "OTP memory 0x%x is exceeded", otp_addr);
+ return;
+ }
+
+ otp_offset = otp_addr << 2;
+ if (!program_otpmem_data(s, otp_addr, data, &value)) {
+ error_setg(errp, "Failed to program data");
+ return;
+ }
+
+ if (blk_pwrite(otp->blk, (int64_t)otp_offset,
+ sizeof(value), &value, 0) < 0) {
+ error_setg(errp, "Failed to write data");
+ }
+
+ return;
+}
+
+static void aspeed_otpmem_set_default(void *s, uint32_t otp_offset,
+ uint32_t data, Error **errp)
+{
+ AspeedOTPMemState *otp = ASPEED_OTPMEM(s);
+
+ if ((otp_offset + 4) > otp->max_size) {
+ error_setg(errp, "OTP memory 0x%x is exceeded", otp_offset);
+ return;
+ }
+
+ if (blk_pwrite(otp->blk, (int64_t)otp_offset,
+ sizeof(data), &data, 0) < 0) {
+ error_setg(errp, "Failed to write data");
+ }
+ return;
+}
+
+static AspeedOTPMemOps aspeed_otpmem_ops = {
+ .read = aspeed_otpmem_read,
+ .prog = aspeed_otpmem_prog,
+ .set_default_value = aspeed_otpmem_set_default
+};
+
+static void aspeed_otpmem_realize(DeviceState *dev, Error **errp)
+{
+ AspeedOTPMemState *s = ASPEED_OTPMEM(dev);
+
+ if (!s->blk) {
+ error_setg(&error_fatal, "OTP memory is not initialized");
+ return;
+ }
+
+ s->max_size = blk_getlength(s->blk);
+ if (s->max_size < 0 || (s->max_size % 4)) {
+ error_setg(&error_fatal,
+ "Unexpected OTP memory size: %" PRId64 "",
+ s->max_size);
+ return;
+ }
+
+ s->ops = &aspeed_otpmem_ops;
+
+ return;
+}
+
+static void aspeed_otpmem_system_reset(DeviceState *dev)
+{
+ return;
+}
+
+static void aspeed_otpmem_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ device_class_set_legacy_reset(dc, aspeed_otpmem_system_reset);
+ dc->realize = aspeed_otpmem_realize;
+ device_class_set_props(dc, aspeed_otpmem_properties);
+
+}
+
+static const TypeInfo aspeed_otpmem_types[] = {
+ {
+ .name = TYPE_ASPEED_OTPMEM,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AspeedOTPMemState),
+ .class_init = aspeed_otpmem_class_init,
+ },
+};
+
+DEFINE_TYPES(aspeed_otpmem_types)
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 6d47de482c..ed1eaaa2ad 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -136,6 +136,7 @@ system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
'aspeed_sbc.c',
'aspeed_sdmc.c',
'aspeed_xdma.c',
+ 'aspeed_otpmem.c',
'aspeed_peci.c',
'aspeed_sli.c'))
diff --git a/include/hw/misc/aspeed_otpmem.h b/include/hw/misc/aspeed_otpmem.h
new file mode 100644
index 0000000000..11e2de70b6
--- /dev/null
+++ b/include/hw/misc/aspeed_otpmem.h
@@ -0,0 +1,40 @@
+/*
+ * ASPEED OTP (One-Time Programmable) memory
+ *
+ * Copyright (C) 2025 Aspeed
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef ASPEED_OTPMMEM_H
+#define ASPEED_OTPMMEM_H
+
+#include "hw/sysbus.h"
+#include "qapi/error.h"
+
+#define TYPE_ASPEED_OTPMEM "aspeed.otpmem"
+#define ASPEED_OTPMEM_DRIVE "otpmem"
+
+#define ASPEED_OTPMEM(obj) OBJECT_CHECK(AspeedOTPMemState, (obj), \
+ TYPE_ASPEED_OTPMEM)
+
+typedef struct AspeedOTPMemOps {
+ void (*read)(void *s, uint32_t addr, uint32_t *out, Error **errp);
+ void (*prog)(void *s, uint32_t addr, uint32_t data, Error **errp);
+ void (*set_default_value)(void *s, uint32_t otp_offset,
+ uint32_t data, Error **errp);
+} AspeedOTPMemOps;
+
+typedef struct AspeedOTPMemState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mmio;
+ BlockBackend *blk;
+ int64_t max_size;
+
+ AspeedOTPMemOps *ops;
+} AspeedOTPMemState;
+
+#endif /* ASPEED_OTPMMEM_H */
+
--
2.43.0
next prev parent reply other threads:[~2025-04-23 2:58 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-23 2:56 [PATCH v3 0/3] hw/misc/aspeed_otp: Introduce OTP memory and integrate with SBC Kane Chen via
2025-04-23 2:56 ` Kane Chen via
2025-04-23 2:56 ` Kane Chen via [this message]
2025-04-23 2:56 ` [PATCH v3 1/3] hw/misc/aspeed_otp: Add Aspeed OTP memory device model Kane Chen via
2025-04-28 7:06 ` Cédric Le Goater
2025-04-28 10:24 ` Kane Chen
2025-04-23 2:56 ` [PATCH v3 2/3] hw/misc/aspeed_sbc: Connect Aspeed OTP memory device to SBC controller Kane Chen via
2025-04-23 2:56 ` Kane Chen via
2025-04-28 7:20 ` Cédric Le Goater
2025-04-28 10:25 ` Kane Chen
2025-05-08 9:46 ` Kane Chen
2025-04-23 2:56 ` [PATCH v3 3/3] hw/arm: Integrate Aspeed OTP memory into AST10x0 and AST2600 SoCs Kane Chen via
2025-04-23 2:56 ` Kane Chen via
2025-04-28 7:41 ` Cédric Le Goater
2025-04-28 10:26 ` Kane Chen
2025-04-28 11:00 ` Cédric Le Goater
2025-04-28 11:39 ` Cédric Le Goater
2025-04-29 2:59 ` Kane Chen
2025-04-29 9:05 ` Cédric Le Goater
2025-04-30 10:30 ` Kane Chen
2025-04-30 11:50 ` Cédric Le Goater
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=20250423025651.189702-2-kane_chen@aspeedtech.com \
--to=qemu-arm@nongnu.org \
--cc=andrew@codeconstruct.com.au \
--cc=clg@kaod.org \
--cc=jamin_lin@aspeedtech.com \
--cc=joel@jms.id.au \
--cc=kane_chen@aspeedtech.com \
--cc=leetroy@gmail.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=steven_lee@aspeedtech.com \
--cc=troy_lee@aspeedtech.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.