40
40
#include <linux/init.h>
41
41
#include <linux/types.h>
42
42
#include <linux/slab.h>
43
+ #include <linux/pm_runtime.h>
43
44
#include <acpi/acpi_bus.h>
44
45
#include <acpi/acpi_drivers.h>
45
46
#include "sleep.h"
47
+ #include "internal.h"
46
48
47
49
#define PREFIX "ACPI: "
48
50
@@ -77,13 +79,30 @@ static struct acpi_driver acpi_power_driver = {
77
79
},
78
80
};
79
81
82
+ /*
83
+ * A power managed device
84
+ * A device may rely on multiple power resources.
85
+ * */
86
+ struct acpi_power_managed_device {
87
+ struct device * dev ; /* The physical device */
88
+ acpi_handle * handle ;
89
+ };
90
+
91
+ struct acpi_power_resource_device {
92
+ struct acpi_power_managed_device * device ;
93
+ struct acpi_power_resource_device * next ;
94
+ };
95
+
80
96
struct acpi_power_resource {
81
97
struct acpi_device * device ;
82
98
acpi_bus_id name ;
83
99
u32 system_level ;
84
100
u32 order ;
85
101
unsigned int ref_count ;
86
102
struct mutex resource_lock ;
103
+
104
+ /* List of devices relying on this power resource */
105
+ struct acpi_power_resource_device * devices ;
87
106
};
88
107
89
108
static struct list_head acpi_power_resource_list ;
@@ -183,8 +202,26 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
183
202
return 0 ;
184
203
}
185
204
205
+ /* Resume the device when all power resources in _PR0 are on */
206
+ static void acpi_power_on_device (struct acpi_power_managed_device * device )
207
+ {
208
+ struct acpi_device * acpi_dev ;
209
+ acpi_handle handle = device -> handle ;
210
+ int state ;
211
+
212
+ if (acpi_bus_get_device (handle , & acpi_dev ))
213
+ return ;
214
+
215
+ if (acpi_power_get_inferred_state (acpi_dev , & state ))
216
+ return ;
217
+
218
+ if (state == ACPI_STATE_D0 && pm_runtime_suspended (device -> dev ))
219
+ pm_request_resume (device -> dev );
220
+ }
221
+
186
222
static int __acpi_power_on (struct acpi_power_resource * resource )
187
223
{
224
+ struct acpi_power_resource_device * device_list = resource -> devices ;
188
225
acpi_status status = AE_OK ;
189
226
190
227
status = acpi_evaluate_object (resource -> device -> handle , "_ON" , NULL , NULL );
@@ -197,6 +234,12 @@ static int __acpi_power_on(struct acpi_power_resource *resource)
197
234
ACPI_DEBUG_PRINT ((ACPI_DB_INFO , "Power resource [%s] turned on\n" ,
198
235
resource -> name ));
199
236
237
+ while (device_list ) {
238
+ acpi_power_on_device (device_list -> device );
239
+
240
+ device_list = device_list -> next ;
241
+ }
242
+
200
243
return 0 ;
201
244
}
202
245
@@ -299,6 +342,125 @@ static int acpi_power_on_list(struct acpi_handle_list *list)
299
342
return result ;
300
343
}
301
344
345
+ static void __acpi_power_resource_unregister_device (struct device * dev ,
346
+ acpi_handle res_handle )
347
+ {
348
+ struct acpi_power_resource * resource = NULL ;
349
+ struct acpi_power_resource_device * prev , * curr ;
350
+
351
+ if (acpi_power_get_context (res_handle , & resource ))
352
+ return ;
353
+
354
+ mutex_lock (& resource -> resource_lock );
355
+ prev = NULL ;
356
+ curr = resource -> devices ;
357
+ while (curr ) {
358
+ if (curr -> device -> dev == dev ) {
359
+ if (!prev )
360
+ resource -> devices = curr -> next ;
361
+ else
362
+ prev -> next = curr -> next ;
363
+
364
+ kfree (curr );
365
+ break ;
366
+ }
367
+
368
+ prev = curr ;
369
+ curr = curr -> next ;
370
+ }
371
+ mutex_unlock (& resource -> resource_lock );
372
+ }
373
+
374
+ /* Unlink dev from all power resources in _PR0 */
375
+ void acpi_power_resource_unregister_device (struct device * dev , acpi_handle handle )
376
+ {
377
+ struct acpi_device * acpi_dev ;
378
+ struct acpi_handle_list * list ;
379
+ int i ;
380
+
381
+ if (!dev || !handle )
382
+ return ;
383
+
384
+ if (acpi_bus_get_device (handle , & acpi_dev ))
385
+ return ;
386
+
387
+ list = & acpi_dev -> power .states [ACPI_STATE_D0 ].resources ;
388
+
389
+ for (i = 0 ; i < list -> count ; i ++ )
390
+ __acpi_power_resource_unregister_device (dev ,
391
+ list -> handles [i ]);
392
+ }
393
+
394
+ static int __acpi_power_resource_register_device (
395
+ struct acpi_power_managed_device * powered_device , acpi_handle handle )
396
+ {
397
+ struct acpi_power_resource * resource = NULL ;
398
+ struct acpi_power_resource_device * power_resource_device ;
399
+ int result ;
400
+
401
+ result = acpi_power_get_context (handle , & resource );
402
+ if (result )
403
+ return result ;
404
+
405
+ power_resource_device = kzalloc (
406
+ sizeof (* power_resource_device ), GFP_KERNEL );
407
+ if (!power_resource_device )
408
+ return - ENOMEM ;
409
+
410
+ power_resource_device -> device = powered_device ;
411
+
412
+ mutex_lock (& resource -> resource_lock );
413
+ power_resource_device -> next = resource -> devices ;
414
+ resource -> devices = power_resource_device ;
415
+ mutex_unlock (& resource -> resource_lock );
416
+
417
+ return 0 ;
418
+ }
419
+
420
+ /* Link dev to all power resources in _PR0 */
421
+ int acpi_power_resource_register_device (struct device * dev , acpi_handle handle )
422
+ {
423
+ struct acpi_device * acpi_dev ;
424
+ struct acpi_handle_list * list ;
425
+ struct acpi_power_managed_device * powered_device ;
426
+ int i , ret ;
427
+
428
+ if (!dev || !handle )
429
+ return - ENODEV ;
430
+
431
+ ret = acpi_bus_get_device (handle , & acpi_dev );
432
+ if (ret )
433
+ goto no_power_resource ;
434
+
435
+ if (!acpi_dev -> power .flags .power_resources )
436
+ goto no_power_resource ;
437
+
438
+ powered_device = kzalloc (sizeof (* powered_device ), GFP_KERNEL );
439
+ if (!powered_device )
440
+ return - ENOMEM ;
441
+
442
+ powered_device -> dev = dev ;
443
+ powered_device -> handle = handle ;
444
+
445
+ list = & acpi_dev -> power .states [ACPI_STATE_D0 ].resources ;
446
+
447
+ for (i = 0 ; i < list -> count ; i ++ ) {
448
+ ret = __acpi_power_resource_register_device (powered_device ,
449
+ list -> handles [i ]);
450
+
451
+ if (ret ) {
452
+ acpi_power_resource_unregister_device (dev , handle );
453
+ break ;
454
+ }
455
+ }
456
+
457
+ return ret ;
458
+
459
+ no_power_resource :
460
+ printk (KERN_WARNING PREFIX "Invalid Power Resource to register!" );
461
+ return - ENODEV ;
462
+ }
463
+
302
464
/**
303
465
* acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
304
466
* ACPI 3.0) _PSW (Power State Wake)
@@ -500,14 +662,14 @@ int acpi_power_transition(struct acpi_device *device, int state)
500
662
{
501
663
int result ;
502
664
503
- if (!device || (state < ACPI_STATE_D0 ) || (state > ACPI_STATE_D3 ))
665
+ if (!device || (state < ACPI_STATE_D0 ) || (state > ACPI_STATE_D3_COLD ))
504
666
return - EINVAL ;
505
667
506
668
if (device -> power .state == state )
507
669
return 0 ;
508
670
509
671
if ((device -> power .state < ACPI_STATE_D0 )
510
- || (device -> power .state > ACPI_STATE_D3 ))
672
+ || (device -> power .state > ACPI_STATE_D3_COLD ))
511
673
return - ENODEV ;
512
674
513
675
/* TBD: Resources must be ordered. */
0 commit comments