summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2008-04-03 19:41:21 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2008-04-03 19:41:21 +0000
commit25713af802cddeafae65918278e5be5d223498fd (patch)
tree560f3cff6dcced54e674376ffdea857a2273e7b3
parentc7c3afede8ed8d78a1e13d88210863785aad1e22 (diff)
Make ebus(4) work on sun4v.
-rw-r--r--sys/arch/sparc64/dev/ebus_mainbus.c94
1 files changed, 79 insertions, 15 deletions
diff --git a/sys/arch/sparc64/dev/ebus_mainbus.c b/sys/arch/sparc64/dev/ebus_mainbus.c
index 5d62eeb7b1e..82e5d91b562 100644
--- a/sys/arch/sparc64/dev/ebus_mainbus.c
+++ b/sys/arch/sparc64/dev/ebus_mainbus.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ebus_mainbus.c,v 1.5 2008/04/03 18:08:04 kettenis Exp $ */
+/* $OpenBSD: ebus_mainbus.c,v 1.6 2008/04/03 19:41:20 kettenis Exp $ */
/*
* Copyright (c) 2007 Mark Kettenis
@@ -41,6 +41,7 @@ extern int ebus_debug;
#define _SPARC_BUS_DMA_PRIVATE
#include <machine/bus.h>
#include <machine/autoconf.h>
+#include <machine/hypervisor.h>
#include <machine/openfirm.h>
#include <dev/pci/pcivar.h>
@@ -65,7 +66,7 @@ int ebus_mainbus_bus_map(bus_space_tag_t, bus_space_tag_t,
void *ebus_mainbus_intr_establish(bus_space_tag_t, bus_space_tag_t,
int, int, int, int (*)(void *), void *, const char *);
bus_space_tag_t ebus_alloc_bus_tag(struct ebus_softc *, bus_space_tag_t);
-
+void ebus_mainbus_intr_ack(struct intrhand *);
int
ebus_mainbus_match(struct device *parent, void *match, void *aux)
@@ -91,21 +92,23 @@ ebus_mainbus_attach(struct device *parent, struct device *self, void *aux)
sc->sc_node = node = ma->ma_node;
sc->sc_ign = INTIGN((ma->ma_upaid) << INTMAP_IGN_SHIFT);
- printf(": ign %x", sc->sc_ign);
-
- for (i = 0; i < pyro_cd.cd_ndevs; i++) {
- psc = pyro_cd.cd_devs[i];
- if (psc && psc->sc_ign == sc->sc_ign) {
- sc->sc_bust = psc->sc_bust;
- sc->sc_csr = psc->sc_csr;
- sc->sc_csrh = psc->sc_csrh;
- break;
+ if (CPU_ISSUN4U) {
+ printf(": ign %x", sc->sc_ign);
+
+ for (i = 0; i < pyro_cd.cd_ndevs; i++) {
+ psc = pyro_cd.cd_devs[i];
+ if (psc && psc->sc_ign == sc->sc_ign) {
+ sc->sc_bust = psc->sc_bust;
+ sc->sc_csr = psc->sc_csr;
+ sc->sc_csrh = psc->sc_csrh;
+ break;
+ }
}
- }
- if (sc->sc_csr == 0) {
- printf(": can't find matching host bridge leaf\n");
- return;
+ if (sc->sc_csr == 0) {
+ printf(": can't find matching host bridge leaf\n");
+ return;
+ }
}
printf("\n");
@@ -244,6 +247,57 @@ ebus_mainbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
int ino;
+#ifdef SUN4V
+ if (CPU_ISSUN4V) {
+ struct upa_reg reg;
+ u_int64_t devhandle, devino = INTINO(ihandle);
+ u_int64_t sysino;
+ int node = -1;
+ int i, err;
+
+ for (i = 0; i < sc->sc_nintmap; i++) {
+ if (sc->sc_intmap[i].cintr == ihandle) {
+ node = sc->sc_intmap[i].cnode;
+ break;
+ }
+ }
+ if (node == -1)
+ return (NULL);
+
+ if (OF_getprop(node, "reg", &reg, sizeof(reg)) != sizeof(reg))
+ return (NULL);
+ devhandle = (reg.ur_paddr >> 32) & 0x0fffffff;
+
+ err = hv_intr_devino_to_sysino(devhandle, devino, &sysino);
+ if (err != H_EOK)
+ return (NULL);
+
+ KASSERT(sysino == INTVEC(sysino));
+ ih = bus_intr_allocate(t0, handler, arg, sysino, level,
+ NULL, NULL, what);
+ if (ih == NULL)
+ return (NULL);
+
+ intr_establish(ih->ih_pil, ih);
+ ih->ih_ack = ebus_mainbus_intr_ack;
+
+ err = hv_intr_settarget(sysino, cpus->ci_upaid);
+ if (err != H_EOK)
+ return (NULL);
+
+ /* Clear pending interrupts. */
+ err = hv_intr_setstate(sysino, INTR_IDLE);
+ if (err != H_EOK)
+ return (NULL);
+
+ err = hv_intr_setenabled(sysino, INTR_ENABLED);
+ if (err != H_EOK)
+ return (NULL);
+
+ return (ih);
+ }
+#endif
+
ihandle |= sc->sc_ign;
ino = INTINO(ihandle);
@@ -278,3 +332,13 @@ ebus_mainbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
return (ih);
}
+
+#ifdef SUN4V
+
+void
+ebus_mainbus_intr_ack(struct intrhand *ih)
+{
+ hv_intr_setstate(ih->ih_number, INTR_IDLE);
+}
+
+#endif