Google luky.org euqset.org

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 3/4]ACPI callback to get correct PCI device suspend state


Hi,
This is an ACPI callback to get correct PCI device suspend state. BIOS
sometimes reports a different device state from the maximum D-state
gotten from PCI config space.

Thanks,
Shaohua

Signed-off-by: Li Shaohua<shaohua.li@xxxxxxxxx>
---

 2.5-root/drivers/pci/pci-acpi.c   |   19 +++++++++++++++++++
 2.5-root/drivers/pci/pci-driver.c |   29 ++++++++++++++++++++++-------
 2.5-root/drivers/pci/pci.h        |    3 +++
 3 files changed, 44 insertions(+), 7 deletions(-)

diff -puN drivers/pci/pci-acpi.c~acpi-pci-get-suspend-state-callback drivers/pci/pci-acpi.c
--- 2.5/drivers/pci/pci-acpi.c~acpi-pci-get-suspend-state-callback	2005-01-05 09:57:46.949890624 +0800
+++ 2.5-root/drivers/pci/pci-acpi.c	2005-01-05 09:57:46.956889560 +0800
@@ -16,6 +16,7 @@
 #include <acpi/acpi_bus.h>
 
 #include <linux/pci-acpi.h>
+#include "pci.h"
 
 static u32 ctrlset_buf[3] = {0, 0, 0};
 static u32 global_ctrlsets = 0;
@@ -208,6 +209,23 @@ acpi_status pci_osc_control_set(u32 flag
 }
 EXPORT_SYMBOL(pci_osc_control_set);
 
+static int acpi_get_suspend_state(struct device *dev, u32 state)
+{
+	char dstate_str[] = "_S0D";
+	acpi_status status;
+	unsigned long val;
+
+	/* state is PM_SUSPEND_* */
+	if ((state >= PM_SUSPEND_MAX) || !DEVICE_ACPI_HANDLE(dev))
+		return -EINVAL;
+	dstate_str[2] += state;
+	status = acpi_evaluate_integer(DEVICE_ACPI_HANDLE(dev), dstate_str,
+		NULL, &val);
+	if (ACPI_SUCCESS(status))
+		return val;
+	return -ENODEV;
+}
+
 /* ACPI bus type */
 int pci_acpi_bind_device(struct device *dev, acpi_handle *handle)
 {
@@ -250,6 +268,7 @@ static int __init pci_acpi_init(void)
 	ret = register_acpi_bus_type(&pci_acpi_bus);
 	if (ret)
 		return 0;
+	platform_pci_get_suspend_state = acpi_get_suspend_state;
 	return 0;
 }
 arch_initcall(pci_acpi_init);
diff -puN drivers/pci/pci-driver.c~acpi-pci-get-suspend-state-callback drivers/pci/pci-driver.c
--- 2.5/drivers/pci/pci-driver.c~acpi-pci-get-suspend-state-callback	2005-01-05 09:57:46.951890320 +0800
+++ 2.5-root/drivers/pci/pci-driver.c	2005-01-05 09:57:46.956889560 +0800
@@ -284,13 +284,13 @@ static int pci_device_remove(struct devi
 	return 0;
 }
 
-static int pci_device_suspend(struct device * dev, u32 state)
+/*
+ * return value: failed < 0, success >= 0
+ */
+int (*platform_pci_get_suspend_state) (struct device *, u32) = NULL;
+static int pci_get_suspend_state(struct device *dev, u32 state)
 {
-	struct pci_dev * pci_dev = to_pci_dev(dev);
-	struct pci_driver * drv = pci_dev->driver;
-	u32 dev_state;
-	int i = 0;
-
+	int dev_state = -1;
 	/* Translate PM_SUSPEND_xx states to PCI device states */
 	static u32 state_conversion[] = {
 		[PM_SUSPEND_ON] = 0,
@@ -299,10 +299,25 @@ static int pci_device_suspend(struct dev
 		[PM_SUSPEND_DISK] = 3,
 	};
 
+	if (platform_pci_get_suspend_state)
+		dev_state = platform_pci_get_suspend_state(dev, state);
+	if (dev_state >= 0)
+		return dev_state;
 	if (state >= sizeof(state_conversion) / sizeof(state_conversion[1]))
 		return -EINVAL;
+	return state_conversion[state];
+}
 
-	dev_state = state_conversion[state];
+static int pci_device_suspend(struct device * dev, u32 state)
+{
+	struct pci_dev * pci_dev = to_pci_dev(dev);
+	struct pci_driver * drv = pci_dev->driver;
+	int dev_state;
+	int i = 0;
+
+	dev_state = pci_get_suspend_state(dev, state);
+	if (dev_state < 0)
+		return -EINVAL;
 	if (drv && drv->suspend)
 		i = drv->suspend(pci_dev, dev_state);
 	else
diff -puN drivers/pci/pci.h~acpi-pci-get-suspend-state-callback drivers/pci/pci.h
--- 2.5/drivers/pci/pci.h~acpi-pci-get-suspend-state-callback	2005-01-05 09:57:46.952890168 +0800
+++ 2.5-root/drivers/pci/pci.h	2005-01-05 09:57:46.956889560 +0800
@@ -11,6 +11,9 @@ extern int pci_bus_alloc_resource(struct
 				  void (*alignf)(void *, struct resource *,
 					  	 unsigned long, unsigned long),
 				  void *alignf_data);
+/* Firmware callbacks */
+extern int (*platform_pci_get_suspend_state)(struct device *dev, u32 state);
+
 /* PCI /proc functions */
 #ifdef CONFIG_PROC_FS
 extern int pci_proc_attach_device(struct pci_dev *dev);
_

An ACPI callback to get suspend state from firmware.

---

 2.5-root/drivers/pci/pci-acpi.c   |   19 +++++++++++++++++++
 2.5-root/drivers/pci/pci-driver.c |   29 ++++++++++++++++++++++-------
 2.5-root/drivers/pci/pci.h        |    3 +++
 3 files changed, 44 insertions(+), 7 deletions(-)

diff -puN drivers/pci/pci-acpi.c~acpi-pci-get-suspend-state-callback drivers/pci/pci-acpi.c
--- 2.5/drivers/pci/pci-acpi.c~acpi-pci-get-suspend-state-callback	2005-01-05 09:57:46.949890624 +0800
+++ 2.5-root/drivers/pci/pci-acpi.c	2005-01-05 09:57:46.956889560 +0800
@@ -16,6 +16,7 @@
 #include <acpi/acpi_bus.h>
 
 #include <linux/pci-acpi.h>
+#include "pci.h"
 
 static u32 ctrlset_buf[3] = {0, 0, 0};
 static u32 global_ctrlsets = 0;
@@ -208,6 +209,23 @@ acpi_status pci_osc_control_set(u32 flag
 }
 EXPORT_SYMBOL(pci_osc_control_set);
 
+static int acpi_get_suspend_state(struct device *dev, u32 state)
+{
+	char dstate_str[] = "_S0D";
+	acpi_status status;
+	unsigned long val;
+
+	/* state is PM_SUSPEND_* */
+	if ((state >= PM_SUSPEND_MAX) || !DEVICE_ACPI_HANDLE(dev))
+		return -EINVAL;
+	dstate_str[2] += state;
+	status = acpi_evaluate_integer(DEVICE_ACPI_HANDLE(dev), dstate_str,
+		NULL, &val);
+	if (ACPI_SUCCESS(status))
+		return val;
+	return -ENODEV;
+}
+
 /* ACPI bus type */
 int pci_acpi_bind_device(struct device *dev, acpi_handle *handle)
 {
@@ -250,6 +268,7 @@ static int __init pci_acpi_init(void)
 	ret = register_acpi_bus_type(&pci_acpi_bus);
 	if (ret)
 		return 0;
+	platform_pci_get_suspend_state = acpi_get_suspend_state;
 	return 0;
 }
 arch_initcall(pci_acpi_init);
diff -puN drivers/pci/pci-driver.c~acpi-pci-get-suspend-state-callback drivers/pci/pci-driver.c
--- 2.5/drivers/pci/pci-driver.c~acpi-pci-get-suspend-state-callback	2005-01-05 09:57:46.951890320 +0800
+++ 2.5-root/drivers/pci/pci-driver.c	2005-01-05 09:57:46.956889560 +0800
@@ -284,13 +284,13 @@ static int pci_device_remove(struct devi
 	return 0;
 }
 
-static int pci_device_suspend(struct device * dev, u32 state)
+/*
+ * return value: failed < 0, success >= 0
+ */
+int (*platform_pci_get_suspend_state) (struct device *, u32) = NULL;
+static int pci_get_suspend_state(struct device *dev, u32 state)
 {
-	struct pci_dev * pci_dev = to_pci_dev(dev);
-	struct pci_driver * drv = pci_dev->driver;
-	u32 dev_state;
-	int i = 0;
-
+	int dev_state = -1;
 	/* Translate PM_SUSPEND_xx states to PCI device states */
 	static u32 state_conversion[] = {
 		[PM_SUSPEND_ON] = 0,
@@ -299,10 +299,25 @@ static int pci_device_suspend(struct dev
 		[PM_SUSPEND_DISK] = 3,
 	};
 
+	if (platform_pci_get_suspend_state)
+		dev_state = platform_pci_get_suspend_state(dev, state);
+	if (dev_state >= 0)
+		return dev_state;
 	if (state >= sizeof(state_conversion) / sizeof(state_conversion[1]))
 		return -EINVAL;
+	return state_conversion[state];
+}
 
-	dev_state = state_conversion[state];
+static int pci_device_suspend(struct device * dev, u32 state)
+{
+	struct pci_dev * pci_dev = to_pci_dev(dev);
+	struct pci_driver * drv = pci_dev->driver;
+	int dev_state;
+	int i = 0;
+
+	dev_state = pci_get_suspend_state(dev, state);
+	if (dev_state < 0)
+		return -EINVAL;
 	if (drv && drv->suspend)
 		i = drv->suspend(pci_dev, dev_state);
 	else
diff -puN drivers/pci/pci.h~acpi-pci-get-suspend-state-callback drivers/pci/pci.h
--- 2.5/drivers/pci/pci.h~acpi-pci-get-suspend-state-callback	2005-01-05 09:57:46.952890168 +0800
+++ 2.5-root/drivers/pci/pci.h	2005-01-05 09:57:46.956889560 +0800
@@ -11,6 +11,9 @@ extern int pci_bus_alloc_resource(struct
 				  void (*alignf)(void *, struct resource *,
 					  	 unsigned long, unsigned long),
 				  void *alignf_data);
+/* Firmware callbacks */
+extern int (*platform_pci_get_suspend_state)(struct device *dev, u32 state);
+
 /* PCI /proc functions */
 #ifdef CONFIG_PROC_FS
 extern int pci_proc_attach_device(struct pci_dev *dev);
_

$B$3$N>pJs$,$"$J$?$NC5$7$F$$?$b$N$+$I$&$+A*Br$7$F$/$@$5$!#(B
yes/$B$^$5$K$3$l$@!*(B   no/$B0c$&$J$!(B   part/$B0lIt8+$D$+$C$?(B   try/$B$3$l$G;n$7$F$_$k(B

$B$"$J$?$,C5$7$F$$?>pJs$O$I$N$h$&$J$3$H$+!"$4<+M3$K5-F~2<$5$!#FC$K!V$^$5$K$3$l$@!*!W$H8@$&>l9g$O5-F~$r$*4j$$7$^$9!#(B
$BNc(B:$B!VJ#?t$N%^%7%s$+$i(BCATV$B7PM3$G(Bipmasquerade$B$rMxMQ$7$F(BWeb$B$r;2>H$7$?$>l9g$N@_Dj$K$D$$F!W(B