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