diff options
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r-- | drivers/pci/hotplug/acpiphp.h | 5 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 101 |
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 | ||
153 | struct 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 | ||
55 | static LIST_HEAD(bridge_list); | 55 | static LIST_HEAD(bridge_list); |
56 | static LIST_HEAD(ioapic_list); | ||
57 | static 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 | |||
857 | static acpi_status | ||
858 | ioapic_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 | ||
910 | static 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 | |||
850 | static int power_on_slot(struct acpiphp_slot *slot) | 918 | static 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 */ |