[PATCH] acpi_pcihp: Fix programming _HPP values
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Tue, 2 May 2006 01:54:50 +0000 (10:54 +0900)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 19 Jun 2006 21:13:22 +0000 (14:13 -0700)
This patch fixes the problem that hotplug parameters are not programed
when PCI cards are hot-added by ACPIPHP, SHPCHP and PCIEHP driver. The
pci_dev structure being hot-added is not bound to ACPI handle, so we
need to trace PCI bus tree to find ACPI handle.

Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Cc: Kristen Accardi <kristen.c.accardi@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/pci/hotplug/acpi_pcihp.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/pci_hotplug.h
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/shpchp.h

index 64cb30d7fc9a9b1259e3c6b342ebf268a2476268..9395fec73423910dfb1d7fd4454187e22734b0cc 100644 (file)
@@ -145,14 +145,27 @@ EXPORT_SYMBOL_GPL(acpi_run_oshp);
 
 /* acpi_get_hp_params_from_firmware
  *
- * @dev - the pci_dev of the newly added device
+ * @bus - the pci_bus of the bus on which the device is newly added
  * @hpp - allocated by the caller
  */
-acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev,
+acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
                struct hotplug_params *hpp)
 {
        acpi_status status = AE_NOT_FOUND;
-       struct pci_dev *pdev = dev;
+       acpi_handle handle, phandle;
+       struct pci_bus *pbus = bus;
+       struct pci_dev *pdev;
+
+       do {
+               pdev = pbus->self;
+               if (!pdev) {
+                       handle = acpi_get_pci_rootbridge_handle(
+                               pci_domain_nr(pbus), pbus->number);
+                       break;
+               }
+               handle = DEVICE_ACPI_HANDLE(&(pdev->dev));
+               pbus = pbus->parent;
+       } while (!handle);
 
        /*
         * _HPP settings apply to all child buses, until another _HPP is
@@ -160,15 +173,16 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev,
         * look for it in the parent device scope since that would apply to
         * this pci dev. If we don't find any _HPP, use hardcoded defaults
         */
-       while (pdev && (ACPI_FAILURE(status))) {
-               acpi_handle handle = DEVICE_ACPI_HANDLE(&(pdev->dev));
-               if (!handle)
-                       break;
+       while (handle) {
                status = acpi_run_hpp(handle, hpp);
-               if (!(pdev->bus->parent))
+               if (ACPI_SUCCESS(status))
+                       break;
+               if (acpi_root_bridge(handle))
+                       break;
+               status = acpi_get_parent(handle, &phandle);
+               if (ACPI_FAILURE(status))
                        break;
-               /* Check if a parent object supports _HPP */
-               pdev = pdev->bus->parent->self;
+               handle = phandle;
        }
        return status;
 }
index 2a83e6bdab6a17ffd478e051da7d15d4cd2327a5..4b0988e93806ab28c1ded79830e0de185f0f991c 100644 (file)
@@ -286,7 +286,7 @@ static void decode_hpp(struct acpiphp_bridge *bridge)
 {
        acpi_status status;
 
-       status = acpi_get_hp_params_from_firmware(bridge->pci_dev, &bridge->hpp);
+       status = acpi_get_hp_params_from_firmware(bridge->pci_bus, &bridge->hpp);
        if (ACPI_FAILURE(status)) {
                /* use default numbers */
                bridge->hpp.cache_line_size = 0x10;
@@ -1250,6 +1250,7 @@ static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus)
 
        memset(&bridge, 0, sizeof(bridge));
        bridge.handle = handle;
+       bridge.pci_bus = bus;
        bridge.pci_dev = bus->self;
        decode_hpp(&bridge);
        list_for_each_entry(dev, &bus->devices, bus_list)
index eb0d01d47236700ef4b3fb8dc60fcfdf6422f8e2..6913ace70e9b502dcbf4fa159b55c501c4c4cbe7 100644 (file)
@@ -188,7 +188,7 @@ struct hotplug_params {
 #include <acpi/acpi_bus.h>
 #include <acpi/actypes.h>
 extern acpi_status acpi_run_oshp(acpi_handle handle);
-extern acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev,
+extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
                                struct hotplug_params *hpp);
 int acpi_root_bridge(acpi_handle handle);
 #endif
index 92c1f0f1e1ad606ca671e0246c149235acd9f0c8..ce89f5815861ed4a9a4c8a9f0502f8514ff7194d 100644 (file)
@@ -284,7 +284,7 @@ struct hpc_ops {
 static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
                        struct hotplug_params *hpp)
 {
-       if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev, hpp)))
+       if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev->bus, hpp)))
                return -ENODEV;
        return 0;
 }
index 5c70f43908c4288408e8e209f8783a4741a1d819..b70fddbce93475c745e45080e6d160da2b4614bf 100644 (file)
@@ -196,7 +196,7 @@ extern void queue_pushbutton_work(void *data);
 static inline int get_hp_params_from_firmware(struct pci_dev *dev,
                        struct hotplug_params *hpp)
 {
-       if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev, hpp)))
+       if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev->bus, hpp)))
                        return -ENODEV;
        return 0;
 }