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