[PATCH] acpi_pcihp: Fix programming _HPP values

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>
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c
index 64cb30d..9395fec 100644
--- a/drivers/pci/hotplug/acpi_pcihp.c
+++ b/drivers/pci/hotplug/acpi_pcihp.c
@@ -145,14 +145,27 @@
 
 /* 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 @@
 	 * 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;
-		/* Check if a parent object supports _HPP */
-		pdev = pdev->bus->parent->self;
+		if (acpi_root_bridge(handle))
+			break;
+		status = acpi_get_parent(handle, &phandle);
+		if (ACPI_FAILURE(status))
+			break;
+		handle = phandle;
 	}
 	return status;
 }
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 2a83e6b..4b0988e 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -286,7 +286,7 @@
 {
 	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 @@
 
 	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)
diff --git a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h
index eb0d01d..6913ace 100644
--- a/drivers/pci/hotplug/pci_hotplug.h
+++ b/drivers/pci/hotplug/pci_hotplug.h
@@ -188,7 +188,7 @@
 #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
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 92c1f0f..ce89f58 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -284,7 +284,7 @@
 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;
 }
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 5c70f43..b70fddb 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -196,7 +196,7 @@
 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;
 }