1 /* 2 * Copyright 1998 Massachusetts Institute of Technology 3 * Copyright (c) 2008 The DragonFly Project. 4 * 5 * Permission to use, copy, modify, and distribute this software and 6 * its documentation for any purpose and without fee is hereby 7 * granted, provided that both the above copyright notice and this 8 * permission notice appear in all copies, that both the above 9 * copyright notice and this permission notice appear in all 10 * supporting documentation, and that the name of M.I.T. not be used 11 * in advertising or publicity pertaining to distribution of the 12 * software without specific, written prior permission. M.I.T. makes 13 * no representations about the suitability of this software for any 14 * purpose. It is provided "as is" without express or implied 15 * warranty. 16 * 17 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 18 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 19 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 21 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 24 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD: src/sys/i386/i386/nexus.c,v 1.26.2.10 2003/02/22 13:16:45 imp Exp $ 31 */ 32 33 /* 34 * This code implements a `root nexus' for Intel Architecture 35 * machines. The function of the root nexus is to serve as an 36 * attachment point for both processors and buses, and to manage 37 * resources which are common to all of them. In particular, 38 * this code implements the core resource managers for interrupt 39 * requests, DMA requests (which rightfully should be a part of the 40 * ISA code but it's easier to do it here for now), I/O port addresses, 41 * and I/O memory address space. 42 */ 43 44 #include "use_pci.h" 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/bus.h> 49 #include <sys/kernel.h> 50 #include <sys/malloc.h> 51 #include <sys/module.h> 52 #include <sys/rman.h> 53 #include <sys/interrupt.h> 54 #include <sys/machintr.h> 55 #include <sys/linker.h> 56 57 #include <machine/vmparam.h> 58 #include <vm/vm.h> 59 #include <vm/pmap.h> 60 #include <machine/pmap.h> 61 62 #include <machine/nexusvar.h> 63 #include <machine/smp.h> 64 #include <machine/intr_machdep.h> 65 #include <machine_base/apic/lapic.h> 66 #include <machine_base/apic/ioapic.h> 67 #include <machine/pc/bios.h> 68 #include <machine/metadata.h> 69 70 #if NPCI > 0 71 #include "pcib_if.h" 72 #endif 73 74 #define ELF_KERN_STR ("elf"__XSTRING(__ELF_WORD_SIZE)" kernel") 75 76 static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device"); 77 struct nexus_device { 78 struct resource_list nx_resources; 79 int nx_pcibus; 80 }; 81 82 #define DEVTONX(dev) ((struct nexus_device *)device_get_ivars(dev)) 83 84 static struct rman irq_rman[MAXCPU], drq_rman, port_rman, mem_rman; 85 86 static int nexus_probe(device_t); 87 static int nexus_attach(device_t); 88 static int nexus_print_all_resources(device_t dev); 89 static int nexus_print_child(device_t, device_t); 90 static device_t nexus_add_child(device_t bus, device_t parent, int order, 91 const char *name, int unit); 92 static struct resource *nexus_alloc_resource(device_t, device_t, int, int *, 93 u_long, u_long, u_long, u_int, int); 94 static int nexus_read_ivar(device_t, device_t, int, uintptr_t *); 95 static int nexus_write_ivar(device_t, device_t, int, uintptr_t); 96 static int nexus_activate_resource(device_t, device_t, int, int, 97 struct resource *); 98 static int nexus_deactivate_resource(device_t, device_t, int, int, 99 struct resource *); 100 static int nexus_release_resource(device_t, device_t, int, int, 101 struct resource *); 102 static int nexus_config_intr(device_t, device_t, int, enum intr_trigger, 103 enum intr_polarity); 104 static int nexus_setup_intr(device_t, device_t, struct resource *, int flags, 105 void (*)(void *), void *, void **, lwkt_serialize_t, 106 const char *); 107 static int nexus_teardown_intr(device_t, device_t, struct resource *, 108 void *); 109 static int nexus_set_resource(device_t, device_t, int, int, u_long, u_long, 110 int); 111 static int nexus_get_resource(device_t, device_t, int, int, u_long *, u_long *); 112 static void nexus_delete_resource(device_t, device_t, int, int); 113 114 #if NPCI > 0 115 static int nexus_alloc_msi(device_t, device_t, int, int, int *, int); 116 static int nexus_release_msi(device_t, device_t, int, int *, int); 117 static int nexus_map_msi(device_t, device_t, int, uint64_t *, uint32_t *, int); 118 static int nexus_alloc_msix(device_t, device_t, int *, int); 119 static int nexus_release_msix(device_t, device_t, int, int); 120 #endif 121 122 /* 123 * The device_identify method will cause nexus to automatically associate 124 * and attach to the root bus. 125 */ 126 static device_method_t nexus_methods[] = { 127 /* Device interface */ 128 DEVMETHOD(device_identify, bus_generic_identify), 129 DEVMETHOD(device_probe, nexus_probe), 130 DEVMETHOD(device_attach, nexus_attach), 131 DEVMETHOD(device_detach, bus_generic_detach), 132 DEVMETHOD(device_shutdown, bus_generic_shutdown), 133 DEVMETHOD(device_suspend, bus_generic_suspend), 134 DEVMETHOD(device_resume, bus_generic_resume), 135 136 /* Bus interface */ 137 DEVMETHOD(bus_print_child, nexus_print_child), 138 DEVMETHOD(bus_add_child, nexus_add_child), 139 DEVMETHOD(bus_read_ivar, nexus_read_ivar), 140 DEVMETHOD(bus_write_ivar, nexus_write_ivar), 141 DEVMETHOD(bus_alloc_resource, nexus_alloc_resource), 142 DEVMETHOD(bus_release_resource, nexus_release_resource), 143 DEVMETHOD(bus_activate_resource, nexus_activate_resource), 144 DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource), 145 DEVMETHOD(bus_config_intr, nexus_config_intr), 146 DEVMETHOD(bus_setup_intr, nexus_setup_intr), 147 DEVMETHOD(bus_teardown_intr, nexus_teardown_intr), 148 DEVMETHOD(bus_set_resource, nexus_set_resource), 149 DEVMETHOD(bus_get_resource, nexus_get_resource), 150 DEVMETHOD(bus_delete_resource, nexus_delete_resource), 151 152 #if NPCI > 0 153 DEVMETHOD(pcib_alloc_msi, nexus_alloc_msi), 154 DEVMETHOD(pcib_release_msi, nexus_release_msi), 155 DEVMETHOD(pcib_map_msi, nexus_map_msi), 156 DEVMETHOD(pcib_alloc_msix, nexus_alloc_msix), 157 DEVMETHOD(pcib_release_msix, nexus_release_msix), 158 #endif 159 160 DEVMETHOD_END 161 }; 162 163 static driver_t nexus_driver = { 164 "nexus", 165 nexus_methods, 166 1, /* no softc */ 167 }; 168 static devclass_t nexus_devclass; 169 170 DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, NULL, NULL); 171 172 static int 173 nexus_probe(device_t dev) 174 { 175 int cpuid; 176 177 device_quiet(dev); /* suppress attach message for neatness */ 178 179 for (cpuid = 0; cpuid < ncpus; ++cpuid) { 180 struct rman *rm = &irq_rman[cpuid]; 181 182 rm->rm_start = 0; 183 rm->rm_end = IDT_HWI_VECTORS - 1; 184 rm->rm_type = RMAN_ARRAY; 185 rm->rm_descr = "Interrupt request lines"; 186 187 if (rman_init(rm, cpuid)) 188 panic("%s rman_init", __func__); 189 MachIntrABI.rman_setup(rm); 190 } 191 192 /* 193 * ISA DMA on PCI systems is implemented in the ISA part of each 194 * PCI->ISA bridge and the channels can be duplicated if there are 195 * multiple bridges. (eg: laptops with docking stations) 196 */ 197 drq_rman.rm_start = 0; 198 drq_rman.rm_end = 7; 199 drq_rman.rm_type = RMAN_ARRAY; 200 drq_rman.rm_descr = "DMA request lines"; 201 /* XXX drq 0 not available on some machines */ 202 if (rman_init(&drq_rman, -1) 203 || rman_manage_region(&drq_rman, 204 drq_rman.rm_start, drq_rman.rm_end)) 205 panic("%s drq_rman", __func__); 206 207 /* 208 * However, IO ports and Memory truely are global at this level, 209 * as are APIC interrupts (however many IO APICS there turn out 210 * to be on large systems..) 211 */ 212 port_rman.rm_start = 0; 213 port_rman.rm_end = 0xffff; 214 port_rman.rm_type = RMAN_ARRAY; 215 port_rman.rm_descr = "I/O ports"; 216 if (rman_init(&port_rman, -1) 217 || rman_manage_region(&port_rman, 0, 0xffff)) 218 panic("%s port_rman", __func__); 219 220 mem_rman.rm_start = 0; 221 mem_rman.rm_end = ~0u; 222 mem_rman.rm_type = RMAN_ARRAY; 223 mem_rman.rm_descr = "I/O memory addresses"; 224 if (rman_init(&mem_rman, -1) 225 || rman_manage_region(&mem_rman, 0, ~0)) 226 panic("%s mem_rman", __func__); 227 228 return bus_generic_probe(dev); 229 } 230 231 static int 232 nexus_attach(device_t dev) 233 { 234 device_t child; 235 236 /* 237 * First, let our child driver's identify any child devices that 238 * they can find. Once that is done attach any devices that we 239 * found. 240 */ 241 #if 0 /* FUTURE */ 242 bus_generic_probe(dev); 243 #endif 244 bus_generic_attach(dev); 245 246 /* 247 * And if we didn't see ISA on a pci bridge, create a 248 * connection point now so it shows up "on motherboard". 249 */ 250 if (!devclass_get_device(devclass_find("isa"), 0)) { 251 child = BUS_ADD_CHILD(dev, dev, 0, "isa", 0); 252 if (child == NULL) 253 panic("%s isa", __func__); 254 device_probe_and_attach(child); 255 } 256 257 return 0; 258 } 259 260 static int 261 nexus_print_all_resources(device_t dev) 262 { 263 struct nexus_device *ndev = DEVTONX(dev); 264 struct resource_list *rl = &ndev->nx_resources; 265 int retval = 0; 266 267 if (SLIST_FIRST(rl) || ndev->nx_pcibus != -1) 268 retval += kprintf(" at"); 269 270 retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx"); 271 retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx"); 272 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 273 274 return retval; 275 } 276 277 static int 278 nexus_print_child(device_t bus, device_t child) 279 { 280 struct nexus_device *ndev = DEVTONX(child); 281 int retval = 0; 282 283 retval += bus_print_child_header(bus, child); 284 retval += nexus_print_all_resources(child); 285 if (ndev->nx_pcibus != -1) 286 retval += kprintf(" pcibus %d", ndev->nx_pcibus); 287 retval += kprintf(" on motherboard\n"); 288 289 return (retval); 290 } 291 292 static device_t 293 nexus_add_child(device_t bus, device_t parent, int order, 294 const char *name, int unit) 295 { 296 device_t child; 297 struct nexus_device *ndev; 298 299 ndev = kmalloc(sizeof(struct nexus_device), M_NEXUSDEV, M_INTWAIT|M_ZERO); 300 resource_list_init(&ndev->nx_resources); 301 ndev->nx_pcibus = -1; 302 303 child = device_add_child_ordered(parent, order, name, unit); 304 305 /* should we free this in nexus_child_detached? */ 306 device_set_ivars(child, ndev); 307 308 return(child); 309 } 310 311 static int 312 nexus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 313 { 314 struct nexus_device *ndev = DEVTONX(child); 315 316 switch (which) { 317 case NEXUS_IVAR_PCIBUS: 318 *result = ndev->nx_pcibus; 319 break; 320 default: 321 return ENOENT; 322 } 323 return 0; 324 } 325 326 static int 327 nexus_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 328 { 329 struct nexus_device *ndev = DEVTONX(child); 330 331 switch (which) { 332 case NEXUS_IVAR_PCIBUS: 333 ndev->nx_pcibus = value; 334 break; 335 default: 336 return ENOENT; 337 } 338 return 0; 339 } 340 341 /* 342 * Allocate a resource on behalf of child. NB: child is usually going to be a 343 * child of one of our descendants, not a direct child of nexus0. 344 * (Exceptions include npx.) 345 */ 346 static struct resource * 347 nexus_alloc_resource(device_t bus, device_t child, int type, int *rid, 348 u_long start, u_long end, u_long count, u_int flags, int cpuid) 349 { 350 struct nexus_device *ndev = DEVTONX(child); 351 struct resource *rv; 352 struct resource_list_entry *rle; 353 struct rman *rm; 354 int needactivate = flags & RF_ACTIVE; 355 356 /* 357 * If this is an allocation of the "default" range for a given RID, and 358 * we know what the resources for this device are (ie. they aren't maintained 359 * by a child bus), then work out the start/end values. 360 */ 361 if ((start == 0UL) && (end == ~0UL) && (count == 1)) { 362 if (ndev == NULL) 363 return(NULL); 364 rle = resource_list_find(&ndev->nx_resources, type, *rid); 365 if (rle == NULL) 366 return(NULL); 367 start = rle->start; 368 end = rle->end; 369 count = rle->count; 370 cpuid = rle->cpuid; 371 } 372 373 flags &= ~RF_ACTIVE; 374 375 switch (type) { 376 case SYS_RES_IRQ: 377 KASSERT(cpuid >= 0 && cpuid < ncpus, 378 ("nexus invalid cpuid: %d", cpuid)); 379 rm = &irq_rman[cpuid]; 380 break; 381 382 case SYS_RES_DRQ: 383 rm = &drq_rman; 384 break; 385 386 case SYS_RES_IOPORT: 387 rm = &port_rman; 388 break; 389 390 case SYS_RES_MEMORY: 391 rm = &mem_rman; 392 break; 393 394 default: 395 return 0; 396 } 397 398 rv = rman_reserve_resource(rm, start, end, count, flags, child); 399 if (rv == NULL) 400 return 0; 401 rman_set_rid(rv, *rid); 402 403 if (type == SYS_RES_MEMORY) { 404 rman_set_bustag(rv, X86_64_BUS_SPACE_MEM); 405 } else if (type == SYS_RES_IOPORT) { 406 rman_set_bustag(rv, X86_64_BUS_SPACE_IO); 407 rman_set_bushandle(rv, rv->r_start); 408 } 409 410 if (needactivate) { 411 if (bus_activate_resource(child, type, *rid, rv)) { 412 rman_release_resource(rv); 413 return 0; 414 } 415 } 416 417 return rv; 418 } 419 420 static int 421 nexus_activate_resource(device_t bus, device_t child, int type, int rid, 422 struct resource *r) 423 { 424 /* 425 * If this is a memory resource, map it into the kernel. 426 */ 427 if (rman_get_bustag(r) == X86_64_BUS_SPACE_MEM) { 428 caddr_t vaddr = 0; 429 430 if (rman_get_end(r) < 1024 * 1024) { 431 /* 432 * The first 1Mb is mapped at KERNBASE. 433 */ 434 vaddr = (caddr_t)(uintptr_t)(KERNBASE + rman_get_start(r)); 435 } else { 436 u_int64_t paddr; 437 u_int64_t psize; 438 u_int32_t poffs; 439 440 paddr = rman_get_start(r); 441 psize = rman_get_size(r); 442 443 poffs = paddr - trunc_page(paddr); 444 vaddr = (caddr_t) pmap_mapdev(paddr-poffs, psize+poffs) + poffs; 445 } 446 rman_set_virtual(r, vaddr); 447 /* IBM-PC: the type of bus_space_handle_t is u_int */ 448 rman_set_bushandle(r, (bus_space_handle_t) vaddr); 449 } 450 return (rman_activate_resource(r)); 451 } 452 453 static int 454 nexus_deactivate_resource(device_t bus, device_t child, int type, int rid, 455 struct resource *r) 456 { 457 /* 458 * If this is a memory resource, unmap it. 459 */ 460 if ((rman_get_bustag(r) == X86_64_BUS_SPACE_MEM) && 461 (rman_get_end(r) >= 1024 * 1024)) { 462 u_int32_t psize; 463 464 psize = rman_get_size(r); 465 pmap_unmapdev((vm_offset_t)rman_get_virtual(r), psize); 466 } 467 468 return (rman_deactivate_resource(r)); 469 } 470 471 static int 472 nexus_release_resource(device_t bus, device_t child, int type, int rid, 473 struct resource *r) 474 { 475 if (rman_get_flags(r) & RF_ACTIVE) { 476 int error = bus_deactivate_resource(child, type, rid, r); 477 if (error) 478 return error; 479 } 480 return (rman_release_resource(r)); 481 } 482 483 static int 484 nexus_config_intr(device_t bus, device_t chile, int irq, 485 enum intr_trigger trig, enum intr_polarity pola) 486 { 487 machintr_legacy_intr_config(irq, trig, pola); 488 return 0; 489 } 490 491 /* 492 * Currently this uses the really grody interface from kern/kern_intr.c 493 * (which really doesn't belong in kern/anything.c). Eventually, all of 494 * the code in kern_intr.c and machdep_intr.c should get moved here, since 495 * this is going to be the official interface. 496 */ 497 static int 498 nexus_setup_intr(device_t bus, device_t child, struct resource *irq, 499 int flags, void (*ihand)(void *), void *arg, void **cookiep, 500 lwkt_serialize_t serializer, const char *desc) 501 { 502 int error, icflags; 503 504 /* somebody tried to setup an irq that failed to allocate! */ 505 if (irq == NULL) 506 panic("%s: NULL irq resource!", __func__); 507 508 *cookiep = NULL; 509 icflags = flags; 510 if ((irq->r_flags & RF_SHAREABLE) == 0) 511 icflags |= INTR_EXCL; 512 513 /* 514 * We depend here on rman_activate_resource() being idempotent. 515 */ 516 error = rman_activate_resource(irq); 517 if (error) 518 return (error); 519 520 /* Use device name, if description is not specified */ 521 if (desc == NULL) 522 desc = device_get_nameunit(child); 523 524 /* 525 * XXX cast the interrupt handler function to an inthand2_t. The 526 * difference is that an additional frame argument is passed which 527 * we do not currently want to expose the BUS subsystem to. 528 */ 529 *cookiep = register_int(irq->r_start, (inthand2_t *)ihand, arg, 530 desc, serializer, icflags, rman_get_cpuid(irq)); 531 if (*cookiep == NULL) 532 error = EINVAL; 533 return (error); 534 } 535 536 static int 537 nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih) 538 { 539 if (ih) { 540 unregister_int(ih, rman_get_cpuid(r)); 541 return (0); 542 } 543 return(-1); 544 } 545 546 static int 547 nexus_set_resource(device_t dev, device_t child, int type, int rid, 548 u_long start, u_long count, int cpuid) 549 { 550 struct nexus_device *ndev = DEVTONX(child); 551 struct resource_list *rl = &ndev->nx_resources; 552 553 /* XXX this should return a success/failure indicator */ 554 resource_list_add(rl, type, rid, start, start + count - 1, count, 555 cpuid); 556 return(0); 557 } 558 559 static int 560 nexus_get_resource(device_t dev, device_t child, int type, int rid, u_long *startp, u_long *countp) 561 { 562 struct nexus_device *ndev = DEVTONX(child); 563 struct resource_list *rl = &ndev->nx_resources; 564 struct resource_list_entry *rle; 565 566 rle = resource_list_find(rl, type, rid); 567 device_printf(child, "type %d rid %d startp %p countp %p - got %p\n", 568 type, rid, startp, countp, rle); 569 if (!rle) 570 return(ENOENT); 571 if (startp) 572 *startp = rle->start; 573 if (countp) 574 *countp = rle->count; 575 return(0); 576 } 577 578 static void 579 nexus_delete_resource(device_t dev, device_t child, int type, int rid) 580 { 581 struct nexus_device *ndev = DEVTONX(child); 582 struct resource_list *rl = &ndev->nx_resources; 583 584 resource_list_delete(rl, type, rid); 585 } 586 587 #if NPCI > 0 588 static int 589 nexus_alloc_msi(device_t dev, device_t child, int count, int maxcount, 590 int *irqs, int cpuid) 591 { 592 if (!lapic_enable) 593 return ENODEV; 594 595 return MachIntrABI.msi_alloc(irqs, count, cpuid); 596 } 597 598 static int 599 nexus_release_msi(device_t dev, device_t child, int count, int *irqs, int cpuid) 600 { 601 KKASSERT(lapic_enable); 602 MachIntrABI.msi_release(irqs, count, cpuid); 603 return 0; 604 } 605 606 static int 607 nexus_map_msi(device_t dev, device_t child, int irq, uint64_t *addr, 608 uint32_t *data, int cpuid) 609 { 610 KKASSERT(lapic_enable); 611 MachIntrABI.msi_map(irq, addr, data, cpuid); 612 return 0; 613 } 614 615 static int 616 nexus_alloc_msix(device_t dev, device_t child, int *irq, int cpuid) 617 { 618 if (!lapic_enable) 619 return ENODEV; 620 621 return MachIntrABI.msix_alloc(irq, cpuid); 622 } 623 624 static int 625 nexus_release_msix(device_t dev, device_t child, int irq, int cpuid) 626 { 627 KKASSERT(lapic_enable); 628 MachIntrABI.msix_release(irq, cpuid); 629 return 0; 630 } 631 #endif 632 633 /* Placeholder for system RAM. */ 634 static void 635 ram_identify(driver_t *driver, device_t parent) 636 { 637 if (resource_disabled("ram", 0)) 638 return; 639 if (BUS_ADD_CHILD(parent, parent, 0, "ram", 0) == NULL) 640 panic("%s", __func__); 641 } 642 643 static int 644 ram_probe(device_t dev) 645 { 646 device_quiet(dev); 647 device_set_desc(dev, "System RAM"); 648 return (0); 649 } 650 651 static int 652 ram_attach(device_t dev) 653 { 654 struct bios_smap *smapbase, *smap, *smapend; 655 struct resource *res; 656 vm_phystable_t *p; 657 caddr_t kmdp; 658 uint32_t smapsize; 659 int error, rid; 660 661 device_quiet(dev); 662 device_set_desc(dev, "System RAM"); 663 664 /* Retrieve the system memory map from the loader. */ 665 kmdp = preload_search_by_type("elf kernel"); 666 if (kmdp == NULL) 667 kmdp = preload_search_by_type(ELF_KERN_STR); 668 if (kmdp != NULL) 669 smapbase = (struct bios_smap *)preload_search_info(kmdp, 670 MODINFO_METADATA | MODINFOMD_SMAP); 671 else 672 smapbase = NULL; 673 if (smapbase != NULL) { 674 smapsize = *((u_int32_t *)smapbase - 1); 675 smapend = (struct bios_smap *)((uintptr_t)smapbase + smapsize); 676 677 rid = 0; 678 for (smap = smapbase; smap < smapend; smap++) { 679 if (smap->type != SMAP_TYPE_MEMORY || 680 smap->length == 0) 681 continue; 682 error = bus_set_resource(dev, SYS_RES_MEMORY, rid, 683 smap->base, smap->length, -1); 684 if (error) 685 panic("%s: resource %d failed set with %d", 686 __func__, rid, error); 687 res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 688 0); 689 if (res == NULL) { 690 panic("%s: resource %d failed to " 691 "attach 0x%016jx/%jd", 692 __func__, rid, 693 (intmax_t)smap->base, 694 (intmax_t)smap->length); 695 } 696 rid++; 697 } 698 return (0); 699 } 700 701 /* 702 * If the system map is not available, fall back to using 703 * dump_avail[]. We use the dump_avail[] array rather than 704 * phys_avail[] for the memory map as phys_avail[] contains 705 * holes for kernel memory, page 0, the message buffer, and 706 * the dcons buffer. We test the end address in the loop 707 * instead of the start since the start address for the first 708 * segment is 0. 709 */ 710 for (rid = 0, p = &dump_avail[0]; p->phys_end; ++rid, ++p) { 711 error = bus_set_resource(dev, SYS_RES_MEMORY, rid, 712 p->phys_beg, 713 p->phys_end - p->phys_beg, 714 -1); 715 if (error) 716 panic("%s: resource %d failed set with %d", __func__, 717 rid, error); 718 res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 0); 719 if (res == NULL) 720 panic("%s: resource %d failed to attach", __func__, 721 rid); 722 } 723 return (0); 724 } 725 static device_method_t ram_methods[] = { 726 /* Device interface */ 727 DEVMETHOD(device_identify, ram_identify), 728 DEVMETHOD(device_probe, ram_probe), 729 DEVMETHOD(device_attach, ram_attach), 730 { 0, 0 } 731 }; 732 733 static driver_t ram_driver = { 734 "ram", 735 ram_methods, 736 1, /* no softc */ 737 }; 738 739 static devclass_t ram_devclass; 740 DRIVER_MODULE(ram, nexus, ram_driver, ram_devclass, NULL, NULL); 741