Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6:
  PCI Hotplug: acpiphp: don't store a pci_dev in acpiphp_func
This commit is contained in:
Linus Torvalds 2009-05-29 12:17:03 -07:00
commit 5606b7f925
2 changed files with 26 additions and 38 deletions

View File

@ -129,7 +129,6 @@ struct acpiphp_func {
struct acpiphp_bridge *bridge; /* Ejectable PCI-to-PCI bridge */
struct list_head sibling;
struct pci_dev *pci_dev;
struct notifier_block nb;
acpi_handle handle;

View File

@ -32,9 +32,6 @@
/*
* Lifetime rules for pci_dev:
* - The one in acpiphp_func has its refcount elevated by pci_get_slot()
* when the driver is loaded or when an insertion event occurs. It loses
* a refcount when its ejected or the driver unloads.
* - The one in acpiphp_bridge has its refcount elevated by pci_get_slot()
* when the bridge is scanned and it loses a refcount when the bridge
* is removed.
@ -130,6 +127,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
unsigned long long adr, sun;
int device, function, retval;
struct pci_bus *pbus = bridge->pci_bus;
struct pci_dev *pdev;
if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
return AE_OK;
@ -213,10 +211,10 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
newfunc->slot = slot;
list_add_tail(&newfunc->sibling, &slot->funcs);
/* associate corresponding pci_dev */
newfunc->pci_dev = pci_get_slot(pbus, PCI_DEVFN(device, function));
if (newfunc->pci_dev) {
pdev = pci_get_slot(pbus, PCI_DEVFN(device, function));
if (pdev) {
slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
pci_dev_put(pdev);
}
if (is_dock_device(handle)) {
@ -617,7 +615,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
if (ACPI_FAILURE(status))
err("failed to remove notify handler\n");
}
pci_dev_put(func->pci_dev);
list_del(list);
kfree(func);
}
@ -1101,22 +1098,24 @@ static int __ref enable_device(struct acpiphp_slot *slot)
pci_enable_bridges(bus);
pci_bus_add_devices(bus);
/* associate pci_dev to our representation */
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
func->function));
if (!func->pci_dev)
dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
func->function));
if (!dev)
continue;
if (func->pci_dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
func->pci_dev->hdr_type != PCI_HEADER_TYPE_CARDBUS)
if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) {
pci_dev_put(dev);
continue;
}
status = find_p2p_bridge(func->handle, (u32)1, bus, NULL);
if (ACPI_FAILURE(status))
warn("find_p2p_bridge failed (error code = 0x%x)\n",
status);
pci_dev_put(dev);
}
slot->flags |= SLOT_ENABLED;
@ -1142,17 +1141,14 @@ static void disable_bridges(struct pci_bus *bus)
*/
static int disable_device(struct acpiphp_slot *slot)
{
int retval = 0;
struct acpiphp_func *func;
struct list_head *l;
struct pci_dev *pdev;
/* is this slot already disabled? */
if (!(slot->flags & SLOT_ENABLED))
goto err_exit;
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
list_for_each_entry(func, &slot->funcs, sibling) {
if (func->bridge) {
/* cleanup p2p bridges under this P2P bridge */
cleanup_p2p_bridge(func->bridge->handle,
@ -1160,35 +1156,28 @@ static int disable_device(struct acpiphp_slot *slot)
func->bridge = NULL;
}
if (func->pci_dev) {
pci_stop_bus_device(func->pci_dev);
if (func->pci_dev->subordinate) {
disable_bridges(func->pci_dev->subordinate);
pci_disable_device(func->pci_dev);
pdev = pci_get_slot(slot->bridge->pci_bus,
PCI_DEVFN(slot->device, func->function));
if (pdev) {
pci_stop_bus_device(pdev);
if (pdev->subordinate) {
disable_bridges(pdev->subordinate);
pci_disable_device(pdev);
}
pci_remove_bus_device(pdev);
pci_dev_put(pdev);
}
}
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
list_for_each_entry(func, &slot->funcs, sibling) {
acpiphp_unconfigure_ioapics(func->handle);
acpiphp_bus_trim(func->handle);
/* try to remove anyway.
* acpiphp_bus_add might have been failed */
if (!func->pci_dev)
continue;
pci_remove_bus_device(func->pci_dev);
pci_dev_put(func->pci_dev);
func->pci_dev = NULL;
}
slot->flags &= (~SLOT_ENABLED);
err_exit:
return retval;
err_exit:
return 0;
}