acpi_resource.c revision 130439
1/*- 2 * Copyright (c) 2000 Michael Smith 3 * Copyright (c) 2000 BSDi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_resource.c 130439 2004-06-13 22:52:30Z njl $"); 30 31#include "opt_acpi.h" 32#include <sys/param.h> 33#include <sys/kernel.h> 34#include <sys/bus.h> 35#include <sys/malloc.h> 36#include <sys/module.h> 37 38#include <machine/bus.h> 39#include <machine/resource.h> 40#include <sys/rman.h> 41 42#include "acpi.h" 43#include <dev/acpica/acpivar.h> 44 45/* Hooks for the ACPI CA debugging infrastructure */ 46#define _COMPONENT ACPI_BUS 47ACPI_MODULE_NAME("RESOURCE") 48 49/* 50 * Fetch a device's resources and associate them with the device. 51 * 52 * Note that it might be nice to also locate ACPI-specific resource items, such 53 * as GPE bits. 54 * 55 * We really need to split the resource-fetching code out from the 56 * resource-parsing code, since we may want to use the parsing 57 * code for _PRS someday. 58 */ 59ACPI_STATUS 60acpi_parse_resources(device_t dev, ACPI_HANDLE handle, 61 struct acpi_parse_resource_set *set, void *arg) 62{ 63 ACPI_BUFFER buf; 64 ACPI_RESOURCE *res; 65 char *curr, *last; 66 ACPI_STATUS status; 67 void *context; 68 69 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 70 71 /* 72 * Special-case some devices that abuse _PRS/_CRS to mean 73 * something other than "I consume this resource". 74 * 75 * XXX do we really need this? It's only relevant once 76 * we start always-allocating these resources, and even 77 * then, the only special-cased device is likely to be 78 * the PCI interrupt link. 79 */ 80 81 /* Fetch the device's current resources. */ 82 buf.Length = ACPI_ALLOCATE_BUFFER; 83 if (ACPI_FAILURE((status = AcpiGetCurrentResources(handle, &buf)))) { 84 if (status != AE_NOT_FOUND) 85 printf("can't fetch resources for %s - %s\n", 86 acpi_name(handle), AcpiFormatException(status)); 87 return_ACPI_STATUS (status); 88 } 89 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s - got %ld bytes of resources\n", 90 acpi_name(handle), (long)buf.Length)); 91 set->set_init(dev, arg, &context); 92 93 /* Iterate through the resources */ 94 curr = buf.Pointer; 95 last = (char *)buf.Pointer + buf.Length; 96 while (curr < last) { 97 res = (ACPI_RESOURCE *)curr; 98 curr += res->Length; 99 100 /* Handle the individual resource types */ 101 switch(res->Id) { 102 case ACPI_RSTYPE_END_TAG: 103 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n")); 104 curr = last; 105 break; 106 case ACPI_RSTYPE_FIXED_IO: 107 if (res->Data.FixedIo.RangeLength <= 0) 108 break; 109 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n", 110 res->Data.FixedIo.BaseAddress, 111 res->Data.FixedIo.RangeLength)); 112 set->set_ioport(dev, context, 113 res->Data.FixedIo.BaseAddress, 114 res->Data.FixedIo.RangeLength); 115 break; 116 case ACPI_RSTYPE_IO: 117 if (res->Data.Io.RangeLength <= 0) 118 break; 119 if (res->Data.Io.MinBaseAddress == res->Data.Io.MaxBaseAddress) { 120 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n", 121 res->Data.Io.MinBaseAddress, 122 res->Data.Io.RangeLength)); 123 set->set_ioport(dev, context, 124 res->Data.Io.MinBaseAddress, 125 res->Data.Io.RangeLength); 126 } else { 127 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n", 128 res->Data.Io.MinBaseAddress, 129 res->Data.Io.MaxBaseAddress, 130 res->Data.Io.RangeLength)); 131 set->set_iorange(dev, context, 132 res->Data.Io.MinBaseAddress, 133 res->Data.Io.MaxBaseAddress, 134 res->Data.Io.RangeLength, 135 res->Data.Io.Alignment); 136 } 137 break; 138 case ACPI_RSTYPE_FIXED_MEM32: 139 if (res->Data.FixedMemory32.RangeLength <= 0) 140 break; 141 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n", 142 res->Data.FixedMemory32.RangeBaseAddress, 143 res->Data.FixedMemory32.RangeLength)); 144 set->set_memory(dev, context, 145 res->Data.FixedMemory32.RangeBaseAddress, 146 res->Data.FixedMemory32.RangeLength); 147 break; 148 case ACPI_RSTYPE_MEM32: 149 if (res->Data.Memory32.RangeLength <= 0) 150 break; 151 if (res->Data.Memory32.MinBaseAddress == 152 res->Data.Memory32.MaxBaseAddress) { 153 154 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n", 155 res->Data.Memory32.MinBaseAddress, 156 res->Data.Memory32.RangeLength)); 157 set->set_memory(dev, context, 158 res->Data.Memory32.MinBaseAddress, 159 res->Data.Memory32.RangeLength); 160 } else { 161 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n", 162 res->Data.Memory32.MinBaseAddress, 163 res->Data.Memory32.MaxBaseAddress, 164 res->Data.Memory32.RangeLength)); 165 set->set_memoryrange(dev, context, 166 res->Data.Memory32.MinBaseAddress, 167 res->Data.Memory32.MaxBaseAddress, 168 res->Data.Memory32.RangeLength, 169 res->Data.Memory32.Alignment); 170 } 171 break; 172 case ACPI_RSTYPE_MEM24: 173 if (res->Data.Memory24.RangeLength <= 0) 174 break; 175 if (res->Data.Memory24.MinBaseAddress == 176 res->Data.Memory24.MaxBaseAddress) { 177 178 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n", 179 res->Data.Memory24.MinBaseAddress, 180 res->Data.Memory24.RangeLength)); 181 set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress, 182 res->Data.Memory24.RangeLength); 183 } else { 184 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n", 185 res->Data.Memory24.MinBaseAddress, 186 res->Data.Memory24.MaxBaseAddress, 187 res->Data.Memory24.RangeLength)); 188 set->set_memoryrange(dev, context, 189 res->Data.Memory24.MinBaseAddress, 190 res->Data.Memory24.MaxBaseAddress, 191 res->Data.Memory24.RangeLength, 192 res->Data.Memory24.Alignment); 193 } 194 break; 195 case ACPI_RSTYPE_IRQ: 196 /* 197 * from 1.0b 6.4.2 198 * "This structure is repeated for each separate interrupt 199 * required" 200 */ 201 set->set_irq(dev, context, res->Data.Irq.Interrupts, 202 res->Data.Irq.NumberOfInterrupts, res->Data.Irq.EdgeLevel, 203 res->Data.Irq.ActiveHighLow); 204 break; 205 case ACPI_RSTYPE_DMA: 206 /* 207 * from 1.0b 6.4.3 208 * "This structure is repeated for each separate dma channel 209 * required" 210 */ 211 set->set_drq(dev, context, res->Data.Dma.Channels, 212 res->Data.Dma.NumberOfChannels); 213 break; 214 case ACPI_RSTYPE_START_DPF: 215 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependant functions\n")); 216 set->set_start_dependant(dev, context, 217 res->Data.StartDpf.CompatibilityPriority); 218 break; 219 case ACPI_RSTYPE_END_DPF: 220 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependant functions\n")); 221 set->set_end_dependant(dev, context); 222 break; 223 case ACPI_RSTYPE_ADDRESS32: 224 if (res->Data.Address32.AddressLength <= 0) 225 break; 226 if (res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) { 227 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 228 "ignored Address32 %s producer\n", 229 res->Data.Address32.ResourceType == ACPI_IO_RANGE ? 230 "IO" : "Memory")); 231 break; 232 } 233 if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE && 234 res->Data.Address32.ResourceType != ACPI_IO_RANGE) { 235 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 236 "ignored Address32 for non-memory, non-I/O\n")); 237 break; 238 } 239 240 if (res->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED && 241 res->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED) { 242 243 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) { 244 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 245 "Address32/Memory 0x%x/%d\n", 246 res->Data.Address32.MinAddressRange, 247 res->Data.Address32.AddressLength)); 248 set->set_memory(dev, context, 249 res->Data.Address32.MinAddressRange, 250 res->Data.Address32.AddressLength); 251 } else { 252 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 253 "Address32/IO 0x%x/%d\n", 254 res->Data.Address32.MinAddressRange, 255 res->Data.Address32.AddressLength)); 256 set->set_ioport(dev, context, 257 res->Data.Address32.MinAddressRange, 258 res->Data.Address32.AddressLength); 259 } 260 } else { 261 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) { 262 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 263 "Address32/Memory 0x%x-0x%x/%d\n", 264 res->Data.Address32.MinAddressRange, 265 res->Data.Address32.MaxAddressRange, 266 res->Data.Address32.AddressLength)); 267 set->set_memoryrange(dev, context, 268 res->Data.Address32.MinAddressRange, 269 res->Data.Address32.MaxAddressRange, 270 res->Data.Address32.AddressLength, 271 res->Data.Address32.Granularity); 272 } else { 273 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 274 "Address32/IO 0x%x-0x%x/%d\n", 275 res->Data.Address32.MinAddressRange, 276 res->Data.Address32.MaxAddressRange, 277 res->Data.Address32.AddressLength)); 278 set->set_iorange(dev, context, 279 res->Data.Address32.MinAddressRange, 280 res->Data.Address32.MaxAddressRange, 281 res->Data.Address32.AddressLength, 282 res->Data.Address32.Granularity); 283 } 284 } 285 break; 286 case ACPI_RSTYPE_ADDRESS16: 287 if (res->Data.Address16.AddressLength <= 0) 288 break; 289 if (res->Data.Address16.ProducerConsumer != ACPI_CONSUMER) { 290 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 291 "ignored Address16 %s producer\n", 292 res->Data.Address16.ResourceType == ACPI_IO_RANGE ? 293 "IO" : "Memory")); 294 break; 295 } 296 if (res->Data.Address16.ResourceType != ACPI_MEMORY_RANGE && 297 res->Data.Address16.ResourceType != ACPI_IO_RANGE) { 298 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 299 "ignored Address16 for non-memory, non-I/O\n")); 300 break; 301 } 302 303 if (res->Data.Address16.MinAddressFixed == ACPI_ADDRESS_FIXED && 304 res->Data.Address16.MaxAddressFixed == ACPI_ADDRESS_FIXED) { 305 306 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) { 307 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 308 "Address16/Memory 0x%x/%d\n", 309 res->Data.Address16.MinAddressRange, 310 res->Data.Address16.AddressLength)); 311 set->set_memory(dev, context, 312 res->Data.Address16.MinAddressRange, 313 res->Data.Address16.AddressLength); 314 } else { 315 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 316 "Address16/IO 0x%x/%d\n", 317 res->Data.Address16.MinAddressRange, 318 res->Data.Address16.AddressLength)); 319 set->set_ioport(dev, context, 320 res->Data.Address16.MinAddressRange, 321 res->Data.Address16.AddressLength); 322 } 323 } else { 324 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) { 325 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 326 "Address16/Memory 0x%x-0x%x/%d\n", 327 res->Data.Address16.MinAddressRange, 328 res->Data.Address16.MaxAddressRange, 329 res->Data.Address16.AddressLength)); 330 set->set_memoryrange(dev, context, 331 res->Data.Address16.MinAddressRange, 332 res->Data.Address16.MaxAddressRange, 333 res->Data.Address16.AddressLength, 334 res->Data.Address16.Granularity); 335 } else { 336 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 337 "Address16/IO 0x%x-0x%x/%d\n", 338 res->Data.Address16.MinAddressRange, 339 res->Data.Address16.MaxAddressRange, 340 res->Data.Address16.AddressLength)); 341 set->set_iorange(dev, context, 342 res->Data.Address16.MinAddressRange, 343 res->Data.Address16.MaxAddressRange, 344 res->Data.Address16.AddressLength, 345 res->Data.Address16.Granularity); 346 } 347 } 348 break; 349 case ACPI_RSTYPE_ADDRESS64: 350 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 351 "unimplemented Address64 resource\n")); 352 break; 353 case ACPI_RSTYPE_EXT_IRQ: 354 /* XXX special handling? */ 355 set->set_irq(dev, context,res->Data.ExtendedIrq.Interrupts, 356 res->Data.ExtendedIrq.NumberOfInterrupts, 357 res->Data.ExtendedIrq.EdgeLevel, 358 res->Data.ExtendedIrq.ActiveHighLow); 359 break; 360 case ACPI_RSTYPE_VENDOR: 361 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 362 "unimplemented VendorSpecific resource\n")); 363 break; 364 default: 365 break; 366 } 367 } 368 369 AcpiOsFree(buf.Pointer); 370 set->set_done(dev, context); 371 return_ACPI_STATUS (AE_OK); 372} 373 374/* 375 * Resource-set vectors used to attach _CRS-derived resources 376 * to an ACPI device. 377 */ 378static void acpi_res_set_init(device_t dev, void *arg, void **context); 379static void acpi_res_set_done(device_t dev, void *context); 380static void acpi_res_set_ioport(device_t dev, void *context, 381 u_int32_t base, u_int32_t length); 382static void acpi_res_set_iorange(device_t dev, void *context, 383 u_int32_t low, u_int32_t high, 384 u_int32_t length, u_int32_t align); 385static void acpi_res_set_memory(device_t dev, void *context, 386 u_int32_t base, u_int32_t length); 387static void acpi_res_set_memoryrange(device_t dev, void *context, 388 u_int32_t low, u_int32_t high, 389 u_int32_t length, u_int32_t align); 390static void acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, 391 int count, int trig, int pol); 392static void acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, 393 int count); 394static void acpi_res_set_start_dependant(device_t dev, void *context, 395 int preference); 396static void acpi_res_set_end_dependant(device_t dev, void *context); 397 398struct acpi_parse_resource_set acpi_res_parse_set = { 399 acpi_res_set_init, 400 acpi_res_set_done, 401 acpi_res_set_ioport, 402 acpi_res_set_iorange, 403 acpi_res_set_memory, 404 acpi_res_set_memoryrange, 405 acpi_res_set_irq, 406 acpi_res_set_drq, 407 acpi_res_set_start_dependant, 408 acpi_res_set_end_dependant 409}; 410 411struct acpi_res_context { 412 int ar_nio; 413 int ar_nmem; 414 int ar_nirq; 415 int ar_ndrq; 416 void *ar_parent; 417}; 418 419static void 420acpi_res_set_init(device_t dev, void *arg, void **context) 421{ 422 struct acpi_res_context *cp; 423 424 if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) { 425 bzero(cp, sizeof(*cp)); 426 cp->ar_parent = arg; 427 *context = cp; 428 } 429} 430 431static void 432acpi_res_set_done(device_t dev, void *context) 433{ 434 struct acpi_res_context *cp = (struct acpi_res_context *)context; 435 436 if (cp == NULL) 437 return; 438 AcpiOsFree(cp); 439} 440 441static void 442acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, 443 u_int32_t length) 444{ 445 struct acpi_res_context *cp = (struct acpi_res_context *)context; 446 447 if (cp == NULL) 448 return; 449 bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length); 450} 451 452static void 453acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, 454 u_int32_t high, u_int32_t length, u_int32_t align) 455{ 456 struct acpi_res_context *cp = (struct acpi_res_context *)context; 457 458 if (cp == NULL) 459 return; 460 device_printf(dev, "I/O range not supported\n"); 461} 462 463static void 464acpi_res_set_memory(device_t dev, void *context, u_int32_t base, 465 u_int32_t length) 466{ 467 struct acpi_res_context *cp = (struct acpi_res_context *)context; 468 469 if (cp == NULL) 470 return; 471 472 bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length); 473} 474 475static void 476acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, 477 u_int32_t high, u_int32_t length, u_int32_t align) 478{ 479 struct acpi_res_context *cp = (struct acpi_res_context *)context; 480 481 if (cp == NULL) 482 return; 483 device_printf(dev, "memory range not supported\n"); 484} 485 486static void 487acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count, 488 int trig, int pol) 489{ 490 struct acpi_res_context *cp = (struct acpi_res_context *)context; 491 492 if (cp == NULL || irq == NULL) 493 return; 494 495 /* This implements no resource relocation. */ 496 if (count != 1) 497 return; 498 499 bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1); 500 BUS_CONFIG_INTR(dev, *irq, (trig == ACPI_EDGE_SENSITIVE) ? 501 INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ? 502 INTR_POLARITY_HIGH : INTR_POLARITY_LOW); 503} 504 505static void 506acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, int count) 507{ 508 struct acpi_res_context *cp = (struct acpi_res_context *)context; 509 510 if (cp == NULL || drq == NULL) 511 return; 512 513 /* This implements no resource relocation. */ 514 if (count != 1) 515 return; 516 517 bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1); 518} 519 520static void 521acpi_res_set_start_dependant(device_t dev, void *context, int preference) 522{ 523 struct acpi_res_context *cp = (struct acpi_res_context *)context; 524 525 if (cp == NULL) 526 return; 527 device_printf(dev, "dependant functions not supported\n"); 528} 529 530static void 531acpi_res_set_end_dependant(device_t dev, void *context) 532{ 533 struct acpi_res_context *cp = (struct acpi_res_context *)context; 534 535 if (cp == NULL) 536 return; 537 device_printf(dev, "dependant functions not supported\n"); 538} 539 540/* 541 * Resource-owning placeholders for IO and memory pseudo-devices. 542 * 543 * This code allocates system resource objects that will be owned by ACPI 544 * child devices. Really, the acpi parent device should have the resources 545 * but this would significantly affect the device probe code. 546 */ 547 548static int acpi_sysres_probe(device_t dev); 549static int acpi_sysres_attach(device_t dev); 550 551static device_method_t acpi_sysres_methods[] = { 552 /* Device interface */ 553 DEVMETHOD(device_probe, acpi_sysres_probe), 554 DEVMETHOD(device_attach, acpi_sysres_attach), 555 556 {0, 0} 557}; 558 559static driver_t acpi_sysres_driver = { 560 "acpi_sysresource", 561 acpi_sysres_methods, 562 0, 563}; 564 565static devclass_t acpi_sysres_devclass; 566DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass, 567 0, 0); 568MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1); 569 570static int 571acpi_sysres_probe(device_t dev) 572{ 573 ACPI_HANDLE h; 574 575 h = acpi_get_handle(dev); 576 if (acpi_disabled("sysresource") || 577 (!acpi_MatchHid(h, "PNP0C01") && !acpi_MatchHid(h, "PNP0C02"))) 578 return (ENXIO); 579 580 device_set_desc(dev, "System Resource"); 581 device_quiet(dev); 582 return (-100); 583} 584 585static int 586acpi_sysres_attach(device_t dev) 587{ 588 device_t gparent; 589 struct resource *res; 590 struct rman *rm; 591 struct resource_list_entry *rle; 592 struct resource_list *rl; 593 594 /* 595 * Pre-allocate/manage all memory and IO resources. We detect duplicates 596 * by setting rle->res to the resource we got from the parent. We can't 597 * ignore them since rman can't handle duplicates. 598 */ 599 rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 600 SLIST_FOREACH(rle, rl, link) { 601 if (rle->res != NULL) { 602 device_printf(dev, "duplicate resource for %lx\n", rle->start); 603 continue; 604 } 605 606 /* Only memory and IO resources are valid here. */ 607 switch (rle->type) { 608 case SYS_RES_IOPORT: 609 rm = &acpi_rman_io; 610 break; 611 case SYS_RES_MEMORY: 612 rm = &acpi_rman_mem; 613 break; 614 default: 615 continue; 616 } 617 618 /* Pre-allocate resource and add to our rman pool. */ 619 gparent = device_get_parent(device_get_parent(dev)); 620 res = BUS_ALLOC_RESOURCE(gparent, dev, rle->type, &rle->rid, 621 rle->start, rle->start + rle->count - 1, rle->count, 0); 622 if (res != NULL) { 623 rman_manage_region(rm, rman_get_start(res), rman_get_end(res)); 624 rle->res = res; 625 } 626 } 627 628 return (0); 629} 630 631struct resource_list_entry * 632acpi_sysres_find(int type, u_long addr) 633{ 634 device_t *devs; 635 int i, numdevs; 636 struct resource_list *rl; 637 struct resource_list_entry *rle; 638 639 /* We only consider IO and memory resources for our pool. */ 640 rle = NULL; 641 if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) 642 return (rle); 643 644 /* Find all the sysresource devices. */ 645 if (devclass_get_devices(acpi_sysres_devclass, &devs, &numdevs) != 0) 646 return (rle); 647 648 /* Check each device for a resource that contains "addr". */ 649 for (i = 0; i < numdevs && rle == NULL; i++) { 650 rl = BUS_GET_RESOURCE_LIST(device_get_parent(devs[i]), devs[i]); 651 if (rl == NULL) 652 continue; 653 SLIST_FOREACH(rle, rl, link) { 654 if (type == rle->type && addr >= rle->start && 655 addr < rle->start + rle->count) 656 break; 657 } 658 } 659 660 free(devs, M_TEMP); 661 return (rle); 662} 663