[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250227123628.2931490-7-hchauhan@ventanamicro.com>
Date: Thu, 27 Feb 2025 18:06:24 +0530
From: Himanshu Chauhan <hchauhan@...tanamicro.com>
To: linux-riscv@...ts.infradead.org,
linux-kernel@...r.kernel.org,
linux-acpi@...r.kernel.org,
linux-efi@...r.kernel.org,
acpica-devel@...ts.linux.dev
Cc: paul.walmsley@...ive.com,
palmer@...belt.com,
lenb@...nel.org,
james.morse@....com,
tony.luck@...el.com,
ardb@...nel.org,
conor@...nel.org,
cleger@...osinc.com,
robert.moore@...el.com,
sunilvl@...tanamicro.com,
apatel@...tanamicro.com,
Himanshu Chauhan <hchauhan@...tanamicro.com>
Subject: [RFC PATCH v1 06/10] riscv: Add functions to register ghes having SSE notification
Add functions to register the ghes entries which have SSE as
notification type. The vector inside the ghes is the SSE event
ID that should be registered.
Signed-off-by: Himanshu Chauhan <hchauhan@...tanamicro.com>
---
drivers/firmware/riscv/riscv_sse.c | 147 +++++++++++++++++++++++++++++
include/linux/riscv_sse.h | 15 +++
2 files changed, 162 insertions(+)
diff --git a/drivers/firmware/riscv/riscv_sse.c b/drivers/firmware/riscv/riscv_sse.c
index c165e32cc9a5..511db9ad7a9e 100644
--- a/drivers/firmware/riscv/riscv_sse.c
+++ b/drivers/firmware/riscv/riscv_sse.c
@@ -5,6 +5,8 @@
#define pr_fmt(fmt) "sse: " fmt
+#include <acpi/ghes.h>
+#include <linux/acpi.h>
#include <linux/cpu.h>
#include <linux/cpuhotplug.h>
#include <linux/cpu_pm.h>
@@ -689,3 +691,148 @@ static int __init sse_init(void)
return ret;
}
arch_initcall(sse_init);
+
+struct sse_ghes_callback {
+ struct list_head head;
+ struct ghes *ghes;
+ sse_event_handler *callback;
+};
+
+struct sse_ghes_event_data {
+ struct list_head head;
+ u32 event_num;
+ struct list_head callback_list;
+ struct sse_event *event;
+};
+
+static DEFINE_SPINLOCK(sse_ghes_event_list_lock);
+static LIST_HEAD(sse_ghes_event_list);
+
+static int sse_ghes_handler(u32 event_num, void *arg, struct pt_regs *regs)
+{
+ struct sse_ghes_event_data *ev_data = arg;
+ struct sse_ghes_callback *cb = NULL;
+
+ list_for_each_entry(cb, &ev_data->callback_list, head) {
+ if (cb && cb->ghes && cb->callback) {
+ cb->callback(ev_data->event_num, cb->ghes, regs);
+ }
+ }
+
+ return 0;
+}
+
+int sse_register_ghes(struct ghes *ghes, sse_event_handler *lo_cb,
+ sse_event_handler *hi_cb)
+{
+ struct sse_ghes_event_data *ev_data, *evd;
+ struct sse_ghes_callback *cb;
+ u32 ev_num;
+ int err;
+
+ if (!sse_available)
+ return -EOPNOTSUPP;
+ if (!ghes || !lo_cb || !hi_cb)
+ return -EINVAL;
+
+ ev_num = ghes->generic->notify.vector;
+
+ ev_data = NULL;
+ spin_lock(&sse_ghes_event_list_lock);
+ list_for_each_entry(evd, &sse_ghes_event_list, head) {
+ if (evd->event_num == ev_num) {
+ ev_data = evd;
+ break;
+ }
+ }
+ spin_unlock(&sse_ghes_event_list_lock);
+
+ if (!ev_data) {
+ ev_data = kzalloc(sizeof(*ev_data), GFP_KERNEL);
+ if (!ev_data)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&ev_data->head);
+ ev_data->event_num = ev_num;
+
+ INIT_LIST_HEAD(&ev_data->callback_list);
+
+ ev_data->event = sse_event_register(ev_num, ev_num,
+ sse_ghes_handler, ev_data);
+ if (IS_ERR(ev_data->event)) {
+ pr_err("%s: Couldn't register event 0x%x\n", __func__, ev_num);
+ kfree(ev_data);
+ return -ENOMEM;
+ }
+
+ err = sse_event_enable(ev_data->event);
+ if (err) {
+ pr_err("%s: Couldn't enable event 0x%x\n", __func__, ev_num);
+ sse_event_unregister(ev_data->event);
+ kfree(ev_data);
+ return err;
+ }
+
+ spin_lock(&sse_ghes_event_list_lock);
+ list_add_tail(&ev_data->head, &sse_ghes_event_list);
+ spin_unlock(&sse_ghes_event_list_lock);
+ }
+
+ list_for_each_entry(cb, &ev_data->callback_list, head) {
+ if (cb->ghes == ghes)
+ return -EALREADY;
+ }
+
+ cb = kzalloc(sizeof(*cb), GFP_KERNEL);
+ if (!cb)
+ return -ENOMEM;
+ INIT_LIST_HEAD(&cb->head);
+ cb->ghes = ghes;
+ cb->callback = lo_cb;
+ list_add_tail(&cb->head, &ev_data->callback_list);
+
+ return 0;
+}
+
+int sse_unregister_ghes(struct ghes *ghes)
+{
+ struct sse_ghes_event_data *ev_data, *tmp;
+ struct sse_ghes_callback *cb;
+ int free_ev_data = 0;
+
+ if (!ghes)
+ return -EINVAL;
+
+ spin_lock(&sse_ghes_event_list_lock);
+
+ list_for_each_entry_safe(ev_data, tmp, &sse_ghes_event_list, head) {
+ list_for_each_entry(cb, &ev_data->callback_list, head) {
+ if (cb->ghes != ghes)
+ continue;
+
+ list_del(&cb->head);
+ kfree(cb);
+ break;
+ }
+
+ if (list_empty(&ev_data->callback_list))
+ free_ev_data = 1;
+
+ if (free_ev_data) {
+ spin_unlock(&sse_ghes_event_list_lock);
+
+ sse_event_disable(ev_data->event);
+ sse_event_unregister(ev_data->event);
+ ev_data->event = NULL;
+
+ spin_lock(&sse_ghes_event_list_lock);
+
+ list_del(&ev_data->head);
+ kfree(ev_data);
+ }
+ }
+
+ spin_unlock(&sse_ghes_event_list_lock);
+
+ return 0;
+}
diff --git a/include/linux/riscv_sse.h b/include/linux/riscv_sse.h
index c73184074b8c..16700677f1e8 100644
--- a/include/linux/riscv_sse.h
+++ b/include/linux/riscv_sse.h
@@ -12,6 +12,8 @@
struct sse_event;
struct pt_regs;
+struct ghes;
+
typedef int (sse_event_handler)(u32 event_num, void *arg, struct pt_regs *regs);
#ifdef CONFIG_RISCV_SSE
@@ -27,6 +29,9 @@ int sse_event_enable(struct sse_event *sse_evt);
void sse_event_disable(struct sse_event *sse_evt);
+int sse_register_ghes(struct ghes *ghes, sse_event_handler *lo_cb,
+ sse_event_handler *hi_cb);
+int sse_unregister_ghes(struct ghes *ghes);
#else
static inline struct sse_event *sse_event_register(u32 event_num, u32 priority,
sse_event_handler *handler,
@@ -50,6 +55,16 @@ static inline int sse_event_enable(struct sse_event *sse_evt)
static inline void sse_event_disable(struct sse_event *sse_evt) {}
+static inline int sse_register_ghes(struct ghes *ghes, sse_event_handler *lo_cb,
+ sse_event_handler *hi_cb)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int sse_unregister_ghes(struct ghes *ghes)
+{
+ return -EOPNOTSUPP;
+}
#endif
--
2.43.0
Powered by blists - more mailing lists