sbus.c revision 157896
1/*- 2 * Copyright (c) 1998 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Paul Kranenburg. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the NetBSD 19 * Foundation, Inc. and its contributors. 20 * 4. Neither the name of The NetBSD Foundation nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36/*- 37 * Copyright (c) 1992, 1993 38 * The Regents of the University of California. All rights reserved. 39 * 40 * This software was developed by the Computer Systems Engineering group 41 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 42 * contributed to Berkeley. 43 * 44 * All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed by the University of 47 * California, Lawrence Berkeley Laboratory. 48 * 49 * Redistribution and use in source and binary forms, with or without 50 * modification, are permitted provided that the following conditions 51 * are met: 52 * 1. Redistributions of source code must retain the above copyright 53 * notice, this list of conditions and the following disclaimer. 54 * 2. Redistributions in binary form must reproduce the above copyright 55 * notice, this list of conditions and the following disclaimer in the 56 * documentation and/or other materials provided with the distribution. 57 * 4. Neither the name of the University nor the names of its contributors 58 * may be used to endorse or promote products derived from this software 59 * without specific prior written permission. 60 * 61 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 63 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 64 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 65 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 69 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 70 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 71 * SUCH DAMAGE. 72 */ 73/*- 74 * Copyright (c) 1999 Eduardo Horvath 75 * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>. 76 * All rights reserved. 77 * 78 * Redistribution and use in source and binary forms, with or without 79 * modification, are permitted provided that the following conditions 80 * are met: 81 * 1. Redistributions of source code must retain the above copyright 82 * notice, this list of conditions and the following disclaimer. 83 * 84 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 85 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 86 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 87 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 88 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 89 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 90 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 91 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 92 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 93 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 94 * SUCH DAMAGE. 95 * 96 * from: @(#)sbus.c 8.1 (Berkeley) 6/11/93 97 * from: NetBSD: sbus.c,v 1.46 2001/10/07 20:30:41 eeh Exp 98 */ 99 100#include <sys/cdefs.h> 101__FBSDID("$FreeBSD: head/sys/sparc64/sbus/sbus.c 157896 2006-04-20 04:20:41Z imp $"); 102 103/* 104 * SBus support. 105 */ 106 107#include <sys/param.h> 108#include <sys/systm.h> 109#include <sys/bus.h> 110#include <sys/kernel.h> 111#include <sys/malloc.h> 112#include <sys/module.h> 113#include <sys/pcpu.h> 114#include <sys/reboot.h> 115 116#include <dev/ofw/ofw_bus.h> 117#include <dev/ofw/ofw_bus_subr.h> 118#include <dev/ofw/openfirm.h> 119 120#include <machine/bus.h> 121#include <machine/bus_private.h> 122#include <machine/iommureg.h> 123#include <machine/bus_common.h> 124#include <machine/intr_machdep.h> 125#include <machine/nexusvar.h> 126#include <machine/ofw_upa.h> 127#include <machine/resource.h> 128 129#include <sys/rman.h> 130 131#include <machine/iommuvar.h> 132 133#include <sparc64/sbus/ofw_sbus.h> 134#include <sparc64/sbus/sbusreg.h> 135#include <sparc64/sbus/sbusvar.h> 136 137struct sbus_devinfo { 138 int sdi_burstsz; 139 int sdi_clockfreq; 140 int sdi_slot; 141 142 struct ofw_bus_devinfo sdi_obdinfo; 143 struct resource_list sdi_rl; 144}; 145 146/* Range descriptor, allocated for each sc_range. */ 147struct sbus_rd { 148 bus_addr_t rd_poffset; 149 bus_addr_t rd_pend; 150 int rd_slot; 151 bus_addr_t rd_coffset; 152 bus_addr_t rd_cend; 153 struct rman rd_rman; 154 bus_space_handle_t rd_bushandle; 155 struct resource *rd_res; 156}; 157 158struct sbus_softc { 159 bus_space_tag_t sc_bustag; 160 bus_space_handle_t sc_bushandle; 161 bus_dma_tag_t sc_dmatag; 162 bus_dma_tag_t sc_cdmatag; 163 bus_space_tag_t sc_cbustag; 164 int sc_clockfreq; /* clock frequency (in Hz) */ 165 struct upa_regs *sc_reg; 166 int sc_nreg; 167 int sc_nrange; 168 struct sbus_rd *sc_rd; 169 int sc_burst; /* burst transfer sizes supp. */ 170 171 struct resource *sc_sysio_res; 172 int sc_ign; /* IGN for this sysio */ 173 struct iommu_state sc_is; /* IOMMU state (iommuvar.h) */ 174 175 struct resource *sc_ot_ires; 176 void *sc_ot_ihand; 177 struct resource *sc_pf_ires; 178 void *sc_pf_ihand; 179}; 180 181struct sbus_clr { 182 struct sbus_softc *scl_sc; 183 bus_addr_t scl_clr; /* clear register */ 184 driver_intr_t *scl_handler; /* handler to call */ 185 void *scl_arg; /* argument for the handler */ 186 void *scl_cookie; /* parent bus int. cookie */ 187}; 188 189#define SYSIO_READ8(sc, off) \ 190 bus_space_read_8((sc)->sc_bustag, (sc)->sc_bushandle, (off)) 191#define SYSIO_WRITE8(sc, off, v) \ 192 bus_space_write_8((sc)->sc_bustag, (sc)->sc_bushandle, (off), (v)) 193 194static device_probe_t sbus_probe; 195static device_attach_t sbus_attach; 196static bus_print_child_t sbus_print_child; 197static bus_probe_nomatch_t sbus_probe_nomatch; 198static bus_read_ivar_t sbus_read_ivar; 199static bus_get_resource_list_t sbus_get_resource_list; 200static bus_setup_intr_t sbus_setup_intr; 201static bus_teardown_intr_t sbus_teardown_intr; 202static bus_alloc_resource_t sbus_alloc_resource; 203static bus_release_resource_t sbus_release_resource; 204static bus_activate_resource_t sbus_activate_resource; 205static bus_deactivate_resource_t sbus_deactivate_resource; 206static ofw_bus_get_devinfo_t sbus_get_devinfo; 207 208static int sbus_inlist(const char *, const char **); 209static struct sbus_devinfo * sbus_setup_dinfo(device_t, struct sbus_softc *, 210 phandle_t); 211static void sbus_destroy_dinfo(struct sbus_devinfo *); 212static void sbus_intr_stub(void *); 213static bus_space_tag_t sbus_alloc_bustag(struct sbus_softc *); 214static void sbus_overtemp(void *); 215static void sbus_pwrfail(void *); 216static int sbus_print_res(struct sbus_devinfo *); 217 218static device_method_t sbus_methods[] = { 219 /* Device interface */ 220 DEVMETHOD(device_probe, sbus_probe), 221 DEVMETHOD(device_attach, sbus_attach), 222 DEVMETHOD(device_shutdown, bus_generic_shutdown), 223 DEVMETHOD(device_suspend, bus_generic_suspend), 224 DEVMETHOD(device_resume, bus_generic_resume), 225 226 /* Bus interface */ 227 DEVMETHOD(bus_print_child, sbus_print_child), 228 DEVMETHOD(bus_probe_nomatch, sbus_probe_nomatch), 229 DEVMETHOD(bus_read_ivar, sbus_read_ivar), 230 DEVMETHOD(bus_setup_intr, sbus_setup_intr), 231 DEVMETHOD(bus_teardown_intr, sbus_teardown_intr), 232 DEVMETHOD(bus_alloc_resource, sbus_alloc_resource), 233 DEVMETHOD(bus_activate_resource, sbus_activate_resource), 234 DEVMETHOD(bus_deactivate_resource, sbus_deactivate_resource), 235 DEVMETHOD(bus_release_resource, sbus_release_resource), 236 DEVMETHOD(bus_get_resource_list, sbus_get_resource_list), 237 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 238 239 /* ofw_bus interface */ 240 DEVMETHOD(ofw_bus_get_devinfo, sbus_get_devinfo), 241 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 242 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 243 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 244 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 245 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 246 247 { 0, 0 } 248}; 249 250static driver_t sbus_driver = { 251 "sbus", 252 sbus_methods, 253 sizeof(struct sbus_softc), 254}; 255 256static devclass_t sbus_devclass; 257 258DRIVER_MODULE(sbus, nexus, sbus_driver, sbus_devclass, 0, 0); 259 260#define OFW_SBUS_TYPE "sbus" 261#define OFW_SBUS_NAME "sbus" 262 263static const char *sbus_order_first[] = { 264 "auxio", 265 "dma", 266 NULL 267}; 268 269static int 270sbus_inlist(const char *name, const char **list) 271{ 272 int i; 273 274 if (name == NULL) 275 return (0); 276 for (i = 0; list[i] != NULL; i++) { 277 if (strcmp(name, list[i]) == 0) 278 return (1); 279 } 280 return (0); 281} 282 283static int 284sbus_probe(device_t dev) 285{ 286 char *t; 287 288 t = nexus_get_device_type(dev); 289 if (((t == NULL || strcmp(t, OFW_SBUS_TYPE) != 0)) && 290 strcmp(nexus_get_name(dev), OFW_SBUS_NAME) != 0) 291 return (ENXIO); 292 device_set_desc(dev, "U2S UPA-SBus bridge"); 293 return (0); 294} 295 296static int 297sbus_attach(device_t dev) 298{ 299 struct sbus_softc *sc; 300 struct sbus_devinfo *sdi; 301 struct sbus_ranges *range; 302 struct resource *res; 303 device_t cdev; 304 bus_addr_t phys; 305 bus_size_t size; 306 char *name; 307 phandle_t child, node; 308 u_int64_t mr; 309 int intr, clock, rid, vec, i; 310 311 sc = device_get_softc(dev); 312 node = nexus_get_node(dev); 313 314 if ((sc->sc_nreg = OF_getprop_alloc(node, "reg", sizeof(*sc->sc_reg), 315 (void **)&sc->sc_reg)) == -1) { 316 panic("%s: error getting reg property", __func__); 317 } 318 if (sc->sc_nreg < 1) 319 panic("%s: bogus properties", __func__); 320 phys = UPA_REG_PHYS(&sc->sc_reg[0]); 321 size = UPA_REG_SIZE(&sc->sc_reg[0]); 322 rid = 0; 323 sc->sc_sysio_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, phys, 324 phys + size - 1, size, RF_ACTIVE); 325 if (sc->sc_sysio_res == NULL || 326 rman_get_start(sc->sc_sysio_res) != phys) 327 panic("%s: cannot allocate device memory", __func__); 328 sc->sc_bustag = rman_get_bustag(sc->sc_sysio_res); 329 sc->sc_bushandle = rman_get_bushandle(sc->sc_sysio_res); 330 331 if (OF_getprop(node, "interrupts", &intr, sizeof(intr)) == -1) 332 panic("%s: cannot get IGN", __func__); 333 sc->sc_ign = (intr & INTMAP_IGN_MASK) >> INTMAP_IGN_SHIFT; 334 sc->sc_cbustag = sbus_alloc_bustag(sc); 335 336 /* 337 * Record clock frequency for synchronous SCSI. 338 * IS THIS THE CORRECT DEFAULT?? 339 */ 340 if (OF_getprop(node, "clock-frequency", &clock, sizeof(clock)) == -1) 341 clock = 25000000; 342 sc->sc_clockfreq = clock; 343 clock /= 1000; 344 device_printf(dev, "clock %d.%03d MHz\n", clock / 1000, clock % 1000); 345 346 /* 347 * Collect address translations from the OBP. 348 */ 349 if ((sc->sc_nrange = OF_getprop_alloc(node, "ranges", 350 sizeof(*range), (void **)&range)) == -1) { 351 panic("%s: error getting ranges property", __func__); 352 } 353 sc->sc_rd = (struct sbus_rd *)malloc(sizeof(*sc->sc_rd) * sc->sc_nrange, 354 M_DEVBUF, M_NOWAIT); 355 if (sc->sc_rd == NULL) 356 panic("%s: cannot allocate rmans", __func__); 357 /* 358 * Preallocate all space that the SBus bridge decodes, so that nothing 359 * else gets in the way; set up rmans etc. 360 */ 361 for (i = 0; i < sc->sc_nrange; i++) { 362 phys = range[i].poffset | ((bus_addr_t)range[i].pspace << 32); 363 size = range[i].size; 364 sc->sc_rd[i].rd_slot = range[i].cspace; 365 sc->sc_rd[i].rd_coffset = range[i].coffset; 366 sc->sc_rd[i].rd_cend = sc->sc_rd[i].rd_coffset + size; 367 rid = 0; 368 if ((res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, phys, 369 phys + size - 1, size, RF_ACTIVE)) == NULL) 370 panic("%s: cannot allocate decoded range", __func__); 371 sc->sc_rd[i].rd_bushandle = rman_get_bushandle(res); 372 sc->sc_rd[i].rd_rman.rm_type = RMAN_ARRAY; 373 sc->sc_rd[i].rd_rman.rm_descr = "SBus Device Memory"; 374 if (rman_init(&sc->sc_rd[i].rd_rman) != 0 || 375 rman_manage_region(&sc->sc_rd[i].rd_rman, 0, size) != 0) 376 panic("%s: failed to set up memory rman", __func__); 377 sc->sc_rd[i].rd_poffset = phys; 378 sc->sc_rd[i].rd_pend = phys + size; 379 sc->sc_rd[i].rd_res = res; 380 } 381 free(range, M_OFWPROP); 382 383 /* 384 * Get the SBus burst transfer size if burst transfers are supported. 385 * XXX: is the default correct? 386 */ 387 if (OF_getprop(node, "burst-sizes", &sc->sc_burst, 388 sizeof(sc->sc_burst)) == -1 || sc->sc_burst == 0) 389 sc->sc_burst = SBUS_BURST_DEF; 390 391 /* initalise the IOMMU */ 392 393 /* punch in our copies */ 394 sc->sc_is.is_bustag = sc->sc_bustag; 395 sc->sc_is.is_bushandle = sc->sc_bushandle; 396 sc->sc_is.is_iommu = SBR_IOMMU; 397 sc->sc_is.is_dtag = SBR_IOMMU_TLB_TAG_DIAG; 398 sc->sc_is.is_ddram = SBR_IOMMU_TLB_DATA_DIAG; 399 sc->sc_is.is_dqueue = SBR_IOMMU_QUEUE_DIAG; 400 sc->sc_is.is_dva = SBR_IOMMU_SVADIAG; 401 sc->sc_is.is_dtcmp = 0; 402 sc->sc_is.is_sb[0] = SBR_STRBUF; 403 sc->sc_is.is_sb[1] = 0; 404 405 /* give us a nice name.. */ 406 name = (char *)malloc(32, M_DEVBUF, M_NOWAIT); 407 if (name == NULL) 408 panic("%s: cannot malloc iommu name", __func__); 409 snprintf(name, 32, "%s dvma", device_get_name(dev)); 410 411 /* 412 * Note: the SBus IOMMU ignores the high bits of an address, so a NULL 413 * DMA pointer will be translated by the first page of the IOTSB. 414 * To detect bugs we'll allocate and ignore the first entry. 415 */ 416 iommu_init(name, &sc->sc_is, 3, -1, 1); 417 418 /* Create the DMA tag. */ 419 sc->sc_dmatag = nexus_get_dmatag(dev); 420 if (bus_dma_tag_create(sc->sc_dmatag, 8, 1, 0, 0x3ffffffff, NULL, NULL, 421 0x3ffffffff, 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_cdmatag) != 0) 422 panic("%s: bus_dma_tag_create failed", __func__); 423 /* Customize the tag. */ 424 sc->sc_cdmatag->dt_cookie = &sc->sc_is; 425 sc->sc_cdmatag->dt_mt = &iommu_dma_methods; 426 /* XXX: register as root dma tag (kludge). */ 427 sparc64_root_dma_tag = sc->sc_cdmatag; 428 429 /* Enable the over-temperature and power-fail interrupts. */ 430 rid = 0; 431 mr = SYSIO_READ8(sc, SBR_THERM_INT_MAP); 432 vec = INTVEC(mr); 433 if ((sc->sc_ot_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, vec, 434 vec, 1, RF_ACTIVE)) == NULL) 435 panic("%s: failed to get temperature interrupt", __func__); 436 bus_setup_intr(dev, sc->sc_ot_ires, INTR_TYPE_MISC | INTR_FAST, 437 sbus_overtemp, sc, &sc->sc_ot_ihand); 438 SYSIO_WRITE8(sc, SBR_THERM_INT_MAP, INTMAP_ENABLE(mr, PCPU_GET(mid))); 439 rid = 0; 440 mr = SYSIO_READ8(sc, SBR_POWER_INT_MAP); 441 vec = INTVEC(mr); 442 if ((sc->sc_pf_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, vec, 443 vec, 1, RF_ACTIVE)) == NULL) 444 panic("%s: failed to get power fail interrupt", __func__); 445 bus_setup_intr(dev, sc->sc_pf_ires, INTR_TYPE_MISC | INTR_FAST, 446 sbus_pwrfail, sc, &sc->sc_pf_ihand); 447 SYSIO_WRITE8(sc, SBR_POWER_INT_MAP, INTMAP_ENABLE(mr, PCPU_GET(mid))); 448 449 /* Initialize the counter-timer. */ 450 sparc64_counter_init(sc->sc_bustag, sc->sc_bushandle, SBR_TC0); 451 452 /* 453 * Loop through ROM children, fixing any relative addresses 454 * and then configuring each device. 455 */ 456 for (child = OF_child(node); child != 0; child = OF_peer(child)) { 457 if ((sdi = sbus_setup_dinfo(dev, sc, child)) == NULL) 458 continue; 459 /* 460 * For devices where there are variants that are actually 461 * split into two SBus devices (as opposed to the first 462 * half of the device being a SBus device and the second 463 * half hanging off of the first one) like 'auxio' and 464 * 'SUNW,fdtwo' or 'dma' and 'esp' probe the SBus device 465 * which is a prerequisite to the driver attaching to the 466 * second one with a lower order. Saves us from dealing 467 * with different probe orders in the respective device 468 * drivers which generally is more hackish. 469 */ 470 cdev = device_add_child_ordered(dev, (OF_child(child) == 0 && 471 sbus_inlist(sdi->sdi_obdinfo.obd_name, sbus_order_first)) ? 472 SBUS_ORDER_FIRST : SBUS_ORDER_NORMAL, NULL, -1); 473 if (cdev == NULL) { 474 device_printf(dev, 475 "<%s>: device_add_child_ordered failed\n", 476 sdi->sdi_obdinfo.obd_name); 477 sbus_destroy_dinfo(sdi); 478 continue; 479 } 480 device_set_ivars(cdev, sdi); 481 } 482 return (bus_generic_attach(dev)); 483} 484 485static struct sbus_devinfo * 486sbus_setup_dinfo(device_t dev, struct sbus_softc *sc, phandle_t node) 487{ 488 struct sbus_devinfo *sdi; 489 struct sbus_regs *reg; 490 u_int32_t base, iv, *intr; 491 int i, nreg, nintr, slot, rslot; 492 493 sdi = malloc(sizeof(*sdi), M_DEVBUF, M_ZERO | M_WAITOK); 494 if (ofw_bus_gen_setup_devinfo(&sdi->sdi_obdinfo, node) != 0) { 495 free(sdi, M_DEVBUF); 496 return (NULL); 497 } 498 resource_list_init(&sdi->sdi_rl); 499 slot = -1; 500 nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)®); 501 if (nreg == -1) { 502 if (sdi->sdi_obdinfo.obd_type == NULL || 503 strcmp(sdi->sdi_obdinfo.obd_type, "hierarchical") != 0) { 504 device_printf(dev, "<%s>: incomplete\n", 505 sdi->sdi_obdinfo.obd_name); 506 goto fail; 507 } 508 } else { 509 for (i = 0; i < nreg; i++) { 510 base = reg[i].sbr_offset; 511 if (SBUS_ABS(base)) { 512 rslot = SBUS_ABS_TO_SLOT(base); 513 base = SBUS_ABS_TO_OFFSET(base); 514 } else 515 rslot = reg[i].sbr_slot; 516 if (slot != -1 && slot != rslot) { 517 device_printf(dev, "<%s>: multiple slots\n", 518 sdi->sdi_obdinfo.obd_name); 519 free(reg, M_OFWPROP); 520 goto fail; 521 } 522 slot = rslot; 523 524 resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY, i, 525 base, base + reg[i].sbr_size, reg[i].sbr_size); 526 } 527 free(reg, M_OFWPROP); 528 } 529 sdi->sdi_slot = slot; 530 531 /* 532 * The `interrupts' property contains the SBus interrupt level. 533 */ 534 nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr), 535 (void **)&intr); 536 if (nintr != -1) { 537 for (i = 0; i < nintr; i++) { 538 iv = intr[i]; 539 /* 540 * SBus card devices need the slot number encoded into 541 * the vector as this is generally not done. 542 */ 543 if ((iv & INTMAP_OBIO_MASK) == 0) 544 iv |= slot << 3; 545 /* Set the ign as appropriate. */ 546 iv |= sc->sc_ign << INTMAP_IGN_SHIFT; 547 resource_list_add(&sdi->sdi_rl, SYS_RES_IRQ, i, 548 iv, iv, 1); 549 } 550 free(intr, M_OFWPROP); 551 } 552 if (OF_getprop(node, "burst-sizes", &sdi->sdi_burstsz, 553 sizeof(sdi->sdi_burstsz)) == -1) 554 sdi->sdi_burstsz = sc->sc_burst; 555 else 556 sdi->sdi_burstsz &= sc->sc_burst; 557 if (OF_getprop(node, "clock-frequency", &sdi->sdi_clockfreq, 558 sizeof(sdi->sdi_clockfreq)) == -1) 559 sdi->sdi_clockfreq = sc->sc_clockfreq; 560 561 return (sdi); 562 563fail: 564 sbus_destroy_dinfo(sdi); 565 return (NULL); 566} 567 568static void 569sbus_destroy_dinfo(struct sbus_devinfo *dinfo) 570{ 571 572 resource_list_free(&dinfo->sdi_rl); 573 ofw_bus_gen_destroy_devinfo(&dinfo->sdi_obdinfo); 574 free(dinfo, M_DEVBUF); 575} 576 577static int 578sbus_print_child(device_t dev, device_t child) 579{ 580 int rv; 581 582 rv = bus_print_child_header(dev, child); 583 rv += sbus_print_res(device_get_ivars(child)); 584 rv += bus_print_child_footer(dev, child); 585 return (rv); 586} 587 588static void 589sbus_probe_nomatch(device_t dev, device_t child) 590{ 591 const char *type; 592 593 device_printf(dev, "<%s>", ofw_bus_get_name(child)); 594 sbus_print_res(device_get_ivars(child)); 595 type = ofw_bus_get_type(child); 596 printf(" type %s (no driver attached)\n", 597 type != NULL ? type : "unknown"); 598} 599 600static int 601sbus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 602{ 603 struct sbus_softc *sc; 604 struct sbus_devinfo *dinfo; 605 606 sc = device_get_softc(dev); 607 if ((dinfo = device_get_ivars(child)) == NULL) 608 return (ENOENT); 609 switch (which) { 610 case SBUS_IVAR_BURSTSZ: 611 *result = dinfo->sdi_burstsz; 612 break; 613 case SBUS_IVAR_CLOCKFREQ: 614 *result = dinfo->sdi_clockfreq; 615 break; 616 case SBUS_IVAR_IGN: 617 *result = sc->sc_ign; 618 break; 619 case SBUS_IVAR_SLOT: 620 *result = dinfo->sdi_slot; 621 break; 622 default: 623 return (ENOENT); 624 } 625 return (0); 626} 627 628static struct resource_list * 629sbus_get_resource_list(device_t dev, device_t child) 630{ 631 struct sbus_devinfo *sdi; 632 633 sdi = device_get_ivars(child); 634 return (&sdi->sdi_rl); 635} 636 637/* Write to the correct clr register, and call the actual handler. */ 638static void 639sbus_intr_stub(void *arg) 640{ 641 struct sbus_clr *scl; 642 643 scl = (struct sbus_clr *)arg; 644 scl->scl_handler(scl->scl_arg); 645 SYSIO_WRITE8(scl->scl_sc, scl->scl_clr, 0); 646} 647 648static int 649sbus_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, 650 driver_intr_t *intr, void *arg, void **cookiep) 651{ 652 struct sbus_softc *sc; 653 struct sbus_clr *scl; 654 bus_addr_t intrmapptr, intrclrptr, intrptr; 655 u_int64_t intrmap; 656 u_int32_t inr, slot; 657 int error, i; 658 long vec = rman_get_start(ires); 659 660 sc = device_get_softc(dev); 661 scl = (struct sbus_clr *)malloc(sizeof(*scl), M_DEVBUF, M_NOWAIT); 662 if (scl == NULL) 663 return (0); 664 intrptr = intrmapptr = intrclrptr = 0; 665 intrmap = 0; 666 inr = INTVEC(vec); 667 if ((inr & INTMAP_OBIO_MASK) == 0) { 668 /* 669 * We're in an SBus slot, register the map and clear 670 * intr registers. 671 */ 672 slot = INTSLOT(vec); 673 intrmapptr = SBR_SLOT0_INT_MAP + slot * 8; 674 intrclrptr = SBR_SLOT0_INT_CLR + 675 (slot * 8 * 8) + (INTPRI(vec) * 8); 676 /* Enable the interrupt, insert IGN. */ 677 intrmap = inr | (sc->sc_ign << INTMAP_IGN_SHIFT); 678 } else { 679 intrptr = SBR_SCSI_INT_MAP; 680 /* Insert IGN */ 681 inr |= sc->sc_ign << INTMAP_IGN_SHIFT; 682 for (i = 0; intrptr <= SBR_RESERVED_INT_MAP && 683 INTVEC(intrmap = SYSIO_READ8(sc, intrptr)) != 684 INTVEC(inr); intrptr += 8, i++) 685 ; 686 if (INTVEC(intrmap) == INTVEC(inr)) { 687 /* Register the map and clear intr registers */ 688 intrmapptr = intrptr; 689 intrclrptr = SBR_SCSI_INT_CLR + i * 8; 690 /* Enable the interrupt */ 691 } else 692 panic("%s: IRQ not found!", __func__); 693 } 694 695 scl->scl_sc = sc; 696 scl->scl_arg = arg; 697 scl->scl_handler = intr; 698 scl->scl_clr = intrclrptr; 699 /* Disable the interrupt while we fiddle with it */ 700 SYSIO_WRITE8(sc, intrmapptr, intrmap); 701 error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, 702 sbus_intr_stub, scl, cookiep); 703 if (error != 0) { 704 free(scl, M_DEVBUF); 705 return (error); 706 } 707 scl->scl_cookie = *cookiep; 708 *cookiep = scl; 709 710 /* 711 * Clear the interrupt, it might have been triggered before it was 712 * set up. 713 */ 714 SYSIO_WRITE8(sc, intrclrptr, 0); 715 /* 716 * Enable the interrupt and program the target module now we have the 717 * handler installed. 718 */ 719 SYSIO_WRITE8(sc, intrmapptr, INTMAP_ENABLE(intrmap, PCPU_GET(mid))); 720 return (error); 721} 722 723static int 724sbus_teardown_intr(device_t dev, device_t child, struct resource *vec, 725 void *cookie) 726{ 727 struct sbus_clr *scl; 728 int error; 729 730 scl = (struct sbus_clr *)cookie; 731 error = BUS_TEARDOWN_INTR(device_get_parent(dev), child, vec, 732 scl->scl_cookie); 733 /* 734 * Don't disable the interrupt for now, so that stray interrupts get 735 * detected... 736 */ 737 if (error != 0) 738 free(scl, M_DEVBUF); 739 return (error); 740} 741 742static struct resource * 743sbus_alloc_resource(device_t bus, device_t child, int type, int *rid, 744 u_long start, u_long end, u_long count, u_int flags) 745{ 746 struct sbus_softc *sc; 747 struct rman *rm; 748 struct resource *rv; 749 struct resource_list *rl; 750 struct resource_list_entry *rle; 751 device_t schild; 752 bus_space_handle_t bh; 753 bus_addr_t toffs; 754 bus_size_t tend; 755 int i, slot; 756 int isdefault, needactivate, passthrough; 757 758 isdefault = (start == 0UL && end == ~0UL); 759 needactivate = flags & RF_ACTIVE; 760 passthrough = (device_get_parent(child) != bus); 761 rle = NULL; 762 sc = device_get_softc(bus); 763 rl = BUS_GET_RESOURCE_LIST(bus, child); 764 switch (type) { 765 case SYS_RES_IRQ: 766 return (resource_list_alloc(rl, bus, child, type, rid, start, 767 end, count, flags)); 768 case SYS_RES_MEMORY: 769 if (!passthrough) { 770 rle = resource_list_find(rl, type, *rid); 771 if (rle == NULL) 772 return (NULL); 773 if (rle->res != NULL) 774 panic("%s: resource entry is busy", __func__); 775 if (isdefault) { 776 start = rle->start; 777 count = ulmax(count, rle->count); 778 end = ulmax(rle->end, start + count - 1); 779 } 780 } 781 rm = NULL; 782 bh = toffs = tend = 0; 783 schild = child; 784 while (device_get_parent(schild) != bus) 785 schild = device_get_parent(child); 786 slot = sbus_get_slot(schild); 787 for (i = 0; i < sc->sc_nrange; i++) { 788 if (sc->sc_rd[i].rd_slot != slot || 789 start < sc->sc_rd[i].rd_coffset || 790 start > sc->sc_rd[i].rd_cend) 791 continue; 792 /* Disallow cross-range allocations. */ 793 if (end > sc->sc_rd[i].rd_cend) 794 return (NULL); 795 /* We've found the connection to the parent bus */ 796 toffs = start - sc->sc_rd[i].rd_coffset; 797 tend = end - sc->sc_rd[i].rd_coffset; 798 rm = &sc->sc_rd[i].rd_rman; 799 bh = sc->sc_rd[i].rd_bushandle; 800 } 801 if (toffs == 0L) 802 return (NULL); 803 flags &= ~RF_ACTIVE; 804 rv = rman_reserve_resource(rm, toffs, tend, count, flags, 805 child); 806 if (rv == NULL) 807 return (NULL); 808 rman_set_rid(rv, *rid); 809 rman_set_bustag(rv, sc->sc_cbustag); 810 rman_set_bushandle(rv, bh + rman_get_start(rv)); 811 if (needactivate) { 812 if (bus_activate_resource(child, type, *rid, rv)) { 813 rman_release_resource(rv); 814 return (NULL); 815 } 816 } 817 if (!passthrough) 818 rle->res = rv; 819 return (rv); 820 default: 821 return (NULL); 822 } 823} 824 825static int 826sbus_activate_resource(device_t bus, device_t child, int type, int rid, 827 struct resource *r) 828{ 829 830 if (type == SYS_RES_IRQ) { 831 return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), 832 child, type, rid, r)); 833 } 834 return (rman_activate_resource(r)); 835} 836 837static int 838sbus_deactivate_resource(device_t bus, device_t child, int type, int rid, 839 struct resource *r) 840{ 841 842 if (type == SYS_RES_IRQ) { 843 return (BUS_DEACTIVATE_RESOURCE(device_get_parent(bus), 844 child, type, rid, r)); 845 } 846 return (rman_deactivate_resource(r)); 847} 848 849static int 850sbus_release_resource(device_t bus, device_t child, int type, int rid, 851 struct resource *r) 852{ 853 struct resource_list *rl; 854 struct resource_list_entry *rle; 855 int error, passthrough; 856 857 passthrough = (device_get_parent(child) != bus); 858 rl = BUS_GET_RESOURCE_LIST(bus, child); 859 if (type == SYS_RES_IRQ) 860 return (resource_list_release(rl, bus, child, type, rid, r)); 861 if ((rman_get_flags(r) & RF_ACTIVE) != 0) { 862 error = bus_deactivate_resource(child, type, rid, r); 863 if (error != 0) 864 return (error); 865 } 866 error = rman_release_resource(r); 867 if (error != 0 || passthrough) 868 return (error); 869 rle = resource_list_find(rl, type, rid); 870 if (rle == NULL) 871 panic("%s: cannot find resource", __func__); 872 if (rle->res == NULL) 873 panic("%s: resource entry is not busy", __func__); 874 rle->res = NULL; 875 return (0); 876} 877 878static const struct ofw_bus_devinfo * 879sbus_get_devinfo(device_t bus, device_t child) 880{ 881 struct sbus_devinfo *sdi; 882 883 sdi = device_get_ivars(child); 884 return (&sdi->sdi_obdinfo); 885} 886 887/* 888 * Handle an overtemp situation. 889 * 890 * SPARCs have temperature sensors which generate interrupts 891 * if the machine's temperature exceeds a certain threshold. 892 * This handles the interrupt and powers off the machine. 893 * The same needs to be done to PCI controller drivers. 894 */ 895static void 896sbus_overtemp(void *arg) 897{ 898 899 printf("DANGER: OVER TEMPERATURE detected\nShutting down NOW.\n"); 900 shutdown_nice(RB_POWEROFF); 901} 902 903/* Try to shut down in time in case of power failure. */ 904static void 905sbus_pwrfail(void *arg) 906{ 907 908 printf("Power failure detected\nShutting down NOW.\n"); 909 shutdown_nice(0); 910} 911 912static bus_space_tag_t 913sbus_alloc_bustag(struct sbus_softc *sc) 914{ 915 bus_space_tag_t sbt; 916 917 sbt = (bus_space_tag_t)malloc(sizeof(struct bus_space_tag), M_DEVBUF, 918 M_NOWAIT | M_ZERO); 919 if (sbt == NULL) 920 panic("%s: out of memory", __func__); 921 922 sbt->bst_cookie = sc; 923 sbt->bst_parent = sc->sc_bustag; 924 sbt->bst_type = SBUS_BUS_SPACE; 925 return (sbt); 926} 927 928static int 929sbus_print_res(struct sbus_devinfo *sdi) 930{ 931 int rv; 932 933 rv = 0; 934 rv += resource_list_print_type(&sdi->sdi_rl, "mem", SYS_RES_MEMORY, 935 "%#lx"); 936 rv += resource_list_print_type(&sdi->sdi_rl, "irq", SYS_RES_IRQ, 937 "%ld"); 938 return (rv); 939} 940