diff options
| author | Satoru Takeuchi <takeuchi_satoru@jp.fujitsu.com> | 2006-09-12 13:22:53 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-09-26 20:43:54 -0400 |
| commit | 600812ecead0da2e7b6f9e5f5aad68b1ad8ae581 (patch) | |
| tree | db714ba8a865f45ccd6d741f0218001f37f27210 | |
| parent | 23186279658cea6d42a050400d3e79c56cb459b4 (diff) | |
acpiphp: add support for ioapic hot-remove
This patch adds support for ioapics hot-remove.
Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: MUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com>
Signed-off-by: Satoru Takeuchi <takeuchi_satoru@jp.fujitsu.com>
Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -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 */ |
