aboutsummaryrefslogtreecommitdiff
path: root/hw/occ.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-24 10:06:49 +1100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-24 10:07:19 +1100
commit531bdefda91102cb3240e4e3289900af0a50e78b (patch)
treecc95231a4ce4a0ae05e7d123eaac4bd9beedef2d /hw/occ.c
parentbed82938878cff16c539c1c6b3887b2cf65b4f57 (diff)
downloadskiboot-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 'hw/occ.c')
-rw-r--r--hw/occ.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/hw/occ.c b/hw/occ.c
index f1a7a27..74c9deb 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -480,6 +480,48 @@ static struct fsp_client fsp_occ_client = {
.message = fsp_occ_msg,
};
+#define OCB_OCI_OCCMISC 0x6a020
+#define OCB_OCI_OCCMISC_AND 0x6a021
+#define OCB_OCI_OCCMISC_OR 0x6a022
+#define OCB_OCI_OCIMISC_IRQ PPC_BIT(0)
+#define OCB_OCI_OCIMISC_IRQ_TMGT PPC_BIT(1)
+#define OCB_OCI_OCIMISC_IRQ_OPAL_DUMMY PPC_BIT(15)
+
+void occ_send_dummy_interrupt(void)
+{
+ xscom_writeme(OCB_OCI_OCCMISC_OR,
+ OCB_OCI_OCIMISC_IRQ |
+ OCB_OCI_OCIMISC_IRQ_OPAL_DUMMY);
+}
+
+static void occ_tmgt_interrupt(void)
+{
+ /* Not currently expected */
+ printf("OCC: TMGT interrupt !\n");
+}
+
+void occ_interrupt(void)
+{
+ uint64_t ireg;
+ int64_t rc;
+
+ /* The OCC interrupt is used to mux up to 15 different sources */
+ rc = xscom_readme(OCB_OCI_OCCMISC, &ireg);
+ if (rc) {
+ prerror("OCC: Failed to read interrupt status !\n");
+ /* Should we mask it in the XIVR ? */
+ return;
+ }
+ prlog(PR_TRACE, "OCC: IRQ received: %04llx\n", ireg >> 48);
+
+ /* Clear the bits */
+ xscom_writeme(OCB_OCI_OCCMISC_AND, ~ireg);
+
+ /* Dispatch */
+ if (ireg & OCB_OCI_OCIMISC_IRQ_TMGT)
+ occ_tmgt_interrupt();
+}
+
void occ_fsp_init(void)
{
/* OCC is P8 only */