aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/acpiphp.h5
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c101
2 files changed, 92 insertions, 14 deletions
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index be104eced34c..7fff07e877c7 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -150,6 +150,11 @@ struct acpiphp_attention_info
150 struct module *owner; 150 struct module *owner;
151}; 151};
152 152
153struct acpiphp_ioapic {
154 struct pci_dev *dev;
155 u32 gsi_base;
156 struct list_head list;
157};
153 158
154/* PCI bus bridge HID */ 159/* PCI bus bridge HID */
155#define ACPI_PCI_HOST_HID "PNP0A03" 160#define ACPI_PCI_HOST_HID "PNP0A03"
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 712f02fb1cbb..83e8e4412de5 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -53,6 +53,8 @@
53#include "acpiphp.h" 53#include "acpiphp.h"
54 54
55static LIST_HEAD(bridge_list); 55static LIST_HEAD(bridge_list);
56static LIST_HEAD(ioapic_list);
57static DEFINE_SPINLOCK(ioapic_list_lock);
56 58
57#define MY_NAME "acpiphp_glue" 59#define MY_NAME "acpiphp_glue"
58 60
@@ -797,6 +799,7 @@ ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
797 struct pci_dev *pdev; 799 struct pci_dev *pdev;
798 u32 gsi_base; 800 u32 gsi_base;
799 u64 phys_addr; 801 u64 phys_addr;
802 struct acpiphp_ioapic *ioapic;
800 803
801 /* Evaluate _STA if present */ 804 /* Evaluate _STA if present */
802 status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); 805 status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
@@ -811,30 +814,87 @@ ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
811 if (get_gsi_base(handle, &gsi_base)) 814 if (get_gsi_base(handle, &gsi_base))
812 return AE_OK; 815 return AE_OK;
813 816
817 ioapic = kmalloc(sizeof(*ioapic), GFP_KERNEL);
818 if (!ioapic)
819 return AE_NO_MEMORY;
820
814 pdev = get_apic_pci_info(handle); 821 pdev = get_apic_pci_info(handle);
815 if (!pdev) 822 if (!pdev)
816 return AE_OK; 823 goto exit_kfree;
817 824
818 if (pci_enable_device(pdev)) { 825 if (pci_enable_device(pdev))
819 pci_dev_put(pdev); 826 goto exit_pci_dev_put;
820 return AE_OK;
821 }
822 827
823 pci_set_master(pdev); 828 pci_set_master(pdev);
824 829
825 if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) { 830 if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)"))
826 pci_disable_device(pdev); 831 goto exit_pci_disable_device;
827 pci_dev_put(pdev);
828 return AE_OK;
829 }
830 832
831 phys_addr = pci_resource_start(pdev, 0); 833 phys_addr = pci_resource_start(pdev, 0);
832 if (acpi_register_ioapic(handle, phys_addr, gsi_base)) { 834 if (acpi_register_ioapic(handle, phys_addr, gsi_base))
833 pci_release_region(pdev, 0); 835 goto exit_pci_release_region;
834 pci_disable_device(pdev); 836
835 pci_dev_put(pdev); 837 ioapic->gsi_base = gsi_base;
838 ioapic->dev = pdev;
839 spin_lock(&ioapic_list_lock);
840 list_add_tail(&ioapic->list, &ioapic_list);
841 spin_unlock(&ioapic_list_lock);
842
843 return AE_OK;
844
845 exit_pci_release_region:
846 pci_release_region(pdev, 0);
847 exit_pci_disable_device:
848 pci_disable_device(pdev);
849 exit_pci_dev_put:
850 pci_dev_put(pdev);
851 exit_kfree:
852 kfree(ioapic);
853
854 return AE_OK;
855}
856
857static acpi_status
858ioapic_remove(acpi_handle handle, u32 lvl, void *context, void **rv)
859{
860 acpi_status status;
861 unsigned long sta;
862 acpi_handle tmp;
863 u32 gsi_base;
864 struct acpiphp_ioapic *pos, *n, *ioapic = NULL;
865
866 /* Evaluate _STA if present */
867 status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
868 if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL)
869 return AE_CTRL_DEPTH;
870
871 /* Scan only PCI bus scope */
872 status = acpi_get_handle(handle, "_HID", &tmp);
873 if (ACPI_SUCCESS(status))
874 return AE_CTRL_DEPTH;
875
876 if (get_gsi_base(handle, &gsi_base))
836 return AE_OK; 877 return AE_OK;
878
879 acpi_unregister_ioapic(handle, gsi_base);
880
881 spin_lock(&ioapic_list_lock);
882 list_for_each_entry_safe(pos, n, &ioapic_list, list) {
883 if (pos->gsi_base != gsi_base)
884 continue;
885 ioapic = pos;
886 list_del(&ioapic->list);
887 break;
837 } 888 }
889 spin_unlock(&ioapic_list_lock);
890
891 if (!ioapic)
892 return AE_OK;
893
894 pci_release_region(ioapic->dev, 0);
895 pci_disable_device(ioapic->dev);
896 pci_dev_put(ioapic->dev);
897 kfree(ioapic);
838 898
839 return AE_OK; 899 return AE_OK;
840} 900}
@@ -847,6 +907,14 @@ static int acpiphp_configure_ioapics(acpi_handle handle)
847 return 0; 907 return 0;
848} 908}
849 909
910static int acpiphp_unconfigure_ioapics(acpi_handle handle)
911{
912 ioapic_remove(handle, 0, NULL, NULL);
913 acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
914 ACPI_UINT32_MAX, ioapic_remove, NULL, NULL);
915 return 0;
916}
917
850static int power_on_slot(struct acpiphp_slot *slot) 918static int power_on_slot(struct acpiphp_slot *slot)
851{ 919{
852 acpi_status status; 920 acpi_status status;
@@ -1146,7 +1214,12 @@ static int disable_device(struct acpiphp_slot *slot)
1146 pci_disable_device(func->pci_dev); 1214 pci_disable_device(func->pci_dev);
1147 } 1215 }
1148 } 1216 }
1217 }
1218
1219 list_for_each (l, &slot->funcs) {
1220 func = list_entry(l, struct acpiphp_func, sibling);
1149 1221
1222 acpiphp_unconfigure_ioapics(func->handle);
1150 acpiphp_bus_trim(func->handle); 1223 acpiphp_bus_trim(func->handle);
1151 /* try to remove anyway. 1224 /* try to remove anyway.
1152 * acpiphp_bus_add might have been failed */ 1225 * acpiphp_bus_add might have been failed */