diff options
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 127 | ||||
-rw-r--r-- | include/linux/pci_ids.h | 2 |
2 files changed, 129 insertions, 0 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index b4a921236252..424e7de181ae 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -552,6 +552,132 @@ static void remove_bridge(acpi_handle handle) | |||
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 | static int power_on_slot(struct acpiphp_slot *slot) | 681 | static int power_on_slot(struct acpiphp_slot *slot) |
556 | { | 682 | { |
557 | acpi_status status; | 683 | acpi_status status; |
@@ -942,6 +1068,7 @@ static int acpiphp_configure_bridge (acpi_handle handle) | |||
942 | acpiphp_sanitize_bus(bus); | 1068 | acpiphp_sanitize_bus(bus); |
943 | acpiphp_set_hpp_values(handle, bus); | 1069 | acpiphp_set_hpp_values(handle, bus); |
944 | pci_enable_bridges(bus); | 1070 | pci_enable_bridges(bus); |
1071 | acpiphp_configure_ioapics(handle); | ||
945 | return 0; | 1072 | return 0; |
946 | } | 1073 | } |
947 | 1074 | ||
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index bf608808a60c..810bbbcee404 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
@@ -62,6 +62,8 @@ | |||
62 | 62 | ||
63 | #define PCI_BASE_CLASS_SYSTEM 0x08 | 63 | #define PCI_BASE_CLASS_SYSTEM 0x08 |
64 | #define PCI_CLASS_SYSTEM_PIC 0x0800 | 64 | #define PCI_CLASS_SYSTEM_PIC 0x0800 |
65 | #define PCI_CLASS_SYSTEM_PIC_IOAPIC 0x080010 | ||
66 | #define PCI_CLASS_SYSTEM_PIC_IOXAPIC 0x080020 | ||
65 | #define PCI_CLASS_SYSTEM_DMA 0x0801 | 67 | #define PCI_CLASS_SYSTEM_DMA 0x0801 |
66 | #define PCI_CLASS_SYSTEM_TIMER 0x0802 | 68 | #define PCI_CLASS_SYSTEM_TIMER 0x0802 |
67 | #define PCI_CLASS_SYSTEM_RTC 0x0803 | 69 | #define PCI_CLASS_SYSTEM_RTC 0x0803 |