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