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 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 int i; 67 void *context; 68 69 FUNCTION_TRACE(__func__); 70 71 /* 72 * Special-case some devices that abuse _PRS/_CRS to mean 73 * something other than "I consume this resource". 74 * 75 * XXX do we really need this? It's only relevant once 76 * we start always-allocating these resources, and even 77 * then, the only special-cased device is likely to be 78 * the PCI interrupt link. 79 */ 80 81 /* 82 * Fetch the device's current resources. 83 */ 84 if (((status = acpi_GetIntoBuffer(handle, AcpiGetCurrentResources, &buf)) != AE_OK)) { 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 for (i = 0; i < res->Data.Irq.NumberOfInterrupts; i++) { 202 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Irq %d\n", 203 res->Data.Irq.Interrupts[i])); 204 set->set_irq(dev, context, 205 res->Data.Irq.Interrupts[i]); 206 } 207 break; 208 209 case ACPI_RSTYPE_DMA: 210 for (i = 0; i < res->Data.Dma.NumberOfChannels; i++) { 211 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Drq %d\n", 212 res->Data.Dma.Channels[i])); 213 set->set_drq(dev, context, 214 res->Data.Dma.Channels[i]); 215 } 216 break; 217 218 case ACPI_RSTYPE_START_DPF: 219 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependant functions\n")); 220 set->set_start_dependant(dev, context, 221 res->Data.StartDpf.CompatibilityPriority); 222 break; 223 224 case ACPI_RSTYPE_END_DPF: 225 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependant functions\n")); 226 set->set_end_dependant(dev, context); 227 break; 228 229 case ACPI_RSTYPE_ADDRESS32: 230 if (res->Data.Address32.AddressLength <= 0) 231 break; 232 if (res->Data.Address32.ProducerConsumer != CONSUMER) { 233 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored Address32 %s producer\n", 234 (res->Data.Address32.ResourceType == IO_RANGE) ? 235 "IO" : "Memory")); 236 break; 237 } 238 if ((res->Data.Address32.ResourceType != MEMORY_RANGE) || 239 (res->Data.Address32.ResourceType != IO_RANGE)) { 240 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 241 "ignored Address32 for non-memory, non-I/O\n")); 242 break; 243 } 244 245 if ((res->Data.Address32.MinAddressFixed == ADDRESS_FIXED) && 246 (res->Data.Address32.MaxAddressFixed == ADDRESS_FIXED)) { 247 if (res->Data.Address32.ResourceType == MEMORY_RANGE) { 248 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/Memory 0x%x/%d\n", 249 res->Data.Address32.MinAddressRange, 250 res->Data.Address32.AddressLength)); 251 set->set_memory(dev, context, 252 res->Data.Address32.MinAddressRange, 253 res->Data.Address32.AddressLength); 254 } else { 255 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/IO 0x%x/%d\n", 256 res->Data.Address32.MinAddressRange, 257 res->Data.Address32.AddressLength)); 258 set->set_ioport(dev, context, 259 res->Data.Address32.MinAddressRange, 260 res->Data.Address32.AddressLength); 261 } 262 } else { 263 if (res->Data.Address32.ResourceType == MEMORY_RANGE) { 264 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/Memory 0x%x-0x%x/%d\n", 265 res->Data.Address32.MinAddressRange, 266 res->Data.Address32.MaxAddressRange, 267 res->Data.Address32.AddressLength)); 268 set->set_memoryrange(dev, context, 269 res->Data.Address32.MinAddressRange, 270 res->Data.Address32.MaxAddressRange, 271 res->Data.Address32.AddressLength, 272 res->Data.Address32.Granularity); 273 } else { 274 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/IO 0x%x-0x%x/%d\n", 275 res->Data.Address32.MinAddressRange, 276 res->Data.Address32.MaxAddressRange, 277 res->Data.Address32.AddressLength)); 278 set->set_iorange(dev, context, 279 res->Data.Address32.MinAddressRange, 280 res->Data.Address32.MaxAddressRange, 281 res->Data.Address32.AddressLength, 282 res->Data.Address32.Granularity); 283 } 284 } 285 break; 286 287 case ACPI_RSTYPE_ADDRESS16: 288 if (res->Data.Address16.AddressLength <= 0) 289 break; 290 if (res->Data.Address16.ProducerConsumer != CONSUMER) { 291 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored Address16 %s producer\n", 292 (res->Data.Address16.ResourceType == IO_RANGE) ? 293 "IO" : "Memory")); 294 break; 295 } 296 if ((res->Data.Address16.ResourceType != MEMORY_RANGE) || 297 (res->Data.Address16.ResourceType != IO_RANGE)) { 298 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 299 "ignored Address16 for non-memory, non-I/O\n")); 300 break; 301 } 302 303 if ((res->Data.Address16.MinAddressFixed == ADDRESS_FIXED) && 304 (res->Data.Address16.MaxAddressFixed == ADDRESS_FIXED)) { 305 if (res->Data.Address16.ResourceType == MEMORY_RANGE) { 306 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/Memory 0x%x/%d\n", 307 res->Data.Address16.MinAddressRange, 308 res->Data.Address16.AddressLength)); 309 set->set_memory(dev, context, 310 res->Data.Address16.MinAddressRange, 311 res->Data.Address16.AddressLength); 312 } else { 313 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/IO 0x%x/%d\n", 314 res->Data.Address16.MinAddressRange, 315 res->Data.Address16.AddressLength)); 316 set->set_ioport(dev, context, 317 res->Data.Address16.MinAddressRange, 318 res->Data.Address16.AddressLength); 319 } 320 } else { 321 if (res->Data.Address16.ResourceType == MEMORY_RANGE) { 322 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/Memory 0x%x-0x%x/%d\n", 323 res->Data.Address16.MinAddressRange, 324 res->Data.Address16.MaxAddressRange, 325 res->Data.Address16.AddressLength)); 326 set->set_memoryrange(dev, context, 327 res->Data.Address16.MinAddressRange, 328 res->Data.Address16.MaxAddressRange, 329 res->Data.Address16.AddressLength, 330 res->Data.Address16.Granularity); 331 } else { 332 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/IO 0x%x-0x%x/%d\n", 333 res->Data.Address16.MinAddressRange, 334 res->Data.Address16.MaxAddressRange, 335 res->Data.Address16.AddressLength)); 336 set->set_iorange(dev, context, 337 res->Data.Address16.MinAddressRange, 338 res->Data.Address16.MaxAddressRange, 339 res->Data.Address16.AddressLength, 340 res->Data.Address16.Granularity); 341 } 342 } 343 break; 344 345 case ACPI_RSTYPE_ADDRESS64: 346 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "unimplemented Address64 resource\n")); 347 break; 348 349 case ACPI_RSTYPE_EXT_IRQ: 350 /* XXX special handling? */ 351 for (i = 0; i < res->Data.ExtendedIrq.NumberOfInterrupts; i++) { 352 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ExtIrq %d\n", 353 res->Data.ExtendedIrq.Interrupts[i])); 354 set->set_irq(dev, context, 355 res->Data.ExtendedIrq.Interrupts[i]); 356 } 357 break; 358 359 case ACPI_RSTYPE_VENDOR: 360 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "unimplemented VendorSpecific resource\n")); 361 break; 362 default: 363 break; 364 } 365 } 366 AcpiOsFree(buf.Pointer); 367 set->set_done(dev, context); 368 return_ACPI_STATUS(AE_OK); 369 } 370 371 /* 372 * Resource-set vectors used to attach _CRS-derived resources 373 * to an ACPI device. 374 */ 375 static void acpi_res_set_init(device_t dev, void **context); 376 static void acpi_res_set_done(device_t dev, void *context); 377 static void acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length); 378 static void acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high, 379 u_int32_t length, u_int32_t align); 380 static void acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length); 381 static void acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high, 382 u_int32_t length, u_int32_t align); 383 static void acpi_res_set_irq(device_t dev, void *context, u_int32_t irq); 384 static void acpi_res_set_drq(device_t dev, void *context, u_int32_t drq); 385 static void acpi_res_set_start_dependant(device_t dev, void *context, int preference); 386 static void acpi_res_set_end_dependant(device_t dev, void *context); 387 388 struct acpi_parse_resource_set acpi_res_parse_set = { 389 acpi_res_set_init, 390 acpi_res_set_done, 391 acpi_res_set_ioport, 392 acpi_res_set_iorange, 393 acpi_res_set_memory, 394 acpi_res_set_memoryrange, 395 acpi_res_set_irq, 396 acpi_res_set_drq, 397 acpi_res_set_start_dependant, 398 acpi_res_set_end_dependant 399 }; 400 401 struct acpi_res_context { 402 int ar_nio; 403 int ar_nmem; 404 int ar_nirq; 405 int ar_ndrq; 406 }; 407 408 static void 409 acpi_res_set_init(device_t dev, void **context) 410 { 411 struct acpi_res_context *cp; 412 413 if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) { 414 bzero(cp, sizeof(*cp)); 415 *context = cp; 416 } 417 } 418 419 static void 420 acpi_res_set_done(device_t dev, void *context) 421 { 422 struct acpi_res_context *cp = (struct acpi_res_context *)context; 423 424 if (cp == NULL) 425 return; 426 AcpiOsFree(cp); 427 } 428 429 static void 430 acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length) 431 { 432 struct acpi_res_context *cp = (struct acpi_res_context *)context; 433 434 if (cp == NULL) 435 return; 436 bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length); 437 } 438 439 static void 440 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) 441 { 442 struct acpi_res_context *cp = (struct acpi_res_context *)context; 443 444 if (cp == NULL) 445 return; 446 device_printf(dev, "I/O range not supported\n"); 447 } 448 449 static void 450 acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length) 451 { 452 struct acpi_res_context *cp = (struct acpi_res_context *)context; 453 454 if (cp == NULL) 455 return; 456 bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length); 457 } 458 459 static void 460 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) 461 { 462 struct acpi_res_context *cp = (struct acpi_res_context *)context; 463 464 if (cp == NULL) 465 return; 466 device_printf(dev, "memory range not supported\n"); 467 } 468 469 static void 470 acpi_res_set_irq(device_t dev, void *context, u_int32_t irq) 471 { 472 struct acpi_res_context *cp = (struct acpi_res_context *)context; 473 474 if (cp == NULL) 475 return; 476 bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq, 1); 477 } 478 479 static void 480 acpi_res_set_drq(device_t dev, void *context, u_int32_t drq) 481 { 482 struct acpi_res_context *cp = (struct acpi_res_context *)context; 483 484 if (cp == NULL) 485 return; 486 bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, drq, 1); 487 } 488 489 static void 490 acpi_res_set_start_dependant(device_t dev, void *context, int preference) 491 { 492 struct acpi_res_context *cp = (struct acpi_res_context *)context; 493 494 if (cp == NULL) 495 return; 496 device_printf(dev, "dependant functions not supported\n"); 497 } 498 499 static void 500 acpi_res_set_end_dependant(device_t dev, void *context) 501 { 502 struct acpi_res_context *cp = (struct acpi_res_context *)context; 503 504 if (cp == NULL) 505 return; 506 } 507 508 /* 509 * Resource-owning placeholders. 510 * 511 * This code "owns" system resource objects that aren't 512 * otherwise useful to devices, and which shouldn't be 513 * considered "free". 514 * 515 * Note that some systems claim *all* of the physical address space 516 * with a PNP0C01 device, so we cannot correctly "own" system memory 517 * here (must be done in the SMAP handler on x86 systems, for 518 * example). 519 */ 520 521 static int acpi_sysresource_probe(device_t dev); 522 static int acpi_sysresource_attach(device_t dev); 523 524 static device_method_t acpi_sysresource_methods[] = { 525 /* Device interface */ 526 DEVMETHOD(device_probe, acpi_sysresource_probe), 527 DEVMETHOD(device_attach, acpi_sysresource_attach), 528 529 {0, 0} 530 }; 531 532 static driver_t acpi_sysresource_driver = { 533 "acpi_sysresource", 534 acpi_sysresource_methods, 535 0, 536 }; 537 538 static devclass_t acpi_sysresource_devclass; 539 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysresource_driver, acpi_sysresource_devclass, 0, 0); 540 541 static int 542 acpi_sysresource_probe(device_t dev) 543 { 544 if (acpi_disabled("sysresource")) 545 return(ENXIO); 546 if (acpi_MatchHid(dev, "PNP0C02")) { 547 device_set_desc(dev, "system resource"); 548 } else { 549 return(ENXIO); 550 } 551 device_quiet(dev); 552 return(-100); 553 } 554 555 static int 556 acpi_sysresource_attach(device_t dev) 557 { 558 struct resource *res; 559 int i, rid; 560 561 /* 562 * Suck up all the resources that might have been assigned to us. 563 * Note that it's impossible to tell the difference between a 564 * resource that someone else has claimed, and one that doesn't 565 * exist. 566 */ 567 for (i = 0; i < 100; i++) { 568 rid = i; 569 res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 0); 570 rid = i; 571 res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, 0); 572 rid = i; 573 res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE); 574 } 575 return(0); 576 } 577