Handle breaks.
authorkettenis <kettenis@openbsd.org>
Thu, 10 Jul 2008 20:27:36 +0000 (20:27 +0000)
committerkettenis <kettenis@openbsd.org>
Thu, 10 Jul 2008 20:27:36 +0000 (20:27 +0000)
sys/arch/sparc64/dev/sbbc.c

index 092ad24..96047ed 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sbbc.c,v 1.2 2008/07/07 14:46:18 kettenis Exp $       */
+/*     $OpenBSD: sbbc.c,v 1.3 2008/07/10 20:27:36 kettenis Exp $       */
 /*
  * Copyright (c) 2008 Mark Kettenis
  *
@@ -52,6 +52,10 @@ extern todr_chip_handle_t todr_handle;
 #define SBBC_SRAM_OFFSET       0x900000
 #define SBBC_SRAM_SIZE         0x20000 /* 128KB SRAM */
 
+#define SBBC_PCI_INT_STATUS    0x2320
+#define SBBC_PCI_INT_ENABLE    0x2330
+#define SBBC_PCI_ENABLE_INT_A  0x11
+
 #define SBBC_EPLD_INTERRUPT    0x13
 #define SBBC_EPLD_INTERRUPT_ON 0x01
 
@@ -120,14 +124,17 @@ struct sbbc_softc {
        bus_space_handle_t      sc_sram_ioh;
        caddr_t                 sc_sram;
        uint32_t                sc_sram_toc;
+       void *                  sc_ih;
 
        struct sparc_bus_space_tag sc_bbt;
 
        struct tty              *sc_tty;
        struct timeout          sc_to;
        caddr_t                 sc_sram_cons;
-       uint32_t                *sc_sram_intr_enabled;
-       uint32_t                *sc_sram_intr_reason;
+       uint32_t                *sc_sram_solscie;
+       uint32_t                *sc_sram_solscir;
+       uint32_t                *sc_sram_scsolie;
+       uint32_t                *sc_sram_scsolir;
 };
 
 struct sbbc_softc *sbbc_cons_input;
@@ -144,6 +151,7 @@ struct cfdriver sbbc_cd = {
        NULL, "sbbc", DV_DULL
 };
 
+int    sbbc_intr(void *);
 void   sbbc_send_intr(struct sbbc_softc *sc);
 
 void   sbbc_attach_tod(struct sbbc_softc *, uint32_t);
@@ -178,6 +186,7 @@ sbbc_attach(struct device *parent, struct device *self, void *aux)
        struct sbbc_sram_toc *toc;
        bus_addr_t base;
        bus_size_t size;
+       pci_intr_handle_t ih;
        int chosen, iosram;
        int i;
 
@@ -192,25 +201,45 @@ sbbc_attach(struct device *parent, struct device *self, void *aux)
                return;
        }
 
+       if (bus_space_map(sc->sc_iot, base + SBBC_REGS_OFFSET,
+           SBBC_REGS_SIZE, 0, &sc->sc_regs_ioh)) {
+               printf(": can't map register space\n");
+               return;
+       }
+
        if (bus_space_map(sc->sc_iot, base + SBBC_EPLD_OFFSET,
            SBBC_EPLD_SIZE, 0, &sc->sc_epld_ioh)) {
                printf(": can't map EPLD registers\n");
-               return;
+               goto unmap_regs;
        }
 
        if (bus_space_map(sc->sc_iot, base + SBBC_SRAM_OFFSET,
            SBBC_SRAM_SIZE, 0, &sc->sc_sram_ioh)) {
                printf(": can't map SRAM\n");
-               return;
+               goto unmap_epld;
+       }
+
+       if (pci_intr_map(pa, &ih)) {
+               printf(": unable to map interrupt\n");
+               goto unmap_sram;
        }
+       printf(": %s\n", pci_intr_string(pa->pa_pc, ih));
+
+       sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_TTY,
+           sbbc_intr, sc, sc->sc_dv.dv_xname);
+       if (sc->sc_ih == NULL) {
+               printf("%s: unable to establish interrupt\n");
+               goto unmap_sram;
+       }
+
+       bus_space_write_4(sc->sc_iot, sc->sc_regs_ioh,
+           SBBC_PCI_INT_ENABLE, SBBC_PCI_ENABLE_INT_A);
 
        /* Check if we are the chosen one. */
        chosen = OF_finddevice("/chosen");
        if (OF_getprop(chosen, "iosram", &iosram, sizeof(iosram)) <= 0 ||
-           PCITAG_NODE(pa->pa_tag) != iosram) {
-               printf("\n");
+           PCITAG_NODE(pa->pa_tag) != iosram)
                return;
-       }
 
        /* SRAM TOC offset defaults to 0. */
        if (OF_getprop(chosen, "iosram-toc", &sc->sc_sram_toc,
@@ -222,15 +251,19 @@ sbbc_attach(struct device *parent, struct device *self, void *aux)
 
        for (i = 0; i < toc->toc_ntags; i++) {
                if (strcmp(toc->toc_tag[i].tag_key, "SOLSCIE") == 0)
-                       sc->sc_sram_intr_enabled = (uint32_t *)
+                       sc->sc_sram_solscie = (uint32_t *)
                            (sc->sc_sram + toc->toc_tag[i].tag_offset);
                if (strcmp(toc->toc_tag[i].tag_key, "SOLSCIR") == 0)
-                       sc->sc_sram_intr_reason = (uint32_t *)
+                       sc->sc_sram_solscir = (uint32_t *)
+                           (sc->sc_sram + toc->toc_tag[i].tag_offset);
+               if (strcmp(toc->toc_tag[i].tag_key, "SCSOLIE") == 0)
+                       sc->sc_sram_scsolie = (uint32_t *)
+                           (sc->sc_sram + toc->toc_tag[i].tag_offset);
+               if (strcmp(toc->toc_tag[i].tag_key, "SCSOLIR") == 0)
+                       sc->sc_sram_scsolir = (uint32_t *)
                            (sc->sc_sram + toc->toc_tag[i].tag_offset);
        }
 
-       *sc->sc_sram_intr_enabled |= SBBC_SRAM_CONS_OUT;
-
        for (i = 0; i < toc->toc_ntags; i++) {
                if (strcmp(toc->toc_tag[i].tag_key, "TODDATA") == 0)
                        sbbc_attach_tod(sc, toc->toc_tag[i].tag_offset);
@@ -238,7 +271,42 @@ sbbc_attach(struct device *parent, struct device *self, void *aux)
                        sbbc_attach_cons(sc, toc->toc_tag[i].tag_offset);
        }
 
-       printf("\n");
+       return;
+
+ unmap_sram:
+       bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_SRAM_SIZE);
+ unmap_epld:
+       bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_EPLD_SIZE);
+ unmap_regs:
+       bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_REGS_SIZE);
+}
+
+int
+sbbc_intr(void *arg)
+{
+       struct sbbc_softc *sc = arg;
+       uint32_t status, reason;
+
+       status = bus_space_read_4(sc->sc_iot, sc->sc_regs_ioh,
+           SBBC_PCI_INT_STATUS);
+       if (status == 0)
+               return (0);
+
+       /* Sigh, we cannot use compare and swap for non-cachable memory. */
+       reason = *sc->sc_sram_scsolir;
+       *sc->sc_sram_scsolir = 0;
+
+#ifdef DDB
+       if (reason & SBBC_SRAM_CONS_BRK && sc == sbbc_cons_input) {
+               if (db_console)
+                       Debugger();
+       }
+#endif
+
+       /* Ack interrupt. */
+       bus_space_write_4(sc->sc_iot, sc->sc_regs_ioh,
+           SBBC_PCI_INT_STATUS, status);
+       return (1);
 }
 
 void
@@ -298,6 +366,10 @@ sbbc_attach_cons(struct sbbc_softc *sc, uint32_t offset)
        int sgcn_is_input, sgcn_is_output, node, maj;
        char buf[32];
 
+       if (sc->sc_sram_solscie == NULL || sc->sc_sram_solscir == NULL ||
+           sc->sc_sram_scsolie == NULL || sc->sc_sram_scsolir == NULL)
+               return;
+
        cons = (struct sbbc_sram_cons *)(sc->sc_sram + offset);
        if (cons->cons_magic != SBBC_CONS_MAGIC ||
            cons->cons_version < SBBC_CONS_VERSION)
@@ -309,6 +381,9 @@ sbbc_attach_cons(struct sbbc_softc *sc, uint32_t offset)
 
        timeout_set(&sc->sc_to, sbbctimeout, sc);
 
+       *sc->sc_sram_solscie |= SBBC_SRAM_CONS_OUT;
+       *sc->sc_sram_scsolie |= SBBC_SRAM_CONS_BRK;
+
        /* Take over console input. */
        prom_serengeti_set_console_input("CON_CLNT");
 
@@ -340,7 +415,7 @@ sbbc_attach_cons(struct sbbc_softc *sc, uint32_t offset)
                /* Let current output drain. */
                DELAY(2000000);
 
-               printf(": console");
+               printf("%s: console\n", sc->sc_dv.dv_xname);
        }
 }
 
@@ -385,7 +460,7 @@ sbbc_cnputc(dev_t dev, int c)
                wrptr = cons->cons_out_begin;
        cons->cons_out_wrptr = wrptr;
 
-       *sc->sc_sram_intr_reason |= SBBC_SRAM_CONS_OUT;
+       *sc->sc_sram_solscir |= SBBC_SRAM_CONS_OUT;
        sbbc_send_intr(sc);
 }