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 } 374 375 link->initial_irq = link->current_irq; 376 377 error = AcpiGetPossibleResources(handle, &buf); 378 if (ACPI_FAILURE(error)) { 379 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 380 "couldn't get PCI interrupt link device _PRS data %s - %s\n", 381 acpi_name(handle), AcpiFormatException(error))); 382 goto out; 383 } 384 385 if (buf.Pointer == NULL) { 386 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 387 "_PRS nuffer is empty - %s\n", acpi_name(handle))); 388 error = AE_NO_MEMORY; 389 goto out; 390 } 391 392 resources = (ACPI_RESOURCE *) buf.Pointer; 393 bcopy(resources, &link->possible_resources, 394 sizeof(link->possible_resources)); 395 396 error = acpi_pci_link_get_irq_resources(resources, 397 &link->number_of_interrupts, link->interrupts); 398 if (ACPI_FAILURE(error)) { 399 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 400 "couldn't get possible IRQs from PCI interrupt link %s - %s\n", 401 acpi_name(handle), AcpiFormatException(error))); 402 goto out; 403 } 404 405 if (link->number_of_interrupts == 0) { 406 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 407 "PCI interrupt link device _PRS data is corrupted - %s\n", 408 acpi_name(handle))); 409 error = AE_NULL_ENTRY; 410 goto out; 411 } 412 413 link->references++; 414 415 TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links); 416 entry->pci_link = link; 417 418 error = AE_OK; 419 out: 420 if (buf.Pointer != NULL) { 421 AcpiOsFree(buf.Pointer); 422 } 423 424 if (error != AE_OK && link != NULL) { 425 AcpiOsFree(link); 426 } 427 428 return_ACPI_STATUS (error); 429 } 430 431 static ACPI_STATUS 432 acpi_pci_link_add_prt(device_t pcidev, ACPI_PCI_ROUTING_TABLE *prt, int busno) 433 { 434 ACPI_HANDLE handle; 435 ACPI_STATUS error; 436 UINT32 sta; 437 struct acpi_prt_entry *entry; 438 439 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 440 441 if ((prt == NULL) || (prt->Source == NULL) || (prt->Source[0] == '\0')) { 442 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 443 "couldn't handle this routing table - hardwired\n")); 444 return_ACPI_STATUS (AE_BAD_PARAMETER); 445 } 446 447 error = AcpiGetHandle(acpi_get_handle(pcidev), prt->Source, &handle); 448 if (ACPI_FAILURE(error)) { 449 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 450 "couldn't get acpi handle - %s\n", 451 AcpiFormatException(error))); 452 return_ACPI_STATUS (error); 453 } 454 455 error = acpi_pci_link_get_object_status(handle, &sta); 456 if (ACPI_FAILURE(error)) { 457 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 458 "couldn't get object status %s - %s\n", 459 acpi_name(handle), AcpiFormatException(error))); 460 return_ACPI_STATUS (error); 461 } 462 463 if (!(sta & (ACPI_STA_PRESENT | ACPI_STA_FUNCTIONAL))) { 464 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 465 "PCI interrupt link is not functional - %s\n", 466 acpi_name(handle))); 467 return_ACPI_STATUS (AE_ERROR); 468 } 469 470 TAILQ_FOREACH(entry, &acpi_prt_entries, links) { 471 if (entry->busno == busno && 472 entry->prt.Address == prt->Address && 473 entry->prt.Pin == prt->Pin) { 474 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 475 "PCI interrupt link entry already exists - %s\n", 476 acpi_name(handle))); 477 return_ACPI_STATUS (AE_ALREADY_EXISTS); 478 } 479 } 480 481 entry = AcpiOsAllocate(sizeof(struct acpi_prt_entry)); 482 if (entry == NULL) { 483 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 484 "couldn't allocate memory - %s\n", acpi_name(handle))); 485 return_ACPI_STATUS (AE_NO_MEMORY); 486 } 487 488 bzero(entry, sizeof(struct acpi_prt_entry)); 489 490 entry->pcidev = pcidev; 491 entry->busno = busno; 492 bcopy(prt, &entry->prt, sizeof(entry->prt)); 493 494 error = acpi_pci_link_add_link(handle, entry); 495 if (ACPI_FAILURE(error)) { 496 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 497 "couldn't add prt entry to pci link %s - %s\n", 498 acpi_name(handle), AcpiFormatException(error))); 499 goto out; 500 } 501 502 TAILQ_INSERT_TAIL(&acpi_prt_entries, entry, links); 503 error = AE_OK; 504 505 out: 506 if (error != AE_OK && entry != NULL) { 507 AcpiOsFree(entry); 508 } 509 510 return_ACPI_STATUS (error); 511 } 512 513 static int 514 acpi_pci_link_is_valid_irq(struct acpi_pci_link_entry *link, UINT8 irq) 515 { 516 UINT8 i; 517 518 if (irq == 0) { 519 return (0); 520 } 521 522 for (i = 0; i < link->number_of_interrupts; i++) { 523 if (link->interrupts[i] == irq) { 524 return (1); 525 } 526 } 527 528 /* allow initial IRQ as valid one. */ 529 if (link->initial_irq == irq) { 530 return (1); 531 } 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 PCI 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 564 bzero(&resbuf, sizeof(resbuf)); 565 crsbuf.Pointer = NULL; 566 resbuf.Id = ACPI_RSTYPE_IRQ; 567 resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ); 568 569 if (link->possible_resources.Id != ACPI_RSTYPE_IRQ && 570 link->possible_resources.Id != ACPI_RSTYPE_EXT_IRQ) { 571 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 572 "Resource is not an IRQ entry %s - %d\n", 573 acpi_name(link->handle), link->possible_resources.Id)); 574 return_ACPI_STATUS (AE_TYPE); 575 } 576 577 switch (link->possible_resources.Id) { 578 case ACPI_RSTYPE_IRQ: 579 /* structure copy other fields */ 580 resbuf.Data.Irq = link->possible_resources.Data.Irq; 581 break; 582 583 case ACPI_RSTYPE_EXT_IRQ: 584 /* XXX */ 585 resbuf.Data.Irq.EdgeLevel = ACPI_LEVEL_SENSITIVE; 586 resbuf.Data.Irq.ActiveHighLow = ACPI_ACTIVE_LOW; 587 resbuf.Data.Irq.SharedExclusive = ACPI_SHARED; 588 break; 589 } 590 591 resbuf.Data.Irq.NumberOfInterrupts = 1; 592 resbuf.Data.Irq.Interrupts[0] = irq; 593 594 error = acpi_AppendBufferResource(&crsbuf, &resbuf); 595 if (ACPI_FAILURE(error)) { 596 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 597 "couldn't setup buffer by acpi_AppendBufferResource - %s\n", 598 acpi_name(link->handle))); 599 return_ACPI_STATUS (error); 600 } 601 602 if (crsbuf.Pointer == NULL) { 603 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 604 "buffer setup by acpi_AppendBufferResource is corrupted - %s\n", 605 acpi_name(link->handle))); 606 return_ACPI_STATUS (AE_NO_MEMORY); 607 } 608 609 error = AcpiSetCurrentResources(link->handle, &crsbuf); 610 if (ACPI_FAILURE(error)) { 611 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 612 "couldn't set PCI interrupt link device _SRS %s - %s\n", 613 acpi_name(link->handle), AcpiFormatException(error))); 614 return_ACPI_STATUS (error); 615 } 616 617 AcpiOsFree(crsbuf.Pointer); 618 link->current_irq = 0; 619 620 error = acpi_pci_link_get_object_status(link->handle, &sta); 621 if (ACPI_FAILURE(error)) { 622 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 623 "couldn't get object status %s - %s\n", 624 acpi_name(link->handle), AcpiFormatException(error))); 625 return_ACPI_STATUS (error); 626 } 627 628 if (!(sta & ACPI_STA_ENABLE)) { 629 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 630 "PCI interrupt link is disabled - %s\n", 631 acpi_name(link->handle))); 632 return_ACPI_STATUS (AE_ERROR); 633 } 634 635 error = acpi_pci_link_get_current_irq(link, &link->current_irq); 636 if (ACPI_FAILURE(error)) { 637 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 638 "couldn't get current IRQ from PCI interrupt link %s - %s\n", 639 acpi_name(link->handle), AcpiFormatException(error))); 640 return_ACPI_STATUS (error); 641 } 642 643 if (link->current_irq == irq) { 644 error = AE_OK; 645 } else { 646 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 647 "couldn't set IRQ %d to PCI interrupt link %d - %s\n", 648 irq, link->current_irq, acpi_name(link->handle))); 649 650 link->current_irq = 0; 651 error = AE_ERROR; 652 } 653 654 return_ACPI_STATUS (error); 655 } 656 657 /* 658 * Auto arbitration for boot-disabled devices 659 */ 660 661 static void 662 acpi_pci_link_bootdisabled_dump(void) 663 664 { 665 int i; 666 int irq; 667 struct acpi_pci_link_entry *link; 668 669 TAILQ_FOREACH(link, &acpi_pci_link_entries, links) { 670 /* boot-disabled link only. */ 671 if (link->current_irq != 0) { 672 continue; 673 } 674 675 printf("%s:\n", acpi_name(link->handle)); 676 printf(" interrupts: "); 677 for (i = 0; i < link->number_of_interrupts; i++) { 678 irq = link->sorted_irq[i]; 679 printf("%6d", irq); 680 } 681 printf("\n"); 682 printf(" penalty: "); 683 for (i = 0; i < link->number_of_interrupts; i++) { 684 irq = link->sorted_irq[i]; 685 printf("%6d", irq_penalty[irq]); 686 } 687 printf("\n"); 688 printf(" references: %d\n", link->references); 689 printf(" priority: %d\n", link->priority); 690 } 691 } 692 693 static void 694 acpi_pci_link_init_irq_penalty(void) 695 { 696 int irq; 697 698 bzero(irq_penalty, sizeof(irq_penalty)); 699 for (irq = 0; irq < MAX_ISA_INTERRUPTS; irq++) { 700 /* 0, 1, 2, 8: timer, keyboard, cascade */ 701 if (irq == 0 || irq == 1 || irq == 2 || irq == 8) { 702 irq_penalty[irq] = 100000; 703 continue; 704 } 705 706 /* 13, 14, 15: npx, ATA controllers */ 707 if (irq == 13 || irq == 14 || irq == 15) { 708 irq_penalty[irq] = 10000; 709 continue; 710 } 711 712 /* 3,4,6,7,12: typicially used by legacy hardware */ 713 if (irq == 3 || irq == 4 || irq == 6 || irq == 7 || irq == 12) { 714 irq_penalty[irq] = 1000; 715 continue; 716 } 717 } 718 } 719 720 static int 721 acpi_pci_link_is_irq_exclusive(ACPI_RESOURCE *res) 722 { 723 if (res == NULL) { 724 return (0); 725 } 726 727 if (res->Id != ACPI_RSTYPE_IRQ && 728 res->Id != ACPI_RSTYPE_EXT_IRQ) { 729 return (0); 730 } 731 732 if (res->Id == ACPI_RSTYPE_IRQ && 733 res->Data.Irq.SharedExclusive == ACPI_EXCLUSIVE) { 734 return (1); 735 } 736 737 if (res->Id == ACPI_RSTYPE_EXT_IRQ && 738 res->Data.ExtendedIrq.SharedExclusive == ACPI_EXCLUSIVE) { 739 return (1); 740 } 741 742 return (0); 743 } 744 745 static void 746 acpi_pci_link_update_irq_penalty(device_t dev, int busno) 747 { 748 int i; 749 int irq; 750 int rid; 751 struct resource *res; 752 struct acpi_prt_entry *entry; 753 struct acpi_pci_link_entry *link; 754 755 TAILQ_FOREACH(entry, &acpi_prt_entries, links) { 756 if (entry->busno != busno) { 757 continue; 758 } 759 760 link = entry->pci_link; 761 if (link == NULL) { 762 continue; /* impossible... */ 763 } 764 765 if (link->current_irq != 0) { 766 /* not boot-disabled link, we will use this IRQ. */ 767 irq_penalty[link->current_irq] += 100; 768 continue; 769 } 770 771 /* boot-disabled link */ 772 for (i = 0; i < link->number_of_interrupts; i++) { 773 /* give 10 for each possible IRQs. */ 774 irq = link->interrupts[i]; 775 irq_penalty[irq] += 10; 776 777 /* higher penalty if exclusive. */ 778 if (acpi_pci_link_is_irq_exclusive(&link->possible_resources)) { 779 irq_penalty[irq] += 100; 780 } 781 782 /* XXX try to get this IRQ in non-sharable mode. */ 783 rid = 0; 784 res = bus_alloc_resource(dev, SYS_RES_IRQ, 785 &rid, irq, irq, 1, 0); 786 if (res != NULL) { 787 bus_release_resource(dev, SYS_RES_IRQ, 788 rid, res); 789 } else { 790 /* this is in use, give 100. */ 791 irq_penalty[irq] += 100; 792 } 793 } 794 795 /* initialize `sorted' possible IRQs. */ 796 bcopy(link->interrupts, link->sorted_irq, 797 sizeof(link->sorted_irq)); 798 } 799 } 800 801 static void 802 acpi_pci_link_set_bootdisabled_priority(void) 803 { 804 int sum_penalty; 805 int i; 806 int irq; 807 struct acpi_pci_link_entry *link, *link_pri; 808 TAILQ_HEAD(, acpi_pci_link_entry) sorted_list; 809 810 if (bootverbose) { 811 printf("---- before setting priority for links ------------\n"); 812 acpi_pci_link_bootdisabled_dump(); 813 } 814 815 /* reset priority for all links. */ 816 TAILQ_FOREACH(link, &acpi_pci_link_entries, links) { 817 link->priority = 0; 818 } 819 820 TAILQ_FOREACH(link, &acpi_pci_link_entries, links) { 821 /* not boot-disabled link, give no chance to be arbitrated. */ 822 if (link->current_irq != 0) { 823 link->priority = 0; 824 continue; 825 } 826 827 /* 828 * Calculate the priority for each boot-disabled links. 829 * o IRQ penalty indicates difficulty to use. 830 * o #references for devices indicates importance of the link. 831 * o #interrupts indicates flexibility of the link. 832 */ 833 sum_penalty = 0; 834 for (i = 0; i < link->number_of_interrupts; i++) { 835 irq = link->interrupts[i]; 836 sum_penalty += irq_penalty[irq]; 837 } 838 839 link->priority = (sum_penalty * link->references) / link->number_of_interrupts; 840 } 841 842 /* 843 * Sort PCI links based on the priority. 844 * XXX Any other better ways rather than using work list? 845 */ 846 TAILQ_INIT(&sorted_list); 847 while (!TAILQ_EMPTY(&acpi_pci_link_entries)) { 848 link = TAILQ_FIRST(&acpi_pci_link_entries); 849 /* find an entry which has the highest priority. */ 850 TAILQ_FOREACH(link_pri, &acpi_pci_link_entries, links) { 851 if (link->priority < link_pri->priority) { 852 link = link_pri; 853 } 854 } 855 /* move to work list. */ 856 TAILQ_REMOVE(&acpi_pci_link_entries, link, links); 857 TAILQ_INSERT_TAIL(&sorted_list, link, links); 858 } 859 860 while (!TAILQ_EMPTY(&sorted_list)) { 861 /* move them back to the list, one by one... */ 862 link = TAILQ_FIRST(&sorted_list); 863 TAILQ_REMOVE(&sorted_list, link, links); 864 TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links); 865 } 866 } 867 868 static void 869 acpi_pci_link_fixup_bootdisabled_link(void) 870 { 871 int i, j; 872 int irq1, irq2; 873 struct acpi_pci_link_entry *link; 874 ACPI_STATUS error; 875 876 if (bootverbose) { 877 printf("---- before fixup boot-disabled links -------------\n"); 878 acpi_pci_link_bootdisabled_dump(); 879 } 880 881 TAILQ_FOREACH(link, &acpi_pci_link_entries, links) { 882 /* ignore non boot-disabled links. */ 883 if (link->current_irq != 0) { 884 continue; 885 } 886 887 /* sort IRQs based on their penalty descending. */ 888 for (i = 0; i < link->number_of_interrupts; i++) { 889 irq1 = link->sorted_irq[i]; 890 for (j = i + 1; j < link->number_of_interrupts; j++) { 891 irq2 = link->sorted_irq[j]; 892 if (irq_penalty[irq1] < irq_penalty[irq2]) { 893 continue; 894 } 895 link->sorted_irq[i] = irq2; 896 link->sorted_irq[j] = irq1; 897 irq1 = irq2; 898 } 899 } 900 901 /* try with lower penalty IRQ. */ 902 for (i = 0; i < link->number_of_interrupts - 1; i++) { 903 irq1 = link->sorted_irq[i]; 904 error = acpi_pci_link_set_irq(link, irq1); 905 if (error == AE_OK) { 906 /* OK, we use this. give another penalty. */ 907 irq_penalty[irq1] += 100 * link->references; 908 break; 909 } 910 /* NG, try next IRQ... */ 911 } 912 } 913 914 if (bootverbose) { 915 printf("---- after fixup boot-disabled links --------------\n"); 916 acpi_pci_link_bootdisabled_dump(); 917 } 918 } 919 920 /* 921 * Public interface 922 */ 923 924 int 925 acpi_pci_link_config(device_t dev, ACPI_BUFFER *prtbuf, int busno) 926 { 927 struct acpi_prt_entry *entry; 928 ACPI_PCI_ROUTING_TABLE *prt; 929 u_int8_t *prtp; 930 ACPI_STATUS error; 931 static int first_time =1; 932 933 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 934 935 if (acpi_disabled("pci_link")) { 936 return (0); 937 } 938 939 if (first_time) { 940 TAILQ_INIT(&acpi_prt_entries); 941 TAILQ_INIT(&acpi_pci_link_entries); 942 acpi_pci_link_init_irq_penalty(); 943 first_time = 0; 944 } 945 946 if (prtbuf == NULL) { 947 return (-1); 948 } 949 950 prtp = prtbuf->Pointer; 951 if (prtp == NULL) { /* didn't get routing table */ 952 return (-1); 953 } 954 955 /* scan the PCI Routing Table */ 956 for (;;) { 957 prt = (ACPI_PCI_ROUTING_TABLE *)prtp; 958 959 if (prt->Length == 0) /* end of table */ 960 break; 961 962 error = acpi_pci_link_add_prt(dev, prt, busno); 963 if (ACPI_FAILURE(error)) { 964 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 965 "couldn't add PCI interrupt link entry - %s\n", 966 AcpiFormatException(error))); 967 } 968 969 /* skip to next entry */ 970 prtp += prt->Length; 971 } 972 973 if (bootverbose) { 974 printf("---- initial configuration ------------------------\n"); 975 TAILQ_FOREACH(entry, &acpi_prt_entries, links) { 976 if (entry->busno != busno) { 977 continue; 978 } 979 980 acpi_pci_link_entry_dump(entry); 981 } 982 } 983 984 /* manual configuration. */ 985 TAILQ_FOREACH(entry, &acpi_prt_entries, links) { 986 UINT8 irq; 987 char *irqstr, *op; 988 char prthint[32]; 989 990 if (entry->busno != busno) { 991 continue; 992 } 993 994 snprintf(prthint, sizeof(prthint), 995 "hw.acpi.pci.link.%d.%d.%d.irq", entry->busno, 996 (int)((entry->prt.Address & 0xffff0000) >> 16), 997 (int)entry->prt.Pin); 998 999 irqstr = getenv(prthint); 1000 if (irqstr == NULL) { 1001 continue; 1002 } 1003 1004 irq = strtoul(irqstr, &op, 0); 1005 if (*op != '\0') { 1006 continue; 1007 } 1008 1009 if (acpi_pci_link_is_valid_irq(entry->pci_link, irq)) { 1010 error = acpi_pci_link_set_irq(entry->pci_link, irq); 1011 if (ACPI_FAILURE(error)) { 1012 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 1013 "couldn't set IRQ to PCI interrupt link entry %s - %s\n", 1014 acpi_name(entry->pci_link->handle), 1015 AcpiFormatException(error))); 1016 } 1017 continue; 1018 } 1019 1020 /* 1021 * Do auto arbitration for this device's PCI link 1022 * if hint value 0 is specified. 1023 */ 1024 if (irq == 0) { 1025 entry->pci_link->current_irq = 0; 1026 } 1027 } 1028 1029 /* auto arbitration */ 1030 acpi_pci_link_update_irq_penalty(dev, busno); 1031 acpi_pci_link_set_bootdisabled_priority(); 1032 acpi_pci_link_fixup_bootdisabled_link(); 1033 1034 if (bootverbose) { 1035 printf("---- arbitrated configuration ---------------------\n"); 1036 TAILQ_FOREACH(entry, &acpi_prt_entries, links) { 1037 if (entry->busno != busno) { 1038 continue; 1039 } 1040 1041 acpi_pci_link_entry_dump(entry); 1042 } 1043 } 1044 1045 return (0); 1046 } 1047 1048 int 1049 acpi_pci_link_resume(device_t dev, ACPI_BUFFER *prtbuf, int busno) 1050 { 1051 struct acpi_prt_entry *entry; 1052 ACPI_STATUS error; 1053 1054 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 1055 1056 if (acpi_disabled("pci_link")) { 1057 return (0); 1058 } 1059 1060 TAILQ_FOREACH(entry, &acpi_prt_entries, links) { 1061 if (entry->pcidev != dev) { 1062 continue; 1063 } 1064 1065 error = acpi_pci_link_set_irq(entry->pci_link, 1066 entry->pci_link->current_irq); 1067 if (ACPI_FAILURE(error)) { 1068 ACPI_DEBUG_PRINT((ACPI_DB_WARN, 1069 "couldn't set IRQ to PCI interrupt link entry %s - %s\n", 1070 acpi_name(entry->pci_link->handle), 1071 AcpiFormatException(error))); 1072 } 1073 } 1074 1075 return (0); 1076 } 1077 1078