Annotation of sys/arch/sparc64/dev/ebus_mainbus.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ebus_mainbus.c,v 1.3 2007/04/07 20:15:54 kettenis Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2007 Mark Kettenis
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: #ifdef DEBUG
! 20: #define EDB_PROM 0x01
! 21: #define EDB_CHILD 0x02
! 22: #define EDB_INTRMAP 0x04
! 23: #define EDB_BUSMAP 0x08
! 24: #define EDB_BUSDMA 0x10
! 25: #define EDB_INTR 0x20
! 26: extern int ebus_debug;
! 27: #define DPRINTF(l, s) do { if (ebus_debug & l) printf s; } while (0)
! 28: #else
! 29: #define DPRINTF(l, s)
! 30: #endif
! 31:
! 32: #include <sys/param.h>
! 33: #include <sys/conf.h>
! 34: #include <sys/device.h>
! 35: #include <sys/errno.h>
! 36: #include <sys/extent.h>
! 37: #include <sys/malloc.h>
! 38: #include <sys/systm.h>
! 39: #include <sys/time.h>
! 40:
! 41: #define _SPARC_BUS_DMA_PRIVATE
! 42: #include <machine/bus.h>
! 43: #include <machine/autoconf.h>
! 44: #include <machine/openfirm.h>
! 45:
! 46: #include <dev/pci/pcivar.h>
! 47:
! 48: #include <sparc64/dev/iommureg.h>
! 49: #include <sparc64/dev/ebusreg.h>
! 50: #include <sparc64/dev/ebusvar.h>
! 51: #include <sparc64/dev/pyrovar.h>
! 52:
! 53: extern struct cfdriver pyro_cd;
! 54:
! 55: int ebus_mainbus_match(struct device *, void *, void *);
! 56: void ebus_mainbus_attach(struct device *, struct device *, void *);
! 57:
! 58: struct cfattach ebus_mainbus_ca = {
! 59: sizeof(struct ebus_softc), ebus_mainbus_match, ebus_mainbus_attach
! 60: };
! 61:
! 62:
! 63: int _ebus_mainbus_bus_map(bus_space_tag_t, bus_space_tag_t,
! 64: bus_addr_t, bus_size_t, int, bus_space_handle_t *);
! 65: void *_ebus_mainbus_intr_establish(bus_space_tag_t, bus_space_tag_t,
! 66: int, int, int, int (*)(void *), void *, const char *);
! 67: bus_space_tag_t ebus_alloc_bus_tag(struct ebus_softc *, bus_space_tag_t);
! 68:
! 69:
! 70: int
! 71: ebus_mainbus_match(struct device *parent, void *match, void *aux)
! 72: {
! 73: struct mainbus_attach_args *ma = aux;
! 74:
! 75: if (strcmp(ma->ma_name, "ebus") == 0)
! 76: return (1);
! 77: return (0);
! 78: }
! 79:
! 80: void
! 81: ebus_mainbus_attach(struct device *parent, struct device *self, void *aux)
! 82: {
! 83: struct ebus_softc *sc = (struct ebus_softc *)self;
! 84: struct mainbus_attach_args *ma = aux;
! 85: struct ebus_attach_args eba;
! 86: struct ebus_interrupt_map_mask *immp;
! 87: int node, nmapmask, error;
! 88: struct pyro_softc *psc;
! 89: int i;
! 90:
! 91: sc->sc_node = node = ma->ma_node;
! 92: sc->sc_ign = INTIGN((ma->ma_upaid) << INTMAP_IGN_SHIFT);
! 93:
! 94: printf(": ign %x", sc->sc_ign);
! 95:
! 96: for (i = 0; i < pyro_cd.cd_ndevs; i++) {
! 97: psc = pyro_cd.cd_devs[i];
! 98: if (psc && psc->sc_ign == sc->sc_ign) {
! 99: sc->sc_bust = psc->sc_bust;
! 100: sc->sc_csr = psc->sc_csr;
! 101: sc->sc_csrh = psc->sc_csrh;
! 102: break;
! 103: }
! 104: }
! 105:
! 106: if (sc->sc_csr == 0) {
! 107: printf(": can't find matching host bridge leaf\n");
! 108: return;
! 109: }
! 110:
! 111: printf("\n");
! 112:
! 113: sc->sc_memtag = ebus_alloc_bus_tag(sc, ma->ma_bustag);
! 114: sc->sc_iotag = ebus_alloc_bus_tag(sc, ma->ma_bustag);
! 115: sc->sc_dmatag = ebus_alloc_dma_tag(sc, ma->ma_dmatag);
! 116:
! 117: /*
! 118: * fill in our softc with information from the prom
! 119: */
! 120: sc->sc_intmap = NULL;
! 121: sc->sc_range = NULL;
! 122: error = getprop(node, "interrupt-map",
! 123: sizeof(struct ebus_interrupt_map),
! 124: &sc->sc_nintmap, (void **)&sc->sc_intmap);
! 125: switch (error) {
! 126: case 0:
! 127: immp = &sc->sc_intmapmask;
! 128: error = getprop(node, "interrupt-map-mask",
! 129: sizeof(struct ebus_interrupt_map_mask), &nmapmask,
! 130: (void **)&immp);
! 131: if (error)
! 132: panic("could not get ebus interrupt-map-mask");
! 133: if (nmapmask != 1)
! 134: panic("ebus interrupt-map-mask is broken");
! 135: break;
! 136: case ENOENT:
! 137: break;
! 138: default:
! 139: panic("ebus interrupt-map: error %d", error);
! 140: break;
! 141: }
! 142:
! 143: error = getprop(node, "ranges", sizeof(struct ebus_mainbus_ranges),
! 144: &sc->sc_nrange, (void **)&sc->sc_range);
! 145: if (error)
! 146: panic("ebus ranges: error %d", error);
! 147:
! 148: /*
! 149: * now attach all our children
! 150: */
! 151: DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node));
! 152: for (node = firstchild(node); node; node = nextsibling(node)) {
! 153: if (ebus_setup_attach_args(sc, node, &eba) != 0) {
! 154: DPRINTF(EDB_CHILD,
! 155: ("ebus_mainbus_attach: %s: incomplete\n",
! 156: getpropstring(node, "name")));
! 157: continue;
! 158: } else {
! 159: DPRINTF(EDB_CHILD, ("- found child `%s', attaching\n",
! 160: eba.ea_name));
! 161: (void)config_found(self, &eba, ebus_print);
! 162: }
! 163: ebus_destroy_attach_args(&eba);
! 164: }
! 165: }
! 166:
! 167: bus_space_tag_t
! 168: ebus_alloc_bus_tag(struct ebus_softc *sc, bus_space_tag_t parent)
! 169: {
! 170: struct sparc_bus_space_tag *bt;
! 171:
! 172: bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT);
! 173: if (bt == NULL)
! 174: panic("could not allocate ebus bus tag");
! 175:
! 176: bzero(bt, sizeof *bt);
! 177: snprintf(bt->name, sizeof(bt->name), "%s", sc->sc_dev.dv_xname);
! 178: bt->cookie = sc;
! 179: bt->parent = parent;
! 180: bt->asi = parent->asi;
! 181: bt->sasi = parent->sasi;
! 182: bt->sparc_bus_map = _ebus_mainbus_bus_map;
! 183: bt->sparc_intr_establish = _ebus_mainbus_intr_establish;
! 184:
! 185: return (bt);
! 186: }
! 187:
! 188: int
! 189: _ebus_mainbus_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset,
! 190: bus_size_t size, int flags, bus_space_handle_t *hp)
! 191: {
! 192: struct ebus_softc *sc = t->cookie;
! 193: struct ebus_mainbus_ranges *range;
! 194: bus_addr_t hi, lo;
! 195: int i;
! 196:
! 197: DPRINTF(EDB_BUSMAP,
! 198: ("\n_ebus_mainbus_bus_map: off %016llx sz %x flags %d",
! 199: (unsigned long long)offset, (int)size, (int)flags));
! 200:
! 201: if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
! 202: printf("\n_ebus_mainbus_bus_map: invalid parent");
! 203: return (EINVAL);
! 204: }
! 205:
! 206: t = t->parent;
! 207:
! 208: if (flags & BUS_SPACE_MAP_PROMADDRESS) {
! 209: return ((*t->sparc_bus_map)
! 210: (t, t0, offset, size, flags, hp));
! 211: }
! 212:
! 213: hi = offset >> 32UL;
! 214: lo = offset & 0xffffffff;
! 215: range = (struct ebus_mainbus_ranges *)sc->sc_range;
! 216:
! 217: DPRINTF(EDB_BUSMAP, (" (hi %08x lo %08x)", (u_int)hi, (u_int)lo));
! 218: for (i = 0; i < sc->sc_nrange; i++) {
! 219: bus_addr_t addr;
! 220:
! 221: if (hi != range[i].child_hi)
! 222: continue;
! 223: if (lo < range[i].child_lo ||
! 224: (lo + size) > (range[i].child_lo + range[i].size))
! 225: continue;
! 226:
! 227: addr = ((bus_addr_t)range[i].phys_hi << 32UL) |
! 228: range[i].phys_lo;
! 229: addr += lo;
! 230: DPRINTF(EDB_BUSMAP,
! 231: ("\n_ebus_mainbus_bus_map: paddr offset %qx addr %qx\n",
! 232: (unsigned long long)offset, (unsigned long long)addr));
! 233: return ((*t->sparc_bus_map)(t, t0, addr, size, flags, hp));
! 234: }
! 235: DPRINTF(EDB_BUSMAP, (": FAILED\n"));
! 236: return (EINVAL);
! 237: }
! 238:
! 239: void *
! 240: _ebus_mainbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
! 241: int level, int flags, int (*handler)(void *), void *arg, const char *what)
! 242: {
! 243: struct ebus_softc *sc = t->cookie;
! 244: struct intrhand *ih = NULL;
! 245: volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
! 246: int ino;
! 247:
! 248: ihandle |= sc->sc_ign;
! 249: ino = INTINO(ihandle);
! 250:
! 251: if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) == 0) {
! 252: u_int64_t *imap, *iclr;
! 253:
! 254: /* XXX */
! 255: imap = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1000;
! 256: iclr = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1400;
! 257: intrmapptr = &imap[ino];
! 258: intrclrptr = &iclr[ino];
! 259: ino |= INTVEC(ihandle);
! 260: }
! 261:
! 262: ih = bus_intr_allocate(t0, handler, arg, ino, level, intrmapptr,
! 263: intrclrptr, what);
! 264: if (ih == NULL)
! 265: return (NULL);
! 266:
! 267: intr_establish(ih->ih_pil, ih);
! 268:
! 269: if (intrmapptr != NULL) {
! 270: u_int64_t intrmap;
! 271:
! 272: intrmap = *intrmapptr;
! 273: intrmap |= (1LL << 6);
! 274: intrmap |= INTMAP_V;
! 275: *intrmapptr = intrmap;
! 276: intrmap = *intrmapptr;
! 277: ih->ih_number |= intrmap & INTMAP_INR;
! 278: }
! 279:
! 280: return (ih);
! 281: }
CVSweb