Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/sparc64/dev import the openbsd pyro and ebus_mainbu...



details:   https://anonhg.NetBSD.org/src/rev/017dd55e5273
branches:  trunk
changeset: 763258:017dd55e5273
user:      mrg <mrg%NetBSD.org@localhost>
date:      Tue Mar 15 11:21:04 2011 +0000

description:
import the openbsd pyro and ebus_mainbus drivers for base reference.

diffstat:

 sys/arch/sparc64/dev/ebus_mainbus.c |  344 +++++++++++++++++++++
 sys/arch/sparc64/dev/pyro.c         |  581 ++++++++++++++++++++++++++++++++++++
 sys/arch/sparc64/dev/pyrovar.h      |   66 ++++
 3 files changed, 991 insertions(+), 0 deletions(-)

diffs (truncated from 1003 to 300 lines):

diff -r 2608d3f4f452 -r 017dd55e5273 sys/arch/sparc64/dev/ebus_mainbus.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/sparc64/dev/ebus_mainbus.c       Tue Mar 15 11:21:04 2011 +0000
@@ -0,0 +1,344 @@
+/*     $OpenBSD: ebus_mainbus.c,v 1.7 2010/11/11 17:58:23 miod Exp $   */
+
+/*
+ * Copyright (c) 2007 Mark Kettenis
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef DEBUG
+#define        EDB_PROM        0x01
+#define EDB_CHILD      0x02
+#define        EDB_INTRMAP     0x04
+#define EDB_BUSMAP     0x08
+#define EDB_BUSDMA     0x10
+#define EDB_INTR       0x20
+extern int ebus_debug;
+#define DPRINTF(l, s)   do { if (ebus_debug & l) printf s; } while (0)
+#else
+#define DPRINTF(l, s)
+#endif
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/errno.h>
+#include <sys/extent.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+
+#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>
+
+#include <sparc64/dev/iommureg.h>
+#include <sparc64/dev/ebusreg.h>
+#include <sparc64/dev/ebusvar.h>
+#include <sparc64/dev/pyrovar.h>
+
+extern struct cfdriver pyro_cd;
+
+int    ebus_mainbus_match(struct device *, void *, void *);
+void   ebus_mainbus_attach(struct device *, struct device *, void *);
+
+struct cfattach ebus_mainbus_ca = {
+       sizeof(struct ebus_softc), ebus_mainbus_match, ebus_mainbus_attach
+};
+
+
+int ebus_mainbus_bus_map(bus_space_tag_t, bus_space_tag_t,
+    bus_addr_t, bus_size_t, int, bus_space_handle_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)
+{
+       struct mainbus_attach_args *ma = aux;
+
+       if (strcmp(ma->ma_name, "ebus") == 0)
+               return (1);
+       return (0);
+}
+
+void
+ebus_mainbus_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct ebus_softc *sc = (struct ebus_softc *)self;
+       struct mainbus_attach_args *ma = aux;
+       struct ebus_attach_args eba;
+       struct ebus_interrupt_map_mask *immp;
+       int node, nmapmask, error;
+       struct pyro_softc *psc;
+       int i;
+
+       sc->sc_node = node = ma->ma_node;
+       sc->sc_ign = INTIGN((ma->ma_upaid) << INTMAP_IGN_SHIFT);
+
+       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;
+               }
+       }
+
+       printf("\n");
+
+       sc->sc_memtag = ebus_alloc_bus_tag(sc, ma->ma_bustag);
+       sc->sc_iotag = ebus_alloc_bus_tag(sc, ma->ma_bustag);
+       sc->sc_dmatag = ebus_alloc_dma_tag(sc, ma->ma_dmatag);
+
+       /*
+        * fill in our softc with information from the prom
+        */
+       sc->sc_intmap = NULL;
+       sc->sc_range = NULL;
+       error = getprop(node, "interrupt-map",
+                       sizeof(struct ebus_interrupt_map),
+                       &sc->sc_nintmap, (void **)&sc->sc_intmap);
+       switch (error) {
+       case 0:
+               immp = &sc->sc_intmapmask;
+               error = getprop(node, "interrupt-map-mask",
+                           sizeof(struct ebus_interrupt_map_mask), &nmapmask,
+                           (void **)&immp);
+               if (error)
+                       panic("could not get ebus interrupt-map-mask");
+               if (nmapmask != 1)
+                       panic("ebus interrupt-map-mask is broken");
+               break;
+       case ENOENT:
+               break;
+       default:
+               panic("ebus interrupt-map: error %d", error);
+               break;
+       }
+
+       error = getprop(node, "ranges", sizeof(struct ebus_mainbus_ranges),
+           &sc->sc_nrange, (void **)&sc->sc_range);
+       if (error)
+               panic("ebus ranges: error %d", error);
+
+       /*
+        * now attach all our children
+        */
+       DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node));
+       for (node = firstchild(node); node; node = nextsibling(node)) {
+               if (ebus_setup_attach_args(sc, node, &eba) != 0) {
+                       DPRINTF(EDB_CHILD,
+                           ("ebus_mainbus_attach: %s: incomplete\n",
+                           getpropstring(node, "name")));
+                       continue;
+               } else {
+                       DPRINTF(EDB_CHILD, ("- found child `%s', attaching\n",
+                           eba.ea_name));
+                       (void)config_found(self, &eba, ebus_print);
+               }
+               ebus_destroy_attach_args(&eba);
+       }
+}
+
+bus_space_tag_t
+ebus_alloc_bus_tag(struct ebus_softc *sc, bus_space_tag_t parent)
+{
+       struct sparc_bus_space_tag *bt;
+
+       bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT | M_ZERO);
+       if (bt == NULL)
+               panic("could not allocate ebus bus tag");
+
+       strlcpy(bt->name, sc->sc_dev.dv_xname, sizeof(bt->name));
+       bt->cookie = sc;
+       bt->parent = parent;
+       bt->asi = parent->asi;
+       bt->sasi = parent->sasi;
+       bt->sparc_bus_map = ebus_mainbus_bus_map;
+       bt->sparc_intr_establish = ebus_mainbus_intr_establish;
+
+       return (bt);
+}
+
+int
+ebus_mainbus_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset,
+    bus_size_t size, int flags, bus_space_handle_t *hp)
+{
+       struct ebus_softc *sc = t->cookie;
+       struct ebus_mainbus_ranges *range;
+       bus_addr_t hi, lo;
+       int i;
+
+       DPRINTF(EDB_BUSMAP,
+           ("\n_ebus_mainbus_bus_map: off %016llx sz %x flags %d",
+           (unsigned long long)offset, (int)size, (int)flags));
+
+       if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
+               printf("\n_ebus_mainbus_bus_map: invalid parent");
+               return (EINVAL);
+       }
+
+       t = t->parent;
+
+       if (flags & BUS_SPACE_MAP_PROMADDRESS) {
+               return ((*t->sparc_bus_map)
+                   (t, t0, offset, size, flags, hp));
+       }
+
+       hi = offset >> 32UL;
+       lo = offset & 0xffffffff;
+       range = (struct ebus_mainbus_ranges *)sc->sc_range;
+
+       DPRINTF(EDB_BUSMAP, (" (hi %08x lo %08x)", (u_int)hi, (u_int)lo));
+       for (i = 0; i < sc->sc_nrange; i++) {
+               bus_addr_t addr;
+
+               if (hi != range[i].child_hi)
+                       continue;
+               if (lo < range[i].child_lo ||
+                   (lo + size) > (range[i].child_lo + range[i].size))
+                       continue;
+
+               addr = ((bus_addr_t)range[i].phys_hi << 32UL) |
+                                   range[i].phys_lo;
+               addr += lo;
+               DPRINTF(EDB_BUSMAP,
+                   ("\n_ebus_mainbus_bus_map: paddr offset %qx addr %qx\n", 
+                   (unsigned long long)offset, (unsigned long long)addr));
+                return ((*t->sparc_bus_map)(t, t0, addr, size, flags, hp));
+       }
+       DPRINTF(EDB_BUSMAP, (": FAILED\n"));
+       return (EINVAL);
+}
+
+void *
+ebus_mainbus_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 ebus_softc *sc = t->cookie;
+       struct intrhand *ih = NULL;
+       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);
+



Home | Main Index | Thread Index | Old Index