aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/powernv/opal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/powernv/opal.c')
-rw-r--r--arch/powerpc/platforms/powernv/opal.c69
1 files changed, 68 insertions, 1 deletions
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 628c564ceadb..106301fd2fa5 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -15,6 +15,7 @@
15#include <linux/of.h> 15#include <linux/of.h>
16#include <linux/of_platform.h> 16#include <linux/of_platform.h>
17#include <linux/interrupt.h> 17#include <linux/interrupt.h>
18#include <linux/notifier.h>
18#include <linux/slab.h> 19#include <linux/slab.h>
19#include <asm/opal.h> 20#include <asm/opal.h>
20#include <asm/firmware.h> 21#include <asm/firmware.h>
@@ -31,6 +32,10 @@ static DEFINE_SPINLOCK(opal_write_lock);
31extern u64 opal_mc_secondary_handler[]; 32extern u64 opal_mc_secondary_handler[];
32static unsigned int *opal_irqs; 33static unsigned int *opal_irqs;
33static unsigned int opal_irq_count; 34static unsigned int opal_irq_count;
35static ATOMIC_NOTIFIER_HEAD(opal_notifier_head);
36static DEFINE_SPINLOCK(opal_notifier_lock);
37static uint64_t last_notified_mask = 0x0ul;
38static atomic_t opal_notifier_hold = ATOMIC_INIT(0);
34 39
35int __init early_init_dt_scan_opal(unsigned long node, 40int __init early_init_dt_scan_opal(unsigned long node,
36 const char *uname, int depth, void *data) 41 const char *uname, int depth, void *data)
@@ -95,6 +100,68 @@ static int __init opal_register_exception_handlers(void)
95 100
96early_initcall(opal_register_exception_handlers); 101early_initcall(opal_register_exception_handlers);
97 102
103int opal_notifier_register(struct notifier_block *nb)
104{
105 if (!nb) {
106 pr_warning("%s: Invalid argument (%p)\n",
107 __func__, nb);
108 return -EINVAL;
109 }
110
111 atomic_notifier_chain_register(&opal_notifier_head, nb);
112 return 0;
113}
114
115static void opal_do_notifier(uint64_t events)
116{
117 unsigned long flags;
118 uint64_t changed_mask;
119
120 if (atomic_read(&opal_notifier_hold))
121 return;
122
123 spin_lock_irqsave(&opal_notifier_lock, flags);
124 changed_mask = last_notified_mask ^ events;
125 last_notified_mask = events;
126 spin_unlock_irqrestore(&opal_notifier_lock, flags);
127
128 /*
129 * We feed with the event bits and changed bits for
130 * enough information to the callback.
131 */
132 atomic_notifier_call_chain(&opal_notifier_head,
133 events, (void *)changed_mask);
134}
135
136void opal_notifier_update_evt(uint64_t evt_mask,
137 uint64_t evt_val)
138{
139 unsigned long flags;
140
141 spin_lock_irqsave(&opal_notifier_lock, flags);
142 last_notified_mask &= ~evt_mask;
143 last_notified_mask |= evt_val;
144 spin_unlock_irqrestore(&opal_notifier_lock, flags);
145}
146
147void opal_notifier_enable(void)
148{
149 int64_t rc;
150 uint64_t evt = 0;
151
152 atomic_set(&opal_notifier_hold, 0);
153
154 /* Process pending events */
155 rc = opal_poll_events(&evt);
156 if (rc == OPAL_SUCCESS && evt)
157 opal_do_notifier(evt);
158}
159
160void opal_notifier_disable(void)
161{
162 atomic_set(&opal_notifier_hold, 1);
163}
164
98int opal_get_chars(uint32_t vtermno, char *buf, int count) 165int opal_get_chars(uint32_t vtermno, char *buf, int count)
99{ 166{
100 s64 len, rc; 167 s64 len, rc;
@@ -297,7 +364,7 @@ static irqreturn_t opal_interrupt(int irq, void *data)
297 364
298 opal_handle_interrupt(virq_to_hw(irq), &events); 365 opal_handle_interrupt(virq_to_hw(irq), &events);
299 366
300 /* XXX TODO: Do something with the events */ 367 opal_do_notifier(events);
301 368
302 return IRQ_HANDLED; 369 return IRQ_HANDLED;
303} 370}