Annotation of sys/arch/sparc64/dev/psycho.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: psycho.c,v 1.52 2007/08/04 16:44:15 kettenis Exp $ */
! 2: /* $NetBSD: psycho.c,v 1.39 2001/10/07 20:30:41 eeh Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1999, 2000 Matthew R. Green
! 6: * Copyright (c) 2003 Henric Jungheim
! 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: * 3. The name of the author may not be used to endorse or promote products
! 18: * derived from this software without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 21: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 22: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 23: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 24: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
! 25: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
! 26: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
! 27: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
! 28: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: */
! 32:
! 33: /*
! 34: * Support for `psycho' and `psycho+' UPA to PCI bridge and
! 35: * UltraSPARC IIi and IIe `sabre' PCI controllers.
! 36: */
! 37:
! 38: #include <sys/param.h>
! 39: #include <sys/device.h>
! 40: #include <sys/errno.h>
! 41: #include <sys/extent.h>
! 42: #include <sys/malloc.h>
! 43: #include <sys/systm.h>
! 44: #include <sys/time.h>
! 45: #include <sys/reboot.h>
! 46:
! 47: #include <uvm/uvm_extern.h>
! 48:
! 49: #define _SPARC_BUS_DMA_PRIVATE
! 50: #include <machine/bus.h>
! 51: #include <machine/autoconf.h>
! 52: #include <machine/psl.h>
! 53:
! 54: #include <dev/pci/pcivar.h>
! 55: #include <dev/pci/pcireg.h>
! 56:
! 57: #include <sparc64/dev/iommureg.h>
! 58: #include <sparc64/dev/iommuvar.h>
! 59: #include <sparc64/dev/psychoreg.h>
! 60: #include <sparc64/dev/psychovar.h>
! 61: #include <sparc64/sparc64/cache.h>
! 62:
! 63: #ifdef DEBUG
! 64: #define PDB_PROM 0x01
! 65: #define PDB_BUSMAP 0x02
! 66: #define PDB_INTR 0x04
! 67: #define PDB_CONF 0x08
! 68: int psycho_debug = ~0;
! 69: #define DPRINTF(l, s) do { if (psycho_debug & l) printf s; } while (0)
! 70: #else
! 71: #define DPRINTF(l, s)
! 72: #endif
! 73:
! 74: pci_chipset_tag_t psycho_alloc_chipset(struct psycho_pbm *, int,
! 75: pci_chipset_tag_t);
! 76: void psycho_get_bus_range(int, int *);
! 77: void psycho_get_ranges(int, struct psycho_ranges **, int *);
! 78: void psycho_set_intr(struct psycho_softc *, int, void *,
! 79: u_int64_t *, u_int64_t *, const char *);
! 80: bus_space_tag_t psycho_alloc_bus_tag(struct psycho_pbm *,
! 81: const char *, int, int, int);
! 82:
! 83: /* Interrupt handlers */
! 84: int psycho_ue(void *);
! 85: int psycho_ce(void *);
! 86: int psycho_bus_a(void *);
! 87: int psycho_bus_b(void *);
! 88: int psycho_bus_error(struct psycho_softc *, int);
! 89: int psycho_powerfail(void *);
! 90: int psycho_wakeup(void *);
! 91:
! 92: /* IOMMU support */
! 93: void psycho_iommu_init(struct psycho_softc *, int);
! 94:
! 95: /*
! 96: * bus space and bus dma support for UltraSPARC `psycho'. note that most
! 97: * of the bus dma support is provided by the iommu dvma controller.
! 98: */
! 99: int psycho_bus_map(bus_space_tag_t, bus_space_tag_t, bus_addr_t,
! 100: bus_size_t, int, bus_space_handle_t *);
! 101: paddr_t psycho_bus_mmap(bus_space_tag_t, bus_space_tag_t, bus_addr_t, off_t,
! 102: int, int);
! 103: bus_addr_t psycho_bus_addr(bus_space_tag_t, bus_space_tag_t,
! 104: bus_space_handle_t);
! 105: void *psycho_intr_establish(bus_space_tag_t, bus_space_tag_t, int, int, int,
! 106: int (*)(void *), void *, const char *);
! 107:
! 108: int psycho_dmamap_create(bus_dma_tag_t, bus_dma_tag_t, bus_size_t, int,
! 109: bus_size_t, bus_size_t, int, bus_dmamap_t *);
! 110: void psycho_sabre_dvmamap_sync(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t,
! 111: bus_size_t, bus_size_t, int);
! 112: void psycho_map_psycho(struct psycho_softc *, int, bus_addr_t, bus_size_t,
! 113: bus_addr_t, bus_size_t);
! 114: int psycho_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
! 115: void psycho_identify_pbm(struct psycho_softc *sc, struct psycho_pbm *pp,
! 116: struct pcibus_attach_args *pa);
! 117:
! 118: /* base pci_chipset */
! 119: extern struct sparc_pci_chipset _sparc_pci_chipset;
! 120:
! 121: /*
! 122: * autoconfiguration
! 123: */
! 124: int psycho_match(struct device *, void *, void *);
! 125: void psycho_attach(struct device *, struct device *, void *);
! 126: int psycho_print(void *aux, const char *p);
! 127:
! 128:
! 129: struct cfattach psycho_ca = {
! 130: sizeof(struct psycho_softc), psycho_match, psycho_attach
! 131: };
! 132:
! 133: struct cfdriver psycho_cd = {
! 134: NULL, "psycho", DV_DULL
! 135: };
! 136:
! 137: /*
! 138: * "sabre" is the UltraSPARC IIi onboard UPA to PCI bridge. It manages a
! 139: * single PCI bus and does not have a streaming buffer. It often has an APB
! 140: * (advanced PCI bridge) connected to it, which was designed specifically for
! 141: * the IIi. The APB let's the IIi handle two independednt PCI buses, and
! 142: * appears as two "simba"'s underneath the sabre.
! 143: *
! 144: * "psycho" and "psycho+" is a dual UPA to PCI bridge. It sits on the UPA bus
! 145: * and manages two PCI buses. "psycho" has two 64-bit 33MHz buses, while
! 146: * "psycho+" controls both a 64-bit 33MHz and a 64-bit 66MHz PCI bus. You
! 147: * will usually find a "psycho+" since I don't think the original "psycho"
! 148: * ever shipped, and if it did it would be in the U30.
! 149: *
! 150: * Each "psycho" PCI bus appears as a separate OFW node, but since they are
! 151: * both part of the same IC, they only have a single register space. As such,
! 152: * they need to be configured together, even though the autoconfiguration will
! 153: * attach them separately.
! 154: *
! 155: * On UltraIIi machines, "sabre" itself usually takes pci0, with "simba" often
! 156: * as pci1 and pci2, although they have been implemented with other PCI bus
! 157: * numbers on some machines.
! 158: *
! 159: * On UltraII machines, there can be any number of "psycho+" ICs, each
! 160: * providing two PCI buses.
! 161: *
! 162: *
! 163: * XXXX The psycho/sabre node has an `interrupts' attribute. They contain
! 164: * the values of the following interrupts in this order:
! 165: *
! 166: * PCI Bus Error (30)
! 167: * DMA UE (2e)
! 168: * DMA CE (2f)
! 169: * Power Fail (25)
! 170: *
! 171: * We really should attach handlers for each.
! 172: *
! 173: */
! 174: #define ROM_PCI_NAME "pci"
! 175:
! 176: struct psycho_type {
! 177: char *p_name;
! 178: int p_type;
! 179: } psycho_types[] = {
! 180: { "SUNW,psycho", PSYCHO_MODE_PSYCHO },
! 181: { "pci108e,8000", PSYCHO_MODE_PSYCHO },
! 182: { "SUNW,sabre", PSYCHO_MODE_SABRE },
! 183: { "pci108e,a000", PSYCHO_MODE_SABRE },
! 184: { "pci108e,a001", PSYCHO_MODE_SABRE },
! 185: { NULL, 0 }
! 186: };
! 187:
! 188: int
! 189: psycho_match(struct device *parent, void *match, void *aux)
! 190: {
! 191: struct mainbus_attach_args *ma = aux;
! 192: struct psycho_type *ptype;
! 193: char *str;
! 194:
! 195: /* match on a name of "pci" and a sabre or a psycho */
! 196: if (strcmp(ma->ma_name, ROM_PCI_NAME) != 0)
! 197: return (0);
! 198:
! 199: for (ptype = psycho_types; ptype->p_name != NULL; ptype++) {
! 200: str = getpropstring(ma->ma_node, "model");
! 201: if (strcmp(str, ptype->p_name) == 0)
! 202: return (1);
! 203: str = getpropstring(ma->ma_node, "compatible");
! 204: if (strcmp(str, ptype->p_name) == 0)
! 205: return (1);
! 206: }
! 207: return (0);
! 208: }
! 209:
! 210: /*
! 211: * SUNW,psycho initialization ...
! 212: * - find the per-psycho registers
! 213: * - figure out the IGN.
! 214: * - find our partner psycho
! 215: * - configure ourselves
! 216: * - bus range, bus,
! 217: * - get interrupt-map and interrupt-map-mask
! 218: * - setup the chipsets.
! 219: * - if we're the first of the pair, initialise the IOMMU, otherwise
! 220: * just copy its tags and addresses.
! 221: */
! 222: void
! 223: psycho_attach(struct device *parent, struct device *self, void *aux)
! 224: {
! 225: struct psycho_softc *sc = (struct psycho_softc *)self;
! 226: struct psycho_softc *osc = NULL;
! 227: struct psycho_pbm *pp;
! 228: struct pcibus_attach_args pba;
! 229: struct mainbus_attach_args *ma = aux;
! 230: u_int64_t csr;
! 231: int psycho_br[2], n;
! 232: struct psycho_type *ptype;
! 233:
! 234: sc->sc_node = ma->ma_node;
! 235: sc->sc_bustag = ma->ma_bustag;
! 236: sc->sc_dmatag = ma->ma_dmatag;
! 237:
! 238: /*
! 239: * call the model-specific initialization routine.
! 240: */
! 241:
! 242: for (ptype = psycho_types; ptype->p_name != NULL; ptype++) {
! 243: char *str;
! 244:
! 245: str = getpropstring(ma->ma_node, "model");
! 246: if (strcmp(str, ptype->p_name) == 0)
! 247: break;
! 248: str = getpropstring(ma->ma_node, "compatible");
! 249: if (strcmp(str, ptype->p_name) == 0)
! 250: break;
! 251: }
! 252: if (ptype->p_name == NULL)
! 253: panic("psycho_attach: unknown model?");
! 254: sc->sc_mode = ptype->p_type;
! 255:
! 256: /*
! 257: * The psycho gets three register banks:
! 258: * (0) per-PBM configuration and status registers
! 259: * (1) per-PBM PCI configuration space, containing only the
! 260: * PBM 256-byte PCI header
! 261: * (2) the shared psycho configuration registers (struct psychoreg)
! 262: *
! 263: * XXX use the prom address for the psycho registers? we do so far.
! 264: */
! 265:
! 266: /* Register layouts are different. stuupid. */
! 267: if (sc->sc_mode == PSYCHO_MODE_PSYCHO) {
! 268: sc->sc_basepaddr = (paddr_t)ma->ma_reg[2].ur_paddr;
! 269:
! 270: if (ma->ma_naddress > 2) {
! 271: psycho_map_psycho(sc, 0,
! 272: ma->ma_address[2], sizeof(struct psychoreg),
! 273: ma->ma_address[0], sizeof(struct pci_ctl));
! 274: } else if (ma->ma_nreg > 2) {
! 275: psycho_map_psycho(sc, 1,
! 276: ma->ma_reg[2].ur_paddr, ma->ma_reg[2].ur_len,
! 277: ma->ma_reg[0].ur_paddr, ma->ma_reg[0].ur_len);
! 278: } else
! 279: panic("psycho_attach: %d not enough registers",
! 280: ma->ma_nreg);
! 281: } else {
! 282: sc->sc_basepaddr = (paddr_t)ma->ma_reg[0].ur_paddr;
! 283:
! 284: if (ma->ma_naddress) {
! 285: psycho_map_psycho(sc, 0,
! 286: ma->ma_address[0], sizeof(struct psychoreg),
! 287: ma->ma_address[0] +
! 288: offsetof(struct psychoreg, psy_pcictl[0]),
! 289: sizeof(struct pci_ctl));
! 290: } else if (ma->ma_nreg) {
! 291: psycho_map_psycho(sc, 1,
! 292: ma->ma_reg[0].ur_paddr, ma->ma_reg[0].ur_len,
! 293: ma->ma_reg[0].ur_paddr +
! 294: offsetof(struct psychoreg, psy_pcictl[0]),
! 295: sizeof(struct pci_ctl));
! 296: } else
! 297: panic("psycho_attach: %d not enough registers",
! 298: ma->ma_nreg);
! 299: }
! 300:
! 301: csr = psycho_psychoreg_read(sc, psy_csr);
! 302: sc->sc_ign = INTMAP_IGN; /* APB IGN is always 0x1f << 6 = 0x7c */
! 303: if (sc->sc_mode == PSYCHO_MODE_PSYCHO)
! 304: sc->sc_ign = PSYCHO_GCSR_IGN(csr) << 6;
! 305:
! 306: printf(": %s, impl %d, version %d, ign %x\n", ptype->p_name,
! 307: PSYCHO_GCSR_IMPL(csr), PSYCHO_GCSR_VERS(csr), sc->sc_ign);
! 308:
! 309: /*
! 310: * Match other psycho's that are already configured against
! 311: * the base physical address. This will be the same for a
! 312: * pair of devices that share register space.
! 313: */
! 314: for (n = 0; n < psycho_cd.cd_ndevs; n++) {
! 315: struct psycho_softc *asc =
! 316: (struct psycho_softc *)psycho_cd.cd_devs[n];
! 317:
! 318: if (asc == NULL || asc == sc)
! 319: /* This entry is not there or it is me */
! 320: continue;
! 321:
! 322: if (asc->sc_basepaddr != sc->sc_basepaddr)
! 323: /* This is an unrelated psycho */
! 324: continue;
! 325:
! 326: /* Found partner */
! 327: osc = asc;
! 328: break;
! 329: }
! 330:
! 331: /* Oh, dear. OK, lets get started */
! 332:
! 333: /*
! 334: * Setup the PCI control register
! 335: */
! 336: csr = psycho_pcictl_read(sc, pci_csr);
! 337: csr |= PCICTL_MRLM | PCICTL_ARB_PARK | PCICTL_ERRINTEN |
! 338: PCICTL_4ENABLE;
! 339: csr &= ~(PCICTL_SERR | PCICTL_CPU_PRIO | PCICTL_ARB_PRIO |
! 340: PCICTL_RTRYWAIT);
! 341: psycho_pcictl_write(sc, pci_csr, csr);
! 342:
! 343: /*
! 344: * Allocate our psycho_pbm
! 345: */
! 346: pp = sc->sc_psycho_this = malloc(sizeof *pp, M_DEVBUF, M_NOWAIT);
! 347: if (pp == NULL)
! 348: panic("could not allocate psycho pbm");
! 349:
! 350: memset(pp, 0, sizeof *pp);
! 351:
! 352: pp->pp_sc = sc;
! 353:
! 354: /* grab the psycho ranges */
! 355: psycho_get_ranges(sc->sc_node, &pp->pp_range, &pp->pp_nrange);
! 356:
! 357: /* get the bus-range for the psycho */
! 358: psycho_get_bus_range(sc->sc_node, psycho_br);
! 359:
! 360: pba.pba_domain = pci_ndomains++;
! 361: pba.pba_bus = psycho_br[0];
! 362: pba.pba_bridgetag = NULL;
! 363:
! 364: printf("%s: bus range %u-%u, PCI bus %d\n", sc->sc_dev.dv_xname,
! 365: psycho_br[0], psycho_br[1], psycho_br[0]);
! 366:
! 367: pp->pp_pcictl = sc->sc_pcictl;
! 368:
! 369: /* allocate our tags */
! 370: pp->pp_memt = psycho_alloc_mem_tag(pp);
! 371: pp->pp_iot = psycho_alloc_io_tag(pp);
! 372: pp->pp_dmat = psycho_alloc_dma_tag(pp);
! 373: pp->pp_flags = (pp->pp_memt ? PCI_FLAGS_MEM_ENABLED : 0) |
! 374: (pp->pp_iot ? PCI_FLAGS_IO_ENABLED : 0);
! 375:
! 376: /* allocate a chipset for this */
! 377: pp->pp_pc = psycho_alloc_chipset(pp, sc->sc_node, &_sparc_pci_chipset);
! 378:
! 379: /* setup the rest of the psycho pbm */
! 380: pba.pba_pc = pp->pp_pc;
! 381:
! 382: /*
! 383: * And finally, if we're a sabre or the first of a pair of psycho's to
! 384: * arrive here, start up the IOMMU and get a config space tag.
! 385: */
! 386:
! 387: if (osc == NULL) {
! 388: uint64_t timeo;
! 389:
! 390: /*
! 391: * Establish handlers for interesting interrupts....
! 392: *
! 393: * XXX We need to remember these and remove this to support
! 394: * hotplug on the UPA/FHC bus.
! 395: *
! 396: * XXX Not all controllers have these, but installing them
! 397: * is better than trying to sort through this mess.
! 398: */
! 399: psycho_set_intr(sc, 15, psycho_ue,
! 400: psycho_psychoreg_vaddr(sc, ue_int_map),
! 401: psycho_psychoreg_vaddr(sc, ue_clr_int), "ue");
! 402: psycho_set_intr(sc, 1, psycho_ce,
! 403: psycho_psychoreg_vaddr(sc, ce_int_map),
! 404: psycho_psychoreg_vaddr(sc, ce_clr_int), "ce");
! 405: psycho_set_intr(sc, 15, psycho_bus_a,
! 406: psycho_psychoreg_vaddr(sc, pciaerr_int_map),
! 407: psycho_psychoreg_vaddr(sc, pciaerr_clr_int), "bus_a");
! 408: #if 0
! 409: psycho_set_intr(sc, 15, psycho_powerfail,
! 410: psycho_psychoreg_vaddr(sc, power_int_map),
! 411: psycho_psychoreg_vaddr(sc, power_clr_int), "powerfail");
! 412: #endif
! 413: if (sc->sc_mode == PSYCHO_MODE_PSYCHO) {
! 414: psycho_set_intr(sc, 15, psycho_bus_b,
! 415: psycho_psychoreg_vaddr(sc, pciberr_int_map),
! 416: psycho_psychoreg_vaddr(sc, pciberr_clr_int),
! 417: "bus_b");
! 418: psycho_set_intr(sc, 1, psycho_wakeup,
! 419: psycho_psychoreg_vaddr(sc, pwrmgt_int_map),
! 420: psycho_psychoreg_vaddr(sc, pwrmgt_clr_int),
! 421: "wakeup");
! 422: }
! 423:
! 424: /*
! 425: * Apparently a number of machines with psycho and psycho+
! 426: * controllers have interrupt latency issues. We'll try
! 427: * setting the interrupt retry timeout to 0xff which gives us
! 428: * a retry of 3-6 usec (which is what sysio is set to) for the
! 429: * moment, which seems to help alleviate this problem.
! 430: */
! 431: timeo = psycho_psychoreg_read(sc, intr_retry_timer);
! 432: if (timeo > 0xfff) {
! 433: #ifdef DEBUG
! 434: printf("decreasing interrupt retry timeout "
! 435: "from %lx to 0xff\n", (long)timeo);
! 436: #endif
! 437: psycho_psychoreg_write(sc, intr_retry_timer, 0xff);
! 438: }
! 439:
! 440: /*
! 441: * Setup IOMMU and PCI configuration if we're the first
! 442: * of a pair of psycho's to arrive here.
! 443: *
! 444: * We should calculate a TSB size based on the amount of RAM,
! 445: * number of bus controllers, and number and type of child
! 446: * devices.
! 447: *
! 448: * For the moment, 32KB should be more than enough.
! 449: */
! 450: sc->sc_is = malloc(sizeof(struct iommu_state),
! 451: M_DEVBUF, M_NOWAIT);
! 452: if (sc->sc_is == NULL)
! 453: panic("psycho_attach: malloc iommu_state");
! 454:
! 455: memset(sc->sc_is, 0, sizeof *sc->sc_is);
! 456:
! 457: if (getproplen(sc->sc_node, "no-streaming-cache") < 0) {
! 458: struct strbuf_ctl *sb = &pp->pp_sb;
! 459: vaddr_t va = (vaddr_t)&pp->pp_flush[0x40];
! 460:
! 461: /*
! 462: * Initialize the strbuf_ctl.
! 463: *
! 464: * The flush sync buffer must be 64-byte aligned.
! 465: */
! 466:
! 467: sb->sb_flush = (void *)(va & ~0x3f);
! 468:
! 469: sb->sb_bustag = sc->sc_bustag;
! 470: if (bus_space_subregion(sc->sc_bustag, sc->sc_pcictl,
! 471: offsetof(struct pci_ctl, pci_strbuf),
! 472: sizeof(struct iommu_strbuf),
! 473: &sb->sb_sb)) {
! 474: printf("STC0 subregion failed\n");
! 475: sb->sb_flush = 0;
! 476: }
! 477: }
! 478:
! 479: /* Point out iommu at the strbuf_ctl. */
! 480: sc->sc_is->is_sb[0] = &pp->pp_sb;
! 481:
! 482: printf("%s: ", sc->sc_dev.dv_xname);
! 483: psycho_iommu_init(sc, 2);
! 484:
! 485: sc->sc_configtag = psycho_alloc_config_tag(sc->sc_psycho_this);
! 486: if (bus_space_map(sc->sc_configtag,
! 487: sc->sc_basepaddr, 0x01000000, 0, &sc->sc_configaddr))
! 488: panic("could not map psycho PCI configuration space");
! 489: } else {
! 490: /* Just copy IOMMU state, config tag and address */
! 491: sc->sc_is = osc->sc_is;
! 492: sc->sc_configtag = osc->sc_configtag;
! 493: sc->sc_configaddr = osc->sc_configaddr;
! 494:
! 495: if (getproplen(sc->sc_node, "no-streaming-cache") < 0) {
! 496: struct strbuf_ctl *sb = &pp->pp_sb;
! 497: vaddr_t va = (vaddr_t)&pp->pp_flush[0x40];
! 498:
! 499: /*
! 500: * Initialize the strbuf_ctl.
! 501: *
! 502: * The flush sync buffer must be 64-byte aligned.
! 503: */
! 504:
! 505: sb->sb_flush = (void *)(va & ~0x3f);
! 506:
! 507: sb->sb_bustag = sc->sc_bustag;
! 508: if (bus_space_subregion(sc->sc_bustag, sc->sc_pcictl,
! 509: offsetof(struct pci_ctl, pci_strbuf),
! 510: sizeof(struct iommu_strbuf),
! 511: &sb->sb_sb)) {
! 512: printf("STC1 subregion failed\n");
! 513: sb->sb_flush = 0;
! 514: }
! 515:
! 516: /* Point out iommu at the strbuf_ctl. */
! 517: sc->sc_is->is_sb[1] = sb;
! 518: }
! 519:
! 520: /* Point out iommu at the strbuf_ctl. */
! 521: sc->sc_is->is_sb[1] = &pp->pp_sb;
! 522:
! 523: printf("%s: ", sc->sc_dev.dv_xname);
! 524: printf("dvma map %x-%x, ", sc->sc_is->is_dvmabase,
! 525: sc->sc_is->is_dvmaend);
! 526: printf("iotdb %llx-%llx",
! 527: (unsigned long long)sc->sc_is->is_ptsb,
! 528: (unsigned long long)(sc->sc_is->is_ptsb +
! 529: (PAGE_SIZE << sc->sc_is->is_tsbsize)));
! 530: iommu_reset(sc->sc_is);
! 531: printf("\n");
! 532: }
! 533:
! 534: /*
! 535: * attach the pci.. note we pass PCI A tags, etc., for the sabre here.
! 536: */
! 537: pba.pba_busname = "pci";
! 538: #if 0
! 539: pba.pba_flags = sc->sc_psycho_this->pp_flags;
! 540: #endif
! 541: pba.pba_dmat = sc->sc_psycho_this->pp_dmat;
! 542: pba.pba_iot = sc->sc_psycho_this->pp_iot;
! 543: pba.pba_memt = sc->sc_psycho_this->pp_memt;
! 544: pba.pba_pc->bustag = sc->sc_configtag;
! 545: pba.pba_pc->bushandle = sc->sc_configaddr;
! 546: pba.pba_pc->intr_map = psycho_intr_map;
! 547:
! 548: if (sc->sc_mode == PSYCHO_MODE_PSYCHO)
! 549: psycho_identify_pbm(sc, pp, &pba);
! 550: else
! 551: pp->pp_id = PSYCHO_PBM_UNKNOWN;
! 552:
! 553: config_found(self, &pba, psycho_print);
! 554: }
! 555:
! 556: void
! 557: psycho_identify_pbm(struct psycho_softc *sc, struct psycho_pbm *pp,
! 558: struct pcibus_attach_args *pa)
! 559: {
! 560: vaddr_t pci_va = (vaddr_t)bus_space_vaddr(sc->sc_bustag, sc->sc_pcictl);
! 561: paddr_t pci_pa;
! 562:
! 563: if (pmap_extract(pmap_kernel(), pci_va, &pci_pa) == 0)
! 564: pp->pp_id = PSYCHO_PBM_UNKNOWN;
! 565: else switch(pci_pa & 0xffff) {
! 566: case 0x2000:
! 567: pp->pp_id = PSYCHO_PBM_A;
! 568: break;
! 569: case 0x4000:
! 570: pp->pp_id = PSYCHO_PBM_B;
! 571: break;
! 572: default:
! 573: pp->pp_id = PSYCHO_PBM_UNKNOWN;
! 574: break;
! 575: }
! 576: }
! 577:
! 578: void
! 579: psycho_map_psycho(struct psycho_softc* sc, int do_map, bus_addr_t reg_addr,
! 580: bus_size_t reg_size, bus_addr_t pci_addr, bus_size_t pci_size)
! 581: {
! 582: if (do_map) {
! 583: if (bus_space_map(sc->sc_bustag,
! 584: reg_addr, reg_size, 0, &sc->sc_regsh))
! 585: panic("psycho_attach: cannot map regs");
! 586:
! 587: if (pci_addr >= reg_addr &&
! 588: pci_addr + pci_size <= reg_addr + reg_size) {
! 589: if (bus_space_subregion(sc->sc_bustag, sc->sc_regsh,
! 590: pci_addr - reg_addr, pci_size, &sc->sc_pcictl))
! 591: panic("psycho_map_psycho: map ctl");
! 592: }
! 593: else if (bus_space_map(sc->sc_bustag, pci_addr, pci_size,
! 594: 0, &sc->sc_pcictl))
! 595: panic("psycho_map_psycho: cannot map pci");
! 596: } else {
! 597: if (bus_space_map(sc->sc_bustag, reg_addr, reg_size,
! 598: BUS_SPACE_MAP_PROMADDRESS, &sc->sc_regsh))
! 599: panic("psycho_map_psycho: cannot map ctl");
! 600: if (bus_space_map(sc->sc_bustag, pci_addr, pci_size,
! 601: BUS_SPACE_MAP_PROMADDRESS, &sc->sc_pcictl))
! 602: panic("psycho_map_psycho: cannot map pci");
! 603: }
! 604: }
! 605:
! 606: int
! 607: psycho_print(void *aux, const char *p)
! 608: {
! 609: if (p == NULL)
! 610: return (UNCONF);
! 611: return (QUIET);
! 612: }
! 613:
! 614: void
! 615: psycho_set_intr(struct psycho_softc *sc, int ipl, void *handler,
! 616: u_int64_t *mapper, u_int64_t *clearer, const char *suffix)
! 617: {
! 618: struct intrhand *ih;
! 619:
! 620: ih = (struct intrhand *)malloc(sizeof(struct intrhand),
! 621: M_DEVBUF, M_NOWAIT);
! 622: if (ih == NULL)
! 623: panic("couldn't malloc intrhand");
! 624: memset(ih, 0, sizeof(struct intrhand));
! 625: ih->ih_arg = sc;
! 626: ih->ih_map = mapper;
! 627: ih->ih_clr = clearer;
! 628: ih->ih_fun = handler;
! 629: ih->ih_pil = (1 << ipl);
! 630: ih->ih_number = INTVEC(*(ih->ih_map));
! 631: snprintf(ih->ih_name, sizeof(ih->ih_name),
! 632: "%s:%s", sc->sc_dev.dv_xname, suffix);
! 633:
! 634: DPRINTF(PDB_INTR, (
! 635: "\ninstalling handler %p arg %p for %s with number %x pil %u",
! 636: ih->ih_fun, ih->ih_arg, sc->sc_dev.dv_xname, ih->ih_number,
! 637: ih->ih_pil));
! 638:
! 639: intr_establish(ipl, ih);
! 640: *(ih->ih_map) |= INTMAP_V;
! 641: }
! 642:
! 643: /*
! 644: * PCI bus support
! 645: */
! 646:
! 647: /*
! 648: * allocate a PCI chipset tag and set its cookie.
! 649: */
! 650: pci_chipset_tag_t
! 651: psycho_alloc_chipset(struct psycho_pbm *pp, int node, pci_chipset_tag_t pc)
! 652: {
! 653: pci_chipset_tag_t npc;
! 654:
! 655: npc = malloc(sizeof *npc, M_DEVBUF, M_NOWAIT);
! 656: if (npc == NULL)
! 657: panic("could not allocate pci_chipset_tag_t");
! 658: memcpy(npc, pc, sizeof *pc);
! 659: npc->cookie = pp;
! 660: npc->rootnode = node;
! 661:
! 662: return (npc);
! 663: }
! 664:
! 665: /*
! 666: * grovel the OBP for various psycho properties
! 667: */
! 668: void
! 669: psycho_get_bus_range(node, brp)
! 670: int node;
! 671: int *brp;
! 672: {
! 673: int n, error;
! 674:
! 675: error = getprop(node, "bus-range", sizeof(*brp), &n, (void **)&brp);
! 676: if (error)
! 677: panic("could not get psycho bus-range, error %d", error);
! 678: if (n != 2)
! 679: panic("broken psycho bus-range");
! 680: DPRINTF(PDB_PROM,
! 681: ("psycho debug: got `bus-range' for node %08x: %u - %u\n",
! 682: node, brp[0], brp[1]));
! 683: }
! 684:
! 685: void
! 686: psycho_get_ranges(int node, struct psycho_ranges **rp, int *np)
! 687: {
! 688:
! 689: if (getprop(node, "ranges", sizeof(**rp), np, (void **)rp))
! 690: panic("could not get psycho ranges");
! 691: DPRINTF(PDB_PROM,
! 692: ("psycho debug: got `ranges' for node %08x: %d entries\n",
! 693: node, *np));
! 694: }
! 695:
! 696: /*
! 697: * Interrupt handlers.
! 698: */
! 699:
! 700: int
! 701: psycho_ue(void *arg)
! 702: {
! 703: struct psycho_softc *sc = arg;
! 704: unsigned long long afsr = psycho_psychoreg_read(sc, psy_ue_afsr);
! 705: unsigned long long afar = psycho_psychoreg_read(sc, psy_ue_afar);
! 706:
! 707: /*
! 708: * It's uncorrectable. Dump the regs and panic.
! 709: */
! 710: panic("%s: uncorrectable DMA error AFAR %llx (pa=%lx tte=%llx/%llx) "
! 711: "AFSR %llx", sc->sc_dev.dv_xname, afar,
! 712: iommu_extract(sc->sc_is, (vaddr_t)afar),
! 713: iommu_lookup_tte(sc->sc_is, (vaddr_t)afar),
! 714: iommu_fetch_tte(sc->sc_is, (paddr_t)afar),
! 715: afsr);
! 716: return (1);
! 717: }
! 718:
! 719: int
! 720: psycho_ce(void *arg)
! 721: {
! 722: struct psycho_softc *sc = arg;
! 723:
! 724: /*
! 725: * It's correctable. Dump the regs and continue.
! 726: */
! 727:
! 728: printf("%s: correctable DMA error AFAR %llx AFSR %llx\n",
! 729: sc->sc_dev.dv_xname,
! 730: (long long)psycho_psychoreg_read(sc, psy_ce_afar),
! 731: (long long)psycho_psychoreg_read(sc, psy_ce_afsr));
! 732: return (1);
! 733: }
! 734:
! 735: int
! 736: psycho_bus_error(struct psycho_softc *sc, int bus)
! 737: {
! 738: u_int64_t afsr, afar, bits;
! 739:
! 740: afar = psycho_psychoreg_read(sc, psy_pcictl[bus].pci_afar);
! 741: afsr = psycho_psychoreg_read(sc, psy_pcictl[bus].pci_afsr);
! 742:
! 743: bits = afsr & (PSY_PCIAFSR_PMA | PSY_PCIAFSR_PTA | PSY_PCIAFSR_PTRY |
! 744: PSY_PCIAFSR_PPERR | PSY_PCIAFSR_SMA | PSY_PCIAFSR_STA |
! 745: PSY_PCIAFSR_STRY | PSY_PCIAFSR_SPERR);
! 746:
! 747: if (bits == 0)
! 748: return (0);
! 749:
! 750: /*
! 751: * It's uncorrectable. Dump the regs and panic.
! 752: */
! 753: printf("%s: PCI bus %c error AFAR %llx (pa=%llx) AFSR %llx\n",
! 754: sc->sc_dev.dv_xname, 'A' + bus, (long long)afar,
! 755: (long long)iommu_extract(sc->sc_is, (vaddr_t)afar),
! 756: (long long)afsr);
! 757:
! 758: psycho_psychoreg_write(sc, psy_pcictl[bus].pci_afsr, bits);
! 759: return (1);
! 760: }
! 761:
! 762: int
! 763: psycho_bus_a(void *arg)
! 764: {
! 765: struct psycho_softc *sc = arg;
! 766:
! 767: return (psycho_bus_error(sc, 0));
! 768: }
! 769:
! 770: int
! 771: psycho_bus_b(void *arg)
! 772: {
! 773: struct psycho_softc *sc = arg;
! 774:
! 775: return (psycho_bus_error(sc, 1));
! 776: }
! 777:
! 778: int
! 779: psycho_powerfail(void *arg)
! 780: {
! 781: /*
! 782: * We lost power. Try to shut down NOW.
! 783: */
! 784: printf("Power Failure Detected: Shutting down NOW.\n");
! 785: boot(RB_POWERDOWN|RB_HALT);
! 786: return (1);
! 787: }
! 788:
! 789: int
! 790: psycho_wakeup(void *arg)
! 791: {
! 792: struct psycho_softc *sc = arg;
! 793:
! 794: /*
! 795: * Gee, we don't really have a framework to deal with this
! 796: * properly.
! 797: */
! 798: printf("%s: power management wakeup\n", sc->sc_dev.dv_xname);
! 799: return (1);
! 800: }
! 801:
! 802: /*
! 803: * initialise the IOMMU..
! 804: */
! 805: void
! 806: psycho_iommu_init(struct psycho_softc *sc, int tsbsize)
! 807: {
! 808: struct iommu_state *is = sc->sc_is;
! 809: int *vdma = NULL, nitem;
! 810: u_int32_t iobase = -1;
! 811: char *name;
! 812:
! 813: /* punch in our copies */
! 814: is->is_bustag = sc->sc_bustag;
! 815: bus_space_subregion(sc->sc_bustag, sc->sc_regsh,
! 816: offsetof(struct psychoreg, psy_iommu), sizeof(struct iommureg),
! 817: &is->is_iommu);
! 818:
! 819: /*
! 820: * Separate the men from the boys. If it has a `virtual-dma'
! 821: * property, use it.
! 822: */
! 823: if (!getprop(sc->sc_node, "virtual-dma", sizeof(vdma), &nitem,
! 824: (void **)&vdma)) {
! 825: /* Damn. Gotta use these values. */
! 826: iobase = vdma[0];
! 827: #define TSBCASE(x) case 1 << ((x) + 23): tsbsize = (x); break
! 828: switch (vdma[1]) {
! 829: TSBCASE(1); TSBCASE(2); TSBCASE(3);
! 830: TSBCASE(4); TSBCASE(5); TSBCASE(6);
! 831: default:
! 832: printf("bogus tsb size %x, using 7\n", vdma[1]);
! 833: TSBCASE(7);
! 834: }
! 835: #undef TSBCASE
! 836: DPRINTF(PDB_CONF, ("psycho_iommu_init: iobase=0x%x\n", iobase));
! 837: free(vdma, M_DEVBUF);
! 838: } else {
! 839: DPRINTF(PDB_CONF, ("psycho_iommu_init: getprop failed, "
! 840: "iobase=0x%x, tsbsize=%d\n", iobase, tsbsize));
! 841: }
! 842:
! 843: /* give us a nice name.. */
! 844: name = (char *)malloc(32, M_DEVBUF, M_NOWAIT);
! 845: if (name == NULL)
! 846: panic("couldn't malloc iommu name");
! 847: snprintf(name, 32, "%s dvma", sc->sc_dev.dv_xname);
! 848:
! 849: iommu_init(name, is, tsbsize, iobase);
! 850: }
! 851:
! 852: /*
! 853: * below here is bus space and bus dma support
! 854: */
! 855:
! 856: bus_space_tag_t
! 857: psycho_alloc_mem_tag(struct psycho_pbm *pp)
! 858: {
! 859: return (psycho_alloc_bus_tag(pp, "mem",
! 860: 0x02, /* 32-bit mem space (where's the #define???) */
! 861: ASI_PRIMARY, ASI_PRIMARY_LITTLE));
! 862: }
! 863:
! 864: bus_space_tag_t
! 865: psycho_alloc_io_tag(struct psycho_pbm *pp)
! 866: {
! 867: return (psycho_alloc_bus_tag(pp, "io",
! 868: 0x01, /* IO space (where's the #define???) */
! 869: ASI_PHYS_NON_CACHED_LITTLE, ASI_PHYS_NON_CACHED));
! 870: }
! 871:
! 872: bus_space_tag_t
! 873: psycho_alloc_config_tag(struct psycho_pbm *pp)
! 874: {
! 875: return (psycho_alloc_bus_tag(pp, "cfg",
! 876: 0x00, /* Config space (where's the #define???) */
! 877: ASI_PHYS_NON_CACHED_LITTLE, ASI_PHYS_NON_CACHED));
! 878: }
! 879:
! 880: bus_space_tag_t
! 881: psycho_alloc_bus_tag(struct psycho_pbm *pp,
! 882: const char *name, int ss, int asi, int sasi)
! 883: {
! 884: struct psycho_softc *sc = pp->pp_sc;
! 885: struct sparc_bus_space_tag *bt;
! 886:
! 887: bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT);
! 888: if (bt == NULL)
! 889: panic("could not allocate psycho bus tag");
! 890:
! 891: bzero(bt, sizeof *bt);
! 892:
! 893: snprintf(bt->name, sizeof(bt->name), "%s-pbm_%s(%d-%2.2x)",
! 894: sc->sc_dev.dv_xname, name, ss, asi);
! 895:
! 896: bt->cookie = pp;
! 897: bt->parent = sc->sc_bustag;
! 898: bt->default_type = ss;
! 899: bt->asi = asi;
! 900: bt->sasi = sasi;
! 901: bt->sparc_bus_map = psycho_bus_map;
! 902: bt->sparc_bus_mmap = psycho_bus_mmap;
! 903: bt->sparc_bus_addr = psycho_bus_addr;
! 904: bt->sparc_intr_establish = psycho_intr_establish;
! 905:
! 906: return (bt);
! 907: }
! 908:
! 909: bus_dma_tag_t
! 910: psycho_alloc_dma_tag(struct psycho_pbm *pp)
! 911: {
! 912: struct psycho_softc *sc = pp->pp_sc;
! 913: bus_dma_tag_t dt, pdt = sc->sc_dmatag;
! 914:
! 915: dt = (bus_dma_tag_t)malloc(sizeof(struct sparc_bus_dma_tag),
! 916: M_DEVBUF, M_NOWAIT);
! 917: if (dt == NULL)
! 918: panic("could not allocate psycho dma tag");
! 919:
! 920: bzero(dt, sizeof *dt);
! 921: dt->_cookie = pp;
! 922: dt->_parent = pdt;
! 923: dt->_dmamap_create = psycho_dmamap_create;
! 924: dt->_dmamap_destroy = iommu_dvmamap_destroy;
! 925: dt->_dmamap_load = iommu_dvmamap_load;
! 926: dt->_dmamap_load_raw = iommu_dvmamap_load_raw;
! 927: dt->_dmamap_unload = iommu_dvmamap_unload;
! 928: if (sc->sc_mode == PSYCHO_MODE_PSYCHO)
! 929: dt->_dmamap_sync = iommu_dvmamap_sync;
! 930: else
! 931: dt->_dmamap_sync = psycho_sabre_dvmamap_sync;
! 932: dt->_dmamem_alloc = iommu_dvmamem_alloc;
! 933: dt->_dmamem_free = iommu_dvmamem_free;
! 934: dt->_dmamem_map = iommu_dvmamem_map;
! 935: dt->_dmamem_unmap = iommu_dvmamem_unmap;
! 936:
! 937: return (dt);
! 938: }
! 939:
! 940: /*
! 941: * bus space support. <sparc64/dev/psychoreg.h> has a discussion about
! 942: * PCI physical addresses.
! 943: */
! 944:
! 945: int
! 946: psycho_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset,
! 947: bus_size_t size, int flags, bus_space_handle_t *hp)
! 948: {
! 949: struct psycho_pbm *pp = t->cookie;
! 950: int i, ss;
! 951:
! 952: DPRINTF(PDB_BUSMAP, ("\npsycho_bus_map: type %d off %qx sz %qx "
! 953: "flags %d", t->default_type, (unsigned long long)offset,
! 954: (unsigned long long)size, flags));
! 955:
! 956: ss = t->default_type;
! 957: DPRINTF(PDB_BUSMAP, (" cspace %d", ss));
! 958:
! 959: if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
! 960: printf("\npsycho_bus_map: invalid parent");
! 961: return (EINVAL);
! 962: }
! 963:
! 964: t = t->parent;
! 965:
! 966: if (flags & BUS_SPACE_MAP_PROMADDRESS) {
! 967: return ((*t->sparc_bus_map)
! 968: (t, t0, offset, size, flags, hp));
! 969: }
! 970:
! 971: for (i = 0; i < pp->pp_nrange; i++) {
! 972: bus_addr_t paddr;
! 973:
! 974: if (((pp->pp_range[i].cspace >> 24) & 0x03) != ss)
! 975: continue;
! 976:
! 977: paddr = pp->pp_range[i].phys_lo + offset;
! 978: paddr |= ((bus_addr_t)pp->pp_range[i].phys_hi << 32);
! 979: DPRINTF(PDB_BUSMAP,
! 980: ("\n_psycho_bus_map: mapping paddr space %lx offset %lx "
! 981: "paddr %qx",
! 982: (long)ss, (long)offset,
! 983: (unsigned long long)paddr));
! 984: return ((*t->sparc_bus_map)(t, t0, paddr, size, flags, hp));
! 985: }
! 986: DPRINTF(PDB_BUSMAP, (" FAILED\n"));
! 987: return (EINVAL);
! 988: }
! 989:
! 990: paddr_t
! 991: psycho_bus_mmap(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t paddr,
! 992: off_t off, int prot, int flags)
! 993: {
! 994: bus_addr_t offset = paddr;
! 995: struct psycho_pbm *pp = t->cookie;
! 996: int i, ss;
! 997:
! 998: ss = t->default_type;
! 999:
! 1000: DPRINTF(PDB_BUSMAP, ("\n_psycho_bus_mmap: prot %d flags %d pa %qx",
! 1001: prot, flags, (unsigned long long)paddr));
! 1002:
! 1003: if (t->parent == 0 || t->parent->sparc_bus_mmap == 0) {
! 1004: printf("\npsycho_bus_mmap: invalid parent");
! 1005: return (-1);
! 1006: }
! 1007:
! 1008: t = t->parent;
! 1009:
! 1010: for (i = 0; i < pp->pp_nrange; i++) {
! 1011: bus_addr_t paddr;
! 1012:
! 1013: if (((pp->pp_range[i].cspace >> 24) & 0x03) != ss)
! 1014: continue;
! 1015:
! 1016: paddr = pp->pp_range[i].phys_lo + offset;
! 1017: paddr |= ((bus_addr_t)pp->pp_range[i].phys_hi << 32);
! 1018: DPRINTF(PDB_BUSMAP, ("\npsycho_bus_mmap: mapping paddr "
! 1019: "space %lx offset %lx paddr %qx",
! 1020: (long)ss, (long)offset,
! 1021: (unsigned long long)paddr));
! 1022: return ((*t->sparc_bus_mmap)(t, t0, paddr, off, prot, flags));
! 1023: }
! 1024:
! 1025: return (-1);
! 1026: }
! 1027:
! 1028: bus_addr_t
! 1029: psycho_bus_addr(bus_space_tag_t t, bus_space_tag_t t0, bus_space_handle_t h)
! 1030: {
! 1031: struct psycho_pbm *pp = t->cookie;
! 1032: bus_addr_t addr;
! 1033: int i, ss;
! 1034:
! 1035: ss = t->default_type;
! 1036:
! 1037: if (t->parent == 0 || t->parent->sparc_bus_addr == 0) {
! 1038: printf("\npsycho_bus_addr: invalid parent");
! 1039: return (-1);
! 1040: }
! 1041:
! 1042: t = t->parent;
! 1043:
! 1044: addr = ((*t->sparc_bus_addr)(t, t0, h));
! 1045: if (addr == -1)
! 1046: return (-1);
! 1047:
! 1048: for (i = 0; i < pp->pp_nrange; i++) {
! 1049: if (((pp->pp_range[i].cspace >> 24) & 0x03) != ss)
! 1050: continue;
! 1051:
! 1052: return (BUS_ADDR_PADDR(addr) - pp->pp_range[i].phys_lo);
! 1053: }
! 1054:
! 1055: return (-1);
! 1056: }
! 1057:
! 1058: /*
! 1059: * Bus-specific interrupt mapping
! 1060: */
! 1061: int
! 1062: psycho_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
! 1063: {
! 1064: struct psycho_pbm *pp = pa->pa_pc->cookie;
! 1065: struct psycho_softc *sc = pp->pp_sc;
! 1066: u_int dev;
! 1067:
! 1068: if (*ihp != (pci_intr_handle_t)-1) {
! 1069: *ihp |= sc->sc_ign;
! 1070: return (0);
! 1071: }
! 1072:
! 1073: /*
! 1074: * We didn't find a PROM mapping for this interrupt. Try to
! 1075: * construct one ourselves based on the swizzled interrupt pin
! 1076: * and the interrupt mapping for PCI slots documented in the
! 1077: * UltraSPARC-IIi User's Manual.
! 1078: */
! 1079:
! 1080: if (pa->pa_intrpin == 0)
! 1081: return (-1);
! 1082:
! 1083: /*
! 1084: * This deserves some documentation. Should anyone
! 1085: * have anything official looking, please speak up.
! 1086: */
! 1087: if (sc->sc_mode == PSYCHO_MODE_PSYCHO &&
! 1088: pp->pp_id == PSYCHO_PBM_B)
! 1089: dev = PCITAG_DEV(pa->pa_intrtag) - 2;
! 1090: else
! 1091: dev = PCITAG_DEV(pa->pa_intrtag) - 1;
! 1092:
! 1093: *ihp = (pa->pa_intrpin - 1) & INTMAP_PCIINT;
! 1094: *ihp |= ((pp->pp_id == PSYCHO_PBM_B) ? INTMAP_PCIBUS : 0);
! 1095: *ihp |= (dev << 2) & INTMAP_PCISLOT;
! 1096: *ihp |= sc->sc_ign;
! 1097:
! 1098: return (0);
! 1099: }
! 1100:
! 1101: /*
! 1102: * install an interrupt handler for a PCI device
! 1103: */
! 1104: void *
! 1105: psycho_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
! 1106: int level, int flags, int (*handler)(void *), void *arg, const char *what)
! 1107: {
! 1108: struct psycho_pbm *pp = t->cookie;
! 1109: struct psycho_softc *sc = pp->pp_sc;
! 1110: struct intrhand *ih;
! 1111: volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
! 1112: int64_t intrmap = 0;
! 1113: int ino;
! 1114: long vec = INTVEC(ihandle);
! 1115:
! 1116: /*
! 1117: * Hunt through all the interrupt mapping regs to look for our
! 1118: * interrupt vector.
! 1119: *
! 1120: * XXX We only compare INOs rather than IGNs since the firmware may
! 1121: * not provide the IGN and the IGN is constant for all device on that
! 1122: * PCI controller. This could cause problems for the FFB/external
! 1123: * interrupt which has a full vector that can be set arbitrarily.
! 1124: */
! 1125:
! 1126: DPRINTF(PDB_INTR,
! 1127: ("\npsycho_intr_establish: ihandle %x vec %lx", ihandle, vec));
! 1128: ino = INTINO(vec);
! 1129: DPRINTF(PDB_INTR, (" ino %x", ino));
! 1130:
! 1131: /* If the device didn't ask for an IPL, use the one encoded. */
! 1132: if (level == IPL_NONE)
! 1133: level = INTLEV(vec);
! 1134: /* If it still has no level, print a warning and assign IPL 2 */
! 1135: if (level == IPL_NONE) {
! 1136: printf("ERROR: no IPL, setting IPL 2.\n");
! 1137: level = 2;
! 1138: }
! 1139:
! 1140: if (flags & BUS_INTR_ESTABLISH_SOFTINTR)
! 1141: goto found;
! 1142:
! 1143: DPRINTF(PDB_INTR,
! 1144: ("\npsycho: intr %lx: %p\nHunting for IRQ...\n",
! 1145: (long)ino, intrlev[ino]));
! 1146:
! 1147: /*
! 1148: * First look for PCI interrupts, otherwise the PCI A slot 0
! 1149: * INTA# interrupt might match an unused non-PCI (obio)
! 1150: * interrupt.
! 1151: */
! 1152:
! 1153: for (intrmapptr = psycho_psychoreg_vaddr(sc, pcia_slot0_int),
! 1154: intrclrptr = psycho_psychoreg_vaddr(sc, pcia0_clr_int[0]);
! 1155: intrmapptr <= (volatile u_int64_t *)
! 1156: psycho_psychoreg_vaddr(sc, pcib_slot3_int);
! 1157: intrmapptr++, intrclrptr += 4) {
! 1158: /* Skip PCI-A Slot 2 and PCI-A Slot 3 on psycho's */
! 1159: if (sc->sc_mode == PSYCHO_MODE_PSYCHO &&
! 1160: (intrmapptr ==
! 1161: psycho_psychoreg_vaddr(sc, pcia_slot2_int) ||
! 1162: intrmapptr ==
! 1163: psycho_psychoreg_vaddr(sc, pcia_slot3_int)))
! 1164: continue;
! 1165:
! 1166: if (((*intrmapptr ^ vec) & 0x3c) == 0) {
! 1167: intrclrptr += vec & 0x3;
! 1168: goto found;
! 1169: }
! 1170: }
! 1171:
! 1172: /* Now hunt through obio. */
! 1173: for (intrmapptr = psycho_psychoreg_vaddr(sc, scsi_int_map),
! 1174: intrclrptr = psycho_psychoreg_vaddr(sc, scsi_clr_int);
! 1175: intrmapptr < (volatile u_int64_t *)
! 1176: psycho_psychoreg_vaddr(sc, ffb0_int_map);
! 1177: intrmapptr++, intrclrptr++) {
! 1178: if (INTINO(*intrmapptr) == ino)
! 1179: goto found;
! 1180: }
! 1181:
! 1182: printf("Cannot find interrupt vector %lx\n", vec);
! 1183: return (NULL);
! 1184:
! 1185: found:
! 1186: ih = bus_intr_allocate(t0, handler, arg, ino | sc->sc_ign, level,
! 1187: intrmapptr, intrclrptr, what);
! 1188: if (ih == NULL) {
! 1189: printf("Cannot allocate interrupt vector %lx\n", vec);
! 1190: return (NULL);
! 1191: }
! 1192:
! 1193: DPRINTF(PDB_INTR, (
! 1194: "\ninstalling handler %p arg %p with number %x pil %u",
! 1195: ih->ih_fun, ih->ih_arg, ih->ih_number, ih->ih_pil));
! 1196:
! 1197: intr_establish(ih->ih_pil, ih);
! 1198:
! 1199: /*
! 1200: * Enable the interrupt now we have the handler installed.
! 1201: * Read the current value as we can't change it besides the
! 1202: * valid bit so so make sure only this bit is changed.
! 1203: *
! 1204: * XXXX --- we really should use bus_space for this.
! 1205: */
! 1206: if (intrmapptr) {
! 1207: intrmap = *intrmapptr;
! 1208: DPRINTF(PDB_INTR, ("; read intrmap = %016qx",
! 1209: (unsigned long long)intrmap));
! 1210:
! 1211: /* Enable the interrupt */
! 1212: intrmap |= INTMAP_V;
! 1213: DPRINTF(PDB_INTR, ("; addr of intrmapptr = %p", intrmapptr));
! 1214: DPRINTF(PDB_INTR, ("; writing intrmap = %016qx",
! 1215: (unsigned long long)intrmap));
! 1216: *intrmapptr = intrmap;
! 1217: DPRINTF(PDB_INTR, ("; reread intrmap = %016qx",
! 1218: (unsigned long long)(intrmap = *intrmapptr)));
! 1219: }
! 1220: return (ih);
! 1221: }
! 1222:
! 1223: /*
! 1224: * hooks into the iommu dvma calls.
! 1225: */
! 1226: int
! 1227: psycho_dmamap_create(bus_dma_tag_t t, bus_dma_tag_t t0, bus_size_t size,
! 1228: int nsegments, bus_size_t maxsegsz, bus_size_t boundary, int flags,
! 1229: bus_dmamap_t *dmamp)
! 1230: {
! 1231: struct psycho_pbm *pp = t->_cookie;
! 1232:
! 1233: return (iommu_dvmamap_create(t, t0, &pp->pp_sb, size, nsegments,
! 1234: maxsegsz, boundary, flags, dmamp));
! 1235: }
! 1236:
! 1237: void
! 1238: psycho_sabre_dvmamap_sync(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map,
! 1239: bus_size_t offset, bus_size_t len, int ops)
! 1240: {
! 1241: struct psycho_pbm *pp = t->_cookie;
! 1242: struct psycho_softc *sc = pp->pp_sc;
! 1243:
! 1244: if (ops & BUS_DMASYNC_POSTREAD)
! 1245: psycho_psychoreg_read(sc, pci_dma_write_sync);
! 1246:
! 1247: if (ops & (BUS_DMASYNC_POSTREAD | BUS_DMASYNC_PREWRITE))
! 1248: membar(MemIssue);
! 1249: }
! 1250:
CVSweb