aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/Kconfig7
-rw-r--r--drivers/pci/Makefile2
-rw-r--r--drivers/pci/hotplug/acpiphp.h6
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c190
-rw-r--r--drivers/pci/ioapic.c127
5 files changed, 136 insertions, 196 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index fdc864f9cf23..d7d28aef8a27 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -69,3 +69,10 @@ config PCI_IOV
69 physical resources. 69 physical resources.
70 70
71 If unsure, say N. 71 If unsure, say N.
72
73config PCI_IOAPIC
74 bool
75 depends on PCI
76 depends on ACPI
77 depends on HOTPLUG
78 default y
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 4a7f11d8f432..4df48d58eaa6 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -14,6 +14,8 @@ CFLAGS_legacy.o += -Wno-deprecated-declarations
14# Build PCI Express stuff if needed 14# Build PCI Express stuff if needed
15obj-$(CONFIG_PCIEPORTBUS) += pcie/ 15obj-$(CONFIG_PCIEPORTBUS) += pcie/
16 16
17obj-$(CONFIG_PCI_IOAPIC) += ioapic.o
18
17obj-$(CONFIG_HOTPLUG) += hotplug.o 19obj-$(CONFIG_HOTPLUG) += hotplug.o
18 20
19# Build the PCI Hotplug drivers if we were asked to 21# Build the PCI Hotplug drivers if we were asked to
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index 7d938df79206..bab52047baa8 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -146,12 +146,6 @@ struct acpiphp_attention_info
146 struct module *owner; 146 struct module *owner;
147}; 147};
148 148
149struct acpiphp_ioapic {
150 struct pci_dev *dev;
151 u32 gsi_base;
152 struct list_head list;
153};
154
155/* PCI bus bridge HID */ 149/* PCI bus bridge HID */
156#define ACPI_PCI_HOST_HID "PNP0A03" 150#define ACPI_PCI_HOST_HID "PNP0A03"
157 151
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 58d25a163a8b..392e4b3fa2e4 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -52,8 +52,6 @@
52#include "acpiphp.h" 52#include "acpiphp.h"
53 53
54static LIST_HEAD(bridge_list); 54static LIST_HEAD(bridge_list);
55static LIST_HEAD(ioapic_list);
56static DEFINE_SPINLOCK(ioapic_list_lock);
57 55
58#define MY_NAME "acpiphp_glue" 56#define MY_NAME "acpiphp_glue"
59 57
@@ -606,190 +604,6 @@ static void remove_bridge(acpi_handle handle)
606 handle_hotplug_event_bridge); 604 handle_hotplug_event_bridge);
607} 605}
608 606
609static struct pci_dev * get_apic_pci_info(acpi_handle handle)
610{
611 struct pci_dev *dev;
612
613 dev = acpi_get_pci_dev(handle);
614 if (!dev)
615 return NULL;
616
617 if ((dev->class != PCI_CLASS_SYSTEM_PIC_IOAPIC) &&
618 (dev->class != PCI_CLASS_SYSTEM_PIC_IOXAPIC))
619 {
620 pci_dev_put(dev);
621 return NULL;
622 }
623
624 return dev;
625}
626
627static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
628{
629 acpi_status status;
630 int result = -1;
631 unsigned long long gsb;
632 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
633 union acpi_object *obj;
634 void *table;
635
636 status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
637 if (ACPI_SUCCESS(status)) {
638 *gsi_base = (u32)gsb;
639 return 0;
640 }
641
642 status = acpi_evaluate_object(handle, "_MAT", NULL, &buffer);
643 if (ACPI_FAILURE(status) || !buffer.length || !buffer.pointer)
644 return -1;
645
646 obj = buffer.pointer;
647 if (obj->type != ACPI_TYPE_BUFFER)
648 goto out;
649
650 table = obj->buffer.pointer;
651 switch (((struct acpi_subtable_header *)table)->type) {
652 case ACPI_MADT_TYPE_IO_SAPIC:
653 *gsi_base = ((struct acpi_madt_io_sapic *)table)->global_irq_base;
654 result = 0;
655 break;
656 case ACPI_MADT_TYPE_IO_APIC:
657 *gsi_base = ((struct acpi_madt_io_apic *)table)->global_irq_base;
658 result = 0;
659 break;
660 default:
661 break;
662 }
663 out:
664 kfree(buffer.pointer);
665 return result;
666}
667
668static acpi_status
669ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
670{
671 acpi_status status;
672 unsigned long long sta;
673 acpi_handle tmp;
674 struct pci_dev *pdev;
675 u32 gsi_base;
676 u64 phys_addr;
677 struct acpiphp_ioapic *ioapic;
678
679 /* Evaluate _STA if present */
680 status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
681 if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL)
682 return AE_CTRL_DEPTH;
683
684 /* Scan only PCI bus scope */
685 status = acpi_get_handle(handle, "_HID", &tmp);
686 if (ACPI_SUCCESS(status))
687 return AE_CTRL_DEPTH;
688
689 if (get_gsi_base(handle, &gsi_base))
690 return AE_OK;
691
692 ioapic = kmalloc(sizeof(*ioapic), GFP_KERNEL);
693 if (!ioapic)
694 return AE_NO_MEMORY;
695
696 pdev = get_apic_pci_info(handle);
697 if (!pdev)
698 goto exit_kfree;
699
700 if (pci_enable_device(pdev))
701 goto exit_pci_dev_put;
702
703 pci_set_master(pdev);
704
705 if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)"))
706 goto exit_pci_disable_device;
707
708 phys_addr = pci_resource_start(pdev, 0);
709 if (acpi_register_ioapic(handle, phys_addr, gsi_base))
710 goto exit_pci_release_region;
711
712 ioapic->gsi_base = gsi_base;
713 ioapic->dev = pdev;
714 spin_lock(&ioapic_list_lock);
715 list_add_tail(&ioapic->list, &ioapic_list);
716 spin_unlock(&ioapic_list_lock);
717
718 return AE_OK;
719
720 exit_pci_release_region:
721 pci_release_region(pdev, 0);
722 exit_pci_disable_device:
723 pci_disable_device(pdev);
724 exit_pci_dev_put:
725 pci_dev_put(pdev);
726 exit_kfree:
727 kfree(ioapic);
728
729 return AE_OK;
730}
731
732static acpi_status
733ioapic_remove(acpi_handle handle, u32 lvl, void *context, void **rv)
734{
735 acpi_status status;
736 unsigned long long sta;
737 acpi_handle tmp;
738 u32 gsi_base;
739 struct acpiphp_ioapic *pos, *n, *ioapic = NULL;
740
741 /* Evaluate _STA if present */
742 status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
743 if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL)
744 return AE_CTRL_DEPTH;
745
746 /* Scan only PCI bus scope */
747 status = acpi_get_handle(handle, "_HID", &tmp);
748 if (ACPI_SUCCESS(status))
749 return AE_CTRL_DEPTH;
750
751 if (get_gsi_base(handle, &gsi_base))
752 return AE_OK;
753
754 acpi_unregister_ioapic(handle, gsi_base);
755
756 spin_lock(&ioapic_list_lock);
757 list_for_each_entry_safe(pos, n, &ioapic_list, list) {
758 if (pos->gsi_base != gsi_base)
759 continue;
760 ioapic = pos;
761 list_del(&ioapic->list);
762 break;
763 }
764 spin_unlock(&ioapic_list_lock);
765
766 if (!ioapic)
767 return AE_OK;
768
769 pci_release_region(ioapic->dev, 0);
770 pci_disable_device(ioapic->dev);
771 pci_dev_put(ioapic->dev);
772 kfree(ioapic);
773
774 return AE_OK;
775}
776
777static int acpiphp_configure_ioapics(acpi_handle handle)
778{
779 ioapic_add(handle, 0, NULL, NULL);
780 acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
781 ACPI_UINT32_MAX, ioapic_add, NULL, NULL);
782 return 0;
783}
784
785static int acpiphp_unconfigure_ioapics(acpi_handle handle)
786{
787 ioapic_remove(handle, 0, NULL, NULL);
788 acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
789 ACPI_UINT32_MAX, ioapic_remove, NULL, NULL);
790 return 0;
791}
792
793static int power_on_slot(struct acpiphp_slot *slot) 607static int power_on_slot(struct acpiphp_slot *slot)
794{ 608{
795 acpi_status status; 609 acpi_status status;
@@ -1014,8 +828,6 @@ static int __ref enable_device(struct acpiphp_slot *slot)
1014 pci_bus_assign_resources(bus); 828 pci_bus_assign_resources(bus);
1015 acpiphp_sanitize_bus(bus); 829 acpiphp_sanitize_bus(bus);
1016 acpiphp_set_hpp_values(bus); 830 acpiphp_set_hpp_values(bus);
1017 list_for_each_entry(func, &slot->funcs, sibling)
1018 acpiphp_configure_ioapics(func->handle);
1019 pci_enable_bridges(bus); 831 pci_enable_bridges(bus);
1020 pci_bus_add_devices(bus); 832 pci_bus_add_devices(bus);
1021 833
@@ -1091,7 +903,6 @@ static int disable_device(struct acpiphp_slot *slot)
1091 } 903 }
1092 904
1093 list_for_each_entry(func, &slot->funcs, sibling) { 905 list_for_each_entry(func, &slot->funcs, sibling) {
1094 acpiphp_unconfigure_ioapics(func->handle);
1095 acpiphp_bus_trim(func->handle); 906 acpiphp_bus_trim(func->handle);
1096 } 907 }
1097 908
@@ -1275,7 +1086,6 @@ static int acpiphp_configure_bridge (acpi_handle handle)
1275 acpiphp_sanitize_bus(bus); 1086 acpiphp_sanitize_bus(bus);
1276 acpiphp_set_hpp_values(bus); 1087 acpiphp_set_hpp_values(bus);
1277 pci_enable_bridges(bus); 1088 pci_enable_bridges(bus);
1278 acpiphp_configure_ioapics(handle);
1279 return 0; 1089 return 0;
1280} 1090}
1281 1091
diff --git a/drivers/pci/ioapic.c b/drivers/pci/ioapic.c
new file mode 100644
index 000000000000..3e0d7b5dd1b9
--- /dev/null
+++ b/drivers/pci/ioapic.c
@@ -0,0 +1,127 @@
1/*
2 * IOAPIC/IOxAPIC/IOSAPIC driver
3 *
4 * Copyright (C) 2009 Fujitsu Limited.
5 * (c) Copyright 2009 Hewlett-Packard Development Company, L.P.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12/*
13 * This driver manages PCI I/O APICs added by hotplug after boot. We try to
14 * claim all I/O APIC PCI devices, but those present at boot were registered
15 * when we parsed the ACPI MADT, so we'll fail when we try to re-register
16 * them.
17 */
18
19#include <linux/pci.h>
20#include <linux/acpi.h>
21#include <acpi/acpi_bus.h>
22
23struct ioapic {
24 acpi_handle handle;
25 u32 gsi_base;
26};
27
28static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent)
29{
30 acpi_handle handle;
31 acpi_status status;
32 unsigned long long gsb;
33 struct ioapic *ioapic;
34 u64 addr;
35 int ret;
36 char *type;
37
38 handle = DEVICE_ACPI_HANDLE(&dev->dev);
39 if (!handle)
40 return -EINVAL;
41
42 status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
43 if (ACPI_FAILURE(status))
44 return -EINVAL;
45
46 /*
47 * The previous code in acpiphp evaluated _MAT if _GSB failed, but
48 * ACPI spec 4.0 sec 6.2.2 requires _GSB for hot-pluggable I/O APICs.
49 */
50
51 ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
52 if (!ioapic)
53 return -ENOMEM;
54
55 ioapic->handle = handle;
56 ioapic->gsi_base = (u32) gsb;
57
58 if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
59 type = "IOAPIC";
60 else
61 type = "IOxAPIC";
62
63 ret = pci_enable_device(dev);
64 if (ret < 0)
65 goto exit_free;
66
67 pci_set_master(dev);
68
69 if (pci_request_region(dev, 0, type))
70 goto exit_disable;
71
72 addr = pci_resource_start(dev, 0);
73 if (acpi_register_ioapic(ioapic->handle, addr, ioapic->gsi_base))
74 goto exit_release;
75
76 pci_set_drvdata(dev, ioapic);
77 dev_info(&dev->dev, "%s at %#llx, GSI %u\n", type, addr,
78 ioapic->gsi_base);
79 return 0;
80
81exit_release:
82 pci_release_region(dev, 0);
83exit_disable:
84 pci_disable_device(dev);
85exit_free:
86 kfree(ioapic);
87 return -ENODEV;
88}
89
90static void ioapic_remove(struct pci_dev *dev)
91{
92 struct ioapic *ioapic = pci_get_drvdata(dev);
93
94 acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base);
95 pci_release_region(dev, 0);
96 pci_disable_device(dev);
97 kfree(ioapic);
98}
99
100
101static struct pci_device_id ioapic_devices[] = {
102 { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
103 PCI_CLASS_SYSTEM_PIC_IOAPIC << 8, 0xffff00, },
104 { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
105 PCI_CLASS_SYSTEM_PIC_IOXAPIC << 8, 0xffff00, },
106 { }
107};
108
109static struct pci_driver ioapic_driver = {
110 .name = "ioapic",
111 .id_table = ioapic_devices,
112 .probe = ioapic_probe,
113 .remove = __devexit_p(ioapic_remove),
114};
115
116static int __init ioapic_init(void)
117{
118 return pci_register_driver(&ioapic_driver);
119}
120
121static void __exit ioapic_exit(void)
122{
123 pci_unregister_driver(&ioapic_driver);
124}
125
126module_init(ioapic_init);
127module_exit(ioapic_exit);