Implement support for using interrupt cookies in vbus(4) and vpci(4) as
authorkettenis <kettenis@openbsd.org>
Wed, 6 Dec 2017 16:20:53 +0000 (16:20 +0000)
committerkettenis <kettenis@openbsd.org>
Wed, 6 Dec 2017 16:20:53 +0000 (16:20 +0000)
introduced in version 3.0 of the Interrupt APIs group.  This makes it possible
boot OpenBSD on SPARC T7/M7 hardware (although there still may be issues with
the onboard mpii(4) controller).

sys/arch/sparc64/dev/vbus.c
sys/arch/sparc64/dev/vpci.c
sys/arch/sparc64/include/hypervisor.h
sys/arch/sparc64/sparc64/autoconf.c
sys/arch/sparc64/sparc64/intr.c

index 35f65a9..85260dd 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: vbus.c,v 1.8 2015/09/27 11:29:20 kettenis Exp $       */
+/*     $OpenBSD: vbus.c,v 1.9 2017/12/06 16:20:53 kettenis Exp $       */
 /*
  * Copyright (c) 2008 Mark Kettenis
  *
@@ -33,6 +33,8 @@ struct vbus_softc {
        struct device           sc_dv;
        bus_space_tag_t         sc_bustag;
        bus_dma_tag_t           sc_dmatag;
+
+       uint64_t                sc_devhandle;
 };
 
 int    vbus_cmp_cells(int *, int *, int *, int);
@@ -73,6 +75,7 @@ vbus_attach(struct device *parent, struct device *self, void *aux)
 
        sc->sc_bustag = vbus_alloc_bus_tag(sc, ma->ma_bustag);
        sc->sc_dmatag = ma->ma_dmatag;
+       sc->sc_devhandle = (ma->ma_reg[0].ur_paddr >> 32) & 0x0fffffff;
        printf("\n");
 
        for (node = OF_child(ma->ma_node); node; node = OF_peer(node)) {
@@ -174,7 +177,7 @@ vbus_intr_map(int node, int ino, uint64_t *sysino)
                        getprop(node, "reg", sizeof(*reg), &nreg, (void **)&reg);
                        devhandle = reg[0] & 0x0fffffff;
 
-                       err = hv_intr_devino_to_sysino(devhandle, devino, sysino);
+                       err = sun4v_intr_devino_to_sysino(devhandle, devino, sysino);
                        if (err != H_EOK)
                                return (-1);
 
@@ -192,6 +195,8 @@ void *
 vbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
     int level, int flags, int (*handler)(void *), void *arg, const char *what)
 {
+       struct vbus_softc *sc = t->cookie;
+       uint64_t devhandle = sc->sc_devhandle;
        uint64_t sysino = INTVEC(ihandle);
        struct intrhand *ih;
        int err;
@@ -204,19 +209,23 @@ vbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
        if (flags & BUS_INTR_ESTABLISH_MPSAFE)
                ih->ih_mpsafe = 1;
 
+       err = sun4v_intr_setcookie(devhandle, sysino, (vaddr_t)ih);
+       if (err != H_EOK)
+               return (NULL);
+
        intr_establish(ih->ih_pil, ih);
        ih->ih_ack = vbus_intr_ack;
 
-       err = hv_intr_settarget(sysino, ih->ih_cpu->ci_upaid);
+       err = sun4v_intr_settarget(devhandle, sysino, ih->ih_cpu->ci_upaid);
        if (err != H_EOK)
                return (NULL);
 
        /* Clear pending interrupts. */
-       err = hv_intr_setstate(sysino, INTR_IDLE);
+       err = sun4v_intr_setstate(devhandle, sysino, INTR_IDLE);
        if (err != H_EOK)
                return (NULL);
 
-       err = hv_intr_setenabled(sysino, INTR_ENABLED);
+       err = sun4v_intr_setenabled(devhandle, sysino, INTR_ENABLED);
        if (err != H_EOK)
                return (NULL);
 
@@ -226,7 +235,11 @@ vbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
 void
 vbus_intr_ack(struct intrhand *ih)
 {
-       hv_intr_setstate(ih->ih_number, INTR_IDLE);
+       bus_space_tag_t t = ih->ih_bus;
+       struct vbus_softc *sc = t->cookie;
+       uint64_t devhandle = sc->sc_devhandle;
+
+       sun4v_intr_setstate(devhandle, ih->ih_number, INTR_IDLE);
 }
 
 bus_space_tag_t
index 491b332..3a1a7a0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: vpci.c,v 1.22 2017/12/05 21:04:32 kettenis Exp $      */
+/*     $OpenBSD: vpci.c,v 1.23 2017/12/06 16:20:53 kettenis Exp $      */
 /*
  * Copyright (c) 2008 Mark Kettenis <kettenis@openbsd.org>
  *
@@ -252,12 +252,12 @@ vpci_init_msi(struct vpci_softc *sc, struct vpci_pbm *pbm)
 
        OF_getprop(sc->sc_node, "msi-eq-to-devino",
            msi_eq_devino, sizeof(msi_eq_devino));
-       err = hv_intr_devino_to_sysino(pbm->vp_devhandle,
+       err = sun4v_intr_devino_to_sysino(pbm->vp_devhandle,
            msi_eq_devino[2], &sysino);
        if (err != H_EOK)
                goto disable_queue;
 
-       if (vpci_intr_establish(sc->sc_bust, sc->sc_bust, sysino,
+       if (vpci_intr_establish(pbm->vp_memt, pbm->vp_memt, sysino,
            IPL_HIGH, 0, vpci_msi_eq_intr, pbm, sc->sc_dv.dv_xname) == NULL)
                goto disable_queue;
 
@@ -333,7 +333,7 @@ vpci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
        int err;
 
        if (*ihp != (pci_intr_handle_t)-1) {
-               err = hv_intr_devino_to_sysino(devhandle, devino, &sysino);
+               err = sun4v_intr_devino_to_sysino(devhandle, devino, &sysino);
                if (err != H_EOK)
                        return (-1);
 
@@ -513,6 +513,7 @@ vpci_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
     int level, int flags, int (*handler)(void *), void *arg, const char *what)
 {
        struct vpci_pbm *pbm = t->cookie;
+       uint64_t devhandle = pbm->vp_devhandle;
        uint64_t sysino = INTVEC(ihandle);
        struct intrhand *ih;
        int err;
@@ -560,19 +561,23 @@ vpci_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
                return (ih);
        }
 
+       err = sun4v_intr_setcookie(devhandle, sysino, (vaddr_t)ih);
+       if (err != H_EOK)
+               return (NULL);
+
        intr_establish(ih->ih_pil, ih);
        ih->ih_ack = vpci_intr_ack;
 
-       err = hv_intr_settarget(sysino, ih->ih_cpu->ci_upaid);
+       err = sun4v_intr_settarget(devhandle, sysino, ih->ih_cpu->ci_upaid);
        if (err != H_EOK)
                return (NULL);
 
        /* Clear pending interrupts. */
-       err = hv_intr_setstate(sysino, INTR_IDLE);
+       err = sun4v_intr_setstate(devhandle, sysino, INTR_IDLE);
        if (err != H_EOK)
                return (NULL);
 
-       err = hv_intr_setenabled(sysino, INTR_ENABLED);
+       err = sun4v_intr_setenabled(devhandle, sysino, INTR_ENABLED);
        if (err != H_EOK)
                return (NULL);
 
@@ -582,7 +587,11 @@ vpci_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
 void
 vpci_intr_ack(struct intrhand *ih)
 {
-       hv_intr_setstate(ih->ih_number, INTR_IDLE);
+       bus_space_tag_t t = ih->ih_bus;
+       struct vpci_pbm *pbm = t->cookie;
+       uint64_t devhandle = pbm->vp_devhandle;
+       
+       sun4v_intr_setstate(devhandle, ih->ih_number, INTR_IDLE);
 }
 
 void
index f01d1f9..39fad75 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: hypervisor.h,v 1.15 2014/01/23 23:56:27 kettenis Exp $        */
+/*     $OpenBSD: hypervisor.h,v 1.16 2017/12/06 16:20:53 kettenis Exp $        */
 
 /*
  * Copyright (c) 2008 Mark Kettenis
@@ -320,3 +320,11 @@ int64_t    hv_rng_data_read(paddr_t raddr, uint64_t *delta);
 #define H_ENOMAP       14
 #define H_ETOOMANY     15
 #define H_ECHANNEL     16
+
+extern uint64_t sun4v_group_interrupt_major;
+
+int64_t sun4v_intr_devino_to_sysino(uint64_t, uint64_t, uint64_t *);
+int64_t sun4v_intr_setcookie(uint64_t, uint64_t, uint64_t);
+int64_t sun4v_intr_setenabled(uint64_t, uint64_t, uint64_t);
+int64_t        sun4v_intr_setstate(uint64_t, uint64_t, uint64_t);
+int64_t        sun4v_intr_settarget(uint64_t, uint64_t, uint64_t);
index 1a9f711..fee9fbc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: autoconf.c,v 1.128 2017/04/30 16:45:45 mpi Exp $      */
+/*     $OpenBSD: autoconf.c,v 1.129 2017/12/06 16:20:53 kettenis Exp $ */
 /*     $NetBSD: autoconf.c,v 1.51 2001/07/24 19:32:11 eeh Exp $ */
 
 /*
@@ -170,6 +170,8 @@ void        sun4v_set_soft_state(int, const char *);
 #define __align32 __attribute__((__aligned__(32)))
 char sun4v_soft_state_booting[] __align32 = "OpenBSD booting";
 char sun4v_soft_state_running[] __align32 = "OpenBSD running";
+
+void   sun4v_interrupt_init(void);
 #endif
 
 #ifdef DEBUG
@@ -436,6 +438,7 @@ bootstrap(int nctx)
        if (CPU_ISSUN4V) {
                sun4v_soft_state_init();
                sun4v_set_soft_state(SIS_TRANSITION, sun4v_soft_state_booting);
+               sun4v_interrupt_init();
        }
 #endif
 }
@@ -733,6 +736,7 @@ cpu_configure(void)
 
 #ifdef SUN4V
 
+#define HSVC_GROUP_INTERRUPT  0x002
 #define HSVC_GROUP_SOFT_STATE 0x003
 
 int sun4v_soft_state_initialized = 0;
@@ -765,6 +769,18 @@ sun4v_set_soft_state(int state, const char *desc)
        if (err != H_EOK)
                printf("soft_state_set: %d\n", err);
 }
+
+void
+sun4v_interrupt_init(void)
+{
+       uint64_t minor;
+
+       if (prom_set_sun4v_api_version(HSVC_GROUP_INTERRUPT, 3, 0, &minor))
+               return;
+       
+       sun4v_group_interrupt_major = 3;
+}
+
 #endif
 
 void
index f82f642..193e734 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: intr.c,v 1.56 2017/04/30 16:45:45 mpi Exp $   */
+/*     $OpenBSD: intr.c,v 1.57 2017/12/06 16:20:53 kettenis Exp $      */
 /*     $NetBSD: intr.c,v 1.39 2001/07/19 23:38:11 eeh Exp $ */
 
 /*
@@ -383,3 +383,57 @@ splassert_check(int wantipl, const char *func)
        }
 }
 #endif
+
+#ifdef SUN4V
+
+#include <machine/hypervisor.h>
+
+uint64_t sun4v_group_interrupt_major;
+
+int64_t
+sun4v_intr_devino_to_sysino(uint64_t devhandle, uint64_t devino, uint64_t *ino)
+{
+       if (sun4v_group_interrupt_major < 3)
+               return hv_intr_devino_to_sysino(devhandle, devino, ino);
+
+       *ino = devino;
+       return H_EOK;
+}
+
+int64_t
+sun4v_intr_setcookie(uint64_t devhandle, uint64_t ino, uint64_t cookie_value)
+{
+       if (sun4v_group_interrupt_major < 3)
+               return H_EOK;
+       
+       return hv_vintr_setcookie(devhandle, ino, cookie_value);
+}
+
+int64_t
+sun4v_intr_setenabled(uint64_t devhandle, uint64_t ino, uint64_t intr_enabled)
+{
+       if (sun4v_group_interrupt_major < 3)
+               return hv_intr_setenabled(ino, intr_enabled);
+
+       return hv_vintr_setenabled(devhandle, ino, intr_enabled);
+}
+
+int64_t
+sun4v_intr_setstate(uint64_t devhandle, uint64_t ino, uint64_t intr_state)
+{
+       if (sun4v_group_interrupt_major < 3)
+               return hv_intr_setstate(ino, intr_state);
+
+       return hv_vintr_setstate(devhandle, ino, intr_state);
+}
+
+int64_t
+sun4v_intr_settarget(uint64_t devhandle, uint64_t ino, uint64_t cpuid)
+{
+       if (sun4v_group_interrupt_major < 3)
+               return hv_intr_settarget(ino, cpuid);
+
+       return hv_vintr_settarget(devhandle, ino, cpuid);
+}
+
+#endif