Loading...
Note: File does not exist in v3.1.
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Pvpanic Device Support
4 *
5 * Copyright (C) 2013 Fujitsu.
6 * Copyright (C) 2018 ZTE.
7 * Copyright (C) 2021 Oracle.
8 */
9
10#include <linux/io.h>
11#include <linux/kernel.h>
12#include <linux/kexec.h>
13#include <linux/mod_devicetable.h>
14#include <linux/module.h>
15#include <linux/platform_device.h>
16#include <linux/panic_notifier.h>
17#include <linux/types.h>
18#include <linux/cdev.h>
19#include <linux/list.h>
20
21#include <uapi/misc/pvpanic.h>
22
23#include "pvpanic.h"
24
25MODULE_AUTHOR("Mihai Carabas <mihai.carabas@oracle.com>");
26MODULE_DESCRIPTION("pvpanic device driver ");
27MODULE_LICENSE("GPL");
28
29static struct list_head pvpanic_list;
30static spinlock_t pvpanic_lock;
31
32static void
33pvpanic_send_event(unsigned int event)
34{
35 struct pvpanic_instance *pi_cur;
36
37 spin_lock(&pvpanic_lock);
38 list_for_each_entry(pi_cur, &pvpanic_list, list) {
39 if (event & pi_cur->capability & pi_cur->events)
40 iowrite8(event, pi_cur->base);
41 }
42 spin_unlock(&pvpanic_lock);
43}
44
45static int
46pvpanic_panic_notify(struct notifier_block *nb, unsigned long code,
47 void *unused)
48{
49 unsigned int event = PVPANIC_PANICKED;
50
51 if (kexec_crash_loaded())
52 event = PVPANIC_CRASH_LOADED;
53
54 pvpanic_send_event(event);
55
56 return NOTIFY_DONE;
57}
58
59static struct notifier_block pvpanic_panic_nb = {
60 .notifier_call = pvpanic_panic_notify,
61 .priority = 1, /* let this called before broken drm_fb_helper */
62};
63
64static void pvpanic_remove(void *param)
65{
66 struct pvpanic_instance *pi_cur, *pi_next;
67 struct pvpanic_instance *pi = param;
68
69 spin_lock(&pvpanic_lock);
70 list_for_each_entry_safe(pi_cur, pi_next, &pvpanic_list, list) {
71 if (pi_cur == pi) {
72 list_del(&pi_cur->list);
73 break;
74 }
75 }
76 spin_unlock(&pvpanic_lock);
77}
78
79int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi)
80{
81 if (!pi || !pi->base)
82 return -EINVAL;
83
84 spin_lock(&pvpanic_lock);
85 list_add(&pi->list, &pvpanic_list);
86 spin_unlock(&pvpanic_lock);
87
88 dev_set_drvdata(dev, pi);
89
90 return devm_add_action_or_reset(dev, pvpanic_remove, pi);
91}
92EXPORT_SYMBOL_GPL(devm_pvpanic_probe);
93
94static int pvpanic_init(void)
95{
96 INIT_LIST_HEAD(&pvpanic_list);
97 spin_lock_init(&pvpanic_lock);
98
99 atomic_notifier_chain_register(&panic_notifier_list,
100 &pvpanic_panic_nb);
101
102 return 0;
103}
104
105static void pvpanic_exit(void)
106{
107 atomic_notifier_chain_unregister(&panic_notifier_list,
108 &pvpanic_panic_nb);
109
110}
111
112module_init(pvpanic_init);
113module_exit(pvpanic_exit);