Re: [PATCH v8 09/10] tests/qtest: cover initial RISC-V RPMI services
Subrahmanya Lingappa <[email protected]>
| Newsgroups | org.nongnu.qemu-riscv,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <CAPxK-6fzMcD7mSfatoAcX4TCmnHyfsjJH_UEgRW1vNPLwBqjZA@mail.gmail.com> |
Sunil, On Mon, Aug 17, 2026 at 4:38 PM Sunil V L <[email protected]> wrote: > > On Fri, Aug 14, 2026 at 10:24 AM Subrahmanya Lingappa > <[email protected]> wrote: > > > > Add qtests for the RPMI transport plus Base, system reset, HSM, and > > system suspend service groups. > > > > Signed-off-by: Subrahmanya Lingappa <[email protected]> > > Reviewed-by: Daniel Henrique Barboza <[email protected]> > > --- > > MAINTAINERS | 1 + > > tests/qtest/meson.build | 2 + > > tests/qtest/riscv-rpmi-test.c | 684 ++++++++++++++++++++++++++++++++++ > > 3 files changed, 687 insertions(+) > > create mode 100644 tests/qtest/riscv-rpmi-test.c > > > > diff --git a/MAINTAINERS b/MAINTAINERS > > index 8e91a31757..6dd71c5a82 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -361,6 +361,7 @@ F: hw/riscv/ > > F: hw/intc/riscv* > > F: hw/misc/riscv_rpmi* > > F: include/hw/misc/riscv_rpmi.h > > +F: tests/qtest/riscv-rpmi-test.c > > F: include/hw/char/riscv_htif.h > > F: include/hw/riscv/ > > F: common-user/host/riscv* > > diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build > > index 4897325d84..d54b79cbcf 100644 > > --- a/tests/qtest/meson.build > > +++ b/tests/qtest/meson.build > > @@ -290,6 +290,8 @@ qtests_riscv32 = \ > > > > qtests_riscv64 = ['riscv-csr-test'] + \ > > (unpack_edk2_blobs ? ['bios-tables-test'] : []) + \ > > + (config_all_devices.has_key('CONFIG_RISCV_RPMI') ? > > + ['riscv-rpmi-test'] : []) + \ > > (config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and > > config_all_devices.has_key('CONFIG_RISCV_IOMMU') ? > > ['iommu-riscv-test'] : []) + \ > > diff --git a/tests/qtest/riscv-rpmi-test.c b/tests/qtest/riscv-rpmi-test.c > > new file mode 100644 > > index 0000000000..dab723b999 > > --- /dev/null > > +++ b/tests/qtest/riscv-rpmi-test.c > > @@ -0,0 +1,684 @@ > > +/* > > + * SPDX-License-Identifier: GPL-2.0-or-later > > + * > > + * QTests for RISC-V RPMI devices. > > + * > > + * Copyright (c) 2026 Qualcomm Technologies, Inc. > > + * Author: > > + * Subrahmanya Lingappa <[email protected]> > > + */ > > + > > +#include "qemu/osdep.h" > > +#include <glib/gstdio.h> > > +#include "libqtest.h" > > +#include "qobject/qdict.h" > > + > > +#define RPMI_SHMEM_BASE 0x10200000ULL > > +#define RPMI_DOORBELL_BASE 0x10230000ULL > > +#define RPMI_IMSIC_S_BASE 0x28000000ULL > > +#define RPMI_CPPC_FASTCHAN_BASE 0x10240000ULL > > +#define RPMI_CPPC_FASTCHAN_SIZE 0x4000 > > +#define RPMI_CPPC_FASTCHAN_FEEDBACK_OFFSET 0x2000 > > +#define RPMI_SLOT_SIZE 64 > > + > > +#define RPMI_A2P_HEAD RPMI_SHMEM_BASE > > +#define RPMI_A2P_TAIL (RPMI_SHMEM_BASE + RPMI_SLOT_SIZE) > > +#define RPMI_A2P_SLOT0 (RPMI_SHMEM_BASE + 2 * RPMI_SLOT_SIZE) > > + > > +#define RPMI_SRVGRP_BASE 0x0001 > > +#define RPMI_SRVGRP_SYSTEM_MSI 0x0002 > > +#define RPMI_SRVGRP_SYSTEM_RESET 0x0003 > > +#define RPMI_SRVGRP_SYSTEM_SUSPEND 0x0004 > > +#define RPMI_SRVGRP_HSM 0x0005 > > +#define RPMI_SRVGRP_CPPC 0x0006 > > +#define RPMI_SRVGRP_CLOCK 0x0008 > > +#define RPMI_SRVGRP_MANAGEMENT_MODE 0x000b > > +#define RPMI_SRVGRP_LOGGING 0x000e > > +#define RPMI_BASE_SRV_GET_PLATFORM_INFO 0x05 > > +#define RPMI_BASE_SRV_PROBE_SERVICE_GROUP 0x06 > > +#define RPMI_SYSMSI_SRV_GET_ATTRIBUTES 0x02 > > +#define RPMI_SYSMSI_SRV_GET_MSI_ATTRIBUTES 0x03 > > +#define RPMI_SYSMSI_SRV_SET_MSI_STATE 0x04 > > +#define RPMI_SYSMSI_SRV_GET_MSI_STATE 0x05 > > +#define RPMI_SYSMSI_SRV_SET_MSI_TARGET 0x06 > > +#define RPMI_SYSMSI_SRV_GET_MSI_TARGET 0x07 > > +#define RPMI_SYSRST_SRV_GET_ATTRIBUTES 0x02 > > +#define RPMI_SYSRST_SRV_SYSTEM_RESET 0x03 > > +#define RPMI_HSM_SRV_GET_HART_STATUS 0x02 > > +#define RPMI_HSM_SRV_GET_HART_LIST 0x03 > > +#define RPMI_HSM_SRV_GET_SUSPEND_TYPES 0x04 > > +#define RPMI_HSM_SRV_GET_SUSPEND_INFO 0x05 > > +#define RPMI_HSM_SRV_HART_START 0x06 > > +#define RPMI_HSM_SRV_HART_STOP 0x07 > > +#define RPMI_HSM_SRV_HART_SUSPEND 0x08 > > +#define RPMI_SYSSUSP_SRV_GET_ATTRIBUTES 0x02 > > +#define RPMI_SYSSUSP_SRV_SYSTEM_SUSPEND 0x03 > > +#define RPMI_CPPC_SRV_PROBE_REG 0x02 > > > Please add only the required definitions. Not the future ones. > > > +#define RPMI_CPPC_SRV_READ_REG 0x03 > > +#define RPMI_CPPC_SRV_WRITE_REG 0x04 > > +#define RPMI_CPPC_SRV_GET_FAST_CHANNEL_REGION 0x05 > > +#define RPMI_CPPC_SRV_GET_FAST_CHANNEL_OFFSET 0x06 > > +#define RPMI_CPPC_SRV_GET_HART_LIST 0x07 > > +#define RPMI_CPPC_NOMINAL_PERF 0x01 > > +#define RPMI_CPPC_DESIRED_PERF 0x05 > > +#define RPMI_CPPC_COUNTER_WRAPAROUND_TIME 0x0a > > +#define RPMI_CPPC_REFERENCE_PERF_COUNTER 0x0b > > +#define RPMI_CPPC_DELIVERED_PERF_COUNTER 0x0c > > +#define RPMI_CPPC_REG_LEN_64 64 > > +#define RPMI_CLK_SRV_GET_NUM_CLOCKS 0x02 > > +#define RPMI_CLK_SRV_GET_ATTRIBUTES 0x03 > > +#define RPMI_CLK_SRV_GET_SUPPORTED_RATES 0x04 > > +#define RPMI_CLK_SRV_SET_CONFIG 0x05 > > +#define RPMI_CLK_SRV_GET_CONFIG 0x06 > > +#define RPMI_CLK_SRV_SET_RATE 0x07 > > +#define RPMI_CLK_SRV_GET_RATE 0x08 > > +#define RPMI_MM_SRV_GET_ATTRIBUTES 0x02 > > +#define RPMI_MM_SRV_COMMUNICATE 0x03 > > +#define RPMI_LOGGING_SRV_SET_CONFIG 0x02 > > +#define RPMI_MSG_NORMAL_REQUEST 0x00 > > +#define RPMI_MSG_POSTED_REQUEST 0x01 > > +#define RPMI_MSG_ACKNOWLEDGEMENT 0x02 > > +#define RPMI_SYSRST_TYPE_SHUTDOWN 0x00 > > +#define RPMI_SYSRST_TYPE_COLD_REBOOT 0x01 > > +#define RPMI_SYSRST_TYPE_INVALID 0x03 > > +#define RPMI_SYSRST_ATTRS_FLAGS_RESETTYPE 1 > > +#define RPMI_SYS_MSI_SHUTDOWN_INDEX 0 > > +#define RPMI_SYS_MSI_REBOOT_INDEX 1 > > +#define RPMI_SYS_MSI_SUSPEND_INDEX 2 > > +#define RPMI_SYS_NUM_MSI 4 > > +#define RPMI_SYSMSI_MSI_STATE_ENABLE 1 > > +#define RPMI_SYSMSI_MSI_STATE_PENDING 2 > > +#define RPMI_TOKEN 0x55aa > > +#define RPMI_ERR_NOTSUPP 0xfffffffeU > > +#define RPMI_ERR_INVALID_PARAM 0xfffffffdU > > +#define RPMI_ERR_INVALID_ADDR 0xfffffffbU > > +#define RPMI_ERR_DENIED 0xfffffffcU > > +#define RPMI_HSM_HART_STATE_STARTED 0x00 > > +#define RPMI_HSM_HART_STATE_STOPPED 0x01 > > +#define RPMI_HSM_HART_STATE_SUSPENDED 0x04 > > +#define VIRT_RPMI_CPPC_NOMINAL_PERF 30 > > +#define VIRT_RPMI_CLOCK_COUNT 6 > > +#define VIRT_RPMI_MM_VERSION 0x10000 > > +#define VIRT_RPMI_SHMEM_SIZE 0x20000 > > +#define RPMI_MM_INPUT_OFFSET 0x3000 > > +#define RPMI_MM_OUTPUT_OFFSET 0x3800 > > +#define RPMI_MM_BUFFER_SIZE 0x400 > > +#define RPMI_MM_INPUT_BASE (RPMI_SHMEM_BASE + RPMI_MM_INPUT_OFFSET) > > +#define RPMI_MM_OUTPUT_BASE (RPMI_SHMEM_BASE + RPMI_MM_OUTPUT_OFFSET) > > +#define MM_EFI_COMM_HEADER_SIZE 24 > > +#define EFI_VAR_COMM_HEADER_SIZE 16 > > +#define EFI_VAR_ACCESS_NAME_OFFSET 36 > > +#define EFI_VAR_NEXT_NAME_OFFSET 24 > > +#define EFI_VAR_FN_GET_VARIABLE 1 > > +#define EFI_VAR_FN_GET_NEXT_VARIABLE_NAME 2 > > +#define EFI_VAR_FN_SET_VARIABLE 3 > > +#define EFI_SUCCESS 0ULL > > +#define EFI_INVALID_PARAMETER 0x8000000000000002ULL > > +#define EFI_BUFFER_TOO_SMALL 0x8000000000000005ULL > > +#define EFI_NOT_FOUND 0x800000000000000eULL > > +#define EFI_VARIABLE_NON_VOLATILE 0x00000001 > > +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 > > +#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 > > + > > +#define RPMI_P2A_ACK_BASE (RPMI_SHMEM_BASE + 16 * RPMI_SLOT_SIZE) > > +#define RPMI_P2A_ACK_HEAD RPMI_P2A_ACK_BASE > > +#define RPMI_P2A_ACK_TAIL (RPMI_P2A_ACK_BASE + RPMI_SLOT_SIZE) > > +#define RPMI_P2A_ACK_SLOT0 (RPMI_P2A_ACK_BASE + 2 * RPMI_SLOT_SIZE) > > + > > +static uint64_t rpmi_response_base; > > + > > +static uint64_t rpmi_queue_slot(uint64_t queue_base, uint32_t index) > > +{ > > + return queue_base + (index + 2) * RPMI_SLOT_SIZE; > > +} > > + > > +static void rpmi_send_request(QTestState *qts, uint16_t service_group, > > + uint8_t service_id, uint8_t request_type, > > + const uint32_t *data, size_t data_words) > > +{ > > + uint32_t tail = qtest_readl(qts, RPMI_A2P_TAIL); > > + uint64_t slot = rpmi_queue_slot(RPMI_SHMEM_BASE, tail); > > + size_t i; > > + > > + qtest_writew(qts, slot, service_group); > > + qtest_writeb(qts, slot + 2, service_id); > > + qtest_writeb(qts, slot + 3, request_type); > > + qtest_writew(qts, slot + 4, data_words * sizeof(*data)); > > + qtest_writew(qts, slot + 6, RPMI_TOKEN); > > + > > + for (i = 0; i < data_words; i++) { > > + qtest_writel(qts, slot + 8 + i * sizeof(*data), data[i]); > > + } > > + > > + g_test_message( > > + "RPMI_A2P_REQ shmem=0x%016" PRIx64 " doorbell=0x%016" PRIx64 > > + " group=0x%04x service=0x%02x type=0x%02x data_len=%zu" > > + " token=0x%04x a2p_tail=%u slot=0x%016" PRIx64, > > + (uint64_t)RPMI_SHMEM_BASE, (uint64_t)RPMI_DOORBELL_BASE, > > + service_group, service_id, request_type, data_words * sizeof(*data), > > + RPMI_TOKEN, tail, slot); > > + > > + qtest_writel(qts, RPMI_A2P_TAIL, (tail + 1) % 16); > > + qtest_writel(qts, RPMI_DOORBELL_BASE, 1); > > +} > > + > > +static uint32_t rpmi_response_word(QTestState *qts, unsigned int word) > > +{ > > + return qtest_readl(qts, rpmi_response_base + 8 + word * sizeof(uint32_t)); > > +} > > + > > +static void rpmi_expect_ack(QTestState *qts, uint16_t service_group, > > + uint8_t service_id, uint16_t data_len) > > +{ > > + uint32_t head = qtest_readl(qts, RPMI_P2A_ACK_HEAD); > > + uint32_t tail = qtest_readl(qts, RPMI_P2A_ACK_TAIL); > > + > > + g_assert_cmphex(tail, !=, head); > > + rpmi_response_base = rpmi_queue_slot(RPMI_P2A_ACK_BASE, head); > > + g_assert_cmphex(qtest_readw(qts, rpmi_response_base), ==, service_group); > > + g_assert_cmphex(qtest_readb(qts, rpmi_response_base + 2), ==, > > + service_id); > > + g_assert_cmphex(qtest_readb(qts, rpmi_response_base + 3), ==, > > + RPMI_MSG_ACKNOWLEDGEMENT); > > + g_assert_cmphex(qtest_readw(qts, rpmi_response_base + 4), ==, data_len); > > + g_assert_cmphex(qtest_readw(qts, rpmi_response_base + 6), ==, > > + RPMI_TOKEN); > > + g_test_message( > > + "RPMI_P2A_ACK shmem=0x%016" PRIx64 > > + " group=0x%04x service=0x%02x type=0x%02x data_len=%u" > > + " token=0x%04x p2a_head=%u slot=0x%016" PRIx64 > > + " status=0x%08x", > > + (uint64_t)RPMI_SHMEM_BASE, service_group, service_id, > > + RPMI_MSG_ACKNOWLEDGEMENT, data_len, RPMI_TOKEN, head, > > + rpmi_response_base, > > + data_len >= sizeof(uint32_t) ? rpmi_response_word(qts, 0) : 0); > > + qtest_writel(qts, RPMI_P2A_ACK_HEAD, (head + 1) % 16); > > +} > > + > > +static void rpmi_send_sysreset(QTestState *qts, uint32_t reset_type, > > + uint8_t request_type) > > +{ > > + rpmi_send_request(qts, RPMI_SRVGRP_SYSTEM_RESET, > > + RPMI_SYSRST_SRV_SYSTEM_RESET, request_type, > > + &reset_type, 1); > > +} > > + > > +static void rpmi_expect_qemu_failure(const char *extra_args, > > + const char *stderr_needle) > > +{ > > + g_autoptr(GError) error = NULL; > > + g_auto(GStrv) split_args = NULL; > > + g_autoptr(GPtrArray) argv = g_ptr_array_new(); > > + g_autofree char *stderr_data = NULL; > > + gint wait_status; > > + gboolean spawned; > > + > > + g_assert_true(g_shell_parse_argv(extra_args, NULL, &split_args, &error)); > > + g_assert_no_error(error); > > + > > + g_ptr_array_add(argv, (gpointer)qtest_qemu_binary(NULL)); > > + for (char **arg = split_args; *arg; arg++) { > > + g_ptr_array_add(argv, *arg); > > + } > > + g_ptr_array_add(argv, NULL); > > + > > + spawned = g_spawn_sync(NULL, (char **)argv->pdata, NULL, > > + G_SPAWN_STDOUT_TO_DEV_NULL, > > + NULL, NULL, NULL, &stderr_data, > > + &wait_status, &error); > > + g_assert_true(spawned); > > + g_assert_no_error(error); > > + g_assert_false(g_spawn_check_exit_status(wait_status, NULL)); > > + g_assert_nonnull(stderr_data); > > + g_assert_nonnull(strstr(stderr_data, stderr_needle)); > > +} > > + > > +static void test_rpmi_machine_realize_off(void) > > +{ > > + QTestState *qts; > > + > > + qts = qtest_init("-machine virt,rpmi=off"); > > + qtest_quit(qts); > > +} > > + > > +static void test_rpmi_machine_rejects_too_many_harts(void) > > +{ > > + rpmi_expect_qemu_failure( > > + "-machine virt,rpmi=on -smp 513 -display none -S", > > + "max CPUs supported by machine 'virt' is 512"); > > +} > > + > > +static void test_rpmi_base_platform_info(void) > > +{ > > + static const char expected[] = "QEMU RISC-V virt RPMI"; > > + QTestState *qts; > > + size_t i; > > + > > + qts = qtest_init("-machine virt,rpmi=on"); > > + rpmi_send_request(qts, RPMI_SRVGRP_BASE, > > + RPMI_BASE_SRV_GET_PLATFORM_INFO, > > + RPMI_MSG_NORMAL_REQUEST, NULL, 0); > > + > > + rpmi_expect_ack(qts, RPMI_SRVGRP_BASE, > > + RPMI_BASE_SRV_GET_PLATFORM_INFO, > > + 2 * sizeof(uint32_t) + sizeof(expected)); > > + g_assert_cmphex(rpmi_response_word(qts, 0), ==, 0); > > + g_assert_cmphex(rpmi_response_word(qts, 1), ==, sizeof(expected)); > > + for (i = 0; i < sizeof(expected); i++) { > > + g_assert_cmphex(qtest_readb(qts, RPMI_P2A_ACK_SLOT0 + 16 + i), ==, > > + expected[i]); > > + } > > + > > + qtest_quit(qts); > > +} > > + > > +static void rpmi_probe_group(QTestState *qts, uint32_t service_group, > > + bool present) > > +{ > > + rpmi_send_request(qts, RPMI_SRVGRP_BASE, > > + RPMI_BASE_SRV_PROBE_SERVICE_GROUP, > > + RPMI_MSG_NORMAL_REQUEST, &service_group, 1); > > + > > + rpmi_expect_ack(qts, RPMI_SRVGRP_BASE, > > + RPMI_BASE_SRV_PROBE_SERVICE_GROUP, > > + 2 * sizeof(uint32_t)); > > + g_assert_cmphex(rpmi_response_word(qts, 0), ==, 0); > > + if (present) { > > + g_assert_cmphex(rpmi_response_word(qts, 1), !=, 0); > > + } else { > > + g_assert_cmphex(rpmi_response_word(qts, 1), ==, 0); > > + } > > +} > > + > > +static void test_rpmi_base_probe_service_groups(void) > > +{ > > + QTestState *qts; > > + > > + qts = qtest_init("-machine virt,rpmi=on,aia=aplic-imsic"); > > + rpmi_probe_group(qts, RPMI_SRVGRP_BASE, true); > > + qtest_system_reset(qts); > > + rpmi_probe_group(qts, RPMI_SRVGRP_SYSTEM_RESET, true); > > + qtest_system_reset(qts); > > + rpmi_probe_group(qts, RPMI_SRVGRP_HSM, true); > > + qtest_system_reset(qts); > > + rpmi_probe_group(qts, RPMI_SRVGRP_SYSTEM_SUSPEND, true); > > + qtest_system_reset(qts); > > > IMO, it is better to add these tests along with the commit which > enabled the feature. Agreed. I will keep only the definitions used by the initial RPMI virt services in this series and remove the future CPPC/Clock/MM/Logging/System MSI definitions from this qtest patch. > > > + rpmi_probe_group(qts, RPMI_SRVGRP_CPPC, false); > > + qtest_system_reset(qts); > > + rpmi_probe_group(qts, RPMI_SRVGRP_SYSTEM_MSI, false); > > + qtest_system_reset(qts); > > + rpmi_probe_group(qts, RPMI_SRVGRP_CLOCK, false); > > + qtest_system_reset(qts); > > + rpmi_probe_group(qts, RPMI_SRVGRP_MANAGEMENT_MODE, false); > > + qtest_system_reset(qts); > > + rpmi_probe_group(qts, RPMI_SRVGRP_LOGGING, false); > > + > > > Please remove these unimplemented service groups from this commit. > Agreed. I will remove probes for unimplemented service groups from this initial qtest patch. The test will only cover the service groups implemented by this series: Base, System Reset, HSM, and System Suspend. Thanks, Subbu > Thanks, > Sunil