[PATCH 04/16] lib/utils: Add RPMI messaging protocol and shared memory transport support
Anup Patel
apatel at ventanamicro.com
Fri Aug 16 23:54:10 PDT 2024
On Fri, Aug 16, 2024 at 6:31 AM Bo Gan <ganboing at gmail.com> wrote:
>
> Hi All,
>
> I have some high level questions.
>
> Given that the RPMI shared memory transport works on HWs described as:
> https://github.com/riscv-software-src/librpmi/blob/main/docs/librpmi-arch.png
>
> I'm wondering maybe we should also define the memory/cache architecture
> we are targeting in this AP-PuC design. E.g., one problem I can think of
> is that AP and PuC are often not cache-coherent. Thus, when doing Tx/Rx,
> we might need cache flush/invalidation. The memory order involving head/
> tailptr, and read/write queue elements is also important. Even if we are
> dealing with a cache-coherent design, the usage of smp_wmb() after updating
> both the queue element and head/tailptr doesn't seems to be right. I think
> it should reflect a load-acquire semantic on headptr and a store-release
> semantic on tailptr. I'm sure there're very good references on how to handle
> memory order on this classic headptr/tailptr pattern, and we probably need
> to rework this part a little bit. For non-cache-coherent HW, I'm really not
> sure how to code this correctly, but my instinct tells me we need to be even
> more careful, make use of cache flushes, and ensure PuC observes the memory
> in the correct order.
There are 4 possible scenarios for coherent view of RPMI shared memory
between PuC and AP:
1) RPMI shared memory is cacheable for both PuC and AP
2) RPMI shared memory is cacheable for PuC but non-cacheable for AP
3) RPMI shared memory is non-cacheable for PuC and cacheable for AP
4) RPMI shared memory is non-cacheable for both PuC and AP
For #1 and #4, nothing special is required on the PuC and AP side to
ensure a coherent view of the RPMI shared memory.
For #2, PuC will have to use cache-clean operation after writing and
cache-invalidate operation before reading the RPMI shared memory
whereas AP need not do anything. To handle this case in librpmi, PuC
firmware can either use rpmi_shmem_simple_noncoherent_ops or
provide custom platform operations when creating RPMI shared
memory instances.
(Refer, https://github.com/riscv-software-src/librpmi/pull/23)
For #3, AP will have to use cache-clean operation after writing and
cache-invalidate operation before reading the RPMI shared memory
whereas PuC need not do anything. To handle this case in OpenSBI
(running on AP), we can use optional "dma-non-coherent" DT property
of the RPMI shared memory DT node which will allow the RPMI shared
memory transport driver to do cache-clean after writing to the shared
memory and cache-invalidate before reading the shared memory.
The #1 and #4 scenarios will be very common in the real world. The
#2 scenario is also possible if PuC does not have any mechanism to
mark shared memory as non-cacheable in HW. The #3 is very unlikely
because most APs (RISC-V CPUs) have PMAs to mark shared memory
as non-cacheable for OpenSBI (M-mode).
Due to the above reasons, the current OpenSBI RPMI patches
(posted recently) don't implement the optional "dma-non-coherent"
DT property in RPMI shared memory mailbox driver.
Regards,
Anup
>
> The librpmi project might be the place where we can document AP-PuC memory
> architectures for both cache-coherent/non-coherent cases, and provide some
> guidance to PuC firmware writers. Excuse me if I'm raising an already solved
> issue, as I'm not following RPMI discussion closely. Thanks!
>
> Bo
>
> On 8/6/24 00:33, Anup Patel wrote:
> > From: Rahul Pathak <rpathak at ventanamicro.com>
> >
> > The RISC-V Platform Management Interface (RPMI) defines a messaging protocol
> > and shared memory based transport for bi-directional communication with an
> > on-chip or external microcontroller.
> >
> > To support RPMI in OpenSBI, add:
> > 1) The RPMI messaging protocol defines and helper macros
> > 2) A FDT mailbox driver for the RPMI shared memory transport
> >
> > Signed-off-by: Rahul Pathak <rpathak at ventanamicro.com>
> > Co-developed-by: Subrahmanya Lingappa <slingappa at ventanamicro.com>
> > Signed-off-by: Subrahmanya Lingappa <slingappa at ventanamicro.com>
> > Co-developed-by: Anup Patel <apatel at ventanamicro.com>
> > Signed-off-by: Anup Patel <apatel at ventanamicro.com>
> > ---
> > include/sbi_utils/mailbox/rpmi_mailbox.h | 32 +
> > include/sbi_utils/mailbox/rpmi_msgprot.h | 186 ++++++
> > lib/utils/mailbox/Kconfig | 14 +
> > lib/utils/mailbox/fdt_mailbox_rpmi_shmem.c | 671 +++++++++++++++++++++
> > lib/utils/mailbox/objects.mk | 5 +
> > lib/utils/mailbox/rpmi_mailbox.c | 79 +++
> > platform/generic/configs/defconfig | 3 +
> > 7 files changed, 990 insertions(+)
> > create mode 100644 include/sbi_utils/mailbox/rpmi_mailbox.h
> > create mode 100644 include/sbi_utils/mailbox/rpmi_msgprot.h
> > create mode 100644 lib/utils/mailbox/fdt_mailbox_rpmi_shmem.c
> > create mode 100644 lib/utils/mailbox/rpmi_mailbox.c
> >
> > diff --git a/include/sbi_utils/mailbox/rpmi_mailbox.h b/include/sbi_utils/mailbox/rpmi_mailbox.h
> > new file mode 100644
> > index 00000000..61af51a8
> > --- /dev/null
> > +++ b/include/sbi_utils/mailbox/rpmi_mailbox.h
> > @@ -0,0 +1,32 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + *
> > + * Copyright (c) 2023 Ventana Micro Systems Inc.
> > + *
> > + * Authors:
> > + * Anup Patel <apatel at ventanamicro.com>
> > + */
> > +
> > +#ifndef __RPMI_MAILBOX_H__
> > +#define __RPMI_MAILBOX_H__
> > +
> > +#include <sbi/sbi_error.h>
> > +#include <sbi_utils/mailbox/rpmi_msgprot.h>
> > +
> > +#define rpmi_u32_count(__var) (sizeof(__var) / sizeof(u32))
> > +
> > +/** Convert RPMI error to SBI error */
> > +int rpmi_xlate_error(enum rpmi_error error);
> > +
> > +/** Typical RPMI normal request with at least status code in response */
> > +int rpmi_normal_request_with_status(
> > + struct mbox_chan *chan, u32 service_id,
> > + void *req, u32 req_words, u32 req_endian_words,
> > + void *resp, u32 resp_words, u32 resp_endian_words);
> > +
> > +/* RPMI posted request which is without any response*/
> > +int rpmi_posted_request(
> > + struct mbox_chan *chan, u32 service_id,
> > + void *req, u32 req_words, u32 req_endian_words);
> > +
> > +#endif /* !__RPMI_MAILBOX_H__ */
> > diff --git a/include/sbi_utils/mailbox/rpmi_msgprot.h b/include/sbi_utils/mailbox/rpmi_msgprot.h
> > new file mode 100644
> > index 00000000..e0c7cba0
> > --- /dev/null
> > +++ b/include/sbi_utils/mailbox/rpmi_msgprot.h
> > @@ -0,0 +1,186 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + *
> > + * Copyright (c) 2023 Ventana Micro Systems Inc.
> > + *
> > + * Authors:
> > + * Rahul Pathak <rpathak at ventanamicro.com>
> > + */
> > +
> > +#ifndef __RPMI_MSGPROT_H__
> > +#define __RPMI_MSGPROT_H__
> > +
> > +#include <sbi/sbi_byteorder.h>
> > +#include <sbi/sbi_error.h>
> > +
> > +/*
> > + * 31 0
> > + * +---------------------+-----------------------+
> > + * | FLAGS | SERVICE_ID | SERVICEGROUP_ID |
> > + * +---------------------+-----------------------+
> > + * | TOKEN | DATA LENGTH |
> > + * +---------------------+-----------------------+
> > + * | DATA/PAYLOAD |
> > + * +---------------------------------------------+
> > + */
> > +
> > +/** Message Header byte offset */
> > +#define RPMI_MSG_HDR_OFFSET (0x0)
> > +/** Message Header Size in bytes */
> > +#define RPMI_MSG_HDR_SIZE (8)
> > +
> > +/** ServiceGroup ID field byte offset */
> > +#define RPMI_MSG_SERVICEGROUP_ID_OFFSET (0x0)
> > +/** ServiceGroup ID field size in bytes */
> > +#define RPMI_MSG_SERVICEGROUP_ID_SIZE (2)
> > +
> > +/** Service ID field byte offset */
> > +#define RPMI_MSG_SERVICE_ID_OFFSET (0x2)
> > +/** Service ID field size in bytes */
> > +#define RPMI_MSG_SERVICE_ID_SIZE (1)
> > +
> > +/** Flags field byte offset */
> > +#define RPMI_MSG_FLAGS_OFFSET (0x3)
> > +/** Flags field size in bytes */
> > +#define RPMI_MSG_FLAGS_SIZE (1)
> > +
> > +#define RPMI_MSG_FLAGS_TYPE_POS (0U)
> > +#define RPMI_MSG_FLAGS_TYPE_MASK 0x7
> > +#define RPMI_MSG_FLAGS_TYPE \
> > + ((0x7) << RPMI_MSG_FLAGS_TYPE_POS)
> > +
> > +#define RPMI_MSG_FLAGS_DOORBELL_POS (3U)
> > +#define RPMI_MSG_FLAGS_DOORBELL_MASK 0x1
> > +#define RPMI_MSG_FLAGS_DOORBELL \
> > + ((0x1) << RPMI_MSG_FLAGS_DOORBELL_POS)
> > +
> > +/** Data length field byte offset */
> > +#define RPMI_MSG_DATALEN_OFFSET (0x4)
> > +/** Data length field size in bytes */
> > +#define RPMI_MSG_DATALEN_SIZE (2)
> > +
> > +/** Token field byte offset */
> > +#define RPMI_MSG_TOKEN_OFFSET (0x6)
> > +/** Token field size in bytes */
> > +#define RPMI_MSG_TOKEN_SIZE (2)
> > +/** Token field mask */
> > +#define RPMI_MSG_TOKEN_MASK (0xffffU)
> > +
> > +/** Data field byte offset */
> > +#define RPMI_MSG_DATA_OFFSET (RPMI_MSG_HDR_SIZE)
> > +/** Data field size in bytes */
> > +#define RPMI_MSG_DATA_SIZE(__slot_size) ((__slot_size) - RPMI_MSG_HDR_SIZE)
> > +
> > +/** Minimum slot size in bytes */
> > +#define RPMI_SLOT_SIZE_MIN (64)
> > +
> > +/** Name length of 16 characters */
> > +#define RPMI_NAME_CHARS_MAX (16)
> > +
> > +/** Queue layout */
> > +#define RPMI_QUEUE_HEAD_SLOT 0
> > +#define RPMI_QUEUE_TAIL_SLOT 1
> > +#define RPMI_QUEUE_HEADER_SLOTS 2
> > +
> > +/** Default timeout values */
> > +#define RPMI_DEF_TX_TIMEOUT 20
> > +#define RPMI_DEF_RX_TIMEOUT 20
> > +
> > +/** RPMI Message Header */
> > +struct rpmi_message_header {
> > + le16_t servicegroup_id;
> > + uint8_t service_id;
> > + uint8_t flags;
> > + le16_t datalen;
> > + le16_t token;
> > +} __packed;
> > +
> > +/** RPMI Message */
> > +struct rpmi_message {
> > + struct rpmi_message_header header;
> > + u8 data[0];
> > +} __packed;
> > +
> > +/** RPMI Messages Types */
> > +enum rpmi_message_type {
> > + /* Normal request backed with ack */
> > + RPMI_MSG_NORMAL_REQUEST = 0x0,
> > + /* Request without any ack */
> > + RPMI_MSG_POSTED_REQUEST = 0x1,
> > + /* Acknowledgment for normal request message */
> > + RPMI_MSG_ACKNOWLDGEMENT = 0x2,
> > + /* Notification message */
> > + RPMI_MSG_NOTIFICATION = 0x3,
> > +};
> > +
> > +/** RPMI Error Types */
> > +enum rpmi_error {
> > + RPMI_SUCCESS = 0,
> > + RPMI_ERR_FAILED = -1,
> > + RPMI_ERR_NOTSUPP = -2,
> > + RPMI_ERR_INVAL = -3,
> > + RPMI_ERR_DENIED = -4,
> > + RPMI_ERR_NOTFOUND = -5,
> > + RPMI_ERR_OUTOFRANGE = -6,
> > + RPMI_ERR_OUTOFRES = -7,
> > + RPMI_ERR_HWFAULT = -8,
> > +};
> > +
> > +/** RPMI Message Arguments */
> > +struct rpmi_message_args {
> > + u32 flags;
> > +#define RPMI_MSG_FLAGS_NO_TX (1U << 0)
> > +#define RPMI_MSG_FLAGS_NO_RX (1U << 1)
> > +#define RPMI_MSG_FLAGS_NO_RX_TOKEN (1U << 2)
> > + enum rpmi_message_type type;
> > + u8 service_id;
> > + u32 tx_endian_words;
> > + u32 rx_endian_words;
> > + u16 rx_token;
> > + u32 rx_data_len;
> > +};
> > +
> > +/*
> > + * RPMI SERVICEGROUPS AND SERVICES
> > + */
> > +
> > +/** RPMI ServiceGroups IDs */
> > +enum rpmi_servicegroup_id {
> > + RPMI_SRVGRP_ID_MIN = 0,
> > + RPMI_SRVGRP_BASE = 0x00001,
> > + RPMI_SRVGRP_ID_MAX_COUNT,
> > +};
> > +
> > +/** RPMI enable notification request */
> > +struct rpmi_enable_notification_req {
> > + u32 eventid;
> > +};
> > +
> > +/** RPMI enable notification response */
> > +struct rpmi_enable_notification_resp {
> > + s32 status;
> > +};
> > +
> > +/** RPMI Base ServiceGroup Service IDs */
> > +enum rpmi_base_service_id {
> > + RPMI_BASE_SRV_ENABLE_NOTIFICATION = 0x01,
> > + RPMI_BASE_SRV_GET_IMPLEMENTATION_VERSION = 0x02,
> > + RPMI_BASE_SRV_GET_IMPLEMENTATION_IDN = 0x03,
> > + RPMI_BASE_SRV_GET_SPEC_VERSION = 0x04,
> > + RPMI_BASE_SRV_GET_HW_INFO = 0x05,
> > + RPMI_BASE_SRV_PROBE_SERVICE_GROUP = 0x06,
> > + RPMI_BASE_SRV_GET_ATTRIBUTES = 0x07,
> > + RPMI_BASE_SRV_SET_MSI = 0x08,
> > +};
> > +
> > +struct rpmi_base_get_attributes_resp {
> > + s32 status_code;
> > +#define RPMI_BASE_FLAGS_F0_EV_NOTIFY (1U << 31)
> > +#define RPMI_BASE_FLAGS_F0_MSI_EN (1U << 30)
> > + u32 f0;
> > + u32 f1;
> > + u32 f2;
> > + u32 f3;
> > +};
> > +
> > +#endif /* !__RPMI_MSGPROT_H__ */
> > diff --git a/lib/utils/mailbox/Kconfig b/lib/utils/mailbox/Kconfig
> > index 3957bfba..6e7f2cdd 100644
> > --- a/lib/utils/mailbox/Kconfig
> > +++ b/lib/utils/mailbox/Kconfig
> > @@ -8,8 +8,22 @@ config FDT_MAILBOX
> > select MAILBOX
> > default n
> >
> > +config RPMI_MAILBOX
> > + bool "RPMI based mailbox drivers"
> > + select MAILBOX
> > + default n
> > +
> > config MAILBOX
> > bool "Mailbox support"
> > default n
> >
> > +if FDT_MAILBOX
> > +
> > +config FDT_MAILBOX_RPMI_SHMEM
> > + bool "RPMI Shared Memory Mailbox Controller"
> > + depends on RPMI_MAILBOX
> > + default n
> > +
> > +endif
> > +
> > endmenu
> > diff --git a/lib/utils/mailbox/fdt_mailbox_rpmi_shmem.c b/lib/utils/mailbox/fdt_mailbox_rpmi_shmem.c
> > new file mode 100644
> > index 00000000..9705507c
> > --- /dev/null
> > +++ b/lib/utils/mailbox/fdt_mailbox_rpmi_shmem.c
> > @@ -0,0 +1,671 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + *
> > + * Copyright (c) 2024 Ventana Micro Systems Inc.
> > + *
> > + * Authors:
> > + * Rahul Pathak <rpathak at ventanamicro.com>
> > + * Subrahmanya Lingappa <slingappa at ventanamicro.com>
> > + * Anup Patel <apatel at ventanamicro.com>
> > + */
> > +
> > +#include <libfdt.h>
> > +#include <sbi/sbi_console.h>
> > +#include <sbi/sbi_error.h>
> > +#include <sbi/sbi_heap.h>
> > +#include <sbi/sbi_timer.h>
> > +#include <sbi/riscv_io.h>
> > +#include <sbi/riscv_locks.h>
> > +#include <sbi/riscv_asm.h>
> > +#include <sbi/riscv_barrier.h>
> > +#include <sbi_utils/fdt/fdt_helper.h>
> > +#include <sbi_utils/mailbox/mailbox.h>
> > +#include <sbi_utils/mailbox/fdt_mailbox.h>
> > +#include <sbi_utils/mailbox/rpmi_mailbox.h>
> > +
> > +/**************** RPMI Transport Structures and Macros ***********/
> > +
> > +#define RPMI_MAILBOX_CHANNELS_MAX (16)
> > +
> > +#define GET_SERVICEGROUP_ID(msg) \
> > +({ \
> > + struct rpmi_message *mbuf = msg; \
> > + le16_to_cpu(mbuf->header.servicegroup_id);\
> > +})
> > +
> > +#define GET_SERVICE_ID(msg) \
> > +({ \
> > + struct rpmi_message *mbuf = msg; \
> > + mbuf->header.service_id; \
> > +})
> > +
> > +#define GET_FLAGS(msg) \
> > +({ \
> > + struct rpmi_message *mbuf = msg; \
> > + mbuf->header.flags; \
> > +})
> > +
> > +#define GET_MESSAGE_ID(msg) \
> > +({ \
> > + struct rpmi_message *mbuf = msg; \
> > + ((u32)mbuf->header.flags << (RPMI_MSG_FLAGS_OFFSET * 8)) | \
> > + ((u32)mbuf->header.service_id << (RPMI_MSG_SERVICE_ID_OFFSET * 8)) | \
> > + ((u32)le16_to_cpu(mbuf->header.servicegroup_id)); \
> > +})
> > +
> > +#define MAKE_MESSAGE_ID(__group_id, __service_id, __flags) \
> > +({ \
> > + u32 __ret = 0; \
> > + __ret |= (u32)(__group_id) << (RPMI_MSG_SERVICEGROUP_ID_OFFSET * 8); \
> > + __ret |= (u32)(__service_id) << (RPMI_MSG_SERVICE_ID_OFFSET * 8); \
> > + __ret |= (u32)(__flags) << (RPMI_MSG_FLAGS_OFFSET * 8); \
> > + __ret; \
> > +})
> > +
> > +#define GET_DLEN(msg) \
> > +({ \
> > + struct rpmi_message *mbuf = msg; \
> > + le16_to_cpu(mbuf->header.datalen); \
> > +})
> > +
> > +#define GET_TOKEN(msg) \
> > +({ \
> > + struct rpmi_message *mbuf = msg; \
> > + le16_to_cpu(mbuf->header.token); \
> > +})
> > +
> > +#define GET_MESSAGE_TYPE(msg) \
> > +({ \
> > + uint8_t flags = *((uint8_t *)msg + RPMI_MSG_FLAGS_OFFSET); \
> > + ((flags & RPMI_MSG_FLAGS_TYPE) >> RPMI_MSG_FLAGS_TYPE_POS)); \
> > +})
> > +
> > +enum rpmi_queue_type {
> > + RPMI_QUEUE_TYPE_REQ = 0,
> > + RPMI_QUEUE_TYPE_ACK = 1,
> > +};
> > +
> > +enum rpmi_queue_idx {
> > + RPMI_QUEUE_IDX_A2P_REQ = 0,
> > + RPMI_QUEUE_IDX_P2A_ACK = 1,
> > + RPMI_QUEUE_IDX_P2A_REQ = 2,
> > + RPMI_QUEUE_IDX_A2P_ACK = 3,
> > + RPMI_QUEUE_IDX_MAX_COUNT,
> > +};
> > +
> > +enum rpmi_reg_idx {
> > + RPMI_REG_IDX_DB_REG = 0, /* Doorbell register */
> > + RPMI_REG_IDX_MAX_COUNT,
> > +};
> > +
> > +/** Mailbox registers */
> > +struct rpmi_mb_regs {
> > + /* doorbell from AP -> PuC*/
> > + volatile le32_t db_reg;
> > +} __packed;
> > +
> > +/** Single Queue Context Structure */
> > +struct smq_queue_ctx {
> > + u32 queue_id;
> > + u32 num_slots;
> > + spinlock_t queue_lock;
> > + /* Type of queue - REQ or ACK */
> > + enum rpmi_queue_type queue_type;
> > + /* Pointers to the queue shared memory */
> > + volatile le32_t *headptr;
> > + volatile le32_t *tailptr;
> > + volatile uint8_t *buffer;
> > + /* Name of the queue */
> > + char name[RPMI_NAME_CHARS_MAX];
> > +};
> > +
> > +struct rpmi_shmem_mbox_controller {
> > + /* Driver specific members */
> > + u32 slot_size;
> > + u32 queue_count;
> > + struct rpmi_mb_regs *mb_regs;
> > + struct smq_queue_ctx queue_ctx_tbl[RPMI_QUEUE_IDX_MAX_COUNT];
> > + /* Mailbox framework related members */
> > + struct mbox_controller controller;
> > + struct mbox_chan channels[RPMI_MAILBOX_CHANNELS_MAX];
> > + struct mbox_chan *base_chan;
> > + u32 impl_version;
> > + u32 impl_id;
> > + u32 spec_version;
> > + struct {
> > + bool f0_ev_notif_en;
> > + bool f0_msi_en;
> > + } base_flags;
> > +};
> > +
> > +/**************** Shared Memory Queues Helpers **************/
> > +
> > +static bool __smq_queue_full(struct smq_queue_ctx *qctx)
> > +{
> > + return ((le32_to_cpu(*qctx->tailptr) + 1) % qctx->num_slots ==
> > + le32_to_cpu(*qctx->headptr)) ? true : false;
> > +}
> > +
> > +static bool __smq_queue_empty(struct smq_queue_ctx *qctx)
> > +{
> > + return (le32_to_cpu(*qctx->headptr) ==
> > + le32_to_cpu(*qctx->tailptr)) ? true : false;
> > +}
> > +
> > +static int __smq_rx(struct smq_queue_ctx *qctx, u32 slot_size,
> > + u32 service_group_id, struct mbox_xfer *xfer)
> > +{
> > + void *dst, *src;
> > + struct rpmi_message *msg;
> > + u32 i, tmp, pos, dlen, msgidn, headidx, tailidx;
> > + struct rpmi_message_args *args = xfer->args;
> > + bool no_rx_token = (args->flags & RPMI_MSG_FLAGS_NO_RX_TOKEN) ?
> > + true : false;
> > +
> > + /* Rx sanity checks */
> > + if ((sizeof(u32) * args->rx_endian_words) >
> > + (slot_size - sizeof(struct rpmi_message_header)))
> > + return SBI_EINVAL;
> > + if ((sizeof(u32) * args->rx_endian_words) > xfer->rx_len)
> > + return SBI_EINVAL;
> > +
> > + /* There should be some message in the queue */
> > + if (__smq_queue_empty(qctx))
> > + return SBI_ENOENT;
> > +
> > + /* Get the head/read index and tail/write index */
> > + headidx = le32_to_cpu(*qctx->headptr);
> > + tailidx = le32_to_cpu(*qctx->tailptr);
> > +
> > + /*
> > + * Compute msgidn expected in the incoming message
> > + * NOTE: DOORBELL bit is not expected to be set.
> > + */
> > + msgidn = MAKE_MESSAGE_ID(service_group_id, args->service_id, args->type);
> > +
> > + /* Find the Rx message with matching token */
> > + pos = headidx;
> > + while (pos != tailidx) {
> > + src = (void *)qctx->buffer + (pos * slot_size);
> > + if ((no_rx_token && GET_MESSAGE_ID(src) == msgidn) ||
> > + (GET_TOKEN(src) == (xfer->seq & RPMI_MSG_TOKEN_MASK)))
> > + break;
> > + pos = (pos + 1) % qctx->num_slots;
> > + }
> > + if (pos == tailidx)
> > + return SBI_ENOENT;
> > +
> > + /* If Rx message is not first message then make it first message */
> > + if (pos != headidx) {
> > + src = (void *)qctx->buffer + (pos * slot_size);
> > + dst = (void *)qctx->buffer + (headidx * slot_size);
> > + for (i = 0; i < slot_size / sizeof(u32); i++) {
> > + tmp = ((u32 *)dst)[i];
> > + ((u32 *)dst)[i] = ((u32 *)src)[i];
> > + ((u32 *)src)[i] = tmp;
> > + }
> > + }
> > +
> > + /* Update rx_token if not available */
> > + msg = (void *)qctx->buffer + (headidx * slot_size);
> > + if (no_rx_token)
> > + args->rx_token = GET_TOKEN(msg);
> > +
> > + /* Extract data from the first message */
> > + if (xfer->rx) {
> > + args->rx_data_len = dlen = GET_DLEN(msg);
> > + if (dlen > xfer->rx_len)
> > + dlen = xfer->rx_len;
> > + src = (void *)msg + sizeof(struct rpmi_message_header);
> > + dst = xfer->rx;
> > + for (i = 0; i < args->rx_endian_words; i++)
> > + ((u32 *)dst)[i] = le32_to_cpu(((u32 *)src)[i]);
> > + dst += sizeof(u32) * args->rx_endian_words;
> > + src += sizeof(u32) * args->rx_endian_words;
> > + sbi_memcpy(dst, src,
> > + xfer->rx_len - (sizeof(u32) * args->rx_endian_words));
> > + }
> > +
> > + /* Update the head/read index */
> > + *qctx->headptr = cpu_to_le32(headidx + 1) % qctx->num_slots;
> > + smp_wmb();
> > +
> > + return SBI_OK;
> > +}
> > +
> > +static int __smq_tx(struct smq_queue_ctx *qctx, struct rpmi_mb_regs *mb_regs,
> > + u32 slot_size, u32 service_group_id, struct mbox_xfer *xfer)
> > +{
> > + u32 i, tailidx;
> > + void *dst, *src;
> > + struct rpmi_message_header header = { 0 };
> > + struct rpmi_message_args *args = xfer->args;
> > +
> > + /* Tx sanity checks */
> > + if ((sizeof(u32) * args->tx_endian_words) >
> > + (slot_size - sizeof(struct rpmi_message_header)))
> > + return SBI_EINVAL;
> > + if ((sizeof(u32) * args->tx_endian_words) > xfer->tx_len)
> > + return SBI_EINVAL;
> > +
> > + /* There should be some room in the queue */
> > + if (__smq_queue_full(qctx))
> > + return SBI_ENOMEM;
> > +
> > + /* Get the tail/write index */
> > + tailidx = le32_to_cpu(*qctx->tailptr);
> > +
> > + /* Prepare the header to be written into the slot */
> > + header.servicegroup_id = cpu_to_le16(service_group_id);
> > + header.service_id = args->service_id;
> > + header.flags = args->type;
> > + header.datalen = cpu_to_le16((u16)xfer->tx_len);
> > + header.token = cpu_to_le16((u16)xfer->seq);
> > +
> > + /* Write header into the slot */
> > + dst = (char *)qctx->buffer + (tailidx * slot_size);
> > + sbi_memcpy(dst, &header, sizeof(header));
> > + dst += sizeof(header);
> > +
> > + /* Write data into the slot */
> > + if (xfer->tx) {
> > + src = xfer->tx;
> > + for (i = 0; i < args->tx_endian_words; i++)
> > + ((u32 *)dst)[i] = cpu_to_le32(((u32 *)src)[i]);
> > + dst += sizeof(u32) * args->tx_endian_words;
> > + src += sizeof(u32) * args->tx_endian_words;
> > + sbi_memcpy(dst, src,
> > + xfer->tx_len - (sizeof(u32) * args->tx_endian_words));
> > + }
> > +
> > + /* Update the tail/write index */
> > + *qctx->tailptr = cpu_to_le32(tailidx + 1) % qctx->num_slots;
> > + smp_wmb();
> > +
> > + /* Ring the RPMI doorbell if present */
> > + if (mb_regs)
> > + writel(cpu_to_le32(1), &mb_regs->db_reg);
> > +
> > + return SBI_OK;
> > +}
> > +
> > +static int smq_rx(struct rpmi_shmem_mbox_controller *mctl,
> > + u32 queue_id, u32 service_group_id, struct mbox_xfer *xfer)
> > +{
> > + int ret, rxretry = 0;
> > + struct smq_queue_ctx *qctx;
> > +
> > + if (mctl->queue_count < queue_id ||
> > + RPMI_MAILBOX_CHANNELS_MAX <= service_group_id) {
> > + sbi_printf("%s: invalid queue_id or service_group_id\n",
> > + __func__);
> > + return SBI_EINVAL;
> > + }
> > + qctx = &mctl->queue_ctx_tbl[queue_id];
> > +
> > + /*
> > + * Once the timeout happens and call this function is returned
> > + * to the client then there is no way to deliver the response
> > + * message after that if it comes later.
> > + *
> > + * REVISIT: In complete timeout duration how much duration
> > + * it should wait(delay) before recv retry. udelay or mdelay
> > + */
> > + do {
> > + spin_lock(&qctx->queue_lock);
> > + ret = __smq_rx(qctx, mctl->slot_size, service_group_id, xfer);
> > + spin_unlock(&qctx->queue_lock);
> > + if (!ret)
> > + return 0;
> > +
> > + sbi_timer_mdelay(1);
> > + rxretry += 1;
> > + } while (rxretry < xfer->rx_timeout);
> > +
> > + return SBI_ETIMEDOUT;
> > +}
> > +
> > +static int smq_tx(struct rpmi_shmem_mbox_controller *mctl,
> > + u32 queue_id, u32 service_group_id, struct mbox_xfer *xfer)
> > +{
> > + int ret, txretry = 0;
> > + struct smq_queue_ctx *qctx;
> > +
> > + if (mctl->queue_count < queue_id ||
> > + RPMI_MAILBOX_CHANNELS_MAX <= service_group_id) {
> > + sbi_printf("%s: invalid queue_id or service_group_id\n",
> > + __func__);
> > + return SBI_EINVAL;
> > + }
> > + qctx = &mctl->queue_ctx_tbl[queue_id];
> > +
> > + /*
> > + * Ignoring the tx timeout since in RPMI has no mechanism
> > + * with which other side can let know about the reception of
> > + * message which marks as tx complete. For RPMI tx complete is
> > + * marked as done when message in successfully copied in queue.
> > + *
> > + * REVISIT: In complete timeout duration how much duration
> > + * it should wait(delay) before send retry. udelay or mdelay
> > + */
> > + do {
> > + spin_lock(&qctx->queue_lock);
> > + ret = __smq_tx(qctx, mctl->mb_regs, mctl->slot_size,
> > + service_group_id, xfer);
> > + spin_unlock(&qctx->queue_lock);
> > + if (!ret)
> > + return 0;
> > +
> > + sbi_timer_mdelay(1);
> > + txretry += 1;
> > + } while (txretry < xfer->tx_timeout);
> > +
> > + return SBI_ETIMEDOUT;
> > +}
> > +
> > +static int smq_base_get_two_u32(struct rpmi_shmem_mbox_controller *mctl,
> > + u32 service_id, u32 *inarg, u32 *outvals)
> > +{
> > + return rpmi_normal_request_with_status(
> > + mctl->base_chan, service_id,
> > + inarg, (inarg) ? 1 : 0, (inarg) ? 1 : 0,
> > + outvals, 2, 2);
> > +}
> > +
> > +/**************** Mailbox Controller Functions **************/
> > +
> > +static int rpmi_shmem_mbox_xfer(struct mbox_chan *chan, struct mbox_xfer *xfer)
> > +{
> > + int ret;
> > + u32 tx_qid = 0, rx_qid = 0;
> > + struct rpmi_shmem_mbox_controller *mctl =
> > + container_of(chan->mbox,
> > + struct rpmi_shmem_mbox_controller,
> > + controller);
> > + struct rpmi_message_args *args = xfer->args;
> > + bool do_tx = (args->flags & RPMI_MSG_FLAGS_NO_TX) ? false : true;
> > + bool do_rx = (args->flags & RPMI_MSG_FLAGS_NO_RX) ? false : true;
> > +
> > + if (!do_tx && !do_rx)
> > + return SBI_EINVAL;
> > +
> > + switch (args->type) {
> > + case RPMI_MSG_NORMAL_REQUEST:
> > + if (do_tx && do_rx) {
> > + tx_qid = RPMI_QUEUE_IDX_A2P_REQ;
> > + rx_qid = RPMI_QUEUE_IDX_P2A_ACK;
> > + } else if (do_tx) {
> > + tx_qid = RPMI_QUEUE_IDX_A2P_REQ;
> > + } else if (do_rx) {
> > + rx_qid = RPMI_QUEUE_IDX_P2A_REQ;
> > + }
> > + break;
> > + case RPMI_MSG_POSTED_REQUEST:
> > + if (do_tx && do_rx)
> > + return SBI_EINVAL;
> > + if (do_tx) {
> > + tx_qid = RPMI_QUEUE_IDX_A2P_REQ;
> > + } else {
> > + rx_qid = RPMI_QUEUE_IDX_P2A_REQ;
> > + }
> > + break;
> > + case RPMI_MSG_ACKNOWLDGEMENT:
> > + if (do_tx && do_rx)
> > + return SBI_EINVAL;
> > + if (do_tx) {
> > + tx_qid = RPMI_QUEUE_IDX_A2P_ACK;
> > + } else {
> > + rx_qid = RPMI_QUEUE_IDX_P2A_ACK;
> > + }
> > + break;
> > + default:
> > + return SBI_ENOTSUPP;
> > + }
> > +
> > + if (do_tx) {
> > + ret = smq_tx(mctl, tx_qid, chan - mctl->channels, xfer);
> > + if (ret)
> > + return ret;
> > + }
> > +
> > + if (do_rx) {
> > + ret = smq_rx(mctl, rx_qid, chan - mctl->channels, xfer);
> > + if (ret)
> > + return ret;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static struct mbox_chan *rpmi_shmem_mbox_request_chan(
> > + struct mbox_controller *mbox,
> > + u32 *chan_args)
> > +{
> > + int ret;
> > + u32 tval[2] = { 0 };
> > + struct rpmi_shmem_mbox_controller *mctl =
> > + container_of(mbox,
> > + struct rpmi_shmem_mbox_controller,
> > + controller);
> > +
> > + if (chan_args[0] >= RPMI_MAILBOX_CHANNELS_MAX)
> > + return NULL;
> > +
> > + /* Base serivce group is always present so probe other groups */
> > + if (chan_args[0] != RPMI_SRVGRP_BASE) {
> > + /* Probe service group */
> > + ret = smq_base_get_two_u32(mctl,
> > + RPMI_BASE_SRV_PROBE_SERVICE_GROUP,
> > + chan_args, tval);
> > + if (ret || !tval[1])
> > + return NULL;
> > + }
> > +
> > + return &mctl->channels[chan_args[0]];
> > +}
> > +
> > +static void *rpmi_shmem_mbox_free_chan(struct mbox_controller *mbox,
> > + struct mbox_chan *chan)
> > +{
> > + /* Nothing to do here */
> > + return NULL;
> > +}
> > +
> > +extern struct fdt_mailbox fdt_mailbox_rpmi_shmem;
> > +
> > +static int rpmi_shmem_transport_init(struct rpmi_shmem_mbox_controller *mctl,
> > + void *fdt, int nodeoff)
> > +{
> > + const char *name;
> > + int count, len, ret, qid;
> > + uint64_t reg_addr, reg_size;
> > + const fdt32_t *prop_slotsz;
> > + struct smq_queue_ctx *qctx;
> > +
> > + ret = fdt_node_check_compatible(fdt, nodeoff,
> > + "riscv,rpmi-shmem-mbox");
> > + if (ret)
> > + return ret;
> > +
> > + /* get queue slot size in bytes */
> > + prop_slotsz = fdt_getprop(fdt, nodeoff, "riscv,slot-size", &len);
> > + if (!prop_slotsz)
> > + return SBI_ENOENT;
> > +
> > + mctl->slot_size = fdt32_to_cpu(*prop_slotsz);
> > + if (mctl->slot_size < RPMI_SLOT_SIZE_MIN) {
> > + sbi_printf("%s: slot_size < mimnum required message size\n",
> > + __func__);
> > + mctl->slot_size = RPMI_SLOT_SIZE_MIN;
> > + }
> > +
> > + /*
> > + * queue names count is taken as the number of queues
> > + * supported which make it mandatory to provide the
> > + * name of the queue.
> > + */
> > + count = fdt_stringlist_count(fdt, nodeoff, "reg-names");
> > + if (count < 0 ||
> > + count > (RPMI_QUEUE_IDX_MAX_COUNT + RPMI_REG_IDX_MAX_COUNT))
> > + return SBI_EINVAL;
> > +
> > + mctl->queue_count = count - RPMI_REG_IDX_MAX_COUNT;
> > +
> > + /* parse all queues and populate queues context structure */
> > + for (qid = 0; qid < mctl->queue_count; qid++) {
> > + qctx = &mctl->queue_ctx_tbl[qid];
> > +
> > + /* get each queue share-memory base address and size*/
> > + ret = fdt_get_node_addr_size(fdt, nodeoff, qid,
> > + ®_addr, ®_size);
> > + if (ret < 0 || !reg_addr || !reg_size)
> > + return SBI_ENOENT;
> > +
> > + ret = sbi_domain_root_add_memrange(reg_addr, reg_size, reg_size,
> > + (SBI_DOMAIN_MEMREGION_MMIO |
> > + SBI_DOMAIN_MEMREGION_M_READABLE |
> > + SBI_DOMAIN_MEMREGION_M_WRITABLE));
> > + if (ret)
> > + return ret;
> > +
> > + /* calculate number of slots in each queue */
> > + qctx->num_slots =
> > + (reg_size - (mctl->slot_size * RPMI_QUEUE_HEADER_SLOTS)) / mctl->slot_size;
> > +
> > + /* setup queue pointers */
> > + qctx->headptr = ((void *)(unsigned long)reg_addr) +
> > + RPMI_QUEUE_HEAD_SLOT * mctl->slot_size;
> > + qctx->tailptr = ((void *)(unsigned long)reg_addr) +
> > + RPMI_QUEUE_TAIL_SLOT * mctl->slot_size;
> > + qctx->buffer = ((void *)(unsigned long)reg_addr) +
> > + RPMI_QUEUE_HEADER_SLOTS * mctl->slot_size;
> > +
> > + /* get the queue name */
> > + name = fdt_stringlist_get(fdt, nodeoff, "reg-names",
> > + qid, &len);
> > + if (!name || (name && len < 0))
> > + return len;
> > +
> > + sbi_memcpy(qctx->name, name, len);
> > +
> > + /* store the index as queue_id */
> > + qctx->queue_id = qid;
> > +
> > + SPIN_LOCK_INIT(qctx->queue_lock);
> > + }
> > +
> > + /* get the db-reg property name */
> > + name = fdt_stringlist_get(fdt, nodeoff, "reg-names", qid, &len);
> > + if (!name || (name && len < 0))
> > + return len;
> > +
> > + /* fetch doorbell register address*/
> > + ret = fdt_get_node_addr_size(fdt, nodeoff, qid, ®_addr,
> > + ®_size);
> > + if (!ret && !(strncmp(name, "db-reg", strlen("db-reg")))) {
> > + mctl->mb_regs = (void *)(unsigned long)reg_addr;
> > + ret = sbi_domain_root_add_memrange(reg_addr, reg_size, reg_size,
> > + (SBI_DOMAIN_MEMREGION_MMIO |
> > + SBI_DOMAIN_MEMREGION_M_READABLE |
> > + SBI_DOMAIN_MEMREGION_M_WRITABLE));
> > + if (ret)
> > + return ret;
> > + }
> > +
> > + return SBI_SUCCESS;
> > +}
> > +
> > +static int rpmi_shmem_mbox_init(void *fdt, int nodeoff, u32 phandle,
> > + const struct fdt_match *match)
> > +{
> > + int ret = 0;
> > + u32 tval[2];
> > + struct rpmi_base_get_attributes_resp resp;
> > + struct rpmi_shmem_mbox_controller *mctl;
> > +
> > + mctl = sbi_zalloc(sizeof(*mctl));
> > + if (!mctl)
> > + return SBI_ENOMEM;
> > +
> > + /* Initialization transport from device tree */
> > + ret = rpmi_shmem_transport_init(mctl, fdt, nodeoff);
> > + if (ret)
> > + goto fail_free_controller;
> > +
> > + /* Register mailbox controller */
> > + mctl->controller.id = phandle;
> > + mctl->controller.max_xfer_len =
> > + mctl->slot_size - sizeof(struct rpmi_message_header);
> > + mctl->controller.driver = &fdt_mailbox_rpmi_shmem;
> > + mctl->controller.request_chan = rpmi_shmem_mbox_request_chan;
> > + mctl->controller.free_chan = rpmi_shmem_mbox_free_chan;
> > + mctl->controller.xfer = rpmi_shmem_mbox_xfer;
> > + ret = mbox_controller_add(&mctl->controller);
> > + if (ret)
> > + goto fail_free_controller;
> > +
> > + /* Request base service group channel */
> > + tval[0] = RPMI_SRVGRP_BASE;
> > + mctl->base_chan = mbox_controller_request_chan(&mctl->controller,
> > + tval);
> > + if (!mctl->base_chan) {
> > + ret = SBI_ENOENT;
> > + goto fail_remove_controller;
> > + }
> > +
> > + /* Get implementation id */
> > + ret = smq_base_get_two_u32(mctl,
> > + RPMI_BASE_SRV_GET_IMPLEMENTATION_VERSION,
> > + NULL, tval);
> > + if (ret)
> > + goto fail_free_chan;
> > + mctl->impl_version = tval[1];
> > +
> > + /* Get implementation version */
> > + ret = smq_base_get_two_u32(mctl, RPMI_BASE_SRV_GET_IMPLEMENTATION_IDN,
> > + NULL, tval);
> > + if (ret)
> > + goto fail_free_chan;
> > + mctl->impl_id = tval[1];
> > +
> > + /* Get specification version */
> > + ret = smq_base_get_two_u32(mctl, RPMI_BASE_SRV_GET_SPEC_VERSION,
> > + NULL, tval);
> > + if (ret)
> > + goto fail_free_chan;
> > + mctl->spec_version = tval[1];
> > +
> > + /* Get optional features implementation flags */
> > + ret = rpmi_normal_request_with_status(
> > + mctl->base_chan, RPMI_BASE_SRV_GET_ATTRIBUTES,
> > + NULL, 0, 0,
> > + &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
> > + if (ret)
> > + goto fail_free_chan;
> > +
> > + mctl->base_flags.f0_ev_notif_en =
> > + resp.f0 & RPMI_BASE_FLAGS_F0_EV_NOTIFY ? 1 : 0;
> > + mctl->base_flags.f0_msi_en =
> > + resp.f0 & RPMI_BASE_FLAGS_F0_MSI_EN ? 1 : 0;
> > +
> > + return 0;
> > +
> > +fail_free_chan:
> > + mbox_controller_free_chan(mctl->base_chan);
> > +fail_remove_controller:
> > + mbox_controller_remove(&mctl->controller);
> > +fail_free_controller:
> > + sbi_free(mctl);
> > + return ret;
> > +}
> > +
> > +static const struct fdt_match rpmi_shmem_mbox_match[] = {
> > + { .compatible = "riscv,rpmi-shmem-mbox" },
> > + { },
> > +};
> > +
> > +struct fdt_mailbox fdt_mailbox_rpmi_shmem = {
> > + .match_table = rpmi_shmem_mbox_match,
> > + .init = rpmi_shmem_mbox_init,
> > + .xlate = fdt_mailbox_simple_xlate,
> > +};
> > diff --git a/lib/utils/mailbox/objects.mk b/lib/utils/mailbox/objects.mk
> > index 2135898c..746b0313 100644
> > --- a/lib/utils/mailbox/objects.mk
> > +++ b/lib/utils/mailbox/objects.mk
> > @@ -11,3 +11,8 @@ libsbiutils-objs-$(CONFIG_FDT_MAILBOX) += mailbox/fdt_mailbox.o
> > libsbiutils-objs-$(CONFIG_FDT_MAILBOX) += mailbox/fdt_mailbox_drivers.carray.o
> >
> > libsbiutils-objs-$(CONFIG_MAILBOX) += mailbox/mailbox.o
> > +
> > +libsbiutils-objs-$(CONFIG_RPMI_MAILBOX) += mailbox/rpmi_mailbox.o
> > +
> > +carray-fdt_mailbox_drivers-$(CONFIG_FDT_MAILBOX_RPMI_SHMEM) += fdt_mailbox_rpmi_shmem
> > +libsbiutils-objs-$(CONFIG_FDT_MAILBOX_RPMI_SHMEM) += mailbox/fdt_mailbox_rpmi_shmem.o
> > diff --git a/lib/utils/mailbox/rpmi_mailbox.c b/lib/utils/mailbox/rpmi_mailbox.c
> > new file mode 100644
> > index 00000000..58c64e56
> > --- /dev/null
> > +++ b/lib/utils/mailbox/rpmi_mailbox.c
> > @@ -0,0 +1,79 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + *
> > + * Copyright (c) 2023 Ventana Micro Systems Inc.
> > + *
> > + * Authors:
> > + * Anup Patel <apatel at ventanamicro.com>
> > + */
> > +
> > +#include <sbi/sbi_error.h>
> > +#include <sbi_utils/mailbox/mailbox.h>
> > +#include <sbi_utils/mailbox/rpmi_mailbox.h>
> > +
> > +int rpmi_xlate_error(enum rpmi_error error)
> > +{
> > + switch (error) {
> > + case RPMI_SUCCESS:
> > + return SBI_OK;
> > + case RPMI_ERR_FAILED:
> > + return SBI_EFAIL;
> > + case RPMI_ERR_NOTSUPP:
> > + return SBI_ENOTSUPP;
> > + case RPMI_ERR_INVAL:
> > + return SBI_EINVAL;
> > + case RPMI_ERR_DENIED:
> > + return SBI_EDENIED;
> > + case RPMI_ERR_NOTFOUND:
> > + return SBI_ENOENT;
> > + case RPMI_ERR_OUTOFRANGE:
> > + return SBI_EINVAL;
> > + case RPMI_ERR_OUTOFRES:
> > + return SBI_ENOSPC;
> > + case RPMI_ERR_HWFAULT:
> > + return SBI_EIO;
> > + default:
> > + return SBI_EUNKNOWN;
> > + }
> > +}
> > +
> > +int rpmi_normal_request_with_status(
> > + struct mbox_chan *chan, u32 service_id,
> > + void *req, u32 req_words, u32 req_endian_words,
> > + void *resp, u32 resp_words, u32 resp_endian_words)
> > +{
> > + int ret;
> > + struct mbox_xfer xfer;
> > + struct rpmi_message_args args = { 0 };
> > +
> > + args.type = RPMI_MSG_NORMAL_REQUEST;
> > + args.service_id = service_id;
> > + args.tx_endian_words = req_endian_words;
> > + args.rx_endian_words = resp_endian_words;
> > + mbox_xfer_init_txrx(&xfer, &args,
> > + req, sizeof(u32) * req_words, RPMI_DEF_TX_TIMEOUT,
> > + resp, sizeof(u32) * resp_words, RPMI_DEF_RX_TIMEOUT);
> > +
> > + ret = mbox_chan_xfer(chan, &xfer);
> > + if (ret)
> > + return ret;
> > +
> > + return rpmi_xlate_error(((u32 *)resp)[0]);
> > +}
> > +
> > +int rpmi_posted_request(
> > + struct mbox_chan *chan, u32 service_id,
> > + void *req, u32 req_words, u32 req_endian_words)
> > +{
> > + struct mbox_xfer xfer;
> > + struct rpmi_message_args args = { 0 };
> > +
> > + args.type = RPMI_MSG_POSTED_REQUEST;
> > + args.flags = RPMI_MSG_FLAGS_NO_RX;
> > + args.service_id = service_id;
> > + args.tx_endian_words = req_endian_words;
> > + mbox_xfer_init_tx(&xfer, &args,
> > + req, sizeof(u32) * req_words, RPMI_DEF_TX_TIMEOUT);
> > +
> > + return mbox_chan_xfer(chan, &xfer);
> > +}
> > diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> > index 079bc4fe..233a9a89 100644
> > --- a/platform/generic/configs/defconfig
> > +++ b/platform/generic/configs/defconfig
> > @@ -20,6 +20,9 @@ CONFIG_FDT_IRQCHIP=y
> > CONFIG_FDT_IRQCHIP_APLIC=y
> > CONFIG_FDT_IRQCHIP_IMSIC=y
> > CONFIG_FDT_IRQCHIP_PLIC=y
> > +CONFIG_FDT_MAILBOX=y
> > +CONFIG_RPMI_MAILBOX=y
> > +CONFIG_FDT_MAILBOX_RPMI_SHMEM=y
> > CONFIG_FDT_REGMAP=y
> > CONFIG_FDT_REGMAP_SYSCON=y
> > CONFIG_FDT_RESET=y
More information about the opensbi
mailing list