diff options
| -rw-r--r-- | drivers/pci/hotplug/acpiphp.h | 10 | ||||
| -rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 60 |
2 files changed, 52 insertions, 18 deletions
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 2b859249303b..b0e61bf261a7 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h | |||
| @@ -142,6 +142,16 @@ static inline acpi_handle func_to_handle(struct acpiphp_func *func) | |||
| 142 | return func_to_acpi_device(func)->handle; | 142 | return func_to_acpi_device(func)->handle; |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | struct acpiphp_root_context { | ||
| 146 | struct acpi_hotplug_context hp; | ||
| 147 | struct acpiphp_bridge *root_bridge; | ||
| 148 | }; | ||
| 149 | |||
| 150 | static inline struct acpiphp_root_context *to_acpiphp_root_context(struct acpi_hotplug_context *hp) | ||
| 151 | { | ||
| 152 | return container_of(hp, struct acpiphp_root_context, hp); | ||
| 153 | } | ||
| 154 | |||
| 145 | /* | 155 | /* |
| 146 | * struct acpiphp_attention_info - device specific attention registration | 156 | * struct acpiphp_attention_info - device specific attention registration |
| 147 | * | 157 | * |
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 75e178330215..91aa3d780138 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
| @@ -373,17 +373,13 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data, | |||
| 373 | 373 | ||
| 374 | static struct acpiphp_bridge *acpiphp_dev_to_bridge(struct acpi_device *adev) | 374 | static struct acpiphp_bridge *acpiphp_dev_to_bridge(struct acpi_device *adev) |
| 375 | { | 375 | { |
| 376 | struct acpiphp_context *context; | ||
| 377 | struct acpiphp_bridge *bridge = NULL; | 376 | struct acpiphp_bridge *bridge = NULL; |
| 378 | 377 | ||
| 379 | acpi_lock_hp_context(); | 378 | acpi_lock_hp_context(); |
| 380 | context = acpiphp_get_context(adev); | 379 | if (adev->hp) { |
| 381 | if (context) { | 380 | bridge = to_acpiphp_root_context(adev->hp)->root_bridge; |
| 382 | bridge = context->bridge; | ||
| 383 | if (bridge) | 381 | if (bridge) |
| 384 | get_bridge(bridge); | 382 | get_bridge(bridge); |
| 385 | |||
| 386 | acpiphp_put_context(context); | ||
| 387 | } | 383 | } |
| 388 | acpi_unlock_hp_context(); | 384 | acpi_unlock_hp_context(); |
| 389 | return bridge; | 385 | return bridge; |
| @@ -881,7 +877,17 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) | |||
| 881 | */ | 877 | */ |
| 882 | get_device(&bus->dev); | 878 | get_device(&bus->dev); |
| 883 | 879 | ||
| 884 | if (!pci_is_root_bus(bridge->pci_bus)) { | 880 | acpi_lock_hp_context(); |
| 881 | if (pci_is_root_bus(bridge->pci_bus)) { | ||
| 882 | struct acpiphp_root_context *root_context; | ||
| 883 | |||
| 884 | root_context = kzalloc(sizeof(*root_context), GFP_KERNEL); | ||
| 885 | if (!root_context) | ||
| 886 | goto err; | ||
| 887 | |||
| 888 | root_context->root_bridge = bridge; | ||
| 889 | acpi_set_hp_context(adev, &root_context->hp, NULL, NULL, NULL); | ||
| 890 | } else { | ||
| 885 | struct acpiphp_context *context; | 891 | struct acpiphp_context *context; |
| 886 | 892 | ||
| 887 | /* | 893 | /* |
| @@ -890,21 +896,16 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) | |||
| 890 | * parent is going to be handled by pciehp, in which case this | 896 | * parent is going to be handled by pciehp, in which case this |
| 891 | * bridge is not interesting to us either. | 897 | * bridge is not interesting to us either. |
| 892 | */ | 898 | */ |
| 893 | acpi_lock_hp_context(); | ||
| 894 | context = acpiphp_get_context(adev); | 899 | context = acpiphp_get_context(adev); |
| 895 | if (!context) { | 900 | if (!context) |
| 896 | acpi_unlock_hp_context(); | 901 | goto err; |
| 897 | put_device(&bus->dev); | 902 | |
| 898 | pci_dev_put(bridge->pci_dev); | ||
| 899 | kfree(bridge); | ||
| 900 | return; | ||
| 901 | } | ||
| 902 | bridge->context = context; | 903 | bridge->context = context; |
| 903 | context->bridge = bridge; | 904 | context->bridge = bridge; |
| 904 | /* Get a reference to the parent bridge. */ | 905 | /* Get a reference to the parent bridge. */ |
| 905 | get_bridge(context->func.parent); | 906 | get_bridge(context->func.parent); |
| 906 | acpi_unlock_hp_context(); | ||
| 907 | } | 907 | } |
| 908 | acpi_unlock_hp_context(); | ||
| 908 | 909 | ||
| 909 | /* Must be added to the list prior to calling acpiphp_add_context(). */ | 910 | /* Must be added to the list prior to calling acpiphp_add_context(). */ |
| 910 | mutex_lock(&bridge_mutex); | 911 | mutex_lock(&bridge_mutex); |
| @@ -919,6 +920,30 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) | |||
| 919 | cleanup_bridge(bridge); | 920 | cleanup_bridge(bridge); |
| 920 | put_bridge(bridge); | 921 | put_bridge(bridge); |
| 921 | } | 922 | } |
| 923 | return; | ||
| 924 | |||
| 925 | err: | ||
| 926 | acpi_unlock_hp_context(); | ||
| 927 | put_device(&bus->dev); | ||
| 928 | pci_dev_put(bridge->pci_dev); | ||
| 929 | kfree(bridge); | ||
| 930 | } | ||
| 931 | |||
| 932 | void acpiphp_drop_bridge(struct acpiphp_bridge *bridge) | ||
| 933 | { | ||
| 934 | if (pci_is_root_bus(bridge->pci_bus)) { | ||
| 935 | struct acpiphp_root_context *root_context; | ||
| 936 | struct acpi_device *adev; | ||
| 937 | |||
| 938 | acpi_lock_hp_context(); | ||
| 939 | adev = ACPI_COMPANION(bridge->pci_bus->bridge); | ||
| 940 | root_context = to_acpiphp_root_context(adev->hp); | ||
| 941 | adev->hp = NULL; | ||
| 942 | acpi_unlock_hp_context(); | ||
| 943 | kfree(root_context); | ||
| 944 | } | ||
| 945 | cleanup_bridge(bridge); | ||
| 946 | put_bridge(bridge); | ||
| 922 | } | 947 | } |
| 923 | 948 | ||
| 924 | /** | 949 | /** |
| @@ -936,8 +961,7 @@ void acpiphp_remove_slots(struct pci_bus *bus) | |||
| 936 | list_for_each_entry(bridge, &bridge_list, list) | 961 | list_for_each_entry(bridge, &bridge_list, list) |
| 937 | if (bridge->pci_bus == bus) { | 962 | if (bridge->pci_bus == bus) { |
| 938 | mutex_unlock(&bridge_mutex); | 963 | mutex_unlock(&bridge_mutex); |
| 939 | cleanup_bridge(bridge); | 964 | acpiphp_drop_bridge(bridge); |
| 940 | put_bridge(bridge); | ||
| 941 | return; | 965 | return; |
| 942 | } | 966 | } |
| 943 | 967 | ||
