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