aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-17 08:11:07 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-17 08:11:07 -0500
commite88c9c603b2ad0cd0fbe90afedba3f1becbbeb79 (patch)
tree55b9f2e2af6547cbb1eab54371a674356a12ba87 /drivers
parentef85bdbec444b42775a18580c6bfe1307a63ef0f (diff)
ACPI: Take power resource initialization errors into account
Some ACPI power resource initialization errors, like memory allocation errors, are not taken into account appropriately in some cases, which may lead to a device having an incomplete list of power resources that one of its power states depends on, for one example. Rework the power resource initialization and namespace scanning code so that power resource initialization errors are treated more seriously. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/internal.h7
-rw-r--r--drivers/acpi/power.c44
-rw-r--r--drivers/acpi/scan.c57
3 files changed, 53 insertions, 55 deletions
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index c35435e3d760..8a6c67c9da42 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -51,10 +51,9 @@ void acpi_free_ids(struct acpi_device *device);
51 -------------------------------------------------------------------------- */ 51 -------------------------------------------------------------------------- */
52int acpi_power_init(void); 52int acpi_power_init(void);
53void acpi_power_resources_list_free(struct list_head *list); 53void acpi_power_resources_list_free(struct list_head *list);
54acpi_status acpi_extract_power_resources(union acpi_object *package, 54int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
55 unsigned int start, 55 struct list_head *list);
56 struct list_head *list); 56int acpi_add_power_resource(acpi_handle handle);
57void acpi_add_power_resource(acpi_handle handle);
58void acpi_power_add_remove_device(struct acpi_device *adev, bool add); 57void acpi_power_add_remove_device(struct acpi_device *adev, bool add);
59int acpi_device_sleep_wake(struct acpi_device *dev, 58int acpi_device_sleep_wake(struct acpi_device *dev,
60 int enable, int sleep_state, int dev_state); 59 int enable, int sleep_state, int dev_state);
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 4b93c97aff9f..1600f753fafe 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -97,18 +97,18 @@ static struct acpi_power_resource *acpi_power_get_context(acpi_handle handle)
97 return container_of(device, struct acpi_power_resource, device); 97 return container_of(device, struct acpi_power_resource, device);
98} 98}
99 99
100static void acpi_power_resources_list_add(acpi_handle handle, 100static int acpi_power_resources_list_add(acpi_handle handle,
101 struct list_head *list) 101 struct list_head *list)
102{ 102{
103 struct acpi_power_resource *resource = acpi_power_get_context(handle); 103 struct acpi_power_resource *resource = acpi_power_get_context(handle);
104 struct acpi_power_resource_entry *entry; 104 struct acpi_power_resource_entry *entry;
105 105
106 if (!resource || !list) 106 if (!resource || !list)
107 return; 107 return -EINVAL;
108 108
109 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 109 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
110 if (!entry) 110 if (!entry)
111 return; 111 return -ENOMEM;
112 112
113 entry->resource = resource; 113 entry->resource = resource;
114 if (!list_empty(list)) { 114 if (!list_empty(list)) {
@@ -117,10 +117,11 @@ static void acpi_power_resources_list_add(acpi_handle handle,
117 list_for_each_entry(e, list, node) 117 list_for_each_entry(e, list, node)
118 if (e->resource->order > resource->order) { 118 if (e->resource->order > resource->order) {
119 list_add_tail(&entry->node, &e->node); 119 list_add_tail(&entry->node, &e->node);
120 return; 120 return 0;
121 } 121 }
122 } 122 }
123 list_add_tail(&entry->node, list); 123 list_add_tail(&entry->node, list);
124 return 0;
124} 125}
125 126
126void acpi_power_resources_list_free(struct list_head *list) 127void acpi_power_resources_list_free(struct list_head *list)
@@ -133,33 +134,37 @@ void acpi_power_resources_list_free(struct list_head *list)
133 } 134 }
134} 135}
135 136
136acpi_status acpi_extract_power_resources(union acpi_object *package, 137int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
137 unsigned int start, 138 struct list_head *list)
138 struct list_head *list)
139{ 139{
140 acpi_status status = AE_OK;
141 unsigned int i; 140 unsigned int i;
141 int err = 0;
142 142
143 for (i = start; i < package->package.count; i++) { 143 for (i = start; i < package->package.count; i++) {
144 union acpi_object *element = &package->package.elements[i]; 144 union acpi_object *element = &package->package.elements[i];
145 acpi_handle rhandle; 145 acpi_handle rhandle;
146 146
147 if (element->type != ACPI_TYPE_LOCAL_REFERENCE) { 147 if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
148 status = AE_BAD_DATA; 148 err = -ENODATA;
149 break; 149 break;
150 } 150 }
151 rhandle = element->reference.handle; 151 rhandle = element->reference.handle;
152 if (!rhandle) { 152 if (!rhandle) {
153 status = AE_NULL_ENTRY; 153 err = -ENODEV;
154 break; 154 break;
155 } 155 }
156 acpi_add_power_resource(rhandle); 156 err = acpi_add_power_resource(rhandle);
157 acpi_power_resources_list_add(rhandle, list); 157 if (err)
158 break;
159
160 err = acpi_power_resources_list_add(rhandle, list);
161 if (err)
162 break;
158 } 163 }
159 if (ACPI_FAILURE(status)) 164 if (err)
160 acpi_power_resources_list_free(list); 165 acpi_power_resources_list_free(list);
161 166
162 return status; 167 return err;
163} 168}
164 169
165static int acpi_power_get_state(acpi_handle handle, int *state) 170static int acpi_power_get_state(acpi_handle handle, int *state)
@@ -662,7 +667,7 @@ static void acpi_release_power_resource(struct device *dev)
662 kfree(resource); 667 kfree(resource);
663} 668}
664 669
665void acpi_add_power_resource(acpi_handle handle) 670int acpi_add_power_resource(acpi_handle handle)
666{ 671{
667 struct acpi_power_resource *resource; 672 struct acpi_power_resource *resource;
668 struct acpi_device *device = NULL; 673 struct acpi_device *device = NULL;
@@ -673,11 +678,11 @@ void acpi_add_power_resource(acpi_handle handle)
673 678
674 acpi_bus_get_device(handle, &device); 679 acpi_bus_get_device(handle, &device);
675 if (device) 680 if (device)
676 return; 681 return 0;
677 682
678 resource = kzalloc(sizeof(*resource), GFP_KERNEL); 683 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
679 if (!resource) 684 if (!resource)
680 return; 685 return -ENOMEM;
681 686
682 device = &resource->device; 687 device = &resource->device;
683 acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER, 688 acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER,
@@ -712,10 +717,11 @@ void acpi_add_power_resource(acpi_handle handle)
712 mutex_lock(&power_resource_list_lock); 717 mutex_lock(&power_resource_list_lock);
713 list_add(&resource->list_node, &acpi_power_resource_list); 718 list_add(&resource->list_node, &acpi_power_resource_list);
714 mutex_unlock(&power_resource_list_lock); 719 mutex_unlock(&power_resource_list_lock);
715 return; 720 return 0;
716 721
717 err: 722 err:
718 acpi_release_power_resource(&device->dev); 723 acpi_release_power_resource(&device->dev);
724 return result;
719} 725}
720 726
721#ifdef CONFIG_ACPI_SLEEP 727#ifdef CONFIG_ACPI_SLEEP
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index d80df969f64a..0b6a6b4febd6 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -892,17 +892,17 @@ void acpi_bus_data_handler(acpi_handle handle, void *context)
892 return; 892 return;
893} 893}
894 894
895static acpi_status 895static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
896acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, 896 struct acpi_device_wakeup *wakeup)
897 struct acpi_device_wakeup *wakeup)
898{ 897{
899 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 898 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
900 union acpi_object *package = NULL; 899 union acpi_object *package = NULL;
901 union acpi_object *element = NULL; 900 union acpi_object *element = NULL;
902 acpi_status status; 901 acpi_status status;
902 int err = -ENODATA;
903 903
904 if (!wakeup) 904 if (!wakeup)
905 return AE_BAD_PARAMETER; 905 return -EINVAL;
906 906
907 INIT_LIST_HEAD(&wakeup->resources); 907 INIT_LIST_HEAD(&wakeup->resources);
908 908
@@ -910,29 +910,25 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
910 status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer); 910 status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer);
911 if (ACPI_FAILURE(status)) { 911 if (ACPI_FAILURE(status)) {
912 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); 912 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
913 return status; 913 return err;
914 } 914 }
915 915
916 package = (union acpi_object *)buffer.pointer; 916 package = (union acpi_object *)buffer.pointer;
917 917
918 if (!package || (package->package.count < 2)) { 918 if (!package || package->package.count < 2)
919 status = AE_BAD_DATA;
920 goto out; 919 goto out;
921 }
922 920
923 element = &(package->package.elements[0]); 921 element = &(package->package.elements[0]);
924 if (!element) { 922 if (!element)
925 status = AE_BAD_DATA;
926 goto out; 923 goto out;
927 } 924
928 if (element->type == ACPI_TYPE_PACKAGE) { 925 if (element->type == ACPI_TYPE_PACKAGE) {
929 if ((element->package.count < 2) || 926 if ((element->package.count < 2) ||
930 (element->package.elements[0].type != 927 (element->package.elements[0].type !=
931 ACPI_TYPE_LOCAL_REFERENCE) 928 ACPI_TYPE_LOCAL_REFERENCE)
932 || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) { 929 || (element->package.elements[1].type != ACPI_TYPE_INTEGER))
933 status = AE_BAD_DATA;
934 goto out; 930 goto out;
935 } 931
936 wakeup->gpe_device = 932 wakeup->gpe_device =
937 element->package.elements[0].reference.handle; 933 element->package.elements[0].reference.handle;
938 wakeup->gpe_number = 934 wakeup->gpe_number =
@@ -941,27 +937,24 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
941 wakeup->gpe_device = NULL; 937 wakeup->gpe_device = NULL;
942 wakeup->gpe_number = element->integer.value; 938 wakeup->gpe_number = element->integer.value;
943 } else { 939 } else {
944 status = AE_BAD_DATA;
945 goto out; 940 goto out;
946 } 941 }
947 942
948 element = &(package->package.elements[1]); 943 element = &(package->package.elements[1]);
949 if (element->type != ACPI_TYPE_INTEGER) { 944 if (element->type != ACPI_TYPE_INTEGER)
950 status = AE_BAD_DATA;
951 goto out; 945 goto out;
952 } 946
953 wakeup->sleep_state = element->integer.value; 947 wakeup->sleep_state = element->integer.value;
954 948
955 status = acpi_extract_power_resources(package, 2, &wakeup->resources); 949 err = acpi_extract_power_resources(package, 2, &wakeup->resources);
956 if (ACPI_FAILURE(status)) 950 if (err)
957 goto out; 951 goto out;
958 952
959 acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number); 953 acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number);
960 954
961 out: 955 out:
962 kfree(buffer.pointer); 956 kfree(buffer.pointer);
963 957 return err;
964 return status;
965} 958}
966 959
967static void acpi_bus_set_run_wake_flags(struct acpi_device *device) 960static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
@@ -1001,17 +994,17 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
1001{ 994{
1002 acpi_handle temp; 995 acpi_handle temp;
1003 acpi_status status = 0; 996 acpi_status status = 0;
1004 int psw_error; 997 int err;
1005 998
1006 /* Presence of _PRW indicates wake capable */ 999 /* Presence of _PRW indicates wake capable */
1007 status = acpi_get_handle(device->handle, "_PRW", &temp); 1000 status = acpi_get_handle(device->handle, "_PRW", &temp);
1008 if (ACPI_FAILURE(status)) 1001 if (ACPI_FAILURE(status))
1009 return; 1002 return;
1010 1003
1011 status = acpi_bus_extract_wakeup_device_power_package(device->handle, 1004 err = acpi_bus_extract_wakeup_device_power_package(device->handle,
1012 &device->wakeup); 1005 &device->wakeup);
1013 if (ACPI_FAILURE(status)) { 1006 if (err) {
1014 ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); 1007 dev_err(&device->dev, "_PRW evaluation error: %d\n", err);
1015 return; 1008 return;
1016 } 1009 }
1017 1010
@@ -1024,8 +1017,8 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
1024 * So it is necessary to call _DSW object first. Only when it is not 1017 * So it is necessary to call _DSW object first. Only when it is not
1025 * present will the _PSW object used. 1018 * present will the _PSW object used.
1026 */ 1019 */
1027 psw_error = acpi_device_sleep_wake(device, 0, 0, 0); 1020 err = acpi_device_sleep_wake(device, 0, 0, 0);
1028 if (psw_error) 1021 if (err)
1029 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1022 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1030 "error in _DSW or _PSW evaluation\n")); 1023 "error in _DSW or _PSW evaluation\n"));
1031} 1024}
@@ -1048,9 +1041,9 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state)
1048 if (buffer.length && package 1041 if (buffer.length && package
1049 && package->type == ACPI_TYPE_PACKAGE 1042 && package->type == ACPI_TYPE_PACKAGE
1050 && package->package.count) { 1043 && package->package.count) {
1051 status = acpi_extract_power_resources(package, 0, 1044 int err = acpi_extract_power_resources(package, 0,
1052 &ps->resources); 1045 &ps->resources);
1053 if (ACPI_SUCCESS(status)) 1046 if (!err)
1054 device->power.flags.power_resources = 1; 1047 device->power.flags.power_resources = 1;
1055 } 1048 }
1056 ACPI_FREE(buffer.pointer); 1049 ACPI_FREE(buffer.pointer);