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 --- 84 unchanged lines hidden (view full) --- 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 152684 2005-11-22 16:39:44Z marius $"); |
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> --- 6 unchanged lines hidden (view full) --- 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; --- 47 unchanged lines hidden (view full) --- 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 223 /* Bus interface */ 224 DEVMETHOD(bus_print_child, sbus_print_child), --- 4 unchanged lines hidden (view full) --- 229 DEVMETHOD(bus_alloc_resource, sbus_alloc_resource), 230 DEVMETHOD(bus_activate_resource, sbus_activate_resource), 231 DEVMETHOD(bus_deactivate_resource, sbus_deactivate_resource), 232 DEVMETHOD(bus_release_resource, sbus_release_resource), 233 DEVMETHOD(bus_get_resource_list, sbus_get_resource_list), 234 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 235 236 /* ofw_bus interface */ |
237 DEVMETHOD(ofw_bus_get_devinfo, sbus_get_devinfo), 238 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 239 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 240 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 241 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 242 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), |
243 244 { 0, 0 } 245}; 246 247static driver_t sbus_driver = { 248 "sbus", 249 sbus_methods, 250 sizeof(struct sbus_softc), --- 44 unchanged lines hidden (view full) --- 295{ 296 struct sbus_softc *sc; 297 struct sbus_devinfo *sdi; 298 struct sbus_ranges *range; 299 struct resource *res; 300 device_t cdev; 301 bus_addr_t phys; 302 bus_size_t size; |
303 char *name; |
304 phandle_t child, node; 305 u_int64_t mr; 306 int intr, clock, rid, vec, i; 307 308 sc = device_get_softc(dev); 309 node = nexus_get_node(dev); 310 311 if ((sc->sc_nreg = OF_getprop_alloc(node, "reg", sizeof(*sc->sc_reg), --- 134 unchanged lines hidden (view full) --- 446 /* Initialize the counter-timer. */ 447 sparc64_counter_init(sc->sc_bustag, sc->sc_bushandle, SBR_TC0); 448 449 /* 450 * Loop through ROM children, fixing any relative addresses 451 * and then configuring each device. 452 */ 453 for (child = OF_child(node); child != 0; child = OF_peer(child)) { |
454 if ((sdi = sbus_setup_dinfo(dev, sc, child)) == NULL) |
455 continue; |
456 /* 457 * For devices where there are variants that are actually 458 * split into two SBus devices (as opposed to the first 459 * half of the device being a SBus device and the second 460 * half hanging off of the first one) like 'auxio' and 461 * 'SUNW,fdtwo' or 'dma' and 'esp' probe the SBus device 462 * which is a prerequisite to the driver attaching to the 463 * second one with a lower order. Saves us from dealing 464 * with different probe orders in the respective device 465 * drivers which generally is more hackish. 466 */ 467 cdev = device_add_child_ordered(dev, (OF_child(child) == 0 && |
468 sbus_inlist(sdi->sdi_obdinfo.obd_name, sbus_order_first)) ? 469 SBUS_ORDER_FIRST : SBUS_ORDER_NORMAL, NULL, -1); 470 if (cdev == NULL) { 471 device_printf(dev, 472 "<%s>: device_add_child_ordered failed\n", 473 sdi->sdi_obdinfo.obd_name); 474 sbus_destroy_dinfo(sdi); 475 continue; 476 } |
477 device_set_ivars(cdev, sdi); 478 } 479 return (bus_generic_attach(dev)); 480} 481 482static struct sbus_devinfo * |
483sbus_setup_dinfo(device_t dev, struct sbus_softc *sc, phandle_t node) |
484{ 485 struct sbus_devinfo *sdi; 486 struct sbus_regs *reg; 487 u_int32_t base, iv, *intr; 488 int i, nreg, nintr, slot, rslot; 489 490 sdi = malloc(sizeof(*sdi), M_DEVBUF, M_ZERO | M_WAITOK); |
491 if (ofw_bus_gen_setup_devinfo(&sdi->sdi_obdinfo, node) != 0) { 492 free(sdi, M_DEVBUF); |
493 return (NULL); |
494 } |
495 resource_list_init(&sdi->sdi_rl); |
496 slot = -1; 497 nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)®); 498 if (nreg == -1) { |
499 if (sdi->sdi_obdinfo.obd_type == NULL || 500 strcmp(sdi->sdi_obdinfo.obd_type, "hierarchical") != 0) { 501 device_printf(dev, "<%s>: incomplete\n", 502 sdi->sdi_obdinfo.obd_name); 503 goto fail; |
504 } 505 } else { 506 for (i = 0; i < nreg; i++) { 507 base = reg[i].sbr_offset; 508 if (SBUS_ABS(base)) { 509 rslot = SBUS_ABS_TO_SLOT(base); 510 base = SBUS_ABS_TO_OFFSET(base); 511 } else 512 rslot = reg[i].sbr_slot; |
513 if (slot != -1 && slot != rslot) { 514 device_printf(dev, "<%s>: multiple slots\n", 515 sdi->sdi_obdinfo.obd_name); 516 free(reg, M_OFWPROP); 517 goto fail; 518 } |
519 slot = rslot; 520 521 resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY, i, 522 base, base + reg[i].sbr_size, reg[i].sbr_size); 523 } 524 free(reg, M_OFWPROP); 525 } 526 sdi->sdi_slot = slot; --- 24 unchanged lines hidden (view full) --- 551 sdi->sdi_burstsz = sc->sc_burst; 552 else 553 sdi->sdi_burstsz &= sc->sc_burst; 554 if (OF_getprop(node, "clock-frequency", &sdi->sdi_clockfreq, 555 sizeof(sdi->sdi_clockfreq)) == -1) 556 sdi->sdi_clockfreq = sc->sc_clockfreq; 557 558 return (sdi); |
559 560fail: 561 sbus_destroy_dinfo(sdi); 562 return (NULL); |
563} 564 |
565static void 566sbus_destroy_dinfo(struct sbus_devinfo *dinfo) 567{ 568 569 resource_list_free(&dinfo->sdi_rl); |
570 ofw_bus_gen_destroy_devinfo(&dinfo->sdi_obdinfo); |
571 free(dinfo, M_DEVBUF); 572} 573 574static int 575sbus_print_child(device_t dev, device_t child) 576{ |
577 int rv; 578 |
579 rv = bus_print_child_header(dev, child); |
580 rv += sbus_print_res(device_get_ivars(child)); |
581 rv += bus_print_child_footer(dev, child); 582 return (rv); 583} 584 585static void 586sbus_probe_nomatch(device_t dev, device_t child) 587{ |
588 const char *type; |
589 |
590 device_printf(dev, "<%s>", ofw_bus_get_name(child)); 591 sbus_print_res(device_get_ivars(child)); 592 type = ofw_bus_get_type(child); |
593 printf(" type %s (no driver attached)\n", |
594 type != NULL ? type : "unknown"); |
595} 596 597static int 598sbus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 599{ 600 struct sbus_softc *sc; 601 struct sbus_devinfo *dinfo; 602 --- 110 unchanged lines hidden (view full) --- 713 * Enable the interrupt and program the target module now we have the 714 * handler installed. 715 */ 716 SYSIO_WRITE8(sc, intrmapptr, INTMAP_ENABLE(intrmap, PCPU_GET(mid))); 717 return (error); 718} 719 720static int |
721sbus_teardown_intr(device_t dev, device_t child, struct resource *vec, 722 void *cookie) |
723{ 724 struct sbus_clr *scl; 725 int error; 726 727 scl = (struct sbus_clr *)cookie; 728 error = BUS_TEARDOWN_INTR(device_get_parent(dev), child, vec, 729 scl->scl_cookie); 730 /* --- 135 unchanged lines hidden (view full) --- 866 if (rle == NULL) 867 panic("%s: cannot find resource", __func__); 868 if (rle->res == NULL) 869 panic("%s: resource entry is not busy", __func__); 870 rle->res = NULL; 871 return (0); 872} 873 |
874static const struct ofw_bus_devinfo * 875sbus_get_devinfo(device_t bus, device_t child) 876{ 877 struct sbus_devinfo *sdi; 878 879 sdi = device_get_ivars(child); 880 return (&sdi->sdi_obdinfo); 881} 882 |
883/* 884 * Handle an overtemp situation. 885 * 886 * SPARCs have temperature sensors which generate interrupts 887 * if the machine's temperature exceeds a certain threshold. 888 * This handles the interrupt and powers off the machine. 889 * The same needs to be done to PCI controller drivers. 890 */ --- 25 unchanged lines hidden (view full) --- 916 panic("%s: out of memory", __func__); 917 918 sbt->bst_cookie = sc; 919 sbt->bst_parent = sc->sc_bustag; 920 sbt->bst_type = SBUS_BUS_SPACE; 921 return (sbt); 922} 923 |
924static int 925sbus_print_res(struct sbus_devinfo *sdi) |
926{ |
927 int rv; |
928 |
929 rv = 0; 930 rv += resource_list_print_type(&sdi->sdi_rl, "mem", SYS_RES_MEMORY, 931 "%#lx"); 932 rv += resource_list_print_type(&sdi->sdi_rl, "irq", SYS_RES_IRQ, 933 "%ld"); 934 return (rv); |
935} |