From nobody Fri Dec 19 20:38:05 2025 Received: from mail-pf1-f173.google.com (mail-pf1-f173.google.com [209.85.210.173]) (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 94BE7323D for ; Fri, 16 May 2025 15:24:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747409059; cv=none; b=n2KsrkzuH3Wy57UEDTg42X9A/SmP0KWlz5tSxYqM2rgA8/I5P1bPBC1o04cNQfhkbx6Qp81U6MlvEGAz3g1R9XHqHFFi5SYQW0lxsvBFD7iZc2WxsPWa5OENznT3m98NvSWHo8VNpiDb0Na+ZclKxRuCQ8mKcPZ6cKtkepZkQSg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747409059; c=relaxed/simple; bh=FB6kVvhTv6uVDZaLO09UQB/X+Twn6n90Vjpy1GeRUkQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=r33xovuhF4uh6EDhG8MQpuDlIqrRu5FngPYlS75UJmiIzQaw1Ab33KutafvoGbmZDba6Rzu4c7Q6F2CGzbVS7nmSQMtM/apjpTbSF3xIEGTa7FtNe3PACQxqXJ2KKPy85RicYkwgEI6gPiDyZfOqVyq2jyHbv5Ttuaemh5YnJ3s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com; spf=pass smtp.mailfrom=rivosinc.com; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b=bRrEQlO+; arc=none smtp.client-ip=209.85.210.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (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.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b="bRrEQlO+" Received: by mail-pf1-f173.google.com with SMTP id d2e1a72fcca58-74248a3359fso2451153b3a.2 for ; Fri, 16 May 2025 08:24:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20230601.gappssmtp.com; s=20230601; t=1747409057; x=1748013857; 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=UKbGApiEtkT8/WDx/Modbo6eDPhoN4O6DcMv04ORqek=; b=bRrEQlO+dnEYER0T5uazDOLxlQizfDY0lIYJfWFAHvh67bQd1zptOkI114bYq9a2/M idLm+aQQnSs4jBmKQ3HQJo0XMyDxQOfejxxO7gaAok0A484jai9asyMYkykgyZXbAQI9 pbJ4Tu8J+CVZkW4a/85ULoHst1K2VMn7/qpgXdkqYNrhnbf/4cyUbF50xlYyK9cdEsQ2 9uW4R2HGY5nJZhcYtY7cTCvz47i0wPRHm3bvZMV2xSogfn7wAHNR2tHs6q0e5H8Rlbr1 DlVoY/jS+mf7abAwr/UkDJe/FdHGpx9Iq35r9EcNP3swJiRLN0pfkAfygWcpogh1KNSJ ++EA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1747409057; x=1748013857; 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=UKbGApiEtkT8/WDx/Modbo6eDPhoN4O6DcMv04ORqek=; b=iXAFqCKoqFTSEeotqKPFb/3DIk0ZgMlGle0XXnBsUqtz86oUqbcZnpnkQGC1wTEaFy c9l7uMjV/bTZbQXsPjKJ3ZRg6M+tGTO3uqiwoIY+xOtfi6BkXKU6N5Ra5Wf6Hi6RVs/F vlQJkgViVupzWIZw59tVM4Syza7tFgTalxtngrKrMRsatJ22UeXmkVUYGhmGcO+SHH5A s7456LjjJKGrRDHAqLjvHx3tk+iMFCoKMi9S0bpebwskU2i05VJ1xypWEu0fcBYAImya OXVhXHNVt6pDi35oxhwOuebi02fZJQwrl+atRpJUsnVDCxIm/vFMrJM/lp6YIjed/x6U LCvQ== X-Forwarded-Encrypted: i=1; AJvYcCX5TTaKzMhyLaRV7NkoBsZThV8bY6OH4EKBa10zQZSeNj0eyhJ33A+IUZHp6a/+nEIgzkuNCANW9oSlZD4=@vger.kernel.org X-Gm-Message-State: AOJu0YyGL1/xLHglTAoaHQdVBVjIKZJONPuE2erC7varOrdq/AFUYQI9 5hxFLfrJYPhqwOmHV8QRCJ+tCN2OXdzHQSTECUh1z+g1R9YiPtaD0dayOQ5T7e1WgfY= X-Gm-Gg: ASbGncvfGjQuEVBXepHUOOk6XquKHKI3CzgF9eT52cHHfZbFCoa7+vXSnxVzmV0yVwz HNBTgnhcVUSR4otfMmeFZza9J2Y04uEEzp3l8w/NJKH40s1k62rhwpNjgsNkwbK11tVPpc9g3BI MQuLYsRiKUN3fo57ZPK1/XBp4fdtxo76/m5Bp5EGrJQu0yTJezdXdPi+JRdxcoSkQ+/RKpBMJSG liJsq958wVI6wQT9me0CBYfM+89SQXciVtpPWDnNgJ+TYLWPwFrsXQnQCgwX99D/D/RPtBv6w85 wN2Hi+8wPvGTd9CoT0+7ldTZR2m2N5oNlVoioKf70bsH3Pzsygf7mh/+vWkt4RY= X-Google-Smtp-Source: AGHT+IEPys89YDQJYKU3/9Q96sLuGwipd4FD9peTZgU8hGsM8WzNmpqONcesktg1K7D9UT/m6i5B0Q== X-Received: by 2002:a05:6a20:12ca:b0:1f3:418c:6281 with SMTP id adf61e73a8af0-21621875ab8mr5817835637.4.1747409056778; Fri, 16 May 2025 08:24:16 -0700 (PDT) Received: from carbon-x1.. ([2a01:e0a:e17:9700:16d2:7456:6634:9626]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-742a96def68sm1666997b3a.30.2025.05.16.08.24.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 16 May 2025 08:24:16 -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 Subject: [PATCH v4 1/4] riscv: add SBI SSE extension definitions Date: Fri, 16 May 2025 17:23:39 +0200 Message-ID: <20250516152355.560448-2-cleger@rivosinc.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250516152355.560448-1-cleger@rivosinc.com> References: <20250516152355.560448-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 Add needed definitions for SBI Supervisor Software Events extension [1]. This extension enables the SBI to inject events into supervisor software much like ARM SDEI. [1] https://lists.riscv.org/g/tech-prs/message/515 Signed-off-by: Cl=C3=A9ment L=C3=A9ger Reviewed-by: Bj=C3=B6rn T=C3=B6pel --- arch/riscv/include/asm/sbi.h | 65 ++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 3d250824178b..4d7f81c620ef 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -35,6 +35,7 @@ enum sbi_ext_id { SBI_EXT_DBCN =3D 0x4442434E, SBI_EXT_STA =3D 0x535441, SBI_EXT_NACL =3D 0x4E41434C, + SBI_EXT_SSE =3D 0x535345, =20 /* Experimentals extensions must lie within this range */ SBI_EXT_EXPERIMENTAL_START =3D 0x08000000, @@ -402,6 +403,66 @@ enum sbi_ext_nacl_feature { #define SBI_NACL_SHMEM_SRET_X(__i) ((__riscv_xlen / 8) * (__i)) #define SBI_NACL_SHMEM_SRET_X_LAST 31 =20 +enum sbi_ext_sse_fid { + SBI_SSE_EVENT_ATTR_READ =3D 0, + SBI_SSE_EVENT_ATTR_WRITE, + SBI_SSE_EVENT_REGISTER, + SBI_SSE_EVENT_UNREGISTER, + SBI_SSE_EVENT_ENABLE, + SBI_SSE_EVENT_DISABLE, + SBI_SSE_EVENT_COMPLETE, + SBI_SSE_EVENT_SIGNAL, + SBI_SSE_EVENT_HART_UNMASK, + SBI_SSE_EVENT_HART_MASK, +}; + +enum sbi_sse_state { + SBI_SSE_STATE_UNUSED =3D 0, + SBI_SSE_STATE_REGISTERED =3D 1, + SBI_SSE_STATE_ENABLED =3D 2, + SBI_SSE_STATE_RUNNING =3D 3, +}; + +/* SBI SSE Event Attributes. */ +enum sbi_sse_attr_id { + SBI_SSE_ATTR_STATUS =3D 0x00000000, + SBI_SSE_ATTR_PRIO =3D 0x00000001, + SBI_SSE_ATTR_CONFIG =3D 0x00000002, + SBI_SSE_ATTR_PREFERRED_HART =3D 0x00000003, + SBI_SSE_ATTR_ENTRY_PC =3D 0x00000004, + SBI_SSE_ATTR_ENTRY_ARG =3D 0x00000005, + SBI_SSE_ATTR_INTERRUPTED_SEPC =3D 0x00000006, + SBI_SSE_ATTR_INTERRUPTED_FLAGS =3D 0x00000007, + SBI_SSE_ATTR_INTERRUPTED_A6 =3D 0x00000008, + SBI_SSE_ATTR_INTERRUPTED_A7 =3D 0x00000009, + + SBI_SSE_ATTR_MAX =3D 0x0000000A +}; + +#define SBI_SSE_ATTR_STATUS_STATE_OFFSET 0 +#define SBI_SSE_ATTR_STATUS_STATE_MASK 0x3 +#define SBI_SSE_ATTR_STATUS_PENDING_OFFSET 2 +#define SBI_SSE_ATTR_STATUS_INJECT_OFFSET 3 + +#define SBI_SSE_ATTR_CONFIG_ONESHOT (1 << 0) + +#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPP (1 << 0) +#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPIE (1 << 1) +#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_HSTATUS_SPV (1 << 2) +#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_HSTATUS_SPVP (1 << 3) + +#define SBI_SSE_EVENT_LOCAL_HIGH_PRIO_RAS 0x00000000 +#define SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP 0x00000001 +#define SBI_SSE_EVENT_GLOBAL_HIGH_PRIO_RAS 0x00008000 +#define SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW 0x00010000 +#define SBI_SSE_EVENT_LOCAL_LOW_PRIO_RAS 0x00100000 +#define SBI_SSE_EVENT_GLOBAL_LOW_PRIO_RAS 0x00108000 +#define SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED 0xffff0000 +#define SBI_SSE_EVENT_GLOBAL_SOFTWARE_INJECTED 0xffff8000 + +#define SBI_SSE_EVENT_PLATFORM (1 << 14) +#define SBI_SSE_EVENT_GLOBAL (1 << 15) + /* SBI spec version fields */ #define SBI_SPEC_VERSION_DEFAULT 0x1 #define SBI_SPEC_VERSION_MAJOR_SHIFT 24 @@ -419,6 +480,8 @@ enum sbi_ext_nacl_feature { #define SBI_ERR_ALREADY_STARTED -7 #define SBI_ERR_ALREADY_STOPPED -8 #define SBI_ERR_NO_SHMEM -9 +#define SBI_ERR_INVALID_STATE -10 +#define SBI_ERR_BAD_RANGE -11 =20 extern unsigned long sbi_spec_version; struct sbiret { @@ -505,6 +568,8 @@ static inline int sbi_err_map_linux_errno(int err) case SBI_ERR_DENIED: return -EPERM; case SBI_ERR_INVALID_PARAM: + case SBI_ERR_BAD_RANGE: + case SBI_ERR_INVALID_STATE: return -EINVAL; case SBI_ERR_INVALID_ADDRESS: return -EFAULT; --=20 2.49.0 From nobody Fri Dec 19 20:38:05 2025 Received: from mail-pf1-f171.google.com (mail-pf1-f171.google.com [209.85.210.171]) (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 903F71C4A10 for ; Fri, 16 May 2025 15:24:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747409066; cv=none; b=gt5D8gnYR9cItVGntTLpFWvRXPeSx6zue9OdslyPpjfFOcFWTBHk6jd0LNxeCbG1nID+/bUxDgOuSnfopCSxEN2jyF5GC/0XqI3yi8pHEkMK1MXBDJmRoIRmbSnMQxe33cmCY/mRSLpHnYkW8kVTuB3ILSY7SXUDVpLmbuMZ8jA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747409066; c=relaxed/simple; bh=2B0+JzLYm9fvjH/0cEPRQY9rd6yICnn91stKCe+aupk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=FIMETTOWlFq5BMPBhPbtqEwCKIrtFvmDEf2tR89DUr0GPFECUpnvFhkq6hP1qN7qetlHMcvzEJ20guojCrymyG4vawgJ0Axkr0sNJAw8YScKA5yzK9lb3IY4+OH0Ssa3XJrJg9aGA31IIgJtZYbk9woSI/Fevt/KscLOCrx3Pok= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com; spf=pass smtp.mailfrom=rivosinc.com; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b=FRFNnBx6; arc=none smtp.client-ip=209.85.210.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (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.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b="FRFNnBx6" Received: by mail-pf1-f171.google.com with SMTP id d2e1a72fcca58-73972a54919so2410854b3a.3 for ; Fri, 16 May 2025 08:24:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20230601.gappssmtp.com; s=20230601; t=1747409064; x=1748013864; 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=pQx9aF4xXrdsoYYoj3PPFjH3qE9ocs8Li8zlWuJn3s8=; b=FRFNnBx6hi5mol3CD5kLM2mG1QMAZiHOgdAYRIxl/XrH6bPgbsxvf54K9meR6rtao3 o2DF0DmdFJkNfT/A+OOHUBlyBVHOmexhrox1JdZZniLB7M6mygvlboAPbtUjbZcpC5a0 JCYtE0WxvadkoIcDVTQL9I7oN8VEZUNOOBagYgdAsv1w+4jPUL3uqxT00oHb1xDIIVF3 450LBWD6SHjVEgdnMD3rhw9g0LxDnni++1dK/jOlOlxpnrg14b6D5svLvxmNptRq2Tzv dryKb00P0EDcU2esxFgaay7ou4kr2StVnsvEBFDw8Tmy6Pq5OyhlyYMU6S0k5JU5J21s oI8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1747409064; x=1748013864; 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=pQx9aF4xXrdsoYYoj3PPFjH3qE9ocs8Li8zlWuJn3s8=; b=ayZF5de5ih6J+thHMLKbaQhcSisoevmnCXsxRMSRf2SvoK+xrWIuY28sY/v4OHn5e2 +Qsi1M2i4LaxnUpjld9bkYHZdSFC0chDAU+cchP+AByo+S5Up06q0dYKp9AWxKZoBnkL 1JOhklIs02K82N8SnupPVaLuq1svozmceZjY9wxsjRkfjySwU7CZQhf0LOzovcCJS7FY UzynfswPRY9o6lmjKlU6VTUD5jdyTfjuio5Y6HeI36CUbnMoufLKehRQGHqEM2w4CxpR w2Bg9AqcE6eBfJPASTHEUBe2AhHyo0tG3evTpF3qjp5Ow33h95v6d+ycgn5h6TM/FRiV F+xA== X-Forwarded-Encrypted: i=1; AJvYcCW3Yn+o4fmkndD+k4tWLlbUAY/009kaKYOJZ/ZC4YAoSbUJQFV3Hwc4ItE9riveUSdTiMCI5TgSLpYTvCg=@vger.kernel.org X-Gm-Message-State: AOJu0YwRwT9/TNnT8IAtX9I3RdrHrjjePK2X73DfbeQI1m1ro479zGcR sF0sQYeo/nVUWS+UtMXyMaPEYKQGuoQ+j7XX4INgAh+nKmzuhnVbUjDL6rthCjZwlaI= X-Gm-Gg: ASbGncsl0rBd02SntJuaJ2+L9jYdfg5a8X/pxNuLzr2vu9unJ27AYfQ30zlO3TA0GFc Klr4C6AD3GnYBGszUz3898TehUAoiSlS6w7UAAGQWAHTLWqnHNF3nplMYdKbIswkPu4B6lb2Fs8 uy/eTh24Ljt9LhY0IYj3DtNkg009TPe9MpiBGyddFrsj7hT7Z+FhWdH7R17qNqcpm+Oi8eNv8Wv 38zJ1gCbc/wxzAvDS/d2/xQj+8hnQAdmzDDhDsN//mkz6up9Y6Oe6JujwVZHadt3ohcC7vdLNqA qum4v5nWQ4zMwRaoDsAqeJ3VcXF0nZQRvmW62KtHdKVyOabpK/g5sdKjuDHH4tc= X-Google-Smtp-Source: AGHT+IEsWxjK1o59NnlqDzEwHB0njs/8JI0z4srHZbIdYyq6Ixyv1+6yV1PYKR0oiDbf4/e8CKi5OA== X-Received: by 2002:a05:6a21:8883:b0:217:feb5:631d with SMTP id adf61e73a8af0-217feb5636amr3176237637.26.1747409063710; Fri, 16 May 2025 08:24:23 -0700 (PDT) Received: from carbon-x1.. ([2a01:e0a:e17:9700:16d2:7456:6634:9626]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-742a96def68sm1666997b3a.30.2025.05.16.08.24.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 16 May 2025 08:24:23 -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 Subject: [PATCH v4 2/4] riscv: add support for SBI Supervisor Software Events extension Date: Fri, 16 May 2025 17:23:40 +0200 Message-ID: <20250516152355.560448-3-cleger@rivosinc.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250516152355.560448-1-cleger@rivosinc.com> References: <20250516152355.560448-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 The SBI SSE extension allows the supervisor software to be notified by the SBI of specific events that are not maskable. The context switch is handled partially by the firmware which will save registers a6 and a7. When entering kernel we can rely on these 2 registers to setup the stack and save all the registers. Since SSE events can be delivered at any time to the kernel (including during exception handling, we need a way to locate the current_task for context tracking. On RISC-V, it is sotred in scratch when in user space or tp when in kernel space (in which case SSCRATCH is zero). But at a at the beginning of exception handling, SSCRATCH is used to swap tp and check the origin of the exception. If interrupted at that point, then, there is no way to reliably know were is located the current task_struct. Even checking the interruption location won't work as SSE event can be nested on top of each other so the original interruption site might be lost at some point. In order to retrieve it reliably, store the current task in an additionnal __sse_entry_task per_cpu array. This array is then used to retrieve the current task based on the hart ID that is passed to the SSE event handler in a6. That being said, the way the current task struct is stored should probably be reworked to find a better reliable alternative. Since each events (and each CPU for local events) have their own context and can preempt each other, allocate a stack (and a shadow stack if needed for each of them (and for each cpu for local events). When completing the event, if we were coming from kernel with interrupts disabled, simply return there. If coming from userspace or kernel with interrupts enabled, simulate an interrupt exception by setting IE_SIE in CSR_IP to allow delivery of signals to user task. For instance this can happen, when a RAS event has been generated by a user application and a SIGBUS has been sent to a task. Signed-off-by: Cl=C3=A9ment L=C3=A9ger --- arch/riscv/include/asm/asm.h | 14 ++- arch/riscv/include/asm/scs.h | 7 ++ arch/riscv/include/asm/sse.h | 45 +++++++ arch/riscv/include/asm/switch_to.h | 14 +++ arch/riscv/include/asm/thread_info.h | 1 + arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/asm-offsets.c | 12 ++ arch/riscv/kernel/sse.c | 132 +++++++++++++++++++++ arch/riscv/kernel/sse_entry.S | 169 +++++++++++++++++++++++++++ 9 files changed, 392 insertions(+), 3 deletions(-) create mode 100644 arch/riscv/include/asm/sse.h create mode 100644 arch/riscv/kernel/sse.c create mode 100644 arch/riscv/kernel/sse_entry.S diff --git a/arch/riscv/include/asm/asm.h b/arch/riscv/include/asm/asm.h index a8a2af6dfe9d..982c4be9a9c3 100644 --- a/arch/riscv/include/asm/asm.h +++ b/arch/riscv/include/asm/asm.h @@ -90,16 +90,24 @@ #define PER_CPU_OFFSET_SHIFT 3 #endif =20 -.macro asm_per_cpu dst sym tmp - REG_L \tmp, TASK_TI_CPU_NUM(tp) - slli \tmp, \tmp, PER_CPU_OFFSET_SHIFT +.macro asm_per_cpu_with_cpu dst sym tmp cpu + slli \tmp, \cpu, PER_CPU_OFFSET_SHIFT la \dst, __per_cpu_offset add \dst, \dst, \tmp REG_L \tmp, 0(\dst) la \dst, \sym add \dst, \dst, \tmp .endm + +.macro asm_per_cpu dst sym tmp + REG_L \tmp, TASK_TI_CPU_NUM(tp) + asm_per_cpu_with_cpu \dst \sym \tmp \tmp +.endm #else /* CONFIG_SMP */ +.macro asm_per_cpu_with_cpu dst sym tmp cpu + la \dst, \sym +.endm + .macro asm_per_cpu dst sym tmp la \dst, \sym .endm diff --git a/arch/riscv/include/asm/scs.h b/arch/riscv/include/asm/scs.h index 0e45db78b24b..62344daad73d 100644 --- a/arch/riscv/include/asm/scs.h +++ b/arch/riscv/include/asm/scs.h @@ -18,6 +18,11 @@ load_per_cpu gp, irq_shadow_call_stack_ptr, \tmp .endm =20 +/* Load the per-CPU IRQ shadow call stack to gp. */ +.macro scs_load_sse_stack reg_evt + REG_L gp, SSE_REG_EVT_SHADOW_STACK(\reg_evt) +.endm + /* Load task_scs_sp(current) to gp. */ .macro scs_load_current REG_L gp, TASK_TI_SCS_SP(tp) @@ -41,6 +46,8 @@ .endm .macro scs_load_irq_stack tmp .endm +.macro scs_load_sse_stack reg_evt +.endm .macro scs_load_current .endm .macro scs_load_current_if_task_changed prev diff --git a/arch/riscv/include/asm/sse.h b/arch/riscv/include/asm/sse.h new file mode 100644 index 000000000000..aaddda77f5b6 --- /dev/null +++ b/arch/riscv/include/asm/sse.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 Rivos Inc. + */ +#ifndef __ASM_SSE_H +#define __ASM_SSE_H + +#include + +#ifdef CONFIG_RISCV_SSE + +struct sse_event_interrupted_state { + unsigned long a6; + unsigned long a7; +}; + +struct sse_event_arch_data { + void *stack; + void *shadow_stack; + unsigned long tmp; + struct sse_event_interrupted_state interrupted; + unsigned long interrupted_state_phys; + u32 evt_id; +}; + +static inline bool sse_event_is_global(u32 evt) +{ + return !!(evt & SBI_SSE_EVENT_GLOBAL); +} + +struct sse_registered_event; +int arch_sse_init_event(struct sse_event_arch_data *arch_evt, u32 evt_id, + int cpu); +void arch_sse_free_event(struct sse_event_arch_data *arch_evt); +int arch_sse_register_event(struct sse_event_arch_data *arch_evt); + +void sse_handle_event(struct sse_event_arch_data *arch_evt, + struct pt_regs *regs); +asmlinkage void handle_sse(void); +asmlinkage void do_sse(struct sse_event_arch_data *arch_evt, + struct pt_regs *reg); + +#endif + +#endif diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/sw= itch_to.h index 0e71eb82f920..cd1cead0c682 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -88,6 +88,19 @@ static inline void __switch_to_envcfg(struct task_struct= *next) :: "r" (next->thread.envcfg) : "memory"); } =20 +#ifdef CONFIG_RISCV_SSE +DECLARE_PER_CPU(struct task_struct *, __sse_entry_task); + +static inline void __switch_sse_entry_task(struct task_struct *next) +{ + __this_cpu_write(__sse_entry_task, next); +} +#else +static inline void __switch_sse_entry_task(struct task_struct *next) +{ +} +#endif + extern struct task_struct *__switch_to(struct task_struct *, struct task_struct *); =20 @@ -122,6 +135,7 @@ do { \ if (switch_to_should_flush_icache(__next)) \ local_flush_icache_all(); \ __switch_to_envcfg(__next); \ + __switch_sse_entry_task(__next); \ ((last) =3D __switch_to(__prev, __next)); \ } while (0) =20 diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/= thread_info.h index f5916a70879a..28e9805e61fc 100644 --- a/arch/riscv/include/asm/thread_info.h +++ b/arch/riscv/include/asm/thread_info.h @@ -36,6 +36,7 @@ #define OVERFLOW_STACK_SIZE SZ_4K =20 #define IRQ_STACK_SIZE THREAD_SIZE +#define SSE_STACK_SIZE THREAD_SIZE =20 #ifndef __ASSEMBLY__ =20 diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index f7480c9c6f8d..d347768d690d 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -99,6 +99,7 @@ obj-$(CONFIG_DYNAMIC_FTRACE) +=3D mcount-dyn.o obj-$(CONFIG_PERF_EVENTS) +=3D perf_callchain.o obj-$(CONFIG_HAVE_PERF_REGS) +=3D perf_regs.o obj-$(CONFIG_RISCV_SBI) +=3D sbi.o sbi_ecall.o +obj-$(CONFIG_RISCV_SSE) +=3D sse.o sse_entry.o ifeq ($(CONFIG_RISCV_SBI), y) obj-$(CONFIG_SMP) +=3D sbi-ipi.o obj-$(CONFIG_SMP) +=3D cpu_ops_sbi.o diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offset= s.c index 16490755304e..7b2d0480f772 100644 --- a/arch/riscv/kernel/asm-offsets.c +++ b/arch/riscv/kernel/asm-offsets.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include =20 void asm_offsets(void); @@ -510,4 +512,14 @@ void asm_offsets(void) DEFINE(FREGS_A6, offsetof(struct __arch_ftrace_regs, a6)); DEFINE(FREGS_A7, offsetof(struct __arch_ftrace_regs, a7)); #endif + +#ifdef CONFIG_RISCV_SSE + OFFSET(SSE_REG_EVT_STACK, sse_event_arch_data, stack); + OFFSET(SSE_REG_EVT_SHADOW_STACK, sse_event_arch_data, shadow_stack); + OFFSET(SSE_REG_EVT_TMP, sse_event_arch_data, tmp); + + DEFINE(SBI_EXT_SSE, SBI_EXT_SSE); + DEFINE(SBI_SSE_EVENT_COMPLETE, SBI_SSE_EVENT_COMPLETE); + DEFINE(NR_CPUS, NR_CPUS); +#endif } diff --git a/arch/riscv/kernel/sse.c b/arch/riscv/kernel/sse.c new file mode 100644 index 000000000000..b59bda2c1f58 --- /dev/null +++ b/arch/riscv/kernel/sse.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2024 Rivos Inc. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +DEFINE_PER_CPU(struct task_struct *, __sse_entry_task); + +void __weak sse_handle_event(struct sse_event_arch_data *arch_evt, struct = pt_regs *regs) +{ +} + +void do_sse(struct sse_event_arch_data *arch_evt, struct pt_regs *regs) +{ + nmi_enter(); + + /* Retrieve missing GPRs from SBI */ + sbi_ecall(SBI_EXT_SSE, SBI_SSE_EVENT_ATTR_READ, arch_evt->evt_id, + SBI_SSE_ATTR_INTERRUPTED_A6, + (SBI_SSE_ATTR_INTERRUPTED_A7 - SBI_SSE_ATTR_INTERRUPTED_A6) + 1, + arch_evt->interrupted_state_phys, 0, 0); + + memcpy(®s->a6, &arch_evt->interrupted, sizeof(arch_evt->interrupted)); + + sse_handle_event(arch_evt, regs); + + /* + * The SSE delivery path does not uses the "standard" exception path and + * thus does not process any pending signal/softirqs. Some drivers might + * enqueue pending work that needs to be handled as soon as possible. + * For that purpose, set the software interrupt pending bit which will + * be serviced once interrupts are reenabled. + */ + if (!user_mode(regs) && !regs_irqs_disabled(regs)) + csr_set(CSR_IP, IE_SIE); + + nmi_exit(); +} + +#ifdef CONFIG_VMAP_STACK +static unsigned long *sse_stack_alloc(unsigned int cpu, unsigned int size) +{ + return arch_alloc_vmap_stack(size, cpu_to_node(cpu)); +} + +static void sse_stack_free(unsigned long *stack) +{ + vfree(stack); +} +#else /* CONFIG_VMAP_STACK */ + +static unsigned long *sse_stack_alloc(unsigned int cpu, unsigned int size) +{ + return kmalloc(size, GFP_KERNEL); +} + +static void sse_stack_free(unsigned long *stack) +{ + kfree(stack); +} + +#endif /* CONFIG_VMAP_STACK */ + +static int sse_init_scs(int cpu, struct sse_event_arch_data *arch_evt) +{ + void *stack; + + if (!scs_is_enabled()) + return 0; + + stack =3D scs_alloc(cpu_to_node(cpu)); + if (!stack) + return -ENOMEM; + + arch_evt->shadow_stack =3D stack; + + return 0; +} + +int arch_sse_init_event(struct sse_event_arch_data *arch_evt, u32 evt_id, = int cpu) +{ + void *stack; + + arch_evt->evt_id =3D evt_id; + stack =3D sse_stack_alloc(cpu, SSE_STACK_SIZE); + if (!stack) + return -ENOMEM; + + arch_evt->stack =3D stack + SSE_STACK_SIZE; + + if (sse_init_scs(cpu, arch_evt)) { + sse_stack_free(arch_evt->stack - SSE_STACK_SIZE); + return -ENOMEM; + } + + if (sse_event_is_global(evt_id)) { + arch_evt->interrupted_state_phys =3D + virt_to_phys(&arch_evt->interrupted); + } else { + arch_evt->interrupted_state_phys =3D + per_cpu_ptr_to_phys(&arch_evt->interrupted); + } + + return 0; +} + +void arch_sse_free_event(struct sse_event_arch_data *arch_evt) +{ + scs_free(arch_evt->shadow_stack); + sse_stack_free(arch_evt->stack - SSE_STACK_SIZE); +} + +int arch_sse_register_event(struct sse_event_arch_data *arch_evt) +{ + struct sbiret sret; + + sret =3D sbi_ecall(SBI_EXT_SSE, SBI_SSE_EVENT_REGISTER, arch_evt->evt_id, + (unsigned long) handle_sse, (unsigned long) arch_evt, + 0, 0, 0); + + return sbi_err_map_linux_errno(sret.error); +} diff --git a/arch/riscv/kernel/sse_entry.S b/arch/riscv/kernel/sse_entry.S new file mode 100644 index 000000000000..c860fc4f36c5 --- /dev/null +++ b/arch/riscv/kernel/sse_entry.S @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 Rivos Inc. + */ + +#include +#include + +#include +#include +#include + +/* When entering handle_sse, the following registers are set: + * a6: contains the hartid + * a7: contains struct sse_registered_event pointer + */ +SYM_CODE_START(handle_sse) + /* Save stack temporarily */ + REG_S sp, SSE_REG_EVT_TMP(a7) + /* Set entry stack */ + REG_L sp, SSE_REG_EVT_STACK(a7) + + addi sp, sp, -(PT_SIZE_ON_STACK) + REG_S ra, PT_RA(sp) + REG_S s0, PT_S0(sp) + REG_S s1, PT_S1(sp) + REG_S s2, PT_S2(sp) + REG_S s3, PT_S3(sp) + REG_S s4, PT_S4(sp) + REG_S s5, PT_S5(sp) + REG_S s6, PT_S6(sp) + REG_S s7, PT_S7(sp) + REG_S s8, PT_S8(sp) + REG_S s9, PT_S9(sp) + REG_S s10, PT_S10(sp) + REG_S s11, PT_S11(sp) + REG_S tp, PT_TP(sp) + REG_S t0, PT_T0(sp) + REG_S t1, PT_T1(sp) + REG_S t2, PT_T2(sp) + REG_S t3, PT_T3(sp) + REG_S t4, PT_T4(sp) + REG_S t5, PT_T5(sp) + REG_S t6, PT_T6(sp) + REG_S gp, PT_GP(sp) + REG_S a0, PT_A0(sp) + REG_S a1, PT_A1(sp) + REG_S a2, PT_A2(sp) + REG_S a3, PT_A3(sp) + REG_S a4, PT_A4(sp) + REG_S a5, PT_A5(sp) + + /* Retrieve entry sp */ + REG_L a4, SSE_REG_EVT_TMP(a7) + /* Save CSRs */ + csrr a0, CSR_EPC + csrr a1, CSR_SSTATUS + csrr a2, CSR_STVAL + csrr a3, CSR_SCAUSE + + REG_S a0, PT_EPC(sp) + REG_S a1, PT_STATUS(sp) + REG_S a2, PT_BADADDR(sp) + REG_S a3, PT_CAUSE(sp) + REG_S a4, PT_SP(sp) + + /* Disable user memory access and floating/vector computing */ + li t0, SR_SUM | SR_FS_VS + csrc CSR_STATUS, t0 + + load_global_pointer + scs_load_sse_stack a7 + + /* Restore current task struct from __sse_entry_task */ + li t1, NR_CPUS + move t3, zero + +#ifdef CONFIG_SMP + /* Find the CPU id associated to the hart id */ + la t0, __cpuid_to_hartid_map +.Lhart_id_loop: + REG_L t2, 0(t0) + beq t2, a6, .Lcpu_id_found + + /* Increment pointer and CPU number */ + addi t3, t3, 1 + addi t0, t0, RISCV_SZPTR + bltu t3, t1, .Lhart_id_loop + + /* + * This should never happen since we expect the hart_id to match one + * of our CPU, but better be safe than sorry + */ + la tp, init_task + la a0, sse_hart_id_panic_string + la t0, panic + jalr t0 + +.Lcpu_id_found: +#endif + asm_per_cpu_with_cpu t2 __sse_entry_task t1 t3 + REG_L tp, 0(t2) + + move a1, sp /* pt_regs on stack */ + + /* + * Save sscratch for restoration since we might have interrupted the + * kernel in early exception path and thus, we don't know the content of + * sscratch. + */ + csrr s4, CSR_SSCRATCH + /* In-kernel scratch is 0 */ + csrw CSR_SCRATCH, x0 + + move a0, a7 + + call do_sse + + csrw CSR_SSCRATCH, s4 + + REG_L a0, PT_EPC(sp) + REG_L a1, PT_STATUS(sp) + REG_L a2, PT_BADADDR(sp) + REG_L a3, PT_CAUSE(sp) + csrw CSR_EPC, a0 + csrw CSR_SSTATUS, a1 + csrw CSR_STVAL, a2 + csrw CSR_SCAUSE, a3 + + REG_L ra, PT_RA(sp) + REG_L s0, PT_S0(sp) + REG_L s1, PT_S1(sp) + REG_L s2, PT_S2(sp) + REG_L s3, PT_S3(sp) + REG_L s4, PT_S4(sp) + REG_L s5, PT_S5(sp) + REG_L s6, PT_S6(sp) + REG_L s7, PT_S7(sp) + REG_L s8, PT_S8(sp) + REG_L s9, PT_S9(sp) + REG_L s10, PT_S10(sp) + REG_L s11, PT_S11(sp) + REG_L tp, PT_TP(sp) + REG_L t0, PT_T0(sp) + REG_L t1, PT_T1(sp) + REG_L t2, PT_T2(sp) + REG_L t3, PT_T3(sp) + REG_L t4, PT_T4(sp) + REG_L t5, PT_T5(sp) + REG_L t6, PT_T6(sp) + REG_L gp, PT_GP(sp) + REG_L a0, PT_A0(sp) + REG_L a1, PT_A1(sp) + REG_L a2, PT_A2(sp) + REG_L a3, PT_A3(sp) + REG_L a4, PT_A4(sp) + REG_L a5, PT_A5(sp) + + REG_L sp, PT_SP(sp) + + li a7, SBI_EXT_SSE + li a6, SBI_SSE_EVENT_COMPLETE + ecall + +SYM_CODE_END(handle_sse) + +SYM_DATA_START_LOCAL(sse_hart_id_panic_string) + .ascii "Unable to match hart_id with cpu\0" +SYM_DATA_END(sse_hart_id_panic_string) --=20 2.49.0 From nobody Fri Dec 19 20:38:05 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 023C21CAA7B for ; Fri, 16 May 2025 15:24:31 +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=1747409074; cv=none; b=E2bxutBtuJ30LYURwiG7UBKkAxiRJZhJHLQAQ2XUnrsIMgloaAI12RS9EoBlwR8paaqCNSRNCi1CTAOYjODJW/HqXDe7q3YsuEBjhOS3lEUOn6ahRDdOqmAc7ijgCEdFYYKvdaVhcHRQTlBwVoV/2rByPtV8Jun9PojAYLoeL98= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747409074; c=relaxed/simple; bh=CEudB7xfGfZknsxjDnLgzXAkHegbhBiCvlQuxxKbElw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ugZ1oMbVNbZlfYS0AxcH2xgouZHI4wEDQr6cVhH1LiVCRL7l3EYBa/1trB29gniIr0lYf4SERn8nGRIf7hFfxsFVvWakDpWD9ZAXyjuYsB1F8xypi67KgD2Vi/dgU3BuB6u1qX2T5kIvpJv8n31TR8M+aq/IbcVEj6zudRd3Qz8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com; spf=pass smtp.mailfrom=rivosinc.com; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b=dm4rj8o1; arc=none smtp.client-ip=209.85.210.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (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.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b="dm4rj8o1" Received: by mail-pf1-f179.google.com with SMTP id d2e1a72fcca58-74294fa4bb5so3156195b3a.1 for ; Fri, 16 May 2025 08:24:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20230601.gappssmtp.com; s=20230601; t=1747409071; x=1748013871; 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=YtK7qFNtUWEuKnh+PHuLi6UhkA6KPFOVgyIBIkZ+PDU=; b=dm4rj8o1tt2swhpbg42htTc7gi0D47lyCJ//Pch/eq+fxF4FfBCiPnp7DfwrCuEG06 2xra+dWiRIY2y1khWUT0zjrpxKZl62TQkURcoFO7glkYReMc28br024Nm3Lr2NLimrKw 6wCI7uPoaxK7LGo1kBQZsDJFNcz8FePrS+KEzHRcjeamymJNxc0Gv9+/C/+swAQzWv1B pe3l8rvwIshtgdYQdKH41ClgCDbrw/HlLdZjy+G8cWixlbgPF/rI12v66kfwP25DWCxh czob9wxDXuwW6gM1+nifcGL3V3aqI8QWliPpctqzDNps4Ovx/M+jRWfZb81PEGbgGSQs AI/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1747409071; x=1748013871; 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=YtK7qFNtUWEuKnh+PHuLi6UhkA6KPFOVgyIBIkZ+PDU=; b=mhO1ST7JFvVHwD2Tf7k4MSe4mc2QWSbRV7ac3fzaNUa6GPeM2XmoV2hL9Imw2eJCQT 5r5SX6YqFvc0DPj3fOKmT88RVqNyflKPh715MflaUX8PDSBl16vWAeZeb75o2hU2Xxxd POrs+cpaZ5KeXq1WU4PU5QqHRsR0ib1tFnv0bVpSutn2RBLQ6ACYjt2VVZtFE8L2S2Fz SeqB3MsnPhUATgX+IPOhNu3Z1kHJHnCX3W5nW3ieay607+NU2eWyhnxY3NCoiGTzihom 4r7LM5Da5YscnWPtrr26xlXr+DHyHK2+NqOMBHEQm2MDyxWH00yd9fepTZ7zRASn2RKa 1UZw== X-Forwarded-Encrypted: i=1; AJvYcCWAsXG+aAUGNcO2pxRIQWWyCBVXHT8TFIKV7r1FbXRPboNXtqN4FeWNprt/0sPgKXFTQtJ+ic80U1sR2Ak=@vger.kernel.org X-Gm-Message-State: AOJu0YzXP1CfRjMRnn/bA7dyrN5nwWbGoxG/SWL0wMOhclxerdVcHV8n yeOGYc9IMJaGaajQrN1NJTNZlfiLYTPK3tOj5P5ndqjFLIERGAKXLYzugOPC/w+i7Is= X-Gm-Gg: ASbGnctdpthzEUac4t028vwM0wqCvtKpJ+xZ8qG9gnWTEwz+JEBn3P4b8878eBMUfrR /md8F33aM2vwhOYH1qiR6wmb6PkBoNHzOyyGiUP58TXVg7dUMgAH2MIDsELZMJBOcM14LGPZ+R/ uOpfzEbDVs6U0SAjLmW7Svcp90xbaXN2CIkvAHbmYduoL67oSTm6gjdDu79lY1gzreatn2veH3U xq1ko8XMuS81v+C8/QoLj0OIlOKbOiBnioHRWTZps9Gxe2f7RMjCtZgL/ILzpAUJ3CwEkCfZKMq z22kjwRVVG2Xuj15HHkZzuZ/JDZiM8NPSSd5mDTuAkLQwlLqAJGQBFxsgjGkwJU= X-Google-Smtp-Source: AGHT+IEPb2CkS9eW8hWebbqfST2/jFMDgmMTTwCG6X9bBOczP0XiPKHLfjkQ/gmtmNVozao4oSdDLw== X-Received: by 2002:a05:6a00:6f57:b0:73d:b1ff:c758 with SMTP id d2e1a72fcca58-742a98abbecmr4911558b3a.18.1747409070996; Fri, 16 May 2025 08:24:30 -0700 (PDT) Received: from carbon-x1.. ([2a01:e0a:e17:9700:16d2:7456:6634:9626]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-742a96def68sm1666997b3a.30.2025.05.16.08.24.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 16 May 2025 08:24:30 -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 , Conor Dooley Subject: [PATCH v4 3/4] drivers: firmware: add riscv SSE support Date: Fri, 16 May 2025 17:23:41 +0200 Message-ID: <20250516152355.560448-4-cleger@rivosinc.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250516152355.560448-1-cleger@rivosinc.com> References: <20250516152355.560448-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 Add driver level interface to use RISC-V SSE arch support. This interface allows registering SSE handlers, and receive them. This will be used by PMU and GHES driver. Signed-off-by: Himanshu Chauhan Co-developed-by: Himanshu Chauhan Signed-off-by: Cl=C3=A9ment L=C3=A9ger Acked-by: Conor Dooley --- MAINTAINERS | 15 + drivers/firmware/Kconfig | 1 + drivers/firmware/Makefile | 1 + drivers/firmware/riscv/Kconfig | 15 + drivers/firmware/riscv/Makefile | 3 + drivers/firmware/riscv/riscv_sse.c | 696 +++++++++++++++++++++++++++++ include/linux/riscv_sse.h | 59 +++ 7 files changed, 790 insertions(+) create mode 100644 drivers/firmware/riscv/Kconfig create mode 100644 drivers/firmware/riscv/Makefile create mode 100644 drivers/firmware/riscv/riscv_sse.c create mode 100644 include/linux/riscv_sse.h diff --git a/MAINTAINERS b/MAINTAINERS index 3563492e4eba..ae21147bf71d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20892,6 +20892,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/g= it/iommu/linux.git F: Documentation/devicetree/bindings/iommu/riscv,iommu.yaml F: drivers/iommu/riscv/ =20 +RISC-V FIRMWARE DRIVERS +M: Conor Dooley +L: linux-riscv@lists.infradead.org +S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git +F: drivers/firmware/riscv/* + RISC-V MICROCHIP FPGA SUPPORT M: Conor Dooley M: Daire McNamara @@ -20956,6 +20963,14 @@ F: arch/riscv/boot/dts/spacemit/ N: spacemit K: spacemit =20 +RISC-V SSE DRIVER +M: Cl=C3=A9ment L=C3=A9ger +R: Himanshu Chauhan +L: linux-riscv@lists.infradead.org +S: Maintained +F: drivers/firmware/riscv/riscv_sse.c +F: include/linux/riscv_sse.h + RISC-V THEAD SoC SUPPORT M: Drew Fustini M: Guo Ren diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index aadc395ee168..fe72e705067c 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -278,6 +278,7 @@ source "drivers/firmware/meson/Kconfig" source "drivers/firmware/microchip/Kconfig" source "drivers/firmware/psci/Kconfig" source "drivers/firmware/qcom/Kconfig" +source "drivers/firmware/riscv/Kconfig" source "drivers/firmware/samsung/Kconfig" source "drivers/firmware/smccc/Kconfig" source "drivers/firmware/tegra/Kconfig" diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 4ddec2820c96..6cdd84570ea7 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -34,6 +34,7 @@ obj-y +=3D efi/ obj-y +=3D imx/ obj-y +=3D psci/ obj-y +=3D qcom/ +obj-y +=3D riscv/ obj-y +=3D samsung/ obj-y +=3D smccc/ obj-y +=3D tegra/ diff --git a/drivers/firmware/riscv/Kconfig b/drivers/firmware/riscv/Kconfig new file mode 100644 index 000000000000..8056ed3262d9 --- /dev/null +++ b/drivers/firmware/riscv/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only +menu "Risc-V Specific firmware drivers" +depends on RISCV + +config RISCV_SSE + bool "Enable SBI Supervisor Software Events support" + depends on RISCV_SBI + default y + help + The Supervisor Software Events support allow the SBI to deliver + NMI-like notifications to the supervisor mode software. When enable, + this option provides support to register callbacks on specific SSE + events. + +endmenu diff --git a/drivers/firmware/riscv/Makefile b/drivers/firmware/riscv/Makef= ile new file mode 100644 index 000000000000..4ccfcbbc28ea --- /dev/null +++ b/drivers/firmware/riscv/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_RISCV_SSE) +=3D riscv_sse.o diff --git a/drivers/firmware/riscv/riscv_sse.c b/drivers/firmware/riscv/ri= scv_sse.c new file mode 100644 index 000000000000..05e4bc8dfa99 --- /dev/null +++ b/drivers/firmware/riscv/riscv_sse.c @@ -0,0 +1,696 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 Rivos Inc. + */ + +#define pr_fmt(fmt) "sse: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct sse_event { + struct list_head list; + u32 evt_id; + u32 priority; + sse_event_handler *handler; + void *handler_arg; + /* Only valid for global events */ + unsigned int cpu; + + union { + struct sse_registered_event *global; + struct sse_registered_event __percpu *local; + }; +}; + +static int sse_hp_state; +static bool sse_available; +static DEFINE_SPINLOCK(events_list_lock); +static LIST_HEAD(events); +static DEFINE_MUTEX(sse_mutex); + +struct sse_registered_event { + struct sse_event_arch_data arch; + struct sse_event *event; + unsigned long attr_buf; + bool is_enabled; +}; + +void sse_handle_event(struct sse_event_arch_data *arch_event, + struct pt_regs *regs) +{ + int ret; + struct sse_registered_event *reg_evt =3D + container_of(arch_event, struct sse_registered_event, arch); + struct sse_event *evt =3D reg_evt->event; + + ret =3D evt->handler(evt->evt_id, evt->handler_arg, regs); + if (ret) + pr_warn("event %x handler failed with error %d\n", evt->evt_id, + ret); +} + +static struct sse_event *sse_event_get(u32 evt) +{ + struct sse_event *event =3D NULL, *tmp; + + scoped_guard(spinlock, &events_list_lock) { + list_for_each_entry(tmp, &events, list) { + if (tmp->evt_id =3D=3D evt) + return event; + } + } + + return NULL; +} + +static phys_addr_t sse_event_get_phys(struct sse_registered_event *reg_evt, + void *addr) +{ + phys_addr_t phys; + + if (sse_event_is_global(reg_evt->event->evt_id)) + phys =3D virt_to_phys(addr); + else + phys =3D per_cpu_ptr_to_phys(addr); + + return phys; +} + +static struct sse_registered_event *sse_get_reg_evt(struct sse_event *even= t) +{ + if (sse_event_is_global(event->evt_id)) + return event->global; + else + return per_cpu_ptr(event->local, smp_processor_id()); +} + +static int sse_sbi_event_func(struct sse_event *event, unsigned long func) +{ + struct sbiret ret; + u32 evt =3D event->evt_id; + struct sse_registered_event *reg_evt =3D sse_get_reg_evt(event); + + ret =3D sbi_ecall(SBI_EXT_SSE, func, evt, 0, 0, 0, 0, 0); + if (ret.error) + pr_debug("Failed to execute func %lx, event %x, error %ld\n", + func, evt, ret.error); + + if (func =3D=3D SBI_SSE_EVENT_DISABLE) + reg_evt->is_enabled =3D false; + else if (func =3D=3D SBI_SSE_EVENT_ENABLE) + reg_evt->is_enabled =3D true; + + return sbi_err_map_linux_errno(ret.error); +} + +int sse_event_disable_local(struct sse_event *event) +{ + return sse_sbi_event_func(event, SBI_SSE_EVENT_DISABLE); +} + +int sse_event_enable_local(struct sse_event *event) +{ + return sse_sbi_event_func(event, SBI_SSE_EVENT_ENABLE); +} + +static int sse_event_attr_get_no_lock(struct sse_registered_event *reg_evt, + unsigned long attr_id, unsigned long *val) +{ + struct sbiret sret; + u32 evt =3D reg_evt->event->evt_id; + unsigned long phys; + + phys =3D sse_event_get_phys(reg_evt, ®_evt->attr_buf); + + sret =3D sbi_ecall(SBI_EXT_SSE, SBI_SSE_EVENT_ATTR_READ, evt, + attr_id, 1, phys, 0, 0); + if (sret.error) { + pr_debug("Failed to get event %x attr %lx, error %ld\n", evt, + attr_id, sret.error); + return sbi_err_map_linux_errno(sret.error); + } + + *val =3D reg_evt->attr_buf; + + return 0; +} + +static int sse_event_attr_set_nolock(struct sse_registered_event *reg_evt, + unsigned long attr_id, unsigned long val) +{ + struct sbiret sret; + u32 evt =3D reg_evt->event->evt_id; + unsigned long phys; + + reg_evt->attr_buf =3D val; + phys =3D sse_event_get_phys(reg_evt, ®_evt->attr_buf); + + sret =3D sbi_ecall(SBI_EXT_SSE, SBI_SSE_EVENT_ATTR_WRITE, evt, + attr_id, 1, phys, 0, 0); + if (sret.error) { + pr_debug("Failed to set event %x attr %lx, error %ld\n", evt, + attr_id, sret.error); + return sbi_err_map_linux_errno(sret.error); + } + + return 0; +} + +static int sse_event_set_target_cpu_nolock(struct sse_event *event, + unsigned int cpu) +{ + unsigned int hart_id =3D cpuid_to_hartid_map(cpu); + struct sse_registered_event *reg_evt =3D event->global; + u32 evt =3D event->evt_id; + bool was_enabled; + int ret; + + if (!sse_event_is_global(evt)) + return -EINVAL; + + was_enabled =3D reg_evt->is_enabled; + if (was_enabled) + sse_event_disable_local(event); + do { + ret =3D sse_event_attr_set_nolock(reg_evt, + SBI_SSE_ATTR_PREFERRED_HART, + hart_id); + } while (ret =3D=3D -EINVAL); + + if (ret =3D=3D 0) + event->cpu =3D cpu; + + if (was_enabled) + sse_event_enable_local(event); + + return 0; +} + +int sse_event_set_target_cpu(struct sse_event *event, unsigned int cpu) +{ + int ret; + + scoped_guard(mutex, &sse_mutex) { + cpus_read_lock(); + + if (!cpu_online(cpu)) + return -EINVAL; + + ret =3D sse_event_set_target_cpu_nolock(event, cpu); + + cpus_read_unlock(); + } + + return ret; +} + +static int sse_event_init_registered(unsigned int cpu, + struct sse_registered_event *reg_evt, + struct sse_event *event) +{ + reg_evt->event =3D event; + arch_sse_init_event(®_evt->arch, event->evt_id, cpu); + + return 0; +} + +static void sse_event_free_registered(struct sse_registered_event *reg_evt) +{ + arch_sse_free_event(®_evt->arch); +} + +static int sse_event_alloc_global(struct sse_event *event) +{ + int err; + struct sse_registered_event *reg_evt; + + reg_evt =3D kzalloc(sizeof(*reg_evt), GFP_KERNEL); + if (!reg_evt) + return -ENOMEM; + + event->global =3D reg_evt; + err =3D sse_event_init_registered(smp_processor_id(), reg_evt, event); + if (err) + kfree(reg_evt); + + return err; +} + +static int sse_event_alloc_local(struct sse_event *event) +{ + int err; + unsigned int cpu, err_cpu; + struct sse_registered_event *reg_evt; + struct sse_registered_event __percpu *reg_evts; + + reg_evts =3D alloc_percpu(struct sse_registered_event); + if (!reg_evts) + return -ENOMEM; + + event->local =3D reg_evts; + + for_each_possible_cpu(cpu) { + reg_evt =3D per_cpu_ptr(reg_evts, cpu); + err =3D sse_event_init_registered(cpu, reg_evt, event); + if (err) { + err_cpu =3D cpu; + goto err_free_per_cpu; + } + } + + return 0; + +err_free_per_cpu: + for_each_possible_cpu(cpu) { + if (cpu =3D=3D err_cpu) + break; + reg_evt =3D per_cpu_ptr(reg_evts, cpu); + sse_event_free_registered(reg_evt); + } + + free_percpu(reg_evts); + + return err; +} + +static struct sse_event *sse_event_alloc(u32 evt, u32 priority, + sse_event_handler *handler, void *arg) +{ + int err; + struct sse_event *event; + + event =3D kzalloc(sizeof(*event), GFP_KERNEL); + if (!event) + return ERR_PTR(-ENOMEM); + + event->evt_id =3D evt; + event->priority =3D priority; + event->handler_arg =3D arg; + event->handler =3D handler; + + if (sse_event_is_global(evt)) { + err =3D sse_event_alloc_global(event); + if (err) + goto err_alloc_reg_evt; + } else { + err =3D sse_event_alloc_local(event); + if (err) + goto err_alloc_reg_evt; + } + + return event; + +err_alloc_reg_evt: + kfree(event); + + return ERR_PTR(err); +} + +static int sse_sbi_register_event(struct sse_event *event, + struct sse_registered_event *reg_evt) +{ + int ret; + + ret =3D sse_event_attr_set_nolock(reg_evt, SBI_SSE_ATTR_PRIO, + event->priority); + if (ret) + return ret; + + return arch_sse_register_event(®_evt->arch); +} + +static int sse_event_register_local(struct sse_event *event) +{ + int ret; + struct sse_registered_event *reg_evt =3D per_cpu_ptr(event->local, + smp_processor_id()); + + ret =3D sse_sbi_register_event(event, reg_evt); + if (ret) + pr_debug("Failed to register event %x: err %d\n", event->evt_id, + ret); + + return ret; +} + +static int sse_sbi_unregister_event(struct sse_event *event) +{ + return sse_sbi_event_func(event, SBI_SSE_EVENT_UNREGISTER); +} + +struct sse_per_cpu_evt { + struct sse_event *event; + unsigned long func; + atomic_t error; +}; + +static void sse_event_per_cpu_func(void *info) +{ + int ret; + struct sse_per_cpu_evt *cpu_evt =3D info; + + if (cpu_evt->func =3D=3D SBI_SSE_EVENT_REGISTER) + ret =3D sse_event_register_local(cpu_evt->event); + else + ret =3D sse_sbi_event_func(cpu_evt->event, cpu_evt->func); + + if (ret) + atomic_set(&cpu_evt->error, ret); +} + +static void sse_event_free(struct sse_event *event) +{ + unsigned int cpu; + struct sse_registered_event *reg_evt; + + if (sse_event_is_global(event->evt_id)) { + sse_event_free_registered(event->global); + kfree(event->global); + } else { + for_each_possible_cpu(cpu) { + reg_evt =3D per_cpu_ptr(event->local, cpu); + sse_event_free_registered(reg_evt); + } + free_percpu(event->local); + } + + kfree(event); +} + +int sse_event_enable(struct sse_event *event) +{ + int ret =3D 0, cpu; + struct sse_per_cpu_evt cpu_evt; + struct sse_registered_event *reg_evt; + + scoped_guard(mutex, &sse_mutex) { + cpus_read_lock(); + if (sse_event_is_global(event->evt_id)) { + reg_evt =3D event->global; + ret =3D sse_event_enable_local(event); + } else { + cpu_evt.event =3D event; + atomic_set(&cpu_evt.error, 0); + cpu_evt.func =3D SBI_SSE_EVENT_ENABLE; + on_each_cpu(sse_event_per_cpu_func, &cpu_evt, 1); + ret =3D atomic_read(&cpu_evt.error); + if (ret) { + cpu_evt.func =3D SBI_SSE_EVENT_DISABLE; + on_each_cpu(sse_event_per_cpu_func, &cpu_evt, 1); + } else { + for_each_online_cpu(cpu) { + + } + } + } + cpus_read_unlock(); + } + + return ret; +} + +static void sse_events_mask(void) +{ + sbi_ecall(SBI_EXT_SSE, SBI_SSE_EVENT_HART_MASK, 0, 0, 0, 0, 0, 0); +} + +static void sse_events_unmask(void) +{ + sbi_ecall(SBI_EXT_SSE, SBI_SSE_EVENT_HART_UNMASK, 0, 0, 0, 0, 0, 0); +} + +static void sse_event_disable_nolock(struct sse_event *event) +{ + struct sse_per_cpu_evt cpu_evt; + + if (sse_event_is_global(event->evt_id)) { + sse_event_disable_local(event); + } else { + cpu_evt.event =3D event; + cpu_evt.func =3D SBI_SSE_EVENT_DISABLE; + on_each_cpu(sse_event_per_cpu_func, &cpu_evt, 1); + } +} + +void sse_event_disable(struct sse_event *event) +{ + scoped_guard(mutex, &sse_mutex) { + cpus_read_lock(); + sse_event_disable_nolock(event); + cpus_read_unlock(); + } +} + +struct sse_event *sse_event_register(u32 evt, u32 priority, + sse_event_handler *handler, void *arg) +{ + struct sse_per_cpu_evt cpu_evt; + struct sse_event *event; + int ret =3D 0; + + if (!sse_available) + return ERR_PTR(-EOPNOTSUPP); + + mutex_lock(&sse_mutex); + if (sse_event_get(evt)) { + pr_debug("Event %x already registered\n", evt); + ret =3D -EEXIST; + goto out_unlock; + } + + event =3D sse_event_alloc(evt, priority, handler, arg); + if (IS_ERR(event)) { + ret =3D PTR_ERR(event); + goto out_unlock; + } + + cpus_read_lock(); + if (sse_event_is_global(evt)) { + unsigned long preferred_hart; + + ret =3D sse_event_attr_get_no_lock(event->global, + SBI_SSE_ATTR_PREFERRED_HART, + &preferred_hart); + if (ret) + goto err_event_free; + event->cpu =3D riscv_hartid_to_cpuid(preferred_hart); + + ret =3D sse_sbi_register_event(event, event->global); + if (ret) + goto err_event_free; + + } else { + cpu_evt.event =3D event; + atomic_set(&cpu_evt.error, 0); + cpu_evt.func =3D SBI_SSE_EVENT_REGISTER; + on_each_cpu(sse_event_per_cpu_func, &cpu_evt, 1); + ret =3D atomic_read(&cpu_evt.error); + if (ret) { + cpu_evt.func =3D SBI_SSE_EVENT_UNREGISTER; + on_each_cpu(sse_event_per_cpu_func, &cpu_evt, 1); + goto err_event_free; + } + } + cpus_read_unlock(); + + scoped_guard(spinlock, &events_list_lock) + list_add(&event->list, &events); + + mutex_unlock(&sse_mutex); + + return event; + +err_event_free: + cpus_read_unlock(); + sse_event_free(event); +out_unlock: + mutex_unlock(&sse_mutex); + + return ERR_PTR(ret); +} + +static void sse_event_unregister_nolock(struct sse_event *event) +{ + struct sse_per_cpu_evt cpu_evt; + + if (sse_event_is_global(event->evt_id)) { + sse_sbi_unregister_event(event); + } else { + cpu_evt.event =3D event; + cpu_evt.func =3D SBI_SSE_EVENT_UNREGISTER; + on_each_cpu(sse_event_per_cpu_func, &cpu_evt, 1); + } +} + +void sse_event_unregister(struct sse_event *event) +{ + scoped_guard(mutex, &sse_mutex) { + cpus_read_lock(); + sse_event_unregister_nolock(event); + cpus_read_unlock(); + + scoped_guard(spinlock, &events_list_lock) + list_del(&event->list); + + sse_event_free(event); + } +} + +static int sse_cpu_online(unsigned int cpu) +{ + struct sse_event *event; + + scoped_guard(spinlock, &events_list_lock) { + list_for_each_entry(event, &events, list) { + if (sse_event_is_global(event->evt_id)) + continue; + + sse_event_register_local(event); + if (sse_get_reg_evt(event)) + sse_event_enable_local(event); + } + } + + /* Ready to handle events. Unmask SSE. */ + sse_events_unmask(); + + return 0; +} + +static int sse_cpu_teardown(unsigned int cpu) +{ + unsigned int next_cpu; + struct sse_event *event; + + /* Mask the sse events */ + sse_events_mask(); + + scoped_guard(spinlock, &events_list_lock) { + list_for_each_entry(event, &events, list) { + if (!sse_event_is_global(event->evt_id)) { + + if (event->global->is_enabled) + sse_event_disable_local(event); + + sse_sbi_unregister_event(event); + continue; + } + + if (event->cpu !=3D smp_processor_id()) + continue; + + /* Update destination hart for global event */ + next_cpu =3D cpumask_any_but(cpu_online_mask, cpu); + sse_event_set_target_cpu_nolock(event, next_cpu); + } + } + + return 0; +} + +static void sse_reset(void) +{ + struct sse_event *event =3D NULL; + + list_for_each_entry(event, &events, list) { + sse_event_disable_nolock(event); + sse_event_unregister_nolock(event); + } +} + +static int sse_pm_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + WARN_ON_ONCE(preemptible()); + + switch (action) { + case CPU_PM_ENTER: + sse_events_mask(); + break; + case CPU_PM_EXIT: + case CPU_PM_ENTER_FAILED: + sse_events_unmask(); + break; + default: + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + +static struct notifier_block sse_pm_nb =3D { + .notifier_call =3D sse_pm_notifier, +}; + +/* + * Mask all CPUs and unregister all events on panic, reboot or kexec. + */ +static int sse_reboot_notifier(struct notifier_block *nb, unsigned long ac= tion, + void *data) +{ + cpuhp_remove_state(sse_hp_state); + + sse_reset(); + + return NOTIFY_OK; +} + +static struct notifier_block sse_reboot_nb =3D { + .notifier_call =3D sse_reboot_notifier, +}; + +static int __init sse_init(void) +{ + int cpu, ret; + + if (sbi_probe_extension(SBI_EXT_SSE) <=3D 0) { + pr_err("Missing SBI SSE extension\n"); + return -EOPNOTSUPP; + } + pr_info("SBI SSE extension detected\n"); + + for_each_possible_cpu(cpu) + INIT_LIST_HEAD(&events); + + ret =3D cpu_pm_register_notifier(&sse_pm_nb); + if (ret) { + pr_warn("Failed to register CPU PM notifier...\n"); + return ret; + } + + ret =3D register_reboot_notifier(&sse_reboot_nb); + if (ret) { + pr_warn("Failed to register reboot notifier...\n"); + goto remove_cpupm; + } + + ret =3D cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "riscv/sse:online", + sse_cpu_online, sse_cpu_teardown); + if (ret < 0) + goto remove_reboot; + + sse_hp_state =3D ret; + sse_available =3D true; + + return 0; + +remove_reboot: + unregister_reboot_notifier(&sse_reboot_nb); + +remove_cpupm: + cpu_pm_unregister_notifier(&sse_pm_nb); + + return ret; +} +arch_initcall(sse_init); diff --git a/include/linux/riscv_sse.h b/include/linux/riscv_sse.h new file mode 100644 index 000000000000..8653fa74ec82 --- /dev/null +++ b/include/linux/riscv_sse.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024 Rivos Inc. + */ + +#ifndef __LINUX_RISCV_SSE_H +#define __LINUX_RISCV_SSE_H + +#include +#include + +struct sse_event; +struct pt_regs; + +typedef int (sse_event_handler)(u32 event_num, void *arg, struct pt_regs *= regs); + +#ifdef CONFIG_RISCV_SSE + +struct sse_event *sse_event_register(u32 event_num, u32 priority, + sse_event_handler *handler, void *arg); + +void sse_event_unregister(struct sse_event *evt); + +int sse_event_set_target_cpu(struct sse_event *sse_evt, unsigned int cpu); + +int sse_event_enable(struct sse_event *sse_evt); + +void sse_event_disable(struct sse_event *sse_evt); + +int sse_event_enable_local(struct sse_event *sse_evt); +int sse_event_disable_local(struct sse_event *sse_evt); + +#else +static inline struct sse_event *sse_event_register(u32 event_num, u32 prio= rity, + sse_event_handler *handler, + void *arg) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +static inline void sse_event_unregister(struct sse_event *evt) {} + +static inline int sse_event_set_target_cpu(struct sse_event *sse_evt, + unsigned int cpu) +{ + return -EOPNOTSUPP; +} + +static inline int sse_event_enable(struct sse_event *sse_evt) +{ + return -EOPNOTSUPP; +} + +static inline void sse_event_disable(struct sse_event *sse_evt) {} + + +#endif + +#endif /* __LINUX_RISCV_SSE_H */ --=20 2.49.0 From nobody Fri Dec 19 20:38:05 2025 Received: from mail-pf1-f174.google.com (mail-pf1-f174.google.com [209.85.210.174]) (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 861EB1D5160 for ; Fri, 16 May 2025 15:24:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747409080; cv=none; b=DuZIdEszkLiRF4KAxz1RYB7NKn22EpHm3g6T4Mq/1cZqjmGCOGAhHODKzQIkFVJZ8HIuizWQzJYWrGQgXoUDyNFbjupyouRrPqgcBCVFGXg5kqo/PEvJXX/yRhVnOqvIXeavq2XqB9iWD5GWX8bghV4SBjal0jGFKfOdPn+1NuE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747409080; c=relaxed/simple; bh=DKtHqS6JwUi0roBeJugt2YK7lKXK5d5b4PNW1NAkqGw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=B6NnBs5NBJnBrgG2RFhsh5az/HjpYzBpbTodJRjvZDIq7R7PdyvyxDsfPW5snsMjkj4FSRaJIOOIyy0ynpXvTcLyrfnvwvOoC4U276Cpu345I/hmkzDipOur0FHH8afCAG2rWHgxFX5Yq64wFLQfEAcpgbYvz9ZIx81Lhzi8cA4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com; spf=pass smtp.mailfrom=rivosinc.com; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b=icBb8MaF; arc=none smtp.client-ip=209.85.210.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (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.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b="icBb8MaF" Received: by mail-pf1-f174.google.com with SMTP id d2e1a72fcca58-74237a74f15so3193485b3a.0 for ; Fri, 16 May 2025 08:24:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20230601.gappssmtp.com; s=20230601; t=1747409078; x=1748013878; 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=NerZz78UKlNpCoQw7YCJwOy+/WEK1liVP1A2MrZ/GSg=; b=icBb8MaF+OH95Dm3qMzdbMCFo7HKyqR0cuaaa3/T1MZgmPEUTi9GnNRKr7YE26kY80 fIX2zHhJzA1CJyJ5hWFSHU7i1LuXZimHpz2sDdVm1I9a7c6A7+DrKZlpoAcLsXYHLoxY Q617EFthJndLtJ0b/hyMjOGyub45XBIvr0ZhoFUleh9hs3Uw8hdIBK1i08oa6yIZNuw8 h6PaCTLJtnGn1RiMpvpK3rsG9YUDgI7196dd4WrfVSwAQglJIGxyKFJm5kj/Q4S36GCg zbxYzI653XYzRyTpZCNY85Dx8D1+B59mTSG8M+YlPfyO2JuKAK/YeRC2bKrLw0YkD3ZI j6HQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1747409078; x=1748013878; 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=NerZz78UKlNpCoQw7YCJwOy+/WEK1liVP1A2MrZ/GSg=; b=gGNTk/RZdACEUaP99O4fYDhHb8jz4PucfUpIR30+Ue8G65m3lFfdCwim2vAHeBKRDU PqMEjY5Y5NplNU8ptycOo8mGapZf3J/oVZgjmqt8h6n4LQg2jWf+5KTsCQxq8Bxctvyz ZkWucqWegEiTsuTEzqfEKUTBs0KOiBtwU+canIpIrGZo0duG9gjkZxIO7MMEeD1hGTyx L+yy9Kwf0+LScWs5rWP2liljjleLarwiLwegOcgJeiYc7MKxcrJFmcVTCUrChL9xbk7n 0XVkRwQKRVPXuxabco76hnx8lFLt35MQyRlvbJzz1Js4I2FKJrIj4WlU+Tw/LezA6x/N rqow== X-Forwarded-Encrypted: i=1; AJvYcCVSvaewK1UyrkdH/Af1Ijeik/LkJGgjXecEBPffKAukBO5aGX2NhO249r985FND+XvkF32C2CGwMecjKdU=@vger.kernel.org X-Gm-Message-State: AOJu0YzMDH8o+R6b8rrWD4BDuqzLBtjPUDByByjI301Ji74v+yC307NP LADmNKhddqX5glrycAXcf2JYzKZtoI1ffmQzIsrZHpVyhQGy1swOOifr7U8VTcAa7p8= X-Gm-Gg: ASbGnct3lLCZ2bhqnlLwpyBKREXodviryKFsZCvEu7+P9GbrHldh5y54ie0nTXlQ66Y Nqv7awiyu/SN1XlNe8hoR/f2sjwBxPZE+gX7ocOZaUfYXRzKmXVoZLmGoKEM405LwGGsjAIHLQy J109wVa9gI4Zkvm9qw89iOzmn3xk+T5OWYqry5bTtZV+E4o8QHkK+7vp3/RN2NBZM36/NMH1Uvj MGd4i10Ct4cwNZ4tfMi479Tm29D29ADZdUvljb1W5u9hsCiLmggjdZe/B15JavEw7VNPULTNHZe sgoKJFiJQcHa/KhrAzjZDosDY+KmwNNWRZadWbdHUkaasn651INQbhecR8pb/F0= X-Google-Smtp-Source: AGHT+IHYlU3K8uJcfIKClp5Bxki/RMRZaz2vq2bBhQewH+zC4/99iinUqM/hNNbn+4ClvSR7T9fjoA== X-Received: by 2002:a05:6a20:6f8a:b0:218:c01:ddce with SMTP id adf61e73a8af0-2180c01de06mr3257419637.40.1747409077715; Fri, 16 May 2025 08:24:37 -0700 (PDT) Received: from carbon-x1.. ([2a01:e0a:e17:9700:16d2:7456:6634:9626]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-742a96def68sm1666997b3a.30.2025.05.16.08.24.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 16 May 2025 08:24:37 -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 Subject: [PATCH v4 4/4] perf: RISC-V: add support for SSE event Date: Fri, 16 May 2025 17:23:42 +0200 Message-ID: <20250516152355.560448-5-cleger@rivosinc.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250516152355.560448-1-cleger@rivosinc.com> References: <20250516152355.560448-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 In order to use SSE within PMU drivers, register a SSE handler for the local PMU event. Reuse the existing overflow IRQ handler and pass appropriate pt_regs. Add a config option RISCV_PMU_SSE to select event delivery via SSE events. Signed-off-by: Cl=C3=A9ment L=C3=A9ger --- drivers/perf/Kconfig | 9 +++++ drivers/perf/riscv_pmu.c | 19 +++++++++ drivers/perf/riscv_pmu_sbi.c | 72 +++++++++++++++++++++++++++++----- include/linux/perf/riscv_pmu.h | 3 ++ 4 files changed, 93 insertions(+), 10 deletions(-) diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig index 4e268de351c4..3462f3a21e5f 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig @@ -105,6 +105,15 @@ config RISCV_PMU_SBI full perf feature support i.e. counter overflow, privilege mode filtering, counter configuration. =20 +config RISCV_PMU_SSE + depends on RISCV_PMU && RISCV_SSE + bool "RISC-V PMU SSE events" + default n + help + Say y if you want to use SSE events to deliver PMU interrupts. This + provides a way to profile the kernel at any level by using NMI-like + SSE events. + config STARFIVE_STARLINK_PMU depends on ARCH_STARFIVE || COMPILE_TEST depends on 64BIT diff --git a/drivers/perf/riscv_pmu.c b/drivers/perf/riscv_pmu.c index 7644147d50b4..1eb28381b80f 100644 --- a/drivers/perf/riscv_pmu.c +++ b/drivers/perf/riscv_pmu.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include =20 @@ -254,6 +255,22 @@ void riscv_pmu_start(struct perf_event *event, int fla= gs) perf_event_update_userpage(event); } =20 +static void riscv_pmu_disable(struct pmu *pmu) +{ + struct riscv_pmu *rvpmu =3D to_riscv_pmu(pmu); + + if (rvpmu->sse_evt) + sse_event_disable_local(rvpmu->sse_evt); +} + +static void riscv_pmu_enable(struct pmu *pmu) +{ + struct riscv_pmu *rvpmu =3D to_riscv_pmu(pmu); + + if (rvpmu->sse_evt) + sse_event_enable_local(rvpmu->sse_evt); +} + static int riscv_pmu_add(struct perf_event *event, int flags) { struct riscv_pmu *rvpmu =3D to_riscv_pmu(event->pmu); @@ -411,6 +428,8 @@ struct riscv_pmu *riscv_pmu_alloc(void) .event_mapped =3D riscv_pmu_event_mapped, .event_unmapped =3D riscv_pmu_event_unmapped, .event_idx =3D riscv_pmu_event_idx, + .pmu_enable =3D riscv_pmu_enable, + .pmu_disable =3D riscv_pmu_disable, .add =3D riscv_pmu_add, .del =3D riscv_pmu_del, .start =3D riscv_pmu_start, diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index 698de8ddf895..885d04a2c338 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -948,10 +949,10 @@ static void pmu_sbi_start_overflow_mask(struct riscv_= pmu *pmu, pmu_sbi_start_ovf_ctrs_sbi(cpu_hw_evt, ctr_ovf_mask); } =20 -static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev) +static irqreturn_t pmu_sbi_ovf_handler(struct cpu_hw_events *cpu_hw_evt, + struct pt_regs *regs, bool from_sse) { struct perf_sample_data data; - struct pt_regs *regs; struct hw_perf_event *hw_evt; union sbi_pmu_ctr_info *info; int lidx, hidx, fidx; @@ -959,7 +960,6 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *d= ev) struct perf_event *event; u64 overflow; u64 overflowed_ctrs =3D 0; - struct cpu_hw_events *cpu_hw_evt =3D dev; u64 start_clock =3D sched_clock(); struct riscv_pmu_snapshot_data *sdata =3D cpu_hw_evt->snapshot_addr; =20 @@ -969,13 +969,15 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void = *dev) /* Firmware counter don't support overflow yet */ fidx =3D find_first_bit(cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS); if (fidx =3D=3D RISCV_MAX_COUNTERS) { - csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num)); + if (!from_sse) + csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num)); return IRQ_NONE; } =20 event =3D cpu_hw_evt->events[fidx]; if (!event) { - ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask); + if (!from_sse) + ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask); return IRQ_NONE; } =20 @@ -990,16 +992,16 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void = *dev) =20 /* * Overflow interrupt pending bit should only be cleared after stopping - * all the counters to avoid any race condition. + * all the counters to avoid any race condition. When using SSE, + * interrupt is cleared when stopping counters. */ - ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask); + if (!from_sse) + ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask); =20 /* No overflow bit is set */ if (!overflow) return IRQ_NONE; =20 - regs =3D get_irq_regs(); - for_each_set_bit(lidx, cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS) { struct perf_event *event =3D cpu_hw_evt->events[lidx]; =20 @@ -1055,6 +1057,52 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void= *dev) return IRQ_HANDLED; } =20 +static irqreturn_t pmu_sbi_ovf_irq_handler(int irq, void *dev) +{ + return pmu_sbi_ovf_handler(dev, get_irq_regs(), false); +} + +#ifdef CONFIG_RISCV_PMU_SSE +static int pmu_sbi_ovf_sse_handler(uint32_t evt, void *arg, + struct pt_regs *regs) +{ + struct cpu_hw_events __percpu *hw_events =3D arg; + struct cpu_hw_events *hw_event =3D raw_cpu_ptr(hw_events); + + pmu_sbi_ovf_handler(hw_event, regs, true); + + return 0; +} + +static int pmu_sbi_setup_sse(struct riscv_pmu *pmu) +{ + int ret; + struct sse_event *evt; + struct cpu_hw_events __percpu *hw_events =3D pmu->hw_events; + + evt =3D sse_event_register(SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW, 0, + pmu_sbi_ovf_sse_handler, hw_events); + if (IS_ERR(evt)) + return PTR_ERR(evt); + + ret =3D sse_event_enable(evt); + if (ret) { + sse_event_unregister(evt); + return ret; + } + + pr_info("using SSE for PMU event delivery\n"); + pmu->sse_evt =3D evt; + + return ret; +} +#else +static int pmu_sbi_setup_sse(struct riscv_pmu *pmu) +{ + return -EOPNOTSUPP; +} +#endif + static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node) { struct riscv_pmu *pmu =3D hlist_entry_safe(node, struct riscv_pmu, node); @@ -1105,6 +1153,10 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu,= struct platform_device *pde struct cpu_hw_events __percpu *hw_events =3D pmu->hw_events; struct irq_domain *domain =3D NULL; =20 + ret =3D pmu_sbi_setup_sse(pmu); + if (!ret) + return 0; + if (riscv_isa_extension_available(NULL, SSCOFPMF)) { riscv_pmu_irq_num =3D RV_IRQ_PMU; riscv_pmu_use_irq =3D true; @@ -1139,7 +1191,7 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, = struct platform_device *pde return -ENODEV; } =20 - ret =3D request_percpu_irq(riscv_pmu_irq, pmu_sbi_ovf_handler, "riscv-pmu= ", hw_events); + ret =3D request_percpu_irq(riscv_pmu_irq, pmu_sbi_ovf_irq_handler, "riscv= -pmu", hw_events); if (ret) { pr_err("registering percpu irq failed [%d]\n", ret); return ret; diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h index 701974639ff2..d4a5c55fe077 100644 --- a/include/linux/perf/riscv_pmu.h +++ b/include/linux/perf/riscv_pmu.h @@ -28,6 +28,8 @@ =20 #define RISCV_PMU_CONFIG1_GUEST_EVENTS 0x1 =20 +struct sse_event; + struct cpu_hw_events { /* currently enabled events */ int n_events; @@ -54,6 +56,7 @@ struct riscv_pmu { char *name; =20 irqreturn_t (*handle_irq)(int irq_num, void *dev); + struct sse_event *sse_evt; =20 unsigned long cmask; u64 (*ctr_read)(struct perf_event *event); --=20 2.49.0