diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-04-30 16:36:33 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-04-30 16:36:33 -0400 |
| commit | a8d22396302b7e4e5f0a594c1c1594388c29edaf (patch) | |
| tree | ff9eb13f13b502f52f7135396fcd1b926fd4fcbe /drivers/pnp | |
| parent | b3413afb4a8995a67f5df6218c6d0ff3a53a6978 (diff) | |
PNP / ACPI: Do not return errors if _DIS or _SRS are not present
The ACPI PNP subsystem returns errors from pnpacpi_set_resources()
and pnpacpi_disable_resources() if the _SRS or _DIS methods are not
present, respectively, but it should not do that, because those
methods are optional. For this reason, modify pnpacpi_set_resources()
and pnpacpi_disable_resources(), respectively, to ignore missing _SRS
or _DIS.
This problem has been uncovered by commit 202317a573b2 (ACPI / scan:
Add acpi_device objects for all device nodes in the namespace) and
manifested itself by causing serial port suspend to fail on some
systems.
Fixes: 202317a573b2 (ACPI / scan: Add acpi_device objects for all device nodes in the namespace)
References: https://bugzilla.kernel.org/show_bug.cgi?id=74371
Reported-by: wxg4net <wxg4net@gmail.com>
Reported-and-tested-by: <nonproffessional@gmail.com>
Cc: 3.14+ <stable@vger.kernel.org> # 3.14+
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/pnp')
| -rw-r--r-- | drivers/pnp/pnpacpi/core.c | 44 |
1 files changed, 26 insertions, 18 deletions
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 9f611cbbc294..c31aa07b3ba5 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c | |||
| @@ -83,8 +83,7 @@ static int pnpacpi_set_resources(struct pnp_dev *dev) | |||
| 83 | { | 83 | { |
| 84 | struct acpi_device *acpi_dev; | 84 | struct acpi_device *acpi_dev; |
| 85 | acpi_handle handle; | 85 | acpi_handle handle; |
| 86 | struct acpi_buffer buffer; | 86 | int ret = 0; |
| 87 | int ret; | ||
| 88 | 87 | ||
| 89 | pnp_dbg(&dev->dev, "set resources\n"); | 88 | pnp_dbg(&dev->dev, "set resources\n"); |
| 90 | 89 | ||
| @@ -97,19 +96,26 @@ static int pnpacpi_set_resources(struct pnp_dev *dev) | |||
| 97 | if (WARN_ON_ONCE(acpi_dev != dev->data)) | 96 | if (WARN_ON_ONCE(acpi_dev != dev->data)) |
| 98 | dev->data = acpi_dev; | 97 | dev->data = acpi_dev; |
| 99 | 98 | ||
| 100 | ret = pnpacpi_build_resource_template(dev, &buffer); | 99 | if (acpi_has_method(handle, METHOD_NAME__SRS)) { |
| 101 | if (ret) | 100 | struct acpi_buffer buffer; |
| 102 | return ret; | 101 | |
| 103 | ret = pnpacpi_encode_resources(dev, &buffer); | 102 | ret = pnpacpi_build_resource_template(dev, &buffer); |
| 104 | if (ret) { | 103 | if (ret) |
| 104 | return ret; | ||
| 105 | |||
| 106 | ret = pnpacpi_encode_resources(dev, &buffer); | ||
| 107 | if (!ret) { | ||
| 108 | acpi_status status; | ||
| 109 | |||
| 110 | status = acpi_set_current_resources(handle, &buffer); | ||
| 111 | if (ACPI_FAILURE(status)) | ||
| 112 | ret = -EIO; | ||
| 113 | } | ||
| 105 | kfree(buffer.pointer); | 114 | kfree(buffer.pointer); |
| 106 | return ret; | ||
| 107 | } | 115 | } |
| 108 | if (ACPI_FAILURE(acpi_set_current_resources(handle, &buffer))) | 116 | if (!ret && acpi_bus_power_manageable(handle)) |
| 109 | ret = -EINVAL; | ||
| 110 | else if (acpi_bus_power_manageable(handle)) | ||
| 111 | ret = acpi_bus_set_power(handle, ACPI_STATE_D0); | 117 | ret = acpi_bus_set_power(handle, ACPI_STATE_D0); |
| 112 | kfree(buffer.pointer); | 118 | |
| 113 | return ret; | 119 | return ret; |
| 114 | } | 120 | } |
| 115 | 121 | ||
| @@ -117,7 +123,7 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev) | |||
| 117 | { | 123 | { |
| 118 | struct acpi_device *acpi_dev; | 124 | struct acpi_device *acpi_dev; |
| 119 | acpi_handle handle; | 125 | acpi_handle handle; |
| 120 | int ret; | 126 | acpi_status status; |
| 121 | 127 | ||
| 122 | dev_dbg(&dev->dev, "disable resources\n"); | 128 | dev_dbg(&dev->dev, "disable resources\n"); |
| 123 | 129 | ||
| @@ -128,13 +134,15 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev) | |||
| 128 | } | 134 | } |
| 129 | 135 | ||
| 130 | /* acpi_unregister_gsi(pnp_irq(dev, 0)); */ | 136 | /* acpi_unregister_gsi(pnp_irq(dev, 0)); */ |
| 131 | ret = 0; | ||
| 132 | if (acpi_bus_power_manageable(handle)) | 137 | if (acpi_bus_power_manageable(handle)) |
| 133 | acpi_bus_set_power(handle, ACPI_STATE_D3_COLD); | 138 | acpi_bus_set_power(handle, ACPI_STATE_D3_COLD); |
| 134 | /* continue even if acpi_bus_set_power() fails */ | 139 | |
| 135 | if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DIS", NULL, NULL))) | 140 | /* continue even if acpi_bus_set_power() fails */ |
| 136 | ret = -ENODEV; | 141 | status = acpi_evaluate_object(handle, "_DIS", NULL, NULL); |
| 137 | return ret; | 142 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) |
| 143 | return -ENODEV; | ||
| 144 | |||
| 145 | return 0; | ||
| 138 | } | 146 | } |
| 139 | 147 | ||
| 140 | #ifdef CONFIG_ACPI_SLEEP | 148 | #ifdef CONFIG_ACPI_SLEEP |
