Commit 9d674f21 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'acpi-hotplug'

* acpi-hotplug:
  ACPI / hotplug / PCI: Add hotplug contexts to PCI host bridges
parents 9b758d4e 882d18a7
...@@ -142,6 +142,16 @@ static inline acpi_handle func_to_handle(struct acpiphp_func *func) ...@@ -142,6 +142,16 @@ static inline acpi_handle func_to_handle(struct acpiphp_func *func)
return func_to_acpi_device(func)->handle; return func_to_acpi_device(func)->handle;
} }
struct acpiphp_root_context {
struct acpi_hotplug_context hp;
struct acpiphp_bridge *root_bridge;
};
static inline struct acpiphp_root_context *to_acpiphp_root_context(struct acpi_hotplug_context *hp)
{
return container_of(hp, struct acpiphp_root_context, hp);
}
/* /*
* struct acpiphp_attention_info - device specific attention registration * struct acpiphp_attention_info - device specific attention registration
* *
......
...@@ -373,17 +373,13 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data, ...@@ -373,17 +373,13 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data,
static struct acpiphp_bridge *acpiphp_dev_to_bridge(struct acpi_device *adev) static struct acpiphp_bridge *acpiphp_dev_to_bridge(struct acpi_device *adev)
{ {
struct acpiphp_context *context;
struct acpiphp_bridge *bridge = NULL; struct acpiphp_bridge *bridge = NULL;
acpi_lock_hp_context(); acpi_lock_hp_context();
context = acpiphp_get_context(adev); if (adev->hp) {
if (context) { bridge = to_acpiphp_root_context(adev->hp)->root_bridge;
bridge = context->bridge;
if (bridge) if (bridge)
get_bridge(bridge); get_bridge(bridge);
acpiphp_put_context(context);
} }
acpi_unlock_hp_context(); acpi_unlock_hp_context();
return bridge; return bridge;
...@@ -881,7 +877,17 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) ...@@ -881,7 +877,17 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
*/ */
get_device(&bus->dev); get_device(&bus->dev);
if (!pci_is_root_bus(bridge->pci_bus)) { acpi_lock_hp_context();
if (pci_is_root_bus(bridge->pci_bus)) {
struct acpiphp_root_context *root_context;
root_context = kzalloc(sizeof(*root_context), GFP_KERNEL);
if (!root_context)
goto err;
root_context->root_bridge = bridge;
acpi_set_hp_context(adev, &root_context->hp, NULL, NULL, NULL);
} else {
struct acpiphp_context *context; struct acpiphp_context *context;
/* /*
...@@ -890,21 +896,16 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) ...@@ -890,21 +896,16 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
* parent is going to be handled by pciehp, in which case this * parent is going to be handled by pciehp, in which case this
* bridge is not interesting to us either. * bridge is not interesting to us either.
*/ */
acpi_lock_hp_context();
context = acpiphp_get_context(adev); context = acpiphp_get_context(adev);
if (!context) { if (!context)
acpi_unlock_hp_context(); goto err;
put_device(&bus->dev);
pci_dev_put(bridge->pci_dev);
kfree(bridge);
return;
}
bridge->context = context; bridge->context = context;
context->bridge = bridge; context->bridge = bridge;
/* Get a reference to the parent bridge. */ /* Get a reference to the parent bridge. */
get_bridge(context->func.parent); get_bridge(context->func.parent);
acpi_unlock_hp_context();
} }
acpi_unlock_hp_context();
/* Must be added to the list prior to calling acpiphp_add_context(). */ /* Must be added to the list prior to calling acpiphp_add_context(). */
mutex_lock(&bridge_mutex); mutex_lock(&bridge_mutex);
...@@ -919,6 +920,30 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) ...@@ -919,6 +920,30 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
cleanup_bridge(bridge); cleanup_bridge(bridge);
put_bridge(bridge); put_bridge(bridge);
} }
return;
err:
acpi_unlock_hp_context();
put_device(&bus->dev);
pci_dev_put(bridge->pci_dev);
kfree(bridge);
}
void acpiphp_drop_bridge(struct acpiphp_bridge *bridge)
{
if (pci_is_root_bus(bridge->pci_bus)) {
struct acpiphp_root_context *root_context;
struct acpi_device *adev;
acpi_lock_hp_context();
adev = ACPI_COMPANION(bridge->pci_bus->bridge);
root_context = to_acpiphp_root_context(adev->hp);
adev->hp = NULL;
acpi_unlock_hp_context();
kfree(root_context);
}
cleanup_bridge(bridge);
put_bridge(bridge);
} }
/** /**
...@@ -936,8 +961,7 @@ void acpiphp_remove_slots(struct pci_bus *bus) ...@@ -936,8 +961,7 @@ void acpiphp_remove_slots(struct pci_bus *bus)
list_for_each_entry(bridge, &bridge_list, list) list_for_each_entry(bridge, &bridge_list, list)
if (bridge->pci_bus == bus) { if (bridge->pci_bus == bus) {
mutex_unlock(&bridge_mutex); mutex_unlock(&bridge_mutex);
cleanup_bridge(bridge); acpiphp_drop_bridge(bridge);
put_bridge(bridge);
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment