[kvm-unit-tests PATCH v9 6/6] riscv: sbi: Add SSE extension tests

Clément Léger cleger at rivosinc.com
Fri Mar 14 07:13:07 PDT 2025



On 14/03/2025 15:11, Andrew Jones wrote:
> 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.

Missed it. I'll resend a V10 if you don't have any other comments.

Thanks,

Clément

> 
>> +			/* 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