diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-07-07 10:17:56 +0200 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-07-07 10:17:56 +0200 |
commit | f1615bbe9be4def59c3b3eaddb60722efeed16c2 (patch) | |
tree | ca3020e65447576fc1826e819651e6ba072030b5 /drivers/pci/hotplug/acpiphp_glue.c | |
parent | cfb3c0ab0903abb6ea5215b37eebd9c2a1f057eb (diff) | |
parent | cd3de83f147601356395b57a8673e9c5ff1e59d1 (diff) |
Merge tag 'v3.16-rc4' into drm-intel-next-queued
Due to Dave's vacation drm-next hasn't opened yet for 3.17 so I
couldn't move my drm-intel-next queue forward yet like I usually do.
Just pull in the latest upstream -rc to unblock patch merging - I
don't want to needlessly rebase my current patch pile really and void
all the testing we've done already.
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 72 |
1 files changed, 46 insertions, 26 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index bccc27ee103..602d153c705 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -41,7 +41,6 @@ #define pr_fmt(fmt) "acpiphp_glue: " fmt -#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> @@ -352,11 +351,9 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data, slot->slot = NULL; bridge->nr_slots--; if (retval == -EBUSY) - pr_warn("Slot %llu already registered by another " - "hotplug driver\n", sun); + pr_warn("Slot %llu already registered by another hotplug driver\n", sun); else - pr_warn("acpiphp_register_hotplug_slot failed " - "(err code = 0x%x)\n", retval); + pr_warn("acpiphp_register_hotplug_slot failed (err code = 0x%x)\n", retval); } /* Even if the slot registration fails, we can still use it. */ } @@ -374,17 +371,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) { - struct acpiphp_context *context; struct acpiphp_bridge *bridge = NULL; acpi_lock_hp_context(); - context = acpiphp_get_context(adev); - if (context) { - bridge = context->bridge; + if (adev->hp) { + bridge = to_acpiphp_root_context(adev->hp)->root_bridge; if (bridge) get_bridge(bridge); - - acpiphp_put_context(context); } acpi_unlock_hp_context(); return bridge; @@ -501,7 +494,7 @@ static int acpiphp_rescan_slot(struct acpiphp_slot *slot) * This function should be called per *physical slot*, * not per each slot object in ACPI namespace. */ -static void __ref enable_slot(struct acpiphp_slot *slot) +static void enable_slot(struct acpiphp_slot *slot) { struct pci_dev *dev; struct pci_bus *bus = slot->bus; @@ -516,8 +509,7 @@ static void __ref enable_slot(struct acpiphp_slot *slot) if (PCI_SLOT(dev->devfn) != slot->device) continue; - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { + if (pci_is_bridge(dev)) { max = pci_scan_bridge(bus, dev, max, pass); if (pass && dev->subordinate) { check_hotplug_bridge(slot, dev); @@ -883,7 +875,17 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) */ 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; /* @@ -892,21 +894,16 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) * parent is going to be handled by pciehp, in which case this * bridge is not interesting to us either. */ - acpi_lock_hp_context(); context = acpiphp_get_context(adev); - if (!context) { - acpi_unlock_hp_context(); - put_device(&bus->dev); - pci_dev_put(bridge->pci_dev); - kfree(bridge); - return; - } + if (!context) + goto err; + bridge->context = context; context->bridge = bridge; /* Get a reference to the parent bridge. */ 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(). */ mutex_lock(&bridge_mutex); @@ -921,6 +918,30 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) cleanup_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); } /** @@ -938,8 +959,7 @@ void acpiphp_remove_slots(struct pci_bus *bus) list_for_each_entry(bridge, &bridge_list, list) if (bridge->pci_bus == bus) { mutex_unlock(&bridge_mutex); - cleanup_bridge(bridge); - put_bridge(bridge); + acpiphp_drop_bridge(bridge); return; } |