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