* [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI
@ 2024-08-06 7:33 Anup Patel
2024-08-06 7:33 ` [PATCH 01/16] lib: Increase ROOT_REGION_MAX to accomodate more memregions Anup Patel
` (15 more replies)
0 siblings, 16 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
This series adds RPMI and SBI MPXY support for OpenSBI. The RPMI service
groups supported include system reset, system suspend, HSM, CPPC, and
clock. The RPMI clock serivice group is exposed to supervisor software
as an MPXY channel.
These patches can also be found in the rpmi_mpxy_v1 branch at:
https://github.com/avpatel/opensbi.git
To test these patches, use the dev-upstream branch of following repos:
* https://github.com/ventanamicro/qemu.git
* https://github.com/ventanamicro/linux.git
To enable QEMU RPMI emulation (using librpmi), use "virt,rpmi=on" as
the QEMU machine name.
Anup Patel (7):
lib: utils/mailbox: Add generic mailbox library
lib: utils/mailbox: Add simple FDT based mailbox framework
lib: utils: Add simple FDT based system suspend driver framework
lib: utils: Add simple FDT based HSM driver framework
lib: utils: Add simple FDT based CPPC driver framework
lib: sbi: Implement SBI MPXY extension
lib: utils: Add simple FDT based MPXY driver framework
Rahul Pathak (5):
lib: Increase ROOT_REGION_MAX to accomodate more memregions
lib/utils: Add RPMI messaging protocol and shared memory transport
support
lib/utils: reset: Add RPMI System Reset driver
lib: sbi: Add SBI Message Proxy (MPXY) framework
lib: utils/mpxy: Add RPMI client driver for MPXY
Subrahmanya Lingappa (4):
lib: utils/suspend: Add RPMI system suspend driver
lib: sbi: Add optional resume address to hart suspend
lib: utils/hsm: Add RPMI HSM driver
lib: utils/cppc: Add RPMI CPPC driver
include/sbi/sbi_ecall_interface.h | 13 +
include/sbi/sbi_error.h | 14 +-
include/sbi/sbi_hsm.h | 6 +-
include/sbi/sbi_mpxy.h | 181 +++++
include/sbi/sbi_platform.h | 17 +
include/sbi_utils/cppc/fdt_cppc.h | 35 +
include/sbi_utils/hsm/fdt_hsm.h | 39 ++
include/sbi_utils/mailbox/fdt_mailbox.h | 36 +
include/sbi_utils/mailbox/mailbox.h | 170 +++++
include/sbi_utils/mailbox/rpmi_mailbox.h | 32 +
include/sbi_utils/mailbox/rpmi_msgprot.h | 513 ++++++++++++++
include/sbi_utils/mpxy/fdt_mpxy.h | 31 +
include/sbi_utils/suspend/fdt_suspend.h | 45 ++
lib/sbi/Kconfig | 3 +
lib/sbi/objects.mk | 4 +
lib/sbi/sbi_domain.c | 2 +-
lib/sbi/sbi_ecall_mpxy.c | 68 ++
lib/sbi/sbi_hsm.c | 6 +-
lib/sbi/sbi_init.c | 6 +
lib/sbi/sbi_mpxy.c | 644 ++++++++++++++++++
lib/utils/Kconfig | 10 +
lib/utils/cppc/Kconfig | 19 +
lib/utils/cppc/fdt_cppc.c | 82 +++
lib/utils/cppc/fdt_cppc_drivers.carray | 3 +
lib/utils/cppc/fdt_cppc_rpmi.c | 287 ++++++++
lib/utils/cppc/objects.mk | 14 +
lib/utils/hsm/Kconfig | 19 +
lib/utils/hsm/fdt_hsm.c | 89 +++
lib/utils/hsm/fdt_hsm_drivers.carray | 3 +
lib/utils/hsm/fdt_hsm_rpmi.c | 351 ++++++++++
lib/utils/hsm/objects.mk | 14 +
lib/utils/mailbox/Kconfig | 29 +
lib/utils/mailbox/fdt_mailbox.c | 142 ++++
lib/utils/mailbox/fdt_mailbox_drivers.carray | 3 +
lib/utils/mailbox/fdt_mailbox_rpmi_shmem.c | 671 +++++++++++++++++++
lib/utils/mailbox/mailbox.c | 116 ++++
lib/utils/mailbox/objects.mk | 18 +
lib/utils/mailbox/rpmi_mailbox.c | 79 +++
lib/utils/mpxy/Kconfig | 19 +
lib/utils/mpxy/fdt_mpxy.c | 50 ++
lib/utils/mpxy/fdt_mpxy_drivers.carray | 3 +
lib/utils/mpxy/fdt_mpxy_rpmi_mbox.c | 408 +++++++++++
lib/utils/mpxy/objects.mk | 14 +
lib/utils/reset/Kconfig | 5 +
lib/utils/reset/fdt_reset_rpmi.c | 141 ++++
lib/utils/reset/objects.mk | 3 +
lib/utils/suspend/Kconfig | 19 +
lib/utils/suspend/fdt_suspend.c | 46 ++
lib/utils/suspend/fdt_suspend_drivers.carray | 3 +
lib/utils/suspend/fdt_suspend_rpmi.c | 137 ++++
lib/utils/suspend/objects.mk | 14 +
platform/generic/allwinner/sun20i-d1.c | 2 +-
platform/generic/configs/defconfig | 12 +
platform/generic/platform.c | 13 +
54 files changed, 4691 insertions(+), 12 deletions(-)
create mode 100644 include/sbi/sbi_mpxy.h
create mode 100644 include/sbi_utils/cppc/fdt_cppc.h
create mode 100644 include/sbi_utils/hsm/fdt_hsm.h
create mode 100644 include/sbi_utils/mailbox/fdt_mailbox.h
create mode 100644 include/sbi_utils/mailbox/mailbox.h
create mode 100644 include/sbi_utils/mailbox/rpmi_mailbox.h
create mode 100644 include/sbi_utils/mailbox/rpmi_msgprot.h
create mode 100644 include/sbi_utils/mpxy/fdt_mpxy.h
create mode 100644 include/sbi_utils/suspend/fdt_suspend.h
create mode 100644 lib/sbi/sbi_ecall_mpxy.c
create mode 100644 lib/sbi/sbi_mpxy.c
create mode 100644 lib/utils/cppc/Kconfig
create mode 100644 lib/utils/cppc/fdt_cppc.c
create mode 100644 lib/utils/cppc/fdt_cppc_drivers.carray
create mode 100644 lib/utils/cppc/fdt_cppc_rpmi.c
create mode 100644 lib/utils/cppc/objects.mk
create mode 100644 lib/utils/hsm/Kconfig
create mode 100644 lib/utils/hsm/fdt_hsm.c
create mode 100644 lib/utils/hsm/fdt_hsm_drivers.carray
create mode 100644 lib/utils/hsm/fdt_hsm_rpmi.c
create mode 100644 lib/utils/hsm/objects.mk
create mode 100644 lib/utils/mailbox/Kconfig
create mode 100644 lib/utils/mailbox/fdt_mailbox.c
create mode 100644 lib/utils/mailbox/fdt_mailbox_drivers.carray
create mode 100644 lib/utils/mailbox/fdt_mailbox_rpmi_shmem.c
create mode 100644 lib/utils/mailbox/mailbox.c
create mode 100644 lib/utils/mailbox/objects.mk
create mode 100644 lib/utils/mailbox/rpmi_mailbox.c
create mode 100644 lib/utils/mpxy/Kconfig
create mode 100644 lib/utils/mpxy/fdt_mpxy.c
create mode 100644 lib/utils/mpxy/fdt_mpxy_drivers.carray
create mode 100644 lib/utils/mpxy/fdt_mpxy_rpmi_mbox.c
create mode 100644 lib/utils/mpxy/objects.mk
create mode 100644 lib/utils/reset/fdt_reset_rpmi.c
create mode 100644 lib/utils/suspend/Kconfig
create mode 100644 lib/utils/suspend/fdt_suspend.c
create mode 100644 lib/utils/suspend/fdt_suspend_drivers.carray
create mode 100644 lib/utils/suspend/fdt_suspend_rpmi.c
create mode 100644 lib/utils/suspend/objects.mk
--
2.34.1
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 01/16] lib: Increase ROOT_REGION_MAX to accomodate more memregions
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-08-06 7:33 ` [PATCH 02/16] lib: utils/mailbox: Add generic mailbox library Anup Patel
` (14 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
From: Rahul Pathak <rpathak@ventanamicro.com>
As more drivers adding memregions into root domain, the current static limit
of ROOT_REGION_MAX is not sufficient. Increase the limit to accomodate more
memregions.
Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
lib/sbi/sbi_domain.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
index 374ac36b..65649169 100644
--- a/lib/sbi/sbi_domain.c
+++ b/lib/sbi/sbi_domain.c
@@ -26,7 +26,7 @@ struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX + 1] = { 0 };
static u32 domain_count = 0;
static bool domain_finalized = false;
-#define ROOT_REGION_MAX 16
+#define ROOT_REGION_MAX 32
static u32 root_memregs_count = 0;
struct sbi_domain root = {
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 02/16] lib: utils/mailbox: Add generic mailbox library
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
2024-08-06 7:33 ` [PATCH 01/16] lib: Increase ROOT_REGION_MAX to accomodate more memregions Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-08-06 7:33 ` [PATCH 03/16] lib: utils/mailbox: Add simple FDT based mailbox framework Anup Patel
` (13 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
Add generic mailbox library which is independent of hardware description
format. The OpenSBI platform support or mailbox drivers can register
mailbox controller instances which can be discovered and used by different
mailbox client drivers. Each mailbox controller instance has a unique ID
which can be used by mailbox client drivers for find the mailbox controller
instance. The mailbox client drivers will typically request a mailbox channel
from the mailbox controller and use it to do data transfer with the remote
end of mailbox channel.
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/mailbox/mailbox.h | 170 ++++++++++++++++++++++++++++
lib/utils/Kconfig | 2 +
lib/utils/mailbox/Kconfig | 9 ++
lib/utils/mailbox/mailbox.c | 116 +++++++++++++++++++
lib/utils/mailbox/objects.mk | 10 ++
5 files changed, 307 insertions(+)
create mode 100644 include/sbi_utils/mailbox/mailbox.h
create mode 100644 lib/utils/mailbox/Kconfig
create mode 100644 lib/utils/mailbox/mailbox.c
create mode 100644 lib/utils/mailbox/objects.mk
diff --git a/include/sbi_utils/mailbox/mailbox.h b/include/sbi_utils/mailbox/mailbox.h
new file mode 100644
index 00000000..7206ce81
--- /dev/null
+++ b/include/sbi_utils/mailbox/mailbox.h
@@ -0,0 +1,170 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#ifndef __MAILBOX_H__
+#define __MAILBOX_H__
+
+#include <sbi/sbi_types.h>
+#include <sbi/sbi_list.h>
+#include <sbi/riscv_atomic.h>
+
+/** Representation of a mailbox channel */
+struct mbox_chan {
+ /** List head */
+ struct sbi_dlist node;
+ /** Pointer to the mailbox controller */
+ struct mbox_controller *mbox;
+ /**
+ * Arguments (or parameters) to identify a mailbox channel
+ * within a mailbox controller.
+ */
+#define MBOX_CHAN_MAX_ARGS 2
+ u32 chan_args[MBOX_CHAN_MAX_ARGS];
+};
+
+#define to_mbox_chan(__node) \
+ container_of((__node), struct mbox_chan, node)
+
+/**
+ * Representation of a mailbox data transfer
+ *
+ * NOTE: If both "tx" and "rx" are non-NULL then Tx is done before Rx.
+ */
+struct mbox_xfer {
+#define MBOX_XFER_SEQ (1UL << 0)
+ /** Transfer flags */
+ unsigned long flags;
+ /** Transfer arguments (or parameters) */
+ void *args;
+ /**
+ * Sequence number
+ *
+ * If MBOX_XFER_SEQ is not set in flags then mbox_chan_xfer()
+ * will generate a unique sequence number and update this field
+ * else mbox_chan_xfer() will blindly use the sequence number
+ * specified by this field.
+ */
+ long seq;
+ /** Send data pointer */
+ void *tx;
+ /** Send data length (valid only if tx != NULL) */
+ unsigned long tx_len;
+ /**
+ * Send timeout milliseconds (valid only if tx != NULL)
+ *
+ * If this field is non-zero along with tx != NULL then the
+ * mailbox controller driver will wait specified milliseconds
+ * for send data transfer to complete else the mailbox controller
+ * driver will not wait.
+ */
+ unsigned long tx_timeout;
+ /** Receive data pointer */
+ void *rx;
+ /** Receive data length (valid only if rx != NULL) */
+ unsigned long rx_len;
+ /**
+ * Receive timeout milliseconds (valid only if rx != NULL)
+ *
+ * If this field is non-zero along with rx != NULL then the
+ * mailbox controller driver will wait specified milliseconds
+ * for receive data transfer to complete else the mailbox
+ * controller driver will not wait.
+ */
+ unsigned long rx_timeout;
+};
+
+#define mbox_xfer_init_tx(__p, __a, __t, __t_len, __t_tim) \
+do { \
+ (__p)->flags = 0; \
+ (__p)->args = (__a); \
+ (__p)->tx = (__t); \
+ (__p)->tx_len = (__t_len); \
+ (__p)->tx_timeout = (__t_tim); \
+ (__p)->rx = NULL; \
+ (__p)->rx_len = 0; \
+ (__p)->rx_timeout = 0; \
+} while (0)
+
+#define mbox_xfer_init_rx(__p, __a, __r, __r_len, __r_tim) \
+do { \
+ (__p)->flags = 0; \
+ (__p)->args = (__a); \
+ (__p)->tx = NULL; \
+ (__p)->tx_len = 0; \
+ (__p)->tx_timeout = 0; \
+ (__p)->rx = (__r); \
+ (__p)->rx_len = (__r_len); \
+ (__p)->rx_timeout = (__r_tim); \
+} while (0)
+
+#define mbox_xfer_init_txrx(__p, __a, __t, __t_len, __t_tim, __r, __r_len, __r_tim)\
+do { \
+ (__p)->flags = 0; \
+ (__p)->args = (__a); \
+ (__p)->tx = (__t); \
+ (__p)->tx_len = (__t_len); \
+ (__p)->tx_timeout = (__t_tim); \
+ (__p)->rx = (__r); \
+ (__p)->rx_len = (__r_len); \
+ (__p)->rx_timeout = (__r_tim); \
+} while (0)
+
+#define mbox_xfer_set_sequence(__p, __seq) \
+do { \
+ (__p)->flags |= MBOX_XFER_SEQ; \
+ (__p)->seq = (__seq); \
+} while (0)
+
+/** Representation of a mailbox controller */
+struct mbox_controller {
+ /** List head */
+ struct sbi_dlist node;
+ /** Next sequence atomic counter */
+ atomic_t xfer_next_seq;
+ /* List of mailbox channels */
+ struct sbi_dlist chan_list;
+ /** Unique ID of the mailbox controller assigned by the driver */
+ unsigned int id;
+ /** Maximum length of transfer supported by the mailbox controller */
+ unsigned int max_xfer_len;
+ /** Pointer to mailbox driver owning this mailbox controller */
+ void *driver;
+ /** Request a mailbox channel from the mailbox controller */
+ struct mbox_chan *(*request_chan)(struct mbox_controller *mbox,
+ u32 *chan_args);
+ /** Free a mailbox channel from the mailbox controller */
+ void *(*free_chan)(struct mbox_controller *mbox,
+ struct mbox_chan *chan);
+ /** Transfer data over mailbox channel */
+ int (*xfer)(struct mbox_chan *chan, struct mbox_xfer *xfer);
+};
+
+#define to_mbox_controller(__node) \
+ container_of((__node), struct mbox_controller, node)
+
+/** Find a registered mailbox controller */
+struct mbox_controller *mbox_controller_find(unsigned int id);
+
+/** Register mailbox controller */
+int mbox_controller_add(struct mbox_controller *mbox);
+
+/** Un-register mailbox controller */
+void mbox_controller_remove(struct mbox_controller *mbox);
+
+/** Request a mailbox channel */
+struct mbox_chan *mbox_controller_request_chan(struct mbox_controller *mbox,
+ u32 *chan_args);
+
+/** Free a mailbox channel */
+void mbox_controller_free_chan(struct mbox_chan *chan);
+
+/** Data transfer over mailbox channel */
+int mbox_chan_xfer(struct mbox_chan *chan, struct mbox_xfer *xfer);
+
+#endif
diff --git a/lib/utils/Kconfig b/lib/utils/Kconfig
index de8b4eb9..6aa7843c 100644
--- a/lib/utils/Kconfig
+++ b/lib/utils/Kconfig
@@ -14,6 +14,8 @@ source "$(OPENSBI_SRC_DIR)/lib/utils/irqchip/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/libfdt/Kconfig"
+source "$(OPENSBI_SRC_DIR)/lib/utils/mailbox/Kconfig"
+
source "$(OPENSBI_SRC_DIR)/lib/utils/regmap/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/reset/Kconfig"
diff --git a/lib/utils/mailbox/Kconfig b/lib/utils/mailbox/Kconfig
new file mode 100644
index 00000000..f91a9bb9
--- /dev/null
+++ b/lib/utils/mailbox/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: BSD-2-Clause
+
+menu "Mailbox Support"
+
+config MAILBOX
+ bool "Mailbox support"
+ default n
+
+endmenu
diff --git a/lib/utils/mailbox/mailbox.c b/lib/utils/mailbox/mailbox.c
new file mode 100644
index 00000000..86f2feac
--- /dev/null
+++ b/lib/utils/mailbox/mailbox.c
@@ -0,0 +1,116 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_string.h>
+#include <sbi_utils/mailbox/mailbox.h>
+
+static SBI_LIST_HEAD(mbox_list);
+
+struct mbox_controller *mbox_controller_find(unsigned int id)
+{
+ struct sbi_dlist *pos;
+
+ sbi_list_for_each(pos, &mbox_list) {
+ struct mbox_controller *mbox = to_mbox_controller(pos);
+
+ if (mbox->id == id)
+ return mbox;
+ }
+
+ return NULL;
+}
+
+int mbox_controller_add(struct mbox_controller *mbox)
+{
+ if (!mbox || !mbox->max_xfer_len)
+ return SBI_EINVAL;
+ if (mbox_controller_find(mbox->id))
+ return SBI_EALREADY;
+
+ SBI_INIT_LIST_HEAD(&mbox->node);
+ ATOMIC_INIT(&mbox->xfer_next_seq, 0);
+ SBI_INIT_LIST_HEAD(&mbox->chan_list);
+ sbi_list_add(&mbox->node, &mbox_list);
+
+ return 0;
+}
+
+void mbox_controller_remove(struct mbox_controller *mbox)
+{
+ struct mbox_chan *chan;
+
+ if (!mbox)
+ return;
+
+ while (!sbi_list_empty(&mbox->chan_list)) {
+ chan = sbi_list_first_entry(&mbox->chan_list,
+ struct mbox_chan, node);
+ if (mbox->free_chan)
+ mbox->free_chan(mbox, chan);
+ sbi_list_del(&chan->node);
+ }
+
+ sbi_list_del(&mbox->node);
+}
+
+struct mbox_chan *mbox_controller_request_chan(struct mbox_controller *mbox,
+ u32 *chan_args)
+{
+ struct mbox_chan *ret;
+ struct sbi_dlist *pos;
+
+ if (!chan_args || !mbox || !mbox->request_chan)
+ return NULL;
+
+ sbi_list_for_each(pos, &mbox->chan_list) {
+ ret = to_mbox_chan(pos);
+ if (!sbi_memcmp(ret->chan_args, chan_args,
+ sizeof(ret->chan_args)))
+ return ret;
+ }
+
+ ret = mbox->request_chan(mbox, chan_args);
+ if (!ret)
+ return NULL;
+
+ SBI_INIT_LIST_HEAD(&ret->node);
+ ret->mbox = mbox;
+ sbi_memcpy(ret->chan_args, chan_args, sizeof(ret->chan_args));
+ sbi_list_add(&ret->node, &mbox->chan_list);
+ return ret;
+}
+
+void mbox_controller_free_chan(struct mbox_chan *chan)
+{
+ if (!chan || !chan->mbox)
+ return;
+
+ if (chan->mbox->free_chan)
+ chan->mbox->free_chan(chan->mbox, chan);
+ sbi_list_del(&chan->node);
+}
+
+int mbox_chan_xfer(struct mbox_chan *chan, struct mbox_xfer *xfer)
+{
+ if (!xfer || !chan || !chan->mbox || !chan->mbox->xfer)
+ return SBI_EINVAL;
+
+ if (xfer->tx && (xfer->tx_len > chan->mbox->max_xfer_len))
+ return SBI_EINVAL;
+
+ if (xfer->rx && (xfer->rx_len > chan->mbox->max_xfer_len))
+ return SBI_EINVAL;
+
+ if (!(xfer->flags & MBOX_XFER_SEQ))
+ mbox_xfer_set_sequence(xfer,
+ atomic_add_return(&chan->mbox->xfer_next_seq, 1));
+
+ return chan->mbox->xfer(chan, xfer);
+}
diff --git a/lib/utils/mailbox/objects.mk b/lib/utils/mailbox/objects.mk
new file mode 100644
index 00000000..79b27e4c
--- /dev/null
+++ b/lib/utils/mailbox/objects.mk
@@ -0,0 +1,10 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2024 Ventana Micro Systems Inc.
+#
+# Authors:
+# Anup Patel <apatel@ventanamicro.com>
+#
+
+libsbiutils-objs-$(CONFIG_MAILBOX) += mailbox/mailbox.o
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 03/16] lib: utils/mailbox: Add simple FDT based mailbox framework
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
2024-08-06 7:33 ` [PATCH 01/16] lib: Increase ROOT_REGION_MAX to accomodate more memregions Anup Patel
2024-08-06 7:33 ` [PATCH 02/16] lib: utils/mailbox: Add generic mailbox library Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-08-06 7:33 ` [PATCH 04/16] lib/utils: Add RPMI messaging protocol and shared memory transport support Anup Patel
` (12 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
Add a simple FDT based mailbox framework which is built on top of the generic
mailbox library. The phandle of FDT mailbox DT node is treated as the unique
mailbox controller ID which is required by the generic mailbox library. The
FDT based mailbox drivers will be probed on-demand from fdt_mailbox_request_chan()
called by the mailbox client drivers.
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/mailbox/fdt_mailbox.h | 36 +++++
lib/utils/mailbox/Kconfig | 6 +
lib/utils/mailbox/fdt_mailbox.c | 142 +++++++++++++++++++
lib/utils/mailbox/fdt_mailbox_drivers.carray | 3 +
lib/utils/mailbox/objects.mk | 3 +
5 files changed, 190 insertions(+)
create mode 100644 include/sbi_utils/mailbox/fdt_mailbox.h
create mode 100644 lib/utils/mailbox/fdt_mailbox.c
create mode 100644 lib/utils/mailbox/fdt_mailbox_drivers.carray
diff --git a/include/sbi_utils/mailbox/fdt_mailbox.h b/include/sbi_utils/mailbox/fdt_mailbox.h
new file mode 100644
index 00000000..27f425db
--- /dev/null
+++ b/include/sbi_utils/mailbox/fdt_mailbox.h
@@ -0,0 +1,36 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#ifndef __FDT_MAILBOX_H__
+#define __FDT_MAILBOX_H__
+
+#include <sbi_utils/mailbox/mailbox.h>
+
+struct fdt_phandle_args;
+
+/** FDT based mailbox driver */
+struct fdt_mailbox {
+ const struct fdt_match *match_table;
+ int (*xlate)(struct mbox_controller *mbox,
+ const struct fdt_phandle_args *pargs,
+ u32 *out_chan_args);
+ int (*init)(void *fdt, int nodeoff, u32 phandle,
+ const struct fdt_match *match);
+};
+
+/** Request a mailbox channel using "mboxes" DT property of client DT node */
+int fdt_mailbox_request_chan(void *fdt, int nodeoff, int index,
+ struct mbox_chan **out_chan);
+
+/** Simple xlate function to convert one mailbox FDT cell into channel args */
+int fdt_mailbox_simple_xlate(struct mbox_controller *mbox,
+ const struct fdt_phandle_args *pargs,
+ u32 *out_chan_args);
+
+#endif
diff --git a/lib/utils/mailbox/Kconfig b/lib/utils/mailbox/Kconfig
index f91a9bb9..3957bfba 100644
--- a/lib/utils/mailbox/Kconfig
+++ b/lib/utils/mailbox/Kconfig
@@ -2,6 +2,12 @@
menu "Mailbox Support"
+config FDT_MAILBOX
+ bool "FDT based mailbox drivers"
+ depends on FDT
+ select MAILBOX
+ default n
+
config MAILBOX
bool "Mailbox support"
default n
diff --git a/lib/utils/mailbox/fdt_mailbox.c b/lib/utils/mailbox/fdt_mailbox.c
new file mode 100644
index 00000000..85a71429
--- /dev/null
+++ b/lib/utils/mailbox/fdt_mailbox.c
@@ -0,0 +1,142 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#include <libfdt.h>
+#include <sbi/sbi_error.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/mailbox/fdt_mailbox.h>
+
+/* List of FDT mailbox drivers generated at compile time */
+extern struct fdt_mailbox *fdt_mailbox_drivers[];
+extern unsigned long fdt_mailbox_drivers_size;
+
+static struct fdt_mailbox *fdt_mailbox_driver(struct mbox_controller *mbox)
+{
+ int pos;
+
+ if (!mbox)
+ return NULL;
+
+ for (pos = 0; pos < fdt_mailbox_drivers_size; pos++) {
+ if (mbox->driver == fdt_mailbox_drivers[pos])
+ return fdt_mailbox_drivers[pos];
+ }
+
+ return NULL;
+}
+
+static int fdt_mailbox_init(void *fdt, u32 phandle)
+{
+ int pos, nodeoff, rc;
+ struct fdt_mailbox *drv;
+ const struct fdt_match *match;
+
+ /* Find node offset */
+ nodeoff = fdt_node_offset_by_phandle(fdt, phandle);
+ if (nodeoff < 0)
+ return nodeoff;
+
+ /* Try all mailbox drivers one-by-one */
+ for (pos = 0; pos < fdt_mailbox_drivers_size; pos++) {
+ drv = fdt_mailbox_drivers[pos];
+
+ match = fdt_match_node(fdt, nodeoff, drv->match_table);
+ if (match && drv->init) {
+ rc = drv->init(fdt, nodeoff, phandle, match);
+ if (rc == SBI_ENODEV)
+ continue;
+ if (rc)
+ return rc;
+ return 0;
+ }
+ }
+
+ return SBI_ENOSYS;
+}
+
+static int fdt_mbox_controller_find(void *fdt, u32 phandle,
+ struct mbox_controller **out_mbox)
+{
+ int rc;
+ struct mbox_controller *mbox = mbox_controller_find(phandle);
+
+ if (!mbox) {
+ /* mailbox not found so initialize matching driver */
+ rc = fdt_mailbox_init(fdt, phandle);
+ if (rc)
+ return rc;
+
+ /* Try to find mailbox controller again */
+ mbox = mbox_controller_find(phandle);
+ if (!mbox)
+ return SBI_ENOSYS;
+ }
+
+ if (out_mbox)
+ *out_mbox = mbox;
+
+ return 0;
+}
+
+int fdt_mailbox_request_chan(void *fdt, int nodeoff, int index,
+ struct mbox_chan **out_chan)
+{
+ int rc;
+ struct mbox_chan *chan;
+ struct fdt_mailbox *drv;
+ struct fdt_phandle_args pargs;
+ struct mbox_controller *mbox = NULL;
+ u32 phandle, chan_args[MBOX_CHAN_MAX_ARGS];
+
+ if (!fdt || (nodeoff < 0) || (index < 0) || !out_chan)
+ return SBI_EINVAL;
+
+ pargs.node_offset = pargs.args_count = 0;
+ rc = fdt_parse_phandle_with_args(fdt, nodeoff,
+ "mboxes", "#mbox-cells",
+ index, &pargs);
+ if (rc)
+ return rc;
+
+ phandle = fdt_get_phandle(fdt, pargs.node_offset);
+ rc = fdt_mbox_controller_find(fdt, phandle, &mbox);
+ if (rc)
+ return rc;
+
+ drv = fdt_mailbox_driver(mbox);
+ if (!drv || !drv->xlate)
+ return SBI_ENOSYS;
+
+ rc = drv->xlate(mbox, &pargs, chan_args);
+ if (rc)
+ return rc;
+
+ chan = mbox_controller_request_chan(mbox, chan_args);
+ if (!chan)
+ return SBI_ENOENT;
+
+ *out_chan = chan;
+ return 0;
+}
+
+int fdt_mailbox_simple_xlate(struct mbox_controller *mbox,
+ const struct fdt_phandle_args *pargs,
+ u32 *out_chan_args)
+{
+ int i;
+
+ if (pargs->args_count < 1)
+ return SBI_EINVAL;
+
+ out_chan_args[0] = pargs->args[0];
+ for (i = 1; i < MBOX_CHAN_MAX_ARGS; i++)
+ out_chan_args[i] = 0;
+
+ return 0;
+}
diff --git a/lib/utils/mailbox/fdt_mailbox_drivers.carray b/lib/utils/mailbox/fdt_mailbox_drivers.carray
new file mode 100644
index 00000000..fd4246df
--- /dev/null
+++ b/lib/utils/mailbox/fdt_mailbox_drivers.carray
@@ -0,0 +1,3 @@
+HEADER: sbi_utils/mailbox/fdt_mailbox.h
+TYPE: struct fdt_mailbox
+NAME: fdt_mailbox_drivers
diff --git a/lib/utils/mailbox/objects.mk b/lib/utils/mailbox/objects.mk
index 79b27e4c..2135898c 100644
--- a/lib/utils/mailbox/objects.mk
+++ b/lib/utils/mailbox/objects.mk
@@ -7,4 +7,7 @@
# Anup Patel <apatel@ventanamicro.com>
#
+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
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 04/16] lib/utils: Add RPMI messaging protocol and shared memory transport support
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
` (2 preceding siblings ...)
2024-08-06 7:33 ` [PATCH 03/16] lib: utils/mailbox: Add simple FDT based mailbox framework Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-08-16 1:01 ` Bo Gan
2024-08-26 22:34 ` Bo Gan
2024-08-06 7:33 ` [PATCH 05/16] lib/utils: reset: Add RPMI System Reset driver Anup Patel
` (11 subsequent siblings)
15 siblings, 2 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
From: Rahul Pathak <rpathak@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@ventanamicro.com>
Co-developed-by: Subrahmanya Lingappa <slingappa@ventanamicro.com>
Signed-off-by: Subrahmanya Lingappa <slingappa@ventanamicro.com>
Co-developed-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@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@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@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@ventanamicro.com>
+ * Subrahmanya Lingappa <slingappa@ventanamicro.com>
+ * Anup Patel <apatel@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@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
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 05/16] lib/utils: reset: Add RPMI System Reset driver
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
` (3 preceding siblings ...)
2024-08-06 7:33 ` [PATCH 04/16] lib/utils: Add RPMI messaging protocol and shared memory transport support Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-08-06 7:33 ` [PATCH 06/16] lib: utils: Add simple FDT based system suspend driver framework Anup Patel
` (10 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
From: Rahul Pathak <rpathak@ventanamicro.com>
Add RPMI based driver for system reset and enable it in the generic
platform defconfig
Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/mailbox/rpmi_msgprot.h | 26 +++++
lib/utils/reset/Kconfig | 5 +
lib/utils/reset/fdt_reset_rpmi.c | 141 +++++++++++++++++++++++
lib/utils/reset/objects.mk | 3 +
platform/generic/configs/defconfig | 1 +
5 files changed, 176 insertions(+)
create mode 100644 lib/utils/reset/fdt_reset_rpmi.c
diff --git a/include/sbi_utils/mailbox/rpmi_msgprot.h b/include/sbi_utils/mailbox/rpmi_msgprot.h
index e0c7cba0..4ede28dd 100644
--- a/include/sbi_utils/mailbox/rpmi_msgprot.h
+++ b/include/sbi_utils/mailbox/rpmi_msgprot.h
@@ -148,6 +148,7 @@ struct rpmi_message_args {
enum rpmi_servicegroup_id {
RPMI_SRVGRP_ID_MIN = 0,
RPMI_SRVGRP_BASE = 0x00001,
+ RPMI_SRVGRP_SYSTEM_RESET = 0x00002,
RPMI_SRVGRP_ID_MAX_COUNT,
};
@@ -183,4 +184,29 @@ struct rpmi_base_get_attributes_resp {
u32 f3;
};
+/** RPMI System Reset ServiceGroup Service IDs */
+enum rpmi_system_reset_service_id {
+ RPMI_SYSRST_SRV_ENABLE_NOTIFICATION = 0x01,
+ RPMI_SYSRST_SRV_GET_SYSTEM_RESET_ATTRIBUTES = 0x02,
+ RPMI_SYSRST_SRV_SYSTEM_RESET = 0x03,
+ RPMI_SYSRST_SRV_ID_MAX_COUNT,
+};
+
+/** RPMI System Reset types */
+enum rpmi_sysrst_reset_type {
+ RPMI_SYSRST_SHUTDOWN = 0,
+ RPMI_SYSRST_COLD_RESET = 1,
+ RPMI_SYSRST_WARM_RESET = 2,
+ RPMI_SYSRST_MAX_IDN_COUNT,
+};
+
+/** Response for system reset attributes */
+struct rpmi_sysrst_get_reset_attributes_resp {
+ s32 status;
+#define RPMI_SYSRST_FLAGS_SUPPORTED_POS (31)
+#define RPMI_SYSRST_FLAGS_SUPPORTED_MASK \
+ (1U << RPMI_SYSRST_FLAGS_SUPPORTED_POS)
+ u32 flags;
+};
+
#endif /* !__RPMI_MSGPROT_H__ */
diff --git a/lib/utils/reset/Kconfig b/lib/utils/reset/Kconfig
index 6c077fe7..68e66716 100644
--- a/lib/utils/reset/Kconfig
+++ b/lib/utils/reset/Kconfig
@@ -24,6 +24,11 @@ config FDT_RESET_HTIF
select SYS_HTIF
default n
+config FDT_RESET_RPMI
+ bool "RPMI FDT reset driver"
+ depends on FDT_MAILBOX && RPMI_MAILBOX
+ default n
+
config FDT_RESET_SG2042_HWMON_MCU
bool "Sophgo SG2042 hwmon MCU FDT reset driver"
default n
diff --git a/lib/utils/reset/fdt_reset_rpmi.c b/lib/utils/reset/fdt_reset_rpmi.c
new file mode 100644
index 00000000..3664a3c6
--- /dev/null
+++ b/lib/utils/reset/fdt_reset_rpmi.c
@@ -0,0 +1,141 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Rahul Pathak <rpathak@ventanamicro.com>
+ */
+
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_system.h>
+#include <sbi/sbi_console.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/reset/fdt_reset.h>
+#include <sbi_utils/mailbox/fdt_mailbox.h>
+#include <sbi_utils/mailbox/rpmi_msgprot.h>
+#include <sbi_utils/mailbox/rpmi_mailbox.h>
+
+/* struct rpmi_sysreset: RPMI System Reset Context */
+struct rpmi_sysreset {
+ int warm_reset_support;
+ struct mbox_chan *chan;
+};
+
+static struct rpmi_sysreset sysreset_ctx;
+
+static int rpmi_system_reset_type_check(u32 reset_type)
+{
+ int ret;
+ struct rpmi_sysrst_get_reset_attributes_resp resp;
+
+ ret = rpmi_normal_request_with_status(sysreset_ctx.chan,
+ RPMI_SYSRST_SRV_GET_SYSTEM_RESET_ATTRIBUTES, &reset_type,
+ rpmi_u32_count(reset_type), rpmi_u32_count(reset_type),
+ &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
+ if (ret) {
+ return 0;
+ }
+
+ return (resp.flags & RPMI_SYSRST_FLAGS_SUPPORTED_MASK) ? 1 : 0;
+}
+
+/**
+ * rpmi_do_system_reset: Do system reset
+ *
+ * @reset_type: RPMI System Reset Type
+ */
+static void rpmi_do_system_reset(u32 reset_type)
+{
+ int ret;
+
+ ret = rpmi_posted_request(sysreset_ctx.chan,
+ RPMI_SYSRST_SRV_SYSTEM_RESET,
+ &reset_type, rpmi_u32_count(reset_type),
+ rpmi_u32_count(reset_type));
+ if (ret)
+ sbi_printf("system reset failed [type: %d]: ret: %d\n",
+ reset_type, ret);
+}
+
+/**
+ * rpmi_system_reset_check: Check the support for
+ * various reset types
+ *
+ * @type: SBI System Reset Type
+ * @reason: Reason for system reset
+ */
+static int rpmi_system_reset_check(u32 type, u32 reason)
+{
+ switch (type) {
+ case SBI_SRST_RESET_TYPE_SHUTDOWN:
+ case SBI_SRST_RESET_TYPE_COLD_REBOOT:
+ return 1;
+ case SBI_SRST_RESET_TYPE_WARM_REBOOT:
+ return sysreset_ctx.warm_reset_support;
+ default:
+ return 0;
+ }
+}
+
+static void rpmi_system_reset(u32 type, u32 reason)
+{
+ u32 reset_type;
+
+ switch (type) {
+ case SBI_SRST_RESET_TYPE_SHUTDOWN:
+ reset_type = RPMI_SYSRST_SHUTDOWN;
+ break;
+ case SBI_SRST_RESET_TYPE_COLD_REBOOT:
+ reset_type = RPMI_SYSRST_COLD_RESET;
+ break;
+ case SBI_SRST_RESET_TYPE_WARM_REBOOT:
+ reset_type = RPMI_SYSRST_WARM_RESET;
+ break;
+ default:
+ return;
+ }
+
+ rpmi_do_system_reset(reset_type);
+}
+
+static struct sbi_system_reset_device rpmi_reset_dev = {
+ .name = "rpmi-system-reset",
+ .system_reset_check = rpmi_system_reset_check,
+ .system_reset = rpmi_system_reset,
+};
+
+static int rpmi_reset_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int ret;
+
+ /* If channel already available then do nothing. */
+ if (sysreset_ctx.chan)
+ return 0;
+
+ /*
+ * If channel request failed then other end does not support
+ * system reset group so do nothing.
+ */
+ ret = fdt_mailbox_request_chan(fdt, nodeoff, 0, &sysreset_ctx.chan);
+ if (ret)
+ return ret;
+
+ sysreset_ctx.warm_reset_support =
+ rpmi_system_reset_type_check(RPMI_SYSRST_WARM_RESET);
+
+ sbi_system_reset_add_device(&rpmi_reset_dev);
+
+ return SBI_OK;
+}
+
+static const struct fdt_match rpmi_reset_match[] = {
+ { .compatible = "riscv,rpmi-system-reset" },
+ {},
+};
+
+struct fdt_reset fdt_reset_rpmi = {
+ .match_table = rpmi_reset_match,
+ .init = rpmi_reset_init,
+};
diff --git a/lib/utils/reset/objects.mk b/lib/utils/reset/objects.mk
index a84336cf..8f3774c5 100644
--- a/lib/utils/reset/objects.mk
+++ b/lib/utils/reset/objects.mk
@@ -29,3 +29,6 @@ libsbiutils-objs-$(CONFIG_FDT_RESET_SUNXI_WDT) += reset/fdt_reset_sunxi_wdt.o
carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SYSCON) += fdt_syscon_poweroff
carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SYSCON) += fdt_syscon_reboot
libsbiutils-objs-$(CONFIG_FDT_RESET_SYSCON) += reset/fdt_reset_syscon.o
+
+carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_RPMI) += fdt_reset_rpmi
+libsbiutils-objs-$(CONFIG_FDT_RESET_RPMI) += reset/fdt_reset_rpmi.o
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index 233a9a89..48f8df4c 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -29,6 +29,7 @@ CONFIG_FDT_RESET=y
CONFIG_FDT_RESET_ATCWDT200=y
CONFIG_FDT_RESET_GPIO=y
CONFIG_FDT_RESET_HTIF=y
+CONFIG_FDT_RESET_RPMI=y
CONFIG_FDT_RESET_SUNXI_WDT=y
CONFIG_FDT_RESET_SG2042_HWMON_MCU=y
CONFIG_FDT_RESET_SYSCON=y
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 06/16] lib: utils: Add simple FDT based system suspend driver framework
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
` (4 preceding siblings ...)
2024-08-06 7:33 ` [PATCH 05/16] lib/utils: reset: Add RPMI System Reset driver Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-08-06 7:33 ` [PATCH 07/16] lib: utils/suspend: Add RPMI system suspend driver Anup Patel
` (9 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
The generic platform can have multiple system suspend drivers so add a
simple FDT based system suspend driver framework.
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/suspend/fdt_suspend.h | 45 +++++++++++++++++++
lib/utils/Kconfig | 2 +
lib/utils/suspend/Kconfig | 10 +++++
lib/utils/suspend/fdt_suspend.c | 46 ++++++++++++++++++++
lib/utils/suspend/fdt_suspend_drivers.carray | 3 ++
lib/utils/suspend/objects.mk | 11 +++++
platform/generic/configs/defconfig | 1 +
platform/generic/platform.c | 2 +
8 files changed, 120 insertions(+)
create mode 100644 include/sbi_utils/suspend/fdt_suspend.h
create mode 100644 lib/utils/suspend/Kconfig
create mode 100644 lib/utils/suspend/fdt_suspend.c
create mode 100644 lib/utils/suspend/fdt_suspend_drivers.carray
create mode 100644 lib/utils/suspend/objects.mk
diff --git a/include/sbi_utils/suspend/fdt_suspend.h b/include/sbi_utils/suspend/fdt_suspend.h
new file mode 100644
index 00000000..cb6fb719
--- /dev/null
+++ b/include/sbi_utils/suspend/fdt_suspend.h
@@ -0,0 +1,45 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#ifndef __FDT_SUSPEND_H__
+#define __FDT_SUSPEND_H__
+
+#include <sbi/sbi_types.h>
+
+struct fdt_suspend {
+ const struct fdt_match *match_table;
+ int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
+};
+
+#ifdef CONFIG_FDT_SUSPEND
+
+/**
+ * fdt_suspend_driver_init() - initialize suspend driver based on the device-tree
+ */
+int fdt_suspend_driver_init(void *fdt, struct fdt_suspend *drv);
+
+/**
+ * fdt_suspend_init() - initialize reset drivers based on the device-tree
+ *
+ * This function shall be invoked in final init.
+ */
+void fdt_suspend_init(void);
+
+#else
+
+static inline int fdt_suspend_driver_init(void *fdt, struct fdt_suspend *drv)
+{
+ return 0;
+}
+
+static inline void fdt_suspend_init(void) { }
+
+#endif
+
+#endif
diff --git a/lib/utils/Kconfig b/lib/utils/Kconfig
index 6aa7843c..3f32c1ca 100644
--- a/lib/utils/Kconfig
+++ b/lib/utils/Kconfig
@@ -22,6 +22,8 @@ source "$(OPENSBI_SRC_DIR)/lib/utils/reset/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/serial/Kconfig"
+source "$(OPENSBI_SRC_DIR)/lib/utils/suspend/Kconfig"
+
source "$(OPENSBI_SRC_DIR)/lib/utils/sys/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/timer/Kconfig"
diff --git a/lib/utils/suspend/Kconfig b/lib/utils/suspend/Kconfig
new file mode 100644
index 00000000..416ae795
--- /dev/null
+++ b/lib/utils/suspend/Kconfig
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: BSD-2-Clause
+
+menu "System Suspend Support"
+
+config FDT_SUSPEND
+ bool "FDT based suspend drivers"
+ depends on FDT
+ default n
+
+endmenu
diff --git a/lib/utils/suspend/fdt_suspend.c b/lib/utils/suspend/fdt_suspend.c
new file mode 100644
index 00000000..029d6476
--- /dev/null
+++ b/lib/utils/suspend/fdt_suspend.c
@@ -0,0 +1,46 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_error.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/suspend/fdt_suspend.h>
+
+/* List of FDT suspend drivers generated at compile time */
+extern struct fdt_suspend *fdt_suspend_drivers[];
+extern unsigned long fdt_suspend_drivers_size;
+
+int fdt_suspend_driver_init(void *fdt, struct fdt_suspend *drv)
+{
+ int noff, rc = SBI_ENODEV;
+ const struct fdt_match *match;
+
+ noff = fdt_find_match(fdt, -1, drv->match_table, &match);
+ if (noff < 0)
+ return SBI_ENODEV;
+
+ if (drv->init) {
+ rc = drv->init(fdt, noff, match);
+ if (rc && rc != SBI_ENODEV) {
+ sbi_printf("%s: %s init failed, %d\n",
+ __func__, match->compatible, rc);
+ }
+ }
+
+ return rc;
+}
+
+void fdt_suspend_init(void)
+{
+ int pos;
+ void *fdt = fdt_get_address();
+
+ for (pos = 0; pos < fdt_suspend_drivers_size; pos++)
+ fdt_suspend_driver_init(fdt, fdt_suspend_drivers[pos]);
+}
diff --git a/lib/utils/suspend/fdt_suspend_drivers.carray b/lib/utils/suspend/fdt_suspend_drivers.carray
new file mode 100644
index 00000000..8793e4cf
--- /dev/null
+++ b/lib/utils/suspend/fdt_suspend_drivers.carray
@@ -0,0 +1,3 @@
+HEADER: sbi_utils/suspend/fdt_suspend.h
+TYPE: struct fdt_suspend
+NAME: fdt_suspend_drivers
diff --git a/lib/utils/suspend/objects.mk b/lib/utils/suspend/objects.mk
new file mode 100644
index 00000000..30d897d1
--- /dev/null
+++ b/lib/utils/suspend/objects.mk
@@ -0,0 +1,11 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2024 Ventana Micro Systems Inc.
+#
+# Authors:
+# Anup Patel <apatel@ventanamicro.com>
+#
+
+libsbiutils-objs-$(CONFIG_FDT_SUSPEND) += suspend/fdt_suspend.o
+libsbiutils-objs-$(CONFIG_FDT_SUSPEND) += suspend/fdt_suspend_drivers.carray.o
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index 48f8df4c..ec439d74 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -44,6 +44,7 @@ CONFIG_FDT_SERIAL_LITEX=y
CONFIG_FDT_SERIAL_UART8250=y
CONFIG_FDT_SERIAL_XILINX_UARTLITE=y
CONFIG_SERIAL_SEMIHOSTING=y
+CONFIG_FDT_SUSPEND=y
CONFIG_FDT_TIMER=y
CONFIG_FDT_TIMER_MTIMER=y
CONFIG_FDT_TIMER_PLMT=y
diff --git a/platform/generic/platform.c b/platform/generic/platform.c
index 3470474a..138a54c2 100644
--- a/platform/generic/platform.c
+++ b/platform/generic/platform.c
@@ -24,6 +24,7 @@
#include <sbi_utils/irqchip/fdt_irqchip.h>
#include <sbi_utils/irqchip/imsic.h>
#include <sbi_utils/serial/fdt_serial.h>
+#include <sbi_utils/suspend/fdt_suspend.h>
#include <sbi_utils/timer/fdt_timer.h>
#include <sbi_utils/ipi/fdt_ipi.h>
#include <sbi_utils/reset/fdt_reset.h>
@@ -225,6 +226,7 @@ static int generic_early_init(bool cold_boot)
if (cold_boot) {
fdt_reset_init();
+ fdt_suspend_init();
if (semihosting_enabled())
rc = semihosting_init();
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 07/16] lib: utils/suspend: Add RPMI system suspend driver
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
` (5 preceding siblings ...)
2024-08-06 7:33 ` [PATCH 06/16] lib: utils: Add simple FDT based system suspend driver framework Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-08-06 7:33 ` [PATCH 08/16] lib: utils: Add simple FDT based HSM driver framework Anup Patel
` (8 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
From: Subrahmanya Lingappa <slingappa@ventanamicro.com>
Add RPMI based system suspend driver.
To test this, execute the follwoing in Linux:
$ echo mem > /sys/power/state
To wake up, execute the following command on qemu monitor terminal:
(qemu) system_wakeup
Signed-off-by: Subrahmanya Lingappa <slingappa@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/mailbox/rpmi_msgprot.h | 34 ++++++
lib/utils/suspend/Kconfig | 9 ++
lib/utils/suspend/fdt_suspend_rpmi.c | 137 +++++++++++++++++++++++
lib/utils/suspend/objects.mk | 3 +
platform/generic/configs/defconfig | 1 +
5 files changed, 184 insertions(+)
create mode 100644 lib/utils/suspend/fdt_suspend_rpmi.c
diff --git a/include/sbi_utils/mailbox/rpmi_msgprot.h b/include/sbi_utils/mailbox/rpmi_msgprot.h
index 4ede28dd..a2403c90 100644
--- a/include/sbi_utils/mailbox/rpmi_msgprot.h
+++ b/include/sbi_utils/mailbox/rpmi_msgprot.h
@@ -5,6 +5,7 @@
*
* Authors:
* Rahul Pathak <rpathak@ventanamicro.com>
+ * Subrahmanya Lingappa <slingappa@ventanamicro.com>
*/
#ifndef __RPMI_MSGPROT_H__
@@ -149,6 +150,7 @@ enum rpmi_servicegroup_id {
RPMI_SRVGRP_ID_MIN = 0,
RPMI_SRVGRP_BASE = 0x00001,
RPMI_SRVGRP_SYSTEM_RESET = 0x00002,
+ RPMI_SRVGRP_SYSTEM_SUSPEND = 0x00003,
RPMI_SRVGRP_ID_MAX_COUNT,
};
@@ -209,4 +211,36 @@ struct rpmi_sysrst_get_reset_attributes_resp {
u32 flags;
};
+/** RPMI System Suspend ServiceGroup Service IDs */
+enum rpmi_system_suspend_service_id {
+ RPMI_SYSSUSP_SRV_ENABLE_NOTIFICATION = 0x01,
+ RPMI_SYSSUSP_SRV_GET_SYSTEM_SUSPEND_ATTRIBUTES = 0x02,
+ RPMI_SYSSUSP_SRV_SYSTEM_SUSPEND = 0x03,
+ RPMI_SYSSUSP_SRV_ID_MAX_COUNT,
+};
+
+/** Request for system suspend attributes */
+struct rpmi_syssusp_get_attr_req {
+ u32 susp_type;
+};
+
+/** Response for system suspend attributes */
+struct rpmi_syssusp_get_attr_resp {
+ s32 status;
+#define RPMI_SYSSUSP_FLAGS_CUSTOM_RESUME_ADDR_SUPPORTED (1U << 31)
+#define RPMI_SYSSUSP_FLAGS_SUPPORTED (1U << 30)
+ u32 flags;
+};
+
+struct rpmi_syssusp_suspend_req {
+ u32 hartid;
+ u32 suspend_type;
+ u32 resume_addr_lo;
+ u32 resume_addr_hi;
+};
+
+struct rpmi_syssusp_suspend_resp {
+ s32 status;
+};
+
#endif /* !__RPMI_MSGPROT_H__ */
diff --git a/lib/utils/suspend/Kconfig b/lib/utils/suspend/Kconfig
index 416ae795..2cbea75c 100644
--- a/lib/utils/suspend/Kconfig
+++ b/lib/utils/suspend/Kconfig
@@ -7,4 +7,13 @@ config FDT_SUSPEND
depends on FDT
default n
+if FDT_SUSPEND
+
+config FDT_SUSPEND_RPMI
+ bool "FDT RPMI suspend driver"
+ depends on FDT_MAILBOX && RPMI_MAILBOX
+ default n
+
+endif
+
endmenu
diff --git a/lib/utils/suspend/fdt_suspend_rpmi.c b/lib/utils/suspend/fdt_suspend_rpmi.c
new file mode 100644
index 00000000..aa5db128
--- /dev/null
+++ b/lib/utils/suspend/fdt_suspend_rpmi.c
@@ -0,0 +1,137 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Subrahmanya Lingappa <slingappa@ventanamicro.com>
+ */
+
+#include <libfdt.h>
+#include <sbi/sbi_system.h>
+#include <sbi/riscv_asm.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/mailbox/fdt_mailbox.h>
+#include <sbi_utils/mailbox/mailbox.h>
+#include <sbi_utils/mailbox/rpmi_mailbox.h>
+#include <sbi_utils/suspend/fdt_suspend.h>
+
+struct rpmi_syssusp {
+ struct mbox_chan *chan;
+ bool cust_res_addr_supported;
+ bool suspend_supported;
+};
+
+static struct rpmi_syssusp syssusp_ctx;
+
+static int rpmi_syssusp_attrs(uint32_t *attrs)
+{
+ int rc;
+ struct rpmi_syssusp_get_attr_resp resp;
+ struct rpmi_syssusp_get_attr_req req;
+
+ req.susp_type = SBI_SUSP_SLEEP_TYPE_SUSPEND;
+
+ rc = rpmi_normal_request_with_status(
+ syssusp_ctx.chan, RPMI_SYSSUSP_SRV_GET_SYSTEM_SUSPEND_ATTRIBUTES,
+ &req, rpmi_u32_count(req), rpmi_u32_count(req),
+ &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
+ if (rc)
+ return rc;
+
+ *attrs = resp.flags;
+
+ return 0;
+}
+
+static int rpmi_syssusp(uint32_t suspend_type, ulong resume_addr)
+{
+ int rc;
+ struct rpmi_syssusp_suspend_req req;
+ struct rpmi_syssusp_suspend_resp resp;
+
+ req.hartid = current_hartid();
+ req.suspend_type = suspend_type;
+ req.resume_addr_lo = resume_addr;
+ req.resume_addr_hi = (u64)resume_addr >> 32;
+
+ rc = rpmi_normal_request_with_status(
+ syssusp_ctx.chan, RPMI_SYSSUSP_SRV_SYSTEM_SUSPEND,
+ &req, rpmi_u32_count(req), rpmi_u32_count(req),
+ &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
+ if (rc)
+ return rc;
+
+ /* Wait for interrupt */
+ wfi();
+
+ return 0;
+}
+
+static int rpmi_system_suspend_check(u32 sleep_type)
+{
+ return ((sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND) &&
+ syssusp_ctx.suspend_supported) ? 0 : SBI_EINVAL;
+}
+
+static int rpmi_system_suspend(u32 sleep_type, ulong resume_addr)
+{
+ int rc;
+
+ if (sleep_type != SBI_SUSP_SLEEP_TYPE_SUSPEND)
+ return SBI_ENOTSUPP;
+
+ rc = rpmi_syssusp(sleep_type, resume_addr);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static struct sbi_system_suspend_device rpmi_suspend_dev = {
+ .name = "rpmi-system-suspend",
+ .system_suspend_check = rpmi_system_suspend_check,
+ .system_suspend = rpmi_system_suspend,
+};
+
+static int rpmi_suspend_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ uint32_t attrs = 0;
+
+ /* If channel already available then do nothing. */
+ if (syssusp_ctx.chan)
+ return 0;
+
+ /*
+ * If channel request failed then other end does not support
+ * suspend service group so do nothing.
+ */
+ rc = fdt_mailbox_request_chan(fdt, nodeoff, 0, &syssusp_ctx.chan);
+ if (rc)
+ return 0;
+
+ /* Get suspend attributes */
+ rc = rpmi_syssusp_attrs(&attrs);
+ if (rc)
+ return rc;
+
+ syssusp_ctx.suspend_supported = attrs & RPMI_SYSSUSP_FLAGS_SUPPORTED;
+ syssusp_ctx.cust_res_addr_supported =
+ attrs & RPMI_SYSSUSP_FLAGS_CUSTOM_RESUME_ADDR_SUPPORTED;
+
+ sbi_system_suspend_set_device(&rpmi_suspend_dev);
+
+ return 0;
+}
+
+static const struct fdt_match rpmi_suspend_match[] = {
+ { .compatible = "riscv,rpmi-system-suspend" },
+ {},
+};
+
+struct fdt_suspend fdt_suspend_rpmi = {
+ .match_table = rpmi_suspend_match,
+ .init = rpmi_suspend_init,
+};
diff --git a/lib/utils/suspend/objects.mk b/lib/utils/suspend/objects.mk
index 30d897d1..657670a8 100644
--- a/lib/utils/suspend/objects.mk
+++ b/lib/utils/suspend/objects.mk
@@ -9,3 +9,6 @@
libsbiutils-objs-$(CONFIG_FDT_SUSPEND) += suspend/fdt_suspend.o
libsbiutils-objs-$(CONFIG_FDT_SUSPEND) += suspend/fdt_suspend_drivers.carray.o
+
+carray-fdt_suspend_drivers-$(CONFIG_FDT_SUSPEND_RPMI) += fdt_suspend_rpmi
+libsbiutils-objs-$(CONFIG_FDT_SUSPEND_RPMI) += suspend/fdt_suspend_rpmi.o
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index ec439d74..54300fb5 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -45,6 +45,7 @@ CONFIG_FDT_SERIAL_UART8250=y
CONFIG_FDT_SERIAL_XILINX_UARTLITE=y
CONFIG_SERIAL_SEMIHOSTING=y
CONFIG_FDT_SUSPEND=y
+CONFIG_FDT_SUSPEND_RPMI=y
CONFIG_FDT_TIMER=y
CONFIG_FDT_TIMER_MTIMER=y
CONFIG_FDT_TIMER_PLMT=y
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 08/16] lib: utils: Add simple FDT based HSM driver framework
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
` (6 preceding siblings ...)
2024-08-06 7:33 ` [PATCH 07/16] lib: utils/suspend: Add RPMI system suspend driver Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-08-06 7:33 ` [PATCH 09/16] lib: sbi: Add optional resume address to hart suspend Anup Patel
` (7 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
The generic platform can have multiple HSM drivers so add a simple
FDT based HSM driver framework.
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/hsm/fdt_hsm.h | 39 ++++++++++++
lib/utils/Kconfig | 2 +
lib/utils/hsm/Kconfig | 10 ++++
lib/utils/hsm/fdt_hsm.c | 89 ++++++++++++++++++++++++++++
lib/utils/hsm/fdt_hsm_drivers.carray | 3 +
lib/utils/hsm/objects.mk | 11 ++++
platform/generic/configs/defconfig | 1 +
platform/generic/platform.c | 6 ++
8 files changed, 161 insertions(+)
create mode 100644 include/sbi_utils/hsm/fdt_hsm.h
create mode 100644 lib/utils/hsm/Kconfig
create mode 100644 lib/utils/hsm/fdt_hsm.c
create mode 100644 lib/utils/hsm/fdt_hsm_drivers.carray
create mode 100644 lib/utils/hsm/objects.mk
diff --git a/include/sbi_utils/hsm/fdt_hsm.h b/include/sbi_utils/hsm/fdt_hsm.h
new file mode 100644
index 00000000..7076873c
--- /dev/null
+++ b/include/sbi_utils/hsm/fdt_hsm.h
@@ -0,0 +1,39 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#ifndef __FDT_HSM_H__
+#define __FDT_HSM_H__
+
+#include <sbi/sbi_types.h>
+
+#ifdef CONFIG_FDT_HSM
+
+struct fdt_hsm {
+ const struct fdt_match *match_table;
+ int (*fdt_fixup)(void *fdt);
+ int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
+ int (*warm_init)(void);
+ void (*exit)(void);
+};
+
+int fdt_hsm_fixup(void *fdt);
+
+void fdt_hsm_exit(void);
+
+int fdt_hsm_init(bool cold_boot);
+
+#else
+
+static inline int fdt_hsm_fixup(void *fdt) { return 0; }
+static inline void fdt_hsm_exit(void) { }
+static inline int fdt_hsm_init(bool cold_boot) { return 0; }
+
+#endif
+
+#endif
diff --git a/lib/utils/Kconfig b/lib/utils/Kconfig
index 3f32c1ca..c860a185 100644
--- a/lib/utils/Kconfig
+++ b/lib/utils/Kconfig
@@ -6,6 +6,8 @@ source "$(OPENSBI_SRC_DIR)/lib/utils/fdt/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/gpio/Kconfig"
+source "$(OPENSBI_SRC_DIR)/lib/utils/hsm/Kconfig"
+
source "$(OPENSBI_SRC_DIR)/lib/utils/i2c/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/ipi/Kconfig"
diff --git a/lib/utils/hsm/Kconfig b/lib/utils/hsm/Kconfig
new file mode 100644
index 00000000..31506116
--- /dev/null
+++ b/lib/utils/hsm/Kconfig
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: BSD-2-Clause
+
+menu "HSM Device Support"
+
+config FDT_HSM
+ bool "FDT based HSM drivers"
+ depends on FDT
+ default n
+
+endmenu
diff --git a/lib/utils/hsm/fdt_hsm.c b/lib/utils/hsm/fdt_hsm.c
new file mode 100644
index 00000000..7166dce8
--- /dev/null
+++ b/lib/utils/hsm/fdt_hsm.c
@@ -0,0 +1,89 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#include <sbi/sbi_error.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/hsm/fdt_hsm.h>
+
+/* List of FDT HSM drivers generated at compile time */
+extern struct fdt_hsm *fdt_hsm_drivers[];
+extern unsigned long fdt_hsm_drivers_size;
+
+static struct fdt_hsm *current_driver = NULL;
+
+int fdt_hsm_fixup(void *fdt)
+{
+ if (current_driver && current_driver->fdt_fixup)
+ return current_driver->fdt_fixup(fdt);
+ return 0;
+}
+
+void fdt_hsm_exit(void)
+{
+ if (current_driver && current_driver->exit)
+ current_driver->exit();
+}
+
+static int fdt_hsm_warm_init(void)
+{
+ if (current_driver && current_driver->warm_init)
+ return current_driver->warm_init();
+ return 0;
+}
+
+static int fdt_hsm_cold_init(void)
+{
+ int pos, noff, rc;
+ struct fdt_hsm *drv;
+ const struct fdt_match *match;
+ void *fdt = fdt_get_address();
+
+ for (pos = 0; pos < fdt_hsm_drivers_size; pos++) {
+ drv = fdt_hsm_drivers[pos];
+
+ noff = -1;
+ while ((noff = fdt_find_match(fdt, noff,
+ drv->match_table, &match)) >= 0) {
+ /* drv->cold_init must not be NULL */
+ if (drv->cold_init == NULL)
+ return SBI_EFAIL;
+
+ rc = drv->cold_init(fdt, noff, match);
+ if (rc == SBI_ENODEV)
+ continue;
+ if (rc)
+ return rc;
+ current_driver = drv;
+
+ /*
+ * We can have multiple HSM devices on multi-die or
+ * multi-socket systems so we cannot break here.
+ */
+ }
+ }
+
+ /*
+ * On some single-hart system there is no need for HSM,
+ * so we cannot return a failure here
+ */
+ return 0;
+}
+
+int fdt_hsm_init(bool cold_boot)
+{
+ int rc;
+
+ if (cold_boot) {
+ rc = fdt_hsm_cold_init();
+ if (rc)
+ return rc;
+ }
+
+ return fdt_hsm_warm_init();
+}
diff --git a/lib/utils/hsm/fdt_hsm_drivers.carray b/lib/utils/hsm/fdt_hsm_drivers.carray
new file mode 100644
index 00000000..21396db2
--- /dev/null
+++ b/lib/utils/hsm/fdt_hsm_drivers.carray
@@ -0,0 +1,3 @@
+HEADER: sbi_utils/hsm/fdt_hsm.h
+TYPE: struct fdt_hsm
+NAME: fdt_hsm_drivers
diff --git a/lib/utils/hsm/objects.mk b/lib/utils/hsm/objects.mk
new file mode 100644
index 00000000..49337bf5
--- /dev/null
+++ b/lib/utils/hsm/objects.mk
@@ -0,0 +1,11 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2024 Ventana Micro Systems Inc.
+#
+# Authors:
+# Anup Patel <apatel@ventanamicro.com>
+#
+
+libsbiutils-objs-$(CONFIG_FDT_HSM) += hsm/fdt_hsm.o
+libsbiutils-objs-$(CONFIG_FDT_HSM) += hsm/fdt_hsm_drivers.carray.o
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index 54300fb5..2efc7136 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -10,6 +10,7 @@ CONFIG_FDT_GPIO=y
CONFIG_FDT_GPIO_DESIGNWARE=y
CONFIG_FDT_GPIO_SIFIVE=y
CONFIG_FDT_GPIO_STARFIVE=y
+CONFIG_FDT_HSM=y
CONFIG_FDT_I2C=y
CONFIG_FDT_I2C_SIFIVE=y
CONFIG_FDT_I2C_DW=y
diff --git a/platform/generic/platform.c b/platform/generic/platform.c
index 138a54c2..bcd7133b 100644
--- a/platform/generic/platform.c
+++ b/platform/generic/platform.c
@@ -21,6 +21,7 @@
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/fdt/fdt_pmu.h>
+#include <sbi_utils/hsm/fdt_hsm.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
#include <sbi_utils/irqchip/imsic.h>
#include <sbi_utils/serial/fdt_serial.h>
@@ -236,6 +237,8 @@ static int generic_early_init(bool cold_boot)
return rc;
}
+ fdt_hsm_init(cold_boot);
+
if (!generic_plat || !generic_plat->early_init)
return 0;
@@ -261,6 +264,7 @@ static int generic_final_init(bool cold_boot)
fdt_cpu_fixup(fdt);
fdt_fixups(fdt);
fdt_domain_fixup(fdt);
+ fdt_hsm_fixup(fdt);
if (generic_plat && generic_plat->fdt_fixup) {
rc = generic_plat->fdt_fixup(fdt, generic_plat_match);
@@ -287,6 +291,8 @@ static int generic_vendor_ext_provider(long funcid,
static void generic_early_exit(void)
{
+ fdt_hsm_exit();
+
if (generic_plat && generic_plat->early_exit)
generic_plat->early_exit(generic_plat_match);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 09/16] lib: sbi: Add optional resume address to hart suspend
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
` (7 preceding siblings ...)
2024-08-06 7:33 ` [PATCH 08/16] lib: utils: Add simple FDT based HSM driver framework Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-08-06 7:33 ` [PATCH 10/16] lib: utils/hsm: Add RPMI HSM driver Anup Patel
` (6 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
From: Subrahmanya Lingappa <slingappa@ventanamicro.com>
Add an optional resume address to the platform specific hart suspend call.
Signed-off-by: Subrahmanya Lingappa <slingappa@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi/sbi_hsm.h | 6 +++++-
lib/sbi/sbi_hsm.c | 6 +++---
platform/generic/allwinner/sun20i-d1.c | 2 +-
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/include/sbi/sbi_hsm.h b/include/sbi/sbi_hsm.h
index 4b5601ba..aa692dfe 100644
--- a/include/sbi/sbi_hsm.h
+++ b/include/sbi/sbi_hsm.h
@@ -39,8 +39,12 @@ struct sbi_hsm_device {
*
* For successful non-retentive suspend, the hart will resume from
* the warm boot entry point.
+ *
+ * NOTE: mmode_resume_addr(resume address) is optional hence it
+ * may or may not be honored by the platform. If its not honored
+ * then platform must ensure to resume from the warmboot address.
*/
- int (*hart_suspend)(u32 suspend_type);
+ int (*hart_suspend)(u32 suspend_type, ulong mmode_resume_addr);
/**
* Perform platform-specific actions to resume from a suspended state.
diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c
index 3706acfb..2f518d44 100644
--- a/lib/sbi/sbi_hsm.c
+++ b/lib/sbi/sbi_hsm.c
@@ -228,10 +228,10 @@ static int hsm_device_hart_stop(void)
return SBI_ENOTSUPP;
}
-static int hsm_device_hart_suspend(u32 suspend_type)
+static int hsm_device_hart_suspend(u32 suspend_type, ulong mmode_resume_addr)
{
if (hsm_dev && hsm_dev->hart_suspend)
- return hsm_dev->hart_suspend(suspend_type);
+ return hsm_dev->hart_suspend(suspend_type, mmode_resume_addr);
return SBI_ENOTSUPP;
}
@@ -536,7 +536,7 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
__sbi_hsm_suspend_non_ret_save(scratch);
/* Try platform specific suspend */
- ret = hsm_device_hart_suspend(suspend_type);
+ ret = hsm_device_hart_suspend(suspend_type, scratch->warmboot_addr);
if (ret == SBI_ENOTSUPP) {
/* Try generic implementation of default suspend types */
if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT ||
diff --git a/platform/generic/allwinner/sun20i-d1.c b/platform/generic/allwinner/sun20i-d1.c
index ab2eee55..33312e0b 100644
--- a/platform/generic/allwinner/sun20i-d1.c
+++ b/platform/generic/allwinner/sun20i-d1.c
@@ -152,7 +152,7 @@ static void sun20i_d1_riscv_cfg_init(void)
writel_relaxed(entry >> 32, SUN20I_D1_RISCV_CFG_BASE + RESET_ENTRY_HI_REG);
}
-static int sun20i_d1_hart_suspend(u32 suspend_type)
+static int sun20i_d1_hart_suspend(u32 suspend_type, ulong mmode_resume_addr)
{
/* Use the generic code for retentive suspend. */
if (!(suspend_type & SBI_HSM_SUSP_NON_RET_BIT))
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 10/16] lib: utils/hsm: Add RPMI HSM driver
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
` (8 preceding siblings ...)
2024-08-06 7:33 ` [PATCH 09/16] lib: sbi: Add optional resume address to hart suspend Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-08-06 7:33 ` [PATCH 11/16] lib: utils: Add simple FDT based CPPC driver framework Anup Patel
` (5 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
From: Subrahmanya Lingappa <slingappa@ventanamicro.com>
The RPMI HSM service group provides set of routine to query and control
power states of a Hart. Add RPMI based Hart State Management (HSM) driver.
Signed-off-by: Subrahmanya Lingappa <slingappa@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/mailbox/rpmi_msgprot.h | 91 ++++++
lib/utils/hsm/Kconfig | 9 +
lib/utils/hsm/fdt_hsm_rpmi.c | 351 +++++++++++++++++++++++
lib/utils/hsm/objects.mk | 3 +
platform/generic/configs/defconfig | 1 +
5 files changed, 455 insertions(+)
create mode 100644 lib/utils/hsm/fdt_hsm_rpmi.c
diff --git a/include/sbi_utils/mailbox/rpmi_msgprot.h b/include/sbi_utils/mailbox/rpmi_msgprot.h
index a2403c90..efe35aee 100644
--- a/include/sbi_utils/mailbox/rpmi_msgprot.h
+++ b/include/sbi_utils/mailbox/rpmi_msgprot.h
@@ -151,6 +151,7 @@ enum rpmi_servicegroup_id {
RPMI_SRVGRP_BASE = 0x00001,
RPMI_SRVGRP_SYSTEM_RESET = 0x00002,
RPMI_SRVGRP_SYSTEM_SUSPEND = 0x00003,
+ RPMI_SRVGRP_HSM = 0x00004,
RPMI_SRVGRP_ID_MAX_COUNT,
};
@@ -243,4 +244,94 @@ struct rpmi_syssusp_suspend_resp {
s32 status;
};
+/** RPMI HSM State Management ServiceGroup Service IDs */
+enum rpmi_cpu_hsm_service_id {
+ RPMI_HSM_SRV_ENABLE_NOTIFICATION = 0x01,
+ RPMI_HSM_SRV_HART_START = 0x02,
+ RPMI_HSM_SRV_HART_STOP = 0x03,
+ RPMI_HSM_SRV_HART_SUSPEND = 0x04,
+ RPMI_HSM_SRV_GET_HART_STATUS = 0x05,
+ RPMI_HSM_SRV_GET_HART_LIST = 0x06,
+ RPMI_HSM_SRV_GET_SUSPEND_TYPES = 0x07,
+ RPMI_HSM_SRV_GET_SUSPEND_INFO = 0x08,
+ RPMI_HSM_SRV_ID_MAX_COUNT,
+};
+
+/* HSM service group request and response structs */
+struct rpmi_hsm_hart_start_req {
+ u32 hartid;
+ u32 start_addr_lo;
+ u32 start_addr_hi;
+};
+
+struct rpmi_hsm_hart_start_resp {
+ s32 status;
+};
+
+struct rpmi_hsm_hart_stop_req {
+ u32 hartid;
+};
+
+struct rpmi_hsm_hart_stop_resp {
+ s32 status;
+};
+
+struct rpmi_hsm_hart_susp_req {
+ u32 hartid;
+ u32 suspend_type;
+ u32 resume_addr_lo;
+ u32 resume_addr_hi;
+};
+
+struct rpmi_hsm_hart_susp_resp {
+ s32 status;
+};
+
+struct rpmi_hsm_get_hart_status_req {
+ u32 hartid;
+};
+
+struct rpmi_hsm_get_hart_status_resp {
+ s32 status;
+ u32 hart_status;
+};
+
+struct rpmi_hsm_get_hart_list_req {
+ u32 start_index;
+};
+
+struct rpmi_hsm_get_hart_list_resp {
+ s32 status;
+ u32 remaining;
+ u32 returned;
+ /* remaining space need to be adjusted for the above 3 u32's */
+ u32 hartid[(RPMI_MSG_DATA_SIZE(RPMI_SLOT_SIZE_MIN) - (sizeof(u32) * 3)) / sizeof(u32)];
+};
+
+struct rpmi_hsm_get_susp_types_req {
+ u32 start_index;
+};
+
+struct rpmi_hsm_get_susp_types_resp {
+ s32 status;
+ u32 remaining;
+ u32 returned;
+ /* remaining space need to be adjusted for the above 3 u32's */
+ u32 types[(RPMI_MSG_DATA_SIZE(RPMI_SLOT_SIZE_MIN) - (sizeof(u32) * 3)) / sizeof(u32)];
+};
+
+struct rpmi_hsm_get_susp_info_req {
+ u32 suspend_type;
+};
+
+struct rpmi_hsm_get_susp_info_resp {
+ s32 status;
+ u32 flags;
+#define RPMI_HSM_FLAGS_LOCAL_TIME_STOP (1U << 31)
+ u32 entry_latency_us;
+ u32 exit_latency_us;
+ u32 wakeup_latency_us;
+ u32 min_residency_us;
+};
+
#endif /* !__RPMI_MSGPROT_H__ */
diff --git a/lib/utils/hsm/Kconfig b/lib/utils/hsm/Kconfig
index 31506116..1ad7958f 100644
--- a/lib/utils/hsm/Kconfig
+++ b/lib/utils/hsm/Kconfig
@@ -7,4 +7,13 @@ config FDT_HSM
depends on FDT
default n
+if FDT_HSM
+
+config FDT_HSM_RPMI
+ bool "FDT RPMI HSM driver"
+ depends on FDT_MAILBOX && RPMI_MAILBOX
+ default n
+
+endif
+
endmenu
diff --git a/lib/utils/hsm/fdt_hsm_rpmi.c b/lib/utils/hsm/fdt_hsm_rpmi.c
new file mode 100644
index 00000000..e598901d
--- /dev/null
+++ b/lib/utils/hsm/fdt_hsm_rpmi.c
@@ -0,0 +1,351 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Subrahmanya Lingappa <slingappa@ventanamicro.com>
+ */
+
+#include <libfdt.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_heap.h>
+#include <sbi/sbi_hsm.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/fdt/fdt_fixup.h>
+#include <sbi_utils/hsm/fdt_hsm.h>
+#include <sbi_utils/mailbox/fdt_mailbox.h>
+#include <sbi_utils/mailbox/mailbox.h>
+#include <sbi_utils/mailbox/rpmi_mailbox.h>
+
+#define MAX_HSM_SUPSEND_STATE_NAMELEN 16
+
+struct rpmi_hsm_suspend {
+ u32 num_states;
+ struct sbi_cpu_idle_state *states;
+};
+
+struct rpmi_hsm {
+ struct mbox_chan *chan;
+ struct rpmi_hsm_suspend *susp;
+};
+
+static unsigned long rpmi_hsm_offset;
+
+static struct rpmi_hsm *rpmi_hsm_get_pointer(u32 hartid)
+{
+ struct sbi_scratch *scratch;
+
+ scratch = sbi_hartid_to_scratch(hartid);
+ if (!scratch || !rpmi_hsm_offset)
+ return NULL;
+
+ return sbi_scratch_offset_ptr(scratch, rpmi_hsm_offset);
+}
+
+static int rpmi_hsm_start(u32 hartid, ulong resume_addr)
+{
+ struct rpmi_hsm_hart_start_req req;
+ struct rpmi_hsm_hart_start_resp resp;
+ struct rpmi_hsm *rpmi = rpmi_hsm_get_pointer(hartid);
+
+ if (!rpmi)
+ return SBI_ENOSYS;
+
+ req.hartid = hartid;
+ req.start_addr_lo = resume_addr;
+ req.start_addr_hi = (u64)resume_addr >> 32;
+
+ return rpmi_normal_request_with_status(
+ rpmi->chan, RPMI_HSM_SRV_HART_START,
+ &req, rpmi_u32_count(req), rpmi_u32_count(req),
+ &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
+}
+
+static int rpmi_hsm_stop(void)
+{
+ int rc;
+ struct rpmi_hsm_hart_stop_req req;
+ struct rpmi_hsm_hart_stop_resp resp;
+ void (*jump_warmboot)(void) =
+ (void (*)(void))sbi_scratch_thishart_ptr()->warmboot_addr;
+ struct rpmi_hsm *rpmi = rpmi_hsm_get_pointer(current_hartid());
+
+ if (!rpmi)
+ return SBI_ENOSYS;
+
+ req.hartid = current_hartid();
+
+ rc = rpmi_normal_request_with_status(
+ rpmi->chan, RPMI_HSM_SRV_HART_STOP,
+ &req, rpmi_u32_count(req), rpmi_u32_count(req),
+ &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
+ if (rc)
+ return rc;
+
+ /* Wait for interrupt */
+ wfi();
+
+ jump_warmboot();
+
+ return 0;
+}
+
+static bool is_rpmi_hsm_susp_supported(struct rpmi_hsm_suspend *susp, u32 type)
+{
+ int i;
+
+ for (i = 0; i < susp->num_states; i++)
+ if (type == susp->states[i].suspend_param)
+ return true;
+
+ return false;
+}
+
+static int rpmi_hsm_suspend(u32 type, ulong resume_addr)
+{
+ int rc;
+ struct rpmi_hsm_hart_susp_req req;
+ struct rpmi_hsm_hart_susp_resp resp;
+ struct rpmi_hsm *rpmi = rpmi_hsm_get_pointer(current_hartid());
+
+ if (!rpmi)
+ return SBI_ENOSYS;
+
+ /* check if harts support this suspend type */
+ if (!is_rpmi_hsm_susp_supported(rpmi->susp, type))
+ return SBI_EINVAL;
+
+ req.hartid = current_hartid();
+ req.suspend_type = type;
+ req.resume_addr_lo = resume_addr;
+ req.resume_addr_hi = (u64)resume_addr >> 32;
+
+ rc = rpmi_normal_request_with_status(
+ rpmi->chan, RPMI_HSM_SRV_HART_SUSPEND,
+ &req, rpmi_u32_count(req), rpmi_u32_count(req),
+ &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
+ if (rc)
+ return rc;
+
+ /* Wait for interrupt */
+ wfi();
+
+ return 0;
+}
+
+static struct sbi_hsm_device sbi_hsm_rpmi = {
+ .name = "rpmi-hsm",
+ .hart_start = rpmi_hsm_start,
+ .hart_stop = rpmi_hsm_stop,
+ .hart_suspend = rpmi_hsm_suspend,
+};
+
+static int rpmi_hsm_fixup(void *fdt)
+{
+ struct rpmi_hsm *rpmi = rpmi_hsm_get_pointer(current_hartid());
+
+ if (!rpmi || !rpmi->susp || !rpmi->susp->num_states)
+ return 0;
+
+ return fdt_add_cpu_idle_states(fdt, rpmi->susp->states);
+}
+
+static int rpmi_hsm_get_num_suspend_states(struct mbox_chan *chan,
+ struct rpmi_hsm_suspend *susp)
+{
+ int rc;
+ struct rpmi_hsm_get_susp_types_req req;
+ struct rpmi_hsm_get_susp_types_resp resp;
+
+ req.start_index = 0;
+ rc = rpmi_normal_request_with_status(
+ chan, RPMI_HSM_SRV_GET_SUSPEND_TYPES,
+ &req, rpmi_u32_count(req), rpmi_u32_count(req),
+ &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
+ if (rc)
+ return rc;
+
+ susp->num_states = resp.returned + resp.remaining;
+ return 0;
+}
+
+static int rpmi_hsm_get_suspend_states(struct mbox_chan *chan,
+ struct rpmi_hsm_suspend *susp)
+{
+ int rc, i, cnt = 0;
+ struct rpmi_hsm_get_susp_types_req req;
+ struct rpmi_hsm_get_susp_types_resp resp;
+ struct rpmi_hsm_get_susp_info_req dreq;
+ struct rpmi_hsm_get_susp_info_resp dresp;
+ struct sbi_cpu_idle_state *state;
+
+ if (!susp->num_states)
+ return 0;
+
+ req.start_index = 0;
+ do {
+ rc = rpmi_normal_request_with_status(
+ chan, RPMI_HSM_SRV_GET_SUSPEND_TYPES,
+ &req, rpmi_u32_count(req), rpmi_u32_count(req),
+ &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
+ if (rc)
+ return rc;
+
+ for (i = 0; i < resp.returned && cnt < susp->num_states; i++)
+ susp->states[cnt++].suspend_param = resp.types[i];
+ req.start_index = i;
+ } while (resp.remaining);
+
+ for (i = 0; i < susp->num_states; i++) {
+ state = &susp->states[i];
+
+ dreq.suspend_type = state->suspend_param;
+ rc = rpmi_normal_request_with_status(
+ chan, RPMI_HSM_SRV_GET_SUSPEND_INFO,
+ &dreq, rpmi_u32_count(dreq), rpmi_u32_count(dreq),
+ &dresp, rpmi_u32_count(dresp), rpmi_u32_count(dresp));
+ if (rc)
+ return rc;
+
+ state->entry_latency_us = dresp.entry_latency_us;
+ state->exit_latency_us = dresp.exit_latency_us;
+ state->wakeup_latency_us = dresp.wakeup_latency_us;
+ state->min_residency_us = dresp.min_residency_us;
+ }
+
+ return 0;
+}
+
+static int rpmi_hsm_update_hart_scratch(struct mbox_chan *chan,
+ struct rpmi_hsm_suspend *susp)
+{
+ int rc, i;
+ struct rpmi_hsm_get_hart_list_req req;
+ struct rpmi_hsm_get_hart_list_resp resp;
+ struct rpmi_hsm *rpmi = rpmi_hsm_get_pointer(current_hartid());
+
+ req.start_index = 0;
+ do {
+ rc = rpmi_normal_request_with_status(
+ chan, RPMI_HSM_SRV_GET_HART_LIST,
+ &req, rpmi_u32_count(req), rpmi_u32_count(req),
+ &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
+ if (rc)
+ return rc;
+
+ for (i = 0; i < resp.returned; i++) {
+ rpmi = rpmi_hsm_get_pointer(resp.hartid[i]);
+ if (!rpmi)
+ return SBI_ENOSYS;
+
+ rpmi->chan = chan;
+ rpmi->susp = susp;
+ }
+
+ req.start_index += resp.returned;
+ } while (resp.remaining);
+
+ return 0;
+}
+
+static int rpmi_hsm_cold_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc, i;
+ struct mbox_chan *chan;
+ struct rpmi_hsm_suspend *susp;
+
+ if (!rpmi_hsm_offset) {
+ rpmi_hsm_offset =
+ sbi_scratch_alloc_type_offset(struct rpmi_hsm);
+ if (!rpmi_hsm_offset)
+ return SBI_ENOMEM;
+ }
+
+ /*
+ * If channel request failed then other end does not support
+ * HSM service group so do nothing.
+ */
+ rc = fdt_mailbox_request_chan(fdt, nodeoff, 0, &chan);
+ if (rc)
+ return 0;
+
+ /* Allocate context for HART suspend states */
+ susp = sbi_zalloc(sizeof(*susp));
+ if (!susp)
+ return SBI_ENOMEM;
+
+ /* Get number of HART suspend states */
+ rc = rpmi_hsm_get_num_suspend_states(chan, susp);
+ if (rc)
+ goto fail_free_susp;
+
+ /* Skip HART suspend state discovery for zero HART suspend states */
+ if (!susp->num_states)
+ goto skip_suspend_states;
+
+ /* Allocate array of HART suspend states */
+ susp->states = sbi_calloc(susp->num_states + 1, sizeof(*susp->states));
+ if (!susp->states) {
+ rc = SBI_ENOMEM;
+ goto fail_free_susp;
+ }
+
+ /* Allocate name of each HART suspend state */
+ for (i = 0; i < susp->num_states; i++) {
+ susp->states[i].name =
+ sbi_zalloc(MAX_HSM_SUPSEND_STATE_NAMELEN);
+ if (!susp->states[i].name) {
+ do {
+ i--;
+ sbi_free((void *)susp->states[i].name);
+ } while (i > 0);
+
+ rc = SBI_ENOMEM;
+ goto fail_free_susp_states;
+ }
+ sbi_snprintf((char *)susp->states[i].name,
+ MAX_HSM_SUPSEND_STATE_NAMELEN, "cpu-susp%d", i);
+ }
+
+ /* Get details about each HART suspend state */
+ rc = rpmi_hsm_get_suspend_states(chan, susp);
+ if (rc)
+ goto fail_free_susp_state_names;
+
+skip_suspend_states:
+ /* Update per-HART scratch space */
+ rc = rpmi_hsm_update_hart_scratch(chan, susp);
+ if (rc)
+ goto fail_free_susp_state_names;
+
+ /* Register HSM device */
+ if (!susp->num_states)
+ sbi_hsm_rpmi.hart_suspend = NULL;
+ sbi_hsm_set_device(&sbi_hsm_rpmi);
+
+ return 0;
+
+fail_free_susp_state_names:
+ for (i = 0; i < susp->num_states; i++)
+ sbi_free((void *)susp->states[i].name);
+fail_free_susp_states:
+ if (susp->num_states)
+ sbi_free(susp->states);
+fail_free_susp:
+ sbi_free(susp);
+ return rc;
+}
+
+static const struct fdt_match rpmi_hsm_match[] = {
+ { .compatible = "riscv,rpmi-hsm" },
+ {},
+};
+
+struct fdt_hsm fdt_hsm_rpmi = {
+ .match_table = rpmi_hsm_match,
+ .fdt_fixup = rpmi_hsm_fixup,
+ .cold_init = rpmi_hsm_cold_init,
+};
diff --git a/lib/utils/hsm/objects.mk b/lib/utils/hsm/objects.mk
index 49337bf5..b54b6f6c 100644
--- a/lib/utils/hsm/objects.mk
+++ b/lib/utils/hsm/objects.mk
@@ -9,3 +9,6 @@
libsbiutils-objs-$(CONFIG_FDT_HSM) += hsm/fdt_hsm.o
libsbiutils-objs-$(CONFIG_FDT_HSM) += hsm/fdt_hsm_drivers.carray.o
+
+carray-fdt_hsm_drivers-$(CONFIG_FDT_HSM_RPMI) += fdt_hsm_rpmi
+libsbiutils-objs-$(CONFIG_FDT_HSM_RPMI) += hsm/fdt_hsm_rpmi.o
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index 2efc7136..78fc96b6 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -11,6 +11,7 @@ CONFIG_FDT_GPIO_DESIGNWARE=y
CONFIG_FDT_GPIO_SIFIVE=y
CONFIG_FDT_GPIO_STARFIVE=y
CONFIG_FDT_HSM=y
+CONFIG_FDT_HSM_RPMI=y
CONFIG_FDT_I2C=y
CONFIG_FDT_I2C_SIFIVE=y
CONFIG_FDT_I2C_DW=y
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 11/16] lib: utils: Add simple FDT based CPPC driver framework
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
` (9 preceding siblings ...)
2024-08-06 7:33 ` [PATCH 10/16] lib: utils/hsm: Add RPMI HSM driver Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-08-06 7:33 ` [PATCH 12/16] lib: utils/cppc: Add RPMI CPPC driver Anup Patel
` (4 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
The generic platform can have multiple CPPC drivers so add a simple
FDT based CPPC driver framework.
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/cppc/fdt_cppc.h | 35 +++++++++++
lib/utils/Kconfig | 2 +
lib/utils/cppc/Kconfig | 10 ++++
lib/utils/cppc/fdt_cppc.c | 82 ++++++++++++++++++++++++++
lib/utils/cppc/fdt_cppc_drivers.carray | 3 +
lib/utils/cppc/objects.mk | 11 ++++
platform/generic/configs/defconfig | 1 +
platform/generic/platform.c | 3 +
8 files changed, 147 insertions(+)
create mode 100644 include/sbi_utils/cppc/fdt_cppc.h
create mode 100644 lib/utils/cppc/Kconfig
create mode 100644 lib/utils/cppc/fdt_cppc.c
create mode 100644 lib/utils/cppc/fdt_cppc_drivers.carray
create mode 100644 lib/utils/cppc/objects.mk
diff --git a/include/sbi_utils/cppc/fdt_cppc.h b/include/sbi_utils/cppc/fdt_cppc.h
new file mode 100644
index 00000000..af0cdc41
--- /dev/null
+++ b/include/sbi_utils/cppc/fdt_cppc.h
@@ -0,0 +1,35 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#ifndef __FDT_CPPC_H__
+#define __FDT_CPPC_H__
+
+#include <sbi/sbi_types.h>
+
+#ifdef CONFIG_FDT_CPPC
+
+struct fdt_cppc {
+ const struct fdt_match *match_table;
+ int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
+ int (*warm_init)(void);
+ void (*exit)(void);
+};
+
+void fdt_cppc_exit(void);
+
+int fdt_cppc_init(bool cold_boot);
+
+#else
+
+static inline void fdt_cppc_exit(void) { }
+static inline int fdt_cppc_init(bool cold_boot) { return 0; }
+
+#endif
+
+#endif
diff --git a/lib/utils/Kconfig b/lib/utils/Kconfig
index c860a185..002d6f8f 100644
--- a/lib/utils/Kconfig
+++ b/lib/utils/Kconfig
@@ -2,6 +2,8 @@
menu "Utils and Drivers Support"
+source "$(OPENSBI_SRC_DIR)/lib/utils/cppc/Kconfig"
+
source "$(OPENSBI_SRC_DIR)/lib/utils/fdt/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/gpio/Kconfig"
diff --git a/lib/utils/cppc/Kconfig b/lib/utils/cppc/Kconfig
new file mode 100644
index 00000000..08d1c97f
--- /dev/null
+++ b/lib/utils/cppc/Kconfig
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: BSD-2-Clause
+
+menu "CPPC Device Support"
+
+config FDT_CPPC
+ bool "FDT based CPPC drivers"
+ depends on FDT
+ default n
+
+endmenu
diff --git a/lib/utils/cppc/fdt_cppc.c b/lib/utils/cppc/fdt_cppc.c
new file mode 100644
index 00000000..de11f0e1
--- /dev/null
+++ b/lib/utils/cppc/fdt_cppc.c
@@ -0,0 +1,82 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#include <sbi/sbi_error.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/cppc/fdt_cppc.h>
+
+/* List of FDT CPPC drivers generated at compile time */
+extern struct fdt_cppc *fdt_cppc_drivers[];
+extern unsigned long fdt_cppc_drivers_size;
+
+static struct fdt_cppc *current_driver = NULL;
+
+void fdt_cppc_exit(void)
+{
+ if (current_driver && current_driver->exit)
+ current_driver->exit();
+}
+
+static int fdt_cppc_warm_init(void)
+{
+ if (current_driver && current_driver->warm_init)
+ return current_driver->warm_init();
+ return 0;
+}
+
+static int fdt_cppc_cold_init(void)
+{
+ int pos, noff, rc;
+ struct fdt_cppc *drv;
+ const struct fdt_match *match;
+ void *fdt = fdt_get_address();
+
+ for (pos = 0; pos < fdt_cppc_drivers_size; pos++) {
+ drv = fdt_cppc_drivers[pos];
+
+ noff = -1;
+ while ((noff = fdt_find_match(fdt, noff,
+ drv->match_table, &match)) >= 0) {
+ /* drv->cold_init must not be NULL */
+ if (drv->cold_init == NULL)
+ return SBI_EFAIL;
+
+ rc = drv->cold_init(fdt, noff, match);
+ if (rc == SBI_ENODEV)
+ continue;
+ if (rc)
+ return rc;
+ current_driver = drv;
+
+ /*
+ * We can have multiple CPPC devices on multi-die or
+ * multi-socket systems so we cannot break here.
+ */
+ }
+ }
+
+ /*
+ * On some single-hart system there is no need for CPPC,
+ * so we cannot return a failure here
+ */
+ return 0;
+}
+
+int fdt_cppc_init(bool cold_boot)
+{
+ int rc;
+
+ if (cold_boot) {
+ rc = fdt_cppc_cold_init();
+ if (rc)
+ return rc;
+ }
+
+ return fdt_cppc_warm_init();
+}
diff --git a/lib/utils/cppc/fdt_cppc_drivers.carray b/lib/utils/cppc/fdt_cppc_drivers.carray
new file mode 100644
index 00000000..c2a9af2c
--- /dev/null
+++ b/lib/utils/cppc/fdt_cppc_drivers.carray
@@ -0,0 +1,3 @@
+HEADER: sbi_utils/cppc/fdt_cppc.h
+TYPE: struct fdt_cppc
+NAME: fdt_cppc_drivers
diff --git a/lib/utils/cppc/objects.mk b/lib/utils/cppc/objects.mk
new file mode 100644
index 00000000..fb37478a
--- /dev/null
+++ b/lib/utils/cppc/objects.mk
@@ -0,0 +1,11 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2024 Ventana Micro Systems Inc.
+#
+# Authors:
+# Anup Patel <apatel@ventanamicro.com>
+#
+
+libsbiutils-objs-$(CONFIG_FDT_CPPC) += cppc/fdt_cppc.o
+libsbiutils-objs-$(CONFIG_FDT_CPPC) += cppc/fdt_cppc_drivers.carray.o
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index 78fc96b6..bd18c3c1 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -6,6 +6,7 @@ CONFIG_PLATFORM_SIFIVE_FU740=y
CONFIG_PLATFORM_SOPHGO_SG2042=y
CONFIG_PLATFORM_STARFIVE_JH7110=y
CONFIG_PLATFORM_THEAD=y
+CONFIG_FDT_CPPC=y
CONFIG_FDT_GPIO=y
CONFIG_FDT_GPIO_DESIGNWARE=y
CONFIG_FDT_GPIO_SIFIVE=y
diff --git a/platform/generic/platform.c b/platform/generic/platform.c
index bcd7133b..d085647d 100644
--- a/platform/generic/platform.c
+++ b/platform/generic/platform.c
@@ -17,6 +17,7 @@
#include <sbi/sbi_string.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_tlb.h>
+#include <sbi_utils/cppc/fdt_cppc.h>
#include <sbi_utils/fdt/fdt_domain.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/fdt/fdt_helper.h>
@@ -238,6 +239,7 @@ static int generic_early_init(bool cold_boot)
}
fdt_hsm_init(cold_boot);
+ fdt_cppc_init(cold_boot);
if (!generic_plat || !generic_plat->early_init)
return 0;
@@ -291,6 +293,7 @@ static int generic_vendor_ext_provider(long funcid,
static void generic_early_exit(void)
{
+ fdt_cppc_exit();
fdt_hsm_exit();
if (generic_plat && generic_plat->early_exit)
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 12/16] lib: utils/cppc: Add RPMI CPPC driver
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
` (10 preceding siblings ...)
2024-08-06 7:33 ` [PATCH 11/16] lib: utils: Add simple FDT based CPPC driver framework Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-08-06 7:33 ` [PATCH 13/16] lib: sbi: Add SBI Message Proxy (MPXY) framework Anup Patel
` (3 subsequent siblings)
15 siblings, 0 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
From: Subrahmanya Lingappa <slingappa@ventanamicro.com>
Add RPMI based driver for CPPC register read, write and probe.
Signed-off-by: Subrahmanya Lingappa <slingappa@ventanamicro.com>
Co-developed-by: Sunil V L <sunilvl@ventanamicro.com>
Signed-off-by: Sunil V L <sunilvl@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/mailbox/rpmi_msgprot.h | 83 +++++++
lib/utils/cppc/Kconfig | 9 +
lib/utils/cppc/fdt_cppc_rpmi.c | 287 +++++++++++++++++++++++
lib/utils/cppc/objects.mk | 3 +
platform/generic/configs/defconfig | 1 +
5 files changed, 383 insertions(+)
create mode 100644 lib/utils/cppc/fdt_cppc_rpmi.c
diff --git a/include/sbi_utils/mailbox/rpmi_msgprot.h b/include/sbi_utils/mailbox/rpmi_msgprot.h
index efe35aee..f7913ab1 100644
--- a/include/sbi_utils/mailbox/rpmi_msgprot.h
+++ b/include/sbi_utils/mailbox/rpmi_msgprot.h
@@ -152,6 +152,7 @@ enum rpmi_servicegroup_id {
RPMI_SRVGRP_SYSTEM_RESET = 0x00002,
RPMI_SRVGRP_SYSTEM_SUSPEND = 0x00003,
RPMI_SRVGRP_HSM = 0x00004,
+ RPMI_SRVGRP_CPPC = 0x00005,
RPMI_SRVGRP_ID_MAX_COUNT,
};
@@ -334,4 +335,86 @@ struct rpmi_hsm_get_susp_info_resp {
u32 min_residency_us;
};
+/** RPMI CPPC ServiceGroup Service IDs */
+enum rpmi_cppc_service_id {
+ RPMI_CPPC_SRV_ENABLE_NOTIFICATION = 0x01,
+ RPMI_CPPC_SRV_PROBE_REG = 0x02,
+ RPMI_CPPC_SRV_READ_REG = 0x03,
+ RPMI_CPPC_SRV_WRITE_REG = 0x04,
+ RPMI_CPPC_SRV_GET_FAST_CHANNEL_ADDR = 0x05,
+ RPMI_CPPC_SRV_POKE_FAST_CHANNEL = 0x06,
+ RPMI_CPPC_SRV_GET_HART_LIST = 0x07,
+ RPMI_CPPC_SRV_MAX_COUNT,
+};
+
+struct rpmi_cppc_probe_req {
+ u32 hart_id;
+ u32 reg_id;
+};
+
+struct rpmi_cppc_probe_resp {
+ s32 status;
+ u32 reg_len;
+};
+
+struct rpmi_cppc_read_reg_req {
+ u32 hart_id;
+ u32 reg_id;
+};
+
+struct rpmi_cppc_read_reg_resp {
+ s32 status;
+ u32 data_lo;
+ u32 data_hi;
+};
+
+struct rpmi_cppc_write_reg_req {
+ u32 hart_id;
+ u32 reg_id;
+ u32 data_lo;
+ u32 data_hi;
+};
+
+struct rpmi_cppc_write_reg_resp {
+ s32 status;
+};
+
+struct rpmi_cppc_get_fast_channel_addr_req {
+ u32 hart_id;
+};
+
+struct rpmi_cppc_get_fast_channel_addr_resp {
+ s32 status;
+#define RPMI_CPPC_FAST_CHANNEL_FLAGS_DB_WIDTH_POS 1
+#define RPMI_CPPC_FAST_CHANNEL_FLAGS_DB_WIDTH_MASK \
+ (3U << RPMI_CPPC_FAST_CHANNEL_FLAGS_DB_WIDTH_POS)
+#define RPMI_CPPC_FAST_CHANNEL_FLAGS_DB_SUPPORTED (1U << 0)
+ u32 flags;
+ u32 addr_lo;
+ u32 addr_hi;
+ u32 db_addr_lo;
+ u32 db_addr_hi;
+ u32 db_id_lo;
+ u32 db_id_hi;
+};
+
+enum rpmi_cppc_fast_channel_db_width {
+ RPMI_CPPC_FAST_CHANNEL_DB_WIDTH_8 = 0x0,
+ RPMI_CPPC_FAST_CHANNEL_DB_WIDTH_16 = 0x1,
+ RPMI_CPPC_FAST_CHANNEL_DB_WIDTH_32 = 0x2,
+ RPMI_CPPC_FAST_CHANNEL_DB_WIDTH_64 = 0x3,
+};
+
+struct rpmi_cppc_hart_list_req {
+ u32 start_index;
+};
+
+struct rpmi_cppc_hart_list_resp {
+ s32 status;
+ u32 remaining;
+ u32 returned;
+ /* remaining space need to be adjusted for the above 3 u32's */
+ u32 hartid[(RPMI_MSG_DATA_SIZE(RPMI_SLOT_SIZE_MIN) - (sizeof(u32) * 3)) / sizeof(u32)];
+};
+
#endif /* !__RPMI_MSGPROT_H__ */
diff --git a/lib/utils/cppc/Kconfig b/lib/utils/cppc/Kconfig
index 08d1c97f..494f6894 100644
--- a/lib/utils/cppc/Kconfig
+++ b/lib/utils/cppc/Kconfig
@@ -7,4 +7,13 @@ config FDT_CPPC
depends on FDT
default n
+if FDT_CPPC
+
+config FDT_CPPC_RPMI
+ bool "FDT RPMI CPPC driver"
+ depends on FDT_MAILBOX && RPMI_MAILBOX
+ default n
+
+endif
+
endmenu
diff --git a/lib/utils/cppc/fdt_cppc_rpmi.c b/lib/utils/cppc/fdt_cppc_rpmi.c
new file mode 100644
index 00000000..e9669ce4
--- /dev/null
+++ b/lib/utils/cppc/fdt_cppc_rpmi.c
@@ -0,0 +1,287 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Subrahmanya Lingappa <slingappa@ventanamicro.com>
+ */
+
+#include <libfdt.h>
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_cppc.h>
+#include <sbi/sbi_ecall_interface.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi_utils/cppc/fdt_cppc.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/mailbox/fdt_mailbox.h>
+#include <sbi_utils/mailbox/rpmi_mailbox.h>
+
+struct rpmi_cppc {
+ struct mbox_chan *chan;
+ bool fast_chan_supported;
+ ulong fast_chan_addr;
+ bool fast_chan_db_supported;
+ enum rpmi_cppc_fast_channel_db_width fast_chan_db_width;
+ ulong fast_chan_db_addr;
+ u64 fast_chan_db_id;
+};
+
+static unsigned long rpmi_cppc_offset;
+
+static struct rpmi_cppc *rpmi_cppc_get_pointer(u32 hartid)
+{
+ struct sbi_scratch *scratch;
+
+ scratch = sbi_hartid_to_scratch(hartid);
+ if (!scratch || !rpmi_cppc_offset)
+ return NULL;
+
+ return sbi_scratch_offset_ptr(scratch, rpmi_cppc_offset);
+}
+
+static int rpmi_cppc_read(unsigned long reg, u64 *val)
+{
+ int rc = SBI_SUCCESS;
+ struct rpmi_cppc_read_reg_req req;
+ struct rpmi_cppc_read_reg_resp resp;
+ struct rpmi_cppc *cppc;
+
+ req.hart_id = current_hartid();
+ req.reg_id = reg;
+ cppc = rpmi_cppc_get_pointer(req.hart_id);
+
+ rc = rpmi_normal_request_with_status(
+ cppc->chan, RPMI_CPPC_SRV_READ_REG,
+ &req, rpmi_u32_count(req), rpmi_u32_count(req),
+ &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
+ if (rc)
+ return rc;
+
+#if __riscv_xlen == 32
+ *val = resp.data_lo;
+#else
+ *val = (u64)resp.data_hi << 32 | resp.data_lo;
+#endif
+ return rc;
+}
+
+static int rpmi_cppc_write(unsigned long reg, u64 val)
+{
+ int rc = SBI_SUCCESS;
+ u32 hart_id = current_hartid();
+ struct rpmi_cppc_write_reg_req req;
+ struct rpmi_cppc_write_reg_resp resp;
+ struct rpmi_cppc *cppc = rpmi_cppc_get_pointer(hart_id);
+
+ if (reg != SBI_CPPC_DESIRED_PERF || !cppc->fast_chan_supported) {
+ req.hart_id = hart_id;
+ req.reg_id = reg;
+ req.data_lo = val & 0xFFFFFFFF;
+ req.data_hi = val >> 32;
+
+ rc = rpmi_normal_request_with_status(
+ cppc->chan, RPMI_CPPC_SRV_WRITE_REG,
+ &req, rpmi_u32_count(req), rpmi_u32_count(req),
+ &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
+ } else {
+ /* use fast path writes */
+#if __riscv_xlen != 32
+ writeq(val, (void *)cppc->fast_chan_addr);
+#else
+ writel((u32)val, (void *)cppc->fast_chan_addr);
+ writel((u32)(val >> 32), (void *)(cppc->fast_chan_addr + 4));
+#endif
+ if (cppc->fast_chan_db_supported) {
+ switch (cppc->fast_chan_db_width) {
+ case RPMI_CPPC_FAST_CHANNEL_DB_WIDTH_8:
+ writeb((u8)cppc->fast_chan_db_id,
+ (void *)cppc->fast_chan_db_addr);
+ break;
+ case RPMI_CPPC_FAST_CHANNEL_DB_WIDTH_16:
+ writew((u16)cppc->fast_chan_db_id,
+ (void *)cppc->fast_chan_db_addr);
+ break;
+ case RPMI_CPPC_FAST_CHANNEL_DB_WIDTH_32:
+ writel((u32)cppc->fast_chan_db_id,
+ (void *)cppc->fast_chan_db_addr);
+ break;
+ case RPMI_CPPC_FAST_CHANNEL_DB_WIDTH_64:
+#if __riscv_xlen != 32
+ writeq(cppc->fast_chan_db_id,
+ (void *)cppc->fast_chan_db_addr);
+#else
+ writel((u32)cppc->fast_chan_db_id,
+ (void *)cppc->fast_chan_db_addr);
+ writel((u32)(cppc->fast_chan_db_id >> 32),
+ (void *)(cppc->fast_chan_db_addr + 4));
+#endif
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return rc;
+}
+
+static int rpmi_cppc_probe(unsigned long reg)
+{
+ int rc;
+ struct rpmi_cppc *cppc;
+ struct rpmi_cppc_probe_resp resp;
+ struct rpmi_cppc_probe_req req;
+
+ req.hart_id = current_hartid();
+ req.reg_id = reg;
+
+ cppc = rpmi_cppc_get_pointer(req.hart_id);
+ if (!cppc)
+ return SBI_ENOSYS;
+
+ rc = rpmi_normal_request_with_status(
+ cppc->chan, RPMI_CPPC_SRV_PROBE_REG,
+ &req, rpmi_u32_count(req), rpmi_u32_count(req),
+ &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
+ if (rc)
+ return rc;
+
+ return resp.reg_len;
+}
+
+static struct sbi_cppc_device sbi_rpmi_cppc = {
+ .name = "rpmi-cppc",
+ .cppc_read = rpmi_cppc_read,
+ .cppc_write = rpmi_cppc_write,
+ .cppc_probe = rpmi_cppc_probe,
+};
+
+#define TOTAL_FAST_CHAN_SIZE 0x1000
+#define FAST_CHANNEL_REGION_ALIGN 0x1000
+
+static int rpmi_cppc_update_hart_scratch(struct mbox_chan *chan)
+{
+ int rc, i;
+ struct rpmi_cppc_hart_list_req req;
+ struct rpmi_cppc_hart_list_resp resp;
+ struct rpmi_cppc_get_fast_channel_addr_req freq;
+ struct rpmi_cppc_get_fast_channel_addr_resp fresp;
+ struct rpmi_cppc *cppc;
+ unsigned long fast_chan_base_addr;
+
+ /* Workaround for Smepmp issue */
+ freq.hart_id = 0;
+ rc = rpmi_normal_request_with_status(
+ chan, RPMI_CPPC_SRV_GET_FAST_CHANNEL_ADDR,
+ &freq, rpmi_u32_count(freq), rpmi_u32_count(freq),
+ &fresp, rpmi_u32_count(fresp), rpmi_u32_count(fresp));
+ if (rc)
+ return rc;
+
+#if __riscv_xlen == 32
+ fast_chan_base_addr = fresp.addr_lo;
+#else
+ fast_chan_base_addr = (ulong)fresp.addr_hi << 32 |
+ fresp.addr_lo;
+#endif
+ rc = sbi_domain_root_add_memrange(fast_chan_base_addr,
+ TOTAL_FAST_CHAN_SIZE,
+ FAST_CHANNEL_REGION_ALIGN,
+ (SBI_DOMAIN_MEMREGION_MMIO |
+ SBI_DOMAIN_MEMREGION_M_READABLE |
+ SBI_DOMAIN_MEMREGION_M_WRITABLE));
+ if (rc)
+ return rc;
+
+ req.start_index = 0;
+ do {
+ rc = rpmi_normal_request_with_status(
+ chan, RPMI_CPPC_SRV_GET_HART_LIST,
+ &req, rpmi_u32_count(req), rpmi_u32_count(req),
+ &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
+ if (rc)
+ return rc;
+
+ for (i = 0; i < resp.returned; i++) {
+ cppc = rpmi_cppc_get_pointer(resp.hartid[i]);
+ if (!cppc)
+ return SBI_ENOSYS;
+ cppc->chan = chan;
+
+ freq.hart_id = resp.hartid[i];
+ rc = rpmi_normal_request_with_status(
+ chan, RPMI_CPPC_SRV_GET_FAST_CHANNEL_ADDR,
+ &freq, rpmi_u32_count(freq), rpmi_u32_count(freq),
+ &fresp, rpmi_u32_count(fresp), rpmi_u32_count(fresp));
+ if (rc)
+ continue;
+
+ cppc->fast_chan_supported = true;
+#if __riscv_xlen == 32
+ cppc->fast_chan_addr = fresp.addr_lo;
+#else
+ cppc->fast_chan_addr = (ulong)fresp.addr_hi << 32 |
+ fresp.addr_lo;
+#endif
+ cppc->fast_chan_db_supported = fresp.flags &
+ RPMI_CPPC_FAST_CHANNEL_FLAGS_DB_SUPPORTED;
+ cppc->fast_chan_db_width = (fresp.flags &
+ RPMI_CPPC_FAST_CHANNEL_FLAGS_DB_WIDTH_MASK) >>
+ RPMI_CPPC_FAST_CHANNEL_FLAGS_DB_WIDTH_POS;
+#if __riscv_xlen == 32
+ cppc->fast_chan_db_addr = fresp.db_addr_lo;
+#else
+ cppc->fast_chan_db_addr = (ulong)fresp.db_addr_hi << 32 |
+ fresp.db_addr_lo;
+#endif
+ cppc->fast_chan_db_id = (u64)fresp.db_id_hi << 32 |
+ fresp.db_id_lo;
+ }
+
+ req.start_index += resp.returned;
+ } while (resp.remaining);
+
+ return 0;
+}
+
+static int rpmi_cppc_cold_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ struct mbox_chan *chan;
+
+ if (!rpmi_cppc_offset) {
+ rpmi_cppc_offset =
+ sbi_scratch_alloc_type_offset(struct rpmi_cppc);
+ if (!rpmi_cppc_offset)
+ return SBI_ENOMEM;
+ }
+
+ /*
+ * If channel request failed then other end does not support
+ * CPPC service group so do nothing.
+ */
+ rc = fdt_mailbox_request_chan(fdt, nodeoff, 0, &chan);
+ if (rc)
+ return 0;
+
+ /* Update per-HART scratch space */
+ rc = rpmi_cppc_update_hart_scratch(chan);
+ if (rc)
+ return rc;
+
+ sbi_cppc_set_device(&sbi_rpmi_cppc);
+
+ return 0;
+}
+
+static const struct fdt_match rpmi_cppc_match[] = {
+ { .compatible = "riscv,rpmi-cppc" },
+ {},
+};
+
+struct fdt_cppc fdt_cppc_rpmi = {
+ .match_table = rpmi_cppc_match,
+ .cold_init = rpmi_cppc_cold_init,
+};
diff --git a/lib/utils/cppc/objects.mk b/lib/utils/cppc/objects.mk
index fb37478a..07dc7d89 100644
--- a/lib/utils/cppc/objects.mk
+++ b/lib/utils/cppc/objects.mk
@@ -9,3 +9,6 @@
libsbiutils-objs-$(CONFIG_FDT_CPPC) += cppc/fdt_cppc.o
libsbiutils-objs-$(CONFIG_FDT_CPPC) += cppc/fdt_cppc_drivers.carray.o
+
+carray-fdt_cppc_drivers-$(CONFIG_FDT_CPPC_RPMI) += fdt_cppc_rpmi
+libsbiutils-objs-$(CONFIG_FDT_CPPC_RPMI) += cppc/fdt_cppc_rpmi.o
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index bd18c3c1..384918f9 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -7,6 +7,7 @@ CONFIG_PLATFORM_SOPHGO_SG2042=y
CONFIG_PLATFORM_STARFIVE_JH7110=y
CONFIG_PLATFORM_THEAD=y
CONFIG_FDT_CPPC=y
+CONFIG_FDT_CPPC_RPMI=y
CONFIG_FDT_GPIO=y
CONFIG_FDT_GPIO_DESIGNWARE=y
CONFIG_FDT_GPIO_SIFIVE=y
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 13/16] lib: sbi: Add SBI Message Proxy (MPXY) framework
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
` (11 preceding siblings ...)
2024-08-06 7:33 ` [PATCH 12/16] lib: utils/cppc: Add RPMI CPPC driver Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-10-11 11:26 ` Yu-Chien Peter Lin
2024-08-06 7:33 ` [PATCH 14/16] lib: sbi: Implement SBI MPXY extension Anup Patel
` (2 subsequent siblings)
15 siblings, 1 reply; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
From: Rahul Pathak <rpathak@ventanamicro.com>
Introduce SBI Message Proxy (MPXY) framework which allows platform specific
code or drivers to register message protocol specific channels.
This framework enables the supervisor software to send messages belonging
to different message protocols via OpenSBI firmware.
Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Co-developed-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Co-developed-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi/sbi_ecall_interface.h | 3 +
include/sbi/sbi_error.h | 14 +-
include/sbi/sbi_mpxy.h | 181 +++++++++
include/sbi/sbi_platform.h | 17 +
lib/sbi/objects.mk | 1 +
lib/sbi/sbi_init.c | 6 +
lib/sbi/sbi_mpxy.c | 644 ++++++++++++++++++++++++++++++
7 files changed, 860 insertions(+), 6 deletions(-)
create mode 100644 include/sbi/sbi_mpxy.h
create mode 100644 lib/sbi/sbi_mpxy.c
diff --git a/include/sbi/sbi_ecall_interface.h b/include/sbi/sbi_ecall_interface.h
index e9a81677..6b993b18 100644
--- a/include/sbi/sbi_ecall_interface.h
+++ b/include/sbi/sbi_ecall_interface.h
@@ -428,6 +428,9 @@ enum sbi_sse_state {
#define SBI_ERR_NO_SHMEM -9
#define SBI_ERR_INVALID_STATE -10
#define SBI_ERR_BAD_RANGE -11
+#define SBI_ERR_NOT_IMPLEMENTED -12
+#define SBI_ERR_TIMEOUT -13
+#define SBI_ERR_IO -14
#define SBI_LAST_ERR SBI_ERR_BAD_RANGE
diff --git a/include/sbi/sbi_error.h b/include/sbi/sbi_error.h
index fb78bf62..173923fb 100644
--- a/include/sbi/sbi_error.h
+++ b/include/sbi/sbi_error.h
@@ -26,16 +26,18 @@
#define SBI_ENO_SHMEM SBI_ERR_NO_SHMEM
#define SBI_EINVALID_STATE SBI_ERR_INVALID_STATE
#define SBI_EBAD_RANGE SBI_ERR_BAD_RANGE
+#define SBI_ENOTIMPL SBI_ERR_NOT_IMPLEMENTED
+#define SBI_ETIMEOUT SBI_ERR_TIMEOUT
+#define SBI_EIO SBI_ERR_IO
#define SBI_ENODEV -1000
#define SBI_ENOSYS -1001
#define SBI_ETIMEDOUT -1002
-#define SBI_EIO -1003
-#define SBI_EILL -1004
-#define SBI_ENOSPC -1005
-#define SBI_ENOMEM -1006
-#define SBI_EUNKNOWN -1007
-#define SBI_ENOENT -1008
+#define SBI_EILL -1003
+#define SBI_ENOSPC -1004
+#define SBI_ENOMEM -1005
+#define SBI_EUNKNOWN -1006
+#define SBI_ENOENT -1007
/* clang-format on */
diff --git a/include/sbi/sbi_mpxy.h b/include/sbi/sbi_mpxy.h
new file mode 100644
index 00000000..5e7935e3
--- /dev/null
+++ b/include/sbi/sbi_mpxy.h
@@ -0,0 +1,181 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Rahul Pathak <rpathak@ventanamicro.com>
+ */
+
+#ifndef __SBI_MPXY_H__
+#define __SBI_MPXY_H__
+
+#include <sbi/sbi_list.h>
+
+struct sbi_scratch;
+
+#define SBI_MPXY_MSGPROTO_VERSION(Major, Minor) ((Major << 16) | Minor)
+
+/** Channel Capability - Events State */
+#define CAP_EVENTSSTATE_POS 2
+#define CAP_EVENTSSTATE_MASK (1U << CAP_EVENTSSTATE_POS)
+
+/** Helpers to enable/disable channel capability bits
+ * _c: capability variable
+ * _m: capability mask
+ */
+#define CAP_ENABLE(_c, _m) INSERT_FIELD(_c, _m, 1)
+#define CAP_DISABLE(_c, _m) INSERT_FIELD(_c, _m, 0)
+#define CAP_GET(_c, _m) EXTRACT_FIELD(_c, _m)
+
+enum sbi_mpxy_attr_id {
+ /* Standard channel attributes managed by MPXY framework */
+ SBI_MPXY_ATTR_MSG_PROT_ID = 0x00000000,
+ SBI_MPXY_ATTR_MSG_PROT_VER = 0x00000001,
+ SBI_MPXY_ATTR_MSG_MAX_LEN = 0x00000002,
+ SBI_MPXY_ATTR_MSG_SEND_TIMEOUT = 0x00000003,
+ SBI_MPXY_ATTR_CHANNEL_CAPABILITY = 0x00000004,
+ SBI_MPXY_ATTR_MSI_CONTROL = 0x00000005,
+ SBI_MPXY_ATTR_MSI_ADDR_LO = 0x00000006,
+ SBI_MPXY_ATTR_MSI_ADDR_HI = 0x00000007,
+ SBI_MPXY_ATTR_MSI_DATA = 0x00000008,
+ SBI_MPXY_ATTR_SSE_EVENT_ID = 0x00000009,
+ SBI_MPXY_ATTR_EVENTS_STATE_CONTROL = 0x0000000A,
+ SBI_MPXY_ATTR_STD_ATTR_MAX_IDX,
+ /* Message protocol specific attributes, managed by
+ * message protocol driver */
+ SBI_MPXY_ATTR_MSGPROTO_ATTR_START = 0x80000000,
+ SBI_MPXY_ATTR_MSGPROTO_ATTR_END = 0xffffffff
+};
+
+/**
+ * SBI MPXY Message Protocol IDs
+ */
+enum sbi_mpxy_msgproto_id {
+ SBI_MPXY_MSGPROTO_RPMI_ID = 0x0,
+};
+
+enum SBI_EXT_MPXY_SHMEM_FLAGS {
+ SBI_EXT_MPXY_SHMEM_FLAG_OVERWRITE = 0b00,
+ SBI_EXT_MPXY_SHMEM_FLAG_OVERWRITE_RETURN = 0b01,
+ SBI_EXT_MPXY_SHMEM_FLAG_MAX_IDX
+};
+
+struct sbi_mpxy_msi_info {
+ /* MSI target address low 32-bit */
+ u32 msi_addr_lo;
+ /* MSI target address high 32-bit */
+ u32 msi_addr_hi;
+ /* MSI data */
+ u32 msi_data;
+};
+
+/**
+ * Channel attributes.
+ * NOTE: The sequence of attribute fields are as per the
+ * defined sequence in the attribute table in spec(or as
+ * per the enum sbi_mpxy_attr_id).
+ */
+struct sbi_mpxy_channel_attrs {
+ /* Message protocol ID */
+ u32 msg_proto_id;
+ /* Message protocol Version */
+ u32 msg_proto_version;
+ /* Message protocol maximum message data length(bytes) */
+ u32 msg_data_maxlen;
+ /* Message protocol message send timeout
+ * in microseconds */
+ u32 msg_send_timeout;
+ /* Bit array for channel capabilities */
+ u32 capability;
+ u32 msi_control;
+ struct sbi_mpxy_msi_info msi_info;
+ u32 sse_event_id;
+ /* Events State Control */
+ u32 eventsstate_ctrl;
+};
+
+/** A Message proxy channel accessible through SBI interface */
+struct sbi_mpxy_channel {
+ /** List head to a set of channels */
+ struct sbi_dlist head;
+ u32 channel_id;
+ struct sbi_mpxy_channel_attrs attrs;
+
+ /**
+ * Read message protocol attributes
+ * NOTE: inmem requires little-endian byte-ordering
+ */
+ int (*read_attributes)(struct sbi_mpxy_channel *channel,
+ u32 *outmem,
+ u32 base_attr_id,
+ u32 attr_count);
+
+ /**
+ * Write message protocol attributes
+ * NOTE: outmem requires little-endian byte-ordering
+ */
+ int (*write_attributes)(struct sbi_mpxy_channel *channel,
+ u32 *inmem,
+ u32 base_attr_id,
+ u32 attr_count);
+ /**
+ * Send a message over a channel
+ * NOTE: For message without response, resp_len == NULL
+ * msgbuf requires little-endian byte-ordering
+ */
+ int (*send_message)(struct sbi_mpxy_channel *channel,
+ u32 msg_id, void *msgbuf, u32 msg_len,
+ void *respbuf, u32 resp_max_len,
+ unsigned long *resp_len);
+
+ /**
+ * Get notifications events if supported on a channel
+ * NOTE: eventsbuf requires little-endian byte-ordering
+ */
+ int (*get_notification_events)(struct sbi_mpxy_channel *channel,
+ void *eventsbuf, u32 bufsize,
+ unsigned long *events_len);
+
+ void (*switch_eventsstate)(u32 enable);
+};
+
+/** Register a Message proxy channel */
+int sbi_mpxy_register_channel(struct sbi_mpxy_channel *channel);
+
+/** Initialize Message proxy subsystem */
+int sbi_mpxy_init(struct sbi_scratch *scratch);
+
+/** Check if some Message proxy channel is available */
+bool sbi_mpxy_channel_available(void);
+
+/** Set Message proxy shared memory on the calling HART */
+int sbi_mpxy_set_shmem(unsigned long shmem_size,
+ unsigned long shmem_phys_lo,
+ unsigned long shmem_phys_hi,
+ unsigned long flags);
+
+/** Get channel IDs list */
+int sbi_mpxy_get_channel_ids(u32 start_index);
+
+/** Read MPXY channel attributes */
+int sbi_mpxy_read_attrs(u32 channel_id, u32 base_attr_id, u32 attr_count);
+
+/** Write MPXY channel attributes */
+int sbi_mpxy_write_attrs(u32 channel_id, u32 base_attr_id, u32 attr_count);
+
+/**
+ * Send a message over a MPXY channel.
+ * For message with response the resp_data_len must point
+ * to valid buffer.
+ * For message without response the resp_data_len must be NULL
+ **/
+int sbi_mpxy_send_message(u32 channel_id, u8 msg_id,
+ unsigned long msg_data_len,
+ unsigned long *resp_data_len);
+
+/** Get Message proxy notification events */
+int sbi_mpxy_get_notification_events(u32 channel_id,
+ unsigned long *events_len);
+
+#endif
diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
index 7b3ac4bf..91996888 100644
--- a/include/sbi/sbi_platform.h
+++ b/include/sbi/sbi_platform.h
@@ -132,6 +132,9 @@ struct sbi_platform_operations {
/** Exit platform timer for current HART */
void (*timer_exit)(void);
+ /** Initialize the platform Message Proxy(MPXY) driver */
+ int (*mpxy_init)(void);
+
/** Check if SBI vendor extension is implemented or not */
bool (*vendor_ext_check)(void);
/** platform specific SBI extension implementation provider */
@@ -627,6 +630,20 @@ static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
sbi_platform_ops(plat)->timer_exit();
}
+/**
+ * Initialize the platform Message Proxy drivers
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return 0 on success and negative error code on failure
+ */
+static inline int sbi_platform_mpxy_init(const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->mpxy_init)
+ return sbi_platform_ops(plat)->mpxy_init();
+ return 0;
+}
+
/**
* Check if SBI vendor extension is implemented or not.
*
diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk
index 535aa709..2cea93b9 100644
--- a/lib/sbi/objects.mk
+++ b/lib/sbi/objects.mk
@@ -81,6 +81,7 @@ libsbi-objs-y += sbi_irqchip.o
libsbi-objs-y += sbi_platform.o
libsbi-objs-y += sbi_pmu.o
libsbi-objs-y += sbi_dbtr.o
+libsbi-objs-y += sbi_mpxy.o
libsbi-objs-y += sbi_scratch.o
libsbi-objs-y += sbi_sse.o
libsbi-objs-y += sbi_string.o
diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
index d80efe97..bac55e79 100644
--- a/lib/sbi/sbi_init.c
+++ b/lib/sbi/sbi_init.c
@@ -24,6 +24,7 @@
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_dbtr.h>
+#include <sbi/sbi_mpxy.h>
#include <sbi/sbi_sse.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_string.h>
@@ -311,6 +312,11 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
}
+ rc = sbi_mpxy_init(scratch);
+ if (rc) {
+ sbi_printf("%s: mpxy init failed (error %d)\n", __func__, rc);
+ sbi_hart_hang();
+ }
/*
* Note: Finalize domains after HSM initialization so that we
* can startup non-root domains.
diff --git a/lib/sbi/sbi_mpxy.c b/lib/sbi/sbi_mpxy.c
new file mode 100644
index 00000000..53adf510
--- /dev/null
+++ b/lib/sbi/sbi_mpxy.c
@@ -0,0 +1,644 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Rahul Pathak <rpathak@ventanamicro.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/sbi_domain.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_mpxy.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi/sbi_string.h>
+#include <sbi/sbi_bitops.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_byteorder.h>
+
+/** Offset of pointer to MPXY state in scratch space */
+static unsigned long mpxy_state_offset;
+
+/** List of MPXY proxy channels */
+static SBI_LIST_HEAD(mpxy_channel_list);
+
+/** Invalid Physical Address(all bits 1) */
+#define INVALID_ADDR (-1U)
+
+/** MPXY Attribute size in bytes */
+#define ATTR_SIZE (4)
+
+/** Channel Capability - MSI */
+#define CAP_MSI_POS 0
+#define CAP_MSI_MASK (1U << CAP_MSI_POS)
+/** Channel Capability - SSE */
+#define CAP_SSE_POS 1
+#define CAP_SSE_MASK (1U << CAP_SSE_POS)
+
+#if __riscv_xlen == 64
+#define SHMEM_PHYS_ADDR(_hi, _lo) (_lo)
+#elif __riscv_xlen == 32
+#define SHMEM_PHYS_ADDR(_hi, _lo) (((u64)(_hi) << 32) | (_lo))
+#else
+#error "Undefined XLEN"
+#endif
+
+/** Per hart shared memory */
+struct mpxy_shmem {
+ unsigned long shmem_size;
+ unsigned long shmem_addr_lo;
+ unsigned long shmem_addr_hi;
+};
+
+struct mpxy_state {
+ /* MSI support in MPXY */
+ bool msi_avail;
+ /* SSE support in MPXY */
+ bool sse_avail;
+ /* MPXY Shared memory details */
+ struct mpxy_shmem shmem;
+};
+
+/** Disable hart shared memory */
+static inline void sbi_mpxy_shmem_disable(struct mpxy_state *rs)
+{
+ rs->shmem.shmem_size = 0;
+ rs->shmem.shmem_addr_lo = INVALID_ADDR;
+ rs->shmem.shmem_addr_hi = INVALID_ADDR;
+}
+
+/** Check if shared memory is already setup on hart */
+static inline bool mpxy_shmem_enabled(struct mpxy_state *rs)
+{
+ return (rs->shmem.shmem_addr_lo == INVALID_ADDR
+ && rs->shmem.shmem_addr_hi == INVALID_ADDR) ?
+ false : true;
+}
+
+/** Get hart shared memory base address */
+static inline void *hart_shmem_base(struct mpxy_state *rs)
+{
+ return (void *)(unsigned long)SHMEM_PHYS_ADDR(rs->shmem.shmem_addr_hi,
+ rs->shmem.shmem_addr_lo);
+}
+
+
+/** Make sure all attributes are packed for direct memcpy in ATTR_READ */
+#define assert_field_offset(field, attr_offset) \
+ _Static_assert( \
+ ((offsetof(struct sbi_mpxy_channel_attrs, field)) / \
+ sizeof(u32)) == attr_offset, \
+ "field " #field \
+ " from struct sbi_mpxy_channel_attrs invalid offset, expected " #attr_offset)
+
+assert_field_offset(msg_proto_id, SBI_MPXY_ATTR_MSG_PROT_ID);
+assert_field_offset(msg_proto_version, SBI_MPXY_ATTR_MSG_PROT_VER);
+assert_field_offset(msg_data_maxlen, SBI_MPXY_ATTR_MSG_MAX_LEN);
+assert_field_offset(msg_send_timeout, SBI_MPXY_ATTR_MSG_SEND_TIMEOUT);
+assert_field_offset(capability, SBI_MPXY_ATTR_CHANNEL_CAPABILITY);
+assert_field_offset(msi_control, SBI_MPXY_ATTR_MSI_CONTROL);
+assert_field_offset(msi_info.msi_addr_lo, SBI_MPXY_ATTR_MSI_ADDR_LO);
+assert_field_offset(msi_info.msi_addr_hi, SBI_MPXY_ATTR_MSI_ADDR_HI);
+assert_field_offset(msi_info.msi_data, SBI_MPXY_ATTR_MSI_DATA);
+assert_field_offset(sse_event_id, SBI_MPXY_ATTR_SSE_EVENT_ID);
+assert_field_offset(eventsstate_ctrl, SBI_MPXY_ATTR_EVENTS_STATE_CONTROL);
+
+/**
+ * Check if the attribute is a standard attribute or
+ * a message protocol specific attribute
+ * attr_id[31] = 0 for standard
+ * attr_id[31] = 1 for message protocol specific
+ */
+static inline bool mpxy_is_std_attr(u32 attr_id)
+{
+ return (attr_id >> 31) ? false : true;
+}
+
+/** Find channel_id in registered channels list */
+static struct sbi_mpxy_channel *mpxy_find_channel(u32 channel_id)
+{
+ struct sbi_mpxy_channel *channel;
+
+ sbi_list_for_each_entry(channel, &mpxy_channel_list, head)
+ if (channel->channel_id == channel_id)
+ return channel;
+
+ return NULL;
+}
+
+/** Copy attributes word size */
+static void mpxy_copy_std_attrs(u32 *outmem, u32 *inmem, u32 count)
+{
+ int idx;
+ for (idx = 0; idx < count; idx++)
+ outmem[idx] = cpu_to_le32(inmem[idx]);
+}
+
+/** Check if any channel is registered with mpxy framework */
+bool sbi_mpxy_channel_available(void)
+{
+ return sbi_list_empty(&mpxy_channel_list) ? false : true;
+}
+
+static void mpxy_std_attrs_init(struct sbi_mpxy_channel *channel)
+{
+ struct mpxy_state *rs =
+ sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
+
+ /* Reset values */
+ channel->attrs.msi_control = 0;
+ channel->attrs.msi_info.msi_data = 0;
+ channel->attrs.msi_info.msi_addr_lo = INVALID_ADDR;
+ channel->attrs.msi_info.msi_addr_hi = INVALID_ADDR;
+ channel->attrs.capability = 0;
+ channel->attrs.eventsstate_ctrl = 0;
+
+ /**
+ * Check if MSI or SSE available for notification interrrupt.
+ * Priority given to MSI if both MSI and SSE are avaialble.
+ */
+ if (rs->msi_avail)
+ channel->attrs.capability =
+ CAP_ENABLE(channel->attrs.capability, CAP_MSI_MASK);
+ else if (rs->sse_avail) {
+ channel->attrs.capability =
+ CAP_ENABLE(channel->attrs.capability, CAP_SSE_MASK);
+ /* TODO: Assign SSE EVENT_ID for the channel */
+ }
+
+ /**
+ * Enable Events State in channel capability if message protocol
+ * provides callback to switch
+ */
+ if (channel->switch_eventsstate)
+ channel->attrs.capability =
+ CAP_ENABLE(channel->attrs.capability,
+ CAP_EVENTSSTATE_MASK);
+}
+
+/**
+ * Register a channel with MPXY framework.
+ * Called by message protocol drivers
+ */
+int sbi_mpxy_register_channel(struct sbi_mpxy_channel *channel)
+{
+ if (!channel)
+ return SBI_EINVAL;
+
+ if (mpxy_find_channel(channel->channel_id))
+ return SBI_EALREADY;
+
+ /* Initialize channel specific attributes */
+ mpxy_std_attrs_init(channel);
+
+ SBI_INIT_LIST_HEAD(&channel->head);
+ sbi_list_add_tail(&channel->head, &mpxy_channel_list);
+
+ return SBI_OK;
+}
+
+int sbi_mpxy_init(struct sbi_scratch *scratch)
+{
+ mpxy_state_offset = sbi_scratch_alloc_type_offset(struct mpxy_state);
+ if (!mpxy_state_offset)
+ return SBI_ENOMEM;
+
+ /** TODO: Proper support for checking msi support from platform.
+ * Currently disable msi and sse and use polling
+ **/
+ struct mpxy_state *rs =
+ sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
+ rs->msi_avail = false;
+ rs->sse_avail = false;
+
+ sbi_mpxy_shmem_disable(rs);
+
+ return sbi_platform_mpxy_init(sbi_platform_ptr(scratch));
+}
+
+int sbi_mpxy_set_shmem(unsigned long shmem_size, unsigned long shmem_phys_lo,
+ unsigned long shmem_phys_hi, unsigned long flags)
+{
+ struct mpxy_state *rs =
+ sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
+ unsigned long *ret_buf;
+
+ shmem_size = lle_to_cpu(shmem_size);
+ shmem_phys_hi = lle_to_cpu(shmem_phys_hi);
+ shmem_phys_lo = lle_to_cpu(shmem_phys_lo);
+
+ /** Disable shared memory if both hi and lo have all bit 1s */
+ if (shmem_phys_lo == INVALID_ADDR &&
+ shmem_phys_hi == INVALID_ADDR) {
+ sbi_mpxy_shmem_disable(rs);
+ return SBI_SUCCESS;
+ }
+
+ if (flags >= SBI_EXT_MPXY_SHMEM_FLAG_MAX_IDX)
+ return SBI_ERR_INVALID_PARAM;
+
+ /** Check shared memory size and address aligned to 4K Page */
+ if (!shmem_size || (shmem_size & ~PAGE_MASK) ||
+ (shmem_phys_lo & ~PAGE_MASK))
+ return SBI_ERR_INVALID_PARAM;
+
+ if (!sbi_domain_check_addr_range(sbi_domain_thishart_ptr(),
+ SHMEM_PHYS_ADDR(shmem_phys_hi, shmem_phys_lo),
+ shmem_size, PRV_S,
+ SBI_DOMAIN_READ | SBI_DOMAIN_WRITE))
+ return SBI_ERR_INVALID_ADDRESS;
+
+ /** Save the current shmem details in new shmem region */
+ if (flags == SBI_EXT_MPXY_SHMEM_FLAG_OVERWRITE_RETURN) {
+ ret_buf = (unsigned long *)(ulong)SHMEM_PHYS_ADDR(shmem_phys_hi, shmem_phys_lo);
+ ret_buf[0] = cpu_to_lle(rs->shmem.shmem_size);
+ ret_buf[1] = cpu_to_lle(rs->shmem.shmem_addr_lo);
+ ret_buf[2] = cpu_to_lle(rs->shmem.shmem_addr_hi);
+ }
+
+ /** Setup the new shared memory */
+ rs->shmem.shmem_size = shmem_size;
+ rs->shmem.shmem_addr_lo = shmem_phys_lo;
+ rs->shmem.shmem_addr_hi = shmem_phys_hi;
+
+ return SBI_SUCCESS;
+}
+
+int sbi_mpxy_get_channel_ids(u32 start_index)
+{
+ u32 node_index = 0, node_ret = 0;
+ u32 remaining, returned, max_channelids;
+ u32 channels_count = 0;
+ u32 *shmem_base;
+ struct sbi_mpxy_channel *channel;
+
+ /* Check if the shared memory is being setup or not. */
+ struct mpxy_state *rs =
+ sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
+
+ if (!mpxy_shmem_enabled(rs))
+ return SBI_ERR_NO_SHMEM;
+
+ sbi_list_for_each_entry(channel, &mpxy_channel_list, head)
+ channels_count += 1;
+
+ if (start_index > channels_count)
+ return SBI_ERR_INVALID_PARAM;
+
+ shmem_base = hart_shmem_base(rs);
+ sbi_hart_map_saddr((unsigned long)hart_shmem_base(rs),
+ rs->shmem.shmem_size);
+
+ /** number of channel ids which can be stored in shmem adjusting
+ * for remaining and returned fields */
+ max_channelids = (rs->shmem.shmem_size / sizeof(u32)) - 2;
+ /* total remaining from the start index */
+ remaining = channels_count - start_index;
+ /* how many can be returned */
+ returned = (remaining > max_channelids)? max_channelids : remaining;
+
+ // Iterate over the list of channels to get the channel ids.
+ sbi_list_for_each_entry(channel, &mpxy_channel_list, head) {
+ if (node_index >= start_index &&
+ node_index < (start_index + returned)) {
+ shmem_base[2 + node_ret] = cpu_to_le32(channel->channel_id);
+ node_ret += 1;
+ }
+
+ node_index += 1;
+ }
+
+ /* final remaininig channel ids */
+ remaining = channels_count - (start_index + returned);
+
+ shmem_base[0] = cpu_to_le32(remaining);
+ shmem_base[1] = cpu_to_le32(returned);
+
+ sbi_hart_unmap_saddr();
+
+ return SBI_SUCCESS;
+}
+
+int sbi_mpxy_read_attrs(u32 channel_id, u32 base_attr_id, u32 attr_count)
+{
+ int ret = SBI_SUCCESS;
+ u32 *attr_ptr, end_id;
+ void *shmem_base;
+
+ struct mpxy_state *rs =
+ sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
+
+ if (!mpxy_shmem_enabled(rs))
+ return SBI_ERR_NO_SHMEM;
+
+ struct sbi_mpxy_channel *channel = mpxy_find_channel(channel_id);
+ if (!channel)
+ return SBI_ERR_NOT_SUPPORTED;
+
+ /* base attribute id is not a defined std attribute or reserved */
+ if (base_attr_id >= SBI_MPXY_ATTR_STD_ATTR_MAX_IDX &&
+ base_attr_id < SBI_MPXY_ATTR_MSGPROTO_ATTR_START)
+ return SBI_ERR_INVALID_PARAM;
+
+ /* Sanity check for base_attr_id and attr_count */
+ if (!attr_count || (attr_count > (rs->shmem.shmem_size / ATTR_SIZE)))
+ return SBI_ERR_INVALID_PARAM;
+
+ shmem_base = hart_shmem_base(rs);
+ end_id = base_attr_id + attr_count - 1;
+
+ sbi_hart_map_saddr((unsigned long)hart_shmem_base(rs),
+ rs->shmem.shmem_size);
+
+ /* Standard attributes range check */
+ if (mpxy_is_std_attr(base_attr_id)) {
+ if (end_id >= SBI_MPXY_ATTR_STD_ATTR_MAX_IDX) {
+ ret = SBI_EBAD_RANGE;
+ goto out;
+ }
+
+ attr_ptr = (u32 *)&channel->attrs;
+ mpxy_copy_std_attrs((u32 *)shmem_base, &attr_ptr[base_attr_id],
+ attr_count);
+ } else {
+ /**
+ * Even if the message protocol driver does not provide
+ * read attribute callback, return bad range error instead
+ * of not supported to let client distinguish it from channel
+ * id not supported.
+ * Check the complate range supported for message protocol
+ * attributes. Actual supported attributes will be checked
+ * by the message protocol driver.
+ */
+ if (!channel->read_attributes ||
+ end_id > SBI_MPXY_ATTR_MSGPROTO_ATTR_END) {
+ ret = SBI_ERR_BAD_RANGE;
+ goto out;
+ }
+
+ /**
+ * Function expected to return the SBI supported errors
+ * At this point both base attribute id and only the mpxy
+ * supported range been verified. Platform callback must
+ * check if the range requested is supported by message
+ * protocol driver */
+ ret = channel->read_attributes(channel,
+ (u32 *)shmem_base,
+ base_attr_id, attr_count);
+ }
+out:
+ sbi_hart_unmap_saddr();
+ return ret;
+}
+
+/**
+ * Verify the channel standard attribute wrt to write permission
+ * and the value to be set if valid or not.
+ * Only attributes needs to be checked which are defined Read/Write
+ * permission. Other with Readonly permission will result in error.
+ *
+ * Attributes values to be written must also be checked because
+ * before writing a range of attributes, we need to make sure that
+ * either complete range of attributes is written successfully or not
+ * at all.
+ */
+static int mpxy_check_write_std_attr(struct sbi_mpxy_channel *channel,
+ u32 attr_id, u32 attr_val)
+{
+ int ret = SBI_SUCCESS;
+ struct sbi_mpxy_channel_attrs *attrs = &channel->attrs;
+
+ switch(attr_id) {
+ case SBI_MPXY_ATTR_MSI_CONTROL:
+ if (attr_val > 1)
+ ret = SBI_ERR_INVALID_PARAM;
+ if (attr_val == 1 &&
+ (attrs->msi_info.msi_addr_lo == INVALID_ADDR) &&
+ (attrs->msi_info.msi_addr_hi == INVALID_ADDR))
+ ret = SBI_ERR_DENIED;
+ break;
+ case SBI_MPXY_ATTR_MSI_ADDR_LO:
+ case SBI_MPXY_ATTR_MSI_ADDR_HI:
+ case SBI_MPXY_ATTR_MSI_DATA:
+ ret = SBI_SUCCESS;
+ break;
+ case SBI_MPXY_ATTR_EVENTS_STATE_CONTROL:
+ if (attr_val > 1)
+ ret = SBI_ERR_INVALID_PARAM;
+ break;
+ default:
+ /** All RO access attributes falls under default */
+ ret = SBI_ERR_BAD_RANGE;
+ };
+
+ return ret;
+}
+
+/**
+ * Write the attribute value
+ */
+static void mpxy_write_std_attr(struct sbi_mpxy_channel *channel, u32 attr_id,
+ u32 attr_val)
+{
+ struct mpxy_state *rs =
+ sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
+
+ struct sbi_mpxy_channel_attrs *attrs = &channel->attrs;
+
+ switch(attr_id) {
+ case SBI_MPXY_ATTR_MSI_CONTROL:
+ if (rs->msi_avail && attr_val <= 1)
+ attrs->msi_control = attr_val;
+ break;
+ case SBI_MPXY_ATTR_MSI_ADDR_LO:
+ if (rs->msi_avail)
+ attrs->msi_info.msi_addr_lo = attr_val;
+ break;
+ case SBI_MPXY_ATTR_MSI_ADDR_HI:
+ if (rs->msi_avail)
+ attrs->msi_info.msi_addr_hi = attr_val;
+ break;
+ case SBI_MPXY_ATTR_MSI_DATA:
+ if (rs->msi_avail)
+ attrs->msi_info.msi_data = attr_val;
+ break;
+ case SBI_MPXY_ATTR_EVENTS_STATE_CONTROL:
+ if (CAP_GET(attrs->capability, CAP_EVENTSSTATE_MASK)) {
+ attrs->eventsstate_ctrl = attr_val;
+ /* call message protocol callback */
+ channel->switch_eventsstate(attr_val);
+ }
+
+ break;
+ };
+}
+
+int sbi_mpxy_write_attrs(u32 channel_id, u32 base_attr_id, u32 attr_count)
+{
+ int ret, mem_idx;
+ void *shmem_base;
+ u32 *mem_ptr, attr_id, end_id, attr_val;
+
+ struct mpxy_state *rs =
+ sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
+
+ if (!mpxy_shmem_enabled(rs))
+ return SBI_ERR_NO_SHMEM;
+
+ struct sbi_mpxy_channel *channel = mpxy_find_channel(channel_id);
+ if (!channel)
+ return SBI_ERR_NOT_SUPPORTED;
+
+ /* base attribute id is not a defined std attribute or reserved */
+ if (base_attr_id >= SBI_MPXY_ATTR_STD_ATTR_MAX_IDX &&
+ base_attr_id < SBI_MPXY_ATTR_MSGPROTO_ATTR_START)
+ return SBI_ERR_INVALID_PARAM;
+
+ /* Sanity check for base_attr_id and attr_count */
+ if (!attr_count || (attr_count > (rs->shmem.shmem_size / ATTR_SIZE)))
+ return SBI_ERR_INVALID_PARAM;
+
+ shmem_base = hart_shmem_base(rs);
+ end_id = base_attr_id + attr_count - 1;
+
+ sbi_hart_map_saddr((unsigned long)shmem_base, rs->shmem.shmem_size);
+
+ mem_ptr = (u32 *)shmem_base;
+
+ if (mpxy_is_std_attr(base_attr_id)) {
+ if (end_id >= SBI_MPXY_ATTR_STD_ATTR_MAX_IDX) {
+ ret = SBI_ERR_BAD_RANGE;
+ goto out;
+ }
+
+ /** Verify the attribute ids range and values */
+ mem_idx = 0;
+ for (attr_id = base_attr_id; attr_id <= end_id; attr_id++) {
+ attr_val = le32_to_cpu(mem_ptr[mem_idx++]);
+ ret = mpxy_check_write_std_attr(channel,
+ attr_id, attr_val);
+ if (ret)
+ goto out;
+ }
+
+ /* Write the attribute ids values */
+ mem_idx = 0;
+ for (attr_id = base_attr_id; attr_id <= end_id; attr_id++) {
+ attr_val = le32_to_cpu(mem_ptr[mem_idx++]);
+ mpxy_write_std_attr(channel, attr_id, attr_val);
+ }
+ } else {/**
+ * Message protocol specific attributes:
+ * If attributes belong to message protocol, they
+ * are simply passed to the message protocol driver
+ * callback after checking the valid range.
+ * Attributes contiguous range & permission & other checks
+ * are done by the mpxy and message protocol glue layer.
+ */
+ /**
+ * Even if the message protocol driver does not provide
+ * write attribute callback, return bad range error instead
+ * of not supported to let client distinguish it from channel
+ * id not supported.
+ */
+ if (!channel->write_attributes ||
+ end_id > SBI_MPXY_ATTR_MSGPROTO_ATTR_END) {
+ ret = SBI_ERR_BAD_RANGE;
+ goto out;
+ }
+
+ /**
+ * Function expected to return the SBI supported errors
+ * At this point both base attribute id and only the mpxy
+ * supported range been verified. Platform callback must
+ * check if the range requested is supported by message
+ * protocol driver */
+ ret = channel->write_attributes(channel,
+ (u32 *)shmem_base,
+ base_attr_id, attr_count);
+ }
+out:
+ sbi_hart_unmap_saddr();
+ return ret;
+}
+
+int sbi_mpxy_send_message(u32 channel_id, u8 msg_id, unsigned long msg_data_len,
+ unsigned long *resp_data_len)
+{
+ int ret;
+ void *msgbuf, *shmem_base;
+
+ struct mpxy_state *rs =
+ sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
+
+ if (!mpxy_shmem_enabled(rs))
+ return SBI_ERR_NO_SHMEM;
+
+ struct sbi_mpxy_channel *channel = mpxy_find_channel(channel_id);
+ if (!channel)
+ return SBI_ERR_NOT_SUPPORTED;
+
+ if (!channel->send_message)
+ return SBI_ERR_NOT_IMPLEMENTED;
+
+ if (msg_data_len > rs->shmem.shmem_size ||
+ msg_data_len > channel->attrs.msg_data_maxlen)
+ return SBI_ERR_INVALID_PARAM;
+
+ shmem_base = hart_shmem_base(rs);
+ sbi_hart_map_saddr((unsigned long)shmem_base, rs->shmem.shmem_size);
+ msgbuf = shmem_base;
+
+ ret = channel->send_message(channel, msg_id, msgbuf, msg_data_len,
+ resp_data_len ? shmem_base : NULL,
+ resp_data_len ? rs->shmem.shmem_size : 0,
+ resp_data_len);
+ sbi_hart_unmap_saddr();
+ if (ret)
+ return ret;
+
+ if (resp_data_len &&
+ (*resp_data_len > rs->shmem.shmem_size ||
+ *resp_data_len > channel->attrs.msg_data_maxlen))
+ return SBI_ERR_FAILED;
+
+ return SBI_SUCCESS;
+}
+
+int sbi_mpxy_get_notification_events(u32 channel_id, unsigned long *events_len)
+{
+ int ret;
+ void *eventsbuf, *shmem_base;
+
+ struct mpxy_state *rs =
+ sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
+
+ if (!mpxy_shmem_enabled(rs))
+ return SBI_ERR_NO_SHMEM;
+
+ struct sbi_mpxy_channel *channel = mpxy_find_channel(channel_id);
+ if (!channel)
+ return SBI_ERR_NOT_SUPPORTED;
+
+ if (!channel->get_notification_events)
+ return SBI_ERR_NOT_IMPLEMENTED;
+
+ shmem_base = hart_shmem_base(rs);
+ sbi_hart_map_saddr((unsigned long)shmem_base, rs->shmem.shmem_size);
+ eventsbuf = shmem_base;
+ ret = channel->get_notification_events(channel, eventsbuf,
+ rs->shmem.shmem_size,
+ events_len);
+ sbi_hart_unmap_saddr();
+
+ if (ret)
+ return ret;
+
+ if (*events_len > rs->shmem.shmem_size)
+ return SBI_ERR_FAILED;
+
+ return SBI_SUCCESS;
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 14/16] lib: sbi: Implement SBI MPXY extension
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
` (12 preceding siblings ...)
2024-08-06 7:33 ` [PATCH 13/16] lib: sbi: Add SBI Message Proxy (MPXY) framework Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-08-07 9:24 ` Yu-Chien Peter Lin
2024-08-06 7:33 ` [PATCH 15/16] lib: utils: Add simple FDT based MPXY driver framework Anup Patel
2024-08-06 7:33 ` [PATCH 16/16] lib: utils/mpxy: Add RPMI client driver for MPXY Anup Patel
15 siblings, 1 reply; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
Implement the SBI MPXY extension which provides an SBI interface to
the supervisor software for send messages via MPXY framework.
Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Co-developed-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi/sbi_ecall_interface.h | 10 +++++
lib/sbi/Kconfig | 3 ++
lib/sbi/objects.mk | 3 ++
lib/sbi/sbi_ecall_mpxy.c | 68 +++++++++++++++++++++++++++++++
4 files changed, 84 insertions(+)
create mode 100644 lib/sbi/sbi_ecall_mpxy.c
diff --git a/include/sbi/sbi_ecall_interface.h b/include/sbi/sbi_ecall_interface.h
index 6b993b18..085b33e7 100644
--- a/include/sbi/sbi_ecall_interface.h
+++ b/include/sbi/sbi_ecall_interface.h
@@ -35,6 +35,7 @@
#define SBI_EXT_DBTR 0x44425452
#define SBI_EXT_SSE 0x535345
#define SBI_EXT_FWFT 0x46574654
+#define SBI_EXT_MPXY 0x4D505859
/* SBI function IDs for BASE extension*/
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
@@ -406,6 +407,15 @@ enum sbi_sse_state {
#define SBI_SSE_EVENT_GLOBAL_BIT (1 << 15)
#define SBI_SSE_EVENT_PLATFORM_BIT (1 << 14)
+/* SBI function IDs for MPXY extension */
+#define SBI_EXT_MPXY_SET_SHMEM 0x0
+#define SBI_EXT_MPXY_GET_CHANNEL_IDS 0x1
+#define SBI_EXT_MPXY_READ_ATTRS 0x2
+#define SBI_EXT_MPXY_WRITE_ATTRS 0x3
+#define SBI_EXT_MPXY_SEND_MSG_WITH_RESP 0x4
+#define SBI_EXT_MPXY_SEND_MSG_NO_RESP 0x5
+#define SBI_EXT_MPXY_GET_NOTIFICATION_EVENTS 0x6
+
/* SBI base specification related macros */
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
diff --git a/lib/sbi/Kconfig b/lib/sbi/Kconfig
index bd8ba2b6..c6cc04bc 100644
--- a/lib/sbi/Kconfig
+++ b/lib/sbi/Kconfig
@@ -66,4 +66,7 @@ config SBI_ECALL_SSE
bool "SSE extension"
default y
+config SBI_ECALL_MPXY
+ bool "MPXY extension"
+ default y
endmenu
diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk
index 2cea93b9..c199b834 100644
--- a/lib/sbi/objects.mk
+++ b/lib/sbi/objects.mk
@@ -61,6 +61,9 @@ libsbi-objs-$(CONFIG_SBI_ECALL_DBTR) += sbi_ecall_dbtr.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_SSE) += ecall_sse
libsbi-objs-$(CONFIG_SBI_ECALL_SSE) += sbi_ecall_sse.o
+carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_MPXY) += ecall_mpxy
+libsbi-objs-$(CONFIG_SBI_ECALL_MPXY) += sbi_ecall_mpxy.o
+
libsbi-objs-y += sbi_bitmap.o
libsbi-objs-y += sbi_bitops.o
libsbi-objs-y += sbi_console.o
diff --git a/lib/sbi/sbi_ecall_mpxy.c b/lib/sbi/sbi_ecall_mpxy.c
new file mode 100644
index 00000000..5f717b76
--- /dev/null
+++ b/lib/sbi/sbi_ecall_mpxy.c
@@ -0,0 +1,68 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#include <sbi/sbi_ecall.h>
+#include <sbi/sbi_ecall_interface.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_trap.h>
+#include <sbi/sbi_mpxy.h>
+
+static int sbi_ecall_mpxy_handler(unsigned long extid, unsigned long funcid,
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
+{
+ int ret = 0;
+
+ switch (funcid) {
+ case SBI_EXT_MPXY_SET_SHMEM:
+ ret = sbi_mpxy_set_shmem(regs->a0, regs->a1, regs->a2, regs->a3);
+ break;
+ case SBI_EXT_MPXY_GET_CHANNEL_IDS:
+ ret = sbi_mpxy_get_channel_ids(regs->a0);
+ break;
+ case SBI_EXT_MPXY_READ_ATTRS:
+ ret = sbi_mpxy_read_attrs(regs->a0, regs->a1, regs->a2);
+ break;
+ case SBI_EXT_MPXY_WRITE_ATTRS:
+ ret = sbi_mpxy_write_attrs(regs->a0, regs->a1, regs->a2);
+ break;
+ case SBI_EXT_MPXY_SEND_MSG_WITH_RESP:
+ ret = sbi_mpxy_send_message(regs->a0, regs->a1,
+ regs->a2, &out->value);
+ break;
+ case SBI_EXT_MPXY_SEND_MSG_NO_RESP:
+ ret = sbi_mpxy_send_message(regs->a0, regs->a1, regs->a2,
+ NULL);
+ break;
+ case SBI_EXT_MPXY_GET_NOTIFICATION_EVENTS:
+ ret = sbi_mpxy_get_notification_events(regs->a0, &out->value);
+ break;
+ default:
+ ret = SBI_ENOTSUPP;
+ }
+
+ return ret;
+}
+
+struct sbi_ecall_extension ecall_mpxy;
+
+static int sbi_ecall_mpxy_register_extensions(void)
+{
+ if (!sbi_mpxy_channel_available())
+ return 0;
+
+ return sbi_ecall_register_extension(&ecall_mpxy);
+}
+
+struct sbi_ecall_extension ecall_mpxy = {
+ .extid_start = SBI_EXT_MPXY,
+ .extid_end = SBI_EXT_MPXY,
+ .register_extensions = sbi_ecall_mpxy_register_extensions,
+ .handle = sbi_ecall_mpxy_handler,
+};
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 15/16] lib: utils: Add simple FDT based MPXY driver framework
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
` (13 preceding siblings ...)
2024-08-06 7:33 ` [PATCH 14/16] lib: sbi: Implement SBI MPXY extension Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
2024-08-06 7:33 ` [PATCH 16/16] lib: utils/mpxy: Add RPMI client driver for MPXY Anup Patel
15 siblings, 0 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
The generic platform can have multiple MPXY drivers so add a simple
FDT based MPXY driver framework.
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/mpxy/fdt_mpxy.h | 31 ++++++++++++++++
lib/utils/Kconfig | 2 ++
lib/utils/mpxy/Kconfig | 10 ++++++
lib/utils/mpxy/fdt_mpxy.c | 50 ++++++++++++++++++++++++++
lib/utils/mpxy/fdt_mpxy_drivers.carray | 3 ++
lib/utils/mpxy/objects.mk | 11 ++++++
platform/generic/configs/defconfig | 1 +
platform/generic/platform.c | 2 ++
8 files changed, 110 insertions(+)
create mode 100644 include/sbi_utils/mpxy/fdt_mpxy.h
create mode 100644 lib/utils/mpxy/Kconfig
create mode 100644 lib/utils/mpxy/fdt_mpxy.c
create mode 100644 lib/utils/mpxy/fdt_mpxy_drivers.carray
create mode 100644 lib/utils/mpxy/objects.mk
diff --git a/include/sbi_utils/mpxy/fdt_mpxy.h b/include/sbi_utils/mpxy/fdt_mpxy.h
new file mode 100644
index 00000000..7ea26055
--- /dev/null
+++ b/include/sbi_utils/mpxy/fdt_mpxy.h
@@ -0,0 +1,31 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#ifndef __FDT_MPXY_H__
+#define __FDT_MPXY_H__
+
+#include <sbi/sbi_types.h>
+
+#ifdef CONFIG_FDT_MPXY
+
+struct fdt_mpxy {
+ const struct fdt_match *match_table;
+ int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
+ void (*exit)(void);
+};
+
+int fdt_mpxy_init(void);
+
+#else
+
+static inline int fdt_mpxy_init(void) { return 0; }
+
+#endif
+
+#endif
diff --git a/lib/utils/Kconfig b/lib/utils/Kconfig
index 002d6f8f..901ba564 100644
--- a/lib/utils/Kconfig
+++ b/lib/utils/Kconfig
@@ -32,4 +32,6 @@ source "$(OPENSBI_SRC_DIR)/lib/utils/sys/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/timer/Kconfig"
+source "$(OPENSBI_SRC_DIR)/lib/utils/mpxy/Kconfig"
+
endmenu
diff --git a/lib/utils/mpxy/Kconfig b/lib/utils/mpxy/Kconfig
new file mode 100644
index 00000000..d084b09a
--- /dev/null
+++ b/lib/utils/mpxy/Kconfig
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: BSD-2-Clause
+
+menu "MPXY Device Support"
+
+config FDT_MPXY
+ bool "FDT based MPXY drivers"
+ depends on FDT
+ default n
+
+endmenu
diff --git a/lib/utils/mpxy/fdt_mpxy.c b/lib/utils/mpxy/fdt_mpxy.c
new file mode 100644
index 00000000..41753fab
--- /dev/null
+++ b/lib/utils/mpxy/fdt_mpxy.c
@@ -0,0 +1,50 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#include <sbi/sbi_error.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/mpxy/fdt_mpxy.h>
+
+/* List of FDT MPXY drivers generated at compile time */
+extern struct fdt_mpxy *fdt_mpxy_drivers[];
+extern unsigned long fdt_mpxy_drivers_size;
+
+int fdt_mpxy_init(void)
+{
+ int pos, noff, rc;
+ struct fdt_mpxy *drv;
+ const struct fdt_match *match;
+ void *fdt = fdt_get_address();
+
+ for (pos = 0; pos < fdt_mpxy_drivers_size; pos++) {
+ drv = fdt_mpxy_drivers[pos];
+
+ noff = -1;
+ while ((noff = fdt_find_match(fdt, noff,
+ drv->match_table, &match)) >= 0) {
+ /* drv->init must not be NULL */
+ if (drv->init == NULL)
+ return SBI_EFAIL;
+
+ rc = drv->init(fdt, noff, match);
+ if (rc == SBI_ENODEV)
+ continue;
+ if (rc)
+ return rc;
+
+ /*
+ * We will have multiple MPXY devices so we
+ * cannot break here.
+ */
+ }
+ }
+
+ /* Platforms might not have any MPXY devices so don't fail */
+ return 0;
+}
diff --git a/lib/utils/mpxy/fdt_mpxy_drivers.carray b/lib/utils/mpxy/fdt_mpxy_drivers.carray
new file mode 100644
index 00000000..d930753a
--- /dev/null
+++ b/lib/utils/mpxy/fdt_mpxy_drivers.carray
@@ -0,0 +1,3 @@
+HEADER: sbi_utils/mpxy/fdt_mpxy.h
+TYPE: struct fdt_mpxy
+NAME: fdt_mpxy_drivers
diff --git a/lib/utils/mpxy/objects.mk b/lib/utils/mpxy/objects.mk
new file mode 100644
index 00000000..43e73c94
--- /dev/null
+++ b/lib/utils/mpxy/objects.mk
@@ -0,0 +1,11 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2024 Ventana Micro Systems Inc.
+#
+# Authors:
+# Anup Patel <apatel@ventanamicro.com>
+#
+
+libsbiutils-objs-$(CONFIG_FDT_MPXY) += mpxy/fdt_mpxy.o
+libsbiutils-objs-$(CONFIG_FDT_MPXY) += mpxy/fdt_mpxy_drivers.carray.o
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index 384918f9..1f0880ee 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -53,3 +53,4 @@ CONFIG_FDT_SUSPEND_RPMI=y
CONFIG_FDT_TIMER=y
CONFIG_FDT_TIMER_MTIMER=y
CONFIG_FDT_TIMER_PLMT=y
+CONFIG_FDT_MPXY=y
diff --git a/platform/generic/platform.c b/platform/generic/platform.c
index d085647d..89bd3af9 100644
--- a/platform/generic/platform.c
+++ b/platform/generic/platform.c
@@ -17,6 +17,7 @@
#include <sbi/sbi_string.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_tlb.h>
+#include <sbi_utils/mpxy/fdt_mpxy.h>
#include <sbi_utils/cppc/fdt_cppc.h>
#include <sbi_utils/fdt/fdt_domain.h>
#include <sbi_utils/fdt/fdt_fixup.h>
@@ -418,6 +419,7 @@ const struct sbi_platform_operations platform_ops = {
.get_tlb_num_entries = generic_tlb_num_entries,
.timer_init = fdt_timer_init,
.timer_exit = fdt_timer_exit,
+ .mpxy_init = fdt_mpxy_init,
.vendor_ext_check = generic_vendor_ext_check,
.vendor_ext_provider = generic_vendor_ext_provider,
};
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 16/16] lib: utils/mpxy: Add RPMI client driver for MPXY
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
` (14 preceding siblings ...)
2024-08-06 7:33 ` [PATCH 15/16] lib: utils: Add simple FDT based MPXY driver framework Anup Patel
@ 2024-08-06 7:33 ` Anup Patel
15 siblings, 0 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-06 7:33 UTC (permalink / raw)
To: opensbi
From: Rahul Pathak <rpathak@ventanamicro.com>
Add a generic RPMI mailbox client driver which provides a MPXY channel.
Initially, this driver only supports RPMI clock service group but can
be extended to support multiple RPMI service groups.
Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Co-developed-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/mailbox/rpmi_msgprot.h | 93 ++++++
lib/utils/mpxy/Kconfig | 9 +
lib/utils/mpxy/fdt_mpxy_rpmi_mbox.c | 408 +++++++++++++++++++++++
lib/utils/mpxy/objects.mk | 3 +
platform/generic/configs/defconfig | 1 +
5 files changed, 514 insertions(+)
create mode 100644 lib/utils/mpxy/fdt_mpxy_rpmi_mbox.c
diff --git a/include/sbi_utils/mailbox/rpmi_msgprot.h b/include/sbi_utils/mailbox/rpmi_msgprot.h
index f7913ab1..50d34017 100644
--- a/include/sbi_utils/mailbox/rpmi_msgprot.h
+++ b/include/sbi_utils/mailbox/rpmi_msgprot.h
@@ -153,6 +153,7 @@ enum rpmi_servicegroup_id {
RPMI_SRVGRP_SYSTEM_SUSPEND = 0x00003,
RPMI_SRVGRP_HSM = 0x00004,
RPMI_SRVGRP_CPPC = 0x00005,
+ RPMI_SRVGRP_CLOCK = 0x00007,
RPMI_SRVGRP_ID_MAX_COUNT,
};
@@ -417,4 +418,96 @@ struct rpmi_cppc_hart_list_resp {
u32 hartid[(RPMI_MSG_DATA_SIZE(RPMI_SLOT_SIZE_MIN) - (sizeof(u32) * 3)) / sizeof(u32)];
};
+/** RPMI Clock ServiceGroup Service IDs */
+enum rpmi_clock_service_id {
+ RPMI_CLOCK_SRV_ENABLE_NOTIFICATION = 0x01,
+ RPMI_CLOCK_SRV_GET_NUM_CLOCKS = 0x02,
+ RPMI_CLOCK_SRV_GET_ATTRIBUTES = 0x03,
+ RPMI_CLOCK_SRV_GET_SUPPORTED_RATES = 0x04,
+ RPMI_CLOCK_SRV_SET_CONFIG = 0x05,
+ RPMI_CLOCK_SRV_GET_CONFIG = 0x06,
+ RPMI_CLOCK_SRV_SET_RATE = 0x07,
+ RPMI_CLOCK_SRV_GET_RATE = 0x08,
+ RPMI_CLOCK_SRV_MAX_COUNT,
+};
+
+struct rpmi_clock_get_num_clocks_resp {
+ s32 status;
+ u32 num_clocks;
+};
+
+struct rpmi_clock_get_attributes_req {
+ u32 clock_id;
+};
+
+struct rpmi_clock_get_attributes_resp {
+ s32 status;
+#define RPMI_CLOCK_FLAGS_FORMAT_POS 30
+#define RPMI_CLOCK_FLAGS_FORMAT_MASK \
+ (3U << RPMI_CLOCK_FLAGS_CLOCK_FORMAT_POS)
+#define RPMI_CLOCK_FLAGS_FORMAT_DISCRETE 0
+#define RPMI_CLOCK_FLAGS_FORMAT_LINEAR 1
+ u32 flags;
+ u32 num_rates;
+ u32 transition_latency;
+ u8 name[16];
+};
+
+struct rpmi_clock_get_supported_rates_req {
+ u32 clock_id;
+ u32 clock_rate_index;
+};
+
+struct rpmi_clock_get_supported_rates_resp {
+ s32 status;
+ u32 flags;
+ u32 remaining;
+ u32 returned;
+ u32 clock_rate[0];
+};
+
+struct rpmi_clock_set_config_req {
+ u32 clock_id;
+#define RPMI_CLOCK_CONFIG_ENABLE (1U << 0)
+ u32 config;
+};
+
+struct rpmi_clock_set_config_resp {
+ s32 status;
+};
+
+struct rpmi_clock_get_config_req {
+ u32 clock_id;
+};
+
+struct rpmi_clock_get_config_resp {
+ s32 status;
+ u32 config;
+};
+
+struct rpmi_clock_set_rate_req {
+ u32 clock_id;
+#define RPMI_CLOCK_SET_RATE_FLAGS_MASK (3U << 0)
+#define RPMI_CLOCK_SET_RATE_FLAGS_ROUND_DOWN 0
+#define RPMI_CLOCK_SET_RATE_FLAGS_ROUND_UP 1
+#define RPMI_CLOCK_SET_RATE_FLAGS_ROUND_PLAT 2
+ u32 flags;
+ u32 clock_rate_low;
+ u32 clock_rate_high;
+};
+
+struct rpmi_clock_set_rate_resp {
+ s32 status;
+};
+
+struct rpmi_clock_get_rate_req {
+ u32 clock_id;
+};
+
+struct rpmi_clock_get_rate_resp {
+ s32 status;
+ u32 clock_rate_low;
+ u32 clock_rate_high;
+};
+
#endif /* !__RPMI_MSGPROT_H__ */
diff --git a/lib/utils/mpxy/Kconfig b/lib/utils/mpxy/Kconfig
index d084b09a..131fb91a 100644
--- a/lib/utils/mpxy/Kconfig
+++ b/lib/utils/mpxy/Kconfig
@@ -7,4 +7,13 @@ config FDT_MPXY
depends on FDT
default n
+if FDT_MPXY
+
+config FDT_MPXY_RPMI_MBOX
+ bool "FDT MPXY mailbox client driver"
+ depends on FDT_MAILBOX
+ default n
+
+endif
+
endmenu
diff --git a/lib/utils/mpxy/fdt_mpxy_rpmi_mbox.c b/lib/utils/mpxy/fdt_mpxy_rpmi_mbox.c
new file mode 100644
index 00000000..d396aa7f
--- /dev/null
+++ b/lib/utils/mpxy/fdt_mpxy_rpmi_mbox.c
@@ -0,0 +1,408 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Rahul Pathak <rpathak@ventanamicro.com>
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#include <libfdt.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_heap.h>
+#include <sbi/sbi_mpxy.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/mpxy/fdt_mpxy.h>
+#include <sbi_utils/mailbox/fdt_mailbox.h>
+#include <sbi_utils/mailbox/rpmi_msgprot.h>
+#include <sbi/sbi_console.h>
+
+#define RPMI_MAJOR_VER (0x0000)
+#define RPMI_MINOR_VER (0x0001)
+#define RPMI_MSG_SEND_TIMEOUT (10) /* microseconds */
+
+/** Convert the mpxy attribute ID to attribute array index */
+#define attr_id2index(attr_id) (attr_id - SBI_MPXY_ATTR_MSGPROTO_ATTR_START)
+
+enum mpxy_msgprot_rpmi_attr_id {
+ MPXY_MSGPROT_RPMI_ATTR_SERVICEGROUP_ID = SBI_MPXY_ATTR_MSGPROTO_ATTR_START,
+ MPXY_MSGPROT_RPMI_ATTR_MAX_ID,
+};
+
+/**
+ * MPXY message protocol attributes for RPMI
+ * Order of attribute fields must follow the
+ * attribute IDs in `enum mpxy_msgprot_rpmi_attr_id`
+ */
+struct mpxy_rpmi_channel_attrs {
+ u32 servicegrp_id;
+};
+
+/* RPMI mbox data per service group */
+struct mpxy_mbox_data {
+ u32 servicegrp_id;
+ u32 num_services;
+ u32 notifications_support;
+ void *priv_data;
+};
+
+/* RPMI service data per service group */
+struct rpmi_service_data {
+ u8 id;
+ u32 min_tx_len;
+ u32 max_tx_len;
+ u32 min_rx_len;
+ u32 max_rx_len;
+};
+
+/**
+ * MPXY mbox instance per MPXY channel. This ties
+ * an MPXY channel with an RPMI Service group.
+ */
+struct mpxy_mbox {
+ struct mbox_chan *chan;
+ struct mpxy_mbox_data *mbox_data;
+ struct mpxy_rpmi_channel_attrs msgprot_attrs;
+ struct sbi_mpxy_channel channel;
+};
+
+/** Make sure all attributes are packed for direct memcpy */
+#define assert_field_offset(field, attr_offset) \
+ _Static_assert( \
+ ((offsetof(struct mpxy_rpmi_channel_attrs, field)) / \
+ sizeof(u32)) == (attr_offset - SBI_MPXY_ATTR_MSGPROTO_ATTR_START),\
+ "field " #field \
+ " from struct mpxy_rpmi_channel_attrs invalid offset, expected " #attr_offset)
+
+assert_field_offset(servicegrp_id, MPXY_MSGPROT_RPMI_ATTR_SERVICEGROUP_ID);
+
+/**
+ * Discover the RPMI service data using message_id
+ * MPXY message_id == RPMI service_id
+ */
+static struct rpmi_service_data *mpxy_find_rpmi_srvid(u32 message_id,
+ struct mpxy_mbox_data *mbox_data)
+{
+ int mid = 0;
+ struct rpmi_service_data *srv = mbox_data->priv_data;
+ for (mid = 0; srv[mid].id < mbox_data->num_services; mid++) {
+ if (srv[mid].id == (u8)message_id)
+ return &srv[mid];
+ }
+
+ return NULL;
+}
+
+/** Copy attributes word size */
+static void mpxy_copy_attrs(u32 *outmem, u32 *inmem, u32 count)
+{
+ u32 idx;
+ for (idx = 0; idx < count; idx++)
+ outmem[idx] = cpu_to_le32(inmem[idx]);
+}
+
+static int mpxy_mbox_read_attributes(struct sbi_mpxy_channel *channel,
+ u32 *outmem, u32 base_attr_id,
+ u32 attr_count)
+{
+ u32 end_id;
+ struct mpxy_mbox *rmb =
+ container_of(channel, struct mpxy_mbox, channel);
+
+ u32 *attr_array = (u32 *)&rmb->msgprot_attrs;
+
+ end_id = base_attr_id + attr_count - 1;
+
+ if (end_id >= MPXY_MSGPROT_RPMI_ATTR_MAX_ID)
+ return SBI_ERR_BAD_RANGE;
+
+ mpxy_copy_attrs(outmem, &attr_array[attr_id2index(base_attr_id)],
+ attr_count);
+
+ return SBI_SUCCESS;
+}
+
+/**
+ * Verify the channel standard attribute wrt to write permission
+ * and the value to be set if valid or not.
+ * Only attributes needs to be checked which are defined Read/Write
+ * permission. Other with Readonly permission will result in error.
+ *
+ * Attributes values to be written must also be checked because
+ * before writing a range of attributes, we need to make sure that
+ * either complete range of attributes is written successfully or not
+ * at all.
+ */
+static int mpxy_check_write_attr(u32 attr_id, u32 attr_val)
+{
+ int ret = SBI_SUCCESS;
+
+ switch(attr_id) {
+ /** All RO access attributes falls under default */
+ default:
+ ret = SBI_ERR_BAD_RANGE;
+ };
+
+ return ret;
+}
+
+static void mpxy_write_attr(struct mpxy_rpmi_channel_attrs *attrs,
+ u32 attr_id,
+ u32 attr_val)
+{
+ /* No writable attributes in RPMI */
+}
+
+static int mpxy_mbox_write_attributes(struct sbi_mpxy_channel *channel,
+ u32 *outmem, u32 base_attr_id,
+ u32 attr_count)
+{
+ int ret, mem_idx;
+ u32 end_id, attr_val, idx;
+ struct mpxy_mbox *rmb =
+ container_of(channel, struct mpxy_mbox, channel);
+
+ end_id = base_attr_id + attr_count - 1;
+
+ if (end_id >= MPXY_MSGPROT_RPMI_ATTR_MAX_ID)
+ return SBI_ERR_BAD_RANGE;
+
+ mem_idx = 0;
+ for (idx = base_attr_id; idx <= end_id; idx++) {
+ attr_val = le32_to_cpu(outmem[mem_idx++]);
+ ret = mpxy_check_write_attr(idx, attr_val);
+ if (ret)
+ return ret;
+ }
+
+ mem_idx = 0;
+ for (idx = base_attr_id; idx <= end_id; idx++) {
+ attr_val = le32_to_cpu(outmem[mem_idx++]);
+ mpxy_write_attr(&rmb->msgprot_attrs, idx, attr_val);
+ }
+
+ return SBI_SUCCESS;
+}
+
+static int mpxy_mbox_send_message(struct sbi_mpxy_channel *channel,
+ u32 message_id, void *tx, u32 tx_len,
+ void *rx, u32 rx_max_len,
+ unsigned long *ack_len)
+{
+ int ret;
+ u32 rx_len = 0;
+ struct mbox_xfer xfer;
+ struct rpmi_message_args args = {0};
+ struct mpxy_mbox *rmb =
+ container_of(channel, struct mpxy_mbox, channel);
+ struct rpmi_service_data *srv =
+ mpxy_find_rpmi_srvid(message_id, rmb->mbox_data);
+ if (!srv)
+ return SBI_EFAIL;
+
+ if (tx_len < srv->min_tx_len || tx_len > srv->max_tx_len)
+ return SBI_EFAIL;
+
+ if (ack_len) {
+ if (srv->min_rx_len == srv->max_rx_len)
+ rx_len = srv->min_rx_len;
+ else if (srv->max_rx_len < channel->attrs.msg_data_maxlen)
+ rx_len = srv->max_rx_len;
+ else
+ rx_len = channel->attrs.msg_data_maxlen;
+
+ args.type = RPMI_MSG_NORMAL_REQUEST;
+ args.flags = (rx) ? 0 : RPMI_MSG_FLAGS_NO_RX;
+ args.service_id = srv->id;
+ mbox_xfer_init_txrx(&xfer, &args,
+ tx, tx_len, RPMI_DEF_TX_TIMEOUT,
+ rx, rx_len, RPMI_DEF_TX_TIMEOUT);
+ }
+ else {
+ args.type = RPMI_MSG_POSTED_REQUEST;
+ args.flags = RPMI_MSG_FLAGS_NO_RX;
+ args.service_id = srv->id;
+ mbox_xfer_init_tx(&xfer, &args,
+ tx, tx_len, RPMI_DEF_TX_TIMEOUT);
+ }
+
+ ret = mbox_chan_xfer(rmb->chan, &xfer);
+ if (ret)
+ return (ret == SBI_ETIMEDOUT) ? SBI_ETIMEDOUT : SBI_EFAIL;
+
+ if (ack_len)
+ *ack_len = args.rx_data_len;
+
+ return SBI_OK;
+}
+
+static int mpxy_mbox_get_notifications(struct sbi_mpxy_channel *channel,
+ void *eventsbuf, u32 bufsize,
+ unsigned long *events_len)
+{
+ return SBI_ENOTSUPP;
+}
+
+static int mpxy_mbox_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc, len;
+ const fdt32_t *val;
+ u32 channel_id;
+ struct mpxy_mbox *rmb;
+ struct mbox_chan *chan;
+ const struct mpxy_mbox_data *data = match->data;
+
+ /* Allocate context for RPXY mbox client */
+ rmb = sbi_zalloc(sizeof(*rmb));
+ if (!rmb)
+ return SBI_ENOMEM;
+
+ /*
+ * If channel request failed then other end does not support
+ * service group so do nothing.
+ */
+ rc = fdt_mailbox_request_chan(fdt, nodeoff, 0, &chan);
+ if (rc) {
+ sbi_free(rmb);
+ return 0;
+ }
+
+ /* Match channel service group id */
+ if (data->servicegrp_id != chan->chan_args[0]) {
+ mbox_controller_free_chan(chan);
+ sbi_free(rmb);
+ return SBI_EINVAL;
+ }
+
+ val = fdt_getprop(fdt, nodeoff, "riscv,sbi-mpxy-channel-id", &len);
+ if (len > 0 && val)
+ channel_id = fdt32_to_cpu(*val);
+ else {
+ mbox_controller_free_chan(chan);
+ sbi_free(rmb);
+ return SBI_ENODEV;
+ }
+
+ /* Setup MPXY mbox client */
+ /* Channel ID*/
+ rmb->channel.channel_id = channel_id;
+ /* Callback for read RPMI attributes */
+ rmb->channel.read_attributes = mpxy_mbox_read_attributes;
+ /* Callback for write RPMI attributes */
+ rmb->channel.write_attributes = mpxy_mbox_write_attributes;
+ /* Callback for sending RPMI message */
+ rmb->channel.send_message = mpxy_mbox_send_message;
+ /* Callback to get RPMI notifications */
+ rmb->channel.get_notification_events = mpxy_mbox_get_notifications;
+
+ /* No callback to switch events state data */
+ rmb->channel.switch_eventsstate = NULL;
+
+ /* RPMI Message Protocol ID */
+ rmb->channel.attrs.msg_proto_id = SBI_MPXY_MSGPROTO_RPMI_ID;
+ /* RPMI Message Protocol Version */
+ rmb->channel.attrs.msg_proto_version =
+ SBI_MPXY_MSGPROTO_VERSION(RPMI_MAJOR_VER, RPMI_MINOR_VER);
+
+ /* RPMI supported max message data length(bytes), same for
+ * all service groups */
+ rmb->channel.attrs.msg_data_maxlen =
+ RPMI_MSG_DATA_SIZE(RPMI_SLOT_SIZE_MIN);
+ /* RPMI message send timeout(milliseconds)
+ * same for all service groups */
+ rmb->channel.attrs.msg_send_timeout = RPMI_MSG_SEND_TIMEOUT;
+
+ /* RPMI message protocol attribute: service group id */
+ rmb->msgprot_attrs.servicegrp_id = data->servicegrp_id;
+
+ rmb->mbox_data = (struct mpxy_mbox_data *)data;
+ rmb->chan = chan;
+
+ /* Register RPXY service group */
+ rc = sbi_mpxy_register_channel(&rmb->channel);
+ if (rc) {
+ mbox_controller_free_chan(chan);
+ sbi_free(rmb);
+ return rc;
+ }
+
+ return SBI_OK;
+}
+
+static struct rpmi_service_data clock_services[] = {
+{
+ .id = RPMI_CLOCK_SRV_ENABLE_NOTIFICATION,
+ .min_tx_len = sizeof(struct rpmi_enable_notification_req),
+ .max_tx_len = sizeof(struct rpmi_enable_notification_req),
+ .min_rx_len = sizeof(struct rpmi_enable_notification_resp),
+ .max_rx_len = sizeof(struct rpmi_enable_notification_resp),
+},
+{
+ .id = RPMI_CLOCK_SRV_GET_NUM_CLOCKS,
+ .min_tx_len = 0,
+ .max_tx_len = 0,
+ .min_rx_len = sizeof(struct rpmi_clock_get_num_clocks_resp),
+ .max_rx_len = sizeof(struct rpmi_clock_get_num_clocks_resp),
+},
+{
+ .id = RPMI_CLOCK_SRV_GET_ATTRIBUTES,
+ .min_tx_len = sizeof(struct rpmi_clock_get_attributes_req),
+ .max_tx_len = sizeof(struct rpmi_clock_get_attributes_req),
+ .min_rx_len = sizeof(struct rpmi_clock_get_attributes_resp),
+ .max_rx_len = sizeof(struct rpmi_clock_get_attributes_resp),
+},
+{
+ .id = RPMI_CLOCK_SRV_GET_SUPPORTED_RATES,
+ .min_tx_len = sizeof(struct rpmi_clock_get_supported_rates_req),
+ .max_tx_len = sizeof(struct rpmi_clock_get_supported_rates_req),
+ .min_rx_len = sizeof(struct rpmi_clock_get_supported_rates_resp),
+ .max_rx_len = -1U,
+},
+{
+ .id = RPMI_CLOCK_SRV_SET_CONFIG,
+ .min_tx_len = sizeof(struct rpmi_clock_set_config_req),
+ .max_tx_len = sizeof(struct rpmi_clock_set_config_req),
+ .min_rx_len = sizeof(struct rpmi_clock_set_config_resp),
+ .max_rx_len = sizeof(struct rpmi_clock_set_config_resp),
+},
+{
+ .id = RPMI_CLOCK_SRV_GET_CONFIG,
+ .min_tx_len = sizeof(struct rpmi_clock_get_config_req),
+ .max_tx_len = sizeof(struct rpmi_clock_get_config_req),
+ .min_rx_len = sizeof(struct rpmi_clock_get_config_resp),
+ .max_rx_len = sizeof(struct rpmi_clock_get_config_resp),
+},
+{
+ .id = RPMI_CLOCK_SRV_SET_RATE,
+ .min_tx_len = sizeof(struct rpmi_clock_set_rate_req),
+ .max_tx_len = sizeof(struct rpmi_clock_set_rate_req),
+ .min_rx_len = sizeof(struct rpmi_clock_set_rate_resp),
+ .max_rx_len = sizeof(struct rpmi_clock_set_rate_resp),
+},
+{
+ .id = RPMI_CLOCK_SRV_GET_RATE,
+ .min_tx_len = sizeof(struct rpmi_clock_get_rate_req),
+ .max_tx_len = sizeof(struct rpmi_clock_get_rate_req),
+ .min_rx_len = sizeof(struct rpmi_clock_get_rate_resp),
+ .max_rx_len = sizeof(struct rpmi_clock_get_rate_resp),
+},
+};
+
+static struct mpxy_mbox_data clock_data = {
+ .servicegrp_id = RPMI_SRVGRP_CLOCK,
+ .num_services = RPMI_CLOCK_SRV_MAX_COUNT,
+ .notifications_support = 1,
+ .priv_data = clock_services,
+};
+
+static const struct fdt_match mpxy_mbox_match[] = {
+ { .compatible = "riscv,rpmi-mpxy-clk", .data = &clock_data },
+ { },
+};
+
+struct fdt_mpxy fdt_mpxy_rpmi_mbox = {
+ .match_table = mpxy_mbox_match,
+ .init = mpxy_mbox_init,
+};
diff --git a/lib/utils/mpxy/objects.mk b/lib/utils/mpxy/objects.mk
index 43e73c94..ccb28b55 100644
--- a/lib/utils/mpxy/objects.mk
+++ b/lib/utils/mpxy/objects.mk
@@ -9,3 +9,6 @@
libsbiutils-objs-$(CONFIG_FDT_MPXY) += mpxy/fdt_mpxy.o
libsbiutils-objs-$(CONFIG_FDT_MPXY) += mpxy/fdt_mpxy_drivers.carray.o
+
+carray-fdt_mpxy_drivers-$(CONFIG_FDT_MPXY_RPMI_MBOX) += fdt_mpxy_rpmi_mbox
+libsbiutils-objs-$(CONFIG_FDT_MPXY_RPMI_MBOX) += mpxy/fdt_mpxy_rpmi_mbox.o
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index 1f0880ee..e23b38b2 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -54,3 +54,4 @@ CONFIG_FDT_TIMER=y
CONFIG_FDT_TIMER_MTIMER=y
CONFIG_FDT_TIMER_PLMT=y
CONFIG_FDT_MPXY=y
+CONFIG_FDT_MPXY_RPMI_MBOX=y
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 14/16] lib: sbi: Implement SBI MPXY extension
2024-08-06 7:33 ` [PATCH 14/16] lib: sbi: Implement SBI MPXY extension Anup Patel
@ 2024-08-07 9:24 ` Yu-Chien Peter Lin
2024-08-07 9:34 ` Rahul Pathak
0 siblings, 1 reply; 25+ messages in thread
From: Yu-Chien Peter Lin @ 2024-08-07 9:24 UTC (permalink / raw)
To: opensbi
Hi Anup,
On Tue, Aug 06, 2024 at 01:03:36PM +0530, Anup Patel wrote:
> [EXTERNAL MAIL]
>
> Implement the SBI MPXY extension which provides an SBI interface to
> the supervisor software for send messages via MPXY framework.
>
> Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
> Co-developed-by: Anup Patel <apatel@ventanamicro.com>
> Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> ---
> include/sbi/sbi_ecall_interface.h | 10 +++++
> lib/sbi/Kconfig | 3 ++
> lib/sbi/objects.mk | 3 ++
> lib/sbi/sbi_ecall_mpxy.c | 68 +++++++++++++++++++++++++++++++
> 4 files changed, 84 insertions(+)
> create mode 100644 lib/sbi/sbi_ecall_mpxy.c
>
> diff --git a/include/sbi/sbi_ecall_interface.h b/include/sbi/sbi_ecall_interface.h
> index 6b993b18..085b33e7 100644
> --- a/include/sbi/sbi_ecall_interface.h
> +++ b/include/sbi/sbi_ecall_interface.h
> @@ -35,6 +35,7 @@
> #define SBI_EXT_DBTR 0x44425452
> #define SBI_EXT_SSE 0x535345
> #define SBI_EXT_FWFT 0x46574654
> +#define SBI_EXT_MPXY 0x4D505859
>
> /* SBI function IDs for BASE extension*/
> #define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
> @@ -406,6 +407,15 @@ enum sbi_sse_state {
> #define SBI_SSE_EVENT_GLOBAL_BIT (1 << 15)
> #define SBI_SSE_EVENT_PLATFORM_BIT (1 << 14)
>
> +/* SBI function IDs for MPXY extension */
> +#define SBI_EXT_MPXY_SET_SHMEM 0x0
> +#define SBI_EXT_MPXY_GET_CHANNEL_IDS 0x1
I am unable to find this FID from the thread:
https://lists.riscv.org/g/tech-rpmi/message/89
Could you please let me know if there's an updated
version of the MPXY Chapter?
Thanks,
Peter Lin
> +#define SBI_EXT_MPXY_READ_ATTRS 0x2
> +#define SBI_EXT_MPXY_WRITE_ATTRS 0x3
> +#define SBI_EXT_MPXY_SEND_MSG_WITH_RESP 0x4
> +#define SBI_EXT_MPXY_SEND_MSG_NO_RESP 0x5
> +#define SBI_EXT_MPXY_GET_NOTIFICATION_EVENTS 0x6
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 14/16] lib: sbi: Implement SBI MPXY extension
2024-08-07 9:24 ` Yu-Chien Peter Lin
@ 2024-08-07 9:34 ` Rahul Pathak
2024-08-07 9:46 ` Yu-Chien Peter Lin
0 siblings, 1 reply; 25+ messages in thread
From: Rahul Pathak @ 2024-08-07 9:34 UTC (permalink / raw)
To: opensbi
On Wed, Aug 7, 2024 at 2:55?PM Yu-Chien Peter Lin
<peterlin@andestech.com> wrote:
>
> Hi Anup,
>
> On Tue, Aug 06, 2024 at 01:03:36PM +0530, Anup Patel wrote:
> > [EXTERNAL MAIL]
> >
> > Implement the SBI MPXY extension which provides an SBI interface to
> > the supervisor software for send messages via MPXY framework.
> >
> > Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
> > Co-developed-by: Anup Patel <apatel@ventanamicro.com>
> > Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> > ---
> > include/sbi/sbi_ecall_interface.h | 10 +++++
> > lib/sbi/Kconfig | 3 ++
> > lib/sbi/objects.mk | 3 ++
> > lib/sbi/sbi_ecall_mpxy.c | 68 +++++++++++++++++++++++++++++++
> > 4 files changed, 84 insertions(+)
> > create mode 100644 lib/sbi/sbi_ecall_mpxy.c
> >
> > diff --git a/include/sbi/sbi_ecall_interface.h b/include/sbi/sbi_ecall_interface.h
> > index 6b993b18..085b33e7 100644
> > --- a/include/sbi/sbi_ecall_interface.h
> > +++ b/include/sbi/sbi_ecall_interface.h
> > @@ -35,6 +35,7 @@
> > #define SBI_EXT_DBTR 0x44425452
> > #define SBI_EXT_SSE 0x535345
> > #define SBI_EXT_FWFT 0x46574654
> > +#define SBI_EXT_MPXY 0x4D505859
> >
> > /* SBI function IDs for BASE extension*/
> > #define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
> > @@ -406,6 +407,15 @@ enum sbi_sse_state {
> > #define SBI_SSE_EVENT_GLOBAL_BIT (1 << 15)
> > #define SBI_SSE_EVENT_PLATFORM_BIT (1 << 14)
> >
> > +/* SBI function IDs for MPXY extension */
> > +#define SBI_EXT_MPXY_SET_SHMEM 0x0
> > +#define SBI_EXT_MPXY_GET_CHANNEL_IDS 0x1
>
> I am unable to find this FID from the thread:
> https://lists.riscv.org/g/tech-rpmi/message/89
>
> Could you please let me know if there's an updated
> version of the MPXY Chapter?
This function was added in the V3 version of MPXY spec.
Here is the link https://lists.riscv.org/g/tech-prs/message/974
> Thanks,
> Peter Lin
>
> > +#define SBI_EXT_MPXY_READ_ATTRS 0x2
> > +#define SBI_EXT_MPXY_WRITE_ATTRS 0x3
> > +#define SBI_EXT_MPXY_SEND_MSG_WITH_RESP 0x4
> > +#define SBI_EXT_MPXY_SEND_MSG_NO_RESP 0x5
> > +#define SBI_EXT_MPXY_GET_NOTIFICATION_EVENTS 0x6
--
Thanks
Rahul Pathak
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 14/16] lib: sbi: Implement SBI MPXY extension
2024-08-07 9:34 ` Rahul Pathak
@ 2024-08-07 9:46 ` Yu-Chien Peter Lin
0 siblings, 0 replies; 25+ messages in thread
From: Yu-Chien Peter Lin @ 2024-08-07 9:46 UTC (permalink / raw)
To: opensbi
Hi Rahul,
On Wed, Aug 07, 2024 at 03:04:31PM +0530, Rahul Pathak wrote:
> [EXTERNAL MAIL]
>
> On Wed, Aug 7, 2024 at 2:55?PM Yu-Chien Peter Lin
> <peterlin@andestech.com> wrote:
> >
> > Hi Anup,
> >
> > On Tue, Aug 06, 2024 at 01:03:36PM +0530, Anup Patel wrote:
> > > [EXTERNAL MAIL]
> > >
> > > Implement the SBI MPXY extension which provides an SBI interface to
> > > the supervisor software for send messages via MPXY framework.
> > >
> > > Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
> > > Co-developed-by: Anup Patel <apatel@ventanamicro.com>
> > > Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> > > ---
> > > include/sbi/sbi_ecall_interface.h | 10 +++++
> > > lib/sbi/Kconfig | 3 ++
> > > lib/sbi/objects.mk | 3 ++
> > > lib/sbi/sbi_ecall_mpxy.c | 68 +++++++++++++++++++++++++++++++
> > > 4 files changed, 84 insertions(+)
> > > create mode 100644 lib/sbi/sbi_ecall_mpxy.c
> > >
> > > diff --git a/include/sbi/sbi_ecall_interface.h b/include/sbi/sbi_ecall_interface.h
> > > index 6b993b18..085b33e7 100644
> > > --- a/include/sbi/sbi_ecall_interface.h
> > > +++ b/include/sbi/sbi_ecall_interface.h
> > > @@ -35,6 +35,7 @@
> > > #define SBI_EXT_DBTR 0x44425452
> > > #define SBI_EXT_SSE 0x535345
> > > #define SBI_EXT_FWFT 0x46574654
> > > +#define SBI_EXT_MPXY 0x4D505859
> > >
> > > /* SBI function IDs for BASE extension*/
> > > #define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
> > > @@ -406,6 +407,15 @@ enum sbi_sse_state {
> > > #define SBI_SSE_EVENT_GLOBAL_BIT (1 << 15)
> > > #define SBI_SSE_EVENT_PLATFORM_BIT (1 << 14)
> > >
> > > +/* SBI function IDs for MPXY extension */
> > > +#define SBI_EXT_MPXY_SET_SHMEM 0x0
> > > +#define SBI_EXT_MPXY_GET_CHANNEL_IDS 0x1
> >
> > I am unable to find this FID from the thread:
> > https://lists.riscv.org/g/tech-rpmi/message/89
> >
> > Could you please let me know if there's an updated
> > version of the MPXY Chapter?
>
> This function was added in the V3 version of MPXY spec.
> Here is the link https://lists.riscv.org/g/tech-prs/message/974
Thanks for the information.
Best regards,
Peter Lin
> > Thanks,
> > Peter Lin
> >
> > > +#define SBI_EXT_MPXY_READ_ATTRS 0x2
> > > +#define SBI_EXT_MPXY_WRITE_ATTRS 0x3
> > > +#define SBI_EXT_MPXY_SEND_MSG_WITH_RESP 0x4
> > > +#define SBI_EXT_MPXY_SEND_MSG_NO_RESP 0x5
> > > +#define SBI_EXT_MPXY_GET_NOTIFICATION_EVENTS 0x6
>
>
>
> --
>
> Thanks
> Rahul Pathak
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 04/16] lib/utils: Add RPMI messaging protocol and shared memory transport support
2024-08-06 7:33 ` [PATCH 04/16] lib/utils: Add RPMI messaging protocol and shared memory transport support Anup Patel
@ 2024-08-16 1:01 ` Bo Gan
2024-08-17 6:54 ` Anup Patel
2024-08-26 22:34 ` Bo Gan
1 sibling, 1 reply; 25+ messages in thread
From: Bo Gan @ 2024-08-16 1:01 UTC (permalink / raw)
To: opensbi
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.
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@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@ventanamicro.com>
> Co-developed-by: Subrahmanya Lingappa <slingappa@ventanamicro.com>
> Signed-off-by: Subrahmanya Lingappa <slingappa@ventanamicro.com>
> Co-developed-by: Anup Patel <apatel@ventanamicro.com>
> Signed-off-by: Anup Patel <apatel@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@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@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@ventanamicro.com>
> + * Subrahmanya Lingappa <slingappa@ventanamicro.com>
> + * Anup Patel <apatel@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@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
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 04/16] lib/utils: Add RPMI messaging protocol and shared memory transport support
2024-08-16 1:01 ` Bo Gan
@ 2024-08-17 6:54 ` Anup Patel
0 siblings, 0 replies; 25+ messages in thread
From: Anup Patel @ 2024-08-17 6:54 UTC (permalink / raw)
To: opensbi
On Fri, Aug 16, 2024 at 6:31?AM Bo Gan <ganboing@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@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@ventanamicro.com>
> > Co-developed-by: Subrahmanya Lingappa <slingappa@ventanamicro.com>
> > Signed-off-by: Subrahmanya Lingappa <slingappa@ventanamicro.com>
> > Co-developed-by: Anup Patel <apatel@ventanamicro.com>
> > Signed-off-by: Anup Patel <apatel@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@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@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@ventanamicro.com>
> > + * Subrahmanya Lingappa <slingappa@ventanamicro.com>
> > + * Anup Patel <apatel@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@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
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 04/16] lib/utils: Add RPMI messaging protocol and shared memory transport support
2024-08-06 7:33 ` [PATCH 04/16] lib/utils: Add RPMI messaging protocol and shared memory transport support Anup Patel
2024-08-16 1:01 ` Bo Gan
@ 2024-08-26 22:34 ` Bo Gan
1 sibling, 0 replies; 25+ messages in thread
From: Bo Gan @ 2024-08-26 22:34 UTC (permalink / raw)
To: opensbi
Hi Anup,
Based on the previous discussion (4 scenarios of cache coherency),I have the
following comments (see inline) mainly focused on memory ordering.
On 8/6/24 00:33, Anup Patel wrote:
> From: Rahul Pathak <rpathak@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@ventanamicro.com>
> Co-developed-by: Subrahmanya Lingappa <slingappa@ventanamicro.com>
> Signed-off-by: Subrahmanya Lingappa <slingappa@ventanamicro.com>
> Co-developed-by: Anup Patel <apatel@ventanamicro.com>
> Signed-off-by: Anup Patel <apatel@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@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@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@ventanamicro.com>
> + * Subrahmanya Lingappa <slingappa@ventanamicro.com>
> + * Anup Patel <apatel@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;
> +
No need to have __smq_queue_empty(qctx)
The empty case is already handled later in if (pos == tailidx)
> + /* 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);
> +
There should be a load-acquire style of fence here. Such as
RISCV_FENCE(r, rw);
Or we can __atomic_load_n(tailptr, __ATOMIC_ACQUIRE) to sync with PuC's update
on tailptr. No need to do the same for headptr, as only AP can update headptr,
and it's already protected by spin_lock(&qctx->queue_lock).
Reason: I think technically we might rely on address-dependency-ordering and
argue that we must have known the value of tailidx before we start fetching "msg"
(correction needed, can speculation happen if CPU guesses the correct value of
"tailidx"?). But for code readability and pairing with PuC's store-release, I'd
still prefer we do a fence/barrier here.
> + /*
> + * 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));
> + }
> +
There should be a store-release style of fence here. Such as
RISCV_FENCE(rw, w);
Or we can __atomic_store_n(headptr, __ATOMIC_RELEASE) to publish it to PuC.
smp_wmb() after the store to headptr is not needed. (Incorrect)
Reason: when PuC observed the free slots by reading head/tailptr, AP must finish
touching the previously in-use slot(s). Otherwise, there might be data-corruption
> + /* 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;
Probably no need for fence/barrier here due to control-dependency.
(reading from tailptr is the dependency of "if(__smq_queue_full(qctx))" which
guards the write to msg below). I'm not 100% sure. We might need a second look.
> +
> + /* 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));
> + }
> +
Remove smp_wmb() below and use store-relase on tailptr. See the comment on
headptr in __smq_rx above.
> + /* 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@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
Thanks!
Bo
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 13/16] lib: sbi: Add SBI Message Proxy (MPXY) framework
2024-08-06 7:33 ` [PATCH 13/16] lib: sbi: Add SBI Message Proxy (MPXY) framework Anup Patel
@ 2024-10-11 11:26 ` Yu-Chien Peter Lin
2024-10-11 11:51 ` Rahul Pathak
0 siblings, 1 reply; 25+ messages in thread
From: Yu-Chien Peter Lin @ 2024-10-11 11:26 UTC (permalink / raw)
To: opensbi
Hi Anup,
On Tue, Aug 06, 2024 at 01:03:35PM +0530, Anup Patel wrote:
> From: Rahul Pathak <rpathak@ventanamicro.com>
>
> Introduce SBI Message Proxy (MPXY) framework which allows platform specific
> code or drivers to register message protocol specific channels.
>
> This framework enables the supervisor software to send messages belonging
> to different message protocols via OpenSBI firmware.
>
> Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
> Co-developed-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
> Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
> Co-developed-by: Anup Patel <apatel@ventanamicro.com>
> Signed-off-by: Anup Patel <apatel@ventanamicro.com>
<...>
> +/** Disable hart shared memory */
> +static inline void sbi_mpxy_shmem_disable(struct mpxy_state *rs)
> +{
> + rs->shmem.shmem_size = 0;
> + rs->shmem.shmem_addr_lo = INVALID_ADDR;
> + rs->shmem.shmem_addr_hi = INVALID_ADDR;
nitpicking: if the abbreviation "rs" representing the RPXY state, would it be renamed as "ms"?
Best regards,
Peter Lin
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 13/16] lib: sbi: Add SBI Message Proxy (MPXY) framework
2024-10-11 11:26 ` Yu-Chien Peter Lin
@ 2024-10-11 11:51 ` Rahul Pathak
0 siblings, 0 replies; 25+ messages in thread
From: Rahul Pathak @ 2024-10-11 11:51 UTC (permalink / raw)
To: opensbi
On Fri, Oct 11, 2024 at 4:57?PM Yu-Chien Peter Lin
<peterlin@andestech.com> wrote:
>
> Hi Anup,
>
> On Tue, Aug 06, 2024 at 01:03:35PM +0530, Anup Patel wrote:
> > From: Rahul Pathak <rpathak@ventanamicro.com>
> >
> > Introduce SBI Message Proxy (MPXY) framework which allows platform specific
> > code or drivers to register message protocol specific channels.
> >
> > This framework enables the supervisor software to send messages belonging
> > to different message protocols via OpenSBI firmware.
> >
> > Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
> > Co-developed-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
> > Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
> > Co-developed-by: Anup Patel <apatel@ventanamicro.com>
> > Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> <...>
> > +/** Disable hart shared memory */
> > +static inline void sbi_mpxy_shmem_disable(struct mpxy_state *rs)
> > +{
> > + rs->shmem.shmem_size = 0;
> > + rs->shmem.shmem_addr_lo = INVALID_ADDR;
> > + rs->shmem.shmem_addr_hi = INVALID_ADDR;
>
> nitpicking: if the abbreviation "rs" representing the RPXY state, would it be renamed as "ms"?
It's the remnant of that only. And noted. If another version of the
series happens, I will change it.
>
> Best regards,
> Peter Lin
Thanks
Rahul Pathak
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2024-10-11 11:51 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-06 7:33 [PATCH 00/16] RPMI and SBI MPXY support for OpenSBI Anup Patel
2024-08-06 7:33 ` [PATCH 01/16] lib: Increase ROOT_REGION_MAX to accomodate more memregions Anup Patel
2024-08-06 7:33 ` [PATCH 02/16] lib: utils/mailbox: Add generic mailbox library Anup Patel
2024-08-06 7:33 ` [PATCH 03/16] lib: utils/mailbox: Add simple FDT based mailbox framework Anup Patel
2024-08-06 7:33 ` [PATCH 04/16] lib/utils: Add RPMI messaging protocol and shared memory transport support Anup Patel
2024-08-16 1:01 ` Bo Gan
2024-08-17 6:54 ` Anup Patel
2024-08-26 22:34 ` Bo Gan
2024-08-06 7:33 ` [PATCH 05/16] lib/utils: reset: Add RPMI System Reset driver Anup Patel
2024-08-06 7:33 ` [PATCH 06/16] lib: utils: Add simple FDT based system suspend driver framework Anup Patel
2024-08-06 7:33 ` [PATCH 07/16] lib: utils/suspend: Add RPMI system suspend driver Anup Patel
2024-08-06 7:33 ` [PATCH 08/16] lib: utils: Add simple FDT based HSM driver framework Anup Patel
2024-08-06 7:33 ` [PATCH 09/16] lib: sbi: Add optional resume address to hart suspend Anup Patel
2024-08-06 7:33 ` [PATCH 10/16] lib: utils/hsm: Add RPMI HSM driver Anup Patel
2024-08-06 7:33 ` [PATCH 11/16] lib: utils: Add simple FDT based CPPC driver framework Anup Patel
2024-08-06 7:33 ` [PATCH 12/16] lib: utils/cppc: Add RPMI CPPC driver Anup Patel
2024-08-06 7:33 ` [PATCH 13/16] lib: sbi: Add SBI Message Proxy (MPXY) framework Anup Patel
2024-10-11 11:26 ` Yu-Chien Peter Lin
2024-10-11 11:51 ` Rahul Pathak
2024-08-06 7:33 ` [PATCH 14/16] lib: sbi: Implement SBI MPXY extension Anup Patel
2024-08-07 9:24 ` Yu-Chien Peter Lin
2024-08-07 9:34 ` Rahul Pathak
2024-08-07 9:46 ` Yu-Chien Peter Lin
2024-08-06 7:33 ` [PATCH 15/16] lib: utils: Add simple FDT based MPXY driver framework Anup Patel
2024-08-06 7:33 ` [PATCH 16/16] lib: utils/mpxy: Add RPMI client driver for MPXY Anup Patel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox