From: Ruslan Ruslichenko <ruslichenko.r@gmail.com>
To: qemu-devel@nongnu.org
Cc: qemu-arm@nongnu.org, artem_mygaiev@epam.com,
volodymyr_babchuk@epam.com, peter.maydell@linaro.org,
francisco.iglesias@amd.com, edgar.iglesias@gmail.com,
berrange@redhat.com, eugene@nuvacore.ai,
Ruslan_Ruslichenko@epam.com, takahiro.nakata.wr@renesas.com,
"Edgar E . Iglesias" <edgar.iglesias@amd.com>
Subject: [PATCH v2 04/20] hw/core: Implement Remote Port bus access helpers
Date: Tue, 15 Sep 2026 18:00:28 +0200 [thread overview]
Message-ID: <20260915160044.345788-5-ruslichenko.r@gmail.com> (raw)
In-Reply-To: <20260915160044.345788-1-ruslichenko.r@gmail.com>
From: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
Add bus access logic for Remote Port memory transactions.
The patch add support for read and write commands, which
enables data communication via the protocol.
This includes support for both legacy and extended packet
formats (such as 64-bit Master IDs) based on peer's
capabilities.
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Signed-off-by: Takahiro Nakata <takahiro.nakata.wr@renesas.com>
Signed-off-by: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
---
hw/core/remote-port-proto.c | 152 ++++++++++++++++++++++++++++
include/hw/core/remote-port-proto.h | 133 ++++++++++++++++++++++++
2 files changed, 285 insertions(+)
diff --git a/hw/core/remote-port-proto.c b/hw/core/remote-port-proto.c
index 9439f4b119..ddaefa7e36 100644
--- a/hw/core/remote-port-proto.c
+++ b/hw/core/remote-port-proto.c
@@ -63,6 +63,8 @@ int rp_decode_hdr(struct rp_pkt *pkt)
int rp_decode_payload(struct rp_pkt *pkt)
{
int used = 0;
+ /* Master_id has an odd decoding due to historical reasons. */
+ uint64_t master_id;
switch (pkt->hdr.cmd) {
case RP_CMD_hello:
@@ -102,6 +104,34 @@ int rp_decode_payload(struct rp_pkt *pkt)
*/
used = pkt->hdr.len;
break;
+ case RP_CMD_write:
+ case RP_CMD_read:
+ assert(pkt->hdr.len >= sizeof pkt->busaccess - sizeof pkt->hdr);
+ pkt->busaccess.timestamp = be64_to_cpu(pkt->busaccess.timestamp);
+ pkt->busaccess.addr = be64_to_cpu(pkt->busaccess.addr);
+ pkt->busaccess.attributes = be64_to_cpu(pkt->busaccess.attributes);
+ pkt->busaccess.len = be32_to_cpu(pkt->busaccess.len);
+ pkt->busaccess.width = be32_to_cpu(pkt->busaccess.width);
+ pkt->busaccess.stream_width = be32_to_cpu(pkt->busaccess.stream_width);
+ master_id = be16_to_cpu(pkt->busaccess.master_id);
+
+ used += sizeof pkt->busaccess - sizeof pkt->hdr;
+
+ if (pkt->busaccess.attributes & RP_BUS_ATTR_EXT_BASE) {
+ struct rp_pkt_busaccess_ext_base *pext = &pkt->busaccess_ext_base;
+
+ assert(pkt->hdr.len >= sizeof *pext - sizeof pkt->hdr);
+ master_id |= (uint64_t)be16_to_cpu(pext->master_id_31_16) << 16;
+ master_id |= (uint64_t)be32_to_cpu(pext->master_id_63_32) << 32;
+ pext->data_offset = be32_to_cpu(pext->data_offset);
+ pext->next_offset = be32_to_cpu(pext->next_offset);
+ pext->byte_enable_offset = be32_to_cpu(pext->byte_enable_offset);
+ pext->byte_enable_len = be32_to_cpu(pext->byte_enable_len);
+
+ used += sizeof *pext - sizeof pkt->busaccess;
+ }
+ pkt->busaccess.master_id = master_id;
+ break;
default:
break;
}
@@ -144,6 +174,127 @@ size_t rp_encode_hello_caps(uint32_t id, uint32_t dev, struct rp_pkt_hello *pkt,
return sizeof *pkt;
}
+static void rp_encode_busaccess_common(struct rp_pkt_busaccess *pkt,
+ int64_t clk, uint16_t master_id,
+ uint64_t addr, uint64_t attr, uint32_t size,
+ uint32_t width, uint32_t stream_width)
+{
+ pkt->timestamp = cpu_to_be64(clk);
+ pkt->master_id = cpu_to_be16(master_id);
+ pkt->addr = cpu_to_be64(addr);
+ pkt->attributes = cpu_to_be64(attr);
+ pkt->len = cpu_to_be32(size);
+ pkt->width = cpu_to_be32(width);
+ pkt->stream_width = cpu_to_be32(stream_width);
+}
+
+size_t rp_encode_read(uint32_t id, uint32_t dev,
+ struct rp_pkt_busaccess *pkt,
+ int64_t clk, uint16_t master_id,
+ uint64_t addr, uint64_t attr, uint32_t size,
+ uint32_t width, uint32_t stream_width)
+{
+ rp_encode_hdr(&pkt->hdr, RP_CMD_read, id, dev,
+ sizeof *pkt - sizeof pkt->hdr, 0);
+ rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
+ size, width, stream_width);
+ return sizeof *pkt;
+}
+
+size_t rp_encode_read_resp(uint32_t id, uint32_t dev,
+ struct rp_pkt_busaccess *pkt,
+ int64_t clk, uint16_t master_id,
+ uint64_t addr, uint64_t attr, uint32_t size,
+ uint32_t width, uint32_t stream_width)
+{
+ rp_encode_hdr(&pkt->hdr, RP_CMD_read, id, dev,
+ sizeof *pkt - sizeof pkt->hdr + size, RP_PKT_FLAGS_response);
+ rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
+ size, width, stream_width);
+ return sizeof *pkt + size;
+}
+
+size_t rp_encode_write(uint32_t id, uint32_t dev,
+ struct rp_pkt_busaccess *pkt,
+ int64_t clk, uint16_t master_id,
+ uint64_t addr, uint64_t attr, uint32_t size,
+ uint32_t width, uint32_t stream_width)
+{
+ rp_encode_hdr(&pkt->hdr, RP_CMD_write, id, dev,
+ sizeof *pkt - sizeof pkt->hdr + size, 0);
+ rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
+ size, width, stream_width);
+ return sizeof *pkt;
+}
+
+size_t rp_encode_write_resp(uint32_t id, uint32_t dev,
+ struct rp_pkt_busaccess *pkt,
+ int64_t clk, uint16_t master_id,
+ uint64_t addr, uint64_t attr, uint32_t size,
+ uint32_t width, uint32_t stream_width)
+{
+ rp_encode_hdr(&pkt->hdr, RP_CMD_write, id, dev,
+ sizeof *pkt - sizeof pkt->hdr, RP_PKT_FLAGS_response);
+ rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
+ size, width, stream_width);
+ return sizeof *pkt;
+}
+
+/* New API for extended header. */
+size_t rp_encode_busaccess(struct rp_peer_state *peer,
+ struct rp_pkt_busaccess_ext_base *pkt,
+ struct rp_encode_busaccess_in *in) {
+ struct rp_pkt_busaccess *pkt_v4_0 = (void *) pkt;
+ uint32_t hsize = 0;
+ uint32_t ret_size = 0;
+
+ /* Allocate packet space. */
+ if (in->cmd == RP_CMD_write && !(in->flags & RP_PKT_FLAGS_response)) {
+ hsize = in->size;
+ }
+ if (in->cmd == RP_CMD_read && (in->flags & RP_PKT_FLAGS_response)) {
+ hsize = in->size;
+ ret_size = in->size;
+ }
+
+ /*
+ * If peer does not support the busaccess base extensions, use the
+ * old layout. For responses, what matters is if we're responding
+ * to a packet with the extensions.
+ */
+ if (!peer->caps.busaccess_ext_base && !(in->attr & RP_BUS_ATTR_EXT_BASE)) {
+ /* Old layout. */
+ assert(in->master_id < UINT16_MAX);
+
+ rp_encode_hdr(&pkt->hdr, in->cmd, in->id, in->dev,
+ sizeof *pkt_v4_0 - sizeof pkt->hdr + hsize, in->flags);
+ rp_encode_busaccess_common(pkt_v4_0, in->clk, in->master_id,
+ in->addr, in->attr,
+ in->size, in->width, in->stream_width);
+ return sizeof *pkt_v4_0 + ret_size;
+ }
+
+ /* Encode the extended fields. */
+ pkt->master_id_31_16 = cpu_to_be16(in->master_id >> 16);
+ pkt->master_id_63_32 = cpu_to_be32(in->master_id >> 32);
+
+ /* We always put data right after the header. */
+ pkt->data_offset = cpu_to_be32(sizeof *pkt);
+ pkt->next_offset = 0;
+
+ pkt->byte_enable_offset = cpu_to_be32(sizeof *pkt + hsize);
+ pkt->byte_enable_len = cpu_to_be32(in->byte_enable_len);
+ hsize += in->byte_enable_len;
+
+ rp_encode_hdr(&pkt->hdr, in->cmd, in->id, in->dev,
+ sizeof *pkt - sizeof pkt->hdr + hsize, in->flags);
+ rp_encode_busaccess_common(pkt_v4_0, in->clk, in->master_id, in->addr,
+ in->attr | RP_BUS_ATTR_EXT_BASE,
+ in->size, in->width, in->stream_width);
+
+ return sizeof *pkt + ret_size;
+}
+
void rp_process_caps(struct rp_peer_state *peer,
void *caps, size_t caps_len)
{
@@ -173,6 +324,7 @@ void rp_process_caps(struct rp_peer_state *peer,
}
}
+
void rp_dpkt_alloc(RemotePortDynPkt *dpkt, size_t size)
{
if (dpkt->size < size) {
diff --git a/include/hw/core/remote-port-proto.h b/include/hw/core/remote-port-proto.h
index ac7b7a9b96..de67cd6501 100644
--- a/include/hw/core/remote-port-proto.h
+++ b/include/hw/core/remote-port-proto.h
@@ -344,6 +344,134 @@ rp_encode_hello(uint32_t id, uint32_t dev, struct rp_pkt_hello *pkt,
NULL, NULL, 0);
}
+static inline void *__attribute__ ((deprecated))
+rp_busaccess_dataptr(struct rp_pkt_busaccess *pkt)
+{
+ /* Right after the packet. */
+ return pkt + 1;
+}
+
+/*
+ * rp_busaccess_rx_dataptr
+ *
+ * Predicts the dataptr for a packet to be transmitted.
+ * This should only be used if you are trying to keep
+ * the entire packet in a linear buffer.
+ */
+static inline unsigned char *
+rp_busaccess_tx_dataptr(struct rp_peer_state *peer,
+ struct rp_pkt_busaccess_ext_base *pkt)
+{
+ unsigned char *p = (unsigned char *) pkt;
+
+ if (peer->caps.busaccess_ext_base) {
+ /* We always put our data right after the header. */
+ return p + sizeof *pkt;
+ } else {
+ /* Right after the old packet layout. */
+ return p + sizeof(struct rp_pkt_busaccess);
+ }
+}
+
+/*
+ * rp_busaccess_rx_dataptr
+ *
+ * Extracts the dataptr from a received packet.
+ */
+static inline unsigned char *
+rp_busaccess_rx_dataptr(struct rp_peer_state *peer,
+ struct rp_pkt_busaccess_ext_base *pkt)
+{
+ unsigned char *p = (unsigned char *) pkt;
+
+ if (pkt->attributes & RP_BUS_ATTR_EXT_BASE) {
+ return p + pkt->data_offset;
+ } else {
+ /* Right after the old packet layout. */
+ return p + sizeof(struct rp_pkt_busaccess);
+ }
+}
+
+static inline unsigned char *
+rp_busaccess_byte_en_ptr(struct rp_peer_state *peer,
+ struct rp_pkt_busaccess_ext_base *pkt)
+{
+ unsigned char *p = (unsigned char *) pkt;
+
+ if ((pkt->attributes & RP_BUS_ATTR_EXT_BASE)
+ && pkt->byte_enable_len) {
+ assert(pkt->byte_enable_offset >= sizeof *pkt);
+ assert(pkt->byte_enable_offset + pkt->byte_enable_len
+ <= pkt->hdr.len + sizeof pkt->hdr);
+ return p + pkt->byte_enable_offset;
+ }
+ return NULL;
+}
+
+size_t __attribute__ ((deprecated))
+rp_encode_read(uint32_t id, uint32_t dev,
+ struct rp_pkt_busaccess *pkt,
+ int64_t clk, uint16_t master_id,
+ uint64_t addr, uint64_t attr, uint32_t size,
+ uint32_t width, uint32_t stream_width);
+
+size_t __attribute__ ((deprecated))
+rp_encode_read_resp(uint32_t id, uint32_t dev,
+ struct rp_pkt_busaccess *pkt,
+ int64_t clk, uint16_t master_id,
+ uint64_t addr, uint64_t attr, uint32_t size,
+ uint32_t width, uint32_t stream_width);
+
+size_t __attribute__ ((deprecated))
+rp_encode_write(uint32_t id, uint32_t dev,
+ struct rp_pkt_busaccess *pkt,
+ int64_t clk, uint16_t master_id,
+ uint64_t addr, uint64_t attr, uint32_t size,
+ uint32_t width, uint32_t stream_width);
+
+size_t __attribute__ ((deprecated))
+rp_encode_write_resp(uint32_t id, uint32_t dev,
+ struct rp_pkt_busaccess *pkt,
+ int64_t clk, uint16_t master_id,
+ uint64_t addr, uint64_t attr, uint32_t size,
+ uint32_t width, uint32_t stream_width);
+
+struct rp_encode_busaccess_in {
+ uint32_t cmd;
+ uint32_t id;
+ uint32_t flags;
+ uint32_t dev;
+ int64_t clk;
+ uint64_t master_id;
+ uint64_t addr;
+ uint64_t attr;
+ uint32_t size;
+ uint32_t width;
+ uint32_t stream_width;
+ uint32_t byte_enable_len;
+};
+
+/* Prepare encode_busaccess input parameters for a packet response. */
+static inline void
+rp_encode_busaccess_in_rsp_init(struct rp_encode_busaccess_in *in,
+ struct rp_pkt *pkt) {
+ memset(in, 0, sizeof *in);
+ in->cmd = pkt->hdr.cmd;
+ in->id = pkt->hdr.id;
+ in->flags = pkt->hdr.flags | RP_PKT_FLAGS_response;
+ in->dev = pkt->hdr.dev;
+ /* FIXME: Propagate all master_id fields? */
+ in->master_id = pkt->busaccess.master_id;
+ in->addr = pkt->busaccess.addr;
+ in->size = pkt->busaccess.len;
+ in->width = pkt->busaccess.width;
+ in->stream_width = pkt->busaccess.stream_width;
+ in->byte_enable_len = 0;
+}
+size_t rp_encode_busaccess(struct rp_peer_state *peer,
+ struct rp_pkt_busaccess_ext_base *pkt,
+ struct rp_encode_busaccess_in *in);
+
void rp_process_caps(struct rp_peer_state *peer,
void *caps, size_t caps_len);
@@ -376,4 +504,9 @@ void rp_dpkt_invalidate(RemotePortDynPkt *dpkt);
void rp_dpkt_free(RemotePortDynPkt *dpkt);
+static inline int rp_get_busaccess_response(struct rp_pkt *pkt)
+{
+ return (pkt->busaccess_ext_base.attributes & RP_BUS_RESP_MASK) >>
+ RP_BUS_RESP_SHIFT;
+}
#endif
--
2.43.0
next prev parent reply other threads:[~2026-09-15 16:02 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-15 16:00 [PATCH v2 00/20] hw/core: Introduce Remote Port Co-simulation Protocol Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 01/20] hw/core: Add Remote Port protocol packet definition Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 02/20] hw/core: Add Remote Port header helpers Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 03/20] hw/core: Add Remote Port session state and hello protocol Ruslan Ruslichenko
2026-09-15 16:00 ` Ruslan Ruslichenko [this message]
2026-09-15 16:00 ` [PATCH v2 05/20] hw/core: Implement Remote Port irq, sync and ATS helpers Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 06/20] hw/core: Add Remote Port object skeleton Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 07/20] hw/core: Add Remote Port protocol thread and handshake Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 08/20] hw/core: Implement Remote Port response handling Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 09/20] hw/core: Implement Remote Port time synchronization Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 10/20] hw/core: Add Remote Port Memory Master object skeleton Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 11/20] hw/core: Implement Remote Port Memory Master bus transactions Ruslan Ruslichenko
2026-10-13 16:09 ` Philippe Mathieu-Daudé
2026-10-13 16:10 ` Philippe Mathieu-Daudé
2026-10-14 8:24 ` Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 12/20] system/physmem: Add ats_do_translate helper Ruslan Ruslichenko
2026-10-13 14:27 ` Clément MATHIEU--DRIF
2026-10-14 8:21 ` Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 13/20] hw/core: Add Remote Port ATS device skeleton Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 14/20] hw/core: Implement Remote Port ATS logic and cache management Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 15/20] hw/core: Add Remote Port memory slave device Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 16/20] hw/core: Add Remote Port GPIO/Interrupt bridge Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 17/20] hw/core: Add Remote Port Stream device Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 18/20] hw/core: Add Remote Port files to build Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 19/20] hw/core: Add FDT support to Remote Port GPIO Ruslan Ruslichenko
2026-09-15 16:00 ` [PATCH v2 20/20] hw/core: Add FDT support to Remote Port memory master Ruslan Ruslichenko
2026-09-28 7:30 ` [PATCH v2 00/20] hw/core: Introduce Remote Port Co-simulation Protocol Ruslan Ruslichenko
2026-10-13 16:17 ` Philippe Mathieu-Daudé
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=20260915160044.345788-5-ruslichenko.r@gmail.com \
--to=ruslichenko.r@gmail.com \
--cc=Ruslan_Ruslichenko@epam.com \
--cc=artem_mygaiev@epam.com \
--cc=berrange@redhat.com \
--cc=edgar.iglesias@amd.com \
--cc=edgar.iglesias@gmail.com \
--cc=eugene@nuvacore.ai \
--cc=francisco.iglesias@amd.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=takahiro.nakata.wr@renesas.com \
--cc=volodymyr_babchuk@epam.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.