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$"); 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 <contrib/dev/acpica/include/acpi.h> 43 #include <contrib/dev/acpica/include/accommon.h> 44 45 #include <dev/acpica/acpivar.h> 46 47 /* Hooks for the ACPI CA debugging infrastructure */ 48 #define _COMPONENT ACPI_BUS 49 ACPI_MODULE_NAME("RESOURCE") 50 51 struct lookup_irq_request { 52 ACPI_RESOURCE *acpi_res; 53 struct resource *res; 54 int counter; 55 int rid; 56 int found; 57 }; 58 59 static ACPI_STATUS 60 acpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context) 61 { 62 struct lookup_irq_request *req; 63 size_t len; 64 u_int irqnum, irq; 65 66 switch (res->Type) { 67 case ACPI_RESOURCE_TYPE_IRQ: 68 irqnum = res->Data.Irq.InterruptCount; 69 irq = res->Data.Irq.Interrupts[0]; 70 len = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ); 71 break; 72 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 73 irqnum = res->Data.ExtendedIrq.InterruptCount; 74 irq = res->Data.ExtendedIrq.Interrupts[0]; 75 len = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ); 76 break; 77 default: 78 return (AE_OK); 79 } 80 if (irqnum != 1) 81 return (AE_OK); 82 req = (struct lookup_irq_request *)context; 83 if (req->counter != req->rid) { 84 req->counter++; 85 return (AE_OK); 86 } 87 req->found = 1; 88 KASSERT(irq == rman_get_start(req->res), 89 ("IRQ resources do not match")); 90 bcopy(res, req->acpi_res, len); 91 return (AE_CTRL_TERMINATE); 92 } 93 94 ACPI_STATUS 95 acpi_lookup_irq_resource(device_t dev, int rid, struct resource *res, 96 ACPI_RESOURCE *acpi_res) 97 { 98 struct lookup_irq_request req; 99 ACPI_STATUS status; 100 101 req.acpi_res = acpi_res; 102 req.res = res; 103 req.counter = 0; 104 req.rid = rid; 105 req.found = 0; 106 status = AcpiWalkResources(acpi_get_handle(dev), "_CRS", 107 acpi_lookup_irq_handler, &req); 108 if (ACPI_SUCCESS(status) && req.found == 0) 109 status = AE_NOT_FOUND; 110 return (status); 111 } 112 113 void 114 acpi_config_intr(device_t dev, ACPI_RESOURCE *res) 115 { 116 u_int irq; 117 int pol, trig; 118 119 switch (res->Type) { 120 case ACPI_RESOURCE_TYPE_IRQ: 121 KASSERT(res->Data.Irq.InterruptCount == 1, 122 ("%s: multiple interrupts", __func__)); 123 irq = res->Data.Irq.Interrupts[0]; 124 trig = res->Data.Irq.Triggering; 125 pol = res->Data.Irq.Polarity; 126 break; 127 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 128 KASSERT(res->Data.ExtendedIrq.InterruptCount == 1, 129 ("%s: multiple interrupts", __func__)); 130 irq = res->Data.ExtendedIrq.Interrupts[0]; 131 trig = res->Data.ExtendedIrq.Triggering; 132 pol = res->Data.ExtendedIrq.Polarity; 133 break; 134 default: 135 panic("%s: bad resource type %u", __func__, res->Type); 136 } 137 BUS_CONFIG_INTR(dev, irq, (trig == ACPI_EDGE_SENSITIVE) ? 138 INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ? 139 INTR_POLARITY_HIGH : INTR_POLARITY_LOW); 140 } 141 142 /* 143 * Fetch a device's resources and associate them with the device. 144 * 145 * Note that it might be nice to also locate ACPI-specific resource items, such 146 * as GPE bits. 147 * 148 * We really need to split the resource-fetching code out from the 149 * resource-parsing code, since we may want to use the parsing 150 * code for _PRS someday. 151 */ 152 ACPI_STATUS 153 acpi_parse_resources(device_t dev, ACPI_HANDLE handle, 154 struct acpi_parse_resource_set *set, void *arg) 155 { 156 ACPI_BUFFER buf; 157 ACPI_RESOURCE *res; 158 char *curr, *last; 159 ACPI_STATUS status; 160 void *context; 161 162 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 163 164 /* 165 * Special-case some devices that abuse _PRS/_CRS to mean 166 * something other than "I consume this resource". 167 * 168 * XXX do we really need this? It's only relevant once 169 * we start always-allocating these resources, and even 170 * then, the only special-cased device is likely to be 171 * the PCI interrupt link. 172 */ 173 174 /* Fetch the device's current resources. */ 175 buf.Length = ACPI_ALLOCATE_BUFFER; 176 if (ACPI_FAILURE((status = AcpiGetCurrentResources(handle, &buf)))) { 177 if (status != AE_NOT_FOUND && status != AE_TYPE) 178 printf("can't fetch resources for %s - %s\n", 179 acpi_name(handle), AcpiFormatException(status)); 180 return_ACPI_STATUS (status); 181 } 182 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s - got %ld bytes of resources\n", 183 acpi_name(handle), (long)buf.Length)); 184 set->set_init(dev, arg, &context); 185 186 /* Iterate through the resources */ 187 curr = buf.Pointer; 188 last = (char *)buf.Pointer + buf.Length; 189 while (curr < last) { 190 res = (ACPI_RESOURCE *)curr; 191 curr += res->Length; 192 193 /* Handle the individual resource types */ 194 switch(res->Type) { 195 case ACPI_RESOURCE_TYPE_END_TAG: 196 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n")); 197 curr = last; 198 break; 199 case ACPI_RESOURCE_TYPE_FIXED_IO: 200 if (res->Data.FixedIo.AddressLength <= 0) 201 break; 202 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n", 203 res->Data.FixedIo.Address, 204 res->Data.FixedIo.AddressLength)); 205 set->set_ioport(dev, context, 206 res->Data.FixedIo.Address, 207 res->Data.FixedIo.AddressLength); 208 break; 209 case ACPI_RESOURCE_TYPE_IO: 210 if (res->Data.Io.AddressLength <= 0) 211 break; 212 if (res->Data.Io.Minimum == res->Data.Io.Maximum) { 213 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n", 214 res->Data.Io.Minimum, 215 res->Data.Io.AddressLength)); 216 set->set_ioport(dev, context, 217 res->Data.Io.Minimum, 218 res->Data.Io.AddressLength); 219 } else { 220 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n", 221 res->Data.Io.Minimum, 222 res->Data.Io.Maximum, 223 res->Data.Io.AddressLength)); 224 set->set_iorange(dev, context, 225 res->Data.Io.Minimum, 226 res->Data.Io.Maximum, 227 res->Data.Io.AddressLength, 228 res->Data.Io.Alignment); 229 } 230 break; 231 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 232 if (res->Data.FixedMemory32.AddressLength <= 0) 233 break; 234 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n", 235 res->Data.FixedMemory32.Address, 236 res->Data.FixedMemory32.AddressLength)); 237 set->set_memory(dev, context, 238 res->Data.FixedMemory32.Address, 239 res->Data.FixedMemory32.AddressLength); 240 break; 241 case ACPI_RESOURCE_TYPE_MEMORY32: 242 if (res->Data.Memory32.AddressLength <= 0) 243 break; 244 if (res->Data.Memory32.Minimum == 245 res->Data.Memory32.Maximum) { 246 247 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n", 248 res->Data.Memory32.Minimum, 249 res->Data.Memory32.AddressLength)); 250 set->set_memory(dev, context, 251 res->Data.Memory32.Minimum, 252 res->Data.Memory32.AddressLength); 253 } else { 254 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n", 255 res->Data.Memory32.Minimum, 256 res->Data.Memory32.Maximum, 257 res->Data.Memory32.AddressLength)); 258 set->set_memoryrange(dev, context, 259 res->Data.Memory32.Minimum, 260 res->Data.Memory32.Maximum, 261 res->Data.Memory32.AddressLength, 262 res->Data.Memory32.Alignment); 263 } 264 break; 265 case ACPI_RESOURCE_TYPE_MEMORY24: 266 if (res->Data.Memory24.AddressLength <= 0) 267 break; 268 if (res->Data.Memory24.Minimum == 269 res->Data.Memory24.Maximum) { 270 271 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n", 272 res->Data.Memory24.Minimum, 273 res->Data.Memory24.AddressLength)); 274 set->set_memory(dev, context, res->Data.Memory24.Minimum, 275 res->Data.Memory24.AddressLength); 276 } else { 277 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n", 278 res->Data.Memory24.Minimum, 279 res->Data.Memory24.Maximum, 280 res->Data.Memory24.AddressLength)); 281 set->set_memoryrange(dev, context, 282 res->Data.Memory24.Minimum, 283 res->Data.Memory24.Maximum, 284 res->Data.Memory24.AddressLength, 285 res->Data.Memory24.Alignment); 286 } 287 break; 288 case ACPI_RESOURCE_TYPE_IRQ: 289 /* 290 * from 1.0b 6.4.2 291 * "This structure is repeated for each separate interrupt 292 * required" 293 */ 294 set->set_irq(dev, context, res->Data.Irq.Interrupts, 295 res->Data.Irq.InterruptCount, res->Data.Irq.Triggering, 296 res->Data.Irq.Polarity); 297 break; 298 case ACPI_RESOURCE_TYPE_DMA: 299 /* 300 * from 1.0b 6.4.3 301 * "This structure is repeated for each separate dma channel 302 * required" 303 */ 304 set->set_drq(dev, context, res->Data.Dma.Channels, 305 res->Data.Dma.ChannelCount); 306 break; 307 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 308 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n")); 309 set->set_start_dependent(dev, context, 310 res->Data.StartDpf.CompatibilityPriority); 311 break; 312 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 313 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n")); 314 set->set_end_dependent(dev, context); 315 break; 316 case ACPI_RESOURCE_TYPE_ADDRESS32: 317 if (res->Data.Address32.AddressLength <= 0) 318 break; 319 if (res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) { 320 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 321 "ignored Address32 %s producer\n", 322 res->Data.Address32.ResourceType == ACPI_IO_RANGE ? 323 "IO" : "Memory")); 324 break; 325 } 326 if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE && 327 res->Data.Address32.ResourceType != ACPI_IO_RANGE) { 328 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 329 "ignored Address32 for non-memory, non-I/O\n")); 330 break; 331 } 332 333 if (res->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED && 334 res->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED) { 335 336 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) { 337 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 338 "Address32/Memory 0x%x/%d\n", 339 res->Data.Address32.Minimum, 340 res->Data.Address32.AddressLength)); 341 set->set_memory(dev, context, 342 res->Data.Address32.Minimum, 343 res->Data.Address32.AddressLength); 344 } else { 345 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 346 "Address32/IO 0x%x/%d\n", 347 res->Data.Address32.Minimum, 348 res->Data.Address32.AddressLength)); 349 set->set_ioport(dev, context, 350 res->Data.Address32.Minimum, 351 res->Data.Address32.AddressLength); 352 } 353 } else { 354 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) { 355 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 356 "Address32/Memory 0x%x-0x%x/%d\n", 357 res->Data.Address32.Minimum, 358 res->Data.Address32.Maximum, 359 res->Data.Address32.AddressLength)); 360 set->set_memoryrange(dev, context, 361 res->Data.Address32.Minimum, 362 res->Data.Address32.Maximum, 363 res->Data.Address32.AddressLength, 364 res->Data.Address32.Granularity); 365 } else { 366 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 367 "Address32/IO 0x%x-0x%x/%d\n", 368 res->Data.Address32.Minimum, 369 res->Data.Address32.Maximum, 370 res->Data.Address32.AddressLength)); 371 set->set_iorange(dev, context, 372 res->Data.Address32.Minimum, 373 res->Data.Address32.Maximum, 374 res->Data.Address32.AddressLength, 375 res->Data.Address32.Granularity); 376 } 377 } 378 break; 379 case ACPI_RESOURCE_TYPE_ADDRESS16: 380 if (res->Data.Address16.AddressLength <= 0) 381 break; 382 if (res->Data.Address16.ProducerConsumer != ACPI_CONSUMER) { 383 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 384 "ignored Address16 %s producer\n", 385 res->Data.Address16.ResourceType == ACPI_IO_RANGE ? 386 "IO" : "Memory")); 387 break; 388 } 389 if (res->Data.Address16.ResourceType != ACPI_MEMORY_RANGE && 390 res->Data.Address16.ResourceType != ACPI_IO_RANGE) { 391 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 392 "ignored Address16 for non-memory, non-I/O\n")); 393 break; 394 } 395 396 if (res->Data.Address16.MinAddressFixed == ACPI_ADDRESS_FIXED && 397 res->Data.Address16.MaxAddressFixed == ACPI_ADDRESS_FIXED) { 398 399 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) { 400 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 401 "Address16/Memory 0x%x/%d\n", 402 res->Data.Address16.Minimum, 403 res->Data.Address16.AddressLength)); 404 set->set_memory(dev, context, 405 res->Data.Address16.Minimum, 406 res->Data.Address16.AddressLength); 407 } else { 408 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 409 "Address16/IO 0x%x/%d\n", 410 res->Data.Address16.Minimum, 411 res->Data.Address16.AddressLength)); 412 set->set_ioport(dev, context, 413 res->Data.Address16.Minimum, 414 res->Data.Address16.AddressLength); 415 } 416 } else { 417 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) { 418 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 419 "Address16/Memory 0x%x-0x%x/%d\n", 420 res->Data.Address16.Minimum, 421 res->Data.Address16.Maximum, 422 res->Data.Address16.AddressLength)); 423 set->set_memoryrange(dev, context, 424 res->Data.Address16.Minimum, 425 res->Data.Address16.Maximum, 426 res->Data.Address16.AddressLength, 427 res->Data.Address16.Granularity); 428 } else { 429 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 430 "Address16/IO 0x%x-0x%x/%d\n", 431 res->Data.Address16.Minimum, 432 res->Data.Address16.Maximum, 433 res->Data.Address16.AddressLength)); 434 set->set_iorange(dev, context, 435 res->Data.Address16.Minimum, 436 res->Data.Address16.Maximum, 437 res->Data.Address16.AddressLength, 438 res->Data.Address16.Granularity); 439 } 440 } 441 break; 442 case ACPI_RESOURCE_TYPE_ADDRESS64: 443 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 444 "unimplemented Address64 resource\n")); 445 break; 446 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 447 if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) { 448 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 449 "ignored ExtIRQ producer\n")); 450 break; 451 } 452 set->set_ext_irq(dev, context, res->Data.ExtendedIrq.Interrupts, 453 res->Data.ExtendedIrq.InterruptCount, 454 res->Data.ExtendedIrq.Triggering, 455 res->Data.ExtendedIrq.Polarity); 456 break; 457 case ACPI_RESOURCE_TYPE_VENDOR: 458 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 459 "unimplemented VendorSpecific resource\n")); 460 break; 461 default: 462 break; 463 } 464 } 465 466 AcpiOsFree(buf.Pointer); 467 set->set_done(dev, context); 468 return_ACPI_STATUS (AE_OK); 469 } 470 471 /* 472 * Resource-set vectors used to attach _CRS-derived resources 473 * to an ACPI device. 474 */ 475 static void acpi_res_set_init(device_t dev, void *arg, void **context); 476 static void acpi_res_set_done(device_t dev, void *context); 477 static void acpi_res_set_ioport(device_t dev, void *context, 478 u_int32_t base, u_int32_t length); 479 static void acpi_res_set_iorange(device_t dev, void *context, 480 u_int32_t low, u_int32_t high, 481 u_int32_t length, u_int32_t align); 482 static void acpi_res_set_memory(device_t dev, void *context, 483 u_int32_t base, u_int32_t length); 484 static void acpi_res_set_memoryrange(device_t dev, void *context, 485 u_int32_t low, u_int32_t high, 486 u_int32_t length, u_int32_t align); 487 static void acpi_res_set_irq(device_t dev, void *context, u_int8_t *irq, 488 int count, int trig, int pol); 489 static void acpi_res_set_ext_irq(device_t dev, void *context, 490 u_int32_t *irq, int count, int trig, int pol); 491 static void acpi_res_set_drq(device_t dev, void *context, u_int8_t *drq, 492 int count); 493 static void acpi_res_set_start_dependent(device_t dev, void *context, 494 int preference); 495 static void acpi_res_set_end_dependent(device_t dev, void *context); 496 497 struct acpi_parse_resource_set acpi_res_parse_set = { 498 acpi_res_set_init, 499 acpi_res_set_done, 500 acpi_res_set_ioport, 501 acpi_res_set_iorange, 502 acpi_res_set_memory, 503 acpi_res_set_memoryrange, 504 acpi_res_set_irq, 505 acpi_res_set_ext_irq, 506 acpi_res_set_drq, 507 acpi_res_set_start_dependent, 508 acpi_res_set_end_dependent 509 }; 510 511 struct acpi_res_context { 512 int ar_nio; 513 int ar_nmem; 514 int ar_nirq; 515 int ar_ndrq; 516 void *ar_parent; 517 }; 518 519 static void 520 acpi_res_set_init(device_t dev, void *arg, void **context) 521 { 522 struct acpi_res_context *cp; 523 524 if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) { 525 bzero(cp, sizeof(*cp)); 526 cp->ar_parent = arg; 527 *context = cp; 528 } 529 } 530 531 static void 532 acpi_res_set_done(device_t dev, void *context) 533 { 534 struct acpi_res_context *cp = (struct acpi_res_context *)context; 535 536 if (cp == NULL) 537 return; 538 AcpiOsFree(cp); 539 } 540 541 static void 542 acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, 543 u_int32_t length) 544 { 545 struct acpi_res_context *cp = (struct acpi_res_context *)context; 546 547 if (cp == NULL) 548 return; 549 bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length); 550 } 551 552 static void 553 acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, 554 u_int32_t high, u_int32_t length, u_int32_t align) 555 { 556 struct acpi_res_context *cp = (struct acpi_res_context *)context; 557 558 if (cp == NULL) 559 return; 560 device_printf(dev, "I/O range not supported\n"); 561 } 562 563 static void 564 acpi_res_set_memory(device_t dev, void *context, u_int32_t base, 565 u_int32_t length) 566 { 567 struct acpi_res_context *cp = (struct acpi_res_context *)context; 568 569 if (cp == NULL) 570 return; 571 572 bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length); 573 } 574 575 static void 576 acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, 577 u_int32_t high, u_int32_t length, u_int32_t align) 578 { 579 struct acpi_res_context *cp = (struct acpi_res_context *)context; 580 581 if (cp == NULL) 582 return; 583 device_printf(dev, "memory range not supported\n"); 584 } 585 586 static void 587 acpi_res_set_irq(device_t dev, void *context, u_int8_t *irq, int count, 588 int trig, int pol) 589 { 590 struct acpi_res_context *cp = (struct acpi_res_context *)context; 591 592 if (cp == NULL || irq == NULL) 593 return; 594 595 /* This implements no resource relocation. */ 596 if (count != 1) 597 return; 598 599 bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1); 600 } 601 602 static void 603 acpi_res_set_ext_irq(device_t dev, void *context, u_int32_t *irq, int count, 604 int trig, int pol) 605 { 606 struct acpi_res_context *cp = (struct acpi_res_context *)context; 607 608 if (cp == NULL || irq == NULL) 609 return; 610 611 /* This implements no resource relocation. */ 612 if (count != 1) 613 return; 614 615 bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1); 616 } 617 618 static void 619 acpi_res_set_drq(device_t dev, void *context, u_int8_t *drq, int count) 620 { 621 struct acpi_res_context *cp = (struct acpi_res_context *)context; 622 623 if (cp == NULL || drq == NULL) 624 return; 625 626 /* This implements no resource relocation. */ 627 if (count != 1) 628 return; 629 630 bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1); 631 } 632 633 static void 634 acpi_res_set_start_dependent(device_t dev, void *context, int preference) 635 { 636 struct acpi_res_context *cp = (struct acpi_res_context *)context; 637 638 if (cp == NULL) 639 return; 640 device_printf(dev, "dependent functions not supported\n"); 641 } 642 643 static void 644 acpi_res_set_end_dependent(device_t dev, void *context) 645 { 646 struct acpi_res_context *cp = (struct acpi_res_context *)context; 647 648 if (cp == NULL) 649 return; 650 device_printf(dev, "dependent functions not supported\n"); 651 } 652 653 /* 654 * Resource-owning placeholders for IO and memory pseudo-devices. 655 * 656 * This code allocates system resources that will be used by ACPI 657 * child devices. The acpi parent manages these resources through a 658 * private rman. 659 */ 660 661 static int acpi_sysres_rid = 100; 662 663 static int acpi_sysres_probe(device_t dev); 664 static int acpi_sysres_attach(device_t dev); 665 666 static device_method_t acpi_sysres_methods[] = { 667 /* Device interface */ 668 DEVMETHOD(device_probe, acpi_sysres_probe), 669 DEVMETHOD(device_attach, acpi_sysres_attach), 670 671 {0, 0} 672 }; 673 674 static driver_t acpi_sysres_driver = { 675 "acpi_sysresource", 676 acpi_sysres_methods, 677 0, 678 }; 679 680 static devclass_t acpi_sysres_devclass; 681 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass, 682 0, 0); 683 MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1); 684 685 static int 686 acpi_sysres_probe(device_t dev) 687 { 688 static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL }; 689 690 if (acpi_disabled("sysresource") || 691 ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids) == NULL) 692 return (ENXIO); 693 694 device_set_desc(dev, "System Resource"); 695 device_quiet(dev); 696 return (BUS_PROBE_DEFAULT); 697 } 698 699 static int 700 acpi_sysres_attach(device_t dev) 701 { 702 device_t bus; 703 struct resource_list_entry *bus_rle, *dev_rle; 704 struct resource_list *bus_rl, *dev_rl; 705 int done, type; 706 u_long start, end, count; 707 708 /* 709 * Loop through all current resources to see if the new one overlaps 710 * any existing ones. If so, grow the old one up and/or down 711 * accordingly. Discard any that are wholly contained in the old. If 712 * the resource is unique, add it to the parent. It will later go into 713 * the rman pool. 714 */ 715 bus = device_get_parent(dev); 716 dev_rl = BUS_GET_RESOURCE_LIST(bus, dev); 717 bus_rl = BUS_GET_RESOURCE_LIST(device_get_parent(bus), bus); 718 STAILQ_FOREACH(dev_rle, dev_rl, link) { 719 if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY) 720 continue; 721 722 start = dev_rle->start; 723 end = dev_rle->end; 724 count = dev_rle->count; 725 type = dev_rle->type; 726 done = FALSE; 727 728 STAILQ_FOREACH(bus_rle, bus_rl, link) { 729 if (bus_rle->type != type) 730 continue; 731 732 /* New resource wholly contained in old, discard. */ 733 if (start >= bus_rle->start && end <= bus_rle->end) 734 break; 735 736 /* New tail overlaps old head, grow existing resource downward. */ 737 if (start < bus_rle->start && end >= bus_rle->start) { 738 bus_rle->count += bus_rle->start - start; 739 bus_rle->start = start; 740 done = TRUE; 741 } 742 743 /* New head overlaps old tail, grow existing resource upward. */ 744 if (start <= bus_rle->end && end > bus_rle->end) { 745 bus_rle->count += end - bus_rle->end; 746 bus_rle->end = end; 747 done = TRUE; 748 } 749 750 /* If we adjusted the old resource, we're finished. */ 751 if (done) 752 break; 753 } 754 755 /* If we didn't merge with anything, add this resource. */ 756 if (bus_rle == NULL) 757 bus_set_resource(bus, type, acpi_sysres_rid++, start, count); 758 } 759 760 /* After merging/moving resources to the parent, free the list. */ 761 resource_list_free(dev_rl); 762 763 return (0); 764 } 765