[PATCH] acpiphp: configure _PRT - V3
authorMUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com>
Wed, 22 Mar 2006 05:49:09 +0000 (14:49 +0900)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 19 Jun 2006 21:13:21 +0000 (14:13 -0700)
Current acpiphp does not free acpi_device structs when the
PCI devices are removed. When the PCI device is added,
acpi_bus_add() fails because acpi_device struct has already
exists. So, _PRT method does not evaluate.

This patch fixes this issue.

Signed-off-by: MUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/pci/hotplug/acpiphp_glue.c

index 053ee843863c1891bc1398b968456cffd6fc31c0..fadd264b64c32728c66cf4156cb3255f0ac41fbf 100644 (file)
@@ -797,36 +797,6 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
 }
 
 
-
-/**
- *  get_func - get a pointer to acpiphp_func given a slot, device
- *  @slot: slot to search
- *  @dev:  pci_dev struct to match.
- *
- *  This function will increase the reference count of pci_dev,
- *  so callers should call pci_dev_put when complete.
- *
- */
-static struct acpiphp_func *
-get_func(struct acpiphp_slot *slot, struct pci_dev *dev)
-{
-       struct acpiphp_func *func = NULL;
-       struct pci_bus *bus = slot->bridge->pci_bus;
-       struct pci_dev *pdev;
-
-       list_for_each_entry(func, &slot->funcs, sibling) {
-               pdev = pci_get_slot(bus, PCI_DEVFN(slot->device,
-                                       func->function));
-               if (pdev) {
-                       if (pdev == dev)
-                               break;
-                       pci_dev_put(pdev);
-               }
-       }
-       return func;
-}
-
-
 /**
  * acpiphp_bus_add - add a new bus to acpi subsystem
  * @func: acpiphp_func of the bridge
@@ -872,6 +842,28 @@ acpiphp_bus_add_out:
 }
 
 
+/**
+ * acpiphp_bus_trim - trim a bus from acpi subsystem
+ * @handle: handle to acpi namespace
+ *
+ */
+int acpiphp_bus_trim(acpi_handle handle)
+{
+       struct acpi_device *device;
+       int retval;
+
+       retval = acpi_bus_get_device(handle, &device);
+       if (retval) {
+               dbg("acpi_device not found\n");
+               return retval;
+       }
+
+       retval = acpi_bus_trim(device, 1);
+       if (retval)
+               err("cannot remove from acpi list\n");
+
+       return retval;
+}
 
 /**
  * enable_device - enable, configure a slot
@@ -918,19 +910,17 @@ static int enable_device(struct acpiphp_slot *slot)
                        if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
                            dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
                                max = pci_scan_bridge(bus, dev, max, pass);
-                               if (pass && dev->subordinate) {
+                               if (pass && dev->subordinate)
                                        pci_bus_size_bridges(dev->subordinate);
-                                       func = get_func(slot, dev);
-                                       if (func) {
-                                               acpiphp_bus_add(func);
-                                               /* side effect of get_func */
-                                               pci_dev_put(dev);
-                                       }
-                               }
                        }
                }
        }
 
+       list_for_each (l, &slot->funcs) {
+               func = list_entry(l, struct acpiphp_func, sibling);
+               acpiphp_bus_add(func);
+       }
+
        pci_bus_assign_resources(bus);
        acpiphp_sanitize_bus(bus);
        pci_enable_bridges(bus);
@@ -967,6 +957,11 @@ static int disable_device(struct acpiphp_slot *slot)
 
        list_for_each (l, &slot->funcs) {
                func = list_entry(l, struct acpiphp_func, sibling);
+
+               acpiphp_bus_trim(func->handle);
+               /* try to remove anyway.
+                * acpiphp_bus_add might have been failed */
+
                if (!func->pci_dev)
                        continue;