aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/power.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-17 08:11:05 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-17 08:11:05 -0500
commit82c7d5efaadf99fb4a26500cd5b59b6fd7659772 (patch)
treebdd905dde94786f58852dcd1aba86d28054257dd /drivers/acpi/power.c
parentd43e167db44b37bb284dc72fff2c3b61bb155752 (diff)
ACPI / scan: Treat power resources in a special way
ACPI power resources need to be treated in a special way by the namespace scanning code, because they need to be ready to use as soon as they have been discovered (even before registering ACPI device nodes using them for power management). For this reason, it doesn't make sense to separate the preparation of struct acpi_device objects representing them in the device hierarchy from the creation of struct acpi_power_resource objects actually used for power resource manipulation. Accordingly, it doesn't make sense to define non-empty .add() and .remove() callbacks in the power resources "driver" (in fact, it is questionable whether or not it is useful to register such a "driver" at all). Rearrange the code in scan.c and power.c so that power resources are initialized entirely by one routine, acpi_add_power_resource(), that also prepares their struct acpi_device objects and registers them with the driver core, telling it to use a special release routine, acpi_release_power_resource(), for removing objects that represent power resources from memory. Make the ACPI namespace scanning code in scan.c always use acpi_add_power_resource() for preparing and registering objects that represent power resources. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/power.c')
-rw-r--r--drivers/acpi/power.c157
1 files changed, 72 insertions, 85 deletions
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 659386c4f0cb..b12933fd2e56 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -58,8 +58,7 @@ ACPI_MODULE_NAME("power");
58#define ACPI_POWER_RESOURCE_STATE_ON 0x01 58#define ACPI_POWER_RESOURCE_STATE_ON 0x01
59#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF 59#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
60 60
61static int acpi_power_add(struct acpi_device *device); 61static inline int acpi_power_add(struct acpi_device *device) { return 0; }
62static int acpi_power_remove(struct acpi_device *device, int type);
63 62
64static const struct acpi_device_id power_device_ids[] = { 63static const struct acpi_device_id power_device_ids[] = {
65 {ACPI_POWER_HID, 0}, 64 {ACPI_POWER_HID, 0},
@@ -76,10 +75,7 @@ static struct acpi_driver acpi_power_driver = {
76 .name = "power", 75 .name = "power",
77 .class = ACPI_POWER_CLASS, 76 .class = ACPI_POWER_CLASS,
78 .ids = power_device_ids, 77 .ids = power_device_ids,
79 .ops = { 78 .ops.add = acpi_power_add,
80 .add = acpi_power_add,
81 .remove = acpi_power_remove,
82 },
83 .drv.pm = &acpi_power_pm, 79 .drv.pm = &acpi_power_pm,
84}; 80};
85 81
@@ -90,9 +86,9 @@ struct acpi_power_dependent_device {
90}; 86};
91 87
92struct acpi_power_resource { 88struct acpi_power_resource {
93 struct acpi_device *device; 89 struct acpi_device device;
94 struct list_head dependent; 90 struct list_head dependent;
95 acpi_bus_id name; 91 char *name;
96 u32 system_level; 92 u32 system_level;
97 u32 order; 93 u32 order;
98 unsigned int ref_count; 94 unsigned int ref_count;
@@ -105,28 +101,14 @@ static struct list_head acpi_power_resource_list;
105 Power Resource Management 101 Power Resource Management
106 -------------------------------------------------------------------------- */ 102 -------------------------------------------------------------------------- */
107 103
108static int 104static struct acpi_power_resource *acpi_power_get_context(acpi_handle handle)
109acpi_power_get_context(acpi_handle handle,
110 struct acpi_power_resource **resource)
111{ 105{
112 int result = 0; 106 struct acpi_device *device;
113 struct acpi_device *device = NULL;
114
115
116 if (!resource)
117 return -ENODEV;
118
119 result = acpi_bus_get_device(handle, &device);
120 if (result) {
121 printk(KERN_WARNING PREFIX "Getting context [%p]\n", handle);
122 return result;
123 }
124 107
125 *resource = acpi_driver_data(device); 108 if (acpi_bus_get_device(handle, &device))
126 if (!*resource) 109 return NULL;
127 return -ENODEV;
128 110
129 return 0; 111 return container_of(device, struct acpi_power_resource, device);
130} 112}
131 113
132static int acpi_power_get_state(acpi_handle handle, int *state) 114static int acpi_power_get_state(acpi_handle handle, int *state)
@@ -171,9 +153,9 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
171 acpi_handle handle = list->handles[i]; 153 acpi_handle handle = list->handles[i];
172 int result; 154 int result;
173 155
174 result = acpi_power_get_context(handle, &resource); 156 resource = acpi_power_get_context(handle);
175 if (result) 157 if (!resource)
176 return result; 158 return -ENODEV;
177 159
178 mutex_lock(&resource->resource_lock); 160 mutex_lock(&resource->resource_lock);
179 161
@@ -226,12 +208,12 @@ static int __acpi_power_on(struct acpi_power_resource *resource)
226{ 208{
227 acpi_status status = AE_OK; 209 acpi_status status = AE_OK;
228 210
229 status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL); 211 status = acpi_evaluate_object(resource->device.handle, "_ON", NULL, NULL);
230 if (ACPI_FAILURE(status)) 212 if (ACPI_FAILURE(status))
231 return -ENODEV; 213 return -ENODEV;
232 214
233 /* Update the power resource's _device_ power state */ 215 /* Update the power resource's _device_ power state */
234 resource->device->power.state = ACPI_STATE_D0; 216 resource->device.power.state = ACPI_STATE_D0;
235 217
236 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n", 218 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
237 resource->name)); 219 resource->name));
@@ -242,11 +224,11 @@ static int __acpi_power_on(struct acpi_power_resource *resource)
242static int acpi_power_on(acpi_handle handle) 224static int acpi_power_on(acpi_handle handle)
243{ 225{
244 int result = 0; 226 int result = 0;
245 struct acpi_power_resource *resource = NULL; 227 struct acpi_power_resource *resource;
246 228
247 result = acpi_power_get_context(handle, &resource); 229 resource = acpi_power_get_context(handle);
248 if (result) 230 if (!resource)
249 return result; 231 return -ENODEV;
250 232
251 mutex_lock(&resource->resource_lock); 233 mutex_lock(&resource->resource_lock);
252 234
@@ -275,11 +257,11 @@ static int acpi_power_off(acpi_handle handle)
275{ 257{
276 int result = 0; 258 int result = 0;
277 acpi_status status = AE_OK; 259 acpi_status status = AE_OK;
278 struct acpi_power_resource *resource = NULL; 260 struct acpi_power_resource *resource;
279 261
280 result = acpi_power_get_context(handle, &resource); 262 resource = acpi_power_get_context(handle);
281 if (result) 263 if (!resource)
282 return result; 264 return -ENODEV;
283 265
284 mutex_lock(&resource->resource_lock); 266 mutex_lock(&resource->resource_lock);
285 267
@@ -297,12 +279,12 @@ static int acpi_power_off(acpi_handle handle)
297 goto unlock; 279 goto unlock;
298 } 280 }
299 281
300 status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL); 282 status = acpi_evaluate_object(resource->device.handle, "_OFF", NULL, NULL);
301 if (ACPI_FAILURE(status)) { 283 if (ACPI_FAILURE(status)) {
302 result = -ENODEV; 284 result = -ENODEV;
303 } else { 285 } else {
304 /* Update the power resource's _device_ power state */ 286 /* Update the power resource's _device_ power state */
305 resource->device->power.state = ACPI_STATE_D3; 287 resource->device.power.state = ACPI_STATE_D3;
306 288
307 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 289 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
308 "Power resource [%s] turned off\n", 290 "Power resource [%s] turned off\n",
@@ -350,7 +332,11 @@ static void acpi_power_add_dependent(acpi_handle rhandle,
350 struct acpi_power_dependent_device *dep; 332 struct acpi_power_dependent_device *dep;
351 struct acpi_power_resource *resource; 333 struct acpi_power_resource *resource;
352 334
353 if (!rhandle || !adev || acpi_power_get_context(rhandle, &resource)) 335 if (!rhandle || !adev)
336 return;
337
338 resource = acpi_power_get_context(rhandle);
339 if (!resource)
354 return; 340 return;
355 341
356 mutex_lock(&resource->resource_lock); 342 mutex_lock(&resource->resource_lock);
@@ -378,7 +364,11 @@ static void acpi_power_remove_dependent(acpi_handle rhandle,
378 struct acpi_power_resource *resource; 364 struct acpi_power_resource *resource;
379 struct work_struct *work = NULL; 365 struct work_struct *work = NULL;
380 366
381 if (!rhandle || !adev || acpi_power_get_context(rhandle, &resource)) 367 if (!rhandle || !adev)
368 return;
369
370 resource = acpi_power_get_context(rhandle);
371 if (!resource)
382 return; 372 return;
383 373
384 mutex_lock(&resource->resource_lock); 374 mutex_lock(&resource->resource_lock);
@@ -648,46 +638,53 @@ int acpi_power_transition(struct acpi_device *device, int state)
648 return result; 638 return result;
649} 639}
650 640
651/* -------------------------------------------------------------------------- 641static void acpi_release_power_resource(struct device *dev)
652 Driver Interface 642{
653 -------------------------------------------------------------------------- */ 643 struct acpi_device *device = to_acpi_device(dev);
644 struct acpi_power_resource *resource;
645
646 acpi_free_ids(device);
647 resource = container_of(device, struct acpi_power_resource, device);
648 kfree(resource);
649}
654 650
655static int acpi_power_add(struct acpi_device *device) 651void acpi_add_power_resource(acpi_handle handle)
656{ 652{
657 int result = 0, state; 653 struct acpi_power_resource *resource;
658 acpi_status status = AE_OK; 654 struct acpi_device *device = NULL;
659 struct acpi_power_resource *resource = NULL;
660 union acpi_object acpi_object; 655 union acpi_object acpi_object;
661 struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object }; 656 struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object };
657 acpi_status status;
658 int state, result = -ENODEV;
662 659
660 acpi_bus_get_device(handle, &device);
661 if (device)
662 return;
663 663
664 if (!device) 664 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
665 return -EINVAL;
666
667 resource = kzalloc(sizeof(struct acpi_power_resource), GFP_KERNEL);
668 if (!resource) 665 if (!resource)
669 return -ENOMEM; 666 return;
670 667
671 resource->device = device; 668 device = &resource->device;
669 acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER,
670 ACPI_STA_DEFAULT);
672 mutex_init(&resource->resource_lock); 671 mutex_init(&resource->resource_lock);
673 INIT_LIST_HEAD(&resource->dependent); 672 INIT_LIST_HEAD(&resource->dependent);
674 strcpy(resource->name, device->pnp.bus_id); 673 resource->name = device->pnp.bus_id;
675 strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); 674 strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
676 strcpy(acpi_device_class(device), ACPI_POWER_CLASS); 675 strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
677 device->driver_data = resource;
678 676
679 /* Evalute the object to get the system level and resource order. */ 677 /* Evalute the object to get the system level and resource order. */
680 status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer); 678 status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
681 if (ACPI_FAILURE(status)) { 679 if (ACPI_FAILURE(status))
682 result = -ENODEV; 680 goto out;
683 goto end; 681
684 }
685 resource->system_level = acpi_object.power_resource.system_level; 682 resource->system_level = acpi_object.power_resource.system_level;
686 resource->order = acpi_object.power_resource.resource_order; 683 resource->order = acpi_object.power_resource.resource_order;
687 684
688 result = acpi_power_get_state(device->handle, &state); 685 result = acpi_power_get_state(handle, &state);
689 if (result) 686 if (result)
690 goto end; 687 goto out;
691 688
692 switch (state) { 689 switch (state) {
693 case ACPI_POWER_RESOURCE_STATE_ON: 690 case ACPI_POWER_RESOURCE_STATE_ON:
@@ -698,34 +695,24 @@ static int acpi_power_add(struct acpi_device *device)
698 break; 695 break;
699 default: 696 default:
700 device->power.state = ACPI_STATE_UNKNOWN; 697 device->power.state = ACPI_STATE_UNKNOWN;
701 break;
702 } 698 }
703 699
704 printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device), 700 printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device),
705 acpi_device_bid(device), state ? "on" : "off"); 701 acpi_device_bid(device), state ? "on" : "off");
706 702
707 end: 703 device->flags.match_driver = true;
704 result = acpi_device_register(device, acpi_release_power_resource);
705
706 out:
708 if (result) 707 if (result)
709 kfree(resource); 708 acpi_release_power_resource(&device->dev);
710 709
711 return result; 710 return;
712} 711}
713 712
714static int acpi_power_remove(struct acpi_device *device, int type) 713/* --------------------------------------------------------------------------
715{ 714 Driver Interface
716 struct acpi_power_resource *resource; 715 -------------------------------------------------------------------------- */
717
718 if (!device)
719 return -EINVAL;
720
721 resource = acpi_driver_data(device);
722 if (!resource)
723 return -EINVAL;
724
725 kfree(resource);
726
727 return 0;
728}
729 716
730#ifdef CONFIG_PM_SLEEP 717#ifdef CONFIG_PM_SLEEP
731static int acpi_power_resume(struct device *dev) 718static int acpi_power_resume(struct device *dev)