[PATCH v2 12/13] lib: utils: Add MPXY RPMI mailbox driver for System MSI service group
Anup Patel
apatel at ventanamicro.com
Tue Jan 21 22:44:39 PST 2025
The supervisor software can directly receive most of the system MSIs
except P2A doorbell and MSIs preferred to be handled in M-mode.
Add MPXY RPMI mailbox client driver for the System MSI service group.
Signed-off-by: Anup Patel <apatel at ventanamicro.com>
---
include/sbi_utils/mailbox/rpmi_msgprot.h | 88 ++++++++++
lib/utils/mpxy/Kconfig | 4 +
lib/utils/mpxy/fdt_mpxy_rpmi_sysmsi.c | 204 +++++++++++++++++++++++
lib/utils/mpxy/objects.mk | 3 +
platform/generic/configs/defconfig | 1 +
5 files changed, 300 insertions(+)
create mode 100644 lib/utils/mpxy/fdt_mpxy_rpmi_sysmsi.c
diff --git a/include/sbi_utils/mailbox/rpmi_msgprot.h b/include/sbi_utils/mailbox/rpmi_msgprot.h
index 363cc653..8d8fa5e5 100644
--- a/include/sbi_utils/mailbox/rpmi_msgprot.h
+++ b/include/sbi_utils/mailbox/rpmi_msgprot.h
@@ -208,6 +208,7 @@ enum rpmi_channel_attribute_id {
enum rpmi_servicegroup_id {
RPMI_SRVGRP_ID_MIN = 0,
RPMI_SRVGRP_BASE = 0x0001,
+ RPMI_SRVGRP_SYSTEM_MSI = 0x0002,
RPMI_SRVGRP_SYSTEM_RESET = 0x0003,
RPMI_SRVGRP_SYSTEM_SUSPEND = 0x0004,
RPMI_SRVGRP_HSM = 0x0005,
@@ -267,6 +268,93 @@ struct rpmi_base_get_platform_info_resp {
char plat_info[];
};
+/** RPMI System MSI ServiceGroup Service IDs */
+enum rpmi_sysmsi_service_id {
+ RPMI_SYSMSI_SRV_ENABLE_NOTIFICATION = 0x01,
+ RPMI_SYSMSI_SRV_GET_ATTRIBUTES = 0x2,
+ RPMI_SYSMSI_SRV_GET_MSI_ATTRIBUTES = 0x3,
+ RPMI_SYSMSI_SRV_SET_MSI_STATE = 0x4,
+ RPMI_SYSMSI_SRV_GET_MSI_STATE = 0x5,
+ RPMI_SYSMSI_SRV_SET_MSI_TARGET = 0x6,
+ RPMI_SYSMSI_SRV_GET_MSI_TARGET = 0x7,
+ RPMI_SYSMSI_SRV_ID_MAX_COUNT,
+};
+
+/** Response for system MSI service group attributes */
+struct rpmi_sysmsi_get_attributes_resp {
+ s32 status;
+ u32 sys_num_msi;
+ u32 p2a_db_index;
+ u32 flag0;
+ u32 flag1;
+};
+
+/** Request for system MSI attributes */
+struct rpmi_sysmsi_get_msi_attributes_req {
+ u32 sys_msi_index;
+};
+
+/** Response for system MSI attributes */
+struct rpmi_sysmsi_get_msi_attributes_resp {
+ s32 status;
+ u32 flag0;
+ u32 flag1;
+ u8 name[16];
+};
+
+#define RPMI_SYSMSI_MSI_ATTRIBUTES_FLAG0_PREF_PRIV (1U << 0)
+
+/** Request for system MSI set state */
+struct rpmi_sysmsi_set_msi_state_req {
+ u32 sys_msi_index;
+ u32 sys_msi_state;
+};
+
+#define RPMI_SYSMSI_MSI_STATE_ENABLE (1U << 0)
+#define RPMI_SYSMSI_MSI_STATE_PENDING (1U << 1)
+
+/** Response for system MSI set state */
+struct rpmi_sysmsi_set_msi_state_resp {
+ s32 status;
+};
+
+/** Request for system MSI get state */
+struct rpmi_sysmsi_get_msi_state_req {
+ u32 sys_msi_index;
+};
+
+/** Response for system MSI get state */
+struct rpmi_sysmsi_get_msi_state_resp {
+ s32 status;
+ u32 sys_msi_state;
+};
+
+/** Request for system MSI set target */
+struct rpmi_sysmsi_set_msi_target_req {
+ u32 sys_msi_index;
+ u32 sys_msi_address_low;
+ u32 sys_msi_address_high;
+ u32 sys_msi_data;
+};
+
+/** Response for system MSI set target */
+struct rpmi_sysmsi_set_msi_target_resp {
+ s32 status;
+};
+
+/** Request for system MSI get target */
+struct rpmi_sysmsi_get_msi_target_req {
+ u32 sys_msi_index;
+};
+
+/** Response for system MSI get target */
+struct rpmi_sysmsi_get_msi_target_resp {
+ s32 status;
+ u32 sys_msi_address_low;
+ u32 sys_msi_address_high;
+ u32 sys_msi_data;
+};
+
/** RPMI System Reset ServiceGroup Service IDs */
enum rpmi_system_reset_service_id {
RPMI_SYSRST_SRV_ENABLE_NOTIFICATION = 0x01,
diff --git a/lib/utils/mpxy/Kconfig b/lib/utils/mpxy/Kconfig
index ff88f24f..8d1f5183 100644
--- a/lib/utils/mpxy/Kconfig
+++ b/lib/utils/mpxy/Kconfig
@@ -18,6 +18,10 @@ config FDT_MPXY_RPMI_CLOCK
bool "MPXY driver for RPMI clock service group"
default n
+config FDT_MPXY_RPMI_SYSMSI
+ bool "MPXY driver for RPMI system MSI service group"
+ default n
+
endif
endmenu
diff --git a/lib/utils/mpxy/fdt_mpxy_rpmi_sysmsi.c b/lib/utils/mpxy/fdt_mpxy_rpmi_sysmsi.c
new file mode 100644
index 00000000..87e6aa53
--- /dev/null
+++ b/lib/utils/mpxy/fdt_mpxy_rpmi_sysmsi.c
@@ -0,0 +1,204 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Ventana Micro Systems Inc.
+ */
+
+#include <sbi/sbi_bitmap.h>
+#include <sbi/sbi_domain.h>
+#include <sbi/sbi_byteorder.h>
+#include <sbi/sbi_heap.h>
+#include <sbi_utils/mailbox/rpmi_mailbox.h>
+#include <sbi_utils/mpxy/fdt_mpxy_rpmi_mbox.h>
+
+struct mpxy_rpmi_sysmsi {
+ u32 sys_num_msi;
+ unsigned long *sys_msi_denied_bmap;
+};
+
+static int mpxy_rpmi_sysmis_xfer(void *context, struct mbox_chan *chan,
+ struct mbox_xfer *xfer)
+{
+ struct rpmi_message_args *args = xfer->args;
+ struct mpxy_rpmi_sysmsi *smg = context;
+ u64 sys_msi_address;
+ u32 sys_msi_index;
+ int rc = 0;
+
+ if (!xfer->rx || args->type != RPMI_MSG_NORMAL_REQUEST)
+ return 0;
+
+ switch (args->service_id) {
+ case RPMI_SYSMSI_SRV_GET_ATTRIBUTES:
+ ((u32 *)xfer->rx)[0] = cpu_to_le32(RPMI_SUCCESS);
+ ((u32 *)xfer->rx)[1] = cpu_to_le32(smg->sys_num_msi);
+ ((u32 *)xfer->rx)[2] = -1U;
+ ((u32 *)xfer->rx)[3] = 0;
+ ((u32 *)xfer->rx)[4] = 0;
+ args->rx_data_len = 5 * sizeof(u32);
+ break;
+ case RPMI_SYSMSI_SRV_GET_MSI_ATTRIBUTES:
+ case RPMI_SYSMSI_SRV_SET_MSI_STATE:
+ case RPMI_SYSMSI_SRV_GET_MSI_STATE:
+ case RPMI_SYSMSI_SRV_SET_MSI_TARGET:
+ case RPMI_SYSMSI_SRV_GET_MSI_TARGET:
+ sys_msi_index = le32_to_cpu(((u32 *)xfer->tx)[0]);
+ if (smg->sys_num_msi <= sys_msi_index) {
+ ((u32 *)xfer->rx)[0] = cpu_to_le32(RPMI_ERR_INVALID_PARAM);
+ args->rx_data_len = sizeof(u32);
+ break;
+ }
+ if (bitmap_test(smg->sys_msi_denied_bmap, sys_msi_index)) {
+ ((u32 *)xfer->rx)[0] = cpu_to_le32(RPMI_ERR_DENIED);
+ args->rx_data_len = sizeof(u32);
+ break;
+ }
+ if (args->service_id == RPMI_SYSMSI_SRV_SET_MSI_TARGET) {
+ sys_msi_address = le32_to_cpu(((u32 *)xfer->tx)[1]);
+ sys_msi_address |= ((u64)le32_to_cpu(((u32 *)xfer->tx)[2])) << 32;
+ if (!sbi_domain_check_addr_range(sbi_domain_thishart_ptr(),
+ sys_msi_address, 0x4, PRV_S,
+ SBI_DOMAIN_READ | SBI_DOMAIN_WRITE)) {
+ ((u32 *)xfer->rx)[0] = cpu_to_le32(RPMI_ERR_INVALID_ADDR);
+ args->rx_data_len = sizeof(u32);
+ break;
+ }
+ }
+ rc = mbox_chan_xfer(chan, xfer);
+ break;
+ default:
+ ((u32 *)xfer->rx)[0] = cpu_to_le32(RPMI_ERR_NOTSUPP);
+ args->rx_data_len = sizeof(u32);
+ break;
+ };
+
+ return rc;
+}
+
+static void mpxy_rpmi_sysmsi_cleanup(void *context)
+{
+ struct mpxy_rpmi_sysmsi *smg = context;
+
+ sbi_free(smg->sys_msi_denied_bmap);
+ sbi_free(smg);
+}
+
+static int mpxy_rpmi_sysmsi_setup(void **context, struct mbox_chan *chan,
+ const struct mpxy_rpmi_mbox_data *data)
+{
+ struct rpmi_sysmsi_get_msi_attributes_resp gmaresp;
+ struct rpmi_sysmsi_get_msi_attributes_req gmareq;
+ struct rpmi_sysmsi_get_attributes_resp garesp;
+ struct mpxy_rpmi_sysmsi *smg;
+ int rc, i;
+
+ rc = rpmi_normal_request_with_status(chan, RPMI_SYSMSI_SRV_GET_ATTRIBUTES,
+ NULL, 0, 0, &garesp, rpmi_u32_count(garesp),
+ rpmi_u32_count(garesp));
+ if (rc)
+ return rc;
+
+ smg = sbi_zalloc(sizeof(*smg));
+ if (!smg)
+ return SBI_ENOMEM;
+
+ smg->sys_num_msi = garesp.sys_num_msi;
+ smg->sys_msi_denied_bmap = sbi_zalloc(bitmap_estimate_size(smg->sys_num_msi));
+ if (!smg->sys_msi_denied_bmap) {
+ sbi_free(smg);
+ return SBI_ENOMEM;
+ }
+
+ for (i = 0; i < smg->sys_num_msi; i++) {
+ gmareq.sys_msi_index = i;
+ rc = rpmi_normal_request_with_status(chan,
+ RPMI_SYSMSI_SRV_GET_MSI_ATTRIBUTES,
+ &gmareq, rpmi_u32_count(gmareq),
+ rpmi_u32_count(gmareq),
+ &gmaresp, rpmi_u32_count(gmaresp),
+ rpmi_u32_count(gmaresp));
+ if (rc) {
+ mpxy_rpmi_sysmsi_cleanup(smg);
+ return rc;
+ }
+
+ if (garesp.p2a_db_index == i ||
+ (gmaresp.flag0 & RPMI_SYSMSI_MSI_ATTRIBUTES_FLAG0_PREF_PRIV))
+ bitmap_set(smg->sys_msi_denied_bmap, i, 1);
+ }
+
+ *context = smg;
+ return 0;
+}
+
+static struct mpxy_rpmi_service_data sysmsi_services[] = {
+{
+ .id = RPMI_SYSMSI_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_SYSMSI_SRV_GET_ATTRIBUTES,
+ .min_tx_len = 0,
+ .max_tx_len = 0,
+ .min_rx_len = sizeof(struct rpmi_sysmsi_get_attributes_resp),
+ .max_rx_len = sizeof(struct rpmi_sysmsi_get_attributes_resp),
+},
+{
+ .id = RPMI_SYSMSI_SRV_GET_MSI_ATTRIBUTES,
+ .min_tx_len = sizeof(struct rpmi_sysmsi_get_msi_attributes_req),
+ .max_tx_len = sizeof(struct rpmi_sysmsi_get_msi_attributes_req),
+ .min_rx_len = sizeof(struct rpmi_sysmsi_get_msi_attributes_resp),
+ .max_rx_len = sizeof(struct rpmi_sysmsi_get_msi_attributes_resp),
+},
+{
+ .id = RPMI_SYSMSI_SRV_SET_MSI_STATE,
+ .min_tx_len = sizeof(struct rpmi_sysmsi_set_msi_state_req),
+ .max_tx_len = sizeof(struct rpmi_sysmsi_set_msi_state_req),
+ .min_rx_len = sizeof(struct rpmi_sysmsi_set_msi_state_resp),
+ .max_rx_len = sizeof(struct rpmi_sysmsi_set_msi_state_resp),
+},
+{
+ .id = RPMI_SYSMSI_SRV_GET_MSI_STATE,
+ .min_tx_len = sizeof(struct rpmi_sysmsi_get_msi_state_req),
+ .max_tx_len = sizeof(struct rpmi_sysmsi_get_msi_state_req),
+ .min_rx_len = sizeof(struct rpmi_sysmsi_get_msi_state_resp),
+ .max_rx_len = sizeof(struct rpmi_sysmsi_get_msi_state_resp),
+},
+{
+ .id = RPMI_SYSMSI_SRV_SET_MSI_TARGET,
+ .min_tx_len = sizeof(struct rpmi_sysmsi_set_msi_target_req),
+ .max_tx_len = sizeof(struct rpmi_sysmsi_set_msi_target_req),
+ .min_rx_len = sizeof(struct rpmi_sysmsi_set_msi_target_resp),
+ .max_rx_len = sizeof(struct rpmi_sysmsi_set_msi_target_resp),
+},
+{
+ .id = RPMI_SYSMSI_SRV_GET_MSI_TARGET,
+ .min_tx_len = sizeof(struct rpmi_sysmsi_get_msi_target_req),
+ .max_tx_len = sizeof(struct rpmi_sysmsi_get_msi_target_req),
+ .min_rx_len = sizeof(struct rpmi_sysmsi_get_msi_target_resp),
+ .max_rx_len = sizeof(struct rpmi_sysmsi_get_msi_target_resp),
+},
+};
+
+static const struct mpxy_rpmi_mbox_data sysmsi_data = {
+ .servicegrp_id = RPMI_SRVGRP_SYSTEM_MSI,
+ .num_services = RPMI_SYSMSI_SRV_ID_MAX_COUNT,
+ .service_data = sysmsi_services,
+ .xfer_group = mpxy_rpmi_sysmis_xfer,
+ .setup_group = mpxy_rpmi_sysmsi_setup,
+ .cleanup_group = mpxy_rpmi_sysmsi_cleanup,
+};
+
+static const struct fdt_match sysmsi_match[] = {
+ { .compatible = "riscv,rpmi-mpxy-system-msi", .data = &sysmsi_data },
+ { },
+};
+
+const struct fdt_driver fdt_mpxy_rpmi_sysmsi = {
+ .match_table = sysmsi_match,
+ .init = mpxy_rpmi_mbox_init,
+ .experimental = true,
+};
diff --git a/lib/utils/mpxy/objects.mk b/lib/utils/mpxy/objects.mk
index 1c9afed9..5b6e9bdf 100644
--- a/lib/utils/mpxy/objects.mk
+++ b/lib/utils/mpxy/objects.mk
@@ -14,3 +14,6 @@ libsbiutils-objs-$(CONFIG_FDT_MPXY_RPMI_MBOX) += mpxy/fdt_mpxy_rpmi_mbox.o
carray-fdt_mpxy_drivers-$(CONFIG_FDT_MPXY_RPMI_CLOCK) += fdt_mpxy_rpmi_clock
libsbiutils-objs-$(CONFIG_FDT_MPXY_RPMI_CLOCK) += mpxy/fdt_mpxy_rpmi_clock.o
+
+carray-fdt_mpxy_drivers-$(CONFIG_FDT_MPXY_RPMI_SYSMSI) += fdt_mpxy_rpmi_sysmsi
+libsbiutils-objs-$(CONFIG_FDT_MPXY_RPMI_SYSMSI) += mpxy/fdt_mpxy_rpmi_sysmsi.o
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index 55607a28..bb260626 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -56,3 +56,4 @@ CONFIG_FDT_TIMER_PLMT=y
CONFIG_FDT_MPXY=y
CONFIG_FDT_MPXY_RPMI_MBOX=y
CONFIG_FDT_MPXY_RPMI_CLOCK=y
+CONFIG_FDT_MPXY_RPMI_SYSMSI=y
--
2.43.0
More information about the opensbi
mailing list