1 // SPDX-License-Identifier: GPL-2.0+
3 * Pvpanic Device Support
5 * Copyright (C) 2013 Fujitsu.
6 * Copyright (C) 2018 ZTE.
7 * Copyright (C) 2021 Oracle.
10 #include <linux/device.h>
11 #include <linux/errno.h>
12 #include <linux/gfp_types.h>
14 #include <linux/kexec.h>
15 #include <linux/kstrtox.h>
16 #include <linux/limits.h>
17 #include <linux/list.h>
18 #include <linux/mod_devicetable.h>
19 #include <linux/module.h>
20 #include <linux/panic_notifier.h>
21 #include <linux/platform_device.h>
22 #include <linux/reboot.h>
23 #include <linux/spinlock.h>
24 #include <linux/sysfs.h>
25 #include <linux/types.h>
27 #include <uapi/misc/pvpanic.h>
31 MODULE_AUTHOR("Mihai Carabas <mihai.carabas@oracle.com>");
32 MODULE_DESCRIPTION("pvpanic device driver");
33 MODULE_LICENSE("GPL");
35 struct pvpanic_instance
{
37 unsigned int capability
;
39 struct sys_off_handler
*sys_off
;
40 struct list_head list
;
43 static struct list_head pvpanic_list
;
44 static spinlock_t pvpanic_lock
;
47 pvpanic_send_event(unsigned int event
)
49 struct pvpanic_instance
*pi_cur
;
51 if (!spin_trylock(&pvpanic_lock
))
54 list_for_each_entry(pi_cur
, &pvpanic_list
, list
) {
55 if (event
& pi_cur
->capability
& pi_cur
->events
)
56 iowrite8(event
, pi_cur
->base
);
58 spin_unlock(&pvpanic_lock
);
62 pvpanic_panic_notify(struct notifier_block
*nb
, unsigned long code
, void *unused
)
64 unsigned int event
= PVPANIC_PANICKED
;
66 if (kexec_crash_loaded())
67 event
= PVPANIC_CRASH_LOADED
;
69 pvpanic_send_event(event
);
75 * Call our notifier very early on panic, deferring the
76 * action taken to the hypervisor.
78 static struct notifier_block pvpanic_panic_nb
= {
79 .notifier_call
= pvpanic_panic_notify
,
83 static int pvpanic_sys_off(struct sys_off_data
*data
)
85 pvpanic_send_event(PVPANIC_SHUTDOWN
);
90 static void pvpanic_synchronize_sys_off_handler(struct device
*dev
, struct pvpanic_instance
*pi
)
92 /* The kernel core has logic to fall back to system halt if no
93 * sys_off_handler is registered.
94 * When the pvpanic sys_off_handler is disabled via sysfs the kernel
95 * should use that fallback logic, so the handler needs to be unregistered.
98 struct sys_off_handler
*sys_off
;
100 if (!(pi
->events
& PVPANIC_SHUTDOWN
) == !pi
->sys_off
)
104 sys_off
= register_sys_off_handler(SYS_OFF_MODE_POWER_OFF
, SYS_OFF_PRIO_LOW
,
105 pvpanic_sys_off
, NULL
);
107 dev_warn(dev
, "Could not register sys_off_handler: %pe\n", sys_off
);
109 pi
->sys_off
= sys_off
;
111 unregister_sys_off_handler(pi
->sys_off
);
116 static void pvpanic_remove(void *param
)
118 struct pvpanic_instance
*pi_cur
, *pi_next
;
119 struct pvpanic_instance
*pi
= param
;
121 spin_lock(&pvpanic_lock
);
122 list_for_each_entry_safe(pi_cur
, pi_next
, &pvpanic_list
, list
) {
124 list_del(&pi_cur
->list
);
128 spin_unlock(&pvpanic_lock
);
130 unregister_sys_off_handler(pi
->sys_off
);
133 static ssize_t
capability_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
135 struct pvpanic_instance
*pi
= dev_get_drvdata(dev
);
137 return sysfs_emit(buf
, "%x\n", pi
->capability
);
139 static DEVICE_ATTR_RO(capability
);
141 static ssize_t
events_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
143 struct pvpanic_instance
*pi
= dev_get_drvdata(dev
);
145 return sysfs_emit(buf
, "%x\n", pi
->events
);
148 static ssize_t
events_store(struct device
*dev
, struct device_attribute
*attr
,
149 const char *buf
, size_t count
)
151 struct pvpanic_instance
*pi
= dev_get_drvdata(dev
);
155 err
= kstrtouint(buf
, 16, &tmp
);
159 if ((tmp
& pi
->capability
) != tmp
)
163 pvpanic_synchronize_sys_off_handler(dev
, pi
);
167 static DEVICE_ATTR_RW(events
);
169 static struct attribute
*pvpanic_dev_attrs
[] = {
170 &dev_attr_capability
.attr
,
171 &dev_attr_events
.attr
,
175 static const struct attribute_group pvpanic_dev_group
= {
176 .attrs
= pvpanic_dev_attrs
,
179 const struct attribute_group
*pvpanic_dev_groups
[] = {
183 EXPORT_SYMBOL_GPL(pvpanic_dev_groups
);
185 int devm_pvpanic_probe(struct device
*dev
, void __iomem
*base
)
187 struct pvpanic_instance
*pi
;
192 pi
= devm_kmalloc(dev
, sizeof(*pi
), GFP_KERNEL
);
197 pi
->capability
= PVPANIC_PANICKED
| PVPANIC_CRASH_LOADED
| PVPANIC_SHUTDOWN
;
199 /* initlize capability by RDPT */
200 pi
->capability
&= ioread8(base
);
201 pi
->events
= pi
->capability
;
204 pvpanic_synchronize_sys_off_handler(dev
, pi
);
206 spin_lock(&pvpanic_lock
);
207 list_add(&pi
->list
, &pvpanic_list
);
208 spin_unlock(&pvpanic_lock
);
210 dev_set_drvdata(dev
, pi
);
212 return devm_add_action_or_reset(dev
, pvpanic_remove
, pi
);
214 EXPORT_SYMBOL_GPL(devm_pvpanic_probe
);
216 static int pvpanic_init(void)
218 INIT_LIST_HEAD(&pvpanic_list
);
219 spin_lock_init(&pvpanic_lock
);
221 atomic_notifier_chain_register(&panic_notifier_list
, &pvpanic_panic_nb
);
225 module_init(pvpanic_init
);
227 static void pvpanic_exit(void)
229 atomic_notifier_chain_unregister(&panic_notifier_list
, &pvpanic_panic_nb
);
232 module_exit(pvpanic_exit
);