summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2020-06-26 19:06:36 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2020-06-26 19:06:36 +0000
commit80b0adb1d96205b461acdab0c0cd9c635314911e (patch)
tree42f0a935d07f5559d9366c91e40ba69909bef190 /sys
parent9016577cb08f7e227391be4cdfa9888f2202e9b7 (diff)
Handle OPAL interrupts.
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/powerpc64/dev/opal.c118
-rw-r--r--sys/arch/powerpc64/include/opal.h9
2 files changed, 124 insertions, 3 deletions
diff --git a/sys/arch/powerpc64/dev/opal.c b/sys/arch/powerpc64/dev/opal.c
index 5e8f97fbed9..318268b33d6 100644
--- a/sys/arch/powerpc64/dev/opal.c
+++ b/sys/arch/powerpc64/dev/opal.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: opal.c,v 1.4 2020/06/22 21:13:40 kettenis Exp $ */
+/* $OpenBSD: opal.c,v 1.5 2020/06/26 19:06:35 kettenis Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
*
@@ -16,8 +16,9 @@
*/
#include <sys/param.h>
-#include <sys/systm.h>
#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
#include <machine/bus.h>
#include <machine/fdt.h>
@@ -28,11 +29,32 @@
#include <dev/ofw/openfirm.h>
#include <dev/ofw/fdt.h>
+#define OPAL_NUM_HANDLERS 4
+
+struct opal_intr {
+ struct opal_softc *oi_sc;
+ uint32_t oi_isn;
+};
+
+struct intrhand {
+ uint64_t ih_events;
+ int (*ih_func)(void *);
+ void *ih_arg;
+};
+
struct opal_softc {
struct device sc_dev;
+
+ struct opal_intr *sc_intr;
+ int sc_nintr;
+
+ struct intrhand *sc_handler[OPAL_NUM_HANDLERS];
+
struct todr_chip_handle sc_todr;
};
+struct opal_softc *opal_sc;
+
int opal_match(struct device *, void *, void *);
void opal_attach(struct device *, struct device *, void *);
@@ -44,6 +66,7 @@ struct cfdriver opal_cd = {
NULL, "opal", DV_DULL
};
+void opal_attach_deferred(struct device *);
void opal_attach_node(struct opal_softc *, int);
int opal_gettime(struct todr_chip_handle *, struct timeval *);
int opal_settime(struct todr_chip_handle *, struct timeval *);
@@ -61,6 +84,8 @@ opal_attach(struct device *parent, struct device *self, void *aux)
{
struct opal_softc *sc = (struct opal_softc *)self;
struct fdt_attach_args *faa = aux;
+ uint32_t *interrupts;
+ int len, i;
int node;
node = OF_getnodebyname(faa->fa_node, "firmware");
@@ -73,8 +98,37 @@ opal_attach(struct device *parent, struct device *self, void *aux)
printf(": %s", version);
}
+ len = OF_getproplen(faa->fa_node, "opal-interrupts");
+ if (len > 0 && (len % sizeof(uint32_t)) != 0) {
+ printf(": can't parse interrupts\n");
+ return;
+ }
+
printf("\n");
+ /* There can be only one. */
+ KASSERT(opal_sc == NULL);
+ opal_sc = sc;
+
+ if (len > 0) {
+ interrupts = malloc(len, M_TEMP, M_WAITOK);
+ OF_getpropintarray(faa->fa_node, "opal-interrupts",
+ interrupts, len);
+ sc->sc_nintr = len / sizeof(uint32_t);
+
+ sc->sc_intr = mallocarray(sc->sc_nintr,
+ sizeof(struct opal_intr), M_DEVBUF, M_WAITOK);
+
+ for (i = 0; i < sc->sc_nintr; i++) {
+ sc->sc_intr[i].oi_sc = sc;
+ sc->sc_intr[i].oi_isn = interrupts[i];
+ }
+
+ free(interrupts, M_TEMP, len);
+
+ config_defer(self, opal_attach_deferred);
+ }
+
sc->sc_todr.todr_gettime = opal_gettime;
sc->sc_todr.todr_settime = opal_settime;
todr_attach(&sc->sc_todr);
@@ -87,6 +141,66 @@ opal_attach(struct device *parent, struct device *self, void *aux)
}
int
+opal_intr(void *arg)
+{
+ struct opal_intr *oi = arg;
+ struct opal_softc *sc = oi->oi_sc;
+ uint64_t events = 0;
+ int i;
+
+ opal_handle_interrupt(oi->oi_isn, opal_phys(&events));
+
+ /* Handle registered events. */
+ for (i = 0; i < OPAL_NUM_HANDLERS; i++) {
+ struct intrhand *ih = sc->sc_handler[i];
+
+ if (ih == NULL)
+ continue;
+ if ((events & ih->ih_events) == 0)
+ continue;
+
+ ih->ih_func(ih->ih_arg);
+ }
+
+ return 1;
+}
+
+void *
+opal_intr_establish(uint64_t events, int level, int (*func)(void *), void *arg)
+{
+ struct opal_softc *sc = opal_sc;
+ struct intrhand *ih;
+ int i;
+
+ for (i = 0; i < OPAL_NUM_HANDLERS; i++) {
+ if (sc->sc_handler[i] == NULL)
+ break;
+ }
+ if (i == OPAL_NUM_HANDLERS)
+ return NULL;
+
+ ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
+ ih->ih_events = events;
+ ih->ih_func = func;
+ ih->ih_arg = arg;
+ sc->sc_handler[i] = ih;
+
+ return ih;
+}
+
+void
+opal_attach_deferred(struct device *self)
+{
+ struct opal_softc *sc = (struct opal_softc *)self;
+ int i;
+
+ for (i = 0; i < sc->sc_nintr; i++) {
+ intr_establish(sc->sc_intr[i].oi_isn, IST_LEVEL, IPL_BIO,
+ opal_intr, &sc->sc_intr[i], sc->sc_dev.dv_xname);
+ }
+}
+
+int
opal_print(void *aux, const char *pnp)
{
struct fdt_attach_args *faa = aux;
diff --git a/sys/arch/powerpc64/include/opal.h b/sys/arch/powerpc64/include/opal.h
index 741cde370a1..af0e92f0298 100644
--- a/sys/arch/powerpc64/include/opal.h
+++ b/sys/arch/powerpc64/include/opal.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: opal.h,v 1.10 2020/06/14 17:56:54 kettenis Exp $ */
+/* $OpenBSD: opal.h,v 1.11 2020/06/26 19:06:35 kettenis Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -27,6 +27,7 @@
#define OPAL_RTC_WRITE 4
#define OPAL_CEC_POWER_DOWN 5
#define OPAL_CEC_REBOOT 6
+#define OPAL_HANDLE_INTERRUPT 9
#define OPAL_POLL_EVENTS 10
#define OPAL_PCI_CONFIG_READ_WORD 15
#define OPAL_PCI_CONFIG_WRITE_WORD 18
@@ -69,6 +70,9 @@
#define OPAL_WRONG_STATE -14
#define OPAL_ASYNC_COMPLETION -15
+/* OPAL_POLL_EVENT */
+#define OPAL_EVENT_CONSOLE_INPUT 0x00000010
+
/* OPAL_PCI_EEH_FREEZE_CLEAR */
#define OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO 1
#define OPAL_EEH_ACTION_CLEAR_FREEZE_DMA 2
@@ -141,6 +145,7 @@ int64_t opal_rtc_read(uint32_t *, uint64_t *);
int64_t opal_rtc_write(uint32_t, uint64_t);
int64_t opal_cec_power_down(uint64_t);
int64_t opal_cec_reboot(void);
+int64_t opal_handle_interrupt(uint32_t, uint64_t *);
int64_t opal_poll_events(uint64_t *);
int64_t opal_pci_config_read_word(uint64_t, uint64_t, uint64_t, uint32_t *);
int64_t opal_pci_config_write_word(uint64_t, uint64_t, uint64_t, uint32_t);
@@ -178,6 +183,8 @@ int64_t opal_xive_dump(uint32_t, uint32_t);
void opal_printf(const char *fmt, ...);
+void *opal_intr_establish(uint64_t, int, int (*)(void *), void *);
+
#endif
#endif /* _MACHINE_OPAL_H_ */