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$ 28 */ 29 30 #include "opt_acpi.h" 31 #include <sys/param.h> 32 #include <sys/kernel.h> 33 #include <sys/bus.h> 34 35 #include <machine/bus.h> 36 #include <machine/resource.h> 37 #include <sys/rman.h> 38 39 #include "acpi.h" 40 41 #include <dev/acpica/acpivar.h> 42 43 /* 44 * Hooks for the ACPI CA debugging infrastructure 45 */ 46 #define _COMPONENT ACPI_BUS 47 ACPI_MODULE_NAME("RESOURCE") 48 49 /* 50 * Fetch a device's resources and associate them with the device. 51 * 52 * Note that it might be nice to also locate ACPI-specific resource items, such 53 * as GPE bits. 54 * 55 * We really need to split the resource-fetching code out from the 56 * resource-parsing code, since we may want to use the parsing 57 * code for _PRS someday. 58 */ 59 ACPI_STATUS 60 acpi_parse_resources(device_t dev, ACPI_HANDLE handle, struct acpi_parse_resource_set *set) 61 { 62 ACPI_BUFFER buf; 63 ACPI_RESOURCE *res; 64 char *curr, *last; 65 ACPI_STATUS status; 66 void *context; 67 68 ACPI_FUNCTION_TRACE(__func__); 69 70 /* 71 * Special-case some devices that abuse _PRS/_CRS to mean 72 * something other than "I consume this resource". 73 * 74 * XXX do we really need this? It's only relevant once 75 * we start always-allocating these resources, and even 76 * then, the only special-cased device is likely to be 77 * the PCI interrupt link. 78 */ 79 80 /* 81 * Fetch the device's current resources. 82 */ 83 buf.Length = ACPI_ALLOCATE_BUFFER; 84 if (ACPI_FAILURE((status = AcpiGetCurrentResources(handle, &buf)))) { 85 if (status != AE_NOT_FOUND) 86 printf("can't fetch resources for %s - %s\n", 87 acpi_name(handle), AcpiFormatException(status)); 88 return_ACPI_STATUS(status); 89 } 90 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s - got %d bytes of resources\n", 91 acpi_name(handle), buf.Length)); 92 set->set_init(dev, &context); 93 94 /* 95 * Iterate through the resources 96 */ 97 curr = buf.Pointer; 98 last = (char *)buf.Pointer + buf.Length; 99 while (curr < last) { 100 res = (ACPI_RESOURCE *)curr; 101 curr += res->Length; 102 103 /* 104 * Handle the individual resource types 105 */ 106 switch(res->Id) { 107 case ACPI_RSTYPE_END_TAG: 108 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n")); 109 curr = last; 110 break; 111 112 case ACPI_RSTYPE_FIXED_IO: 113 if (res->Data.FixedIo.RangeLength <= 0) 114 break; 115 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n", 116 res->Data.FixedIo.BaseAddress, 117 res->Data.FixedIo.RangeLength)); 118 set->set_ioport(dev, context, 119 res->Data.FixedIo.BaseAddress, 120 res->Data.FixedIo.RangeLength); 121 break; 122 123 case ACPI_RSTYPE_IO: 124 if (res->Data.Io.RangeLength <= 0) 125 break; 126 if (res->Data.Io.MinBaseAddress == res->Data.Io.MaxBaseAddress) { 127 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n", 128 res->Data.Io.MinBaseAddress, 129 res->Data.Io.RangeLength)); 130 set->set_ioport(dev, context, 131 res->Data.Io.MinBaseAddress, 132 res->Data.Io.RangeLength); 133 } else { 134 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n", 135 res->Data.Io.MinBaseAddress, 136 res->Data.Io.MaxBaseAddress, 137 res->Data.Io.RangeLength)); 138 set->set_iorange(dev, context, 139 res->Data.Io.MinBaseAddress, 140 res->Data.Io.MaxBaseAddress, 141 res->Data.Io.RangeLength, res->Data.Io.Alignment); 142 } 143 break; 144 145 case ACPI_RSTYPE_FIXED_MEM32: 146 if (res->Data.FixedMemory32.RangeLength <= 0) 147 break; 148 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n", 149 res->Data.FixedMemory32.RangeBaseAddress, 150 res->Data.FixedMemory32.RangeLength)); 151 set->set_memory(dev, context, res->Data.FixedMemory32.RangeBaseAddress, 152 res->Data.FixedMemory32.RangeLength); 153 break; 154 155 case ACPI_RSTYPE_MEM32: 156 if (res->Data.Memory32.RangeLength <= 0) 157 break; 158 if (res->Data.Memory32.MinBaseAddress == res->Data.Memory32.MaxBaseAddress) { 159 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n", 160 res->Data.Memory32.MinBaseAddress, 161 res->Data.Memory32.RangeLength)); 162 set->set_memory(dev, context, 163 res->Data.Memory32.MinBaseAddress, 164 res->Data.Memory32.RangeLength); 165 } else { 166 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n", 167 res->Data.Memory32.MinBaseAddress, 168 res->Data.Memory32.MaxBaseAddress, 169 res->Data.Memory32.RangeLength)); 170 set->set_memoryrange(dev, context, 171 res->Data.Memory32.MinBaseAddress, 172 res->Data.Memory32.MaxBaseAddress, 173 res->Data.Memory32.RangeLength, 174 res->Data.Memory32.Alignment); 175 } 176 break; 177 178 case ACPI_RSTYPE_MEM24: 179 if (res->Data.Memory24.RangeLength <= 0) 180 break; 181 if (res->Data.Memory24.MinBaseAddress == res->Data.Memory24.MaxBaseAddress) { 182 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n", 183 res->Data.Memory24.MinBaseAddress, 184 res->Data.Memory24.RangeLength)); 185 set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress, 186 res->Data.Memory24.RangeLength); 187 } else { 188 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n", 189 res->Data.Memory24.MinBaseAddress, 190 res->Data.Memory24.MaxBaseAddress, 191 res->Data.Memory24.RangeLength)); 192 set->set_memoryrange(dev, context, 193 res->Data.Memory24.MinBaseAddress, 194 res->Data.Memory24.MaxBaseAddress, 195 res->Data.Memory24.RangeLength, 196 res->Data.Memory24.Alignment); 197 } 198 break; 199 200 case ACPI_RSTYPE_IRQ: 201 /* 202 * from 1.0b 6.4.2 203 * "This structure is repeated for each separate interrupt 204 * required" 205 */ 206 set->set_irq(dev, context, res->Data.Irq.Interrupts, 207 res->Data.Irq.NumberOfInterrupts); 208 break; 209 210 case ACPI_RSTYPE_DMA: 211 /* 212 * from 1.0b 6.4.3 213 * "This structure is repeated for each separate dma channel 214 * required" 215 */ 216 217 set->set_drq(dev, context, res->Data.Dma.Channels, 218 res->Data.Dma.NumberOfChannels); 219 break; 220 221 case ACPI_RSTYPE_START_DPF: 222 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependant functions\n")); 223 set->set_start_dependant(dev, context, 224 res->Data.StartDpf.CompatibilityPriority); 225 break; 226 227 case ACPI_RSTYPE_END_DPF: 228 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependant functions\n")); 229 set->set_end_dependant(dev, context); 230 break; 231 232 case ACPI_RSTYPE_ADDRESS32: 233 if (res->Data.Address32.AddressLength <= 0) 234 break; 235 if (res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) { 236 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored Address32 %s producer\n", 237 (res->Data.Address32.ResourceType == ACPI_IO_RANGE) ? 238 "IO" : "Memory")); 239 break; 240 } 241 if ((res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE) || 242 (res->Data.Address32.ResourceType != ACPI_IO_RANGE)) { 243 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 244 "ignored Address32 for non-memory, non-I/O\n")); 245 break; 246 } 247 248 if ((res->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED) && 249 (res->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED)) { 250 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) { 251 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/Memory 0x%x/%d\n", 252 res->Data.Address32.MinAddressRange, 253 res->Data.Address32.AddressLength)); 254 set->set_memory(dev, context, 255 res->Data.Address32.MinAddressRange, 256 res->Data.Address32.AddressLength); 257 } else { 258 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/IO 0x%x/%d\n", 259 res->Data.Address32.MinAddressRange, 260 res->Data.Address32.AddressLength)); 261 set->set_ioport(dev, context, 262 res->Data.Address32.MinAddressRange, 263 res->Data.Address32.AddressLength); 264 } 265 } else { 266 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) { 267 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/Memory 0x%x-0x%x/%d\n", 268 res->Data.Address32.MinAddressRange, 269 res->Data.Address32.MaxAddressRange, 270 res->Data.Address32.AddressLength)); 271 set->set_memoryrange(dev, context, 272 res->Data.Address32.MinAddressRange, 273 res->Data.Address32.MaxAddressRange, 274 res->Data.Address32.AddressLength, 275 res->Data.Address32.Granularity); 276 } else { 277 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/IO 0x%x-0x%x/%d\n", 278 res->Data.Address32.MinAddressRange, 279 res->Data.Address32.MaxAddressRange, 280 res->Data.Address32.AddressLength)); 281 set->set_iorange(dev, context, 282 res->Data.Address32.MinAddressRange, 283 res->Data.Address32.MaxAddressRange, 284 res->Data.Address32.AddressLength, 285 res->Data.Address32.Granularity); 286 } 287 } 288 break; 289 290 case ACPI_RSTYPE_ADDRESS16: 291 if (res->Data.Address16.AddressLength <= 0) 292 break; 293 if (res->Data.Address16.ProducerConsumer != ACPI_CONSUMER) { 294 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored Address16 %s producer\n", 295 (res->Data.Address16.ResourceType == ACPI_IO_RANGE) ? 296 "IO" : "Memory")); 297 break; 298 } 299 if ((res->Data.Address16.ResourceType != ACPI_MEMORY_RANGE) || 300 (res->Data.Address16.ResourceType != ACPI_IO_RANGE)) { 301 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 302 "ignored Address16 for non-memory, non-I/O\n")); 303 break; 304 } 305 306 if ((res->Data.Address16.MinAddressFixed == ACPI_ADDRESS_FIXED) && 307 (res->Data.Address16.MaxAddressFixed == ACPI_ADDRESS_FIXED)) { 308 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) { 309 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/Memory 0x%x/%d\n", 310 res->Data.Address16.MinAddressRange, 311 res->Data.Address16.AddressLength)); 312 set->set_memory(dev, context, 313 res->Data.Address16.MinAddressRange, 314 res->Data.Address16.AddressLength); 315 } else { 316 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/IO 0x%x/%d\n", 317 res->Data.Address16.MinAddressRange, 318 res->Data.Address16.AddressLength)); 319 set->set_ioport(dev, context, 320 res->Data.Address16.MinAddressRange, 321 res->Data.Address16.AddressLength); 322 } 323 } else { 324 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) { 325 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/Memory 0x%x-0x%x/%d\n", 326 res->Data.Address16.MinAddressRange, 327 res->Data.Address16.MaxAddressRange, 328 res->Data.Address16.AddressLength)); 329 set->set_memoryrange(dev, context, 330 res->Data.Address16.MinAddressRange, 331 res->Data.Address16.MaxAddressRange, 332 res->Data.Address16.AddressLength, 333 res->Data.Address16.Granularity); 334 } else { 335 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/IO 0x%x-0x%x/%d\n", 336 res->Data.Address16.MinAddressRange, 337 res->Data.Address16.MaxAddressRange, 338 res->Data.Address16.AddressLength)); 339 set->set_iorange(dev, context, 340 res->Data.Address16.MinAddressRange, 341 res->Data.Address16.MaxAddressRange, 342 res->Data.Address16.AddressLength, 343 res->Data.Address16.Granularity); 344 } 345 } 346 break; 347 348 case ACPI_RSTYPE_ADDRESS64: 349 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "unimplemented Address64 resource\n")); 350 break; 351 352 case ACPI_RSTYPE_EXT_IRQ: 353 /* XXX special handling? */ 354 set->set_irq(dev, context,res->Data.ExtendedIrq.Interrupts, 355 res->Data.ExtendedIrq.NumberOfInterrupts); 356 break; 357 358 case ACPI_RSTYPE_VENDOR: 359 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "unimplemented VendorSpecific resource\n")); 360 break; 361 default: 362 break; 363 } 364 } 365 AcpiOsFree(buf.Pointer); 366 set->set_done(dev, context); 367 return_ACPI_STATUS(AE_OK); 368 } 369 370 /* 371 * Resource-set vectors used to attach _CRS-derived resources 372 * to an ACPI device. 373 */ 374 static void acpi_res_set_init(device_t dev, void **context); 375 static void acpi_res_set_done(device_t dev, void *context); 376 static void acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length); 377 static void acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high, 378 u_int32_t length, u_int32_t align); 379 static void acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length); 380 static void acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high, 381 u_int32_t length, u_int32_t align); 382 static void acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, 383 int count); 384 static void acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, 385 int count); 386 static void acpi_res_set_start_dependant(device_t dev, void *context, int preference); 387 static void acpi_res_set_end_dependant(device_t dev, void *context); 388 389 struct acpi_parse_resource_set acpi_res_parse_set = { 390 acpi_res_set_init, 391 acpi_res_set_done, 392 acpi_res_set_ioport, 393 acpi_res_set_iorange, 394 acpi_res_set_memory, 395 acpi_res_set_memoryrange, 396 acpi_res_set_irq, 397 acpi_res_set_drq, 398 acpi_res_set_start_dependant, 399 acpi_res_set_end_dependant 400 }; 401 402 struct acpi_res_context { 403 int ar_nio; 404 int ar_nmem; 405 int ar_nirq; 406 int ar_ndrq; 407 }; 408 409 static void 410 acpi_res_set_init(device_t dev, void **context) 411 { 412 struct acpi_res_context *cp; 413 414 if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) { 415 bzero(cp, sizeof(*cp)); 416 *context = cp; 417 } 418 } 419 420 static void 421 acpi_res_set_done(device_t dev, void *context) 422 { 423 struct acpi_res_context *cp = (struct acpi_res_context *)context; 424 425 if (cp == NULL) 426 return; 427 AcpiOsFree(cp); 428 } 429 430 static void 431 acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length) 432 { 433 struct acpi_res_context *cp = (struct acpi_res_context *)context; 434 435 if (cp == NULL) 436 return; 437 bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length); 438 } 439 440 static void 441 acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align) 442 { 443 struct acpi_res_context *cp = (struct acpi_res_context *)context; 444 445 if (cp == NULL) 446 return; 447 device_printf(dev, "I/O range not supported\n"); 448 } 449 450 static void 451 acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length) 452 { 453 struct acpi_res_context *cp = (struct acpi_res_context *)context; 454 455 if (cp == NULL) 456 return; 457 458 bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length); 459 } 460 461 static void 462 acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align) 463 { 464 struct acpi_res_context *cp = (struct acpi_res_context *)context; 465 466 if (cp == NULL) 467 return; 468 device_printf(dev, "memory range not supported\n"); 469 } 470 471 static void 472 acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count) 473 { 474 struct acpi_res_context *cp = (struct acpi_res_context *)context; 475 476 if (cp == NULL) 477 return; 478 if (irq == NULL) 479 return; 480 481 /*This implements no resource relocation.*/ 482 if(count != 1) 483 return; 484 485 bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1); 486 } 487 488 static void 489 acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, int count) 490 { 491 struct acpi_res_context *cp = (struct acpi_res_context *)context; 492 493 if (cp == NULL) 494 return; 495 if (drq == NULL) 496 return; 497 498 /*This implements no resource relocation.*/ 499 if(count != 1) 500 return; 501 502 bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1); 503 } 504 505 static void 506 acpi_res_set_start_dependant(device_t dev, void *context, int preference) 507 { 508 struct acpi_res_context *cp = (struct acpi_res_context *)context; 509 510 if (cp == NULL) 511 return; 512 device_printf(dev, "dependant functions not supported\n"); 513 } 514 515 static void 516 acpi_res_set_end_dependant(device_t dev, void *context) 517 { 518 struct acpi_res_context *cp = (struct acpi_res_context *)context; 519 520 if (cp == NULL) 521 return; 522 } 523 524 /* 525 * Resource-owning placeholders. 526 * 527 * This code "owns" system resource objects that aren't 528 * otherwise useful to devices, and which shouldn't be 529 * considered "free". 530 * 531 * Note that some systems claim *all* of the physical address space 532 * with a PNP0C01 device, so we cannot correctly "own" system memory 533 * here (must be done in the SMAP handler on x86 systems, for 534 * example). 535 */ 536 537 static int acpi_sysresource_probe(device_t dev); 538 static int acpi_sysresource_attach(device_t dev); 539 540 static device_method_t acpi_sysresource_methods[] = { 541 /* Device interface */ 542 DEVMETHOD(device_probe, acpi_sysresource_probe), 543 DEVMETHOD(device_attach, acpi_sysresource_attach), 544 545 {0, 0} 546 }; 547 548 static driver_t acpi_sysresource_driver = { 549 "acpi_sysresource", 550 acpi_sysresource_methods, 551 0, 552 }; 553 554 static devclass_t acpi_sysresource_devclass; 555 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysresource_driver, acpi_sysresource_devclass, 0, 0); 556 557 static int 558 acpi_sysresource_probe(device_t dev) 559 { 560 if (acpi_disabled("sysresource")) 561 return(ENXIO); 562 if (acpi_MatchHid(dev, "PNP0C02")) { 563 device_set_desc(dev, "system resource"); 564 } else { 565 return(ENXIO); 566 } 567 device_quiet(dev); 568 return(-100); 569 } 570 571 static int 572 acpi_sysresource_attach(device_t dev) 573 { 574 struct resource *res; 575 int i, rid; 576 577 /* 578 * Suck up all the resources that might have been assigned to us. 579 * Note that it's impossible to tell the difference between a 580 * resource that someone else has claimed, and one that doesn't 581 * exist. 582 */ 583 for (i = 0; i < 100; i++) { 584 rid = i; 585 res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 0); 586 rid = i; 587 res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, 0); 588 rid = i; 589 res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE); 590 } 591 return(0); 592 } 593