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 +#include +#include +#include +#include +#include + +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