[PATCH 12/12] lib: utils: Add MPXY RPMI mailbox driver for System MSI service group
Samuel Holland
samuel.holland at sifive.com
Sun Jan 19 15:11:54 PST 2025
Hi Anup,
On 2025-01-16 9:56 AM, Anup Patel wrote:
> 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 | 208 +++++++++++++++++++++++
> lib/utils/mpxy/objects.mk | 3 +
> platform/generic/configs/defconfig | 1 +
> 5 files changed, 304 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..3dacf28f
> --- /dev/null
> +++ b/lib/utils/mpxy/fdt_mpxy_rpmi_sysmsi.c
> @@ -0,0 +1,208 @@
> +/*
> + * 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);
> + }
> +
Is my understanding correct that this function will eventually contain code to
wire up the P2A doorbell to M-mode for notification support?
> + *context = smg;
> + return 0;
> +}
> +
> +static struct mpxy_rpmi_service_group_ops sysmsi_ops = {
> + .xfer_group = mpxy_rpmi_sysmis_xfer,
> + .setup_group = mpxy_rpmi_sysmsi_setup,
> + .cleanup_group = mpxy_rpmi_sysmsi_cleanup,
> +};
> +
> +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 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,
> + .group_ops = &sysmsi_ops,
> +};
> +
> +static const struct fdt_match sysmsi_match[] = {
> + { .compatible = "riscv,rpmi-mpxy-system-msi", .data = &sysmsi_data },
> + { },
> +};
> +
> +struct fdt_driver fdt_mpxy_rpmi_sysmsi = {
> + .match_table = sysmsi_match,
> + .init = mpxy_rpmi_mbox_init,
> + .experimental = true,
> +};
All of these object definitions should be `const`.
Regards,
Samuel
> 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
More information about the opensbi
mailing list