From nobody Wed Sep 10 05:50:41 2025 Received: from mail-pf1-f179.google.com (mail-pf1-f179.google.com [209.85.210.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 46176315760 for ; Mon, 8 Sep 2025 18:19:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757355588; cv=none; b=CXor/VuCXkEpThglzbWxczXbgOaPBAv81t9PeH5aLgPz5WrxvYcU5LrHhpjflC4ZrPqGWUfRgyimGB88BoplvfaipCxVJmyiq1RccPx+sQm/vf7rQEuSrsPyYFrJrwbmOMA3TTaAAkS4EperRdbjz3lR/aIQnz8c+CHo8CrJCsQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757355588; c=relaxed/simple; bh=CsrCjoEb8GMpMM4AvLanvFBpu9wQgvuAkVBQK2O1DVo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=tQIGeMVX4IBZEAusz0fnyo9YuSiCkokD9W7HwKp+Z8cSrjkXrWlt+3TX9DEBEaxvtK/g0Qio86kPnxed8wYCCiBoOG0s9ohJucMl9P7IHITgMNATFy+ziyuNswvF0H0B9MjhV9O4d89Ck+8CBAV4sa6p6Pom/f/oAMq6FSMLqyo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rivosinc.com; spf=pass smtp.mailfrom=rivosinc.com; dkim=pass (2048-bit key) header.d=rivosinc.com header.i=@rivosinc.com header.b=FJHfJ2Gc; arc=none smtp.client-ip=209.85.210.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rivosinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rivosinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rivosinc.com header.i=@rivosinc.com header.b="FJHfJ2Gc" Received: by mail-pf1-f179.google.com with SMTP id d2e1a72fcca58-77256e75eacso4236974b3a.0 for ; Mon, 08 Sep 2025 11:19:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc.com; s=google; t=1757355585; x=1757960385; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=U6V/dwP2/cPc37KZ6fRfJbHeVitho/24+GF4+3qcxjQ=; b=FJHfJ2GcXMCm4wMkwkJ081DfbZ/zC75Bza6YzDrZudAliAUuZIvVb71/EwPNFRoczj n4RG6KntZXvPk3ecOv8kTBUF62bom2Ef0PTGSikVshoxqiyfMwicXUffvpM5fk4cbSpJ tZR80FUgi5g6mvqWm00Nipf1C87z+TAp+AOpz4yGW/7j/ym/Z1ndo2U2OOz7Pp05Widx puF75/0qX8Y12TUsVBWdx+hLTVnQ8vLkBK7aP29CZnrS4dDbLv7S64jWKtma81idndtB sbv4HzMacS4dPZrOTPv3yk+BHS+EQuGw+5MgQgCLU6TVftIY1bPf2HzDSSv2FER3xM6l 3qRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757355585; x=1757960385; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=U6V/dwP2/cPc37KZ6fRfJbHeVitho/24+GF4+3qcxjQ=; b=HR60/yf1yIrxrPSR0+N89N4sPohk+GooJHiVXyZq679roTw2UwRhO3viakOK2zWFZo 4aD6985i6x0QfO8tPfPmzHv5T3E+BjInGacvbnIWsqyS2clDk61xQOgIETq7f8b10ZvB 8r3pUUwqTwT5z27yLbtBmw464XKWHdhgeyWVHVJNvuZ/zMc6lMRzuNH36c/uvKG3SADy P9h2u3engpqmq2dQsEC/6Og0zWsxRHdPMuls8KmsjIfaAVVoSd30BOGctLyyqIFhjYDA c3muCeSeJ61kTYn3+KFpT8oq/j8n00o0TIfawUuuwVaAzvy3DF8AexbMq6sPGn7qCoib YUgw== X-Forwarded-Encrypted: i=1; AJvYcCXIx1EBgSJQtXy23yDhc9rhl4wYLlz4rngzl0VPyA3Uq0NjOP2h8bMuuQ7Te6XfuqWV8UjWA2Aw7Xu9DfM=@vger.kernel.org X-Gm-Message-State: AOJu0Ywmke6Mvt5n96yv92aU/xGTja/aa7szfkSSJeamae7qNj+ctjnm XiLrFtXhfZbhUy38P0az58p4eor3Ap1dVIJHmsTVFSaNUJuB02NnkKShJ6Dy5VJPbGY= X-Gm-Gg: ASbGncvTR9Fa5KZqBMLoAToUrRMjHRK6gYIHAy/rcVNDHP8volraeUqDcRBPYW+RujA pjrjyHMmUxAkB+kdbMYOTA6Mgm+Dc8YVWkMVCociel5m1bQNQInzZ9gYXte4y/+U+wR7KMF/Ew4 Pp3fUK8wo4S2HFDcefLCs8WtgA1bmrx0CoenM5rurBiA3vBugddyHfVMf9/WSCacqi6LKB5DbG8 DfVnt/ysbdjWPld8cc2Hdka4aie7Fw6LAQsAl3YFSePianqOQPMivnCDO/Tn2qskrJ7gKBaSrWF ni/Rk75rEJ0IYxPOa2EZ5h/G2KkaL9Q1swGRPn8SCDYgBNlNmNHS9fdQYQjlrsZ7h0Cybnp3T5G UEp8= X-Google-Smtp-Source: AGHT+IHm6bZzRXmeABRwy/G5p7vy/KaN9wuIGKtA/dz7LR+i0K/fWZnNXX5BokaCfbMv/B97mbG9kA== X-Received: by 2002:a17:903:19c6:b0:24c:ed95:2725 with SMTP id d9443c01a7336-2516e97ecbfmr104227365ad.4.1757355585343; Mon, 08 Sep 2025 11:19:45 -0700 (PDT) Received: from cleger.eu.int ([2001:41d0:420:f300::]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-24ccd763948sm117012755ad.118.2025.09.08.11.19.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 08 Sep 2025 11:19:44 -0700 (PDT) From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= To: Paul Walmsley , Palmer Dabbelt , linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Himanshu Chauhan , Anup Patel , Xu Lu , Atish Patra , =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= , Yunhui Cui Subject: [PATCH v7 5/5] selftests/riscv: add SSE test module Date: Mon, 8 Sep 2025 18:17:07 +0000 Message-ID: <20250908181717.1997461-6-cleger@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250908181717.1997461-1-cleger@rivosinc.com> References: <20250908181717.1997461-1-cleger@rivosinc.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable This module, once loaded, will execute a series of tests using the SSE framework. The provided script will check for any error reported by the test module. Signed-off-by: Cl=C3=A9ment L=C3=A9ger --- tools/testing/selftests/riscv/Makefile | 2 +- tools/testing/selftests/riscv/sse/Makefile | 5 + .../selftests/riscv/sse/module/Makefile | 16 + .../riscv/sse/module/riscv_sse_test.c | 513 ++++++++++++++++++ .../selftests/riscv/sse/run_sse_test.sh | 44 ++ 5 files changed, 579 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/riscv/sse/Makefile create mode 100644 tools/testing/selftests/riscv/sse/module/Makefile create mode 100644 tools/testing/selftests/riscv/sse/module/riscv_sse_test= .c create mode 100644 tools/testing/selftests/riscv/sse/run_sse_test.sh diff --git a/tools/testing/selftests/riscv/Makefile b/tools/testing/selftes= ts/riscv/Makefile index 099b8c1f46f8..c62f58414b29 100644 --- a/tools/testing/selftests/riscv/Makefile +++ b/tools/testing/selftests/riscv/Makefile @@ -5,7 +5,7 @@ ARCH ?=3D $(shell uname -m 2>/dev/null || echo not) =20 ifneq (,$(filter $(ARCH),riscv)) -RISCV_SUBTARGETS ?=3D abi hwprobe mm sigreturn vector +RISCV_SUBTARGETS ?=3D abi hwprobe mm sigreturn vector sse else RISCV_SUBTARGETS :=3D endif diff --git a/tools/testing/selftests/riscv/sse/Makefile b/tools/testing/sel= ftests/riscv/sse/Makefile new file mode 100644 index 000000000000..67eaee06f213 --- /dev/null +++ b/tools/testing/selftests/riscv/sse/Makefile @@ -0,0 +1,5 @@ +TEST_GEN_MODS_DIR :=3D module + +TEST_FILES :=3D run_sse_test.sh + +include ../../lib.mk diff --git a/tools/testing/selftests/riscv/sse/module/Makefile b/tools/test= ing/selftests/riscv/sse/module/Makefile new file mode 100644 index 000000000000..02018f083456 --- /dev/null +++ b/tools/testing/selftests/riscv/sse/module/Makefile @@ -0,0 +1,16 @@ +TESTMODS_DIR :=3D $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST)))= )) +KDIR ?=3D /lib/modules/$(shell uname -r)/build + +obj-m +=3D riscv_sse_test.o + +# Ensure that KDIR exists, otherwise skip the compilation +modules: +ifneq ("$(wildcard $(KDIR))", "") + $(Q)$(MAKE) -C $(KDIR) modules KBUILD_EXTMOD=3D$(TESTMODS_DIR) +endif + +# Ensure that KDIR exists, otherwise skip the clean target +clean: +ifneq ("$(wildcard $(KDIR))", "") + $(Q)$(MAKE) -C $(KDIR) clean KBUILD_EXTMOD=3D$(TESTMODS_DIR) +endif diff --git a/tools/testing/selftests/riscv/sse/module/riscv_sse_test.c b/to= ols/testing/selftests/riscv/sse/module/riscv_sse_test.c new file mode 100644 index 000000000000..e49a2f1179f6 --- /dev/null +++ b/tools/testing/selftests/riscv/sse/module/riscv_sse_test.c @@ -0,0 +1,513 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 Rivos Inc. + */ + +#define pr_fmt(fmt) "riscv_sse_test: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define RUN_LOOP_COUNT 1000 +#define SSE_FAILED_PREFIX "FAILED: " +#define sse_err(...) pr_err(SSE_FAILED_PREFIX __VA_ARGS__) + +struct sse_event_desc { + u32 evt_id; + const char *name; + bool can_inject; +}; + +static struct sse_event_desc sse_event_descs[] =3D { + { + .evt_id =3D SBI_SSE_EVENT_LOCAL_HIGH_PRIO_RAS, + .name =3D "local_high_prio_ras", + }, + { + .evt_id =3D SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP, + .name =3D "local_double_trap", + }, + { + .evt_id =3D SBI_SSE_EVENT_GLOBAL_HIGH_PRIO_RAS, + .name =3D "global_high_prio_ras", + }, + { + .evt_id =3D SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW, + .name =3D "local_pmu_overflow", + }, + { + .evt_id =3D SBI_SSE_EVENT_LOCAL_LOW_PRIO_RAS, + .name =3D "local_low_prio_ras", + }, + { + .evt_id =3D SBI_SSE_EVENT_GLOBAL_LOW_PRIO_RAS, + .name =3D "global_low_prio_ras", + }, + { + .evt_id =3D SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED, + .name =3D "local_software_injected", + }, + { + .evt_id =3D SBI_SSE_EVENT_GLOBAL_SOFTWARE_INJECTED, + .name =3D "global_software_injected", + } +}; + +static struct sse_event_desc *sse_get_evt_desc(u32 evt) +{ + int i; + + for (i =3D 0; i < ARRAY_SIZE(sse_event_descs); i++) { + if (sse_event_descs[i].evt_id =3D=3D evt) + return &sse_event_descs[i]; + } + + return NULL; +} + +static const char *sse_evt_name(u32 evt) +{ + struct sse_event_desc *desc =3D sse_get_evt_desc(evt); + + return desc !=3D NULL ? desc->name : NULL; +} + +static bool sse_test_can_inject_event(u32 evt) +{ + struct sse_event_desc *desc =3D sse_get_evt_desc(evt); + + return desc !=3D NULL ? desc->can_inject : false; +} + +static struct sbiret sbi_sse_ecall(int fid, unsigned long arg0, unsigned l= ong arg1) +{ + return sbi_ecall(SBI_EXT_SSE, fid, arg0, arg1, 0, 0, 0, 0); +} + +static int sse_event_attr_get(u32 evt, unsigned long attr_id, + unsigned long *val) +{ + struct sbiret sret; + unsigned long *attr_buf, phys; + + attr_buf =3D kmalloc(sizeof(unsigned long), GFP_KERNEL); + if (!attr_buf) + return -ENOMEM; + + phys =3D virt_to_phys(attr_buf); + + sret =3D sbi_ecall(SBI_EXT_SSE, SBI_SSE_EVENT_ATTR_READ, evt, attr_id, 1, + phys, 0, 0); + if (sret.error) + return sbi_err_map_linux_errno(sret.error); + + *val =3D *attr_buf; + + return 0; +} + +static int sse_test_signal(u32 evt, unsigned int cpu) +{ + unsigned int hart_id =3D cpuid_to_hartid_map(cpu); + struct sbiret ret; + + ret =3D sbi_sse_ecall(SBI_SSE_EVENT_INJECT, evt, hart_id); + if (ret.error) { + sse_err("Failed to signal event %x, error %ld\n", evt, ret.error); + return sbi_err_map_linux_errno(ret.error); + } + + return 0; +} + +static int sse_test_inject_event(struct sse_event *event, u32 evt, unsigne= d int cpu) +{ + int res; + unsigned long status; + + if (sse_event_is_global(evt)) { + /* + * Due to the fact the completion might happen faster than + * the call to SBI_SSE_COMPLETE in the handler, if the event was + * running on another CPU, we need to wait for the event status + * to be !RUNNING. + */ + do { + res =3D sse_event_attr_get(evt, SBI_SSE_ATTR_STATUS, &status); + if (res) { + sse_err("Failed to get status for evt %x, error %d\n", evt, res); + return res; + } + status =3D status & SBI_SSE_ATTR_STATUS_STATE_MASK; + } while (status =3D=3D SBI_SSE_STATE_RUNNING); + + res =3D sse_event_set_target_cpu(event, cpu); + if (res) { + sse_err("Failed to set cpu for evt %x, error %d\n", evt, res); + return res; + } + } + + return sse_test_signal(evt, cpu); +} + +struct fast_test_arg { + u32 evt; + int cpu; + bool completion; +}; + +static int sse_test_handler(u32 evt, void *arg, struct pt_regs *regs) +{ + int ret =3D 0; + struct fast_test_arg *targ =3D arg; + u32 test_evt =3D READ_ONCE(targ->evt); + int cpu =3D READ_ONCE(targ->cpu); + + if (evt !=3D test_evt) { + sse_err("Received SSE event id %x instead of %x\n", test_evt, evt); + ret =3D -EINVAL; + } + + if (cpu !=3D smp_processor_id()) { + sse_err("Received SSE event %d on CPU %d instead of %d\n", evt, smp_proc= essor_id(), + cpu); + ret =3D -EINVAL; + } + + WRITE_ONCE(targ->completion, true); + + return ret; +} + +static void sse_run_fast_test(struct fast_test_arg *test_arg, struct sse_e= vent *event, u32 evt) +{ + unsigned long timeout; + int ret, cpu; + + for_each_online_cpu(cpu) { + WRITE_ONCE(test_arg->completion, false); + WRITE_ONCE(test_arg->cpu, cpu); + /* Test arg is used on another CPU */ + smp_wmb(); + + ret =3D sse_test_inject_event(event, evt, cpu); + if (ret) { + sse_err("event %s injection failed, err %d\n", sse_evt_name(evt), ret); + return; + } + + timeout =3D jiffies + HZ / 100; + /* We can not use since they are not NMI safe */ + while (!READ_ONCE(test_arg->completion) && + time_before(jiffies, timeout)) { + cpu_relax(); + } + if (!time_before(jiffies, timeout)) { + sse_err("Failed to wait for event %s completion on CPU %d\n", + sse_evt_name(evt), cpu); + return; + } + } +} + +static void sse_test_injection_fast(void) +{ + int i, ret =3D 0, j; + u32 evt; + struct fast_test_arg test_arg; + struct sse_event *event; + + pr_info("Starting SSE test (fast)\n"); + + for (i =3D 0; i < ARRAY_SIZE(sse_event_descs); i++) { + evt =3D sse_event_descs[i].evt_id; + WRITE_ONCE(test_arg.evt, evt); + + if (!sse_event_descs[i].can_inject) + continue; + + event =3D sse_event_register(evt, 0, sse_test_handler, + (void *)&test_arg); + if (IS_ERR(event)) { + sse_err("Failed to register event %s, err %ld\n", sse_evt_name(evt), + PTR_ERR(event)); + goto out; + } + + ret =3D sse_event_enable(event); + if (ret) { + sse_err("Failed to enable event %s, err %d\n", sse_evt_name(evt), ret); + goto err_unregister; + } + + pr_info("Starting testing event %s\n", sse_evt_name(evt)); + + for (j =3D 0; j < RUN_LOOP_COUNT; j++) + sse_run_fast_test(&test_arg, event, evt); + + pr_info("Finished testing event %s\n", sse_evt_name(evt)); + + sse_event_disable(event); +err_unregister: + sse_event_unregister(event); + } +out: + pr_info("Finished SSE test (fast)\n"); +} + +struct priority_test_arg { + unsigned long evt; + struct sse_event *event; + bool called; + u32 prio; + struct priority_test_arg *next_evt_arg; + void (*check_func)(struct priority_test_arg *arg); +}; + +static int sse_hi_priority_test_handler(u32 evt, void *arg, + struct pt_regs *regs) +{ + struct priority_test_arg *targ =3D arg; + struct priority_test_arg *next =3D READ_ONCE(targ->next_evt_arg); + + WRITE_ONCE(targ->called, 1); + + if (next) { + sse_test_signal(next->evt, smp_processor_id()); + if (!READ_ONCE(next->called)) { + sse_err("Higher priority event %s was not handled %s\n", + sse_evt_name(next->evt), sse_evt_name(evt)); + } + } + + return 0; +} + +static int sse_low_priority_test_handler(u32 evt, void *arg, struct pt_reg= s *regs) +{ + struct priority_test_arg *targ =3D arg; + struct priority_test_arg *next =3D READ_ONCE(targ->next_evt_arg); + + WRITE_ONCE(targ->called, 1); + + if (next) { + sse_test_signal(next->evt, smp_processor_id()); + if (READ_ONCE(next->called)) { + sse_err("Lower priority event %s was handle before %s\n", + sse_evt_name(next->evt), sse_evt_name(evt)); + } + } + + return 0; +} + +static void sse_test_injection_priority_arg(struct priority_test_arg *args= , unsigned int args_size, + sse_event_handler_fn handler, const char *test_name) +{ + unsigned int i; + int ret; + struct sse_event *event; + struct priority_test_arg *arg, *first_arg =3D NULL, *prev_arg =3D NULL; + + pr_info("Starting SSE priority test (%s)\n", test_name); + for (i =3D 0; i < args_size; i++) { + arg =3D &args[i]; + + if (!sse_test_can_inject_event(arg->evt)) + continue; + + WRITE_ONCE(arg->called, false); + WRITE_ONCE(arg->next_evt_arg, NULL); + if (prev_arg) + WRITE_ONCE(prev_arg->next_evt_arg, arg); + + prev_arg =3D arg; + + if (!first_arg) + first_arg =3D arg; + + event =3D sse_event_register(arg->evt, arg->prio, handler, (void *)arg); + if (IS_ERR(event)) { + sse_err("Failed to register event %s, err %ld\n", sse_evt_name(arg->evt= ), + PTR_ERR(event)); + goto release_events; + } + arg->event =3D event; + + if (sse_event_is_global(arg->evt)) { + /* Target event at current CPU */ + ret =3D sse_event_set_target_cpu(event, smp_processor_id()); + if (ret) { + sse_err("Failed to set event %s target CPU, err %d\n", + sse_evt_name(arg->evt), ret); + goto release_events; + } + } + + ret =3D sse_event_enable(event); + if (ret) { + sse_err("Failed to enable event %s, err %d\n", sse_evt_name(arg->evt), = ret); + goto release_events; + } + } + + if (!first_arg) { + sse_err("No injectable event available\n"); + return; + } + + /* Inject first event, handler should trigger the others in chain. */ + ret =3D sse_test_inject_event(first_arg->event, first_arg->evt, smp_proce= ssor_id()); + if (ret) { + sse_err("SSE event %s injection failed\n", sse_evt_name(first_arg->evt)); + goto release_events; + } + + /* + * Event are injected directly on the current CPU after calling sse_test_= inject_event() + * so that execution is premmpted right away, no need to wait for timeout. + */ + arg =3D first_arg; + while (arg) { + if (!READ_ONCE(arg->called)) { + sse_err("Event %s handler was not called\n", + sse_evt_name(arg->evt)); + ret =3D -EINVAL; + } + + + event =3D arg->event; + arg =3D READ_ONCE(arg->next_evt_arg); + } + +release_events: + + arg =3D first_arg; + while (arg) { + event =3D arg->event; + if (!event) + break; + + sse_event_disable(event); + sse_event_unregister(event); + arg =3D READ_ONCE(arg->next_evt_arg); + } + + pr_info("Finished SSE priority test (%s)\n", test_name); +} + +static void sse_test_injection_priority(void) +{ + struct priority_test_arg default_hi_prio_args[] =3D { + { .evt =3D SBI_SSE_EVENT_GLOBAL_SOFTWARE_INJECTED }, + { .evt =3D SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED }, + { .evt =3D SBI_SSE_EVENT_GLOBAL_LOW_PRIO_RAS }, + { .evt =3D SBI_SSE_EVENT_LOCAL_LOW_PRIO_RAS }, + { .evt =3D SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW }, + { .evt =3D SBI_SSE_EVENT_GLOBAL_HIGH_PRIO_RAS }, + { .evt =3D SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP }, + { .evt =3D SBI_SSE_EVENT_LOCAL_HIGH_PRIO_RAS }, + }; + + struct priority_test_arg default_low_prio_args[] =3D { + { .evt =3D SBI_SSE_EVENT_LOCAL_HIGH_PRIO_RAS }, + { .evt =3D SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP }, + { .evt =3D SBI_SSE_EVENT_GLOBAL_HIGH_PRIO_RAS }, + { .evt =3D SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW }, + { .evt =3D SBI_SSE_EVENT_LOCAL_LOW_PRIO_RAS }, + { .evt =3D SBI_SSE_EVENT_GLOBAL_LOW_PRIO_RAS }, + { .evt =3D SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED }, + { .evt =3D SBI_SSE_EVENT_GLOBAL_SOFTWARE_INJECTED }, + + }; + struct priority_test_arg set_prio_args[] =3D { + { .evt =3D SBI_SSE_EVENT_GLOBAL_SOFTWARE_INJECTED, .prio =3D 5 }, + { .evt =3D SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED, .prio =3D 10 }, + { .evt =3D SBI_SSE_EVENT_GLOBAL_LOW_PRIO_RAS, .prio =3D 15 }, + { .evt =3D SBI_SSE_EVENT_LOCAL_LOW_PRIO_RAS, .prio =3D 20 }, + { .evt =3D SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW, .prio =3D 25 }, + { .evt =3D SBI_SSE_EVENT_GLOBAL_HIGH_PRIO_RAS, .prio =3D 30 }, + { .evt =3D SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP, .prio =3D 35 }, + { .evt =3D SBI_SSE_EVENT_LOCAL_HIGH_PRIO_RAS, .prio =3D 40 }, + }; + + struct priority_test_arg same_prio_args[] =3D { + { .evt =3D SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW, .prio =3D 0 }, + { .evt =3D SBI_SSE_EVENT_LOCAL_HIGH_PRIO_RAS, .prio =3D 10 }, + { .evt =3D SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED, .prio =3D 10 }, + { .evt =3D SBI_SSE_EVENT_GLOBAL_SOFTWARE_INJECTED, .prio =3D 10 }, + { .evt =3D SBI_SSE_EVENT_GLOBAL_HIGH_PRIO_RAS, .prio =3D 20 }, + }; + + sse_test_injection_priority_arg(default_hi_prio_args, ARRAY_SIZE(default_= hi_prio_args), + sse_hi_priority_test_handler, "high"); + + sse_test_injection_priority_arg(default_low_prio_args, ARRAY_SIZE(default= _low_prio_args), + sse_low_priority_test_handler, "low"); + + sse_test_injection_priority_arg(set_prio_args, ARRAY_SIZE(set_prio_args), + sse_low_priority_test_handler, "set"); + + sse_test_injection_priority_arg(same_prio_args, ARRAY_SIZE(same_prio_args= ), + sse_low_priority_test_handler, "same_prio_args"); +} + + +static bool sse_get_inject_status(u32 evt) +{ + int ret; + unsigned long val; + + /* Check if injection is supported */ + ret =3D sse_event_attr_get(evt, SBI_SSE_ATTR_STATUS, &val); + if (ret) + return false; + + return !!(val & BIT(SBI_SSE_ATTR_STATUS_INJECT_OFFSET)); +} + +static void sse_init_events(void) +{ + int i; + + for (i =3D 0; i < ARRAY_SIZE(sse_event_descs); i++) { + struct sse_event_desc *desc =3D &sse_event_descs[i]; + + desc->can_inject =3D sse_get_inject_status(desc->evt_id); + if (!desc->can_inject) + pr_info("Can not inject event %s, tests using this event will be skippe= d\n", + desc->name); + } +} + +static int __init sse_test_init(void) +{ + sse_init_events(); + + sse_test_injection_fast(); + sse_test_injection_priority(); + + return 0; +} + +static void __exit sse_test_exit(void) +{ +} + +module_init(sse_test_init); +module_exit(sse_test_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Cl=C3=A9ment L=C3=A9ger "); +MODULE_DESCRIPTION("Test module for SSE"); diff --git a/tools/testing/selftests/riscv/sse/run_sse_test.sh b/tools/test= ing/selftests/riscv/sse/run_sse_test.sh new file mode 100644 index 000000000000..888bc4a99cb3 --- /dev/null +++ b/tools/testing/selftests/riscv/sse/run_sse_test.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2025 Rivos Inc. + +MODULE_NAME=3Driscv_sse_test +DRIVER=3D"./module/${MODULE_NAME}.ko" + +check_test_failed_prefix() { + if dmesg | grep -q "${MODULE_NAME}: FAILED:";then + echo "${MODULE_NAME} failed, please check dmesg" + exit 1 + fi +} + +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=3D4 + +check_test_requirements() +{ + uid=3D$(id -u) + if [ $uid -ne 0 ]; then + echo "$0: Must be run as root" + exit $ksft_skip + fi + + if ! which insmod > /dev/null 2>&1; then + echo "$0: You need insmod installed" + exit $ksft_skip + fi + + if [ ! -f $DRIVER ]; then + echo "$0: You need to compile ${MODULE_NAME} module" + exit $ksft_skip + fi +} + +check_test_requirements + +insmod $DRIVER > /dev/null 2>&1 +rmmod $MODULE_NAME +check_test_failed_prefix + +exit 0 --=20 2.43.0