diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-10-24 10:06:49 +1100 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-10-24 10:07:19 +1100 |
commit | 531bdefda91102cb3240e4e3289900af0a50e78b (patch) | |
tree | cc95231a4ce4a0ae05e7d123eaac4bd9beedef2d /core/opal.c | |
parent | bed82938878cff16c539c1c6b3887b2cf65b4f57 (diff) | |
download | skiboot-531bdefda91102cb3240e4e3289900af0a50e78b.zip skiboot-531bdefda91102cb3240e4e3289900af0a50e78b.tar.gz skiboot-531bdefda91102cb3240e4e3289900af0a50e78b.tar.bz2 |
irq/occ/opal: Add self-sent dummy interrupt
This makes OPAL use the OCC interrupt facility to send itself an interrupt
whenever the OPAL event bit is set as a result of an OPAL call that wasn't
itself opal_handle_interrupt() or opal_handle_hmi() (both of which we know
the OS will already deal with appropriately).
This ensures that OPAL event changes are notified to Linux via its
interrupt path which is necessary for it to properly broadcast the state
change to its various clients.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'core/opal.c')
-rw-r--r-- | core/opal.c | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/core/opal.c b/core/opal.c index 4ad322c..f6bd00d 100644 --- a/core/opal.c +++ b/core/opal.c @@ -157,11 +157,26 @@ void opal_update_pending_evt(uint64_t evt_mask, uint64_t evt_values) /* XXX FIXME: Use atomics instead ??? Or caller locks (con_lock ?) */ lock(&evt_lock); new_evts = (opal_pending_events & ~evt_mask) | evt_values; + if (opal_pending_events != new_evts) { + uint64_t tok; + #ifdef OPAL_TRACE_EVT_CHG - printf("OPAL: Evt change: 0x%016llx -> 0x%016llx\n", - opal_pending_events, new_evts); + printf("OPAL: Evt change: 0x%016llx -> 0x%016llx\n", + opal_pending_events, new_evts); #endif - opal_pending_events = new_evts; + /* + * If an event gets *set* while we are in a different call chain + * than opal_handle_interrupt() or opal_handle_hmi(), then we + * artificially generate an interrupt (OCC interrupt specifically) + * to ensure that Linux properly broadcast the event change internally + */ + if ((new_evts & ~opal_pending_events) != 0) { + tok = this_cpu()->current_token; + if (tok != OPAL_HANDLE_INTERRUPT && tok != OPAL_HANDLE_HMI) + occ_send_dummy_interrupt(); + } + opal_pending_events = new_evts; + } unlock(&evt_lock); } |