Annotation of sys/arch/sparc64/dev/pyro.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pyro.c,v 1.7 2007/04/03 19:59:01 kettenis Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
! 5: * Copyright (c) 2003 Henric Jungheim
! 6: * Copyright (c) 2007 Mark Kettenis
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 20: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 21: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
! 22: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 23: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 24: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 26: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
! 27: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 28: * POSSIBILITY OF SUCH DAMAGE.
! 29: */
! 30:
! 31: #include <sys/param.h>
! 32: #include <sys/device.h>
! 33: #include <sys/errno.h>
! 34: #include <sys/malloc.h>
! 35: #include <sys/systm.h>
! 36:
! 37: #define _SPARC_BUS_DMA_PRIVATE
! 38: #include <machine/bus.h>
! 39: #include <machine/autoconf.h>
! 40:
! 41: #include <dev/pci/pcivar.h>
! 42: #include <dev/pci/pcireg.h>
! 43:
! 44: #include <sparc64/dev/iommureg.h>
! 45: #include <sparc64/dev/iommuvar.h>
! 46: #include <sparc64/dev/pyrovar.h>
! 47:
! 48: #ifdef DEBUG
! 49: #define PDB_PROM 0x01
! 50: #define PDB_BUSMAP 0x02
! 51: #define PDB_INTR 0x04
! 52: #define PDB_CONF 0x08
! 53: int pyro_debug = ~0;
! 54: #define DPRINTF(l, s) do { if (pyro_debug & l) printf s; } while (0)
! 55: #else
! 56: #define DPRINTF(l, s)
! 57: #endif
! 58:
! 59: extern struct sparc_pci_chipset _sparc_pci_chipset;
! 60:
! 61: int pyro_match(struct device *, void *, void *);
! 62: void pyro_attach(struct device *, struct device *, void *);
! 63: void pyro_init(struct pyro_softc *, int);
! 64: void pyro_init_iommu(struct pyro_softc *, struct pyro_pbm *);
! 65: int pyro_print(void *, const char *);
! 66:
! 67: pci_chipset_tag_t pyro_alloc_chipset(struct pyro_pbm *, int,
! 68: pci_chipset_tag_t);
! 69: bus_space_tag_t pyro_alloc_mem_tag(struct pyro_pbm *);
! 70: bus_space_tag_t pyro_alloc_io_tag(struct pyro_pbm *);
! 71: bus_space_tag_t pyro_alloc_config_tag(struct pyro_pbm *);
! 72: bus_space_tag_t _pyro_alloc_bus_tag(struct pyro_pbm *, const char *,
! 73: int, int, int);
! 74: bus_dma_tag_t pyro_alloc_dma_tag(struct pyro_pbm *);
! 75:
! 76: int pyro_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
! 77: int _pyro_bus_map(bus_space_tag_t, bus_space_tag_t, bus_addr_t,
! 78: bus_size_t, int, bus_space_handle_t *);
! 79: paddr_t _pyro_bus_mmap(bus_space_tag_t, bus_space_tag_t, bus_addr_t, off_t,
! 80: int, int);
! 81: void *_pyro_intr_establish(bus_space_tag_t, bus_space_tag_t, int, int, int,
! 82: int (*)(void *), void *, const char *);
! 83:
! 84: int pyro_dmamap_create(bus_dma_tag_t, bus_dma_tag_t, bus_size_t, int,
! 85: bus_size_t, bus_size_t, int, bus_dmamap_t *);
! 86:
! 87: int
! 88: pyro_match(struct device *parent, void *match, void *aux)
! 89: {
! 90: struct mainbus_attach_args *ma = aux;
! 91: char *str;
! 92:
! 93: if (strcmp(ma->ma_name, "pci") != 0)
! 94: return (0);
! 95:
! 96: str = getpropstring(ma->ma_node, "compatible");
! 97: if (strcmp(str, "pciex108e,80f0") == 0)
! 98: return (1);
! 99:
! 100: return (0);
! 101: }
! 102:
! 103: void
! 104: pyro_attach(struct device *parent, struct device *self, void *aux)
! 105: {
! 106: struct pyro_softc *sc = (struct pyro_softc *)self;
! 107: struct mainbus_attach_args *ma = aux;
! 108: int busa;
! 109:
! 110: sc->sc_node = ma->ma_node;
! 111: sc->sc_dmat = ma->ma_dmatag;
! 112: sc->sc_bust = ma->ma_bustag;
! 113: sc->sc_csr = ma->ma_reg[0].ur_paddr;
! 114: sc->sc_xbc = ma->ma_reg[1].ur_paddr;
! 115: sc->sc_ign = INTIGN(ma->ma_upaid << INTMAP_IGN_SHIFT);
! 116:
! 117: if ((ma->ma_reg[0].ur_paddr & 0x00700000) == 0x00600000)
! 118: busa = 1;
! 119: else
! 120: busa = 0;
! 121:
! 122: if (bus_space_map(sc->sc_bust, sc->sc_csr,
! 123: ma->ma_reg[0].ur_len, 0, &sc->sc_csrh)) {
! 124: printf(": failed to map csr registers\n");
! 125: return;
! 126: }
! 127:
! 128: if (bus_space_map(sc->sc_bust, sc->sc_xbc,
! 129: ma->ma_reg[1].ur_len, 0, &sc->sc_xbch)) {
! 130: printf(": failed to map xbc registers\n");
! 131: return;
! 132: }
! 133:
! 134: pyro_init(sc, busa);
! 135: }
! 136:
! 137: void
! 138: pyro_init(struct pyro_softc *sc, int busa)
! 139: {
! 140: struct pyro_pbm *pbm;
! 141: struct pcibus_attach_args pba;
! 142: int *busranges = NULL, nranges;
! 143:
! 144: pbm = (struct pyro_pbm *)malloc(sizeof(*pbm), M_DEVBUF, M_NOWAIT);
! 145: if (pbm == NULL)
! 146: panic("pyro: can't alloc pyro pbm");
! 147: bzero(pbm, sizeof(*pbm));
! 148:
! 149: pbm->pp_sc = sc;
! 150: pbm->pp_bus_a = busa;
! 151:
! 152: if (getprop(sc->sc_node, "ranges", sizeof(struct pyro_range),
! 153: &pbm->pp_nrange, (void **)&pbm->pp_range))
! 154: panic("pyro: can't get ranges");
! 155:
! 156: if (getprop(sc->sc_node, "bus-range", sizeof(int), &nranges,
! 157: (void **)&busranges))
! 158: panic("pyro: can't get bus-range");
! 159:
! 160: printf(": \"%s\", rev %d, ign %x, bus %c %d to %d\n",
! 161: sc->sc_oberon ? "Oberon" : "Fire",
! 162: getpropint(sc->sc_node, "module-revision#", 0), sc->sc_ign,
! 163: busa ? 'A' : 'B', busranges[0], busranges[1]);
! 164:
! 165: printf("%s: ", sc->sc_dv.dv_xname);
! 166: pyro_init_iommu(sc, pbm);
! 167:
! 168: pbm->pp_memt = pyro_alloc_mem_tag(pbm);
! 169: pbm->pp_iot = pyro_alloc_io_tag(pbm);
! 170: pbm->pp_cfgt = pyro_alloc_config_tag(pbm);
! 171: pbm->pp_dmat = pyro_alloc_dma_tag(pbm);
! 172:
! 173: if (bus_space_map(pbm->pp_cfgt, 0, 0x10000000, 0, &pbm->pp_cfgh))
! 174: panic("pyro: could not map config space");
! 175:
! 176: pbm->pp_pc = pyro_alloc_chipset(pbm, sc->sc_node, &_sparc_pci_chipset);
! 177:
! 178: pbm->pp_pc->bustag = pbm->pp_cfgt;
! 179: pbm->pp_pc->bushandle = pbm->pp_cfgh;
! 180:
! 181: pba.pba_busname = "pci";
! 182: pba.pba_domain = pci_ndomains++;
! 183: pba.pba_bus = busranges[0];
! 184: pba.pba_bridgetag = NULL;
! 185: pba.pba_pc = pbm->pp_pc;
! 186: #if 0
! 187: pba.pba_flags = pbm->pp_flags;
! 188: #endif
! 189: pba.pba_dmat = pbm->pp_dmat;
! 190: pba.pba_memt = pbm->pp_memt;
! 191: pba.pba_iot = pbm->pp_iot;
! 192: pba.pba_pc->intr_map = pyro_intr_map;
! 193:
! 194: free(busranges, M_DEVBUF);
! 195:
! 196: config_found(&sc->sc_dv, &pba, pyro_print);
! 197: }
! 198:
! 199: void
! 200: pyro_init_iommu(struct pyro_softc *sc, struct pyro_pbm *pbm)
! 201: {
! 202: struct iommu_state *is = &pbm->pp_is;
! 203: int tsbsize = 7;
! 204: u_int32_t iobase = -1;
! 205: char *name;
! 206:
! 207: is->is_bustag = sc->sc_bust;
! 208:
! 209: if (bus_space_subregion(is->is_bustag, sc->sc_csrh,
! 210: 0x40000, 0x100, &is->is_iommu)) {
! 211: panic("pyro: unable to create iommu handle");
! 212: }
! 213:
! 214: is->is_sb[0] = &pbm->pp_sb;
! 215: is->is_sb[0]->sb_bustag = is->is_bustag;
! 216:
! 217: name = (char *)malloc(32, M_DEVBUF, M_NOWAIT);
! 218: if (name == NULL)
! 219: panic("couldn't malloc iommu name");
! 220: snprintf(name, 32, "%s dvma", sc->sc_dv.dv_xname);
! 221:
! 222: iommu_init(name, is, tsbsize, iobase);
! 223: }
! 224:
! 225: int
! 226: pyro_print(void *aux, const char *p)
! 227: {
! 228: if (p == NULL)
! 229: return (UNCONF);
! 230: return (QUIET);
! 231: }
! 232:
! 233: /*
! 234: * Bus-specific interrupt mapping
! 235: */
! 236: int
! 237: pyro_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
! 238: {
! 239: struct pyro_pbm *pp = pa->pa_pc->cookie;
! 240: struct pyro_softc *sc = pp->pp_sc;
! 241: u_int dev;
! 242:
! 243: if (*ihp != (pci_intr_handle_t)-1) {
! 244: *ihp |= sc->sc_ign;
! 245: return (0);
! 246: }
! 247:
! 248: /*
! 249: * We didn't find a PROM mapping for this interrupt. Try to
! 250: * construct one ourselves based on the swizzled interrupt pin
! 251: * and the interrupt mapping for PCI slots documented in the
! 252: * UltraSPARC-IIi User's Manual.
! 253: */
! 254:
! 255: if (pa->pa_intrpin == 0)
! 256: return (-1);
! 257:
! 258: /*
! 259: * This deserves some documentation. Should anyone
! 260: * have anything official looking, please speak up.
! 261: */
! 262: dev = pa->pa_device - 1;
! 263:
! 264: *ihp = (pa->pa_intrpin - 1) & INTMAP_PCIINT;
! 265: *ihp |= (dev << 2) & INTMAP_PCISLOT;
! 266: *ihp |= sc->sc_ign;
! 267:
! 268: return (0);
! 269: }
! 270:
! 271: bus_space_tag_t
! 272: pyro_alloc_mem_tag(struct pyro_pbm *pp)
! 273: {
! 274: return (_pyro_alloc_bus_tag(pp, "mem",
! 275: 0x02, /* 32-bit mem space (where's the #define???) */
! 276: ASI_PRIMARY, ASI_PRIMARY_LITTLE));
! 277: }
! 278:
! 279: bus_space_tag_t
! 280: pyro_alloc_io_tag(struct pyro_pbm *pp)
! 281: {
! 282: return (_pyro_alloc_bus_tag(pp, "io",
! 283: 0x01, /* IO space (where's the #define???) */
! 284: ASI_PHYS_NON_CACHED_LITTLE, ASI_PHYS_NON_CACHED));
! 285: }
! 286:
! 287: bus_space_tag_t
! 288: pyro_alloc_config_tag(struct pyro_pbm *pp)
! 289: {
! 290: return (_pyro_alloc_bus_tag(pp, "cfg",
! 291: 0x00, /* Config space (where's the #define???) */
! 292: ASI_PHYS_NON_CACHED_LITTLE, ASI_PHYS_NON_CACHED));
! 293: }
! 294:
! 295: bus_space_tag_t
! 296: _pyro_alloc_bus_tag(struct pyro_pbm *pbm, const char *name, int ss,
! 297: int asi, int sasi)
! 298: {
! 299: struct pyro_softc *sc = pbm->pp_sc;
! 300: struct sparc_bus_space_tag *bt;
! 301:
! 302: bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT);
! 303: if (bt == NULL)
! 304: panic("pyro: could not allocate bus tag");
! 305:
! 306: bzero(bt, sizeof *bt);
! 307: snprintf(bt->name, sizeof(bt->name), "%s-pbm_%s(%d/%2.2x)",
! 308: sc->sc_dv.dv_xname, name, ss, asi);
! 309:
! 310: bt->cookie = pbm;
! 311: bt->parent = sc->sc_bust;
! 312: bt->default_type = ss;
! 313: bt->asi = asi;
! 314: bt->sasi = sasi;
! 315: bt->sparc_bus_map = _pyro_bus_map;
! 316: bt->sparc_bus_mmap = _pyro_bus_mmap;
! 317: bt->sparc_intr_establish = _pyro_intr_establish;
! 318: return (bt);
! 319: }
! 320:
! 321: bus_dma_tag_t
! 322: pyro_alloc_dma_tag(struct pyro_pbm *pbm)
! 323: {
! 324: struct pyro_softc *sc = pbm->pp_sc;
! 325: bus_dma_tag_t dt, pdt = sc->sc_dmat;
! 326:
! 327: dt = (bus_dma_tag_t)malloc(sizeof(struct sparc_bus_dma_tag),
! 328: M_DEVBUF, M_NOWAIT);
! 329: if (dt == NULL)
! 330: panic("pyro: could not alloc dma tag");
! 331:
! 332: bzero(dt, sizeof(*dt));
! 333: dt->_cookie = pbm;
! 334: dt->_parent = pdt;
! 335: dt->_dmamap_create = pyro_dmamap_create;
! 336: dt->_dmamap_destroy = iommu_dvmamap_destroy;
! 337: dt->_dmamap_load = iommu_dvmamap_load;
! 338: dt->_dmamap_load_raw = iommu_dvmamap_load_raw;
! 339: dt->_dmamap_unload = iommu_dvmamap_unload;
! 340: dt->_dmamap_sync = iommu_dvmamap_sync;
! 341: dt->_dmamem_alloc = iommu_dvmamem_alloc;
! 342: dt->_dmamem_free = iommu_dvmamem_free;
! 343: dt->_dmamem_map = iommu_dvmamem_map;
! 344: dt->_dmamem_unmap = iommu_dvmamem_unmap;
! 345: return (dt);
! 346: }
! 347:
! 348: pci_chipset_tag_t
! 349: pyro_alloc_chipset(struct pyro_pbm *pbm, int node, pci_chipset_tag_t pc)
! 350: {
! 351: pci_chipset_tag_t npc;
! 352:
! 353: npc = malloc(sizeof *npc, M_DEVBUF, M_NOWAIT);
! 354: if (npc == NULL)
! 355: panic("pyro: could not allocate pci_chipset_tag_t");
! 356: memcpy(npc, pc, sizeof *pc);
! 357: npc->cookie = pbm;
! 358: npc->rootnode = node;
! 359: npc->tagshift = 4; /* PCIe has a larger config space */
! 360: return (npc);
! 361: }
! 362:
! 363: int
! 364: pyro_dmamap_create(bus_dma_tag_t t, bus_dma_tag_t t0, bus_size_t size,
! 365: int nsegments, bus_size_t maxsegsz, bus_size_t boundary, int flags,
! 366: bus_dmamap_t *dmamp)
! 367: {
! 368: struct pyro_pbm *pp = t->_cookie;
! 369:
! 370: return (iommu_dvmamap_create(t, t0, &pp->pp_sb, size, nsegments,
! 371: maxsegsz, boundary, flags, dmamp));
! 372: }
! 373:
! 374: int
! 375: _pyro_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset,
! 376: bus_size_t size, int flags, bus_space_handle_t *hp)
! 377: {
! 378: struct pyro_pbm *pbm = t->cookie;
! 379: int i, ss;
! 380:
! 381: DPRINTF(PDB_BUSMAP, ("_pyro_bus_map: type %d off %qx sz %qx flags %d",
! 382: t->default_type,
! 383: (unsigned long long)offset,
! 384: (unsigned long long)size,
! 385: flags));
! 386:
! 387: ss = t->default_type;
! 388: DPRINTF(PDB_BUSMAP, (" cspace %d", ss));
! 389:
! 390: if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
! 391: printf("\n_pyro_bus_map: invalid parent");
! 392: return (EINVAL);
! 393: }
! 394:
! 395: if (flags & BUS_SPACE_MAP_PROMADDRESS) {
! 396: return ((*t->parent->sparc_bus_map)
! 397: (t, t0, offset, size, flags, hp));
! 398: }
! 399:
! 400: for (i = 0; i < pbm->pp_nrange; i++) {
! 401: bus_addr_t paddr;
! 402:
! 403: if (((pbm->pp_range[i].cspace >> 24) & 0x03) != ss)
! 404: continue;
! 405:
! 406: paddr = pbm->pp_range[i].phys_lo + offset;
! 407: paddr |= ((bus_addr_t)pbm->pp_range[i].phys_hi) << 32;
! 408: return ((*t->parent->sparc_bus_map)
! 409: (t, t0, paddr, size, flags, hp));
! 410: }
! 411:
! 412: return (EINVAL);
! 413: }
! 414:
! 415: paddr_t
! 416: _pyro_bus_mmap(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t paddr,
! 417: off_t off, int prot, int flags)
! 418: {
! 419: bus_addr_t offset = paddr;
! 420: struct pyro_pbm *pbm = t->cookie;
! 421: int i, ss;
! 422:
! 423: ss = t->default_type;
! 424:
! 425: DPRINTF(PDB_BUSMAP, ("_pyro_bus_mmap: prot %d flags %d pa %qx\n",
! 426: prot, flags, (unsigned long long)paddr));
! 427:
! 428: if (t->parent == 0 || t->parent->sparc_bus_mmap == 0) {
! 429: printf("\n_pyro_bus_mmap: invalid parent");
! 430: return (-1);
! 431: }
! 432:
! 433: for (i = 0; i < pbm->pp_nrange; i++) {
! 434: bus_addr_t paddr;
! 435:
! 436: if (((pbm->pp_range[i].cspace >> 24) & 0x03) != ss)
! 437: continue;
! 438:
! 439: paddr = pbm->pp_range[i].phys_lo + offset;
! 440: paddr |= ((bus_addr_t)pbm->pp_range[i].phys_hi<<32);
! 441: return ((*t->parent->sparc_bus_mmap)
! 442: (t, t0, paddr, off, prot, flags));
! 443: }
! 444:
! 445: return (-1);
! 446: }
! 447:
! 448: void *
! 449: _pyro_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
! 450: int level, int flags, int (*handler)(void *), void *arg, const char *what)
! 451: {
! 452: struct pyro_pbm *pbm = t->cookie;
! 453: struct pyro_softc *sc = pbm->pp_sc;
! 454: struct intrhand *ih = NULL;
! 455: volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
! 456: int ino;
! 457:
! 458: ino = INTINO(ihandle);
! 459:
! 460: if (level == IPL_NONE)
! 461: level = INTLEV(ihandle);
! 462: if (level == IPL_NONE) {
! 463: printf(": no IPL, setting IPL 2.\n");
! 464: level = 2;
! 465: }
! 466:
! 467: if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) == 0) {
! 468: u_int64_t *imap, *iclr;
! 469:
! 470: imap = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1000;
! 471: iclr = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1400;
! 472: intrmapptr = &imap[ino];
! 473: intrclrptr = &iclr[ino];
! 474: ino |= INTVEC(ihandle);
! 475: }
! 476:
! 477: ih = bus_intr_allocate(t0, handler, arg, ino, level, intrmapptr,
! 478: intrclrptr, what);
! 479: if (ih == NULL)
! 480: return (NULL);
! 481:
! 482: intr_establish(ih->ih_pil, ih);
! 483:
! 484: if (intrmapptr != NULL) {
! 485: u_int64_t intrmap;
! 486:
! 487: intrmap = *intrmapptr;
! 488: intrmap |= (1LL << 6);
! 489: intrmap |= INTMAP_V;
! 490: *intrmapptr = intrmap;
! 491: intrmap = *intrmapptr;
! 492: ih->ih_number |= intrmap & INTMAP_INR;
! 493: }
! 494:
! 495: return (ih);
! 496: }
! 497:
! 498: const struct cfattach pyro_ca = {
! 499: sizeof(struct pyro_softc), pyro_match, pyro_attach
! 500: };
! 501:
! 502: struct cfdriver pyro_cd = {
! 503: NULL, "pyro", DV_DULL
! 504: };
CVSweb