summaryrefslogtreecommitdiff
path: root/sys/arch/sparc64/dev
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2007-04-04 18:38:55 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2007-04-04 18:38:55 +0000
commit5e037677525f64162ee68035f794b3ffee3aa398 (patch)
tree3ab6445af015487f5f7990f313741eeaad1a77be /sys/arch/sparc64/dev
parent8259c11e7dfb90bc3b3db8a0489a607e25e7bde3 (diff)
Add support for ebus at mainbus, as found on machines with pyro(4) like the
v215.
Diffstat (limited to 'sys/arch/sparc64/dev')
-rw-r--r--sys/arch/sparc64/dev/ebus.c30
-rw-r--r--sys/arch/sparc64/dev/ebus_mainbus.c271
-rw-r--r--sys/arch/sparc64/dev/ebusreg.h10
-rw-r--r--sys/arch/sparc64/dev/ebusvar.h18
4 files changed, 307 insertions, 22 deletions
diff --git a/sys/arch/sparc64/dev/ebus.c b/sys/arch/sparc64/dev/ebus.c
index a28a6ceb58d..7d65356b0c9 100644
--- a/sys/arch/sparc64/dev/ebus.c
+++ b/sys/arch/sparc64/dev/ebus.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ebus.c,v 1.15 2007/01/09 22:37:18 kettenis Exp $ */
+/* $OpenBSD: ebus.c,v 1.16 2007/04/04 18:38:54 kettenis Exp $ */
/* $NetBSD: ebus.c,v 1.24 2001/07/25 03:49:54 eeh Exp $ */
/*
@@ -89,10 +89,6 @@ struct cfdriver ebus_cd = {
};
-int ebus_setup_attach_args(struct ebus_softc *, int,
- struct ebus_attach_args *);
-void ebus_destroy_attach_args(struct ebus_attach_args *);
-int ebus_print(void *, const char *);
void ebus_find_ino(struct ebus_softc *, struct ebus_attach_args *);
int ebus_find_node(struct pci_attach_args *);
@@ -196,7 +192,7 @@ ebus_attach(struct device *parent, struct device *self, void *aux)
}
error = getprop(node, "ranges", sizeof(struct ebus_ranges),
- &sc->sc_nrange, (void **)&sc->sc_range);
+ &sc->sc_nrange, &sc->sc_range);
if (error)
panic("ebus ranges: error %d", error);
@@ -421,6 +417,7 @@ _ebus_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_ranges *range = sc->sc_range;
bus_addr_t hi, lo;
int i;
@@ -448,24 +445,22 @@ _ebus_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset,
for (i = 0; i < sc->sc_nrange; i++) {
bus_addr_t pciaddr;
- if (hi != sc->sc_range[i].child_hi)
+ if (hi != range[i].child_hi)
continue;
- if (lo < sc->sc_range[i].child_lo ||
- (lo + size) >
- (sc->sc_range[i].child_lo + sc->sc_range[i].size))
+ if (lo < range[i].child_lo ||
+ (lo + size) > (range[i].child_lo + range[i].size))
continue;
- if(((sc->sc_range[i].phys_hi >> 24) & 3) != t->default_type)
+ if(((range[i].phys_hi >> 24) & 3) != t->default_type)
continue;
- pciaddr = ((bus_addr_t)sc->sc_range[i].phys_mid << 32UL) |
- sc->sc_range[i].phys_lo;
+ pciaddr = ((bus_addr_t)range[i].phys_mid << 32UL) |
+ range[i].phys_lo;
pciaddr += lo;
DPRINTF(EDB_BUSMAP,
("\n_ebus_bus_map: mapping space %x paddr offset %qx "
"pciaddr %qx\n", (int)t->default_type,
(unsigned long long)offset, (unsigned long long)pciaddr));
- /* pass it onto the psycho */
return ((*t->sparc_bus_map)(t, t0, pciaddr, size, flags, hp));
}
DPRINTF(EDB_BUSMAP, (": FAILED\n"));
@@ -478,6 +473,7 @@ ebus_bus_mmap(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t paddr,
{
bus_addr_t offset = paddr;
struct ebus_softc *sc = t->cookie;
+ struct ebus_ranges *range = sc->sc_range;
int i;
if (t->parent == 0 || t->parent->sparc_bus_mmap == 0) {
@@ -488,9 +484,8 @@ ebus_bus_mmap(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t paddr,
t = t->parent;
for (i = 0; i < sc->sc_nrange; i++) {
- bus_addr_t paddr =
- ((bus_addr_t)sc->sc_range[i].child_hi << 32) |
- sc->sc_range[i].child_lo;
+ bus_addr_t paddr = ((bus_addr_t)range[i].child_hi << 32) |
+ range[i].child_lo;
if (offset != paddr)
continue;
@@ -502,4 +497,3 @@ ebus_bus_mmap(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t paddr,
return (-1);
}
-
diff --git a/sys/arch/sparc64/dev/ebus_mainbus.c b/sys/arch/sparc64/dev/ebus_mainbus.c
new file mode 100644
index 00000000000..ba6c3839969
--- /dev/null
+++ b/sys/arch/sparc64/dev/ebus_mainbus.c
@@ -0,0 +1,271 @@
+/* $OpenBSD: ebus_mainbus.c,v 1.1 2007/04/04 18:38:54 kettenis 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/openfirm.h>
+
+#include <sparc64/dev/iommureg.h>
+#include <sparc64/dev/ebusreg.h>
+#include <sparc64/dev/ebusvar.h>
+#include <sparc64/sparc64/cache.h>
+
+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
+};
+
+struct cfdriver ebus_mainbus_cd = {
+ NULL, "ebus", DV_DULL
+};
+
+
+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);
+
+
+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;
+
+ sc->sc_ign = INTIGN((ma->ma_upaid & 0x1e) << INTMAP_IGN_SHIFT);
+
+ printf(": ign %x\n", sc->sc_ign);
+
+ 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);
+
+ sc->sc_node = node = ma->ma_node;
+
+ /* XXX double mapping? */
+ sc->sc_bust = ma->ma_bustag;
+ sc->sc_csr = ma->ma_reg[0].ur_paddr + 0x600000 - 0x464000;
+ if (bus_space_map(sc->sc_bust, sc->sc_csr, 0x2000, 0, &sc->sc_csrh)) {
+ printf(": failed to map csr registers\n");
+ return;
+ }
+
+ /*
+ * 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);
+ if (bt == NULL)
+ panic("could not allocate ebus bus tag");
+
+ bzero(bt, sizeof *bt);
+ snprintf(bt->name, sizeof(bt->name), "%s", sc->sc_dev.dv_xname);
+ 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;
+
+ ihandle |= sc->sc_ign;
+ ino = INTINO(ihandle);
+
+ if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) == 0) {
+ u_int64_t *imap, *iclr;
+
+ /* XXX */
+ imap = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1000;
+ iclr = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1400;
+ intrmapptr = &imap[ino];
+ intrclrptr = &iclr[ino];
+ ino |= INTVEC(ihandle);
+ }
+
+ ih = bus_intr_allocate(t0, handler, arg, ino, level, intrmapptr,
+ intrclrptr, what);
+ if (ih == NULL)
+ return (NULL);
+
+ intr_establish(ih->ih_pil, ih);
+
+ if (intrmapptr != NULL) {
+ u_int64_t intrmap;
+
+ intrmap = *intrmapptr;
+ intrmap |= (1LL << 6);
+ intrmap |= INTMAP_V;
+ *intrmapptr = intrmap;
+ intrmap = *intrmapptr;
+ ih->ih_number |= intrmap & INTMAP_INR;
+ }
+
+ return (ih);
+}
diff --git a/sys/arch/sparc64/dev/ebusreg.h b/sys/arch/sparc64/dev/ebusreg.h
index d508ad28f74..62fb679eed4 100644
--- a/sys/arch/sparc64/dev/ebusreg.h
+++ b/sys/arch/sparc64/dev/ebusreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ebusreg.h,v 1.4 2001/10/01 18:08:04 jason Exp $ */
+/* $OpenBSD: ebusreg.h,v 1.5 2007/04/04 18:38:54 kettenis Exp $ */
/* $NetBSD: ebusreg.h,v 1.1 1999/06/04 13:29:13 mrg Exp $ */
/*
@@ -79,6 +79,14 @@ struct ebus_ranges {
u_int32_t size;
};
+struct ebus_mainbus_ranges {
+ u_int32_t child_hi;
+ u_int32_t child_lo;
+ u_int32_t phys_hi;
+ u_int32_t phys_lo;
+ u_int32_t size;
+};
+
struct ebus_interrupt_map {
u_int32_t hi; /* high phys addr mask */
u_int32_t lo; /* low phys addr mask */
diff --git a/sys/arch/sparc64/dev/ebusvar.h b/sys/arch/sparc64/dev/ebusvar.h
index 023d8350ebb..cf626495f3f 100644
--- a/sys/arch/sparc64/dev/ebusvar.h
+++ b/sys/arch/sparc64/dev/ebusvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ebusvar.h,v 1.5 2003/02/17 01:29:20 henric Exp $ */
+/* $OpenBSD: ebusvar.h,v 1.6 2007/04/04 18:38:54 kettenis Exp $ */
/* $NetBSD: ebusvar.h,v 1.5 2001/07/20 00:07:13 eeh Exp $ */
/*
@@ -63,16 +63,28 @@ struct ebus_softc {
bus_space_tag_t sc_iotag; /* from pci */
bus_dma_tag_t sc_dmatag; /* XXX */
- struct ebus_ranges *sc_range;
+ void *sc_range;
struct ebus_interrupt_map *sc_intmap;
struct ebus_interrupt_map_mask sc_intmapmask;
int sc_nrange; /* counters */
int sc_nintmap;
+
+ int sc_ign;
+
+ bus_space_tag_t sc_bust;
+ bus_addr_t sc_csr;
+ bus_space_handle_t sc_csrh;
};
+
+int ebus_setup_attach_args(struct ebus_softc *, int,
+ struct ebus_attach_args *);
+void ebus_destroy_attach_args(struct ebus_attach_args *);
+int ebus_print(void *, const char *);
+
+
bus_dma_tag_t ebus_alloc_dma_tag(struct ebus_softc *, bus_dma_tag_t);
-bus_space_tag_t ebus_alloc_bus_tag(struct ebus_softc *, int);
#define ebus_bus_map(t, bt, a, s, f, v, hp) \
bus_space_map(t, a, s, f, hp)