From: Andrew Jones <andrew.jones@linux.dev>
To: kvm-riscv@lists.infradead.org
Cc: atishp@rivosinc.com, cleger@rivosinc.com, jamestiotio@gmail.com
Subject: [kvm-unit-tests PATCH 07/10] riscv: sbi: HSM suspend may not be supported
Date: Fri, 21 Feb 2025 16:55:41 +0100 [thread overview]
Message-ID: <20250221155533.123418-19-andrew.jones@linux.dev> (raw)
In-Reply-To: <20250221155533.123418-12-andrew.jones@linux.dev>
The spec doesn't require that any suspend types are supported and
indeed KVM doesn't support non-retentive suspend. Tolerate
SBI_ERR_NOT_SUPPORTED.
TODO: The HSM tests have lots of duplicated code and this patch
adds even more. We need to refactor them and we should break them
out into their own riscv/sbi-hsm.c file too.
Signed-off-by: Andrew Jones <andrew.jones@linux.dev>
---
riscv/sbi.c | 87 ++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 70 insertions(+), 17 deletions(-)
diff --git a/riscv/sbi.c b/riscv/sbi.c
index 7bffaac07283..a0a8331b04bd 100644
--- a/riscv/sbi.c
+++ b/riscv/sbi.c
@@ -571,6 +571,8 @@ static void hart_start_invalid_hartid(void *data)
sbi_hsm_invalid_hartid_check = true;
}
+static cpumask_t hsm_suspend_not_supported;
+
static void ipi_nop(struct pt_regs *regs)
{
ipi_ack();
@@ -587,7 +589,9 @@ static void hart_suspend_and_wait_ipi(unsigned long suspend_type, unsigned long
local_irq_enable();
ret = sbi_hart_suspend_raw(suspend_type, resume_addr, opaque);
- if (ret.error)
+ if (ret.error == SBI_ERR_NOT_SUPPORTED)
+ cpumask_set_cpu(smp_processor_id(), &hsm_suspend_not_supported);
+ else if (ret.error)
report_fail("failed to %s cpu%d (hartid = %lx) (error=%ld)",
typestr, smp_processor_id(), hartid, ret.error);
else if (!returns)
@@ -707,7 +711,7 @@ static void check_hsm(void)
{
struct sbiret ret;
unsigned long hartid;
- cpumask_t secondary_cpus_mask, mask;
+ cpumask_t secondary_cpus_mask, mask, resume_mask;
struct hart_state_transition_info transition_states;
bool ipi_unavailable = false;
int cpu, me = smp_processor_id();
@@ -715,7 +719,7 @@ static void check_hsm(void)
unsigned long hsm_timer_duration = getenv("SBI_HSM_TIMER_DURATION")
? strtol(getenv("SBI_HSM_TIMER_DURATION"), NULL, 0) : 200000;
unsigned long sbi_hsm_hart_start_params[NR_CPUS * SBI_HSM_NUM_OF_PARAMS];
- int count, check;
+ int count, check, expected_count, resume_count;
max_cpus = MIN(MIN(max_cpus, nr_cpus), cpumask_weight(&cpu_present_mask));
@@ -879,6 +883,7 @@ static void check_hsm(void)
goto sbi_hsm_hart_stop_tests;
}
+ cpumask_clear(&hsm_suspend_not_supported);
on_cpumask_async(&secondary_cpus_mask, hart_retentive_suspend, NULL);
transition_states = (struct hart_state_transition_info) {
@@ -888,22 +893,36 @@ static void check_hsm(void)
};
count = hart_wait_state_transition(&secondary_cpus_mask, hsm_timer_duration, &transition_states);
- report(count == max_cpus - 1, "all secondary harts retentive suspended");
+ expected_count = max_cpus - 1 - cpumask_weight(&hsm_suspend_not_supported);
+
+ if (expected_count != 0) {
+ if (expected_count != max_cpus - 1)
+ report_info("not all harts support retentive suspend");
+ report(count == expected_count, "supporting secondary harts retentive suspended");
+ } else {
+ report_skip("retentive suspend not supported by any harts");
+ goto nonret_suspend_tests;
+ }
+
+ cpumask_andnot(&resume_mask, &secondary_cpus_mask, &hsm_suspend_not_supported);
+ resume_count = cpumask_weight(&resume_mask);
/* Ignore the return value since we check the status of each hart anyway */
- sbi_send_ipi_cpumask(&secondary_cpus_mask);
+ sbi_send_ipi_cpumask(&resume_mask);
transition_states = (struct hart_state_transition_info) {
.initial_state = SBI_EXT_HSM_SUSPENDED,
.intermediate_state = SBI_EXT_HSM_RESUME_PENDING,
.final_state = SBI_EXT_HSM_STARTED,
};
- count = hart_wait_state_transition(&secondary_cpus_mask, hsm_timer_duration, &transition_states);
+ count = hart_wait_state_transition(&resume_mask, hsm_timer_duration, &transition_states);
- report(count == max_cpus - 1, "all secondary harts retentive resumed");
+ report(count == resume_count, "supporting secondary harts retentive resumed");
+nonret_suspend_tests:
hart_wait_until_idle(&secondary_cpus_mask, hsm_timer_duration);
+ cpumask_clear(&hsm_suspend_not_supported);
on_cpumask_async(&secondary_cpus_mask, hart_non_retentive_suspend, NULL);
transition_states = (struct hart_state_transition_info) {
@@ -913,20 +932,32 @@ static void check_hsm(void)
};
count = hart_wait_state_transition(&secondary_cpus_mask, hsm_timer_duration, &transition_states);
- report(count == max_cpus - 1, "all secondary harts non-retentive suspended");
+ expected_count = max_cpus - 1 - cpumask_weight(&hsm_suspend_not_supported);
+
+ if (expected_count != 0) {
+ if (expected_count != max_cpus - 1)
+ report_info("not all harts support non-retentive suspend");
+ report(count == expected_count, "supporting secondary harts non-retentive suspended");
+ } else {
+ report_skip("non-retentive suspend not supported by any harts");
+ goto hsm_suspend_tests_done;
+ }
+
+ cpumask_andnot(&resume_mask, &secondary_cpus_mask, &hsm_suspend_not_supported);
+ resume_count = cpumask_weight(&resume_mask);
/* Ignore the return value since we check the status of each hart anyway */
- sbi_send_ipi_cpumask(&secondary_cpus_mask);
+ sbi_send_ipi_cpumask(&resume_mask);
transition_states = (struct hart_state_transition_info) {
.initial_state = SBI_EXT_HSM_SUSPENDED,
.intermediate_state = SBI_EXT_HSM_RESUME_PENDING,
.final_state = SBI_EXT_HSM_STARTED,
};
- count = hart_wait_state_transition(&secondary_cpus_mask, hsm_timer_duration, &transition_states);
+ count = hart_wait_state_transition(&resume_mask, hsm_timer_duration, &transition_states);
check = 0;
- for_each_cpu(cpu, &secondary_cpus_mask) {
+ for_each_cpu(cpu, &resume_mask) {
sbi_hsm_timer_fired = false;
timer_start(hsm_timer_duration);
@@ -952,15 +983,16 @@ static void check_hsm(void)
check++;
}
- report(count == max_cpus - 1, "all secondary harts non-retentive resumed");
- report(check == max_cpus - 1, "all secondary harts have expected register values after non-retentive resume");
+ report(count == resume_count, "supporting secondary harts non-retentive resumed");
+ report(check == resume_count, "supporting secondary harts have expected register values after non-retentive resume");
+hsm_suspend_tests_done:
report_prefix_pop();
sbi_hsm_hart_stop_tests:
report_prefix_push("hart_stop");
- if (ipi_unavailable)
+ if (ipi_unavailable || expected_count == 0)
on_cpumask_async(&secondary_cpus_mask, stop_cpu, NULL);
else
memset(sbi_hsm_stop_hart, 1, sizeof(sbi_hsm_stop_hart));
@@ -994,6 +1026,7 @@ sbi_hsm_hart_stop_tests:
/* Boot up the secondary cpu and let it proceed to the idle loop */
on_cpu(cpu, start_cpu, NULL);
+ cpumask_clear(&hsm_suspend_not_supported);
on_cpu_async(cpu, hart_retentive_suspend_with_msb_set, NULL);
transition_states = (struct hart_state_transition_info) {
@@ -1003,7 +1036,14 @@ sbi_hsm_hart_stop_tests:
};
count = hart_wait_state_transition(&mask, hsm_timer_duration, &transition_states);
- report(count, "secondary hart retentive suspended with MSB set");
+ expected_count = 1 - cpumask_weight(&hsm_suspend_not_supported);
+
+ if (expected_count) {
+ report(count == expected_count, "retentive suspend with MSB set");
+ } else {
+ report_skip("retentive suspend not supported by cpu%d", cpu);
+ goto nonret_suspend_with_msb;
+ }
/* Ignore the return value since we manually validate the status of the hart anyway */
sbi_send_ipi_cpu(cpu);
@@ -1017,10 +1057,12 @@ sbi_hsm_hart_stop_tests:
report(count, "secondary hart retentive resumed with MSB set");
+nonret_suspend_with_msb:
/* Reset these flags so that we can reuse them for the non-retentive suspension test */
sbi_hsm_stop_hart[cpu] = 0;
sbi_hsm_non_retentive_hart_suspend_checks[cpu] = 0;
+ cpumask_clear(&hsm_suspend_not_supported);
on_cpu_async(cpu, hart_non_retentive_suspend_with_msb_set, NULL);
transition_states = (struct hart_state_transition_info) {
@@ -1030,7 +1072,14 @@ sbi_hsm_hart_stop_tests:
};
count = hart_wait_state_transition(&mask, hsm_timer_duration, &transition_states);
- report(count, "secondary hart non-retentive suspended with MSB set");
+ expected_count = 1 - cpumask_weight(&hsm_suspend_not_supported);
+
+ if (expected_count) {
+ report(count == expected_count, "non-retentive suspend with MSB set");
+ } else {
+ report_skip("non-retentive suspend not supported by cpu%d", cpu);
+ goto hsm_hart_stop_test;
+ }
/* Ignore the return value since we manually validate the status of the hart anyway */
sbi_send_ipi_cpu(cpu);
@@ -1071,11 +1120,15 @@ sbi_hsm_hart_stop_tests:
report(count, "secondary hart non-retentive resumed with MSB set");
report(check, "secondary hart has expected register values after non-retentive resume with MSB set");
+hsm_hart_stop_test:
report_prefix_pop();
report_prefix_push("hart_stop");
- sbi_hsm_stop_hart[cpu] = 1;
+ if (expected_count == 0)
+ on_cpu_async(cpu, stop_cpu, NULL);
+ else
+ sbi_hsm_stop_hart[cpu] = 1;
transition_states = (struct hart_state_transition_info) {
.initial_state = SBI_EXT_HSM_STARTED,
--
2.48.1
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
next prev parent reply other threads:[~2025-02-21 15:56 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-21 15:55 [kvm-unit-tests PATCH 00/10] riscv: sbi: Test improvements and a couple new Andrew Jones
2025-02-21 15:55 ` [kvm-unit-tests PATCH 01/10] riscv: sbi: Mark known fwft failures as kfails Andrew Jones
2025-02-24 16:53 ` Clément Léger
2025-02-25 10:14 ` Clément Léger
2025-02-25 10:25 ` Andrew Jones
2025-02-25 15:32 ` Andrew Jones
2025-02-25 15:48 ` Clément Léger
2025-02-26 18:01 ` Andrew Jones
2025-02-21 15:55 ` [kvm-unit-tests PATCH 02/10] riscv: sbi: Ensure we have IPIs enabled for HSM suspend tests Andrew Jones
2025-02-21 15:55 ` [kvm-unit-tests PATCH 03/10] riscv: sbi: Ensure SUSP test gets an interrupt Andrew Jones
2025-02-21 15:55 ` [kvm-unit-tests PATCH 04/10] riscv: sbi: Improve susp expected error output Andrew Jones
2025-02-21 15:55 ` [kvm-unit-tests PATCH 05/10] riscv: sbi: Improve interrupt handling cleanup Andrew Jones
2025-02-21 15:55 ` [kvm-unit-tests PATCH 06/10] lib/cpumask: Add some operators Andrew Jones
2025-02-21 15:55 ` Andrew Jones [this message]
2025-02-21 15:55 ` [kvm-unit-tests PATCH 08/10] riscv: sbi: Probe/skip SUSP Andrew Jones
2025-02-25 15:16 ` Clément Léger
2025-02-21 15:55 ` [kvm-unit-tests PATCH 09/10] riscv: sbi: susp: Check upper bits of sleep_type are ignored Andrew Jones
2025-02-25 15:20 ` Clément Léger
2025-02-21 15:55 ` [kvm-unit-tests PATCH 10/10] riscv: sbi: Add bad fid tests Andrew Jones
2025-02-26 17:59 ` [kvm-unit-tests PATCH 11/10] riscv: sbi: Add fwft pte_hw_ad_updating test Andrew Jones
2025-02-27 9:09 ` Clément Léger
2025-02-27 12:07 ` Andrew Jones
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250221155533.123418-19-andrew.jones@linux.dev \
--to=andrew.jones@linux.dev \
--cc=atishp@rivosinc.com \
--cc=cleger@rivosinc.com \
--cc=jamestiotio@gmail.com \
--cc=kvm-riscv@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.