^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) // Copyright (C) 2017 Arm Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #define pr_fmt(fmt) "sdei: " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <acpi/ghes.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/arm_sdei.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/arm-smccc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/atomic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/compiler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/cpuhotplug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/cpu_pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/hardirq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/kprobes.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/kvm_host.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/notifier.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/percpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/ptrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/preempt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * The call to use to reach the firmware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static asmlinkage void (*sdei_firmware_call)(unsigned long function_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) unsigned long arg0, unsigned long arg1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) unsigned long arg2, unsigned long arg3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) unsigned long arg4, struct arm_smccc_res *res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* entry point from firmware to arch asm code */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static unsigned long sdei_entry_point;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct sdei_event {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) /* These three are protected by the sdei_list_lock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) bool reregister;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) bool reenable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) u32 event_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) u8 type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) u8 priority;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* This pointer is handed to firmware as the event argument. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) union {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /* Shared events */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct sdei_registered_event *registered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* CPU private events */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct sdei_registered_event __percpu *private_registered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /* Take the mutex for any API call or modification. Take the mutex first. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static DEFINE_MUTEX(sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /* and then hold this when modifying the list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static DEFINE_SPINLOCK(sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static LIST_HEAD(sdei_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /* Private events are registered/enabled via IPI passing one of these */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct sdei_crosscall_args {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct sdei_event *event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) atomic_t errors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) int first_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define CROSSCALL_INIT(arg, event) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) arg.event = event; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) arg.first_error = 0; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) atomic_set(&arg.errors, 0); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static inline int sdei_do_local_call(smp_call_func_t fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct sdei_event *event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct sdei_crosscall_args arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) CROSSCALL_INIT(arg, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) fn(&arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return arg.first_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static inline int sdei_do_cross_call(smp_call_func_t fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct sdei_event *event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct sdei_crosscall_args arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) CROSSCALL_INIT(arg, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) on_each_cpu(fn, &arg, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return arg.first_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) sdei_cross_call_return(struct sdei_crosscall_args *arg, int err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (err && (atomic_inc_return(&arg->errors) == 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) arg->first_error = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static int sdei_to_linux_errno(unsigned long sdei_err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) switch (sdei_err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) case SDEI_NOT_SUPPORTED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) case SDEI_INVALID_PARAMETERS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) case SDEI_DENIED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) case SDEI_PENDING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return -EINPROGRESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) case SDEI_OUT_OF_RESOURCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) static int invoke_sdei_fn(unsigned long function_id, unsigned long arg0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) unsigned long arg1, unsigned long arg2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) unsigned long arg3, unsigned long arg4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) u64 *result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct arm_smccc_res res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (sdei_firmware_call) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) sdei_firmware_call(function_id, arg0, arg1, arg2, arg3, arg4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) &res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) err = sdei_to_linux_errno(res.a0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * !sdei_firmware_call means we failed to probe or called
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * sdei_mark_interface_broken(). -EIO is not an error returned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * by sdei_to_linux_errno() and is used to suppress messages
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * from this driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) err = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) res.a0 = SDEI_NOT_SUPPORTED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) *result = res.a0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) NOKPROBE_SYMBOL(invoke_sdei_fn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static struct sdei_event *sdei_event_find(u32 event_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) struct sdei_event *e, *found = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) lockdep_assert_held(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) spin_lock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) list_for_each_entry(e, &sdei_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (e->event_num == event_num) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) found = e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) spin_unlock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) return found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) int sdei_api_event_context(u32 query, u64 *result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_CONTEXT, query, 0, 0, 0, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) NOKPROBE_SYMBOL(sdei_api_event_context);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static int sdei_api_event_get_info(u32 event, u32 info, u64 *result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_GET_INFO, event, info, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 0, 0, result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) static struct sdei_event *sdei_event_create(u32 event_num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) sdei_event_callback *cb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) void *cb_arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) u64 result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct sdei_event *event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct sdei_registered_event *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) lockdep_assert_held(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) event = kzalloc(sizeof(*event), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (!event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) INIT_LIST_HEAD(&event->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) event->event_num = event_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) &result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) event->priority = result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_TYPE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) &result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) event->type = result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (event->type == SDEI_EVENT_TYPE_SHARED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) reg = kzalloc(sizeof(*reg), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (!reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) reg->event_num = event->event_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) reg->priority = event->priority;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) reg->callback = cb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) reg->callback_arg = cb_arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) event->registered = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) struct sdei_registered_event __percpu *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) regs = alloc_percpu(struct sdei_registered_event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (!regs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) for_each_possible_cpu(cpu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) reg = per_cpu_ptr(regs, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) reg->event_num = event->event_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) reg->priority = event->priority;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) reg->callback = cb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) reg->callback_arg = cb_arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) event->private_registered = regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) spin_lock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) list_add(&event->list, &sdei_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) spin_unlock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) kfree(event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) return ERR_PTR(err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) static void sdei_event_destroy_llocked(struct sdei_event *event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) lockdep_assert_held(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) lockdep_assert_held(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) list_del(&event->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (event->type == SDEI_EVENT_TYPE_SHARED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) kfree(event->registered);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) free_percpu(event->private_registered);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) kfree(event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) static void sdei_event_destroy(struct sdei_event *event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) spin_lock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) sdei_event_destroy_llocked(event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) spin_unlock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) static int sdei_api_get_version(u64 *version)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) return invoke_sdei_fn(SDEI_1_0_FN_SDEI_VERSION, 0, 0, 0, 0, 0, version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) int sdei_mask_local_cpu(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) WARN_ON_ONCE(preemptible());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_MASK, 0, 0, 0, 0, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (err && err != -EIO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) pr_warn_once("failed to mask CPU[%u]: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) smp_processor_id(), err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) static void _ipi_mask_cpu(void *ignored)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) sdei_mask_local_cpu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) int sdei_unmask_local_cpu(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) WARN_ON_ONCE(preemptible());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_UNMASK, 0, 0, 0, 0, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) if (err && err != -EIO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) pr_warn_once("failed to unmask CPU[%u]: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) smp_processor_id(), err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) static void _ipi_unmask_cpu(void *ignored)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) sdei_unmask_local_cpu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) static void _ipi_private_reset(void *ignored)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PRIVATE_RESET, 0, 0, 0, 0, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (err && err != -EIO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) pr_warn_once("failed to reset CPU[%u]: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) smp_processor_id(), err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) static int sdei_api_shared_reset(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) return invoke_sdei_fn(SDEI_1_0_FN_SDEI_SHARED_RESET, 0, 0, 0, 0, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) static void sdei_mark_interface_broken(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) pr_err("disabling SDEI firmware interface\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) on_each_cpu(&_ipi_mask_cpu, NULL, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) sdei_firmware_call = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) static int sdei_platform_reset(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) on_each_cpu(&_ipi_private_reset, NULL, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) err = sdei_api_shared_reset();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) pr_err("Failed to reset platform: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) sdei_mark_interface_broken();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) static int sdei_api_event_enable(u32 event_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_ENABLE, event_num, 0, 0, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) /* Called directly by the hotplug callbacks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) static void _local_event_enable(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) struct sdei_crosscall_args *arg = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) WARN_ON_ONCE(preemptible());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) err = sdei_api_event_enable(arg->event->event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) sdei_cross_call_return(arg, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) int sdei_event_enable(u32 event_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) int err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) struct sdei_event *event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) mutex_lock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) event = sdei_event_find(event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) if (!event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) mutex_unlock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) cpus_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) if (event->type == SDEI_EVENT_TYPE_SHARED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) err = sdei_api_event_enable(event->event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) err = sdei_do_cross_call(_local_event_enable, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) if (!err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) spin_lock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) event->reenable = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) spin_unlock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) cpus_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) mutex_unlock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) static int sdei_api_event_disable(u32 event_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_DISABLE, event_num, 0, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 0, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) static void _ipi_event_disable(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) struct sdei_crosscall_args *arg = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) err = sdei_api_event_disable(arg->event->event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) sdei_cross_call_return(arg, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) int sdei_event_disable(u32 event_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) int err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) struct sdei_event *event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) mutex_lock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) event = sdei_event_find(event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) if (!event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) mutex_unlock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) spin_lock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) event->reenable = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) spin_unlock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (event->type == SDEI_EVENT_TYPE_SHARED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) err = sdei_api_event_disable(event->event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) err = sdei_do_cross_call(_ipi_event_disable, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) mutex_unlock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) static int sdei_api_event_unregister(u32 event_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_UNREGISTER, event_num, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 0, 0, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) /* Called directly by the hotplug callbacks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) static void _local_event_unregister(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) struct sdei_crosscall_args *arg = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) WARN_ON_ONCE(preemptible());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) err = sdei_api_event_unregister(arg->event->event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) sdei_cross_call_return(arg, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) int sdei_event_unregister(u32 event_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) struct sdei_event *event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) WARN_ON(in_nmi());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) mutex_lock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) event = sdei_event_find(event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (!event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) pr_warn("Event %u not registered\n", event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) err = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) spin_lock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) event->reregister = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) event->reenable = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) spin_unlock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) if (event->type == SDEI_EVENT_TYPE_SHARED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) err = sdei_api_event_unregister(event->event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) err = sdei_do_cross_call(_local_event_unregister, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) sdei_event_destroy(event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) mutex_unlock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) * unregister events, but don't destroy them as they are re-registered by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) * sdei_reregister_shared().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) static int sdei_unregister_shared(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) struct sdei_event *event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) mutex_lock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) spin_lock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) list_for_each_entry(event, &sdei_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) if (event->type != SDEI_EVENT_TYPE_SHARED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) err = sdei_api_event_unregister(event->event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) spin_unlock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) mutex_unlock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) static int sdei_api_event_register(u32 event_num, unsigned long entry_point,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) void *arg, u64 flags, u64 affinity)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_REGISTER, event_num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) (unsigned long)entry_point, (unsigned long)arg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) flags, affinity, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) /* Called directly by the hotplug callbacks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) static void _local_event_register(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) struct sdei_registered_event *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) struct sdei_crosscall_args *arg = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) WARN_ON(preemptible());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) reg = per_cpu_ptr(arg->event->private_registered, smp_processor_id());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) err = sdei_api_event_register(arg->event->event_num, sdei_entry_point,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) reg, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) sdei_cross_call_return(arg, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) struct sdei_event *event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) WARN_ON(in_nmi());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) mutex_lock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) if (sdei_event_find(event_num)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) pr_warn("Event %u already registered\n", event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) err = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) event = sdei_event_create(event_num, cb, arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) if (IS_ERR(event)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) err = PTR_ERR(event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) pr_warn("Failed to create event %u: %d\n", event_num, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) cpus_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) if (event->type == SDEI_EVENT_TYPE_SHARED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) err = sdei_api_event_register(event->event_num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) sdei_entry_point,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) event->registered,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) SDEI_EVENT_REGISTER_RM_ANY, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) err = sdei_do_cross_call(_local_event_register, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) sdei_do_cross_call(_local_event_unregister, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) sdei_event_destroy(event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) pr_warn("Failed to register event %u: %d\n", event_num, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) goto cpu_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) spin_lock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) event->reregister = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) spin_unlock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) cpu_unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) cpus_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) mutex_unlock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) static int sdei_reregister_shared(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) struct sdei_event *event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) mutex_lock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) spin_lock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) list_for_each_entry(event, &sdei_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) if (event->type != SDEI_EVENT_TYPE_SHARED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) if (event->reregister) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) err = sdei_api_event_register(event->event_num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) sdei_entry_point, event->registered,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) SDEI_EVENT_REGISTER_RM_ANY, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) pr_err("Failed to re-register event %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) event->event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) sdei_event_destroy_llocked(event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) if (event->reenable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) err = sdei_api_event_enable(event->event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) pr_err("Failed to re-enable event %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) event->event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) spin_unlock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) mutex_unlock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) static int sdei_cpuhp_down(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) struct sdei_event *event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) /* un-register private events */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) spin_lock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) list_for_each_entry(event, &sdei_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) if (event->type == SDEI_EVENT_TYPE_SHARED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) err = sdei_do_local_call(_local_event_unregister, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) pr_err("Failed to unregister event %u: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) event->event_num, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) spin_unlock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) return sdei_mask_local_cpu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) static int sdei_cpuhp_up(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) struct sdei_event *event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) /* re-register/enable private events */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) spin_lock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) list_for_each_entry(event, &sdei_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) if (event->type == SDEI_EVENT_TYPE_SHARED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) if (event->reregister) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) err = sdei_do_local_call(_local_event_register, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) pr_err("Failed to re-register event %u: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) event->event_num, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) if (event->reenable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) err = sdei_do_local_call(_local_event_enable, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) pr_err("Failed to re-enable event %u: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) event->event_num, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) spin_unlock(&sdei_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) return sdei_unmask_local_cpu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) /* When entering idle, mask/unmask events for this cpu */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) static int sdei_pm_notifier(struct notifier_block *nb, unsigned long action,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) switch (action) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) case CPU_PM_ENTER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) rv = sdei_mask_local_cpu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) case CPU_PM_EXIT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) case CPU_PM_ENTER_FAILED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) rv = sdei_unmask_local_cpu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) return notifier_from_errno(rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) return NOTIFY_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) static struct notifier_block sdei_pm_nb = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) .notifier_call = sdei_pm_notifier,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) static int sdei_device_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) on_each_cpu(_ipi_mask_cpu, NULL, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) static int sdei_device_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) on_each_cpu(_ipi_unmask_cpu, NULL, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) * We need all events to be reregistered when we resume from hibernate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) * The sequence is freeze->thaw. Reboot. freeze->restore. We unregister
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) * events during freeze, then re-register and re-enable them during thaw
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) * and restore.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) static int sdei_device_freeze(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) /* unregister private events */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) err = sdei_unregister_shared();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) static int sdei_device_thaw(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) /* re-register shared events */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) err = sdei_reregister_shared();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) pr_warn("Failed to re-register shared events...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) sdei_mark_interface_broken();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) &sdei_cpuhp_up, &sdei_cpuhp_down);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) pr_warn("Failed to re-register CPU hotplug notifier...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) static int sdei_device_restore(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) err = sdei_platform_reset();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) return sdei_device_thaw(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) static const struct dev_pm_ops sdei_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) .suspend = sdei_device_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) .resume = sdei_device_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) .freeze = sdei_device_freeze,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) .thaw = sdei_device_thaw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) .restore = sdei_device_restore,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) * Mask all CPUs and unregister all events on panic, reboot or kexec.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) static int sdei_reboot_notifier(struct notifier_block *nb, unsigned long action,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) * We are going to reset the interface, after this there is no point
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) * doing work when we take CPUs offline.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) sdei_platform_reset();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) return NOTIFY_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) static struct notifier_block sdei_reboot_nb = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) .notifier_call = sdei_reboot_notifier,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) static void sdei_smccc_smc(unsigned long function_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) unsigned long arg0, unsigned long arg1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) unsigned long arg2, unsigned long arg3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) unsigned long arg4, struct arm_smccc_res *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) NOKPROBE_SYMBOL(sdei_smccc_smc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) static void sdei_smccc_hvc(unsigned long function_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) unsigned long arg0, unsigned long arg1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) unsigned long arg2, unsigned long arg3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) unsigned long arg4, struct arm_smccc_res *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) arm_smccc_hvc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) NOKPROBE_SYMBOL(sdei_smccc_hvc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) sdei_event_callback *critical_cb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) u64 result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) u32 event_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) sdei_event_callback *cb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) event_num = ghes->generic->notify.vector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) if (event_num == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) * Event 0 is reserved by the specification for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) * SDEI_EVENT_SIGNAL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) &result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) if (result == SDEI_EVENT_PRIORITY_CRITICAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) cb = critical_cb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) cb = normal_cb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) err = sdei_event_register(event_num, cb, ghes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) err = sdei_event_enable(event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) int sdei_unregister_ghes(struct ghes *ghes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) u32 event_num = ghes->generic->notify.vector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) might_sleep();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) * The event may be running on another CPU. Disable it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) * to stop new events, then try to unregister a few times.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) err = sdei_event_disable(event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) for (i = 0; i < 3; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) err = sdei_event_unregister(event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) if (err != -EINPROGRESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) schedule();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) #ifdef CONFIG_FIQ_DEBUGGER_TRUST_ZONE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) int sdei_event_enable_nolock(u32 event_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) return sdei_api_event_enable(event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) int sdei_event_disable_nolock(u32 event_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) return sdei_api_event_disable(event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) int sdei_event_routing_set_nolock(u32 event_num, unsigned long flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) unsigned long affinity)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_ROUTING_SET, event_num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) (unsigned long)flags, (unsigned long)affinity,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) int sdei_event_routing_set(u32 event_num, unsigned long flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) unsigned long affinity)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) int err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) struct sdei_event *event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) mutex_lock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) event = sdei_event_find(event_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) if (!event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) mutex_unlock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) err = sdei_event_routing_set_nolock(event_num, flags, affinity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) mutex_unlock(&sdei_events_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) static int sdei_get_conduit(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) const char *method;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) struct device_node *np = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) sdei_firmware_call = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) if (np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) if (of_property_read_string(np, "method", &method)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) pr_warn("missing \"method\" property\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) return SMCCC_CONDUIT_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) if (!strcmp("hvc", method)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) sdei_firmware_call = &sdei_smccc_hvc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) return SMCCC_CONDUIT_HVC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) } else if (!strcmp("smc", method)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) sdei_firmware_call = &sdei_smccc_smc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) return SMCCC_CONDUIT_SMC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) pr_warn("invalid \"method\" property: %s\n", method);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) } else if (!acpi_disabled) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) if (acpi_psci_use_hvc()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) sdei_firmware_call = &sdei_smccc_hvc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) return SMCCC_CONDUIT_HVC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) sdei_firmware_call = &sdei_smccc_smc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) return SMCCC_CONDUIT_SMC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) return SMCCC_CONDUIT_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) static int sdei_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) u64 ver = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) int conduit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) conduit = sdei_get_conduit(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) if (!sdei_firmware_call)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) err = sdei_api_get_version(&ver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) pr_err("Failed to get SDEI version: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) sdei_mark_interface_broken();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) pr_info("SDEIv%d.%d (0x%x) detected in firmware.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) (int)SDEI_VERSION_MAJOR(ver), (int)SDEI_VERSION_MINOR(ver),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) (int)SDEI_VERSION_VENDOR(ver));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) if (SDEI_VERSION_MAJOR(ver) != 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) pr_warn("Conflicting SDEI version detected.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) sdei_mark_interface_broken();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) err = sdei_platform_reset();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) sdei_entry_point = sdei_arch_get_entry_point(conduit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) if (!sdei_entry_point) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) /* Not supported due to hardware or boot configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) sdei_mark_interface_broken();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) err = cpu_pm_register_notifier(&sdei_pm_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) pr_warn("Failed to register CPU PM notifier...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) err = register_reboot_notifier(&sdei_reboot_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) pr_warn("Failed to register reboot notifier...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) goto remove_cpupm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) &sdei_cpuhp_up, &sdei_cpuhp_down);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) pr_warn("Failed to register CPU hotplug notifier...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) goto remove_reboot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) remove_reboot:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) unregister_reboot_notifier(&sdei_reboot_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) remove_cpupm:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) cpu_pm_unregister_notifier(&sdei_pm_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) sdei_mark_interface_broken();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) static const struct of_device_id sdei_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) { .compatible = "arm,sdei-1.0" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) static struct platform_driver sdei_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) .name = "sdei",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) .pm = &sdei_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) .of_match_table = sdei_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) .probe = sdei_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) static bool __init sdei_present_acpi(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) struct acpi_table_header *sdei_table_header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) if (acpi_disabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) status = acpi_get_table(ACPI_SIG_SDEI, 0, &sdei_table_header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) const char *msg = acpi_format_exception(status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) pr_info("Failed to get ACPI:SDEI table, %s\n", msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) acpi_put_table(sdei_table_header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) static int __init sdei_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) struct platform_device *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) ret = platform_driver_register(&sdei_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) if (ret || !sdei_present_acpi())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) pdev = platform_device_register_simple(sdei_driver.driver.name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) 0, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) if (IS_ERR(pdev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) ret = PTR_ERR(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) platform_driver_unregister(&sdei_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) pr_info("Failed to register ACPI:SDEI platform device %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) * On an ACPI system SDEI needs to be ready before HEST:GHES tries to register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) * its events. ACPI is initialised from a subsys_initcall(), GHES is initialised
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) * by device_initcall(). We want to be called in the middle.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) subsys_initcall_sync(sdei_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) int sdei_event_handler(struct pt_regs *regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) struct sdei_registered_event *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) mm_segment_t orig_addr_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) u32 event_num = arg->event_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) * Save restore 'fs'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) * The architecture's entry code save/restores 'fs' when taking an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) * exception from the kernel. This ensures addr_limit isn't inherited
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) * if you interrupted something that allowed the uaccess routines to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) * access kernel memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) * Do the same here because this doesn't come via the same entry code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) orig_addr_limit = force_uaccess_begin();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) err = arg->callback(event_num, regs, arg->callback_arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) pr_err_ratelimited("event %u on CPU %u failed with error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) event_num, smp_processor_id(), err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) force_uaccess_end(orig_addr_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) NOKPROBE_SYMBOL(sdei_event_handler);