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