aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/power.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/power.c')
-rw-r--r--drivers/acpi/power.c299
1 files changed, 144 insertions, 155 deletions
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 844c155aeb0f..9ac2a9fa90ff 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -56,9 +56,6 @@ ACPI_MODULE_NAME("power");
56#define ACPI_POWER_RESOURCE_STATE_ON 0x01 56#define ACPI_POWER_RESOURCE_STATE_ON 0x01
57#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF 57#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
58 58
59int acpi_power_nocheck;
60module_param_named(power_nocheck, acpi_power_nocheck, bool, 000);
61
62static int acpi_power_add(struct acpi_device *device); 59static int acpi_power_add(struct acpi_device *device);
63static int acpi_power_remove(struct acpi_device *device, int type); 60static int acpi_power_remove(struct acpi_device *device, int type);
64static int acpi_power_resume(struct acpi_device *device); 61static int acpi_power_resume(struct acpi_device *device);
@@ -80,18 +77,13 @@ static struct acpi_driver acpi_power_driver = {
80 }, 77 },
81}; 78};
82 79
83struct acpi_power_reference {
84 struct list_head node;
85 struct acpi_device *device;
86};
87
88struct acpi_power_resource { 80struct acpi_power_resource {
89 struct acpi_device * device; 81 struct acpi_device * device;
90 acpi_bus_id name; 82 acpi_bus_id name;
91 u32 system_level; 83 u32 system_level;
92 u32 order; 84 u32 order;
85 unsigned int ref_count;
93 struct mutex resource_lock; 86 struct mutex resource_lock;
94 struct list_head reference;
95}; 87};
96 88
97static struct list_head acpi_power_resource_list; 89static struct list_head acpi_power_resource_list;
@@ -153,9 +145,8 @@ static int acpi_power_get_state(acpi_handle handle, int *state)
153 145
154static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) 146static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
155{ 147{
156 int result = 0, state1; 148 int cur_state;
157 u32 i = 0; 149 int i = 0;
158
159 150
160 if (!list || !state) 151 if (!list || !state)
161 return -EINVAL; 152 return -EINVAL;
@@ -163,122 +154,149 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
163 /* The state of the list is 'on' IFF all resources are 'on'. */ 154 /* The state of the list is 'on' IFF all resources are 'on'. */
164 155
165 for (i = 0; i < list->count; i++) { 156 for (i = 0; i < list->count; i++) {
166 /* 157 struct acpi_power_resource *resource;
167 * The state of the power resource can be obtained by 158 acpi_handle handle = list->handles[i];
168 * using the ACPI handle. In such case it is unnecessary to 159 int result;
169 * get the Power resource first and then get its state again. 160
170 */ 161 result = acpi_power_get_context(handle, &resource);
171 result = acpi_power_get_state(list->handles[i], &state1);
172 if (result) 162 if (result)
173 return result; 163 return result;
174 164
175 *state = state1; 165 mutex_lock(&resource->resource_lock);
166
167 result = acpi_power_get_state(handle, &cur_state);
168
169 mutex_unlock(&resource->resource_lock);
176 170
177 if (*state != ACPI_POWER_RESOURCE_STATE_ON) 171 if (result)
172 return result;
173
174 if (cur_state != ACPI_POWER_RESOURCE_STATE_ON)
178 break; 175 break;
179 } 176 }
180 177
181 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n", 178 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n",
182 *state ? "on" : "off")); 179 cur_state ? "on" : "off"));
183 180
184 return result; 181 *state = cur_state;
182
183 return 0;
185} 184}
186 185
187static int acpi_power_on(acpi_handle handle, struct acpi_device *dev) 186static int __acpi_power_on(struct acpi_power_resource *resource)
188{ 187{
189 int result = 0;
190 int found = 0;
191 acpi_status status = AE_OK; 188 acpi_status status = AE_OK;
192 struct acpi_power_resource *resource = NULL;
193 struct list_head *node, *next;
194 struct acpi_power_reference *ref;
195 189
190 status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
191 if (ACPI_FAILURE(status))
192 return -ENODEV;
193
194 /* Update the power resource's _device_ power state */
195 resource->device->power.state = ACPI_STATE_D0;
196
197 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
198 resource->name));
199
200 return 0;
201}
202
203static int acpi_power_on(acpi_handle handle)
204{
205 int result = 0;
206 struct acpi_power_resource *resource = NULL;
196 207
197 result = acpi_power_get_context(handle, &resource); 208 result = acpi_power_get_context(handle, &resource);
198 if (result) 209 if (result)
199 return result; 210 return result;
200 211
201 mutex_lock(&resource->resource_lock); 212 mutex_lock(&resource->resource_lock);
202 list_for_each_safe(node, next, &resource->reference) {
203 ref = container_of(node, struct acpi_power_reference, node);
204 if (dev->handle == ref->device->handle) {
205 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already referenced by resource [%s]\n",
206 dev->pnp.bus_id, resource->name));
207 found = 1;
208 break;
209 }
210 }
211 213
212 if (!found) { 214 if (resource->ref_count++) {
213 ref = kmalloc(sizeof (struct acpi_power_reference), 215 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
214 irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); 216 "Power resource [%s] already on",
215 if (!ref) { 217 resource->name));
216 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "kmalloc() failed\n")); 218 } else {
217 mutex_unlock(&resource->resource_lock); 219 result = __acpi_power_on(resource);
218 return -ENOMEM; 220 if (result)
219 } 221 resource->ref_count--;
220 list_add_tail(&ref->node, &resource->reference);
221 ref->device = dev;
222 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] added to resource [%s] references\n",
223 dev->pnp.bus_id, resource->name));
224 } 222 }
225 mutex_unlock(&resource->resource_lock);
226 223
227 status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL); 224 mutex_unlock(&resource->resource_lock);
228 if (ACPI_FAILURE(status))
229 return -ENODEV;
230
231 /* Update the power resource's _device_ power state */
232 resource->device->power.state = ACPI_STATE_D0;
233 225
234 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned on\n", 226 return result;
235 resource->name));
236 return 0;
237} 227}
238 228
239static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev) 229static int acpi_power_off(acpi_handle handle)
240{ 230{
241 int result = 0; 231 int result = 0;
242 acpi_status status = AE_OK; 232 acpi_status status = AE_OK;
243 struct acpi_power_resource *resource = NULL; 233 struct acpi_power_resource *resource = NULL;
244 struct list_head *node, *next;
245 struct acpi_power_reference *ref;
246 234
247 result = acpi_power_get_context(handle, &resource); 235 result = acpi_power_get_context(handle, &resource);
248 if (result) 236 if (result)
249 return result; 237 return result;
250 238
251 mutex_lock(&resource->resource_lock); 239 mutex_lock(&resource->resource_lock);
252 list_for_each_safe(node, next, &resource->reference) { 240
253 ref = container_of(node, struct acpi_power_reference, node); 241 if (!resource->ref_count) {
254 if (dev->handle == ref->device->handle) { 242 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
255 list_del(&ref->node); 243 "Power resource [%s] already off",
256 kfree(ref); 244 resource->name));
257 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] removed from resource [%s] references\n", 245 goto unlock;
258 dev->pnp.bus_id, resource->name));
259 break;
260 }
261 } 246 }
262 247
263 if (!list_empty(&resource->reference)) { 248 if (--resource->ref_count) {
264 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cannot turn resource [%s] off - resource is in use\n", 249 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
265 resource->name)); 250 "Power resource [%s] still in use\n",
266 mutex_unlock(&resource->resource_lock); 251 resource->name));
267 return 0; 252 goto unlock;
268 } 253 }
269 mutex_unlock(&resource->resource_lock);
270 254
271 status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL); 255 status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL);
272 if (ACPI_FAILURE(status)) 256 if (ACPI_FAILURE(status)) {
273 return -ENODEV; 257 result = -ENODEV;
258 } else {
259 /* Update the power resource's _device_ power state */
260 resource->device->power.state = ACPI_STATE_D3;
274 261
275 /* Update the power resource's _device_ power state */ 262 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
276 resource->device->power.state = ACPI_STATE_D3; 263 "Power resource [%s] turned off\n",
264 resource->name));
265 }
277 266
278 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n", 267 unlock:
279 resource->name)); 268 mutex_unlock(&resource->resource_lock);
280 269
281 return 0; 270 return result;
271}
272
273static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res)
274{
275 int i;
276
277 for (i = num_res - 1; i >= 0 ; i--)
278 acpi_power_off(list->handles[i]);
279}
280
281static void acpi_power_off_list(struct acpi_handle_list *list)
282{
283 __acpi_power_off_list(list, list->count);
284}
285
286static int acpi_power_on_list(struct acpi_handle_list *list)
287{
288 int result = 0;
289 int i;
290
291 for (i = 0; i < list->count; i++) {
292 result = acpi_power_on(list->handles[i]);
293 if (result) {
294 __acpi_power_off_list(list, i);
295 break;
296 }
297 }
298
299 return result;
282} 300}
283 301
284/** 302/**
@@ -364,7 +382,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
364 382
365 /* Open power resource */ 383 /* Open power resource */
366 for (i = 0; i < dev->wakeup.resources.count; i++) { 384 for (i = 0; i < dev->wakeup.resources.count; i++) {
367 int ret = acpi_power_on(dev->wakeup.resources.handles[i], dev); 385 int ret = acpi_power_on(dev->wakeup.resources.handles[i]);
368 if (ret) { 386 if (ret) {
369 printk(KERN_ERR PREFIX "Transition power state\n"); 387 printk(KERN_ERR PREFIX "Transition power state\n");
370 dev->wakeup.flags.valid = 0; 388 dev->wakeup.flags.valid = 0;
@@ -419,8 +437,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
419 437
420 /* Close power resource */ 438 /* Close power resource */
421 for (i = 0; i < dev->wakeup.resources.count; i++) { 439 for (i = 0; i < dev->wakeup.resources.count; i++) {
422 int ret = acpi_power_off_device( 440 int ret = acpi_power_off(dev->wakeup.resources.handles[i]);
423 dev->wakeup.resources.handles[i], dev);
424 if (ret) { 441 if (ret) {
425 printk(KERN_ERR PREFIX "Transition power state\n"); 442 printk(KERN_ERR PREFIX "Transition power state\n");
426 dev->wakeup.flags.valid = 0; 443 dev->wakeup.flags.valid = 0;
@@ -438,19 +455,16 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
438 Device Power Management 455 Device Power Management
439 -------------------------------------------------------------------------- */ 456 -------------------------------------------------------------------------- */
440 457
441int acpi_power_get_inferred_state(struct acpi_device *device) 458int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
442{ 459{
443 int result = 0; 460 int result = 0;
444 struct acpi_handle_list *list = NULL; 461 struct acpi_handle_list *list = NULL;
445 int list_state = 0; 462 int list_state = 0;
446 int i = 0; 463 int i = 0;
447 464
448 465 if (!device || !state)
449 if (!device)
450 return -EINVAL; 466 return -EINVAL;
451 467
452 device->power.state = ACPI_STATE_UNKNOWN;
453
454 /* 468 /*
455 * We know a device's inferred power state when all the resources 469 * We know a device's inferred power state when all the resources
456 * required for a given D-state are 'on'. 470 * required for a given D-state are 'on'.
@@ -465,66 +479,51 @@ int acpi_power_get_inferred_state(struct acpi_device *device)
465 return result; 479 return result;
466 480
467 if (list_state == ACPI_POWER_RESOURCE_STATE_ON) { 481 if (list_state == ACPI_POWER_RESOURCE_STATE_ON) {
468 device->power.state = i; 482 *state = i;
469 return 0; 483 return 0;
470 } 484 }
471 } 485 }
472 486
473 device->power.state = ACPI_STATE_D3; 487 *state = ACPI_STATE_D3;
474
475 return 0; 488 return 0;
476} 489}
477 490
478int acpi_power_transition(struct acpi_device *device, int state) 491int acpi_power_on_resources(struct acpi_device *device, int state)
479{ 492{
480 int result = 0; 493 if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3)
481 struct acpi_handle_list *cl = NULL; /* Current Resources */ 494 return -EINVAL;
482 struct acpi_handle_list *tl = NULL; /* Target Resources */ 495
483 int i = 0; 496 return acpi_power_on_list(&device->power.states[state].resources);
497}
484 498
499int acpi_power_transition(struct acpi_device *device, int state)
500{
501 int result;
485 502
486 if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) 503 if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
487 return -EINVAL; 504 return -EINVAL;
488 505
506 if (device->power.state == state)
507 return 0;
508
489 if ((device->power.state < ACPI_STATE_D0) 509 if ((device->power.state < ACPI_STATE_D0)
490 || (device->power.state > ACPI_STATE_D3)) 510 || (device->power.state > ACPI_STATE_D3))
491 return -ENODEV; 511 return -ENODEV;
492 512
493 cl = &device->power.states[device->power.state].resources;
494 tl = &device->power.states[state].resources;
495
496 /* TBD: Resources must be ordered. */ 513 /* TBD: Resources must be ordered. */
497 514
498 /* 515 /*
499 * First we reference all power resources required in the target list 516 * First we reference all power resources required in the target list
500 * (e.g. so the device doesn't lose power while transitioning). 517 * (e.g. so the device doesn't lose power while transitioning). Then,
501 */ 518 * we dereference all power resources used in the current list.
502 for (i = 0; i < tl->count; i++) {
503 result = acpi_power_on(tl->handles[i], device);
504 if (result)
505 goto end;
506 }
507
508 if (device->power.state == state) {
509 goto end;
510 }
511
512 /*
513 * Then we dereference all power resources used in the current list.
514 */ 519 */
515 for (i = 0; i < cl->count; i++) { 520 result = acpi_power_on_list(&device->power.states[state].resources);
516 result = acpi_power_off_device(cl->handles[i], device); 521 if (!result)
517 if (result) 522 acpi_power_off_list(
518 goto end; 523 &device->power.states[device->power.state].resources);
519 }
520 524
521 end: 525 /* We shouldn't change the state unless the above operations succeed. */
522 if (result) 526 device->power.state = result ? ACPI_STATE_UNKNOWN : state;
523 device->power.state = ACPI_STATE_UNKNOWN;
524 else {
525 /* We shouldn't change the state till all above operations succeed */
526 device->power.state = state;
527 }
528 527
529 return result; 528 return result;
530} 529}
@@ -551,7 +550,6 @@ static int acpi_power_add(struct acpi_device *device)
551 550
552 resource->device = device; 551 resource->device = device;
553 mutex_init(&resource->resource_lock); 552 mutex_init(&resource->resource_lock);
554 INIT_LIST_HEAD(&resource->reference);
555 strcpy(resource->name, device->pnp.bus_id); 553 strcpy(resource->name, device->pnp.bus_id);
556 strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); 554 strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
557 strcpy(acpi_device_class(device), ACPI_POWER_CLASS); 555 strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
@@ -594,22 +592,14 @@ static int acpi_power_add(struct acpi_device *device)
594 592
595static int acpi_power_remove(struct acpi_device *device, int type) 593static int acpi_power_remove(struct acpi_device *device, int type)
596{ 594{
597 struct acpi_power_resource *resource = NULL; 595 struct acpi_power_resource *resource;
598 struct list_head *node, *next;
599 596
600 597 if (!device)
601 if (!device || !acpi_driver_data(device))
602 return -EINVAL; 598 return -EINVAL;
603 599
604 resource = acpi_driver_data(device); 600 resource = acpi_driver_data(device);
605 601 if (!resource)
606 mutex_lock(&resource->resource_lock); 602 return -EINVAL;
607 list_for_each_safe(node, next, &resource->reference) {
608 struct acpi_power_reference *ref = container_of(node, struct acpi_power_reference, node);
609 list_del(&ref->node);
610 kfree(ref);
611 }
612 mutex_unlock(&resource->resource_lock);
613 603
614 kfree(resource); 604 kfree(resource);
615 605
@@ -619,29 +609,28 @@ static int acpi_power_remove(struct acpi_device *device, int type)
619static int acpi_power_resume(struct acpi_device *device) 609static int acpi_power_resume(struct acpi_device *device)
620{ 610{
621 int result = 0, state; 611 int result = 0, state;
622 struct acpi_power_resource *resource = NULL; 612 struct acpi_power_resource *resource;
623 struct acpi_power_reference *ref;
624 613
625 if (!device || !acpi_driver_data(device)) 614 if (!device)
626 return -EINVAL; 615 return -EINVAL;
627 616
628 resource = acpi_driver_data(device); 617 resource = acpi_driver_data(device);
618 if (!resource)
619 return -EINVAL;
620
621 mutex_lock(&resource->resource_lock);
629 622
630 result = acpi_power_get_state(device->handle, &state); 623 result = acpi_power_get_state(device->handle, &state);
631 if (result) 624 if (result)
632 return result; 625 goto unlock;
633 626
634 mutex_lock(&resource->resource_lock); 627 if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count)
635 if (state == ACPI_POWER_RESOURCE_STATE_OFF && 628 result = __acpi_power_on(resource);
636 !list_empty(&resource->reference)) {
637 ref = container_of(resource->reference.next, struct acpi_power_reference, node);
638 mutex_unlock(&resource->resource_lock);
639 result = acpi_power_on(device->handle, ref->device);
640 return result;
641 }
642 629
630 unlock:
643 mutex_unlock(&resource->resource_lock); 631 mutex_unlock(&resource->resource_lock);
644 return 0; 632
633 return result;
645} 634}
646 635
647int __init acpi_power_init(void) 636int __init acpi_power_init(void)