aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Helgaas <bjorn.helgaas@hp.com>2009-10-26 13:20:47 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-11-04 16:06:39 -0500
commit204d49a5613a06eb2fa5c3b842a29b1336cc7995 (patch)
tree942a75a2a900858c7bd34af0669256e09faae577
parent476f644edf7c22b47e6a118e4a1e138112a5ef14 (diff)
PCI hotplug: move IOAPIC support from acpiphp to ioapic driver
This patch moves PCI I/O APIC support from acpiphp to a separate driver. Like pciehp and shpchp, acpiphp handles PCI hotplug, i.e., addition and removal of PCI adapters. But in addition, acpiphp handles some ACPI hotplug, such as the addition of new host bridges, and the I/O APIC support was tangled up with that. I don't think the I/O APIC support needs to be in acpiphp; PCI I/O APICs usually appear as a function on a PCI host bridge, and we'll enumerate the APIC before any of the devices behind the bridge that use it. As far as I know, nobody actually uses I/O APIC hotplug. It depends on acpi_register_ioapic(), which is only implemented for ia64, and I don't think any vendors have supported I/O chassis hotplug yet. Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com> Reviewed-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> CC: Satoru Takeuchi <takeuchi_satoru@jp.fujitsu.com> CC: MUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-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);