diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2007-04-04 18:38:55 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2007-04-04 18:38:55 +0000 |
commit | 5e037677525f64162ee68035f794b3ffee3aa398 (patch) | |
tree | 3ab6445af015487f5f7990f313741eeaad1a77be /sys/arch/sparc64/dev | |
parent | 8259c11e7dfb90bc3b3db8a0489a607e25e7bde3 (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.c | 30 | ||||
-rw-r--r-- | sys/arch/sparc64/dev/ebus_mainbus.c | 271 | ||||
-rw-r--r-- | sys/arch/sparc64/dev/ebusreg.h | 10 | ||||
-rw-r--r-- | sys/arch/sparc64/dev/ebusvar.h | 18 |
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) |