[kvm-unit-tests PATCH v9 6/6] riscv: sbi: Add SSE extension tests
Andrew Jones
andrew.jones at linux.dev
Fri Mar 14 07:11:14 PDT 2025
On Fri, Mar 14, 2025 at 12:10:29PM +0100, Clément Léger wrote:
...
> +static void sse_test_inject_local(uint32_t event_id)
> +{
> + int cpu;
> + uint64_t timeout;
> + struct sbiret ret;
> + struct sse_local_per_cpu *cpu_args, *cpu_arg;
> + struct sse_foreign_cpu_test_arg *handler_arg;
> +
> + cpu_args = calloc(NR_CPUS, sizeof(struct sbi_sse_handler_arg));
> +
> + report_prefix_push("local_dispatch");
> + for_each_online_cpu(cpu) {
> + cpu_arg = &cpu_args[cpu];
> + cpu_arg->handler_arg.event_id = event_id;
> + cpu_arg->args.stack = sse_alloc_stack();
> + cpu_arg->args.handler = sse_foreign_cpu_handler;
> + cpu_arg->args.handler_data = (void *)&cpu_arg->handler_arg;
> + cpu_arg->state = SBI_SSE_STATE_UNUSED;
> + }
> +
> + on_cpus(sse_register_enable_local, cpu_args);
> + for_each_online_cpu(cpu) {
> + cpu_arg = &cpu_args[cpu];
> + ret = cpu_arg->ret;
> + if (ret.error) {
> + report_fail("CPU failed to register/enable event: %ld", ret.error);
> + goto cleanup;
> + }
> +
> + handler_arg = &cpu_arg->handler_arg;
> + WRITE_ONCE(handler_arg->expected_cpu, cpu);
> + /* For handler_arg content to be visible for other CPUs */
> + smp_wmb();
> + ret = sbi_sse_inject(event_id, cpus[cpu].hartid);
> + if (ret.error) {
> + report_fail("CPU failed to inject event: %ld", ret.error);
> + goto cleanup;
> + }
> + }
> +
> + for_each_online_cpu(cpu) {
> + handler_arg = &cpu_args[cpu].handler_arg;
> + smp_rmb();
> +
> + timeout = sse_event_get_complete_timeout();
> + while (!READ_ONCE(handler_arg->done) || timer_get_cycles() < timeout) {
I pointed this out in the last review, the || should be a &&. We don't
want to keep waiting until we reach the timeout if we get the done signal
earlier.
> + /* For handler_arg update to be visible */
> + smp_rmb();
> + cpu_relax();
> + }
> + report(READ_ONCE(handler_arg->done), "Event handled");
> + WRITE_ONCE(handler_arg->done, false);
> + }
> +
> +cleanup:
> + on_cpus(sbi_sse_disable_unregister_local, cpu_args);
> + for_each_online_cpu(cpu) {
> + cpu_arg = &cpu_args[cpu];
> + ret = READ_ONCE(cpu_arg->ret);
> + if (ret.error)
> + report_fail("CPU failed to disable/unregister event: %ld", ret.error);
> + }
> +
> + for_each_online_cpu(cpu) {
> + cpu_arg = &cpu_args[cpu];
> + sse_free_stack(cpu_arg->args.stack);
> + }
> +
> + report_prefix_pop();
> +}
> +
> +static void sse_test_inject_global_cpu(uint32_t event_id, unsigned int cpu,
> + struct sse_foreign_cpu_test_arg *test_arg)
> +{
> + unsigned long value;
> + struct sbiret ret;
> + uint64_t timeout;
> + enum sbi_sse_state state;
> +
> + WRITE_ONCE(test_arg->expected_cpu, cpu);
> + /* For test_arg content to be visible for other CPUs */
> + smp_wmb();
> + value = cpu;
> + ret = sbi_sse_write_attrs(event_id, SBI_SSE_ATTR_PREFERRED_HART, 1, &value);
> + if (!sbiret_report_error(&ret, SBI_SUCCESS, "Set preferred hart"))
> + return;
> +
> + ret = sbi_sse_enable(event_id);
> + if (!sbiret_report_error(&ret, SBI_SUCCESS, "Enable event"))
> + return;
> +
> + ret = sbi_sse_inject(event_id, cpu);
> + if (!sbiret_report_error(&ret, SBI_SUCCESS, "Inject event"))
> + goto disable;
> +
> + smp_rmb();
> + timeout = sse_event_get_complete_timeout();
> + while (!READ_ONCE(test_arg->done) || timer_get_cycles() < timeout) {
same comment
> + /* For shared test_arg structure */
> + smp_rmb();
> + cpu_relax();
> + }
> +
> + report(READ_ONCE(test_arg->done), "event handler called");
> + WRITE_ONCE(test_arg->done, false);
> +
> + timeout = sse_event_get_complete_timeout();
> + /* Wait for event to be back in ENABLED state */
> + do {
> + ret = sse_event_get_state(event_id, &state);
> + if (ret.error)
> + goto disable;
> + cpu_relax();
> + } while (state != SBI_SSE_STATE_ENABLED || timer_get_cycles() < timeout);
same comment
Otherwise,
Reviewed-by: Andrew Jones <andrew.jones at linux.dev>
Thanks,
drew
More information about the kvm-riscv
mailing list