1 /* $NetBSD: acpi_resource.c,v 1.44 2025/01/02 16:32:34 andvar Exp $ */ 2 3 /* 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /*- 39 * Copyright (c) 2000 Michael Smith 40 * Copyright (c) 2000 BSDi 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 */ 64 65 /* 66 * ACPI resource parsing. 67 */ 68 69 #include <sys/cdefs.h> 70 __KERNEL_RCSID(0, "$NetBSD: acpi_resource.c,v 1.44 2025/01/02 16:32:34 andvar Exp $"); 71 72 #include <sys/param.h> 73 #include <sys/device.h> 74 #include <sys/systm.h> 75 76 #include <dev/acpi/acpireg.h> 77 #include <dev/acpi/acpivar.h> 78 79 #define _COMPONENT ACPI_RESOURCE_COMPONENT 80 ACPI_MODULE_NAME("RESOURCE") 81 82 static ACPI_STATUS acpi_resource_parse_callback(ACPI_RESOURCE *, void *); 83 84 struct resource_parse_callback_arg { 85 const struct acpi_resource_parse_ops *ops; 86 bool include_producer; 87 device_t dev; 88 void *context; 89 }; 90 91 static ACPI_STATUS 92 acpi_resource_parse_callback(ACPI_RESOURCE *res, void *context) 93 { 94 struct resource_parse_callback_arg *arg = context; 95 const struct acpi_resource_parse_ops *ops; 96 int i; 97 98 ACPI_FUNCTION_TRACE(__func__); 99 100 ops = arg->ops; 101 102 switch (res->Type) { 103 case ACPI_RESOURCE_TYPE_END_TAG: 104 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n")); 105 break; 106 case ACPI_RESOURCE_TYPE_FIXED_IO: 107 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 108 "FixedIo 0x%x/%u\n", 109 res->Data.FixedIo.Address, 110 res->Data.FixedIo.AddressLength)); 111 if (ops->ioport) 112 (*ops->ioport)(arg->dev, arg->context, 113 res->Data.FixedIo.Address, 114 res->Data.FixedIo.AddressLength); 115 break; 116 117 case ACPI_RESOURCE_TYPE_IO: 118 if (res->Data.Io.Minimum == 119 res->Data.Io.Maximum) { 120 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 121 "Io 0x%x/%u\n", 122 res->Data.Io.Minimum, 123 res->Data.Io.AddressLength)); 124 if (ops->ioport) 125 (*ops->ioport)(arg->dev, arg->context, 126 res->Data.Io.Minimum, 127 res->Data.Io.AddressLength); 128 } else { 129 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 130 "Io 0x%x-0x%x/%u\n", 131 res->Data.Io.Minimum, 132 res->Data.Io.Maximum, 133 res->Data.Io.AddressLength)); 134 if (ops->iorange) 135 (*ops->iorange)(arg->dev, arg->context, 136 res->Data.Io.Minimum, 137 res->Data.Io.Maximum, 138 res->Data.Io.AddressLength, 139 res->Data.Io.Alignment); 140 } 141 break; 142 143 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 144 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 145 "FixedMemory32 0x%x/%u\n", 146 res->Data.FixedMemory32.Address, 147 res->Data.FixedMemory32.AddressLength)); 148 if (ops->memory) 149 (*ops->memory)(arg->dev, arg->context, 150 res->Data.FixedMemory32.Address, 151 res->Data.FixedMemory32.AddressLength, 152 res->Data.FixedMemory32.Address); 153 break; 154 155 case ACPI_RESOURCE_TYPE_MEMORY32: 156 if (res->Data.Memory32.Minimum == 157 res->Data.Memory32.Maximum) { 158 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 159 "Memory32 0x%x/%u\n", 160 res->Data.Memory32.Minimum, 161 res->Data.Memory32.AddressLength)); 162 if (ops->memory) 163 (*ops->memory)(arg->dev, arg->context, 164 res->Data.Memory32.Minimum, 165 res->Data.Memory32.AddressLength, 166 res->Data.Memory32.Minimum); 167 } else { 168 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 169 "Memory32 0x%x-0x%x/%u\n", 170 res->Data.Memory32.Minimum, 171 res->Data.Memory32.Maximum, 172 res->Data.Memory32.AddressLength)); 173 if (ops->memrange) 174 (*ops->memrange)(arg->dev, arg->context, 175 res->Data.Memory32.Minimum, 176 res->Data.Memory32.Maximum, 177 res->Data.Memory32.AddressLength, 178 res->Data.Memory32.Alignment); 179 } 180 break; 181 182 case ACPI_RESOURCE_TYPE_MEMORY24: 183 if (res->Data.Memory24.Minimum == 184 res->Data.Memory24.Maximum) { 185 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 186 "Memory24 0x%x/%u\n", 187 res->Data.Memory24.Minimum, 188 res->Data.Memory24.AddressLength)); 189 if (ops->memory) 190 (*ops->memory)(arg->dev, arg->context, 191 res->Data.Memory24.Minimum, 192 res->Data.Memory24.AddressLength, 193 res->Data.Memory24.Minimum); 194 } else { 195 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 196 "Memory24 0x%x-0x%x/%u\n", 197 res->Data.Memory24.Minimum, 198 res->Data.Memory24.Maximum, 199 res->Data.Memory24.AddressLength)); 200 if (ops->memrange) 201 (*ops->memrange)(arg->dev, arg->context, 202 res->Data.Memory24.Minimum, 203 res->Data.Memory24.Maximum, 204 res->Data.Memory24.AddressLength, 205 res->Data.Memory24.Alignment); 206 } 207 break; 208 209 case ACPI_RESOURCE_TYPE_IRQ: 210 for (i = 0; i < res->Data.Irq.InterruptCount; i++) { 211 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 212 "IRQ %u\n", 213 res->Data.Irq.Interrupts[i])); 214 if (ops->irq) 215 (*ops->irq)(arg->dev, arg->context, 216 res->Data.Irq.Interrupts[i], 217 res->Data.Irq.Triggering); 218 } 219 break; 220 221 case ACPI_RESOURCE_TYPE_DMA: 222 for (i = 0; i < res->Data.Dma.ChannelCount; i++) { 223 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 224 "DRQ %u\n", 225 res->Data.Dma.Channels[i])); 226 if (ops->drq) 227 (*ops->drq)(arg->dev, arg->context, 228 res->Data.Dma.Channels[i]); 229 } 230 break; 231 232 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 233 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 234 "Start dependent functions: %u\n", 235 res->Data.StartDpf.CompatibilityPriority)); 236 if (ops->start_dep) 237 (*ops->start_dep)(arg->dev, arg->context, 238 res->Data.StartDpf.CompatibilityPriority); 239 break; 240 241 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 242 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 243 "End dependent functions\n")); 244 if (ops->end_dep) 245 (*ops->end_dep)(arg->dev, arg->context); 246 break; 247 248 case ACPI_RESOURCE_TYPE_ADDRESS32: 249 /* XXX Only fixed size supported for now */ 250 if (res->Data.Address32.Address.AddressLength == 0) 251 break; 252 #define ADDRESS32_FIXED2(r) \ 253 ((r)->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED && \ 254 (r)->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED) 255 switch (res->Data.Address32.ResourceType) { 256 case ACPI_MEMORY_RANGE: 257 if (ADDRESS32_FIXED2(res)) { 258 if (ops->memory) 259 (*ops->memory)(arg->dev, arg->context, 260 res->Data.Address32.Address.Minimum, 261 res->Data.Address32.Address.AddressLength, 262 res->Data.Address32.Address.Minimum + 263 res->Data.Address32.Address.TranslationOffset); 264 } else { 265 if (ops->memrange) 266 (*ops->memrange)(arg->dev, arg->context, 267 res->Data.Address32.Address.Minimum, 268 res->Data.Address32.Address.Maximum, 269 res->Data.Address32.Address.AddressLength, 270 res->Data.Address32.Address.Granularity); 271 } 272 break; 273 case ACPI_IO_RANGE: 274 if (ADDRESS32_FIXED2(res)) { 275 if (ops->ioport) 276 (*ops->ioport)(arg->dev, arg->context, 277 res->Data.Address32.Address.Minimum, 278 res->Data.Address32.Address.AddressLength); 279 } else { 280 if (ops->iorange) 281 (*ops->iorange)(arg->dev, arg->context, 282 res->Data.Address32.Address.Minimum, 283 res->Data.Address32.Address.Maximum, 284 res->Data.Address32.Address.AddressLength, 285 res->Data.Address32.Address.Granularity); 286 } 287 break; 288 case ACPI_BUS_NUMBER_RANGE: 289 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 290 "Address32/BusNumber unimplemented\n")); 291 break; 292 } 293 #undef ADDRESS32_FIXED2 294 break; 295 296 case ACPI_RESOURCE_TYPE_ADDRESS16: 297 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 298 "Address16 unimplemented\n")); 299 break; 300 301 case ACPI_RESOURCE_TYPE_ADDRESS64: 302 #ifdef _LP64 303 /* XXX Only fixed size supported for now */ 304 if (res->Data.Address64.Address.AddressLength == 0) 305 break; 306 #define ADDRESS64_FIXED2(r) \ 307 ((r)->Data.Address64.MinAddressFixed == ACPI_ADDRESS_FIXED && \ 308 (r)->Data.Address64.MaxAddressFixed == ACPI_ADDRESS_FIXED) 309 switch (res->Data.Address64.ResourceType) { 310 case ACPI_MEMORY_RANGE: 311 if (ADDRESS64_FIXED2(res)) { 312 if (ops->memory) 313 (*ops->memory)(arg->dev, arg->context, 314 res->Data.Address64.Address.Minimum, 315 res->Data.Address64.Address.AddressLength, 316 res->Data.Address64.Address.Minimum + 317 res->Data.Address64.Address.TranslationOffset); 318 } else { 319 if (ops->memrange) 320 (*ops->memrange)(arg->dev, arg->context, 321 res->Data.Address64.Address.Minimum, 322 res->Data.Address64.Address.Maximum, 323 res->Data.Address64.Address.AddressLength, 324 res->Data.Address64.Address.Granularity); 325 } 326 break; 327 case ACPI_IO_RANGE: 328 if (ADDRESS64_FIXED2(res)) { 329 if (ops->ioport) 330 (*ops->ioport)(arg->dev, arg->context, 331 res->Data.Address64.Address.Minimum, 332 res->Data.Address64.Address.AddressLength); 333 } else { 334 if (ops->iorange) 335 (*ops->iorange)(arg->dev, arg->context, 336 res->Data.Address64.Address.Minimum, 337 res->Data.Address64.Address.Maximum, 338 res->Data.Address64.Address.AddressLength, 339 res->Data.Address64.Address.Granularity); 340 } 341 break; 342 case ACPI_BUS_NUMBER_RANGE: 343 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 344 "Address64/BusNumber unimplemented\n")); 345 break; 346 } 347 #undef ADDRESS64_FIXED2 348 #else 349 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 350 "Address64 unimplemented\n")); 351 #endif 352 break; 353 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 354 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 355 "Extended address64 unimplemented\n")); 356 break; 357 358 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 359 if (!arg->include_producer && 360 res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) { 361 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 362 "ignored ExtIRQ producer\n")); 363 break; 364 } 365 for (i = 0; i < res->Data.ExtendedIrq.InterruptCount; i++) { 366 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 367 "ExtIRQ %u\n", 368 res->Data.ExtendedIrq.Interrupts[i])); 369 if (ops->irq) 370 (*ops->irq)(arg->dev, arg->context, 371 res->Data.ExtendedIrq.Interrupts[i], 372 res->Data.ExtendedIrq.Triggering); 373 } 374 break; 375 376 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 377 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 378 "GenericRegister unimplemented\n")); 379 break; 380 381 case ACPI_RESOURCE_TYPE_VENDOR: 382 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 383 "VendorSpecific unimplemented\n")); 384 break; 385 386 default: 387 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 388 "Unknown resource type: %u\n", res->Type)); 389 break; 390 } 391 392 return_ACPI_STATUS(AE_OK); 393 } 394 395 396 /* 397 * acpi_resource_parse: 398 * 399 * Parse a device node's resources and fill them in for the 400 * client. 401 * 402 * This API supports _CRS (current resources) and 403 * _PRS (possible resources). 404 * 405 * Note that it might be nice to also locate ACPI-specific resource 406 * items, such as GPE bits. 407 */ 408 ACPI_STATUS 409 acpi_resource_parse(device_t dev, ACPI_HANDLE handle, const char *path, 410 void *arg, const struct acpi_resource_parse_ops *ops) 411 { 412 struct resource_parse_callback_arg cbarg; 413 ACPI_STATUS rv; 414 415 ACPI_FUNCTION_TRACE(__func__); 416 417 if (ops->init) 418 (*ops->init)(dev, arg, &cbarg.context); 419 else 420 cbarg.context = arg; 421 cbarg.ops = ops; 422 cbarg.dev = dev; 423 cbarg.include_producer = false; 424 425 rv = AcpiWalkResources(handle, path, acpi_resource_parse_callback, 426 &cbarg); 427 if (ACPI_FAILURE(rv)) { 428 aprint_error_dev(dev, "ACPI: unable to get %s resources: %s\n", 429 path, AcpiFormatException(rv)); 430 return_ACPI_STATUS(rv); 431 } 432 433 if (ops->fini) 434 (*ops->fini)(dev, cbarg.context); 435 436 return_ACPI_STATUS(AE_OK); 437 } 438 439 /* 440 * acpi_resource_parse_any: 441 * 442 * Parse a device node's resources and fill them in for the 443 * client. Like acpi_resource_parse, but doesn't skip ResourceProducer 444 * type resources. 445 */ 446 ACPI_STATUS 447 acpi_resource_parse_any(device_t dev, ACPI_HANDLE handle, const char *path, 448 void *arg, const struct acpi_resource_parse_ops *ops) 449 { 450 struct resource_parse_callback_arg cbarg; 451 ACPI_STATUS rv; 452 453 ACPI_FUNCTION_TRACE(__func__); 454 455 if (ops->init) 456 (*ops->init)(dev, arg, &cbarg.context); 457 else 458 cbarg.context = arg; 459 cbarg.ops = ops; 460 cbarg.dev = dev; 461 cbarg.include_producer = true; 462 463 rv = AcpiWalkResources(handle, path, acpi_resource_parse_callback, 464 &cbarg); 465 if (ACPI_FAILURE(rv)) { 466 aprint_error_dev(dev, "ACPI: unable to get %s resources: %s\n", 467 path, AcpiFormatException(rv)); 468 return_ACPI_STATUS(rv); 469 } 470 471 if (ops->fini) 472 (*ops->fini)(dev, cbarg.context); 473 474 return_ACPI_STATUS(AE_OK); 475 } 476 477 478 /* 479 * acpi_resource_print: 480 * 481 * Print the resources assigned to a device. 482 */ 483 void 484 acpi_resource_print(device_t dev, struct acpi_resources *res) 485 { 486 const char *sep; 487 488 if (SIMPLEQ_EMPTY(&res->ar_io) && 489 SIMPLEQ_EMPTY(&res->ar_iorange) && 490 SIMPLEQ_EMPTY(&res->ar_mem) && 491 SIMPLEQ_EMPTY(&res->ar_memrange) && 492 SIMPLEQ_EMPTY(&res->ar_irq) && 493 SIMPLEQ_EMPTY(&res->ar_drq)) 494 return; 495 496 aprint_normal(":"); 497 498 if (SIMPLEQ_EMPTY(&res->ar_io) == 0) { 499 struct acpi_io *ar; 500 501 sep = ""; 502 aprint_normal(" io "); 503 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) { 504 aprint_normal("%s0x%x", sep, ar->ar_base); 505 if (ar->ar_length > 1) 506 aprint_normal("-0x%x", ar->ar_base + 507 ar->ar_length - 1); 508 sep = ","; 509 } 510 } 511 512 /* XXX iorange */ 513 514 if (SIMPLEQ_EMPTY(&res->ar_mem) == 0) { 515 struct acpi_mem *ar; 516 517 sep = ""; 518 aprint_normal(" mem "); 519 SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) { 520 aprint_normal("%s0x%" PRIx64, sep, 521 (uint64_t)ar->ar_base); 522 if (ar->ar_length > 1) 523 aprint_normal("-0x%" PRIx64, 524 (uint64_t)ar->ar_base + 525 ar->ar_length - 1); 526 sep = ","; 527 } 528 } 529 530 /* XXX memrange */ 531 532 if (SIMPLEQ_EMPTY(&res->ar_irq) == 0) { 533 struct acpi_irq *ar; 534 535 sep = ""; 536 aprint_normal(" irq "); 537 SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) { 538 aprint_normal("%s%d", sep, ar->ar_irq); 539 sep = ","; 540 } 541 } 542 543 if (SIMPLEQ_EMPTY(&res->ar_drq) == 0) { 544 struct acpi_drq *ar; 545 546 sep = ""; 547 aprint_normal(" drq "); 548 SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) { 549 aprint_normal("%s%d", sep, ar->ar_drq); 550 sep = ","; 551 } 552 } 553 554 aprint_normal("\n"); 555 aprint_naive("\n"); 556 } 557 558 /* 559 * acpi_resource_cleanup: 560 * 561 * Free all allocated buffers 562 */ 563 void 564 acpi_resource_cleanup(struct acpi_resources *res) 565 { 566 while (!SIMPLEQ_EMPTY(&res->ar_io)) { 567 struct acpi_io *ar; 568 ar = SIMPLEQ_FIRST(&res->ar_io); 569 SIMPLEQ_REMOVE_HEAD(&res->ar_io, ar_list); 570 ACPI_FREE(ar); 571 } 572 573 while (!SIMPLEQ_EMPTY(&res->ar_iorange)) { 574 struct acpi_iorange *ar; 575 ar = SIMPLEQ_FIRST(&res->ar_iorange); 576 SIMPLEQ_REMOVE_HEAD(&res->ar_iorange, ar_list); 577 ACPI_FREE(ar); 578 } 579 580 while (!SIMPLEQ_EMPTY(&res->ar_mem)) { 581 struct acpi_mem *ar; 582 ar = SIMPLEQ_FIRST(&res->ar_mem); 583 SIMPLEQ_REMOVE_HEAD(&res->ar_mem, ar_list); 584 ACPI_FREE(ar); 585 } 586 587 while (!SIMPLEQ_EMPTY(&res->ar_memrange)) { 588 struct acpi_memrange *ar; 589 ar = SIMPLEQ_FIRST(&res->ar_memrange); 590 SIMPLEQ_REMOVE_HEAD(&res->ar_memrange, ar_list); 591 ACPI_FREE(ar); 592 } 593 594 while (!SIMPLEQ_EMPTY(&res->ar_irq)) { 595 struct acpi_irq *ar; 596 ar = SIMPLEQ_FIRST(&res->ar_irq); 597 SIMPLEQ_REMOVE_HEAD(&res->ar_irq, ar_list); 598 ACPI_FREE(ar); 599 } 600 601 while (!SIMPLEQ_EMPTY(&res->ar_drq)) { 602 struct acpi_drq *ar; 603 ar = SIMPLEQ_FIRST(&res->ar_drq); 604 SIMPLEQ_REMOVE_HEAD(&res->ar_drq, ar_list); 605 ACPI_FREE(ar); 606 } 607 608 res->ar_nio = res->ar_niorange = res->ar_nmem = 609 res->ar_nmemrange = res->ar_nirq = res->ar_ndrq = 0; 610 } 611 612 struct acpi_io * 613 acpi_res_io(struct acpi_resources *res, int idx) 614 { 615 struct acpi_io *ar; 616 617 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) { 618 if (ar->ar_index == idx) 619 return ar; 620 } 621 return NULL; 622 } 623 624 struct acpi_iorange * 625 acpi_res_iorange(struct acpi_resources *res, int idx) 626 { 627 struct acpi_iorange *ar; 628 629 SIMPLEQ_FOREACH(ar, &res->ar_iorange, ar_list) { 630 if (ar->ar_index == idx) 631 return ar; 632 } 633 return NULL; 634 } 635 636 struct acpi_mem * 637 acpi_res_mem(struct acpi_resources *res, int idx) 638 { 639 struct acpi_mem *ar; 640 641 SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) { 642 if (ar->ar_index == idx) 643 return ar; 644 } 645 return NULL; 646 } 647 648 struct acpi_memrange * 649 acpi_res_memrange(struct acpi_resources *res, int idx) 650 { 651 struct acpi_memrange *ar; 652 653 SIMPLEQ_FOREACH(ar, &res->ar_memrange, ar_list) { 654 if (ar->ar_index == idx) 655 return ar; 656 } 657 return NULL; 658 } 659 660 struct acpi_irq * 661 acpi_res_irq(struct acpi_resources *res, int idx) 662 { 663 struct acpi_irq *ar; 664 665 SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) { 666 if (ar->ar_index == idx) 667 return ar; 668 } 669 return NULL; 670 } 671 672 struct acpi_drq * 673 acpi_res_drq(struct acpi_resources *res, int idx) 674 { 675 struct acpi_drq *ar; 676 677 SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) { 678 if (ar->ar_index == idx) 679 return ar; 680 } 681 return NULL; 682 } 683 684 /***************************************************************************** 685 * Default ACPI resource parse operations. 686 *****************************************************************************/ 687 688 static void acpi_res_parse_init(device_t, void *, void **); 689 static void acpi_res_parse_fini(device_t, void *); 690 691 static void acpi_res_parse_ioport(device_t, void *, uint32_t, 692 uint32_t); 693 static void acpi_res_parse_iorange(device_t, void *, uint32_t, 694 uint32_t, uint32_t, uint32_t); 695 696 static void acpi_res_parse_memory(device_t, void *, uint64_t, 697 uint64_t, uint64_t); 698 static void acpi_res_parse_memrange(device_t, void *, uint64_t, 699 uint64_t, uint64_t, uint64_t); 700 701 static void acpi_res_parse_irq(device_t, void *, uint32_t, uint32_t); 702 static void acpi_res_parse_drq(device_t, void *, uint32_t); 703 704 static void acpi_res_parse_start_dep(device_t, void *, int); 705 static void acpi_res_parse_end_dep(device_t, void *); 706 707 const struct acpi_resource_parse_ops acpi_resource_parse_ops_default = { 708 .init = acpi_res_parse_init, 709 .fini = acpi_res_parse_fini, 710 711 .ioport = acpi_res_parse_ioport, 712 .iorange = acpi_res_parse_iorange, 713 714 .memory = acpi_res_parse_memory, 715 .memrange = acpi_res_parse_memrange, 716 717 .irq = acpi_res_parse_irq, 718 .drq = acpi_res_parse_drq, 719 720 .start_dep = acpi_res_parse_start_dep, 721 .end_dep = acpi_res_parse_end_dep, 722 }; 723 724 const struct acpi_resource_parse_ops acpi_resource_parse_ops_quiet = { 725 .init = acpi_res_parse_init, 726 .fini = NULL, 727 728 .ioport = acpi_res_parse_ioport, 729 .iorange = acpi_res_parse_iorange, 730 731 .memory = acpi_res_parse_memory, 732 .memrange = acpi_res_parse_memrange, 733 734 .irq = acpi_res_parse_irq, 735 .drq = acpi_res_parse_drq, 736 737 .start_dep = acpi_res_parse_start_dep, 738 .end_dep = acpi_res_parse_end_dep, 739 }; 740 741 static void 742 acpi_res_parse_init(device_t dev, void *arg, void **contextp) 743 { 744 struct acpi_resources *res = arg; 745 746 SIMPLEQ_INIT(&res->ar_io); 747 res->ar_nio = 0; 748 749 SIMPLEQ_INIT(&res->ar_iorange); 750 res->ar_niorange = 0; 751 752 SIMPLEQ_INIT(&res->ar_mem); 753 res->ar_nmem = 0; 754 755 SIMPLEQ_INIT(&res->ar_memrange); 756 res->ar_nmemrange = 0; 757 758 SIMPLEQ_INIT(&res->ar_irq); 759 res->ar_nirq = 0; 760 761 SIMPLEQ_INIT(&res->ar_drq); 762 res->ar_ndrq = 0; 763 764 *contextp = res; 765 } 766 767 static void 768 acpi_res_parse_fini(device_t dev, void *context) 769 { 770 struct acpi_resources *res = context; 771 772 /* Print the resources we're using. */ 773 acpi_resource_print(dev, res); 774 } 775 776 static void 777 acpi_res_parse_ioport(device_t dev, void *context, uint32_t base, 778 uint32_t length) 779 { 780 struct acpi_resources *res = context; 781 struct acpi_io *ar; 782 783 /* 784 * Check if there is another I/O port directly below/under 785 * this one. 786 */ 787 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) { 788 if (ar->ar_base == base + length ) { 789 /* 790 * Entry just below existing entry - adjust 791 * the entry and return. 792 */ 793 ar->ar_base = base; 794 ar->ar_length += length; 795 return; 796 } else if (ar->ar_base + ar->ar_length == base) { 797 /* 798 * Entry just above existing entry - adjust 799 * the entry and return. 800 */ 801 ar->ar_length += length; 802 return; 803 } 804 } 805 806 /* IO and FixedIO I/O resource addresses are limited to 10/16-bit. */ 807 if (base + length - 1 > UINT16_MAX) { 808 aprint_error_dev(dev, "ACPI: invalid I/O register resource %d," 809 " base 0x%x, length %d\n", 810 res->ar_nio, base, length); 811 res->ar_nio++; 812 return; 813 } 814 815 ar = ACPI_ALLOCATE(sizeof(*ar)); 816 if (ar == NULL) { 817 aprint_error_dev(dev, "ACPI: unable to allocate I/O resource %d\n", 818 res->ar_nio); 819 res->ar_nio++; 820 return; 821 } 822 823 ar->ar_index = res->ar_nio++; 824 ar->ar_base = base; 825 ar->ar_length = length; 826 827 SIMPLEQ_INSERT_TAIL(&res->ar_io, ar, ar_list); 828 } 829 830 static void 831 acpi_res_parse_iorange(device_t dev, void *context, uint32_t low, 832 uint32_t high, uint32_t length, uint32_t align) 833 { 834 struct acpi_resources *res = context; 835 struct acpi_iorange *ar; 836 837 ar = ACPI_ALLOCATE(sizeof(*ar)); 838 if (ar == NULL) { 839 aprint_error_dev(dev, "ACPI: unable to allocate I/O range resource %d\n", 840 res->ar_niorange); 841 res->ar_niorange++; 842 return; 843 } 844 845 ar->ar_index = res->ar_niorange++; 846 ar->ar_low = low; 847 ar->ar_high = high; 848 ar->ar_length = length; 849 ar->ar_align = align; 850 851 SIMPLEQ_INSERT_TAIL(&res->ar_iorange, ar, ar_list); 852 } 853 854 static void 855 acpi_res_parse_memory(device_t dev, void *context, uint64_t base, 856 uint64_t length, uint64_t xbase) 857 { 858 struct acpi_resources *res = context; 859 struct acpi_mem *ar; 860 861 ar = ACPI_ALLOCATE(sizeof(*ar)); 862 if (ar == NULL) { 863 aprint_error_dev(dev, "ACPI: unable to allocate Memory resource %d\n", 864 res->ar_nmem); 865 res->ar_nmem++; 866 return; 867 } 868 869 ar->ar_index = res->ar_nmem++; 870 ar->ar_base = base; 871 ar->ar_length = length; 872 ar->ar_xbase = xbase; 873 874 SIMPLEQ_INSERT_TAIL(&res->ar_mem, ar, ar_list); 875 } 876 877 static void 878 acpi_res_parse_memrange(device_t dev, void *context, uint64_t low, 879 uint64_t high, uint64_t length, uint64_t align) 880 { 881 struct acpi_resources *res = context; 882 struct acpi_memrange *ar; 883 884 ar = ACPI_ALLOCATE(sizeof(*ar)); 885 if (ar == NULL) { 886 aprint_error_dev(dev, "ACPI: unable to allocate Memory range resource %d\n", 887 res->ar_nmemrange); 888 res->ar_nmemrange++; 889 return; 890 } 891 892 ar->ar_index = res->ar_nmemrange++; 893 ar->ar_low = low; 894 ar->ar_high = high; 895 ar->ar_length = length; 896 ar->ar_align = align; 897 898 SIMPLEQ_INSERT_TAIL(&res->ar_memrange, ar, ar_list); 899 } 900 901 static void 902 acpi_res_parse_irq(device_t dev, void *context, uint32_t irq, uint32_t type) 903 { 904 struct acpi_resources *res = context; 905 struct acpi_irq *ar; 906 907 ar = ACPI_ALLOCATE(sizeof(*ar)); 908 if (ar == NULL) { 909 aprint_error_dev(dev, "ACPI: unable to allocate IRQ resource %d\n", 910 res->ar_nirq); 911 res->ar_nirq++; 912 return; 913 } 914 915 ar->ar_index = res->ar_nirq++; 916 ar->ar_irq = irq; 917 ar->ar_type = type; 918 919 SIMPLEQ_INSERT_TAIL(&res->ar_irq, ar, ar_list); 920 } 921 922 static void 923 acpi_res_parse_drq(device_t dev, void *context, uint32_t drq) 924 { 925 struct acpi_resources *res = context; 926 struct acpi_drq *ar; 927 928 ar = ACPI_ALLOCATE(sizeof(*ar)); 929 if (ar == NULL) { 930 aprint_error_dev(dev, "ACPI: unable to allocate DRQ resource %d\n", 931 res->ar_ndrq); 932 res->ar_ndrq++; 933 return; 934 } 935 936 ar->ar_index = res->ar_ndrq++; 937 ar->ar_drq = drq; 938 939 SIMPLEQ_INSERT_TAIL(&res->ar_drq, ar, ar_list); 940 } 941 942 static void 943 acpi_res_parse_start_dep(device_t dev, void *context, 944 int preference) 945 { 946 947 aprint_error_dev(dev, "ACPI: dependent functions not supported\n"); 948 } 949 950 static void 951 acpi_res_parse_end_dep(device_t dev, void *context) 952 { 953 954 /* Nothing to do. */ 955 } 956