psycho.c revision 119737
1275970Scy/* 2275970Scy * Copyright (c) 1999, 2000 Matthew R. Green 3275970Scy * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org> 4275970Scy * All rights reserved. 5275970Scy * 6275970Scy * Redistribution and use in source and binary forms, with or without 7275970Scy * modification, are permitted provided that the following conditions 8275970Scy * are met: 9290000Sglebius * 1. Redistributions of source code must retain the above copyright 10290000Sglebius * notice, this list of conditions and the following disclaimer. 11290000Sglebius * 2. Redistributions in binary form must reproduce the above copyright 12275970Scy * notice, this list of conditions and the following disclaimer in the 13275970Scy * documentation and/or other materials provided with the distribution. 14275970Scy * 3. The name of the author may not be used to endorse or promote products 15275970Scy * derived from this software without specific prior written permission. 16275970Scy * 17275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18290000Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19290000Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20290000Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22275970Scy * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23275970Scy * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24275970Scy * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25275970Scy * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26290000Sglebius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27290000Sglebius * SUCH DAMAGE. 28290000Sglebius * 29290000Sglebius * from: NetBSD: psycho.c,v 1.39 2001/10/07 20:30:41 eeh Exp 30290000Sglebius * 31290000Sglebius * $FreeBSD: head/sys/sparc64/pci/psycho.c 119737 2003-09-04 15:25:10Z tmm $ 32290000Sglebius */ 33290000Sglebius 34290000Sglebius/* 35290000Sglebius * Support for `psycho' and `psycho+' UPA to PCI bridge and 36290000Sglebius * UltraSPARC IIi and IIe `sabre' PCI controllers. 37290000Sglebius */ 38290000Sglebius 39290000Sglebius#include "opt_ofw_pci.h" 40290000Sglebius#include "opt_psycho.h" 41290000Sglebius 42290000Sglebius#include <sys/param.h> 43290000Sglebius#include <sys/systm.h> 44290000Sglebius#include <sys/bus.h> 45290000Sglebius#include <sys/kernel.h> 46290000Sglebius#include <sys/malloc.h> 47290000Sglebius#include <sys/pcpu.h> 48290000Sglebius 49290000Sglebius#include <dev/ofw/openfirm.h> 50290000Sglebius#include <dev/ofw/ofw_pci.h> 51290000Sglebius 52290000Sglebius#include <machine/bus.h> 53290000Sglebius#include <machine/bus_private.h> 54290000Sglebius#include <machine/iommureg.h> 55290000Sglebius#include <machine/bus_common.h> 56290000Sglebius#include <machine/frame.h> 57290000Sglebius#include <machine/intr_machdep.h> 58290000Sglebius#include <machine/nexusvar.h> 59290000Sglebius#include <machine/ofw_bus.h> 60290000Sglebius#include <machine/ofw_upa.h> 61290000Sglebius#include <machine/resource.h> 62290000Sglebius#include <machine/cpu.h> 63290000Sglebius 64290000Sglebius#include <sys/rman.h> 65290000Sglebius 66290000Sglebius#include <machine/iommuvar.h> 67290000Sglebius 68290000Sglebius#include <dev/pci/pcivar.h> 69290000Sglebius#include <dev/pci/pcireg.h> 70290000Sglebius 71290000Sglebius#include <sparc64/pci/ofw_pci.h> 72290000Sglebius#include <sparc64/pci/psychoreg.h> 73290000Sglebius#include <sparc64/pci/psychovar.h> 74290000Sglebius 75275970Scy#include "pcib_if.h" 76275970Scy 77290000Sglebiusstatic void psycho_get_ranges(phandle_t, struct upa_ranges **, int *); 78275970Scystatic void psycho_set_intr(struct psycho_softc *, int, device_t, bus_addr_t, 79275970Scy int, driver_intr_t); 80275970Scystatic int psycho_find_intrmap(struct psycho_softc *, int, bus_addr_t *, 81275970Scy bus_addr_t *, u_long *); 82275970Scystatic void psycho_intr_stub(void *); 83275970Scystatic bus_space_tag_t psycho_alloc_bus_tag(struct psycho_softc *, int); 84290000Sglebius#ifndef OFW_NEWPCI 85275970Scystatic ofw_pci_binit_t psycho_binit; 86275970Scy#endif 87290000Sglebius 88290000Sglebius/* Interrupt handlers */ 89275970Scystatic void psycho_ue(void *); 90290000Sglebiusstatic void psycho_ce(void *); 91275970Scystatic void psycho_bus_a(void *); 92275970Scystatic void psycho_bus_b(void *); 93275970Scystatic void psycho_powerfail(void *); 94290000Sglebius#ifdef PSYCHO_MAP_WAKEUP 95290000Sglebiusstatic void psycho_wakeup(void *); 96290000Sglebius#endif 97290000Sglebius 98290000Sglebius/* IOMMU support */ 99290000Sglebiusstatic void psycho_iommu_init(struct psycho_softc *, int); 100290000Sglebius 101290000Sglebius/* 102290000Sglebius * Methods. 103290000Sglebius */ 104290000Sglebiusstatic device_probe_t psycho_probe; 105290000Sglebiusstatic device_attach_t psycho_attach; 106290000Sglebiusstatic bus_read_ivar_t psycho_read_ivar; 107290000Sglebiusstatic bus_setup_intr_t psycho_setup_intr; 108290000Sglebiusstatic bus_teardown_intr_t psycho_teardown_intr; 109290000Sglebiusstatic bus_alloc_resource_t psycho_alloc_resource; 110290000Sglebiusstatic bus_activate_resource_t psycho_activate_resource; 111290000Sglebiusstatic bus_deactivate_resource_t psycho_deactivate_resource; 112290000Sglebiusstatic bus_release_resource_t psycho_release_resource; 113290000Sglebiusstatic pcib_maxslots_t psycho_maxslots; 114290000Sglebiusstatic pcib_read_config_t psycho_read_config; 115290000Sglebiusstatic pcib_write_config_t psycho_write_config; 116290000Sglebiusstatic pcib_route_interrupt_t psycho_route_interrupt; 117290000Sglebiusstatic ofw_pci_intr_pending_t psycho_intr_pending; 118290000Sglebius#ifndef OFW_NEWPCI 119290000Sglebiusstatic ofw_pci_guess_ino_t psycho_guess_ino; 120290000Sglebius#endif 121290000Sglebiusstatic ofw_pci_get_bus_handle_t psycho_get_bus_handle; 122290000Sglebius#ifdef OFW_NEWPCI 123290000Sglebiusstatic ofw_pci_get_node_t psycho_get_node; 124275970Scystatic ofw_pci_adjust_busrange_t psycho_adjust_busrange; 125275970Scy#endif 126275970Scy 127275970Scystatic device_method_t psycho_methods[] = { 128275970Scy /* Device interface */ 129275970Scy DEVMETHOD(device_probe, psycho_probe), 130275970Scy DEVMETHOD(device_attach, psycho_attach), 131275970Scy 132290000Sglebius /* Bus interface */ 133275970Scy DEVMETHOD(bus_print_child, bus_generic_print_child), 134275970Scy DEVMETHOD(bus_read_ivar, psycho_read_ivar), 135275970Scy DEVMETHOD(bus_setup_intr, psycho_setup_intr), 136275970Scy DEVMETHOD(bus_teardown_intr, psycho_teardown_intr), 137275970Scy DEVMETHOD(bus_alloc_resource, psycho_alloc_resource), 138275970Scy DEVMETHOD(bus_activate_resource, psycho_activate_resource), 139275970Scy DEVMETHOD(bus_deactivate_resource, psycho_deactivate_resource), 140275970Scy DEVMETHOD(bus_release_resource, psycho_release_resource), 141280849Scy 142275970Scy /* pcib interface */ 143275970Scy DEVMETHOD(pcib_maxslots, psycho_maxslots), 144275970Scy DEVMETHOD(pcib_read_config, psycho_read_config), 145275970Scy DEVMETHOD(pcib_write_config, psycho_write_config), 146275970Scy DEVMETHOD(pcib_route_interrupt, psycho_route_interrupt), 147275970Scy 148275970Scy /* ofw_pci interface */ 149275970Scy DEVMETHOD(ofw_pci_intr_pending, psycho_intr_pending), 150275970Scy#ifndef OFW_NEWPCI 151275970Scy DEVMETHOD(ofw_pci_guess_ino, psycho_guess_ino), 152275970Scy#endif 153275970Scy DEVMETHOD(ofw_pci_get_bus_handle, psycho_get_bus_handle), 154275970Scy#ifdef OFW_NEWPCI 155290000Sglebius DEVMETHOD(ofw_pci_get_node, psycho_get_node), 156290000Sglebius DEVMETHOD(ofw_pci_adjust_busrange, psycho_adjust_busrange), 157290000Sglebius#endif 158290000Sglebius 159290000Sglebius { 0, 0 } 160290000Sglebius}; 161290000Sglebius 162290000Sglebiusstatic driver_t psycho_driver = { 163290000Sglebius "pcib", 164290000Sglebius psycho_methods, 165290000Sglebius sizeof(struct psycho_softc), 166290000Sglebius}; 167290000Sglebius 168290000Sglebiusstatic devclass_t psycho_devclass; 169290000Sglebius 170290000SglebiusDRIVER_MODULE(psycho, nexus, psycho_driver, psycho_devclass, 0, 0); 171290000Sglebius 172290000SglebiusSLIST_HEAD(, psycho_softc) psycho_softcs = 173290000Sglebius SLIST_HEAD_INITIALIZER(psycho_softcs); 174290000Sglebius 175290000Sglebiusstruct psycho_clr { 176290000Sglebius struct psycho_softc *pci_sc; 177290000Sglebius bus_addr_t pci_clr; /* clear register */ 178290000Sglebius driver_intr_t *pci_handler; /* handler to call */ 179290000Sglebius void *pci_arg; /* argument for the handler */ 180290000Sglebius void *pci_cookie; /* interrupt cookie of parent bus */ 181290000Sglebius}; 182290000Sglebius 183290000Sglebiusstruct psycho_strayclr { 184290000Sglebius struct psycho_softc *psc_sc; 185290000Sglebius bus_addr_t psc_clr; /* clear register */ 186290000Sglebius}; 187290000Sglebius 188290000Sglebius#define PSYCHO_READ8(sc, off) \ 189290000Sglebius bus_space_read_8((sc)->sc_bustag, (sc)->sc_bushandle, (off)) 190290000Sglebius#define PSYCHO_WRITE8(sc, off, v) \ 191275970Scy bus_space_write_8((sc)->sc_bustag, (sc)->sc_bushandle, (off), (v)) 192275970Scy#define PCICTL_READ8(sc, off) \ 193275970Scy PSYCHO_READ8((sc), (sc)->sc_pcictl + (off)) 194275970Scy#define PCICTL_WRITE8(sc, off, v) \ 195275970Scy PSYCHO_WRITE8((sc), (sc)->sc_pcictl + (off), (v)) 196275970Scy 197275970Scy/* 198275970Scy * "sabre" is the UltraSPARC IIi onboard UPA to PCI bridge. It manages a 199275970Scy * single PCI bus and does not have a streaming buffer. It often has an APB 200275970Scy * (advanced PCI bridge) connected to it, which was designed specifically for 201290000Sglebius * the IIi. The APB let's the IIi handle two independednt PCI buses, and 202290000Sglebius * appears as two "simba"'s underneath the sabre. 203290000Sglebius * 204290000Sglebius * "psycho" and "psycho+" is a dual UPA to PCI bridge. It sits on the UPA bus 205290000Sglebius * and manages two PCI buses. "psycho" has two 64-bit 33MHz buses, while 206290000Sglebius * "psycho+" controls both a 64-bit 33Mhz and a 64-bit 66Mhz PCI bus. You 207290000Sglebius * will usually find a "psycho+" since I don't think the original "psycho" 208290000Sglebius * ever shipped, and if it did it would be in the U30. 209290000Sglebius * 210290000Sglebius * Each "psycho" PCI bus appears as a separate OFW node, but since they are 211290000Sglebius * both part of the same IC, they only have a single register space. As such, 212290000Sglebius * they need to be configured together, even though the autoconfiguration will 213290000Sglebius * attach them separately. 214275970Scy * 215290000Sglebius * On UltraIIi machines, "sabre" itself usually takes pci0, with "simba" often 216290000Sglebius * as pci1 and pci2, although they have been implemented with other PCI bus 217290000Sglebius * numbers on some machines. 218290000Sglebius * 219290000Sglebius * On UltraII machines, there can be any number of "psycho+" ICs, each 220275970Scy * providing two PCI buses. 221275970Scy * 222275970Scy * 223275970Scy * XXXX The psycho/sabre node has an `interrupts' attribute. They contain 224275970Scy * the values of the following interrupts in this order: 225275970Scy * 226275970Scy * PCI Bus Error (30) 227275970Scy * DMA UE (2e) 228275970Scy * DMA CE (2f) 229275970Scy * Power Fail (25) 230290000Sglebius * 231290000Sglebius * We really should attach handlers for each. 232290000Sglebius */ 233290000Sglebius#ifdef DEBUGGER_ON_POWERFAIL 234290000Sglebius#define PSYCHO_PWRFAIL_INT_FLAGS INTR_FAST 235275970Scy#else 236275970Scy#define PSYCHO_PWRFAIL_INT_FLAGS 0 237275970Scy#endif 238275970Scy 239275970Scy#define OFW_PCI_TYPE "pci" 240275970Scy 241275970Scystruct psycho_desc { 242275970Scy char *pd_string; 243275970Scy int pd_mode; 244275970Scy char *pd_name; 245275970Scy}; 246275970Scy 247275970Scystatic struct psycho_desc psycho_compats[] = { 248275970Scy { "pci108e,8000", PSYCHO_MODE_PSYCHO, "Psycho compatible" }, 249275970Scy { "pci108e,a000", PSYCHO_MODE_SABRE, "Sabre (US-IIi) compatible" }, 250275970Scy { "pci108e,a001", PSYCHO_MODE_SABRE, "Sabre (US-IIe) compatible" }, 251275970Scy { NULL, 0, NULL } 252275970Scy}; 253275970Scy 254275970Scystatic struct psycho_desc psycho_models[] = { 255275970Scy { "SUNW,psycho", PSYCHO_MODE_PSYCHO, "Psycho" }, 256275970Scy { "SUNW,sabre", PSYCHO_MODE_SABRE, "Sabre" }, 257275970Scy { NULL, 0, NULL } 258275970Scy}; 259275970Scy 260275970Scystatic struct psycho_desc * 261290000Sglebiuspsycho_find_desc(struct psycho_desc *table, char *string) 262275970Scy{ 263290000Sglebius struct psycho_desc *desc; 264290000Sglebius 265290000Sglebius for (desc = table; desc->pd_string != NULL; desc++) { 266275970Scy if (strcmp(desc->pd_string, string) == 0) 267275970Scy return (desc); 268275970Scy } 269275970Scy return (NULL); 270275970Scy} 271275970Scy 272275970Scystatic struct psycho_desc * 273275970Scypsycho_get_desc(phandle_t node, char *model) 274275970Scy{ 275275970Scy struct psycho_desc *rv; 276275970Scy char compat[32]; 277275970Scy 278275970Scy rv = NULL; 279290000Sglebius if (model != NULL) 280290000Sglebius rv = psycho_find_desc(psycho_models, model); 281290000Sglebius if (rv == NULL && 282290000Sglebius OF_getprop(node, "compatible", compat, sizeof(compat)) != -1) 283290000Sglebius rv = psycho_find_desc(psycho_compats, compat); 284290000Sglebius return (rv); 285290000Sglebius} 286290000Sglebius 287290000Sglebiusstatic int 288290000Sglebiuspsycho_probe(device_t dev) 289290000Sglebius{ 290290000Sglebius phandle_t node; 291290000Sglebius char *dtype; 292290000Sglebius 293290000Sglebius node = nexus_get_node(dev); 294290000Sglebius dtype = nexus_get_device_type(dev); 295290000Sglebius if (nexus_get_reg(dev) != NULL && dtype != NULL && 296275970Scy strcmp(dtype, OFW_PCI_TYPE) == 0 && 297290000Sglebius psycho_get_desc(node, nexus_get_model(dev)) != NULL) { 298275970Scy device_set_desc(dev, "U2P UPA-PCI bridge"); 299290000Sglebius return (0); 300275970Scy } 301275970Scy 302275970Scy return (ENXIO); 303290000Sglebius} 304290000Sglebius 305290000Sglebius/* 306290000Sglebius * SUNW,psycho initialisation .. 307275970Scy * - find the per-psycho registers 308290000Sglebius * - figure out the IGN. 309290000Sglebius * - find our partner psycho 310290000Sglebius * - configure ourselves 311290000Sglebius * - bus range, bus, 312275970Scy * - interrupt map, 313290000Sglebius * - setup the chipsets. 314290000Sglebius * - if we're the first of the pair, initialise the IOMMU, otherwise 315290000Sglebius * just copy it's tags and addresses. 316290000Sglebius */ 317275970Scystatic int 318290000Sglebiuspsycho_attach(device_t dev) 319290000Sglebius{ 320290000Sglebius struct psycho_softc *sc; 321275970Scy struct psycho_softc *osc = NULL; 322275970Scy struct psycho_softc *asc; 323290000Sglebius struct upa_regs *reg; 324290000Sglebius#ifndef OFW_NEWPCI 325275970Scy struct ofw_pci_bdesc obd; 326290000Sglebius#endif 327290000Sglebius struct psycho_desc *desc; 328275970Scy phandle_t node; 329275970Scy u_int64_t csr; 330290000Sglebius u_long mlen; 331290000Sglebius int psycho_br[2]; 332290000Sglebius int n, i, nreg, rid; 333275970Scy#ifdef PSYCHO_DEBUG 334275970Scy bus_addr_t map, clr; 335275970Scy u_int64_t mr; 336275970Scy#endif 337275970Scy 338275970Scy node = nexus_get_node(dev); 339275970Scy sc = device_get_softc(dev); 340275970Scy desc = psycho_get_desc(node, nexus_get_model(dev)); 341275970Scy 342290000Sglebius sc->sc_node = node; 343290000Sglebius sc->sc_dev = dev; 344290000Sglebius sc->sc_dmatag = nexus_get_dmatag(dev); 345290000Sglebius sc->sc_mode = desc->pd_mode; 346290000Sglebius 347290000Sglebius /* 348275970Scy * The psycho gets three register banks: 349275970Scy * (0) per-PBM configuration and status registers 350275970Scy * (1) per-PBM PCI configuration space, containing only the 351275970Scy * PBM 256-byte PCI header 352290000Sglebius * (2) the shared psycho configuration registers (struct psychoreg) 353290000Sglebius */ 354290000Sglebius reg = nexus_get_reg(dev); 355290000Sglebius nreg = nexus_get_nreg(dev); 356275970Scy /* Register layouts are different. stuupid. */ 357275970Scy if (sc->sc_mode == PSYCHO_MODE_PSYCHO) { 358290000Sglebius if (nreg <= 2) 359275970Scy panic("psycho_attach: %d not enough registers", nreg); 360275970Scy sc->sc_basepaddr = (vm_paddr_t)UPA_REG_PHYS(®[2]); 361275970Scy mlen = UPA_REG_SIZE(®[2]); 362275970Scy sc->sc_pcictl = UPA_REG_PHYS(®[0]) - sc->sc_basepaddr; 363275970Scy switch (sc->sc_pcictl) { 364275970Scy case PSR_PCICTL0: 365275970Scy sc->sc_half = 0; 366275970Scy break; 367275970Scy case PSR_PCICTL1: 368275970Scy sc->sc_half = 1; 369275970Scy break; 370275970Scy default: 371275970Scy panic("psycho_attach: bogus pci control register " 372290000Sglebius "location"); 373290000Sglebius } 374290000Sglebius } else { 375275970Scy if (nreg <= 0) 376275970Scy panic("psycho_attach: %d not enough registers", nreg); 377275970Scy sc->sc_basepaddr = (vm_paddr_t)UPA_REG_PHYS(®[0]); 378275970Scy mlen = UPA_REG_SIZE(reg); 379275970Scy sc->sc_pcictl = PSR_PCICTL0; 380290000Sglebius sc->sc_half = 0; 381290000Sglebius } 382290000Sglebius 383290000Sglebius /* 384290000Sglebius * Match other psycho's that are already configured against 385290000Sglebius * the base physical address. This will be the same for a 386290000Sglebius * pair of devices that share register space. 387290000Sglebius */ 388290000Sglebius SLIST_FOREACH(asc, &psycho_softcs, sc_link) { 389290000Sglebius if (asc->sc_basepaddr == sc->sc_basepaddr) { 390290000Sglebius /* Found partner */ 391290000Sglebius osc = asc; 392290000Sglebius break; 393275970Scy } 394290000Sglebius } 395290000Sglebius 396275970Scy if (osc == NULL) { 397290000Sglebius rid = 0; 398290000Sglebius sc->sc_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 399290000Sglebius sc->sc_basepaddr, sc->sc_basepaddr + mlen - 1, mlen, 400290000Sglebius RF_ACTIVE); 401290000Sglebius if (sc->sc_mem_res == NULL || 402290000Sglebius rman_get_start(sc->sc_mem_res) != sc->sc_basepaddr) 403290000Sglebius panic("psycho_attach: can't allocate device memory"); 404290000Sglebius sc->sc_bustag = rman_get_bustag(sc->sc_mem_res); 405290000Sglebius sc->sc_bushandle = rman_get_bushandle(sc->sc_mem_res); 406290000Sglebius } else { 407290000Sglebius /* 408290000Sglebius * There's another psycho using the same register space. Copy the 409290000Sglebius * relevant stuff. 410290000Sglebius */ 411275970Scy sc->sc_mem_res = NULL; 412275970Scy sc->sc_bustag = osc->sc_bustag; 413275970Scy sc->sc_bushandle = osc->sc_bushandle; 414275970Scy } 415275970Scy csr = PSYCHO_READ8(sc, PSR_CS); 416275970Scy sc->sc_ign = 0x7c0; /* APB IGN is always 0x7c */ 417275970Scy if (sc->sc_mode == PSYCHO_MODE_PSYCHO) 418275970Scy sc->sc_ign = PSYCHO_GCSR_IGN(csr) << 6; 419275970Scy 420275970Scy device_printf(dev, "%s, impl %d, version %d, ign %#x, bus %c\n", 421275970Scy desc->pd_name, (int)PSYCHO_GCSR_IMPL(csr), 422275970Scy (int)PSYCHO_GCSR_VERS(csr), sc->sc_ign, 'A' + sc->sc_half); 423275970Scy 424275970Scy /* 425275970Scy * Setup the PCI control register 426275970Scy */ 427275970Scy csr = PCICTL_READ8(sc, PCR_CS); 428275970Scy csr |= PCICTL_MRLM | PCICTL_ARB_PARK | PCICTL_ERRINTEN | PCICTL_4ENABLE; 429275970Scy csr &= ~(PCICTL_SERR | PCICTL_CPU_PRIO | PCICTL_ARB_PRIO | 430275970Scy PCICTL_RTRYWAIT); 431275970Scy PCICTL_WRITE8(sc, PCR_CS, csr); 432275970Scy 433275970Scy if (sc->sc_mode == PSYCHO_MODE_SABRE) { 434275970Scy /* 435275970Scy * Use the PROM preset for now. 436275970Scy */ 437290000Sglebius csr = PCICTL_READ8(sc, PCR_TAS); 438290000Sglebius if (csr == 0) 439290000Sglebius panic("psycho_attach: sabre TAS not initialized."); 440290000Sglebius sc->sc_dvmabase = (ffs(csr) - 1) << PCITAS_ADDR_SHIFT; 441275970Scy } else 442275970Scy sc->sc_dvmabase = -1; 443275970Scy 444275970Scy /* Grab the psycho ranges */ 445275970Scy psycho_get_ranges(sc->sc_node, &sc->sc_range, &sc->sc_nrange); 446290000Sglebius 447290000Sglebius /* Initialize memory and i/o rmans */ 448290000Sglebius sc->sc_io_rman.rm_type = RMAN_ARRAY; 449290000Sglebius sc->sc_io_rman.rm_descr = "Psycho PCI I/O Ports"; 450290000Sglebius if (rman_init(&sc->sc_io_rman) != 0 || 451290000Sglebius rman_manage_region(&sc->sc_io_rman, 0, PSYCHO_IO_SIZE) != 0) 452275970Scy panic("psycho_probe: failed to set up i/o rman"); 453290000Sglebius sc->sc_mem_rman.rm_type = RMAN_ARRAY; 454290000Sglebius sc->sc_mem_rman.rm_descr = "Psycho PCI Memory"; 455275970Scy if (rman_init(&sc->sc_mem_rman) != 0 || 456275970Scy rman_manage_region(&sc->sc_mem_rman, 0, PSYCHO_MEM_SIZE) != 0) 457275970Scy panic("psycho_probe: failed to set up memory rman"); 458290000Sglebius /* 459290000Sglebius * Find the addresses of the various bus spaces. 460290000Sglebius * There should not be multiple ones of one kind. 461290000Sglebius * The physical start addresses of the ranges are the configuration, 462290000Sglebius * memory and IO handles. 463290000Sglebius */ 464290000Sglebius for (n = 0; n < sc->sc_nrange; n++) { 465290000Sglebius i = UPA_RANGE_CS(&sc->sc_range[n]); 466290000Sglebius if (sc->sc_bh[i] != 0) 467290000Sglebius panic("psycho_attach: duplicate range for space %d", i); 468290000Sglebius sc->sc_bh[i] = UPA_RANGE_PHYS(&sc->sc_range[n]); 469290000Sglebius } 470290000Sglebius /* 471290000Sglebius * Check that all needed handles are present. The PCI_CS_MEM64 one is 472290000Sglebius * not currently used. 473290000Sglebius */ 474290000Sglebius for (n = 0; n < 3; n++) { 475290000Sglebius if (sc->sc_bh[n] == 0) 476290000Sglebius panic("psycho_attach: range %d missing", n); 477290000Sglebius } 478290000Sglebius 479290000Sglebius /* Register the softc, this is needed for paired psychos. */ 480290000Sglebius SLIST_INSERT_HEAD(&psycho_softcs, sc, sc_link); 481290000Sglebius 482290000Sglebius /* 483290000Sglebius * If we're a sabre or the first of a pair of psycho's to arrive here, 484290000Sglebius * start up the IOMMU. 485290000Sglebius */ 486290000Sglebius if (osc == NULL) { 487290000Sglebius /* 488290000Sglebius * Establish handlers for interesting interrupts.... 489290000Sglebius * 490290000Sglebius * XXX We need to remember these and remove this to support 491290000Sglebius * hotplug on the UPA/FHC bus. 492290000Sglebius * 493290000Sglebius * XXX Not all controllers have these, but installing them 494290000Sglebius * is better than trying to sort through this mess. 495275970Scy */ 496275970Scy psycho_set_intr(sc, 0, dev, PSR_UE_INT_MAP, INTR_FAST, 497275970Scy psycho_ue); 498275970Scy psycho_set_intr(sc, 1, dev, PSR_CE_INT_MAP, 0, psycho_ce); 499275970Scy psycho_set_intr(sc, 2, dev, PSR_PCIAERR_INT_MAP, INTR_FAST, 500275970Scy psycho_bus_a); 501275970Scy psycho_set_intr(sc, 4, dev, PSR_POWER_INT_MAP, 502290000Sglebius PSYCHO_PWRFAIL_INT_FLAGS, psycho_powerfail); 503290000Sglebius /* Psycho-specific initialization. */ 504290000Sglebius if (sc->sc_mode == PSYCHO_MODE_PSYCHO) { 505275970Scy /* 506275970Scy * Sabres do not have the following two interrupts. 507275970Scy */ 508290000Sglebius psycho_set_intr(sc, 3, dev, PSR_PCIBERR_INT_MAP, 509290000Sglebius INTR_FAST, psycho_bus_b); 510290000Sglebius#ifdef PSYCHO_MAP_WAKEUP 511275970Scy /* 512290000Sglebius * psycho_wakeup() doesn't do anything useful right 513290000Sglebius * now. 514290000Sglebius */ 515290000Sglebius psycho_set_intr(sc, 5, dev, PSR_PWRMGT_INT_MAP, 0, 516290000Sglebius psycho_wakeup); 517290000Sglebius#endif /* PSYCHO_MAP_WAKEUP */ 518290000Sglebius 519290000Sglebius /* Initialize the counter-timer. */ 520290000Sglebius sparc64_counter_init(sc->sc_bustag, sc->sc_bushandle, 521290000Sglebius PSR_TC0); 522290000Sglebius } 523290000Sglebius 524290000Sglebius /* 525290000Sglebius * Setup IOMMU and PCI configuration if we're the first 526290000Sglebius * of a pair of psycho's to arrive here. 527290000Sglebius * 528290000Sglebius * We should calculate a TSB size based on amount of RAM 529290000Sglebius * and number of bus controllers and number and type of 530290000Sglebius * child devices. 531290000Sglebius * 532290000Sglebius * For the moment, 32KB should be more than enough. 533290000Sglebius */ 534290000Sglebius sc->sc_is = malloc(sizeof(struct iommu_state), M_DEVBUF, 535290000Sglebius M_NOWAIT); 536290000Sglebius if (sc->sc_is == NULL) 537290000Sglebius panic("psycho_attach: malloc iommu_state failed"); 538290000Sglebius sc->sc_is->is_sb[0] = 0; 539290000Sglebius sc->sc_is->is_sb[1] = 0; 540290000Sglebius if (OF_getproplen(sc->sc_node, "no-streaming-cache") < 0) 541290000Sglebius sc->sc_is->is_sb[0] = sc->sc_pcictl + PCR_STRBUF; 542290000Sglebius psycho_iommu_init(sc, 3); 543290000Sglebius } else { 544290000Sglebius /* Just copy IOMMU state, config tag and address */ 545290000Sglebius sc->sc_is = osc->sc_is; 546290000Sglebius if (OF_getproplen(sc->sc_node, "no-streaming-cache") < 0) 547290000Sglebius sc->sc_is->is_sb[1] = sc->sc_pcictl + PCR_STRBUF; 548290000Sglebius iommu_reset(sc->sc_is); 549290000Sglebius } 550275970Scy 551275970Scy /* Allocate our tags. */ 552290000Sglebius sc->sc_memt = psycho_alloc_bus_tag(sc, PCI_MEMORY_BUS_SPACE); 553275970Scy sc->sc_iot = psycho_alloc_bus_tag(sc, PCI_IO_BUS_SPACE); 554275970Scy sc->sc_cfgt = psycho_alloc_bus_tag(sc, PCI_CONFIG_BUS_SPACE); 555275970Scy if (bus_dma_tag_create(sc->sc_dmatag, 8, 1, 0, 0x3ffffffff, NULL, NULL, 556275970Scy 0x3ffffffff, 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_dmat) != 0) 557275970Scy panic("psycho_attach: bus_dma_tag_create failed"); 558275970Scy /* Customize the tag. */ 559275970Scy sc->sc_dmat->dt_cookie = sc->sc_is; 560275970Scy sc->sc_dmat->dt_mt = &iommu_dma_methods; 561275970Scy /* XXX: register as root dma tag (kludge). */ 562290000Sglebius sparc64_root_dma_tag = sc->sc_dmat; 563290000Sglebius 564290000Sglebius#ifdef PSYCHO_DEBUG 565290000Sglebius /* 566275970Scy * Enable all interrupts and clear all interrupt states. 567290000Sglebius * This aids the debugging of interrupt routing problems. 568290000Sglebius */ 569290000Sglebius for (map = PSR_PCIA0_INT_MAP, clr = PSR_PCIA0_INT_CLR, n = 0; 570290000Sglebius map <= PSR_PCIB3_INT_MAP; map += 8, clr += 32, n++) { 571290000Sglebius mr = PSYCHO_READ8(sc, map); 572275970Scy device_printf(dev, "intr map (pci) %d: %#lx\n", n, (u_long)mr); 573290000Sglebius PSYCHO_WRITE8(sc, map, mr & ~INTMAP_V); 574275970Scy for (i = 0; i < 4; i++) 575275970Scy PCICTL_WRITE8(sc, clr + i * 8, 0); 576275970Scy PSYCHO_WRITE8(sc, map, INTMAP_ENABLE(mr, PCPU_GET(mid))); 577290000Sglebius } 578290000Sglebius for (map = PSR_SCSI_INT_MAP, clr = PSR_SCSI_INT_CLR, n = 0; 579290000Sglebius map <= PSR_SERIAL_INT_MAP; map += 8, clr += 8, n++) { 580290000Sglebius mr = PSYCHO_READ8(sc, map); 581290000Sglebius device_printf(dev, "intr map (obio) %d: %#lx, clr: %#lx\n", n, 582290000Sglebius (u_long)mr, (u_long)clr); 583290000Sglebius PSYCHO_WRITE8(sc, map, mr & ~INTMAP_V); 584275970Scy PSYCHO_WRITE8(sc, clr, 0); 585275970Scy PSYCHO_WRITE8(sc, map, INTMAP_ENABLE(mr, PCPU_GET(mid))); 586275970Scy } 587275970Scy#endif /* PSYCHO_DEBUG */ 588275970Scy 589275970Scy /* 590290000Sglebius * Get the bus range from the firmware; it is used solely for obtaining 591290000Sglebius * the inital bus number, and cannot be trusted on all machines. 592290000Sglebius */ 593290000Sglebius n = OF_getprop(node, "bus-range", (void *)psycho_br, sizeof(psycho_br)); 594290000Sglebius if (n == -1) 595275970Scy panic("could not get psycho bus-range"); 596275970Scy if (n != sizeof(psycho_br)) 597275970Scy panic("broken psycho bus-range (%d)", n); 598275970Scy 599275970Scy sc->sc_secbus = sc->sc_subbus = ofw_pci_alloc_busno(sc->sc_node); 600275970Scy /* 601275970Scy * Program the bus range registers. 602275970Scy * NOTE: the psycho, the second write changes the bus number the 603275970Scy * psycho itself uses for it's configuration space, so these 604275970Scy * writes must be kept in this order! 605275970Scy * The sabre always uses bus 0, but there only can be one sabre per 606275970Scy * machine. 607275970Scy */ 608275970Scy PCIB_WRITE_CONFIG(dev, psycho_br[0], PCS_DEVICE, PCS_FUNC, PCSR_SUBBUS, 609290000Sglebius sc->sc_subbus, 1); 610275970Scy PCIB_WRITE_CONFIG(dev, psycho_br[0], PCS_DEVICE, PCS_FUNC, PCSR_SECBUS, 611275970Scy sc->sc_secbus, 1); 612275970Scy 613290000Sglebius#ifdef OFW_NEWPCI 614290000Sglebius ofw_bus_setup_iinfo(node, &sc->sc_iinfo, sizeof(ofw_pci_intr_t)); 615290000Sglebius#else 616290000Sglebius obd.obd_bus = obd.obd_secbus = sc->sc_secbus; 617290000Sglebius obd.obd_subbus = sc->sc_subbus; 618290000Sglebius obd.obd_slot = PCS_DEVICE; 619290000Sglebius obd.obd_func = PCS_FUNC; 620290000Sglebius obd.obd_init = psycho_binit; 621290000Sglebius obd.obd_super = NULL; 622290000Sglebius 623290000Sglebius /* 624290000Sglebius * Initialize the interrupt registers of all devices hanging from 625290000Sglebius * the host bridge directly or indirectly via PCI-PCI bridges. 626290000Sglebius * The MI code (and the PCI spec) assume that this is done during 627275970Scy * system initialization, however the firmware does not do this 628290000Sglebius * at least on some models, and we probably shouldn't trust that 629290000Sglebius * the firmware uses the same model as this driver if it does. 630290000Sglebius * Additionally, set up the bus numbers and ranges. 631290000Sglebius */ 632290000Sglebius ofw_pci_init(dev, sc->sc_node, sc->sc_ign, &obd); 633290000Sglebius#endif /* OFW_NEWPCI */ 634290000Sglebius 635290000Sglebius device_add_child(dev, "pci", sc->sc_secbus); 636290000Sglebius return (bus_generic_attach(dev)); 637290000Sglebius} 638290000Sglebius 639290000Sglebiusstatic void 640275970Scypsycho_set_intr(struct psycho_softc *sc, int index, 641275970Scy device_t dev, bus_addr_t map, int iflags, driver_intr_t handler) 642275970Scy{ 643275970Scy int rid, vec; 644275970Scy u_int64_t mr; 645275970Scy 646275970Scy mr = PSYCHO_READ8(sc, map); 647275970Scy vec = INTVEC(mr); 648275970Scy sc->sc_irq_res[index] = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 649275970Scy vec, vec, 1, RF_ACTIVE); 650275970Scy if (sc->sc_irq_res[index] == NULL) 651275970Scy panic("psycho_set_intr: failed to get interrupt"); 652275970Scy bus_setup_intr(dev, sc->sc_irq_res[index], INTR_TYPE_MISC | iflags, 653275970Scy handler, sc, &sc->sc_ihand[index]); 654290000Sglebius PSYCHO_WRITE8(sc, map, INTMAP_ENABLE(mr, PCPU_GET(mid))); 655275970Scy} 656275970Scy 657275970Scystatic int 658275970Scypsycho_find_intrmap(struct psycho_softc *sc, int ino, bus_addr_t *intrmapptr, 659290000Sglebius bus_addr_t *intrclrptr, bus_addr_t *intrdiagptr) 660290000Sglebius{ 661290000Sglebius bus_addr_t intrmap, intrclr; 662290000Sglebius u_int64_t im; 663290000Sglebius u_long diag; 664275970Scy int found; 665275970Scy 666275970Scy found = 0; 667275970Scy /* Hunt thru obio first */ 668275970Scy diag = PSYCHO_READ8(sc, PSR_OBIO_INT_DIAG); 669275970Scy for (intrmap = PSR_SCSI_INT_MAP, intrclr = PSR_SCSI_INT_CLR; 670275970Scy intrmap <= PSR_SERIAL_INT_MAP; intrmap += 8, intrclr += 8, 671275970Scy diag >>= 2) { 672275970Scy im = PSYCHO_READ8(sc, intrmap); 673275970Scy if (INTINO(im) == ino) { 674275970Scy diag &= 2; 675275970Scy found = 1; 676275970Scy break; 677275970Scy } 678275970Scy } 679275970Scy 680275970Scy if (!found) { 681275970Scy diag = PSYCHO_READ8(sc, PSR_PCI_INT_DIAG); 682275970Scy /* Now do PCI interrupts */ 683275970Scy for (intrmap = PSR_PCIA0_INT_MAP, intrclr = PSR_PCIA0_INT_CLR; 684275970Scy intrmap <= PSR_PCIB3_INT_MAP; intrmap += 8, intrclr += 32, 685290000Sglebius diag >>= 8) { 686275970Scy if (sc->sc_mode == PSYCHO_MODE_PSYCHO && 687275970Scy (intrmap == PSR_PCIA2_INT_MAP || 688275970Scy intrmap == PSR_PCIA3_INT_MAP)) 689275970Scy continue; 690275970Scy im = PSYCHO_READ8(sc, intrmap); 691275970Scy if (((im ^ ino) & 0x3c) == 0) { 692275970Scy intrclr += 8 * (ino & 3); 693275970Scy diag = (diag >> ((ino & 3) * 2)) & 2; 694275970Scy found = 1; 695275970Scy break; 696275970Scy } 697275970Scy } 698275970Scy } 699275970Scy if (intrmapptr != NULL) 700275970Scy *intrmapptr = intrmap; 701290000Sglebius if (intrclrptr != NULL) 702290000Sglebius *intrclrptr = intrclr; 703290000Sglebius if (intrdiagptr != NULL) 704290000Sglebius *intrdiagptr = diag; 705275970Scy return (found); 706275970Scy} 707275970Scy 708275970Scy/* grovel the OBP for various psycho properties */ 709290000Sglebiusstatic void 710275970Scypsycho_get_ranges(phandle_t node, struct upa_ranges **rp, int *np) 711275970Scy{ 712290000Sglebius 713290000Sglebius *np = OF_getprop_alloc(node, "ranges", sizeof(**rp), (void **)rp); 714290000Sglebius if (*np == -1) 715290000Sglebius panic("could not get psycho ranges"); 716290000Sglebius} 717275970Scy 718290000Sglebius/* 719275970Scy * Interrupt handlers. 720290000Sglebius */ 721275970Scystatic void 722290000Sglebiuspsycho_ue(void *arg) 723275970Scy{ 724275970Scy struct psycho_softc *sc = (struct psycho_softc *)arg; 725275970Scy u_int64_t afar, afsr; 726275970Scy 727290000Sglebius afar = PSYCHO_READ8(sc, PSR_UE_AFA); 728290000Sglebius afsr = PSYCHO_READ8(sc, PSR_UE_AFS); 729290000Sglebius /* 730290000Sglebius * On the UltraSPARC-IIi/IIe, IOMMU misses/protection faults cause 731290000Sglebius * the AFAR to be set to the physical address of the TTE entry that 732290000Sglebius * was invalid/write protected. Call into the iommu code to have 733275970Scy * them decoded to virtual IO addresses. 734275970Scy */ 735290000Sglebius if ((afsr & UEAFSR_P_DTE) != 0) 736290000Sglebius iommu_decode_fault(sc->sc_is, afar); 737290000Sglebius /* It's uncorrectable. Dump the regs and panic. */ 738290000Sglebius panic("%s: uncorrectable DMA error AFAR %#lx AFSR %#lx", 739290000Sglebius device_get_name(sc->sc_dev), (u_long)afar, (u_long)afsr); 740290000Sglebius} 741290000Sglebius 742275970Scystatic void 743275970Scypsycho_ce(void *arg) 744290000Sglebius{ 745290000Sglebius struct psycho_softc *sc = (struct psycho_softc *)arg; 746290000Sglebius u_int64_t afar, afsr; 747290000Sglebius 748290000Sglebius afar = PSYCHO_READ8(sc, PSR_CE_AFA); 749290000Sglebius afsr = PSYCHO_READ8(sc, PSR_CE_AFS); 750290000Sglebius /* It's correctable. Dump the regs and continue. */ 751290000Sglebius device_printf(sc->sc_dev, "correctable DMA error AFAR %#lx " 752290000Sglebius "AFSR %#lx\n", (u_long)afar, (u_long)afsr); 753290000Sglebius /* Clear the error bits that we caught. */ 754290000Sglebius PSYCHO_WRITE8(sc, PSR_CE_AFS, afsr & CEAFSR_ERRMASK); 755290000Sglebius PSYCHO_WRITE8(sc, PSR_CE_INT_CLR, 0); 756290000Sglebius} 757290000Sglebius 758290000Sglebiusstatic void 759290000Sglebiuspsycho_bus_a(void *arg) 760290000Sglebius{ 761290000Sglebius struct psycho_softc *sc = (struct psycho_softc *)arg; 762290000Sglebius u_int64_t afar, afsr; 763290000Sglebius 764290000Sglebius afar = PSYCHO_READ8(sc, PSR_PCICTL0 + PCR_AFA); 765290000Sglebius afsr = PSYCHO_READ8(sc, PSR_PCICTL0 + PCR_AFS); 766290000Sglebius /* It's uncorrectable. Dump the regs and panic. */ 767290000Sglebius panic("%s: PCI bus A error AFAR %#lx AFSR %#lx", 768290000Sglebius device_get_name(sc->sc_dev), (u_long)afar, (u_long)afsr); 769290000Sglebius} 770290000Sglebius 771290000Sglebiusstatic void 772290000Sglebiuspsycho_bus_b(void *arg) 773290000Sglebius{ 774290000Sglebius struct psycho_softc *sc = (struct psycho_softc *)arg; 775290000Sglebius u_int64_t afar, afsr; 776290000Sglebius 777275970Scy afar = PSYCHO_READ8(sc, PSR_PCICTL1 + PCR_AFA); 778275970Scy afsr = PSYCHO_READ8(sc, PSR_PCICTL1 + PCR_AFS); 779275970Scy /* It's uncorrectable. Dump the regs and panic. */ 780275970Scy panic("%s: PCI bus B error AFAR %#lx AFSR %#lx", 781275970Scy device_get_name(sc->sc_dev), (u_long)afar, (u_long)afsr); 782275970Scy} 783275970Scy 784275970Scystatic void 785275970Scypsycho_powerfail(void *arg) 786275970Scy{ 787275970Scy 788275970Scy /* We lost power. Try to shut down NOW. */ 789290000Sglebius#ifdef DEBUGGER_ON_POWERFAIL 790290000Sglebius struct psycho_softc *sc = (struct psycho_softc *)arg; 791290000Sglebius 792290000Sglebius Debugger("powerfail"); 793290000Sglebius PSYCHO_WRITE8(sc, PSR_POWER_INT_CLR, 0); 794290000Sglebius#else 795290000Sglebius printf("Power Failure Detected: Shutting down NOW.\n"); 796290000Sglebius shutdown_nice(0); 797275970Scy#endif 798290000Sglebius} 799290000Sglebius 800290000Sglebius#ifdef PSYCHO_MAP_WAKEUP 801290000Sglebiusstatic void 802290000Sglebiuspsycho_wakeup(void *arg) 803290000Sglebius{ 804290000Sglebius struct psycho_softc *sc = (struct psycho_softc *)arg; 805290000Sglebius 806275970Scy PSYCHO_WRITE8(sc, PSR_PWRMGT_INT_CLR, 0); 807275970Scy /* Gee, we don't really have a framework to deal with this properly. */ 808275970Scy device_printf(sc->sc_dev, "power management wakeup\n"); 809290000Sglebius} 810290000Sglebius#endif /* PSYCHO_MAP_WAKEUP */ 811290000Sglebius 812290000Sglebius/* initialise the IOMMU... */ 813275970Scyvoid 814290000Sglebiuspsycho_iommu_init(struct psycho_softc *sc, int tsbsize) 815275970Scy{ 816275970Scy char *name; 817275970Scy struct iommu_state *is = sc->sc_is; 818275970Scy 819275970Scy /* punch in our copies */ 820275970Scy is->is_bustag = sc->sc_bustag; 821275970Scy is->is_bushandle = sc->sc_bushandle; 822275970Scy is->is_iommu = PSR_IOMMU; 823275970Scy is->is_dtag = PSR_IOMMU_TLB_TAG_DIAG; 824275970Scy is->is_ddram = PSR_IOMMU_TLB_DATA_DIAG; 825275970Scy is->is_dqueue = PSR_IOMMU_QUEUE_DIAG; 826275970Scy is->is_dva = PSR_IOMMU_SVADIAG; 827275970Scy is->is_dtcmp = PSR_IOMMU_TLB_CMP_DIAG; 828275970Scy 829275970Scy /* give us a nice name.. */ 830290000Sglebius name = (char *)malloc(32, M_DEVBUF, M_NOWAIT); 831290000Sglebius if (name == 0) 832290000Sglebius panic("couldn't malloc iommu name"); 833275970Scy snprintf(name, 32, "%s dvma", device_get_name(sc->sc_dev)); 834275970Scy 835290000Sglebius iommu_init(name, is, tsbsize, sc->sc_dvmabase, 0); 836290000Sglebius} 837290000Sglebius 838290000Sglebius#ifndef OFW_NEWPCI 839290000Sglebiusstatic void 840290000Sglebiuspsycho_binit(device_t busdev, struct ofw_pci_bdesc *obd) 841275970Scy{ 842275970Scy 843275970Scy#ifdef PSYCHO_DEBUG 844275970Scy printf("psycho at %u/%u/%u: setting bus #s to %u/%u/%u\n", 845275970Scy obd->obd_bus, obd->obd_slot, obd->obd_func, obd->obd_bus, 846275970Scy obd->obd_secbus, obd->obd_subbus); 847275970Scy#endif /* PSYCHO_DEBUG */ 848275970Scy PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func, 849275970Scy PCSR_SUBBUS, obd->obd_subbus, 1); 850275970Scy} 851275970Scy#endif 852275970Scy 853275970Scystatic int 854275970Scypsycho_maxslots(device_t dev) 855275970Scy{ 856275970Scy 857275970Scy /* XXX: is this correct? */ 858275970Scy return (PCI_SLOTMAX); 859290000Sglebius} 860275970Scy 861290000Sglebius#ifndef OFW_NEWPCI 862290000Sglebius/* 863290000Sglebius * Keep a table of quirky PCI devices that need fixups before the MI PCI code 864290000Sglebius * creates the resource lists. This needs to be moved around once other bus 865290000Sglebius * drivers are added. Moving it to the MI code should maybe be reconsidered 866290000Sglebius * if one of these devices appear in non-sparc64 boxen. It's likely that not 867290000Sglebius * all BIOSes/firmwares can deal with them. 868290000Sglebius */ 869290000Sglebiusstruct psycho_dquirk { 870290000Sglebius u_int32_t dq_devid; 871290000Sglebius int dq_quirk; 872290000Sglebius}; 873290000Sglebius 874290000Sglebius/* Quirk types. May be or'ed together. */ 875290000Sglebius#define DQT_BAD_INTPIN 1 /* Intpin reg 0, but intpin used */ 876275970Scy 877290000Sglebiusstatic struct psycho_dquirk dquirks[] = { 878275970Scy { 0x1001108e, DQT_BAD_INTPIN }, /* Sun HME (PCIO func. 1) */ 879275970Scy { 0x1101108e, DQT_BAD_INTPIN }, /* Sun GEM (PCIO2 func. 1) */ 880290000Sglebius { 0x1102108e, DQT_BAD_INTPIN }, /* Sun FireWire ctl. (PCIO2 func. 2) */ 881290000Sglebius { 0x1103108e, DQT_BAD_INTPIN }, /* Sun USB ctl. (PCIO2 func. 3) */ 882290000Sglebius}; 883290000Sglebius#endif /* !OFW_NEWPCI */ 884290000Sglebius 885290000Sglebius#define NDQUIRKS (sizeof(dquirks) / sizeof(dquirks[0])) 886290000Sglebius 887290000Sglebiusstatic u_int32_t 888290000Sglebiuspsycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, 889290000Sglebius int width) 890290000Sglebius{ 891290000Sglebius struct psycho_softc *sc; 892290000Sglebius bus_space_handle_t bh; 893290000Sglebius u_long offset = 0; 894275970Scy#ifndef OFW_NEWPCI 895290000Sglebius u_int32_t devid; 896290000Sglebius#endif 897290000Sglebius u_int8_t byte; 898290000Sglebius u_int16_t shrt; 899290000Sglebius u_int32_t wrd; 900290000Sglebius u_int32_t r; 901290000Sglebius int i; 902290000Sglebius 903290000Sglebius sc = (struct psycho_softc *)device_get_softc(dev); 904290000Sglebius offset = PSYCHO_CONF_OFF(bus, slot, func, reg); 905290000Sglebius bh = sc->sc_bh[PCI_CS_CONFIG]; 906290000Sglebius switch (width) { 907290000Sglebius case 1: 908290000Sglebius i = bus_space_peek_1(sc->sc_cfgt, bh, offset, &byte); 909290000Sglebius r = byte; 910290000Sglebius break; 911290000Sglebius case 2: 912290000Sglebius i = bus_space_peek_2(sc->sc_cfgt, bh, offset, &shrt); 913290000Sglebius r = shrt; 914290000Sglebius break; 915290000Sglebius case 4: 916290000Sglebius i = bus_space_peek_4(sc->sc_cfgt, bh, offset, &wrd); 917290000Sglebius r = wrd; 918290000Sglebius break; 919290000Sglebius default: 920290000Sglebius panic("psycho_read_config: bad width"); 921290000Sglebius } 922290000Sglebius 923290000Sglebius if (i) { 924290000Sglebius#ifdef PSYCHO_DEBUG 925290000Sglebius printf("psycho read data error reading: %d.%d.%d: 0x%x\n", 926290000Sglebius bus, slot, func, reg); 927290000Sglebius#endif 928290000Sglebius r = -1; 929290000Sglebius } 930290000Sglebius 931290000Sglebius#ifndef OFW_NEWPCI 932290000Sglebius if (reg == PCIR_INTPIN && r == 0) { 933290000Sglebius /* Check for DQT_BAD_INTPIN quirk. */ 934290000Sglebius devid = psycho_read_config(dev, bus, slot, func, 935290000Sglebius PCIR_DEVVENDOR, 4); 936290000Sglebius for (i = 0; i < NDQUIRKS; i++) { 937290000Sglebius if (dquirks[i].dq_devid == devid) { 938290000Sglebius /* 939290000Sglebius * Need to set the intpin to a value != 0 so 940290000Sglebius * that the MI code will think that this device 941290000Sglebius * has an interrupt. 942290000Sglebius * Just use 1 (intpin a) for now. This is, of 943290000Sglebius * course, bogus, but since interrupts are 944290000Sglebius * routed in advance, this does not really 945290000Sglebius * matter. 946290000Sglebius */ 947290000Sglebius if ((dquirks[i].dq_quirk & DQT_BAD_INTPIN) != 0) 948290000Sglebius r = 1; 949290000Sglebius break; 950290000Sglebius } 951290000Sglebius } 952310419Sdelphij } 953290000Sglebius#endif /* !OFW_NEWPCI */ 954290000Sglebius return (r); 955290000Sglebius} 956290000Sglebius 957290000Sglebiusstatic void 958290000Sglebiuspsycho_write_config(device_t dev, u_int bus, u_int slot, u_int func, 959290000Sglebius u_int reg, u_int32_t val, int width) 960290000Sglebius{ 961290000Sglebius struct psycho_softc *sc; 962290000Sglebius bus_space_handle_t bh; 963290000Sglebius u_long offset = 0; 964290000Sglebius 965290000Sglebius sc = (struct psycho_softc *)device_get_softc(dev); 966290000Sglebius offset = PSYCHO_CONF_OFF(bus, slot, func, reg); 967290000Sglebius bh = sc->sc_bh[PCI_CS_CONFIG]; 968290000Sglebius switch (width) { 969290000Sglebius case 1: 970290000Sglebius bus_space_write_1(sc->sc_cfgt, bh, offset, val); 971290000Sglebius break; 972290000Sglebius case 2: 973290000Sglebius bus_space_write_2(sc->sc_cfgt, bh, offset, val); 974290000Sglebius break; 975290000Sglebius case 4: 976290000Sglebius bus_space_write_4(sc->sc_cfgt, bh, offset, val); 977290000Sglebius break; 978290000Sglebius default: 979290000Sglebius panic("psycho_write_config: bad width"); 980290000Sglebius } 981290000Sglebius} 982290000Sglebius 983290000Sglebiusstatic int 984290000Sglebiuspsycho_route_interrupt(device_t bridge, device_t dev, int pin) 985290000Sglebius{ 986290000Sglebius#ifdef OFW_NEWPCI 987290000Sglebius struct psycho_softc *sc = device_get_softc(bridge); 988290000Sglebius struct ofw_pci_register reg; 989290000Sglebius bus_addr_t intrmap; 990290000Sglebius phandle_t node = ofw_pci_get_node(dev); 991290000Sglebius ofw_pci_intr_t pintr, mintr; 992290000Sglebius u_int8_t maskbuf[sizeof(reg) + sizeof(pintr)]; 993290000Sglebius 994290000Sglebius pintr = pin; 995290000Sglebius if (ofw_bus_lookup_imap(node, &sc->sc_iinfo, ®, sizeof(reg), 996290000Sglebius &pintr, sizeof(pintr), &mintr, sizeof(mintr), maskbuf)) 997290000Sglebius return (mintr); 998290000Sglebius /* 999290000Sglebius * If this is outside of the range for an intpin, it's likely a full 1000290000Sglebius * INO, and no mapping is required at all; this happens on the u30, 1001290000Sglebius * where there's no interrupt map at the psycho node. Fortunately, 1002290000Sglebius * there seem to be no INOs in the intpin range on this boxen, so 1003290000Sglebius * this easy heuristics will do. 1004290000Sglebius */ 1005290000Sglebius if (pin > 4) 1006290000Sglebius return (pin); 1007290000Sglebius /* 1008290000Sglebius * Guess the INO; we always assume that this is a non-OBIO 1009290000Sglebius * device, and that pin is a "real" intpin number. Determine 1010290000Sglebius * the mapping register to be used by the slot number. 1011290000Sglebius * We only need to do this on e450s, it seems; here, the slot numbers 1012290000Sglebius * for bus A are one-based, while those for bus B seemingly have an 1013290000Sglebius * offset of 2 (hence the factor of 3 below). 1014290000Sglebius */ 1015290000Sglebius intrmap = PSR_PCIA0_INT_MAP + 1016290000Sglebius 8 * (pci_get_slot(dev) - 1 + 3 * sc->sc_half); 1017290000Sglebius mintr = INTINO(PSYCHO_READ8(sc, intrmap)) + pin - 1; 1018290000Sglebius device_printf(bridge, "guessing interrupt %d for device %d/%d pin %d\n", 1019290000Sglebius (int)mintr, pci_get_slot(dev), pci_get_function(dev), pin); 1020290000Sglebius return (mintr); 1021290000Sglebius#else 1022290000Sglebius /* 1023290000Sglebius * XXX: ugly loathsome hack: 1024290000Sglebius * We can't use ofw_pci_route_intr() here; the device passed may be 1025290000Sglebius * the one of a bridge, so the original device can't be recovered. 1026290000Sglebius * 1027290000Sglebius * We need to use the firmware to route interrupts, however it has 1028290000Sglebius * no interface which could be used to interpret intpins; instead, 1029290000Sglebius * all assignments are done by device. 1030290000Sglebius * 1031290000Sglebius * The MI pci code will try to reroute interrupts of 0, although they 1032290000Sglebius * are correct; all other interrupts are preinitialized, so if we 1033290000Sglebius * get here, the intline is either 0 (so return 0), or we hit a 1034290000Sglebius * device which was not preinitialized (e.g. hotplugged stuff), in 1035290000Sglebius * which case we are lost. 1036290000Sglebius */ 1037290000Sglebius return (0); 1038290000Sglebius#endif /* OFW_NEWPCI */ 1039290000Sglebius} 1040290000Sglebius 1041290000Sglebiusstatic int 1042290000Sglebiuspsycho_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 1043290000Sglebius{ 1044290000Sglebius struct psycho_softc *sc; 1045290000Sglebius 1046290000Sglebius sc = (struct psycho_softc *)device_get_softc(dev); 1047290000Sglebius switch (which) { 1048290000Sglebius case PCIB_IVAR_BUS: 1049290000Sglebius *result = sc->sc_secbus; 1050290000Sglebius return (0); 1051290000Sglebius } 1052290000Sglebius return (ENOENT); 1053290000Sglebius} 1054290000Sglebius 1055290000Sglebius/* Write to the correct clr register, and call the actual handler. */ 1056290000Sglebiusstatic void 1057290000Sglebiuspsycho_intr_stub(void *arg) 1058290000Sglebius{ 1059290000Sglebius struct psycho_clr *pc; 1060290000Sglebius 1061290000Sglebius pc = (struct psycho_clr *)arg; 1062290000Sglebius pc->pci_handler(pc->pci_arg); 1063275970Scy PSYCHO_WRITE8(pc->pci_sc, pc->pci_clr, 0); 1064275970Scy} 1065275970Scy 1066290000Sglebiusstatic int 1067290000Sglebiuspsycho_setup_intr(device_t dev, device_t child, 1068290000Sglebius struct resource *ires, int flags, driver_intr_t *intr, void *arg, 1069290000Sglebius void **cookiep) 1070290000Sglebius{ 1071290000Sglebius struct psycho_softc *sc; 1072290000Sglebius struct psycho_clr *pc; 1073290000Sglebius bus_addr_t intrmapptr, intrclrptr; 1074290000Sglebius long vec = rman_get_start(ires); 1075290000Sglebius u_int64_t mr; 1076290000Sglebius int ino, error; 1077290000Sglebius 1078290000Sglebius sc = (struct psycho_softc *)device_get_softc(dev); 1079275970Scy pc = (struct psycho_clr *)malloc(sizeof(*pc), M_DEVBUF, M_NOWAIT); 1080290000Sglebius if (pc == NULL) 1081290000Sglebius return (NULL); 1082275970Scy 1083290000Sglebius /* 1084290000Sglebius * Hunt through all the interrupt mapping regs to look for our 1085275970Scy * interrupt vector. 1086290000Sglebius * 1087290000Sglebius * XXX We only compare INOs rather than IGNs since the firmware may 1088290000Sglebius * not provide the IGN and the IGN is constant for all device on that 1089290000Sglebius * PCI controller. This could cause problems for the FFB/external 1090290000Sglebius * interrupt which has a full vector that can be set arbitrarily. 1091290000Sglebius */ 1092290000Sglebius ino = INTINO(vec); 1093290000Sglebius 1094290000Sglebius if (!psycho_find_intrmap(sc, ino, &intrmapptr, &intrclrptr, NULL)) { 1095290000Sglebius device_printf(dev, "Cannot find interrupt vector %lx\n", vec); 1096290000Sglebius free(pc, M_DEVBUF); 1097290000Sglebius return (NULL); 1098290000Sglebius } 1099290000Sglebius 1100290000Sglebius#ifdef PSYCHO_DEBUG 1101275970Scy device_printf(dev, "psycho_setup_intr: INO %d, map %#lx, clr %#lx\n", 1102290000Sglebius ino, (u_long)intrmapptr, (u_long)intrclrptr); 1103290000Sglebius#endif 1104290000Sglebius pc->pci_sc = sc; 1105290000Sglebius pc->pci_arg = arg; 1106290000Sglebius pc->pci_handler = intr; 1107290000Sglebius pc->pci_clr = intrclrptr; 1108290000Sglebius /* Disable the interrupt while we fiddle with it */ 1109290000Sglebius mr = PSYCHO_READ8(sc, intrmapptr); 1110290000Sglebius PSYCHO_WRITE8(sc, intrmapptr, mr & ~INTMAP_V); 1111290000Sglebius error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, 1112290000Sglebius psycho_intr_stub, pc, cookiep); 1113290000Sglebius if (error != 0) { 1114290000Sglebius free(pc, M_DEVBUF); 1115290000Sglebius return (error); 1116290000Sglebius } 1117290000Sglebius pc->pci_cookie = *cookiep; 1118290000Sglebius *cookiep = pc; 1119290000Sglebius 1120290000Sglebius /* 1121290000Sglebius * Clear the interrupt, it might have been triggered before it was 1122290000Sglebius * set up. 1123290000Sglebius */ 1124290000Sglebius PSYCHO_WRITE8(sc, intrclrptr, 0); 1125290000Sglebius /* 1126290000Sglebius * Enable the interrupt and program the target module now we have the 1127290000Sglebius * handler installed. 1128290000Sglebius */ 1129290000Sglebius PSYCHO_WRITE8(sc, intrmapptr, INTMAP_ENABLE(mr, PCPU_GET(mid))); 1130290000Sglebius return (error); 1131290000Sglebius} 1132275970Scy 1133275970Scystatic int 1134275970Scypsycho_teardown_intr(device_t dev, device_t child, 1135275970Scy struct resource *vec, void *cookie) 1136275970Scy{ 1137275970Scy struct psycho_clr *pc; 1138275970Scy int error; 1139294904Sdelphij 1140290000Sglebius pc = (struct psycho_clr *)cookie; 1141290000Sglebius error = BUS_TEARDOWN_INTR(device_get_parent(dev), child, vec, 1142290000Sglebius pc->pci_cookie); 1143290000Sglebius /* 1144290000Sglebius * Don't disable the interrupt for now, so that stray interupts get 1145290000Sglebius * detected... 1146290000Sglebius */ 1147290000Sglebius if (error != 0) 1148290000Sglebius free(pc, M_DEVBUF); 1149290000Sglebius return (error); 1150290000Sglebius} 1151290000Sglebius 1152290000Sglebiusstatic struct resource * 1153290000Sglebiuspsycho_alloc_resource(device_t bus, device_t child, int type, int *rid, 1154290000Sglebius u_long start, u_long end, u_long count, u_int flags) 1155290000Sglebius{ 1156290000Sglebius struct psycho_softc *sc; 1157290000Sglebius struct resource *rv; 1158275970Scy struct rman *rm; 1159290000Sglebius bus_space_tag_t bt; 1160290000Sglebius bus_space_handle_t bh; 1161290000Sglebius int needactivate = flags & RF_ACTIVE; 1162290000Sglebius 1163290000Sglebius flags &= ~RF_ACTIVE; 1164294904Sdelphij 1165294904Sdelphij sc = (struct psycho_softc *)device_get_softc(bus); 1166294904Sdelphij if (type == SYS_RES_IRQ) { 1167294904Sdelphij /* 1168290000Sglebius * XXX: Don't accept blank ranges for now, only single 1169290000Sglebius * interrupts. The other case should not happen with the MI pci 1170275970Scy * code... 1171275970Scy * XXX: This may return a resource that is out of the range 1172290000Sglebius * that was specified. Is this correct...? 1173275970Scy */ 1174275970Scy if (start != end) 1175275970Scy panic("psycho_alloc_resource: XXX: interrupt range"); 1176275970Scy start = end |= sc->sc_ign; 1177290000Sglebius return (bus_alloc_resource(bus, type, rid, start, end, 1178290000Sglebius count, flags)); 1179290000Sglebius } 1180290000Sglebius switch (type) { 1181275970Scy case SYS_RES_MEMORY: 1182275970Scy rm = &sc->sc_mem_rman; 1183275970Scy bt = sc->sc_memt; 1184290000Sglebius bh = sc->sc_bh[PCI_CS_MEM32]; 1185290000Sglebius break; 1186275970Scy case SYS_RES_IOPORT: 1187290000Sglebius rm = &sc->sc_io_rman; 1188290000Sglebius bt = sc->sc_iot; 1189290000Sglebius bh = sc->sc_bh[PCI_CS_IO]; 1190290000Sglebius break; 1191290000Sglebius default: 1192290000Sglebius return (NULL); 1193290000Sglebius } 1194290000Sglebius 1195294904Sdelphij rv = rman_reserve_resource(rm, start, end, count, flags, child); 1196275970Scy if (rv == NULL) 1197290000Sglebius return (NULL); 1198290000Sglebius 1199290000Sglebius bh += rman_get_start(rv); 1200290000Sglebius rman_set_bustag(rv, bt); 1201290000Sglebius rman_set_bushandle(rv, bh); 1202290000Sglebius 1203275970Scy if (needactivate) { 1204275970Scy if (bus_activate_resource(child, type, *rid, rv)) { 1205275970Scy rman_release_resource(rv); 1206275970Scy return (NULL); 1207275970Scy } 1208275970Scy } 1209275970Scy 1210290000Sglebius return (rv); 1211290000Sglebius} 1212290000Sglebius 1213290000Sglebiusstatic int 1214290000Sglebiuspsycho_activate_resource(device_t bus, device_t child, int type, int rid, 1215290000Sglebius struct resource *r) 1216290000Sglebius{ 1217290000Sglebius void *p; 1218290000Sglebius int error; 1219290000Sglebius 1220290000Sglebius if (type == SYS_RES_IRQ) 1221290000Sglebius return (bus_activate_resource(bus, type, rid, r)); 1222290000Sglebius if (type == SYS_RES_MEMORY) { 1223290000Sglebius /* 1224290000Sglebius * Need to memory-map the device space, as some drivers depend 1225290000Sglebius * on the virtual address being set and useable. 1226290000Sglebius */ 1227290000Sglebius error = sparc64_bus_mem_map(rman_get_bustag(r), 1228290000Sglebius rman_get_bushandle(r), rman_get_size(r), 0, NULL, &p); 1229290000Sglebius if (error != 0) 1230290000Sglebius return (error); 1231290000Sglebius rman_set_virtual(r, p); 1232290000Sglebius } 1233290000Sglebius return (rman_activate_resource(r)); 1234290000Sglebius} 1235290000Sglebius 1236290000Sglebiusstatic int 1237290000Sglebiuspsycho_deactivate_resource(device_t bus, device_t child, int type, int rid, 1238290000Sglebius struct resource *r) 1239290000Sglebius{ 1240290000Sglebius 1241290000Sglebius if (type == SYS_RES_IRQ) 1242290000Sglebius return (bus_deactivate_resource(bus, type, rid, r)); 1243275970Scy if (type == SYS_RES_MEMORY) { 1244275970Scy sparc64_bus_mem_unmap(rman_get_virtual(r), rman_get_size(r)); 1245275970Scy rman_set_virtual(r, NULL); 1246275970Scy } 1247275970Scy return (rman_deactivate_resource(r)); 1248290000Sglebius} 1249290000Sglebius 1250290000Sglebiusstatic int 1251275970Scypsycho_release_resource(device_t bus, device_t child, int type, int rid, 1252275970Scy struct resource *r) 1253275970Scy{ 1254275970Scy int error; 1255275970Scy 1256275970Scy if (type == SYS_RES_IRQ) 1257275970Scy return (bus_release_resource(bus, type, rid, r)); 1258275970Scy if (rman_get_flags(r) & RF_ACTIVE) { 1259275970Scy error = bus_deactivate_resource(child, type, rid, r); 1260275970Scy if (error) 1261290000Sglebius return error; 1262290000Sglebius } 1263290000Sglebius return (rman_release_resource(r)); 1264290000Sglebius} 1265275970Scy 1266275970Scystatic int 1267275970Scypsycho_intr_pending(device_t dev, ofw_pci_intr_t intr) 1268275970Scy{ 1269275970Scy struct psycho_softc *sc; 1270275970Scy u_long diag; 1271275970Scy 1272275970Scy sc = (struct psycho_softc *)device_get_softc(dev); 1273275970Scy if (!psycho_find_intrmap(sc, intr, NULL, NULL, &diag)) { 1274275970Scy device_printf(dev, "psycho_intr_pending: mapping not found for" 1275290000Sglebius " %d\n", intr); 1276290000Sglebius return (0); 1277290000Sglebius } 1278275970Scy return (diag != 0); 1279290000Sglebius} 1280290000Sglebius 1281290000Sglebius#ifndef OFW_NEWPCI 1282290000Sglebiusstatic ofw_pci_intr_t 1283290000Sglebiuspsycho_guess_ino(device_t dev, phandle_t node, u_int slot, u_int pin) 1284290000Sglebius{ 1285290000Sglebius struct psycho_softc *sc = (struct psycho_softc *)device_get_softc(dev); 1286290000Sglebius bus_addr_t intrmap; 1287275970Scy 1288275970Scy /* 1289275970Scy * If this is not for one of our direct children (i.e. we are mapping 1290275970Scy * at our node), tell the interrupt mapper to go on - we need the 1291275970Scy * slot number of the device or it's topmost parent bridge to guess 1292275970Scy * the INO. 1293275970Scy */ 1294275970Scy if (node != sc->sc_node) 1295275970Scy return (PCI_INVALID_IRQ); 1296275970Scy /* 1297290000Sglebius * Actually guess the INO. We always assume that this is a non-OBIO 1298290000Sglebius * device, and use from the slot number to determine it. 1299290000Sglebius * We only need to do this on e450s, it seems; here, the slot numbers 1300290000Sglebius * for bus A are one-based, while those for bus B seemingly have an 1301290000Sglebius * offset of 2 (hence the factor of 3 below). 1302290000Sglebius */ 1303290000Sglebius intrmap = PSR_PCIA0_INT_MAP + 8 * (slot - 1 + 3 * sc->sc_half); 1304290000Sglebius return (INTINO(PSYCHO_READ8(sc, intrmap)) + pin - 1); 1305290000Sglebius} 1306290000Sglebius#endif /* !OFW_NEWPCI */ 1307290000Sglebius 1308275970Scystatic bus_space_handle_t 1309275970Scypsycho_get_bus_handle(device_t dev, int type, bus_space_handle_t childhdl, 1310275970Scy bus_space_tag_t *tag) 1311290000Sglebius{ 1312275970Scy struct psycho_softc *sc; 1313275970Scy 1314275970Scy sc = (struct psycho_softc *)device_get_softc(dev); 1315275970Scy switch (type) { 1316275970Scy case SYS_RES_IOPORT: 1317275970Scy *tag = sc->sc_iot; 1318290000Sglebius return (sc->sc_bh[PCI_CS_IO] + childhdl); 1319290000Sglebius case SYS_RES_MEMORY: 1320290000Sglebius *tag = sc->sc_memt; 1321275970Scy return (sc->sc_bh[PCI_CS_MEM32] + childhdl); 1322290000Sglebius default: 1323290000Sglebius panic("psycho_get_bus_handle: illegal space\n"); 1324290000Sglebius } 1325290000Sglebius} 1326290000Sglebius 1327290000Sglebius#ifdef OFW_NEWPCI 1328290000Sglebiusstatic phandle_t 1329290000Sglebiuspsycho_get_node(device_t bus, device_t dev) 1330275970Scy{ 1331275970Scy struct psycho_softc *sc = device_get_softc(bus); 1332290000Sglebius 1333275970Scy /* We only have one child, the PCI bus, which needs our own node. */ 1334275970Scy return (sc->sc_node); 1335275970Scy} 1336275970Scy 1337275970Scystatic void 1338275970Scypsycho_adjust_busrange(device_t dev, u_int subbus) 1339275970Scy{ 1340275970Scy struct psycho_softc *sc = device_get_softc(dev); 1341290000Sglebius 1342290000Sglebius /* If necessary, adjust the subordinate bus number register. */ 1343290000Sglebius if (subbus > sc->sc_subbus) { 1344290000Sglebius#ifdef PSYCHO_DEBUG 1345290000Sglebius device_printf(dev, 1346290000Sglebius "adjusting secondary bus number from %d to %d\n", 1347290000Sglebius sc->sc_subbus, subbus); 1348290000Sglebius#endif 1349290000Sglebius sc->sc_subbus = subbus; 1350290000Sglebius PCIB_WRITE_CONFIG(dev, sc->sc_secbus, PCS_DEVICE, PCS_FUNC, 1351290000Sglebius PCSR_SUBBUS, subbus, 1); 1352275970Scy } 1353275970Scy} 1354275970Scy#endif 1355275970Scy 1356275970Scy/* 1357275970Scy * below here is bus space and bus dma support 1358275970Scy */ 1359290000Sglebiusstatic bus_space_tag_t 1360290000Sglebiuspsycho_alloc_bus_tag(struct psycho_softc *sc, int type) 1361275970Scy{ 1362275970Scy bus_space_tag_t bt; 1363275970Scy 1364275970Scy bt = (bus_space_tag_t)malloc(sizeof(struct bus_space_tag), M_DEVBUF, 1365275970Scy M_NOWAIT | M_ZERO); 1366290000Sglebius if (bt == NULL) 1367290000Sglebius panic("psycho_alloc_bus_tag: out of memory"); 1368290000Sglebius 1369275970Scy bzero(bt, sizeof *bt); 1370290000Sglebius bt->bst_cookie = sc; 1371275970Scy bt->bst_parent = sc->sc_bustag; 1372290000Sglebius bt->bst_type = type; 1373290000Sglebius return (bt); 1374290000Sglebius} 1375275970Scy