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