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", ®, 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