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 void *context; 67 68 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 if (((status = acpi_GetIntoBuffer(handle, AcpiGetCurrentResources, &buf)) != AE_OK)) { 84 if (status != AE_NOT_FOUND) 85 printf("can't fetch resources for %s - %s\n", 86 acpi_name(handle), AcpiFormatException(status)); 87 return_ACPI_STATUS(status); 88 } 89 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s - got %d bytes of resources\n", 90 acpi_name(handle), buf.Length)); 91 set->set_init(dev, &context); 92 93 /* 94 * Iterate through the resources 95 */ 96 curr = buf.Pointer; 97 last = (char *)buf.Pointer + buf.Length; 98 while (curr < last) { 99 res = (ACPI_RESOURCE *)curr; 100 curr += res->Length; 101 102 /* 103 * Handle the individual resource types 104 */ 105 switch(res->Id) { 106 case ACPI_RSTYPE_END_TAG: 107 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n")); 108 curr = last; 109 break; 110 111 case ACPI_RSTYPE_FIXED_IO: 112 if (res->Data.FixedIo.RangeLength <= 0) 113 break; 114 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n", 115 res->Data.FixedIo.BaseAddress, 116 res->Data.FixedIo.RangeLength)); 117 set->set_ioport(dev, context, 118 res->Data.FixedIo.BaseAddress, 119 res->Data.FixedIo.RangeLength); 120 break; 121 122 case ACPI_RSTYPE_IO: 123 if (res->Data.Io.RangeLength <= 0) 124 break; 125 if (res->Data.Io.MinBaseAddress == res->Data.Io.MaxBaseAddress) { 126 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n", 127 res->Data.Io.MinBaseAddress, 128 res->Data.Io.RangeLength)); 129 set->set_ioport(dev, context, 130 res->Data.Io.MinBaseAddress, 131 res->Data.Io.RangeLength); 132 } else { 133 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n", 134 res->Data.Io.MinBaseAddress, 135 res->Data.Io.MaxBaseAddress, 136 res->Data.Io.RangeLength)); 137 set->set_iorange(dev, context, 138 res->Data.Io.MinBaseAddress, 139 res->Data.Io.MaxBaseAddress, 140 res->Data.Io.RangeLength, res->Data.Io.Alignment); 141 } 142 break; 143 144 case ACPI_RSTYPE_FIXED_MEM32: 145 if (res->Data.FixedMemory32.RangeLength <= 0) 146 break; 147 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n", 148 res->Data.FixedMemory32.RangeBaseAddress, 149 res->Data.FixedMemory32.RangeLength)); 150 set->set_memory(dev, context, res->Data.FixedMemory32.RangeBaseAddress, 151 res->Data.FixedMemory32.RangeLength); 152 break; 153 154 case ACPI_RSTYPE_MEM32: 155 if (res->Data.Memory32.RangeLength <= 0) 156 break; 157 if (res->Data.Memory32.MinBaseAddress == res->Data.Memory32.MaxBaseAddress) { 158 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n", 159 res->Data.Memory32.MinBaseAddress, 160 res->Data.Memory32.RangeLength)); 161 set->set_memory(dev, context, 162 res->Data.Memory32.MinBaseAddress, 163 res->Data.Memory32.RangeLength); 164 } else { 165 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n", 166 res->Data.Memory32.MinBaseAddress, 167 res->Data.Memory32.MaxBaseAddress, 168 res->Data.Memory32.RangeLength)); 169 set->set_memoryrange(dev, context, 170 res->Data.Memory32.MinBaseAddress, 171 res->Data.Memory32.MaxBaseAddress, 172 res->Data.Memory32.RangeLength, 173 res->Data.Memory32.Alignment); 174 } 175 break; 176 177 case ACPI_RSTYPE_MEM24: 178 if (res->Data.Memory24.RangeLength <= 0) 179 break; 180 if (res->Data.Memory24.MinBaseAddress == res->Data.Memory24.MaxBaseAddress) { 181 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n", 182 res->Data.Memory24.MinBaseAddress, 183 res->Data.Memory24.RangeLength)); 184 set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress, 185 res->Data.Memory24.RangeLength); 186 } else { 187 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n", 188 res->Data.Memory24.MinBaseAddress, 189 res->Data.Memory24.MaxBaseAddress, 190 res->Data.Memory24.RangeLength)); 191 set->set_memoryrange(dev, context, 192 res->Data.Memory24.MinBaseAddress, 193 res->Data.Memory24.MaxBaseAddress, 194 res->Data.Memory24.RangeLength, 195 res->Data.Memory24.Alignment); 196 } 197 break; 198 199 case ACPI_RSTYPE_IRQ: 200 /* 201 * from 1.0b 6.4.2 202 * "This structure is repeated for each separate interrupt 203 * required" 204 */ 205 set->set_irq(dev, context, res->Data.Irq.Interrupts, 206 res->Data.Irq.NumberOfInterrupts); 207 break; 208 209 case ACPI_RSTYPE_DMA: 210 /* 211 * from 1.0b 6.4.3 212 * "This structure is repeated for each separate dma channel 213 * required" 214 */ 215 216 set->set_drq(dev, context, res->Data.Dma.Channels, 217 res->Data.Dma.NumberOfChannels); 218 break; 219 220 case ACPI_RSTYPE_START_DPF: 221 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependant functions\n")); 222 set->set_start_dependant(dev, context, 223 res->Data.StartDpf.CompatibilityPriority); 224 break; 225 226 case ACPI_RSTYPE_END_DPF: 227 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependant functions\n")); 228 set->set_end_dependant(dev, context); 229 break; 230 231 case ACPI_RSTYPE_ADDRESS32: 232 if (res->Data.Address32.AddressLength <= 0) 233 break; 234 if (res->Data.Address32.ProducerConsumer != CONSUMER) { 235 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored Address32 %s producer\n", 236 (res->Data.Address32.ResourceType == IO_RANGE) ? 237 "IO" : "Memory")); 238 break; 239 } 240 if ((res->Data.Address32.ResourceType != MEMORY_RANGE) || 241 (res->Data.Address32.ResourceType != IO_RANGE)) { 242 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 243 "ignored Address32 for non-memory, non-I/O\n")); 244 break; 245 } 246 247 if ((res->Data.Address32.MinAddressFixed == ADDRESS_FIXED) && 248 (res->Data.Address32.MaxAddressFixed == ADDRESS_FIXED)) { 249 if (res->Data.Address32.ResourceType == MEMORY_RANGE) { 250 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/Memory 0x%x/%d\n", 251 res->Data.Address32.MinAddressRange, 252 res->Data.Address32.AddressLength)); 253 set->set_memory(dev, context, 254 res->Data.Address32.MinAddressRange, 255 res->Data.Address32.AddressLength); 256 } else { 257 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/IO 0x%x/%d\n", 258 res->Data.Address32.MinAddressRange, 259 res->Data.Address32.AddressLength)); 260 set->set_ioport(dev, context, 261 res->Data.Address32.MinAddressRange, 262 res->Data.Address32.AddressLength); 263 } 264 } else { 265 if (res->Data.Address32.ResourceType == MEMORY_RANGE) { 266 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/Memory 0x%x-0x%x/%d\n", 267 res->Data.Address32.MinAddressRange, 268 res->Data.Address32.MaxAddressRange, 269 res->Data.Address32.AddressLength)); 270 set->set_memoryrange(dev, context, 271 res->Data.Address32.MinAddressRange, 272 res->Data.Address32.MaxAddressRange, 273 res->Data.Address32.AddressLength, 274 res->Data.Address32.Granularity); 275 } else { 276 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/IO 0x%x-0x%x/%d\n", 277 res->Data.Address32.MinAddressRange, 278 res->Data.Address32.MaxAddressRange, 279 res->Data.Address32.AddressLength)); 280 set->set_iorange(dev, context, 281 res->Data.Address32.MinAddressRange, 282 res->Data.Address32.MaxAddressRange, 283 res->Data.Address32.AddressLength, 284 res->Data.Address32.Granularity); 285 } 286 } 287 break; 288 289 case ACPI_RSTYPE_ADDRESS16: 290 if (res->Data.Address16.AddressLength <= 0) 291 break; 292 if (res->Data.Address16.ProducerConsumer != CONSUMER) { 293 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored Address16 %s producer\n", 294 (res->Data.Address16.ResourceType == IO_RANGE) ? 295 "IO" : "Memory")); 296 break; 297 } 298 if ((res->Data.Address16.ResourceType != MEMORY_RANGE) || 299 (res->Data.Address16.ResourceType != IO_RANGE)) { 300 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 301 "ignored Address16 for non-memory, non-I/O\n")); 302 break; 303 } 304 305 if ((res->Data.Address16.MinAddressFixed == ADDRESS_FIXED) && 306 (res->Data.Address16.MaxAddressFixed == ADDRESS_FIXED)) { 307 if (res->Data.Address16.ResourceType == MEMORY_RANGE) { 308 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/Memory 0x%x/%d\n", 309 res->Data.Address16.MinAddressRange, 310 res->Data.Address16.AddressLength)); 311 set->set_memory(dev, context, 312 res->Data.Address16.MinAddressRange, 313 res->Data.Address16.AddressLength); 314 } else { 315 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/IO 0x%x/%d\n", 316 res->Data.Address16.MinAddressRange, 317 res->Data.Address16.AddressLength)); 318 set->set_ioport(dev, context, 319 res->Data.Address16.MinAddressRange, 320 res->Data.Address16.AddressLength); 321 } 322 } else { 323 if (res->Data.Address16.ResourceType == MEMORY_RANGE) { 324 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/Memory 0x%x-0x%x/%d\n", 325 res->Data.Address16.MinAddressRange, 326 res->Data.Address16.MaxAddressRange, 327 res->Data.Address16.AddressLength)); 328 set->set_memoryrange(dev, context, 329 res->Data.Address16.MinAddressRange, 330 res->Data.Address16.MaxAddressRange, 331 res->Data.Address16.AddressLength, 332 res->Data.Address16.Granularity); 333 } else { 334 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/IO 0x%x-0x%x/%d\n", 335 res->Data.Address16.MinAddressRange, 336 res->Data.Address16.MaxAddressRange, 337 res->Data.Address16.AddressLength)); 338 set->set_iorange(dev, context, 339 res->Data.Address16.MinAddressRange, 340 res->Data.Address16.MaxAddressRange, 341 res->Data.Address16.AddressLength, 342 res->Data.Address16.Granularity); 343 } 344 } 345 break; 346 347 case ACPI_RSTYPE_ADDRESS64: 348 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "unimplemented Address64 resource\n")); 349 break; 350 351 case ACPI_RSTYPE_EXT_IRQ: 352 /* XXX special handling? */ 353 set->set_irq(dev, context,res->Data.ExtendedIrq.Interrupts, 354 res->Data.ExtendedIrq.NumberOfInterrupts); 355 break; 356 357 case ACPI_RSTYPE_VENDOR: 358 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "unimplemented VendorSpecific resource\n")); 359 break; 360 default: 361 break; 362 } 363 } 364 AcpiOsFree(buf.Pointer); 365 set->set_done(dev, context); 366 return_ACPI_STATUS(AE_OK); 367 } 368 369 /* 370 * Resource-set vectors used to attach _CRS-derived resources 371 * to an ACPI device. 372 */ 373 static void acpi_res_set_init(device_t dev, void **context); 374 static void acpi_res_set_done(device_t dev, void *context); 375 static void acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length); 376 static void acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high, 377 u_int32_t length, u_int32_t align); 378 static void acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length); 379 static void acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high, 380 u_int32_t length, u_int32_t align); 381 static void acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, 382 int count); 383 static void acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, 384 int count); 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 457 bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length); 458 } 459 460 static void 461 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) 462 { 463 struct acpi_res_context *cp = (struct acpi_res_context *)context; 464 465 if (cp == NULL) 466 return; 467 device_printf(dev, "memory range not supported\n"); 468 } 469 470 static void 471 acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count) 472 { 473 struct acpi_res_context *cp = (struct acpi_res_context *)context; 474 475 if (cp == NULL) 476 return; 477 if (irq == NULL) 478 return; 479 480 /*This implements no resource relocation.*/ 481 if(count != 1) 482 return; 483 484 bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1); 485 } 486 487 static void 488 acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, int count) 489 { 490 struct acpi_res_context *cp = (struct acpi_res_context *)context; 491 492 if (cp == NULL) 493 return; 494 if (drq == NULL) 495 return; 496 497 /*This implements no resource relocation.*/ 498 if(count != 1) 499 return; 500 501 bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1); 502 } 503 504 static void 505 acpi_res_set_start_dependant(device_t dev, void *context, int preference) 506 { 507 struct acpi_res_context *cp = (struct acpi_res_context *)context; 508 509 if (cp == NULL) 510 return; 511 device_printf(dev, "dependant functions not supported\n"); 512 } 513 514 static void 515 acpi_res_set_end_dependant(device_t dev, void *context) 516 { 517 struct acpi_res_context *cp = (struct acpi_res_context *)context; 518 519 if (cp == NULL) 520 return; 521 } 522 523 /* 524 * Resource-owning placeholders. 525 * 526 * This code "owns" system resource objects that aren't 527 * otherwise useful to devices, and which shouldn't be 528 * considered "free". 529 * 530 * Note that some systems claim *all* of the physical address space 531 * with a PNP0C01 device, so we cannot correctly "own" system memory 532 * here (must be done in the SMAP handler on x86 systems, for 533 * example). 534 */ 535 536 static int acpi_sysresource_probe(device_t dev); 537 static int acpi_sysresource_attach(device_t dev); 538 539 static device_method_t acpi_sysresource_methods[] = { 540 /* Device interface */ 541 DEVMETHOD(device_probe, acpi_sysresource_probe), 542 DEVMETHOD(device_attach, acpi_sysresource_attach), 543 544 {0, 0} 545 }; 546 547 static driver_t acpi_sysresource_driver = { 548 "acpi_sysresource", 549 acpi_sysresource_methods, 550 0, 551 }; 552 553 static devclass_t acpi_sysresource_devclass; 554 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysresource_driver, acpi_sysresource_devclass, 0, 0); 555 556 static int 557 acpi_sysresource_probe(device_t dev) 558 { 559 if (acpi_disabled("sysresource")) 560 return(ENXIO); 561 if (acpi_MatchHid(dev, "PNP0C02")) { 562 device_set_desc(dev, "system resource"); 563 } else { 564 return(ENXIO); 565 } 566 device_quiet(dev); 567 return(-100); 568 } 569 570 static int 571 acpi_sysresource_attach(device_t dev) 572 { 573 struct resource *res; 574 int i, rid; 575 576 /* 577 * Suck up all the resources that might have been assigned to us. 578 * Note that it's impossible to tell the difference between a 579 * resource that someone else has claimed, and one that doesn't 580 * exist. 581 */ 582 for (i = 0; i < 100; i++) { 583 rid = i; 584 res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 0); 585 rid = i; 586 res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, 0); 587 rid = i; 588 res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE); 589 } 590 return(0); 591 } 592