1 /*- 2 * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include "opt_acpi.h" 31 #include <sys/param.h> 32 #include <sys/kernel.h> 33 #include <sys/bus.h> 34 35 #include "acpi.h" 36 #include <dev/acpica/acpivar.h> 37 #include <dev/acpica/acpi_pcibvar.h> 38 39 /* Hooks for the ACPI CA debugging infrastructure. */ 40 #define _COMPONENT ACPI_BUS 41 ACPI_MODULE_NAME("PCI_LINK") 42 43 #define MAX_POSSIBLE_INTERRUPTS 16 44 #define MAX_ISA_INTERRUPTS 16 45 #define MAX_ACPI_INTERRUPTS 255 46 47 struct acpi_pci_link_entry { 48 TAILQ_ENTRY(acpi_pci_link_entry) links; 49 ACPI_HANDLE handle; 50 UINT8 current_irq; 51 UINT8 initial_irq; 52 ACPI_RESOURCE possible_resources; 53 UINT8 number_of_interrupts; 54 UINT8 interrupts[MAX_POSSIBLE_INTERRUPTS]; 55 UINT8 sorted_irq[MAX_POSSIBLE_INTERRUPTS]; 56 int references; 57 int priority; 58 }; 59 60 TAILQ_HEAD(acpi_pci_link_entries, acpi_pci_link_entry); 61 static struct acpi_pci_link_entries acpi_pci_link_entries; 62 63 struct acpi_prt_entry { 64 TAILQ_ENTRY(acpi_prt_entry) links; 65 device_t pcidev; 66 int busno; 67 ACPI_PCI_ROUTING_TABLE prt; 68 struct acpi_pci_link_entry *pci_link; 69 }; 70 71 TAILQ_HEAD(acpi_prt_entries, acpi_prt_entry); 72 static struct acpi_prt_entries acpi_prt_entries; 73 74 static int irq_penalty[MAX_ACPI_INTERRUPTS]; 75 76 #define ACPI_STA_PRESENT 0x00000001 77 #define ACPI_STA_ENABLE 0x00000002 78 #define ACPI_STA_SHOWINUI 0x00000004 79 #define ACPI_STA_FUNCTIONAL 0x00000008 80 81 /* 82 * PCI link object management 83 */ 84 85 static void 86 acpi_pci_link_dump_polarity(UINT32 ActiveHighLow) 87 { 88 89 switch (ActiveHighLow) { 90 case ACPI_ACTIVE_HIGH: 91 printf("high,"); 92 break; 93 case ACPI_ACTIVE_LOW: 94 printf("low,"); 95 break; 96 default: 97 printf("unknown,"); 98 break; 99 } 100 } 101 102 static void 103 acpi_pci_link_dump_trigger(UINT32 EdgeLevel) 104 { 105 106 switch (EdgeLevel) { 107 case ACPI_EDGE_SENSITIVE: 108 printf("edge,"); 109 break; 110 case ACPI_LEVEL_SENSITIVE: 111 printf("level,"); 112 break; 113 default: 114 printf("unknown,"); 115 break; 116 } 117 } 118 119 static void 120 acpi_pci_link_dump_sharemode(UINT32 SharedExclusive) 121 { 122 123 switch (SharedExclusive) { 124 case ACPI_EXCLUSIVE: 125 printf("exclusive"); 126 break; 127 case ACPI_SHARED: 128 printf("sharable"); 129 break; 130 default: 131 printf("unknown"); 132 break; 133 } 134 } 135 136 static void 137 acpi_pci_link_entry_dump(struct acpi_prt_entry *entry) 138 { 139 UINT8 i; 140 ACPI_RESOURCE_IRQ *Irq; 141 ACPI_RESOURCE_EXT_IRQ *ExtIrq; 142 143 if (entry == NULL || entry->pci_link == NULL) 144 return; 145 146 printf("%s irq %3d: ", acpi_name(entry->pci_link->handle), 147 entry->pci_link->current_irq); 148 149 printf("["); 150 for (i = 0; i < entry->pci_link->number_of_interrupts; i++) 151 printf("%3d", entry->pci_link->interrupts[i]); 152 printf("] "); 153 154 switch (entry->pci_link->possible_resources.Id) { 155 case ACPI_RSTYPE_IRQ: 156 Irq = &entry->pci_link->possible_resources.Data.Irq; 157 acpi_pci_link_dump_polarity(Irq->ActiveHighLow); 158 acpi_pci_link_dump_trigger(Irq->EdgeLevel); 159 acpi_pci_link_dump_sharemode(Irq->SharedExclusive); 160 break; 161 case ACPI_RSTYPE_EXT_IRQ: 162 ExtIrq = &entry->pci_link->possible_resources.Data.ExtendedIrq; 163 acpi_pci_link_dump_polarity(ExtIrq->ActiveHighLow); 164 acpi_pci_link_dump_trigger(ExtIrq->EdgeLevel); 165 acpi_pci_link_dump_sharemode(ExtIrq->SharedExclusive); 166 break; 167 } 168 169 printf(" %d.%d.%d\n", entry->busno, 170 (int)((entry->prt.Address & 0xffff0000) >> 16), 171 (int)entry->prt.Pin); 172 } 173 174 static ACPI_STATUS 175 acpi_pci_link_get_object_status(ACPI_HANDLE handle, UINT32 *sta) 176 { 177 ACPI_DEVICE_INFO *devinfo; 178 ACPI_BUFFER buf; 179 ACPI_STATUS error; 180 181 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 182 183 if (handle == NULL || sta == NULL) { 184 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n")); 185 return_ACPI_STATUS (AE_BAD_PARAMETER); 186 } 187 188 buf.Pointer = NULL; 189 buf.Length = ACPI_ALLOCATE_BUFFER; 190 error = AcpiGetObjectInfo(handle, &buf); 191 if (ACPI_FAILURE(error)) { 192 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 193 "couldn't get object info %s - %s\n", 194 acpi_name(handle), AcpiFormatException(error))); 195 return_ACPI_STATUS (error); 196 } 197 198 devinfo = (ACPI_DEVICE_INFO *)buf.Pointer; 199 if ((devinfo->Valid & ACPI_VALID_HID) == 0 || 200 strcmp(devinfo->HardwareId.Value, "PNP0C0F") != 0) { 201 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid hardware ID - %s\n", 202 acpi_name(handle))); 203 AcpiOsFree(buf.Pointer); 204 return_ACPI_STATUS (AE_TYPE); 205 } 206 207 if ((devinfo->Valid & ACPI_VALID_STA) != 0) { 208 *sta = devinfo->CurrentStatus; 209 } else { 210 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "invalid status - %s\n", 211 acpi_name(handle))); 212 *sta = 0; 213 } 214 215 AcpiOsFree(buf.Pointer); 216 return_ACPI_STATUS (AE_OK); 217 } 218 219 static ACPI_STATUS 220 acpi_pci_link_get_irq_resources(ACPI_RESOURCE *resources, 221 UINT8 *number_of_interrupts, UINT8 interrupts[]) 222 { 223 UINT8 count; 224 UINT8 i; 225 UINT32 NumberOfInterrupts; 226 UINT32 *Interrupts; 227 228 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 229 230 if (resources == NULL || number_of_interrupts == NULL) { 231 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n")); 232 return_ACPI_STATUS (AE_BAD_PARAMETER); 233 } 234 235 *number_of_interrupts = 0; 236 NumberOfInterrupts = 0; 237 Interrupts = NULL; 238 239 if (resources->Id == ACPI_RSTYPE_START_DPF) 240 resources = ACPI_NEXT_RESOURCE(resources); 241 242 if (resources->Id != ACPI_RSTYPE_IRQ && 243 resources->Id != ACPI_RSTYPE_EXT_IRQ) { 244 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 245 "Resource is not an IRQ entry - %d\n", resources->Id)); 246 return_ACPI_STATUS (AE_TYPE); 247 } 248 249 switch (resources->Id) { 250 case ACPI_RSTYPE_IRQ: 251 NumberOfInterrupts = resources->Data.Irq.NumberOfInterrupts; 252 Interrupts = resources->Data.Irq.Interrupts; 253 break; 254 case ACPI_RSTYPE_EXT_IRQ: 255 NumberOfInterrupts = 256 resources->Data.ExtendedIrq.NumberOfInterrupts; 257 Interrupts = resources->Data.ExtendedIrq.Interrupts; 258 break; 259 } 260 261 if (NumberOfInterrupts == 0) { 262 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Blank IRQ resource\n")); 263 return_ACPI_STATUS (AE_NULL_ENTRY); 264 } 265 266 count = 0; 267 for (i = 0; i < NumberOfInterrupts; i++) { 268 if (i >= MAX_POSSIBLE_INTERRUPTS) { 269 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "too many IRQs (%d)\n", 270 i)); 271 break; 272 } 273 if (Interrupts[i] == 0) { 274 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "invalid IRQ %d\n", 275 Interrupts[i])); 276 continue; 277 } 278 interrupts[count] = Interrupts[i]; 279 count++; 280 } 281 *number_of_interrupts = count; 282 283 return_ACPI_STATUS (AE_OK); 284 } 285 286 static ACPI_STATUS 287 acpi_pci_link_get_current_irq(struct acpi_pci_link_entry *link, UINT8 *irq) 288 { 289 ACPI_STATUS error; 290 ACPI_BUFFER buf; 291 ACPI_RESOURCE *resources; 292 UINT8 number_of_interrupts; 293 UINT8 interrupts[MAX_POSSIBLE_INTERRUPTS];; 294 295 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 296 297 if (link == NULL || irq == NULL) { 298 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n")); 299 return_ACPI_STATUS (AE_BAD_PARAMETER); 300 } 301 302 *irq = 0; 303 buf.Pointer = NULL; 304 buf.Length = ACPI_ALLOCATE_BUFFER; 305 error = AcpiGetCurrentResources(link->handle, &buf); 306 if (ACPI_FAILURE(error)) { 307 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 308 "couldn't get PCI interrupt link device _CRS %s - %s\n", 309 acpi_name(link->handle), AcpiFormatException(error))); 310 return_ACPI_STATUS (error); 311 } 312 if (buf.Pointer == NULL) { 313 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 314 "couldn't allocate memory - %s\n", 315 acpi_name(link->handle))); 316 return_ACPI_STATUS (AE_NO_MEMORY); 317 } 318 319 resources = (ACPI_RESOURCE *) buf.Pointer; 320 number_of_interrupts = 0; 321 bzero(interrupts, sizeof(interrupts)); 322 error = acpi_pci_link_get_irq_resources(resources, 323 &number_of_interrupts, interrupts); 324 AcpiOsFree(buf.Pointer); 325 326 if (ACPI_FAILURE(error)) { 327 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 328 "couldn't get current IRQ from interrupt link %s - %s\n", 329 acpi_name(link->handle), AcpiFormatException(error))); 330 return_ACPI_STATUS (error); 331 } 332 333 if (number_of_interrupts == 0) { 334 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 335 "PCI interrupt link device _CRS data is corrupted - %s\n", 336 acpi_name(link->handle))); 337 return_ACPI_STATUS (AE_NULL_ENTRY); 338 } 339 340 *irq = interrupts[0]; 341 342 return_ACPI_STATUS (AE_OK); 343 } 344 345 static ACPI_STATUS 346 acpi_pci_link_add_link(ACPI_HANDLE handle, struct acpi_prt_entry *entry) 347 { 348 ACPI_STATUS error; 349 ACPI_BUFFER buf; 350 ACPI_RESOURCE *resources; 351 struct acpi_pci_link_entry *link; 352 353 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 354 355 entry->pci_link = NULL; 356 TAILQ_FOREACH(link, &acpi_pci_link_entries, links) { 357 if (link->handle == handle) { 358 entry->pci_link = link; 359 link->references++; 360 return_ACPI_STATUS (AE_OK); 361 } 362 } 363 364 link = AcpiOsAllocate(sizeof(struct acpi_pci_link_entry)); 365 if (link == NULL) { 366 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 367 "couldn't allocate memory - %s\n", acpi_name(handle))); 368 return_ACPI_STATUS (AE_NO_MEMORY); 369 } 370 371 buf.Pointer = NULL; 372 buf.Length = ACPI_ALLOCATE_BUFFER; 373 374 bzero(link, sizeof(struct acpi_pci_link_entry)); 375 376 link->handle = handle; 377 378 error = acpi_pci_link_get_current_irq(link, &link->current_irq); 379 if (ACPI_FAILURE(error)) { 380 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 381 "couldn't get current IRQ from interrupt link %s - %s\n", 382 acpi_name(handle), AcpiFormatException(error))); 383 } 384 385 link->initial_irq = link->current_irq; 386 387 error = AcpiGetPossibleResources(handle, &buf); 388 if (ACPI_FAILURE(error)) { 389 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 390 "couldn't get interrupt link device _PRS data %s - %s\n", 391 acpi_name(handle), AcpiFormatException(error))); 392 goto out; 393 } 394 if (buf.Pointer == NULL) { 395 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 396 "_PRS nuffer is empty - %s\n", acpi_name(handle))); 397 error = AE_NO_MEMORY; 398 goto out; 399 } 400 401 resources = (ACPI_RESOURCE *) buf.Pointer; 402 bcopy(resources, &link->possible_resources, 403 sizeof(link->possible_resources)); 404 405 error = acpi_pci_link_get_irq_resources(resources, 406 &link->number_of_interrupts, link->interrupts); 407 if (ACPI_FAILURE(error)) { 408 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 409 "couldn't get possible IRQs from interrupt link %s - %s\n", 410 acpi_name(handle), AcpiFormatException(error))); 411 goto out; 412 } 413 414 if (link->number_of_interrupts == 0) { 415 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 416 "interrupt link device _PRS data is corrupted - %s\n", 417 acpi_name(handle))); 418 error = AE_NULL_ENTRY; 419 goto out; 420 } 421 422 link->references++; 423 424 TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links); 425 entry->pci_link = link; 426 427 error = AE_OK; 428 out: 429 if (buf.Pointer != NULL) 430 AcpiOsFree(buf.Pointer); 431 if (error != AE_OK && link != NULL) 432 AcpiOsFree(link); 433 434 return_ACPI_STATUS (error); 435 } 436 437 static ACPI_STATUS 438 acpi_pci_link_add_prt(device_t pcidev, ACPI_PCI_ROUTING_TABLE *prt, int busno) 439 { 440 ACPI_HANDLE handle; 441 ACPI_STATUS error; 442 UINT32 sta; 443 struct acpi_prt_entry *entry; 444 445 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 446 447 if (prt == NULL || prt->Source == NULL || prt->Source[0] == '\0') { 448 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 449 "couldn't handle this routing table - hardwired\n")); 450 return_ACPI_STATUS (AE_BAD_PARAMETER); 451 } 452 453 error = AcpiGetHandle(acpi_get_handle(pcidev), prt->Source, &handle); 454 if (ACPI_FAILURE(error)) { 455 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "couldn't get handle - %s\n", 456 AcpiFormatException(error))); 457 return_ACPI_STATUS (error); 458 } 459 460 error = acpi_pci_link_get_object_status(handle, &sta); 461 if (ACPI_FAILURE(error)) { 462 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 463 "couldn't get object status %s - %s\n", 464 acpi_name(handle), AcpiFormatException(error))); 465 return_ACPI_STATUS (error); 466 } 467 468 if ((sta & (ACPI_STA_PRESENT | ACPI_STA_FUNCTIONAL)) == 0) { 469 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 470 "interrupt link is not functional - %s\n", 471 acpi_name(handle))); 472 return_ACPI_STATUS (AE_ERROR); 473 } 474 475 TAILQ_FOREACH(entry, &acpi_prt_entries, links) { 476 if (entry->busno == busno && 477 entry->prt.Address == prt->Address && 478 entry->prt.Pin == prt->Pin) { 479 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 480 "interrupt link entry already exists - %s\n", 481 acpi_name(handle))); 482 return_ACPI_STATUS (AE_ALREADY_EXISTS); 483 } 484 } 485 486 entry = AcpiOsAllocate(sizeof(struct acpi_prt_entry)); 487 if (entry == NULL) { 488 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 489 "couldn't allocate memory - %s\n", acpi_name(handle))); 490 return_ACPI_STATUS (AE_NO_MEMORY); 491 } 492 bzero(entry, sizeof(struct acpi_prt_entry)); 493 494 entry->pcidev = pcidev; 495 entry->busno = busno; 496 bcopy(prt, &entry->prt, sizeof(entry->prt)); 497 498 error = acpi_pci_link_add_link(handle, entry); 499 if (ACPI_FAILURE(error)) { 500 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 501 "couldn't add _PRT entry to link %s - %s\n", 502 acpi_name(handle), AcpiFormatException(error))); 503 goto out; 504 } 505 506 TAILQ_INSERT_TAIL(&acpi_prt_entries, entry, links); 507 error = AE_OK; 508 509 out: 510 if (error != AE_OK && entry != NULL) 511 AcpiOsFree(entry); 512 513 return_ACPI_STATUS (error); 514 } 515 516 static int 517 acpi_pci_link_is_valid_irq(struct acpi_pci_link_entry *link, UINT8 irq) 518 { 519 UINT8 i; 520 521 if (irq == 0) 522 return (0); 523 524 for (i = 0; i < link->number_of_interrupts; i++) { 525 if (link->interrupts[i] == irq) 526 return (1); 527 } 528 529 /* allow initial IRQ as valid one. */ 530 if (link->initial_irq == irq) 531 return (1); 532 533 return (0); 534 } 535 536 static ACPI_STATUS 537 acpi_pci_link_set_irq(struct acpi_pci_link_entry *link, UINT8 irq) 538 { 539 ACPI_STATUS error; 540 ACPI_RESOURCE resbuf; 541 ACPI_BUFFER crsbuf; 542 UINT32 sta; 543 544 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 545 546 if (!acpi_pci_link_is_valid_irq(link, irq)) { 547 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 548 "couldn't set invalid IRQ %d - %s\n", irq, 549 acpi_name(link->handle))); 550 return_ACPI_STATUS (AE_BAD_PARAMETER); 551 } 552 553 error = acpi_pci_link_get_current_irq(link, &link->current_irq); 554 if (ACPI_FAILURE(error)) { 555 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 556 "couldn't get current IRQ from interrupt link %s - %s\n", 557 acpi_name(link->handle), AcpiFormatException(error))); 558 } 559 560 if (link->current_irq == irq) 561 return_ACPI_STATUS (AE_OK); 562 563 bzero(&resbuf, sizeof(resbuf)); 564 crsbuf.Pointer = NULL; 565 566 switch (link->possible_resources.Id) { 567 case ACPI_RSTYPE_IRQ: 568 resbuf.Id = ACPI_RSTYPE_IRQ; 569 resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ); 570 571 /* structure copy other fields */ 572 resbuf.Data.Irq = link->possible_resources.Data.Irq; 573 resbuf.Data.Irq.NumberOfInterrupts = 1; 574 resbuf.Data.Irq.Interrupts[0] = irq; 575 break; 576 case ACPI_RSTYPE_EXT_IRQ: 577 resbuf.Id = ACPI_RSTYPE_EXT_IRQ; 578 resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_EXT_IRQ); 579 580 /* structure copy other fields */ 581 resbuf.Data.ExtendedIrq = 582 link->possible_resources.Data.ExtendedIrq; 583 resbuf.Data.ExtendedIrq.NumberOfInterrupts = 1; 584 resbuf.Data.ExtendedIrq.Interrupts[0] = irq; 585 break; 586 default: 587 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 588 "Resource is not an IRQ entry %s - %d\n", 589 acpi_name(link->handle), link->possible_resources.Id)); 590 return_ACPI_STATUS (AE_TYPE); 591 } 592 593 error = acpi_AppendBufferResource(&crsbuf, &resbuf); 594 if (ACPI_FAILURE(error)) { 595 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 596 "couldn't setup buffer by acpi_AppendBufferResource - %s\n", 597 acpi_name(link->handle))); 598 return_ACPI_STATUS (error); 599 } 600 if (crsbuf.Pointer == NULL) { 601 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 602 "appended buffer for %s is corrupted\n", 603 acpi_name(link->handle))); 604 return_ACPI_STATUS (AE_NO_MEMORY); 605 } 606 607 error = AcpiSetCurrentResources(link->handle, &crsbuf); 608 if (ACPI_FAILURE(error)) { 609 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 610 "couldn't set link device _SRS %s - %s\n", 611 acpi_name(link->handle), AcpiFormatException(error))); 612 return_ACPI_STATUS (error); 613 } 614 615 AcpiOsFree(crsbuf.Pointer); 616 link->current_irq = 0; 617 618 error = acpi_pci_link_get_object_status(link->handle, &sta); 619 if (ACPI_FAILURE(error)) { 620 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 621 "couldn't get object status %s - %s\n", 622 acpi_name(link->handle), AcpiFormatException(error))); 623 return_ACPI_STATUS (error); 624 } 625 626 if ((sta & ACPI_STA_ENABLE) == 0) { 627 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 628 "interrupt link %s is disabled\n", 629 acpi_name(link->handle))); 630 return_ACPI_STATUS (AE_ERROR); 631 } 632 633 error = acpi_pci_link_get_current_irq(link, &link->current_irq); 634 if (ACPI_FAILURE(error)) { 635 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 636 "couldn't get current IRQ from interrupt link %s - %s\n", 637 acpi_name(link->handle), AcpiFormatException(error))); 638 return_ACPI_STATUS (error); 639 } 640 641 if (link->current_irq == irq) { 642 error = AE_OK; 643 } else { 644 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 645 "couldn't set IRQ %d to PCI interrupt link %d - %s\n", 646 irq, link->current_irq, acpi_name(link->handle))); 647 link->current_irq = 0; 648 error = AE_ERROR; 649 } 650 651 return_ACPI_STATUS (error); 652 } 653 654 /* 655 * Auto arbitration for boot-disabled devices 656 */ 657 658 static void 659 acpi_pci_link_bootdisabled_dump(void) 660 { 661 int i; 662 int irq; 663 struct acpi_pci_link_entry *link; 664 665 TAILQ_FOREACH(link, &acpi_pci_link_entries, links) { 666 /* boot-disabled link only. */ 667 if (link->current_irq != 0) 668 continue; 669 670 printf("%s:\n", acpi_name(link->handle)); 671 printf(" interrupts: "); 672 for (i = 0; i < link->number_of_interrupts; i++) { 673 irq = link->sorted_irq[i]; 674 printf("%6d", irq); 675 } 676 printf("\n"); 677 printf(" penalty: "); 678 for (i = 0; i < link->number_of_interrupts; i++) { 679 irq = link->sorted_irq[i]; 680 printf("%6d", irq_penalty[irq]); 681 } 682 printf("\n"); 683 printf(" references: %d\n", link->references); 684 printf(" priority: %d\n", link->priority); 685 } 686 } 687 688 static void 689 acpi_pci_link_init_irq_penalty(void) 690 { 691 int irq; 692 693 bzero(irq_penalty, sizeof(irq_penalty)); 694 for (irq = 0; irq < MAX_ISA_INTERRUPTS; irq++) { 695 /* 0, 1, 2, 8: timer, keyboard, cascade */ 696 if (irq == 0 || irq == 1 || irq == 2 || irq == 8) { 697 irq_penalty[irq] = 100000; 698 continue; 699 } 700 701 /* 13, 14, 15: npx, ATA controllers */ 702 if (irq == 13 || irq == 14 || irq == 15) { 703 irq_penalty[irq] = 10000; 704 continue; 705 } 706 707 /* 3,4,6,7,12: typicially used by legacy hardware */ 708 if (irq == 3 || irq == 4 || irq == 6 || irq == 7 || irq == 12) { 709 irq_penalty[irq] = 1000; 710 continue; 711 } 712 } 713 } 714 715 static int 716 link_exclusive(ACPI_RESOURCE *res) 717 { 718 719 if (res == NULL || 720 (res->Id != ACPI_RSTYPE_IRQ && 721 res->Id != ACPI_RSTYPE_EXT_IRQ)) 722 return (0); 723 724 if ((res->Id == ACPI_RSTYPE_IRQ && 725 res->Data.Irq.SharedExclusive == ACPI_EXCLUSIVE) || 726 (res->Id == ACPI_RSTYPE_EXT_IRQ && 727 res->Data.ExtendedIrq.SharedExclusive == ACPI_EXCLUSIVE)) 728 return (1); 729 730 return (0); 731 } 732 733 static void 734 acpi_pci_link_update_irq_penalty(device_t dev, int busno) 735 { 736 int i; 737 int irq; 738 int rid; 739 struct resource *res; 740 struct acpi_prt_entry *entry; 741 struct acpi_pci_link_entry *link; 742 743 TAILQ_FOREACH(entry, &acpi_prt_entries, links) { 744 if (entry->busno != busno) 745 continue; 746 747 /* Impossible? */ 748 link = entry->pci_link; 749 if (link == NULL) 750 continue; 751 752 if (link->current_irq != 0) { 753 /* not boot-disabled link, we will use this IRQ. */ 754 irq_penalty[link->current_irq] += 100; 755 continue; 756 } 757 758 /* boot-disabled link */ 759 for (i = 0; i < link->number_of_interrupts; i++) { 760 /* give 10 for each possible IRQs. */ 761 irq = link->interrupts[i]; 762 irq_penalty[irq] += 10; 763 764 /* higher penalty if exclusive. */ 765 if (link_exclusive(&link->possible_resources)) 766 irq_penalty[irq] += 100; 767 768 /* XXX try to get this IRQ in non-sharable mode. */ 769 rid = 0; 770 res = bus_alloc_resource(dev, SYS_RES_IRQ, 771 &rid, irq, irq, 1, 0); 772 if (res != NULL) { 773 bus_release_resource(dev, SYS_RES_IRQ, 774 rid, res); 775 } else { 776 /* this is in use, give 100. */ 777 irq_penalty[irq] += 100; 778 } 779 } 780 781 /* initialize `sorted' possible IRQs. */ 782 bcopy(link->interrupts, link->sorted_irq, 783 sizeof(link->sorted_irq)); 784 } 785 } 786 787 static void 788 acpi_pci_link_set_bootdisabled_priority(void) 789 { 790 int sum_penalty; 791 int i; 792 int irq; 793 struct acpi_pci_link_entry *link, *link_pri; 794 TAILQ_HEAD(, acpi_pci_link_entry) sorted_list; 795 796 if (bootverbose) { 797 printf("ACPI PCI link before setting link priority:\n"); 798 acpi_pci_link_bootdisabled_dump(); 799 } 800 801 /* reset priority for all links. */ 802 TAILQ_FOREACH(link, &acpi_pci_link_entries, links) 803 link->priority = 0; 804 805 TAILQ_FOREACH(link, &acpi_pci_link_entries, links) { 806 /* not boot-disabled link, give no chance to be arbitrated. */ 807 if (link->current_irq != 0) { 808 link->priority = 0; 809 continue; 810 } 811 812 /* 813 * Calculate the priority for each boot-disabled links. 814 * o IRQ penalty indicates difficulty to use. 815 * o #references for devices indicates importance of the link. 816 * o #interrupts indicates flexibility of the link. 817 */ 818 sum_penalty = 0; 819 for (i = 0; i < link->number_of_interrupts; i++) { 820 irq = link->interrupts[i]; 821 sum_penalty += irq_penalty[irq]; 822 } 823 824 link->priority = (sum_penalty * link->references) / 825 link->number_of_interrupts; 826 } 827 828 /* 829 * Sort PCI links based on the priority. 830 * XXX Any other better ways rather than using work list? 831 */ 832 TAILQ_INIT(&sorted_list); 833 while (!TAILQ_EMPTY(&acpi_pci_link_entries)) { 834 link = TAILQ_FIRST(&acpi_pci_link_entries); 835 /* find an entry which has the highest priority. */ 836 TAILQ_FOREACH(link_pri, &acpi_pci_link_entries, links) 837 if (link->priority < link_pri->priority) 838 link = link_pri; 839 840 /* move to work list. */ 841 TAILQ_REMOVE(&acpi_pci_link_entries, link, links); 842 TAILQ_INSERT_TAIL(&sorted_list, link, links); 843 } 844 845 while (!TAILQ_EMPTY(&sorted_list)) { 846 /* move them back to the list, one by one... */ 847 link = TAILQ_FIRST(&sorted_list); 848 TAILQ_REMOVE(&sorted_list, link, links); 849 TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links); 850 } 851 } 852 853 static void 854 acpi_pci_link_fixup_bootdisabled_link(void) 855 { 856 int i, j; 857 int irq1, irq2; 858 struct acpi_pci_link_entry *link; 859 ACPI_STATUS error; 860 861 if (bootverbose) { 862 printf("ACPI PCI link before fixup for boot-disabled links:\n"); 863 acpi_pci_link_bootdisabled_dump(); 864 } 865 866 TAILQ_FOREACH(link, &acpi_pci_link_entries, links) { 867 /* ignore non boot-disabled links. */ 868 if (link->current_irq != 0) 869 continue; 870 871 /* sort IRQs based on their penalty descending. */ 872 for (i = 0; i < link->number_of_interrupts; i++) { 873 irq1 = link->sorted_irq[i]; 874 for (j = i + 1; j < link->number_of_interrupts; j++) { 875 irq2 = link->sorted_irq[j]; 876 if (irq_penalty[irq1] < irq_penalty[irq2]) { 877 continue; 878 } 879 link->sorted_irq[i] = irq2; 880 link->sorted_irq[j] = irq1; 881 irq1 = irq2; 882 } 883 } 884 885 /* try with lower penalty IRQ. */ 886 for (i = 0; i < link->number_of_interrupts; i++) { 887 irq1 = link->sorted_irq[i]; 888 error = acpi_pci_link_set_irq(link, irq1); 889 if (error == AE_OK) { 890 /* OK, we use this. give another penalty. */ 891 irq_penalty[irq1] += 100 * link->references; 892 break; 893 } 894 } 895 } 896 897 if (bootverbose) { 898 printf("ACPI PCI link after fixup for boot-disabled links:\n"); 899 acpi_pci_link_bootdisabled_dump(); 900 } 901 } 902 903 /* 904 * Public interface 905 */ 906 907 int 908 acpi_pci_link_config(device_t dev, ACPI_BUFFER *prtbuf, int busno) 909 { 910 struct acpi_prt_entry *entry; 911 ACPI_PCI_ROUTING_TABLE *prt; 912 u_int8_t *prtp; 913 ACPI_STATUS error; 914 static int first_time =1; 915 916 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 917 918 if (acpi_disabled("pci_link")) 919 return (0); 920 921 if (first_time) { 922 TAILQ_INIT(&acpi_prt_entries); 923 TAILQ_INIT(&acpi_pci_link_entries); 924 acpi_pci_link_init_irq_penalty(); 925 first_time = 0; 926 } 927 928 if (prtbuf == NULL) 929 return (-1); 930 931 prtp = prtbuf->Pointer; 932 if (prtp == NULL) /* didn't get routing table */ 933 return (-1); 934 935 /* scan the PCI Routing Table */ 936 for (;;) { 937 prt = (ACPI_PCI_ROUTING_TABLE *)prtp; 938 939 if (prt->Length == 0) /* end of table */ 940 break; 941 942 error = acpi_pci_link_add_prt(dev, prt, busno); 943 if (ACPI_FAILURE(error)) { 944 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 945 "couldn't add PCI interrupt link entry - %s\n", 946 AcpiFormatException(error))); 947 } 948 949 /* skip to next entry */ 950 prtp += prt->Length; 951 } 952 953 if (bootverbose) { 954 printf("ACPI PCI link initial configuration:\n"); 955 TAILQ_FOREACH(entry, &acpi_prt_entries, links) { 956 if (entry->busno != busno) 957 continue; 958 acpi_pci_link_entry_dump(entry); 959 } 960 } 961 962 /* manual configuration. */ 963 TAILQ_FOREACH(entry, &acpi_prt_entries, links) { 964 int irq; 965 char prthint[32]; 966 967 if (entry->busno != busno) 968 continue; 969 970 snprintf(prthint, sizeof(prthint), 971 "hw.acpi.pci.link.%d.%d.%d.irq", entry->busno, 972 (int)((entry->prt.Address & 0xffff0000) >> 16), 973 (int)entry->prt.Pin); 974 975 if (getenv_int(prthint, &irq) == 0) 976 continue; 977 978 if (acpi_pci_link_is_valid_irq(entry->pci_link, irq)) { 979 error = acpi_pci_link_set_irq(entry->pci_link, irq); 980 if (ACPI_FAILURE(error)) { 981 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 982 "couldn't set IRQ to link entry %s - %s\n", 983 acpi_name(entry->pci_link->handle), 984 AcpiFormatException(error))); 985 } 986 continue; 987 } 988 989 /* 990 * Do auto arbitration for this device's PCI link 991 * if hint value 0 is specified. 992 */ 993 if (irq == 0) 994 entry->pci_link->current_irq = 0; 995 } 996 997 /* auto arbitration */ 998 acpi_pci_link_update_irq_penalty(dev, busno); 999 acpi_pci_link_set_bootdisabled_priority(); 1000 acpi_pci_link_fixup_bootdisabled_link(); 1001 1002 if (bootverbose) { 1003 printf("ACPI PCI link arbitrated configuration:\n"); 1004 TAILQ_FOREACH(entry, &acpi_prt_entries, links) { 1005 if (entry->busno != busno) 1006 continue; 1007 acpi_pci_link_entry_dump(entry); 1008 } 1009 } 1010 1011 return (0); 1012 } 1013 1014 int 1015 acpi_pci_link_resume(device_t dev, ACPI_BUFFER *prtbuf, int busno) 1016 { 1017 struct acpi_prt_entry *entry; 1018 ACPI_STATUS error; 1019 1020 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 1021 1022 if (acpi_disabled("pci_link")) 1023 return (0); 1024 1025 TAILQ_FOREACH(entry, &acpi_prt_entries, links) { 1026 if (entry->pcidev != dev) 1027 continue; 1028 1029 error = acpi_pci_link_set_irq(entry->pci_link, 1030 entry->pci_link->current_irq); 1031 if (ACPI_FAILURE(error)) { 1032 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 1033 "couldn't set IRQ to link entry %s - %s\n", 1034 acpi_name(entry->pci_link->handle), 1035 AcpiFormatException(error))); 1036 } 1037 } 1038 1039 return (0); 1040 } 1041