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