1 /* $NetBSD: acpi_resource.c,v 1.38 2018/10/25 10:38:57 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.38 2018/10/25 10:38:57 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 break; 152 153 case ACPI_RESOURCE_TYPE_MEMORY32: 154 if (res->Data.Memory32.Minimum == 155 res->Data.Memory32.Maximum) { 156 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 157 "Memory32 0x%x/%u\n", 158 res->Data.Memory32.Minimum, 159 res->Data.Memory32.AddressLength)); 160 if (ops->memory) 161 (*ops->memory)(arg->dev, arg->context, 162 res->Data.Memory32.Minimum, 163 res->Data.Memory32.AddressLength); 164 } else { 165 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 166 "Memory32 0x%x-0x%x/%u\n", 167 res->Data.Memory32.Minimum, 168 res->Data.Memory32.Maximum, 169 res->Data.Memory32.AddressLength)); 170 if (ops->memrange) 171 (*ops->memrange)(arg->dev, arg->context, 172 res->Data.Memory32.Minimum, 173 res->Data.Memory32.Maximum, 174 res->Data.Memory32.AddressLength, 175 res->Data.Memory32.Alignment); 176 } 177 break; 178 179 case ACPI_RESOURCE_TYPE_MEMORY24: 180 if (res->Data.Memory24.Minimum == 181 res->Data.Memory24.Maximum) { 182 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 183 "Memory24 0x%x/%u\n", 184 res->Data.Memory24.Minimum, 185 res->Data.Memory24.AddressLength)); 186 if (ops->memory) 187 (*ops->memory)(arg->dev, arg->context, 188 res->Data.Memory24.Minimum, 189 res->Data.Memory24.AddressLength); 190 } else { 191 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 192 "Memory24 0x%x-0x%x/%u\n", 193 res->Data.Memory24.Minimum, 194 res->Data.Memory24.Maximum, 195 res->Data.Memory24.AddressLength)); 196 if (ops->memrange) 197 (*ops->memrange)(arg->dev, arg->context, 198 res->Data.Memory24.Minimum, 199 res->Data.Memory24.Maximum, 200 res->Data.Memory24.AddressLength, 201 res->Data.Memory24.Alignment); 202 } 203 break; 204 205 case ACPI_RESOURCE_TYPE_IRQ: 206 for (i = 0; i < res->Data.Irq.InterruptCount; i++) { 207 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 208 "IRQ %u\n", 209 res->Data.Irq.Interrupts[i])); 210 if (ops->irq) 211 (*ops->irq)(arg->dev, arg->context, 212 res->Data.Irq.Interrupts[i], 213 res->Data.Irq.Triggering); 214 } 215 break; 216 217 case ACPI_RESOURCE_TYPE_DMA: 218 for (i = 0; i < res->Data.Dma.ChannelCount; i++) { 219 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 220 "DRQ %u\n", 221 res->Data.Dma.Channels[i])); 222 if (ops->drq) 223 (*ops->drq)(arg->dev, arg->context, 224 res->Data.Dma.Channels[i]); 225 } 226 break; 227 228 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 229 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 230 "Start dependent functions: %u\n", 231 res->Data.StartDpf.CompatibilityPriority)); 232 if (ops->start_dep) 233 (*ops->start_dep)(arg->dev, arg->context, 234 res->Data.StartDpf.CompatibilityPriority); 235 break; 236 237 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 238 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 239 "End dependent functions\n")); 240 if (ops->end_dep) 241 (*ops->end_dep)(arg->dev, arg->context); 242 break; 243 244 case ACPI_RESOURCE_TYPE_ADDRESS32: 245 /* XXX Only fixed size supported for now */ 246 if (res->Data.Address32.Address.AddressLength == 0 || 247 res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) 248 break; 249 #define ADDRESS32_FIXED2(r) \ 250 ((r)->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED && \ 251 (r)->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED) 252 switch (res->Data.Address32.ResourceType) { 253 case ACPI_MEMORY_RANGE: 254 if (ADDRESS32_FIXED2(res)) { 255 if (ops->memory) 256 (*ops->memory)(arg->dev, arg->context, 257 res->Data.Address32.Address.Minimum, 258 res->Data.Address32.Address.AddressLength); 259 } else { 260 if (ops->memrange) 261 (*ops->memrange)(arg->dev, arg->context, 262 res->Data.Address32.Address.Minimum, 263 res->Data.Address32.Address.Maximum, 264 res->Data.Address32.Address.AddressLength, 265 res->Data.Address32.Address.Granularity); 266 } 267 break; 268 case ACPI_IO_RANGE: 269 if (ADDRESS32_FIXED2(res)) { 270 if (ops->ioport) 271 (*ops->ioport)(arg->dev, arg->context, 272 res->Data.Address32.Address.Minimum, 273 res->Data.Address32.Address.AddressLength); 274 } else { 275 if (ops->iorange) 276 (*ops->iorange)(arg->dev, arg->context, 277 res->Data.Address32.Address.Minimum, 278 res->Data.Address32.Address.Maximum, 279 res->Data.Address32.Address.AddressLength, 280 res->Data.Address32.Address.Granularity); 281 } 282 break; 283 case ACPI_BUS_NUMBER_RANGE: 284 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 285 "Address32/BusNumber unimplemented\n")); 286 break; 287 } 288 #undef ADDRESS32_FIXED2 289 break; 290 291 case ACPI_RESOURCE_TYPE_ADDRESS16: 292 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 293 "Address16 unimplemented\n")); 294 break; 295 296 case ACPI_RESOURCE_TYPE_ADDRESS64: 297 #ifdef _LP64 298 /* XXX Only fixed size supported for now */ 299 if (res->Data.Address64.Address.AddressLength == 0 || 300 res->Data.Address64.ProducerConsumer != ACPI_CONSUMER) 301 break; 302 #define ADDRESS64_FIXED2(r) \ 303 ((r)->Data.Address64.MinAddressFixed == ACPI_ADDRESS_FIXED && \ 304 (r)->Data.Address64.MaxAddressFixed == ACPI_ADDRESS_FIXED) 305 switch (res->Data.Address64.ResourceType) { 306 case ACPI_MEMORY_RANGE: 307 if (ADDRESS64_FIXED2(res)) { 308 if (ops->memory) 309 (*ops->memory)(arg->dev, arg->context, 310 res->Data.Address64.Address.Minimum, 311 res->Data.Address64.Address.AddressLength); 312 } else { 313 if (ops->memrange) 314 (*ops->memrange)(arg->dev, arg->context, 315 res->Data.Address64.Address.Minimum, 316 res->Data.Address64.Address.Maximum, 317 res->Data.Address64.Address.AddressLength, 318 res->Data.Address64.Address.Granularity); 319 } 320 break; 321 case ACPI_IO_RANGE: 322 if (ADDRESS64_FIXED2(res)) { 323 if (ops->ioport) 324 (*ops->ioport)(arg->dev, arg->context, 325 res->Data.Address64.Address.Minimum, 326 res->Data.Address64.Address.AddressLength); 327 } else { 328 if (ops->iorange) 329 (*ops->iorange)(arg->dev, arg->context, 330 res->Data.Address64.Address.Minimum, 331 res->Data.Address64.Address.Maximum, 332 res->Data.Address64.Address.AddressLength, 333 res->Data.Address64.Address.Granularity); 334 } 335 break; 336 case ACPI_BUS_NUMBER_RANGE: 337 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 338 "Address64/BusNumber unimplemented\n")); 339 break; 340 } 341 #undef ADDRESS64_FIXED2 342 #else 343 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 344 "Address64 unimplemented\n")); 345 #endif 346 break; 347 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 348 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 349 "Extended address64 unimplemented\n")); 350 break; 351 352 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 353 if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) { 354 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 355 "ignored ExtIRQ producer\n")); 356 break; 357 } 358 for (i = 0; i < res->Data.ExtendedIrq.InterruptCount; i++) { 359 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 360 "ExtIRQ %u\n", 361 res->Data.ExtendedIrq.Interrupts[i])); 362 if (ops->irq) 363 (*ops->irq)(arg->dev, arg->context, 364 res->Data.ExtendedIrq.Interrupts[i], 365 res->Data.ExtendedIrq.Triggering); 366 } 367 break; 368 369 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 370 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 371 "GenericRegister unimplemented\n")); 372 break; 373 374 case ACPI_RESOURCE_TYPE_VENDOR: 375 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 376 "VendorSpecific unimplemented\n")); 377 break; 378 379 default: 380 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 381 "Unknown resource type: %u\n", res->Type)); 382 break; 383 } 384 385 return_ACPI_STATUS(AE_OK); 386 } 387 388 389 /* 390 * acpi_resource_parse: 391 * 392 * Parse a device node's resources and fill them in for the 393 * client. 394 * 395 * This API supports _CRS (current resources) and 396 * _PRS (possible resources). 397 * 398 * Note that it might be nice to also locate ACPI-specific resource 399 * items, such as GPE bits. 400 */ 401 ACPI_STATUS 402 acpi_resource_parse(device_t dev, ACPI_HANDLE handle, const char *path, 403 void *arg, const struct acpi_resource_parse_ops *ops) 404 { 405 struct resource_parse_callback_arg cbarg; 406 ACPI_STATUS rv; 407 408 ACPI_FUNCTION_TRACE(__func__); 409 410 if (ops->init) 411 (*ops->init)(dev, arg, &cbarg.context); 412 else 413 cbarg.context = arg; 414 cbarg.ops = ops; 415 cbarg.dev = dev; 416 417 rv = AcpiWalkResources(handle, path, acpi_resource_parse_callback, 418 &cbarg); 419 if (ACPI_FAILURE(rv)) { 420 aprint_error_dev(dev, "ACPI: unable to get %s resources: %s\n", 421 path, AcpiFormatException(rv)); 422 return_ACPI_STATUS(rv); 423 } 424 425 if (ops->fini) 426 (*ops->fini)(dev, cbarg.context); 427 428 return_ACPI_STATUS(AE_OK); 429 } 430 431 /* 432 * acpi_resource_print: 433 * 434 * Print the resources assigned to a device. 435 */ 436 void 437 acpi_resource_print(device_t dev, struct acpi_resources *res) 438 { 439 const char *sep; 440 441 if (SIMPLEQ_EMPTY(&res->ar_io) && 442 SIMPLEQ_EMPTY(&res->ar_iorange) && 443 SIMPLEQ_EMPTY(&res->ar_mem) && 444 SIMPLEQ_EMPTY(&res->ar_memrange) && 445 SIMPLEQ_EMPTY(&res->ar_irq) && 446 SIMPLEQ_EMPTY(&res->ar_drq)) 447 return; 448 449 aprint_normal(":"); 450 451 if (SIMPLEQ_EMPTY(&res->ar_io) == 0) { 452 struct acpi_io *ar; 453 454 sep = ""; 455 aprint_normal(" io "); 456 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) { 457 aprint_normal("%s0x%x", sep, ar->ar_base); 458 if (ar->ar_length > 1) 459 aprint_normal("-0x%x", ar->ar_base + 460 ar->ar_length - 1); 461 sep = ","; 462 } 463 } 464 465 /* XXX iorange */ 466 467 if (SIMPLEQ_EMPTY(&res->ar_mem) == 0) { 468 struct acpi_mem *ar; 469 470 sep = ""; 471 aprint_normal(" mem "); 472 SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) { 473 aprint_normal("%s0x%" PRIx64, sep, 474 (uint64_t)ar->ar_base); 475 if (ar->ar_length > 1) 476 aprint_normal("-0x%" PRIx64, 477 (uint64_t)ar->ar_base + 478 ar->ar_length - 1); 479 sep = ","; 480 } 481 } 482 483 /* XXX memrange */ 484 485 if (SIMPLEQ_EMPTY(&res->ar_irq) == 0) { 486 struct acpi_irq *ar; 487 488 sep = ""; 489 aprint_normal(" irq "); 490 SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) { 491 aprint_normal("%s%d", sep, ar->ar_irq); 492 sep = ","; 493 } 494 } 495 496 if (SIMPLEQ_EMPTY(&res->ar_drq) == 0) { 497 struct acpi_drq *ar; 498 499 sep = ""; 500 aprint_normal(" drq "); 501 SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) { 502 aprint_normal("%s%d", sep, ar->ar_drq); 503 sep = ","; 504 } 505 } 506 507 aprint_normal("\n"); 508 aprint_naive("\n"); 509 } 510 511 /* 512 * acpi_resource_cleanup: 513 * 514 * Free all allocated buffers 515 */ 516 void 517 acpi_resource_cleanup(struct acpi_resources *res) 518 { 519 while (!SIMPLEQ_EMPTY(&res->ar_io)) { 520 struct acpi_io *ar; 521 ar = SIMPLEQ_FIRST(&res->ar_io); 522 SIMPLEQ_REMOVE_HEAD(&res->ar_io, ar_list); 523 ACPI_FREE(ar); 524 } 525 526 while (!SIMPLEQ_EMPTY(&res->ar_iorange)) { 527 struct acpi_iorange *ar; 528 ar = SIMPLEQ_FIRST(&res->ar_iorange); 529 SIMPLEQ_REMOVE_HEAD(&res->ar_iorange, ar_list); 530 ACPI_FREE(ar); 531 } 532 533 while (!SIMPLEQ_EMPTY(&res->ar_mem)) { 534 struct acpi_mem *ar; 535 ar = SIMPLEQ_FIRST(&res->ar_mem); 536 SIMPLEQ_REMOVE_HEAD(&res->ar_mem, ar_list); 537 ACPI_FREE(ar); 538 } 539 540 while (!SIMPLEQ_EMPTY(&res->ar_memrange)) { 541 struct acpi_memrange *ar; 542 ar = SIMPLEQ_FIRST(&res->ar_memrange); 543 SIMPLEQ_REMOVE_HEAD(&res->ar_memrange, ar_list); 544 ACPI_FREE(ar); 545 } 546 547 while (!SIMPLEQ_EMPTY(&res->ar_irq)) { 548 struct acpi_irq *ar; 549 ar = SIMPLEQ_FIRST(&res->ar_irq); 550 SIMPLEQ_REMOVE_HEAD(&res->ar_irq, ar_list); 551 ACPI_FREE(ar); 552 } 553 554 while (!SIMPLEQ_EMPTY(&res->ar_drq)) { 555 struct acpi_drq *ar; 556 ar = SIMPLEQ_FIRST(&res->ar_drq); 557 SIMPLEQ_REMOVE_HEAD(&res->ar_drq, ar_list); 558 ACPI_FREE(ar); 559 } 560 561 res->ar_nio = res->ar_niorange = res->ar_nmem = 562 res->ar_nmemrange = res->ar_nirq = res->ar_ndrq = 0; 563 } 564 565 struct acpi_io * 566 acpi_res_io(struct acpi_resources *res, int idx) 567 { 568 struct acpi_io *ar; 569 570 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) { 571 if (ar->ar_index == idx) 572 return ar; 573 } 574 return NULL; 575 } 576 577 struct acpi_iorange * 578 acpi_res_iorange(struct acpi_resources *res, int idx) 579 { 580 struct acpi_iorange *ar; 581 582 SIMPLEQ_FOREACH(ar, &res->ar_iorange, ar_list) { 583 if (ar->ar_index == idx) 584 return ar; 585 } 586 return NULL; 587 } 588 589 struct acpi_mem * 590 acpi_res_mem(struct acpi_resources *res, int idx) 591 { 592 struct acpi_mem *ar; 593 594 SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) { 595 if (ar->ar_index == idx) 596 return ar; 597 } 598 return NULL; 599 } 600 601 struct acpi_memrange * 602 acpi_res_memrange(struct acpi_resources *res, int idx) 603 { 604 struct acpi_memrange *ar; 605 606 SIMPLEQ_FOREACH(ar, &res->ar_memrange, ar_list) { 607 if (ar->ar_index == idx) 608 return ar; 609 } 610 return NULL; 611 } 612 613 struct acpi_irq * 614 acpi_res_irq(struct acpi_resources *res, int idx) 615 { 616 struct acpi_irq *ar; 617 618 SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) { 619 if (ar->ar_index == idx) 620 return ar; 621 } 622 return NULL; 623 } 624 625 struct acpi_drq * 626 acpi_res_drq(struct acpi_resources *res, int idx) 627 { 628 struct acpi_drq *ar; 629 630 SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) { 631 if (ar->ar_index == idx) 632 return ar; 633 } 634 return NULL; 635 } 636 637 /***************************************************************************** 638 * Default ACPI resource parse operations. 639 *****************************************************************************/ 640 641 static void acpi_res_parse_init(device_t, void *, void **); 642 static void acpi_res_parse_fini(device_t, void *); 643 644 static void acpi_res_parse_ioport(device_t, void *, uint32_t, 645 uint32_t); 646 static void acpi_res_parse_iorange(device_t, void *, uint32_t, 647 uint32_t, uint32_t, uint32_t); 648 649 static void acpi_res_parse_memory(device_t, void *, uint64_t, 650 uint64_t); 651 static void acpi_res_parse_memrange(device_t, void *, uint64_t, 652 uint64_t, uint64_t, uint64_t); 653 654 static void acpi_res_parse_irq(device_t, void *, uint32_t, uint32_t); 655 static void acpi_res_parse_drq(device_t, void *, uint32_t); 656 657 static void acpi_res_parse_start_dep(device_t, void *, int); 658 static void acpi_res_parse_end_dep(device_t, void *); 659 660 const struct acpi_resource_parse_ops acpi_resource_parse_ops_default = { 661 .init = acpi_res_parse_init, 662 .fini = acpi_res_parse_fini, 663 664 .ioport = acpi_res_parse_ioport, 665 .iorange = acpi_res_parse_iorange, 666 667 .memory = acpi_res_parse_memory, 668 .memrange = acpi_res_parse_memrange, 669 670 .irq = acpi_res_parse_irq, 671 .drq = acpi_res_parse_drq, 672 673 .start_dep = acpi_res_parse_start_dep, 674 .end_dep = acpi_res_parse_end_dep, 675 }; 676 677 const struct acpi_resource_parse_ops acpi_resource_parse_ops_quiet = { 678 .init = acpi_res_parse_init, 679 .fini = NULL, 680 681 .ioport = acpi_res_parse_ioport, 682 .iorange = acpi_res_parse_iorange, 683 684 .memory = acpi_res_parse_memory, 685 .memrange = acpi_res_parse_memrange, 686 687 .irq = acpi_res_parse_irq, 688 .drq = acpi_res_parse_drq, 689 690 .start_dep = acpi_res_parse_start_dep, 691 .end_dep = acpi_res_parse_end_dep, 692 }; 693 694 static void 695 acpi_res_parse_init(device_t dev, void *arg, void **contextp) 696 { 697 struct acpi_resources *res = arg; 698 699 SIMPLEQ_INIT(&res->ar_io); 700 res->ar_nio = 0; 701 702 SIMPLEQ_INIT(&res->ar_iorange); 703 res->ar_niorange = 0; 704 705 SIMPLEQ_INIT(&res->ar_mem); 706 res->ar_nmem = 0; 707 708 SIMPLEQ_INIT(&res->ar_memrange); 709 res->ar_nmemrange = 0; 710 711 SIMPLEQ_INIT(&res->ar_irq); 712 res->ar_nirq = 0; 713 714 SIMPLEQ_INIT(&res->ar_drq); 715 res->ar_ndrq = 0; 716 717 *contextp = res; 718 } 719 720 static void 721 acpi_res_parse_fini(device_t dev, void *context) 722 { 723 struct acpi_resources *res = context; 724 725 /* Print the resources we're using. */ 726 acpi_resource_print(dev, res); 727 } 728 729 static void 730 acpi_res_parse_ioport(device_t dev, void *context, uint32_t base, 731 uint32_t length) 732 { 733 struct acpi_resources *res = context; 734 struct acpi_io *ar; 735 736 /* 737 * Check if there is another I/O port directly below/under 738 * this one. 739 */ 740 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) { 741 if (ar->ar_base == base + length ) { 742 /* 743 * Entry just below existing entry - adjust 744 * the entry and return. 745 */ 746 ar->ar_base = base; 747 ar->ar_length += length; 748 return; 749 } else if (ar->ar_base + ar->ar_length == base) { 750 /* 751 * Entry just above existing entry - adjust 752 * the entry and return. 753 */ 754 ar->ar_length += length; 755 return; 756 } 757 } 758 759 ar = ACPI_ALLOCATE(sizeof(*ar)); 760 if (ar == NULL) { 761 aprint_error_dev(dev, "ACPI: unable to allocate I/O resource %d\n", 762 res->ar_nio); 763 res->ar_nio++; 764 return; 765 } 766 767 ar->ar_index = res->ar_nio++; 768 ar->ar_base = base; 769 ar->ar_length = length; 770 771 SIMPLEQ_INSERT_TAIL(&res->ar_io, ar, ar_list); 772 } 773 774 static void 775 acpi_res_parse_iorange(device_t dev, void *context, uint32_t low, 776 uint32_t high, uint32_t length, uint32_t align) 777 { 778 struct acpi_resources *res = context; 779 struct acpi_iorange *ar; 780 781 ar = ACPI_ALLOCATE(sizeof(*ar)); 782 if (ar == NULL) { 783 aprint_error_dev(dev, "ACPI: unable to allocate I/O range resource %d\n", 784 res->ar_niorange); 785 res->ar_niorange++; 786 return; 787 } 788 789 ar->ar_index = res->ar_niorange++; 790 ar->ar_low = low; 791 ar->ar_high = high; 792 ar->ar_length = length; 793 ar->ar_align = align; 794 795 SIMPLEQ_INSERT_TAIL(&res->ar_iorange, ar, ar_list); 796 } 797 798 static void 799 acpi_res_parse_memory(device_t dev, void *context, uint64_t base, 800 uint64_t length) 801 { 802 struct acpi_resources *res = context; 803 struct acpi_mem *ar; 804 805 ar = ACPI_ALLOCATE(sizeof(*ar)); 806 if (ar == NULL) { 807 aprint_error_dev(dev, "ACPI: unable to allocate Memory resource %d\n", 808 res->ar_nmem); 809 res->ar_nmem++; 810 return; 811 } 812 813 ar->ar_index = res->ar_nmem++; 814 ar->ar_base = base; 815 ar->ar_length = length; 816 817 SIMPLEQ_INSERT_TAIL(&res->ar_mem, ar, ar_list); 818 } 819 820 static void 821 acpi_res_parse_memrange(device_t dev, void *context, uint64_t low, 822 uint64_t high, uint64_t length, uint64_t align) 823 { 824 struct acpi_resources *res = context; 825 struct acpi_memrange *ar; 826 827 ar = ACPI_ALLOCATE(sizeof(*ar)); 828 if (ar == NULL) { 829 aprint_error_dev(dev, "ACPI: unable to allocate Memory range resource %d\n", 830 res->ar_nmemrange); 831 res->ar_nmemrange++; 832 return; 833 } 834 835 ar->ar_index = res->ar_nmemrange++; 836 ar->ar_low = low; 837 ar->ar_high = high; 838 ar->ar_length = length; 839 ar->ar_align = align; 840 841 SIMPLEQ_INSERT_TAIL(&res->ar_memrange, ar, ar_list); 842 } 843 844 static void 845 acpi_res_parse_irq(device_t dev, void *context, uint32_t irq, uint32_t type) 846 { 847 struct acpi_resources *res = context; 848 struct acpi_irq *ar; 849 850 ar = ACPI_ALLOCATE(sizeof(*ar)); 851 if (ar == NULL) { 852 aprint_error_dev(dev, "ACPI: unable to allocate IRQ resource %d\n", 853 res->ar_nirq); 854 res->ar_nirq++; 855 return; 856 } 857 858 ar->ar_index = res->ar_nirq++; 859 ar->ar_irq = irq; 860 ar->ar_type = type; 861 862 SIMPLEQ_INSERT_TAIL(&res->ar_irq, ar, ar_list); 863 } 864 865 static void 866 acpi_res_parse_drq(device_t dev, void *context, uint32_t drq) 867 { 868 struct acpi_resources *res = context; 869 struct acpi_drq *ar; 870 871 ar = ACPI_ALLOCATE(sizeof(*ar)); 872 if (ar == NULL) { 873 aprint_error_dev(dev, "ACPI: unable to allocate DRQ resource %d\n", 874 res->ar_ndrq); 875 res->ar_ndrq++; 876 return; 877 } 878 879 ar->ar_index = res->ar_ndrq++; 880 ar->ar_drq = drq; 881 882 SIMPLEQ_INSERT_TAIL(&res->ar_drq, ar, ar_list); 883 } 884 885 static void 886 acpi_res_parse_start_dep(device_t dev, void *context, 887 int preference) 888 { 889 890 aprint_error_dev(dev, "ACPI: dependent functions not supported\n"); 891 } 892 893 static void 894 acpi_res_parse_end_dep(device_t dev, void *context) 895 { 896 897 /* Nothing to do. */ 898 } 899