[PATCH] ACPI based I/O APIC hot-plug: acpiphp support

This patch adds PCI based I/O xAPIC hot-add support to ACPIPHP
driver. When PCI root bridge is hot-added, all PCI based I/O xAPICs
under the root bridge are hot-added by this patch. Hot-remove support
is TBD.

Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by Kenji Kaneshige and committed by Greg Kroah-Hartman a0d399a8 0e888adc

+129
+127
drivers/pci/hotplug/acpiphp_glue.c
··· 552 552 } 553 553 } 554 554 555 + static struct pci_dev * get_apic_pci_info(acpi_handle handle) 556 + { 557 + struct acpi_pci_id id; 558 + struct pci_bus *bus; 559 + struct pci_dev *dev; 560 + 561 + if (ACPI_FAILURE(acpi_get_pci_id(handle, &id))) 562 + return NULL; 563 + 564 + bus = pci_find_bus(id.segment, id.bus); 565 + if (!bus) 566 + return NULL; 567 + 568 + dev = pci_get_slot(bus, PCI_DEVFN(id.device, id.function)); 569 + if (!dev) 570 + return NULL; 571 + 572 + if ((dev->class != PCI_CLASS_SYSTEM_PIC_IOAPIC) && 573 + (dev->class != PCI_CLASS_SYSTEM_PIC_IOXAPIC)) 574 + { 575 + pci_dev_put(dev); 576 + return NULL; 577 + } 578 + 579 + return dev; 580 + } 581 + 582 + static int get_gsi_base(acpi_handle handle, u32 *gsi_base) 583 + { 584 + acpi_status status; 585 + int result = -1; 586 + unsigned long gsb; 587 + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 588 + union acpi_object *obj; 589 + void *table; 590 + 591 + status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb); 592 + if (ACPI_SUCCESS(status)) { 593 + *gsi_base = (u32)gsb; 594 + return 0; 595 + } 596 + 597 + status = acpi_evaluate_object(handle, "_MAT", NULL, &buffer); 598 + if (ACPI_FAILURE(status) || !buffer.length || !buffer.pointer) 599 + return -1; 600 + 601 + obj = buffer.pointer; 602 + if (obj->type != ACPI_TYPE_BUFFER) 603 + goto out; 604 + 605 + table = obj->buffer.pointer; 606 + switch (((acpi_table_entry_header *)table)->type) { 607 + case ACPI_MADT_IOSAPIC: 608 + *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base; 609 + result = 0; 610 + break; 611 + case ACPI_MADT_IOAPIC: 612 + *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base; 613 + result = 0; 614 + break; 615 + default: 616 + break; 617 + } 618 + out: 619 + acpi_os_free(buffer.pointer); 620 + return result; 621 + } 622 + 623 + static acpi_status 624 + ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv) 625 + { 626 + acpi_status status; 627 + unsigned long sta; 628 + acpi_handle tmp; 629 + struct pci_dev *pdev; 630 + u32 gsi_base; 631 + u64 phys_addr; 632 + 633 + /* Evaluate _STA if present */ 634 + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); 635 + if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL) 636 + return AE_CTRL_DEPTH; 637 + 638 + /* Scan only PCI bus scope */ 639 + status = acpi_get_handle(handle, "_HID", &tmp); 640 + if (ACPI_SUCCESS(status)) 641 + return AE_CTRL_DEPTH; 642 + 643 + if (get_gsi_base(handle, &gsi_base)) 644 + return AE_OK; 645 + 646 + pdev = get_apic_pci_info(handle); 647 + if (!pdev) 648 + return AE_OK; 649 + 650 + if (pci_enable_device(pdev)) { 651 + pci_dev_put(pdev); 652 + return AE_OK; 653 + } 654 + 655 + pci_set_master(pdev); 656 + 657 + if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) { 658 + pci_disable_device(pdev); 659 + pci_dev_put(pdev); 660 + return AE_OK; 661 + } 662 + 663 + phys_addr = pci_resource_start(pdev, 0); 664 + if (acpi_register_ioapic(handle, phys_addr, gsi_base)) { 665 + pci_release_region(pdev, 0); 666 + pci_disable_device(pdev); 667 + pci_dev_put(pdev); 668 + return AE_OK; 669 + } 670 + 671 + return AE_OK; 672 + } 673 + 674 + static int acpiphp_configure_ioapics(acpi_handle handle) 675 + { 676 + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 677 + ACPI_UINT32_MAX, ioapic_add, NULL, NULL); 678 + return 0; 679 + } 680 + 555 681 static int power_on_slot(struct acpiphp_slot *slot) 556 682 { 557 683 acpi_status status; ··· 1068 942 acpiphp_sanitize_bus(bus); 1069 943 acpiphp_set_hpp_values(handle, bus); 1070 944 pci_enable_bridges(bus); 945 + acpiphp_configure_ioapics(handle); 1071 946 return 0; 1072 947 } 1073 948
+2
include/linux/pci_ids.h
··· 62 62 63 63 #define PCI_BASE_CLASS_SYSTEM 0x08 64 64 #define PCI_CLASS_SYSTEM_PIC 0x0800 65 + #define PCI_CLASS_SYSTEM_PIC_IOAPIC 0x080010 66 + #define PCI_CLASS_SYSTEM_PIC_IOXAPIC 0x080020 65 67 #define PCI_CLASS_SYSTEM_DMA 0x0801 66 68 #define PCI_CLASS_SYSTEM_TIMER 0x0802 67 69 #define PCI_CLASS_SYSTEM_RTC 0x0803