1 /* $NetBSD: acpi_resource.c,v 1.41 2019/12/31 17:26:04 jmcneill 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.41 2019/12/31 17:26:04 jmcneill 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 device_t dev; 87 void *context; 88 }; 89 90 static ACPI_STATUS 91 acpi_resource_parse_callback(ACPI_RESOURCE *res, void *context) 92 { 93 struct resource_parse_callback_arg *arg = context; 94 const struct acpi_resource_parse_ops *ops; 95 int i; 96 97 ACPI_FUNCTION_TRACE(__func__); 98 99 ops = arg->ops; 100 101 switch (res->Type) { 102 case ACPI_RESOURCE_TYPE_END_TAG: 103 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n")); 104 break; 105 case ACPI_RESOURCE_TYPE_FIXED_IO: 106 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 107 "FixedIo 0x%x/%u\n", 108 res->Data.FixedIo.Address, 109 res->Data.FixedIo.AddressLength)); 110 if (ops->ioport) 111 (*ops->ioport)(arg->dev, arg->context, 112 res->Data.FixedIo.Address, 113 res->Data.FixedIo.AddressLength); 114 break; 115 116 case ACPI_RESOURCE_TYPE_IO: 117 if (res->Data.Io.Minimum == 118 res->Data.Io.Maximum) { 119 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 120 "Io 0x%x/%u\n", 121 res->Data.Io.Minimum, 122 res->Data.Io.AddressLength)); 123 if (ops->ioport) 124 (*ops->ioport)(arg->dev, arg->context, 125 res->Data.Io.Minimum, 126 res->Data.Io.AddressLength); 127 } else { 128 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 129 "Io 0x%x-0x%x/%u\n", 130 res->Data.Io.Minimum, 131 res->Data.Io.Maximum, 132 res->Data.Io.AddressLength)); 133 if (ops->iorange) 134 (*ops->iorange)(arg->dev, arg->context, 135 res->Data.Io.Minimum, 136 res->Data.Io.Maximum, 137 res->Data.Io.AddressLength, 138 res->Data.Io.Alignment); 139 } 140 break; 141 142 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 143 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 144 "FixedMemory32 0x%x/%u\n", 145 res->Data.FixedMemory32.Address, 146 res->Data.FixedMemory32.AddressLength)); 147 if (ops->memory) 148 (*ops->memory)(arg->dev, arg->context, 149 res->Data.FixedMemory32.Address, 150 res->Data.FixedMemory32.AddressLength, 151 res->Data.FixedMemory32.Address); 152 break; 153 154 case ACPI_RESOURCE_TYPE_MEMORY32: 155 if (res->Data.Memory32.Minimum == 156 res->Data.Memory32.Maximum) { 157 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 158 "Memory32 0x%x/%u\n", 159 res->Data.Memory32.Minimum, 160 res->Data.Memory32.AddressLength)); 161 if (ops->memory) 162 (*ops->memory)(arg->dev, arg->context, 163 res->Data.Memory32.Minimum, 164 res->Data.Memory32.AddressLength, 165 res->Data.Memory32.Minimum); 166 } else { 167 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 168 "Memory32 0x%x-0x%x/%u\n", 169 res->Data.Memory32.Minimum, 170 res->Data.Memory32.Maximum, 171 res->Data.Memory32.AddressLength)); 172 if (ops->memrange) 173 (*ops->memrange)(arg->dev, arg->context, 174 res->Data.Memory32.Minimum, 175 res->Data.Memory32.Maximum, 176 res->Data.Memory32.AddressLength, 177 res->Data.Memory32.Alignment); 178 } 179 break; 180 181 case ACPI_RESOURCE_TYPE_MEMORY24: 182 if (res->Data.Memory24.Minimum == 183 res->Data.Memory24.Maximum) { 184 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 185 "Memory24 0x%x/%u\n", 186 res->Data.Memory24.Minimum, 187 res->Data.Memory24.AddressLength)); 188 if (ops->memory) 189 (*ops->memory)(arg->dev, arg->context, 190 res->Data.Memory24.Minimum, 191 res->Data.Memory24.AddressLength, 192 res->Data.Memory24.Minimum); 193 } else { 194 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 195 "Memory24 0x%x-0x%x/%u\n", 196 res->Data.Memory24.Minimum, 197 res->Data.Memory24.Maximum, 198 res->Data.Memory24.AddressLength)); 199 if (ops->memrange) 200 (*ops->memrange)(arg->dev, arg->context, 201 res->Data.Memory24.Minimum, 202 res->Data.Memory24.Maximum, 203 res->Data.Memory24.AddressLength, 204 res->Data.Memory24.Alignment); 205 } 206 break; 207 208 case ACPI_RESOURCE_TYPE_IRQ: 209 for (i = 0; i < res->Data.Irq.InterruptCount; i++) { 210 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 211 "IRQ %u\n", 212 res->Data.Irq.Interrupts[i])); 213 if (ops->irq) 214 (*ops->irq)(arg->dev, arg->context, 215 res->Data.Irq.Interrupts[i], 216 res->Data.Irq.Triggering); 217 } 218 break; 219 220 case ACPI_RESOURCE_TYPE_DMA: 221 for (i = 0; i < res->Data.Dma.ChannelCount; i++) { 222 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 223 "DRQ %u\n", 224 res->Data.Dma.Channels[i])); 225 if (ops->drq) 226 (*ops->drq)(arg->dev, arg->context, 227 res->Data.Dma.Channels[i]); 228 } 229 break; 230 231 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 232 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 233 "Start dependent functions: %u\n", 234 res->Data.StartDpf.CompatibilityPriority)); 235 if (ops->start_dep) 236 (*ops->start_dep)(arg->dev, arg->context, 237 res->Data.StartDpf.CompatibilityPriority); 238 break; 239 240 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 241 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 242 "End dependent functions\n")); 243 if (ops->end_dep) 244 (*ops->end_dep)(arg->dev, arg->context); 245 break; 246 247 case ACPI_RESOURCE_TYPE_ADDRESS32: 248 /* XXX Only fixed size supported for now */ 249 if (res->Data.Address32.Address.AddressLength == 0 || 250 res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) 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 res->Data.Address64.ProducerConsumer != ACPI_CONSUMER) 306 break; 307 #define ADDRESS64_FIXED2(r) \ 308 ((r)->Data.Address64.MinAddressFixed == ACPI_ADDRESS_FIXED && \ 309 (r)->Data.Address64.MaxAddressFixed == ACPI_ADDRESS_FIXED) 310 switch (res->Data.Address64.ResourceType) { 311 case ACPI_MEMORY_RANGE: 312 if (ADDRESS64_FIXED2(res)) { 313 if (ops->memory) 314 (*ops->memory)(arg->dev, arg->context, 315 res->Data.Address64.Address.Minimum, 316 res->Data.Address64.Address.AddressLength, 317 res->Data.Address64.Address.Minimum + 318 res->Data.Address64.Address.TranslationOffset); 319 } else { 320 if (ops->memrange) 321 (*ops->memrange)(arg->dev, arg->context, 322 res->Data.Address64.Address.Minimum, 323 res->Data.Address64.Address.Maximum, 324 res->Data.Address64.Address.AddressLength, 325 res->Data.Address64.Address.Granularity); 326 } 327 break; 328 case ACPI_IO_RANGE: 329 if (ADDRESS64_FIXED2(res)) { 330 if (ops->ioport) 331 (*ops->ioport)(arg->dev, arg->context, 332 res->Data.Address64.Address.Minimum, 333 res->Data.Address64.Address.AddressLength); 334 } else { 335 if (ops->iorange) 336 (*ops->iorange)(arg->dev, arg->context, 337 res->Data.Address64.Address.Minimum, 338 res->Data.Address64.Address.Maximum, 339 res->Data.Address64.Address.AddressLength, 340 res->Data.Address64.Address.Granularity); 341 } 342 break; 343 case ACPI_BUS_NUMBER_RANGE: 344 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 345 "Address64/BusNumber unimplemented\n")); 346 break; 347 } 348 #undef ADDRESS64_FIXED2 349 #else 350 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 351 "Address64 unimplemented\n")); 352 #endif 353 break; 354 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 355 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 356 "Extended address64 unimplemented\n")); 357 break; 358 359 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 360 if (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 424 rv = AcpiWalkResources(handle, path, acpi_resource_parse_callback, 425 &cbarg); 426 if (ACPI_FAILURE(rv)) { 427 aprint_error_dev(dev, "ACPI: unable to get %s resources: %s\n", 428 path, AcpiFormatException(rv)); 429 return_ACPI_STATUS(rv); 430 } 431 432 if (ops->fini) 433 (*ops->fini)(dev, cbarg.context); 434 435 return_ACPI_STATUS(AE_OK); 436 } 437 438 /* 439 * acpi_resource_print: 440 * 441 * Print the resources assigned to a device. 442 */ 443 void 444 acpi_resource_print(device_t dev, struct acpi_resources *res) 445 { 446 const char *sep; 447 448 if (SIMPLEQ_EMPTY(&res->ar_io) && 449 SIMPLEQ_EMPTY(&res->ar_iorange) && 450 SIMPLEQ_EMPTY(&res->ar_mem) && 451 SIMPLEQ_EMPTY(&res->ar_memrange) && 452 SIMPLEQ_EMPTY(&res->ar_irq) && 453 SIMPLEQ_EMPTY(&res->ar_drq)) 454 return; 455 456 aprint_normal(":"); 457 458 if (SIMPLEQ_EMPTY(&res->ar_io) == 0) { 459 struct acpi_io *ar; 460 461 sep = ""; 462 aprint_normal(" io "); 463 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) { 464 aprint_normal("%s0x%x", sep, ar->ar_base); 465 if (ar->ar_length > 1) 466 aprint_normal("-0x%x", ar->ar_base + 467 ar->ar_length - 1); 468 sep = ","; 469 } 470 } 471 472 /* XXX iorange */ 473 474 if (SIMPLEQ_EMPTY(&res->ar_mem) == 0) { 475 struct acpi_mem *ar; 476 477 sep = ""; 478 aprint_normal(" mem "); 479 SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) { 480 aprint_normal("%s0x%" PRIx64, sep, 481 (uint64_t)ar->ar_base); 482 if (ar->ar_length > 1) 483 aprint_normal("-0x%" PRIx64, 484 (uint64_t)ar->ar_base + 485 ar->ar_length - 1); 486 sep = ","; 487 } 488 } 489 490 /* XXX memrange */ 491 492 if (SIMPLEQ_EMPTY(&res->ar_irq) == 0) { 493 struct acpi_irq *ar; 494 495 sep = ""; 496 aprint_normal(" irq "); 497 SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) { 498 aprint_normal("%s%d", sep, ar->ar_irq); 499 sep = ","; 500 } 501 } 502 503 if (SIMPLEQ_EMPTY(&res->ar_drq) == 0) { 504 struct acpi_drq *ar; 505 506 sep = ""; 507 aprint_normal(" drq "); 508 SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) { 509 aprint_normal("%s%d", sep, ar->ar_drq); 510 sep = ","; 511 } 512 } 513 514 aprint_normal("\n"); 515 aprint_naive("\n"); 516 } 517 518 /* 519 * acpi_resource_cleanup: 520 * 521 * Free all allocated buffers 522 */ 523 void 524 acpi_resource_cleanup(struct acpi_resources *res) 525 { 526 while (!SIMPLEQ_EMPTY(&res->ar_io)) { 527 struct acpi_io *ar; 528 ar = SIMPLEQ_FIRST(&res->ar_io); 529 SIMPLEQ_REMOVE_HEAD(&res->ar_io, ar_list); 530 ACPI_FREE(ar); 531 } 532 533 while (!SIMPLEQ_EMPTY(&res->ar_iorange)) { 534 struct acpi_iorange *ar; 535 ar = SIMPLEQ_FIRST(&res->ar_iorange); 536 SIMPLEQ_REMOVE_HEAD(&res->ar_iorange, ar_list); 537 ACPI_FREE(ar); 538 } 539 540 while (!SIMPLEQ_EMPTY(&res->ar_mem)) { 541 struct acpi_mem *ar; 542 ar = SIMPLEQ_FIRST(&res->ar_mem); 543 SIMPLEQ_REMOVE_HEAD(&res->ar_mem, ar_list); 544 ACPI_FREE(ar); 545 } 546 547 while (!SIMPLEQ_EMPTY(&res->ar_memrange)) { 548 struct acpi_memrange *ar; 549 ar = SIMPLEQ_FIRST(&res->ar_memrange); 550 SIMPLEQ_REMOVE_HEAD(&res->ar_memrange, ar_list); 551 ACPI_FREE(ar); 552 } 553 554 while (!SIMPLEQ_EMPTY(&res->ar_irq)) { 555 struct acpi_irq *ar; 556 ar = SIMPLEQ_FIRST(&res->ar_irq); 557 SIMPLEQ_REMOVE_HEAD(&res->ar_irq, ar_list); 558 ACPI_FREE(ar); 559 } 560 561 while (!SIMPLEQ_EMPTY(&res->ar_drq)) { 562 struct acpi_drq *ar; 563 ar = SIMPLEQ_FIRST(&res->ar_drq); 564 SIMPLEQ_REMOVE_HEAD(&res->ar_drq, ar_list); 565 ACPI_FREE(ar); 566 } 567 568 res->ar_nio = res->ar_niorange = res->ar_nmem = 569 res->ar_nmemrange = res->ar_nirq = res->ar_ndrq = 0; 570 } 571 572 struct acpi_io * 573 acpi_res_io(struct acpi_resources *res, int idx) 574 { 575 struct acpi_io *ar; 576 577 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) { 578 if (ar->ar_index == idx) 579 return ar; 580 } 581 return NULL; 582 } 583 584 struct acpi_iorange * 585 acpi_res_iorange(struct acpi_resources *res, int idx) 586 { 587 struct acpi_iorange *ar; 588 589 SIMPLEQ_FOREACH(ar, &res->ar_iorange, ar_list) { 590 if (ar->ar_index == idx) 591 return ar; 592 } 593 return NULL; 594 } 595 596 struct acpi_mem * 597 acpi_res_mem(struct acpi_resources *res, int idx) 598 { 599 struct acpi_mem *ar; 600 601 SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) { 602 if (ar->ar_index == idx) 603 return ar; 604 } 605 return NULL; 606 } 607 608 struct acpi_memrange * 609 acpi_res_memrange(struct acpi_resources *res, int idx) 610 { 611 struct acpi_memrange *ar; 612 613 SIMPLEQ_FOREACH(ar, &res->ar_memrange, ar_list) { 614 if (ar->ar_index == idx) 615 return ar; 616 } 617 return NULL; 618 } 619 620 struct acpi_irq * 621 acpi_res_irq(struct acpi_resources *res, int idx) 622 { 623 struct acpi_irq *ar; 624 625 SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) { 626 if (ar->ar_index == idx) 627 return ar; 628 } 629 return NULL; 630 } 631 632 struct acpi_drq * 633 acpi_res_drq(struct acpi_resources *res, int idx) 634 { 635 struct acpi_drq *ar; 636 637 SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) { 638 if (ar->ar_index == idx) 639 return ar; 640 } 641 return NULL; 642 } 643 644 /***************************************************************************** 645 * Default ACPI resource parse operations. 646 *****************************************************************************/ 647 648 static void acpi_res_parse_init(device_t, void *, void **); 649 static void acpi_res_parse_fini(device_t, void *); 650 651 static void acpi_res_parse_ioport(device_t, void *, uint32_t, 652 uint32_t); 653 static void acpi_res_parse_iorange(device_t, void *, uint32_t, 654 uint32_t, uint32_t, uint32_t); 655 656 static void acpi_res_parse_memory(device_t, void *, uint64_t, 657 uint64_t, uint64_t); 658 static void acpi_res_parse_memrange(device_t, void *, uint64_t, 659 uint64_t, uint64_t, uint64_t); 660 661 static void acpi_res_parse_irq(device_t, void *, uint32_t, uint32_t); 662 static void acpi_res_parse_drq(device_t, void *, uint32_t); 663 664 static void acpi_res_parse_start_dep(device_t, void *, int); 665 static void acpi_res_parse_end_dep(device_t, void *); 666 667 const struct acpi_resource_parse_ops acpi_resource_parse_ops_default = { 668 .init = acpi_res_parse_init, 669 .fini = acpi_res_parse_fini, 670 671 .ioport = acpi_res_parse_ioport, 672 .iorange = acpi_res_parse_iorange, 673 674 .memory = acpi_res_parse_memory, 675 .memrange = acpi_res_parse_memrange, 676 677 .irq = acpi_res_parse_irq, 678 .drq = acpi_res_parse_drq, 679 680 .start_dep = acpi_res_parse_start_dep, 681 .end_dep = acpi_res_parse_end_dep, 682 }; 683 684 const struct acpi_resource_parse_ops acpi_resource_parse_ops_quiet = { 685 .init = acpi_res_parse_init, 686 .fini = NULL, 687 688 .ioport = acpi_res_parse_ioport, 689 .iorange = acpi_res_parse_iorange, 690 691 .memory = acpi_res_parse_memory, 692 .memrange = acpi_res_parse_memrange, 693 694 .irq = acpi_res_parse_irq, 695 .drq = acpi_res_parse_drq, 696 697 .start_dep = acpi_res_parse_start_dep, 698 .end_dep = acpi_res_parse_end_dep, 699 }; 700 701 static void 702 acpi_res_parse_init(device_t dev, void *arg, void **contextp) 703 { 704 struct acpi_resources *res = arg; 705 706 SIMPLEQ_INIT(&res->ar_io); 707 res->ar_nio = 0; 708 709 SIMPLEQ_INIT(&res->ar_iorange); 710 res->ar_niorange = 0; 711 712 SIMPLEQ_INIT(&res->ar_mem); 713 res->ar_nmem = 0; 714 715 SIMPLEQ_INIT(&res->ar_memrange); 716 res->ar_nmemrange = 0; 717 718 SIMPLEQ_INIT(&res->ar_irq); 719 res->ar_nirq = 0; 720 721 SIMPLEQ_INIT(&res->ar_drq); 722 res->ar_ndrq = 0; 723 724 *contextp = res; 725 } 726 727 static void 728 acpi_res_parse_fini(device_t dev, void *context) 729 { 730 struct acpi_resources *res = context; 731 732 /* Print the resources we're using. */ 733 acpi_resource_print(dev, res); 734 } 735 736 static void 737 acpi_res_parse_ioport(device_t dev, void *context, uint32_t base, 738 uint32_t length) 739 { 740 struct acpi_resources *res = context; 741 struct acpi_io *ar; 742 743 /* 744 * Check if there is another I/O port directly below/under 745 * this one. 746 */ 747 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) { 748 if (ar->ar_base == base + length ) { 749 /* 750 * Entry just below existing entry - adjust 751 * the entry and return. 752 */ 753 ar->ar_base = base; 754 ar->ar_length += length; 755 return; 756 } else if (ar->ar_base + ar->ar_length == base) { 757 /* 758 * Entry just above existing entry - adjust 759 * the entry and return. 760 */ 761 ar->ar_length += length; 762 return; 763 } 764 } 765 766 ar = ACPI_ALLOCATE(sizeof(*ar)); 767 if (ar == NULL) { 768 aprint_error_dev(dev, "ACPI: unable to allocate I/O resource %d\n", 769 res->ar_nio); 770 res->ar_nio++; 771 return; 772 } 773 774 ar->ar_index = res->ar_nio++; 775 ar->ar_base = base; 776 ar->ar_length = length; 777 778 SIMPLEQ_INSERT_TAIL(&res->ar_io, ar, ar_list); 779 } 780 781 static void 782 acpi_res_parse_iorange(device_t dev, void *context, uint32_t low, 783 uint32_t high, uint32_t length, uint32_t align) 784 { 785 struct acpi_resources *res = context; 786 struct acpi_iorange *ar; 787 788 ar = ACPI_ALLOCATE(sizeof(*ar)); 789 if (ar == NULL) { 790 aprint_error_dev(dev, "ACPI: unable to allocate I/O range resource %d\n", 791 res->ar_niorange); 792 res->ar_niorange++; 793 return; 794 } 795 796 ar->ar_index = res->ar_niorange++; 797 ar->ar_low = low; 798 ar->ar_high = high; 799 ar->ar_length = length; 800 ar->ar_align = align; 801 802 SIMPLEQ_INSERT_TAIL(&res->ar_iorange, ar, ar_list); 803 } 804 805 static void 806 acpi_res_parse_memory(device_t dev, void *context, uint64_t base, 807 uint64_t length, uint64_t xbase) 808 { 809 struct acpi_resources *res = context; 810 struct acpi_mem *ar; 811 812 ar = ACPI_ALLOCATE(sizeof(*ar)); 813 if (ar == NULL) { 814 aprint_error_dev(dev, "ACPI: unable to allocate Memory resource %d\n", 815 res->ar_nmem); 816 res->ar_nmem++; 817 return; 818 } 819 820 ar->ar_index = res->ar_nmem++; 821 ar->ar_base = base; 822 ar->ar_length = length; 823 ar->ar_xbase = xbase; 824 825 SIMPLEQ_INSERT_TAIL(&res->ar_mem, ar, ar_list); 826 } 827 828 static void 829 acpi_res_parse_memrange(device_t dev, void *context, uint64_t low, 830 uint64_t high, uint64_t length, uint64_t align) 831 { 832 struct acpi_resources *res = context; 833 struct acpi_memrange *ar; 834 835 ar = ACPI_ALLOCATE(sizeof(*ar)); 836 if (ar == NULL) { 837 aprint_error_dev(dev, "ACPI: unable to allocate Memory range resource %d\n", 838 res->ar_nmemrange); 839 res->ar_nmemrange++; 840 return; 841 } 842 843 ar->ar_index = res->ar_nmemrange++; 844 ar->ar_low = low; 845 ar->ar_high = high; 846 ar->ar_length = length; 847 ar->ar_align = align; 848 849 SIMPLEQ_INSERT_TAIL(&res->ar_memrange, ar, ar_list); 850 } 851 852 static void 853 acpi_res_parse_irq(device_t dev, void *context, uint32_t irq, uint32_t type) 854 { 855 struct acpi_resources *res = context; 856 struct acpi_irq *ar; 857 858 ar = ACPI_ALLOCATE(sizeof(*ar)); 859 if (ar == NULL) { 860 aprint_error_dev(dev, "ACPI: unable to allocate IRQ resource %d\n", 861 res->ar_nirq); 862 res->ar_nirq++; 863 return; 864 } 865 866 ar->ar_index = res->ar_nirq++; 867 ar->ar_irq = irq; 868 ar->ar_type = type; 869 870 SIMPLEQ_INSERT_TAIL(&res->ar_irq, ar, ar_list); 871 } 872 873 static void 874 acpi_res_parse_drq(device_t dev, void *context, uint32_t drq) 875 { 876 struct acpi_resources *res = context; 877 struct acpi_drq *ar; 878 879 ar = ACPI_ALLOCATE(sizeof(*ar)); 880 if (ar == NULL) { 881 aprint_error_dev(dev, "ACPI: unable to allocate DRQ resource %d\n", 882 res->ar_ndrq); 883 res->ar_ndrq++; 884 return; 885 } 886 887 ar->ar_index = res->ar_ndrq++; 888 ar->ar_drq = drq; 889 890 SIMPLEQ_INSERT_TAIL(&res->ar_drq, ar, ar_list); 891 } 892 893 static void 894 acpi_res_parse_start_dep(device_t dev, void *context, 895 int preference) 896 { 897 898 aprint_error_dev(dev, "ACPI: dependent functions not supported\n"); 899 } 900 901 static void 902 acpi_res_parse_end_dep(device_t dev, void *context) 903 { 904 905 /* Nothing to do. */ 906 } 907