aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2009-09-18 15:41:09 -0400
committerLen Brown <len.brown@intel.com>2009-09-19 01:30:01 -0400
commitde584afa5e188a2da484bb5373d449598cdb9f5e (patch)
tree629dce13dc9c6f5160cf4515a11965d88feb9ef5
parent74fca6a42863ffacaf7ba6f1936a9f228950f657 (diff)
hwmon driver for ACPI 4.0 power meters
This driver exposes ACPI 4.0 compliant power meters as hardware monitoring devices. This second revision of the driver also exports the ACPI string info as sysfs attributes, a list of the devices that the meter measures, and will send ACPI notifications over the ACPI netlink socket. This latest revision only enables the power capping controls if it can be confirmed that the power cap can be enforced by the hardware and explains how the notification interfaces work. [akpm@linux-foundation.org: remove default-y] [akpm@linux-foundation.org: build fix] Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Cc: Zhang Rui <rui.zhang@intel.com> Cc: Pavel Machek <pavel@ucw.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--Documentation/hwmon/acpi_power_meter51
-rw-r--r--drivers/acpi/Kconfig11
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/power_meter.c1018
4 files changed, 1081 insertions, 0 deletions
diff --git a/Documentation/hwmon/acpi_power_meter b/Documentation/hwmon/acpi_power_meter
new file mode 100644
index 000000000000..c80399a00c50
--- /dev/null
+++ b/Documentation/hwmon/acpi_power_meter
@@ -0,0 +1,51 @@
1Kernel driver power_meter
2=========================
3
4This driver talks to ACPI 4.0 power meters.
5
6Supported systems:
7 * Any recent system with ACPI 4.0.
8 Prefix: 'power_meter'
9 Datasheet: http://acpi.info/, section 10.4.
10
11Author: Darrick J. Wong
12
13Description
14-----------
15
16This driver implements sensor reading support for the power meters exposed in
17the ACPI 4.0 spec (Chapter 10.4). These devices have a simple set of
18features--a power meter that returns average power use over a configurable
19interval, an optional capping mechanism, and a couple of trip points. The
20sysfs interface conforms with the specification outlined in the "Power" section
21of Documentation/hwmon/sysfs-interface.
22
23Special Features
24----------------
25
26The power[1-*]_is_battery knob indicates if the power supply is a battery.
27Both power[1-*]_average_{min,max} must be set before the trip points will work.
28When both of them are set, an ACPI event will be broadcast on the ACPI netlink
29socket and a poll notification will be sent to the appropriate
30power[1-*]_average sysfs file.
31
32The power[1-*]_{model_number, serial_number, oem_info} fields display arbitrary
33strings that ACPI provides with the meter. The measures/ directory contains
34symlinks to the devices that this meter measures.
35
36Some computers have the ability to enforce a power cap in hardware. If this is
37the case, the power[1-*]_cap and related sysfs files will appear. When the
38average power consumption exceeds the cap, an ACPI event will be broadcast on
39the netlink event socket and a poll notification will be sent to the
40appropriate power[1-*]_alarm file to indicate that capping has begun, and the
41hardware has taken action to reduce power consumption. Most likely this will
42result in reduced performance.
43
44There are a few other ACPI notifications that can be sent by the firmware. In
45all cases the ACPI event will be broadcast on the ACPI netlink event socket as
46well as sent as a poll notification to a sysfs file. The events are as
47follows:
48
49power[1-*]_cap will be notified if the firmware changes the power cap.
50power[1-*]_interval will be notified if the firmware changes the averaging
51interval.
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 7ec7d88c5999..2c1cab5642ff 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -82,6 +82,17 @@ config ACPI_PROCFS_POWER
82 82
83 Say N to delete power /proc/acpi/ directories that have moved to /sys/ 83 Say N to delete power /proc/acpi/ directories that have moved to /sys/
84 84
85config ACPI_POWER_METER
86 tristate "ACPI 4.0 power meter"
87 depends on HWMON
88 help
89 This driver exposes ACPI 4.0 power meters as hardware monitoring
90 devices. Say Y (or M) if you have a computer with ACPI 4.0 firmware
91 and a power meter.
92
93 To compile this driver as a module, choose M here:
94 the module will be called power-meter.
95
85config ACPI_SYSFS_POWER 96config ACPI_SYSFS_POWER
86 bool "Future power /sys interface" 97 bool "Future power /sys interface"
87 select POWER_SUPPLY 98 select POWER_SUPPLY
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 03a985be3fe3..82cd49dc603b 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
56obj-$(CONFIG_ACPI_BATTERY) += battery.o 56obj-$(CONFIG_ACPI_BATTERY) += battery.o
57obj-$(CONFIG_ACPI_SBS) += sbshc.o 57obj-$(CONFIG_ACPI_SBS) += sbshc.o
58obj-$(CONFIG_ACPI_SBS) += sbs.o 58obj-$(CONFIG_ACPI_SBS) += sbs.o
59obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o
59 60
60# processor has its own "processor." module_param namespace 61# processor has its own "processor." module_param namespace
61processor-y := processor_core.o processor_throttling.o 62processor-y := processor_core.o processor_throttling.o
diff --git a/drivers/acpi/power_meter.c b/drivers/acpi/power_meter.c
new file mode 100644
index 000000000000..e6bfd77986b8
--- /dev/null
+++ b/drivers/acpi/power_meter.c
@@ -0,0 +1,1018 @@
1/*
2 * A hwmon driver for ACPI 4.0 power meters
3 * Copyright (C) 2009 IBM
4 *
5 * Author: Darrick J. Wong <djwong@us.ibm.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <linux/module.h>
23#include <linux/hwmon.h>
24#include <linux/hwmon-sysfs.h>
25#include <linux/jiffies.h>
26#include <linux/mutex.h>
27#include <linux/dmi.h>
28#include <linux/kdev_t.h>
29#include <linux/sched.h>
30#include <linux/time.h>
31#include <acpi/acpi_drivers.h>
32#include <acpi/acpi_bus.h>
33
34#define ACPI_POWER_METER_NAME "power_meter"
35ACPI_MODULE_NAME(ACPI_POWER_METER_NAME);
36#define ACPI_POWER_METER_DEVICE_NAME "Power Meter"
37#define ACPI_POWER_METER_CLASS "power_meter_resource"
38
39#define NUM_SENSORS 17
40
41#define POWER_METER_CAN_MEASURE (1 << 0)
42#define POWER_METER_CAN_TRIP (1 << 1)
43#define POWER_METER_CAN_CAP (1 << 2)
44#define POWER_METER_CAN_NOTIFY (1 << 3)
45#define POWER_METER_IS_BATTERY (1 << 8)
46#define UNKNOWN_HYSTERESIS 0xFFFFFFFF
47
48#define METER_NOTIFY_CONFIG 0x80
49#define METER_NOTIFY_TRIP 0x81
50#define METER_NOTIFY_CAP 0x82
51#define METER_NOTIFY_CAPPING 0x83
52#define METER_NOTIFY_INTERVAL 0x84
53
54#define POWER_AVERAGE_NAME "power1_average"
55#define POWER_CAP_NAME "power1_cap"
56#define POWER_AVG_INTERVAL_NAME "power1_average_interval"
57#define POWER_ALARM_NAME "power1_alarm"
58
59static int cap_in_hardware;
60static int force_cap_on;
61
62static int can_cap_in_hardware(void)
63{
64 return force_cap_on || cap_in_hardware;
65}
66
67static struct acpi_device_id power_meter_ids[] = {
68 {"ACPI000D", 0},
69 {"", 0},
70};
71MODULE_DEVICE_TABLE(acpi, power_meter_ids);
72
73struct acpi_power_meter_capabilities {
74 acpi_integer flags;
75 acpi_integer units;
76 acpi_integer type;
77 acpi_integer accuracy;
78 acpi_integer sampling_time;
79 acpi_integer min_avg_interval;
80 acpi_integer max_avg_interval;
81 acpi_integer hysteresis;
82 acpi_integer configurable_cap;
83 acpi_integer min_cap;
84 acpi_integer max_cap;
85};
86
87struct acpi_power_meter_resource {
88 struct acpi_device *acpi_dev;
89 acpi_bus_id name;
90 struct mutex lock;
91 struct device *hwmon_dev;
92 struct acpi_power_meter_capabilities caps;
93 acpi_string model_number;
94 acpi_string serial_number;
95 acpi_string oem_info;
96 acpi_integer power;
97 acpi_integer cap;
98 acpi_integer avg_interval;
99 int sensors_valid;
100 unsigned long sensors_last_updated;
101 struct sensor_device_attribute sensors[NUM_SENSORS];
102 int num_sensors;
103 int trip[2];
104 int num_domain_devices;
105 struct acpi_device **domain_devices;
106 struct kobject *holders_dir;
107};
108
109struct ro_sensor_template {
110 char *label;
111 ssize_t (*show)(struct device *dev,
112 struct device_attribute *devattr,
113 char *buf);
114 int index;
115};
116
117struct rw_sensor_template {
118 char *label;
119 ssize_t (*show)(struct device *dev,
120 struct device_attribute *devattr,
121 char *buf);
122 ssize_t (*set)(struct device *dev,
123 struct device_attribute *devattr,
124 const char *buf, size_t count);
125 int index;
126};
127
128/* Averaging interval */
129static int update_avg_interval(struct acpi_power_meter_resource *resource)
130{
131 unsigned long long data;
132 acpi_status status;
133
134 status = acpi_evaluate_integer(resource->acpi_dev->handle, "_GAI",
135 NULL, &data);
136 if (ACPI_FAILURE(status)) {
137 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _GAI"));
138 return -ENODEV;
139 }
140
141 resource->avg_interval = data;
142 return 0;
143}
144
145static ssize_t show_avg_interval(struct device *dev,
146 struct device_attribute *devattr,
147 char *buf)
148{
149 struct acpi_device *acpi_dev = to_acpi_device(dev);
150 struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
151
152 mutex_lock(&resource->lock);
153 update_avg_interval(resource);
154 mutex_unlock(&resource->lock);
155
156 return sprintf(buf, "%llu\n", resource->avg_interval);
157}
158
159static ssize_t set_avg_interval(struct device *dev,
160 struct device_attribute *devattr,
161 const char *buf, size_t count)
162{
163 struct acpi_device *acpi_dev = to_acpi_device(dev);
164 struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
165 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
166 struct acpi_object_list args = { 1, &arg0 };
167 int res;
168 unsigned long temp;
169 unsigned long long data;
170 acpi_status status;
171
172 res = strict_strtoul(buf, 10, &temp);
173 if (res)
174 return res;
175
176 if (temp > resource->caps.max_avg_interval ||
177 temp < resource->caps.min_avg_interval)
178 return -EINVAL;
179 arg0.integer.value = temp;
180
181 mutex_lock(&resource->lock);
182 status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PAI",
183 &args, &data);
184 if (!ACPI_FAILURE(status))
185 resource->avg_interval = temp;
186 mutex_unlock(&resource->lock);
187
188 if (ACPI_FAILURE(status)) {
189 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PAI"));
190 return -EINVAL;
191 }
192
193 /* _PAI returns 0 on success, nonzero otherwise */
194 if (data)
195 return -EINVAL;
196
197 return count;
198}
199
200/* Cap functions */
201static int update_cap(struct acpi_power_meter_resource *resource)
202{
203 unsigned long long data;
204 acpi_status status;
205
206 status = acpi_evaluate_integer(resource->acpi_dev->handle, "_GHL",
207 NULL, &data);
208 if (ACPI_FAILURE(status)) {
209 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _GHL"));
210 return -ENODEV;
211 }
212
213 resource->cap = data;
214 return 0;
215}
216
217static ssize_t show_cap(struct device *dev,
218 struct device_attribute *devattr,
219 char *buf)
220{
221 struct acpi_device *acpi_dev = to_acpi_device(dev);
222 struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
223
224 mutex_lock(&resource->lock);
225 update_cap(resource);
226 mutex_unlock(&resource->lock);
227
228 return sprintf(buf, "%llu\n", resource->cap * 1000);
229}
230
231static ssize_t set_cap(struct device *dev, struct device_attribute *devattr,
232 const char *buf, size_t count)
233{
234 struct acpi_device *acpi_dev = to_acpi_device(dev);
235 struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
236 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
237 struct acpi_object_list args = { 1, &arg0 };
238 int res;
239 unsigned long temp;
240 unsigned long long data;
241 acpi_status status;
242
243 res = strict_strtoul(buf, 10, &temp);
244 if (res)
245 return res;
246
247 temp /= 1000;
248 if (temp > resource->caps.max_cap || temp < resource->caps.min_cap)
249 return -EINVAL;
250 arg0.integer.value = temp;
251
252 mutex_lock(&resource->lock);
253 status = acpi_evaluate_integer(resource->acpi_dev->handle, "_SHL",
254 &args, &data);
255 if (!ACPI_FAILURE(status))
256 resource->cap = temp;
257 mutex_unlock(&resource->lock);
258
259 if (ACPI_FAILURE(status)) {
260 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SHL"));
261 return -EINVAL;
262 }
263
264 /* _SHL returns 0 on success, nonzero otherwise */
265 if (data)
266 return -EINVAL;
267
268 return count;
269}
270
271/* Power meter trip points */
272static int set_acpi_trip(struct acpi_power_meter_resource *resource)
273{
274 union acpi_object arg_objs[] = {
275 {ACPI_TYPE_INTEGER},
276 {ACPI_TYPE_INTEGER}
277 };
278 struct acpi_object_list args = { 2, arg_objs };
279 unsigned long long data;
280 acpi_status status;
281
282 /* Both trip levels must be set */
283 if (resource->trip[0] < 0 || resource->trip[1] < 0)
284 return 0;
285
286 /* This driver stores min, max; ACPI wants max, min. */
287 arg_objs[0].integer.value = resource->trip[1];
288 arg_objs[1].integer.value = resource->trip[0];
289
290 status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PTP",
291 &args, &data);
292 if (ACPI_FAILURE(status)) {
293 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTP"));
294 return -EINVAL;
295 }
296
297 return data;
298}
299
300static ssize_t set_trip(struct device *dev, struct device_attribute *devattr,
301 const char *buf, size_t count)
302{
303 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
304 struct acpi_device *acpi_dev = to_acpi_device(dev);
305 struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
306 int res;
307 unsigned long temp;
308
309 res = strict_strtoul(buf, 10, &temp);
310 if (res)
311 return res;
312
313 temp /= 1000;
314 if (temp < 0)
315 return -EINVAL;
316
317 mutex_lock(&resource->lock);
318 resource->trip[attr->index - 7] = temp;
319 res = set_acpi_trip(resource);
320 mutex_unlock(&resource->lock);
321
322 if (res)
323 return res;
324
325 return count;
326}
327
328/* Power meter */
329static int update_meter(struct acpi_power_meter_resource *resource)
330{
331 unsigned long long data;
332 acpi_status status;
333 unsigned long local_jiffies = jiffies;
334
335 if (time_before(local_jiffies, resource->sensors_last_updated +
336 msecs_to_jiffies(resource->caps.sampling_time)) &&
337 resource->sensors_valid)
338 return 0;
339
340 status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PMM",
341 NULL, &data);
342 if (ACPI_FAILURE(status)) {
343 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMM"));
344 return -ENODEV;
345 }
346
347 resource->power = data;
348 resource->sensors_valid = 1;
349 resource->sensors_last_updated = jiffies;
350 return 0;
351}
352
353static ssize_t show_power(struct device *dev,
354 struct device_attribute *devattr,
355 char *buf)
356{
357 struct acpi_device *acpi_dev = to_acpi_device(dev);
358 struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
359
360 mutex_lock(&resource->lock);
361 update_meter(resource);
362 mutex_unlock(&resource->lock);
363
364 return sprintf(buf, "%llu\n", resource->power * 1000);
365}
366
367/* Miscellaneous */
368static ssize_t show_str(struct device *dev,
369 struct device_attribute *devattr,
370 char *buf)
371{
372 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
373 struct acpi_device *acpi_dev = to_acpi_device(dev);
374 struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
375 acpi_string val;
376
377 switch (attr->index) {
378 case 0:
379 val = resource->model_number;
380 break;
381 case 1:
382 val = resource->serial_number;
383 break;
384 case 2:
385 val = resource->oem_info;
386 break;
387 default:
388 BUG();
389 }
390
391 return sprintf(buf, "%s\n", val);
392}
393
394static ssize_t show_val(struct device *dev,
395 struct device_attribute *devattr,
396 char *buf)
397{
398 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
399 struct acpi_device *acpi_dev = to_acpi_device(dev);
400 struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
401 acpi_integer val = 0;
402
403 switch (attr->index) {
404 case 0:
405 val = resource->caps.min_avg_interval;
406 break;
407 case 1:
408 val = resource->caps.max_avg_interval;
409 break;
410 case 2:
411 val = resource->caps.min_cap * 1000;
412 break;
413 case 3:
414 val = resource->caps.max_cap * 1000;
415 break;
416 case 4:
417 if (resource->caps.hysteresis == UNKNOWN_HYSTERESIS)
418 return sprintf(buf, "unknown\n");
419
420 val = resource->caps.hysteresis * 1000;
421 break;
422 case 5:
423 if (resource->caps.flags & POWER_METER_IS_BATTERY)
424 val = 1;
425 else
426 val = 0;
427 break;
428 case 6:
429 if (resource->power > resource->cap)
430 val = 1;
431 else
432 val = 0;
433 break;
434 case 7:
435 case 8:
436 if (resource->trip[attr->index - 7] < 0)
437 return sprintf(buf, "unknown\n");
438
439 val = resource->trip[attr->index - 7] * 1000;
440 break;
441 default:
442 BUG();
443 }
444
445 return sprintf(buf, "%llu\n", val);
446}
447
448static ssize_t show_accuracy(struct device *dev,
449 struct device_attribute *devattr,
450 char *buf)
451{
452 struct acpi_device *acpi_dev = to_acpi_device(dev);
453 struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
454 unsigned int acc = resource->caps.accuracy;
455
456 return sprintf(buf, "%u.%u%%\n", acc / 1000, acc % 1000);
457}
458
459static ssize_t show_name(struct device *dev,
460 struct device_attribute *devattr,
461 char *buf)
462{
463 return sprintf(buf, "%s\n", ACPI_POWER_METER_NAME);
464}
465
466/* Sensor descriptions. If you add a sensor, update NUM_SENSORS above! */
467static struct ro_sensor_template meter_ro_attrs[] = {
468{POWER_AVERAGE_NAME, show_power, 0},
469{"power1_accuracy", show_accuracy, 0},
470{"power1_average_interval_min", show_val, 0},
471{"power1_average_interval_max", show_val, 1},
472{"power1_is_battery", show_val, 5},
473{NULL, NULL, 0},
474};
475
476static struct rw_sensor_template meter_rw_attrs[] = {
477{POWER_AVG_INTERVAL_NAME, show_avg_interval, set_avg_interval, 0},
478{NULL, NULL, NULL, 0},
479};
480
481static struct ro_sensor_template misc_cap_attrs[] = {
482{"power1_cap_min", show_val, 2},
483{"power1_cap_max", show_val, 3},
484{"power1_cap_hyst", show_val, 4},
485{POWER_ALARM_NAME, show_val, 6},
486{NULL, NULL, 0},
487};
488
489static struct ro_sensor_template ro_cap_attrs[] = {
490{POWER_CAP_NAME, show_cap, 0},
491{NULL, NULL, 0},
492};
493
494static struct rw_sensor_template rw_cap_attrs[] = {
495{POWER_CAP_NAME, show_cap, set_cap, 0},
496{NULL, NULL, NULL, 0},
497};
498
499static struct rw_sensor_template trip_attrs[] = {
500{"power1_average_min", show_val, set_trip, 7},
501{"power1_average_max", show_val, set_trip, 8},
502{NULL, NULL, NULL, 0},
503};
504
505static struct ro_sensor_template misc_attrs[] = {
506{"name", show_name, 0},
507{"power1_model_number", show_str, 0},
508{"power1_oem_info", show_str, 2},
509{"power1_serial_number", show_str, 1},
510{NULL, NULL, 0},
511};
512
513/* Read power domain data */
514static void remove_domain_devices(struct acpi_power_meter_resource *resource)
515{
516 int i;
517
518 if (!resource->num_domain_devices)
519 return;
520
521 for (i = 0; i < resource->num_domain_devices; i++) {
522 struct acpi_device *obj = resource->domain_devices[i];
523 if (!obj)
524 continue;
525
526 sysfs_remove_link(resource->holders_dir,
527 kobject_name(&obj->dev.kobj));
528 put_device(&obj->dev);
529 }
530
531 kfree(resource->domain_devices);
532 kobject_put(resource->holders_dir);
533}
534
535static int read_domain_devices(struct acpi_power_meter_resource *resource)
536{
537 int res = 0;
538 int i;
539 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
540 union acpi_object *pss;
541 acpi_status status;
542
543 status = acpi_evaluate_object(resource->acpi_dev->handle, "_PMD", NULL,
544 &buffer);
545 if (ACPI_FAILURE(status)) {
546 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMD"));
547 return -ENODEV;
548 }
549
550 pss = buffer.pointer;
551 if (!pss ||
552 pss->type != ACPI_TYPE_PACKAGE) {
553 dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME
554 "Invalid _PMD data\n");
555 res = -EFAULT;
556 goto end;
557 }
558
559 if (!pss->package.count)
560 goto end;
561
562 resource->domain_devices = kzalloc(sizeof(struct acpi_device *) *
563 pss->package.count, GFP_KERNEL);
564 if (!resource->domain_devices) {
565 res = -ENOMEM;
566 goto end;
567 }
568
569 resource->holders_dir = kobject_create_and_add("measures",
570 &resource->acpi_dev->dev.kobj);
571 if (!resource->holders_dir) {
572 res = -ENOMEM;
573 goto exit_free;
574 }
575
576 resource->num_domain_devices = pss->package.count;
577
578 for (i = 0; i < pss->package.count; i++) {
579 struct acpi_device *obj;
580 union acpi_object *element = &(pss->package.elements[i]);
581
582 /* Refuse non-references */
583 if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
584 continue;
585
586 /* Create a symlink to domain objects */
587 resource->domain_devices[i] = NULL;
588 status = acpi_bus_get_device(element->reference.handle,
589 &resource->domain_devices[i]);
590 if (ACPI_FAILURE(status))
591 continue;
592
593 obj = resource->domain_devices[i];
594 get_device(&obj->dev);
595
596 res = sysfs_create_link(resource->holders_dir, &obj->dev.kobj,
597 kobject_name(&obj->dev.kobj));
598 if (res) {
599 put_device(&obj->dev);
600 resource->domain_devices[i] = NULL;
601 }
602 }
603
604 res = 0;
605 goto end;
606
607exit_free:
608 kfree(resource->domain_devices);
609end:
610 kfree(buffer.pointer);
611 return res;
612}
613
614/* Registration and deregistration */
615static int register_ro_attrs(struct acpi_power_meter_resource *resource,
616 struct ro_sensor_template *ro)
617{
618 struct device *dev = &resource->acpi_dev->dev;
619 struct sensor_device_attribute *sensors =
620 &resource->sensors[resource->num_sensors];
621 int res = 0;
622
623 while (ro->label) {
624 sensors->dev_attr.attr.name = ro->label;
625 sensors->dev_attr.attr.mode = S_IRUGO;
626 sensors->dev_attr.show = ro->show;
627 sensors->index = ro->index;
628
629 res = device_create_file(dev, &sensors->dev_attr);
630 if (res) {
631 sensors->dev_attr.attr.name = NULL;
632 goto error;
633 }
634 sensors++;
635 resource->num_sensors++;
636 ro++;
637 }
638
639error:
640 return res;
641}
642
643static int register_rw_attrs(struct acpi_power_meter_resource *resource,
644 struct rw_sensor_template *rw)
645{
646 struct device *dev = &resource->acpi_dev->dev;
647 struct sensor_device_attribute *sensors =
648 &resource->sensors[resource->num_sensors];
649 int res = 0;
650
651 while (rw->label) {
652 sensors->dev_attr.attr.name = rw->label;
653 sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR;
654 sensors->dev_attr.show = rw->show;
655 sensors->dev_attr.store = rw->set;
656 sensors->index = rw->index;
657
658 res = device_create_file(dev, &sensors->dev_attr);
659 if (res) {
660 sensors->dev_attr.attr.name = NULL;
661 goto error;
662 }
663 sensors++;
664 resource->num_sensors++;
665 rw++;
666 }
667
668error:
669 return res;
670}
671
672static void remove_attrs(struct acpi_power_meter_resource *resource)
673{
674 int i;
675
676 for (i = 0; i < resource->num_sensors; i++) {
677 if (!resource->sensors[i].dev_attr.attr.name)
678 continue;
679 device_remove_file(&resource->acpi_dev->dev,
680 &resource->sensors[i].dev_attr);
681 }
682
683 remove_domain_devices(resource);
684
685 resource->num_sensors = 0;
686}
687
688static int setup_attrs(struct acpi_power_meter_resource *resource)
689{
690 int res = 0;
691
692 res = read_domain_devices(resource);
693 if (res)
694 return res;
695
696 if (resource->caps.flags & POWER_METER_CAN_MEASURE) {
697 res = register_ro_attrs(resource, meter_ro_attrs);
698 if (res)
699 goto error;
700 res = register_rw_attrs(resource, meter_rw_attrs);
701 if (res)
702 goto error;
703 }
704
705 if (resource->caps.flags & POWER_METER_CAN_CAP) {
706 if (!can_cap_in_hardware()) {
707 dev_err(&resource->acpi_dev->dev,
708 "Ignoring unsafe software power cap!\n");
709 goto skip_unsafe_cap;
710 }
711
712 if (resource->caps.configurable_cap) {
713 res = register_rw_attrs(resource, rw_cap_attrs);
714 if (res)
715 goto error;
716 } else {
717 res = register_ro_attrs(resource, ro_cap_attrs);
718 if (res)
719 goto error;
720 }
721 res = register_ro_attrs(resource, misc_cap_attrs);
722 if (res)
723 goto error;
724 }
725skip_unsafe_cap:
726
727 if (resource->caps.flags & POWER_METER_CAN_TRIP) {
728 res = register_rw_attrs(resource, trip_attrs);
729 if (res)
730 goto error;
731 }
732
733 res = register_ro_attrs(resource, misc_attrs);
734 if (res)
735 goto error;
736
737 return res;
738error:
739 remove_domain_devices(resource);
740 remove_attrs(resource);
741 return res;
742}
743
744static void free_capabilities(struct acpi_power_meter_resource *resource)
745{
746 acpi_string *str;
747 int i;
748
749 str = &resource->model_number;
750 for (i = 0; i < 3; i++, str++)
751 kfree(*str);
752}
753
754static int read_capabilities(struct acpi_power_meter_resource *resource)
755{
756 int res = 0;
757 int i;
758 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
759 struct acpi_buffer state = { 0, NULL };
760 struct acpi_buffer format = { sizeof("NNNNNNNNNNN"), "NNNNNNNNNNN" };
761 union acpi_object *pss;
762 acpi_string *str;
763 acpi_status status;
764
765 status = acpi_evaluate_object(resource->acpi_dev->handle, "_PMC", NULL,
766 &buffer);
767 if (ACPI_FAILURE(status)) {
768 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMC"));
769 return -ENODEV;
770 }
771
772 pss = buffer.pointer;
773 if (!pss ||
774 pss->type != ACPI_TYPE_PACKAGE ||
775 pss->package.count != 14) {
776 dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME
777 "Invalid _PMC data\n");
778 res = -EFAULT;
779 goto end;
780 }
781
782 /* Grab all the integer data at once */
783 state.length = sizeof(struct acpi_power_meter_capabilities);
784 state.pointer = &resource->caps;
785
786 status = acpi_extract_package(pss, &format, &state);
787 if (ACPI_FAILURE(status)) {
788 ACPI_EXCEPTION((AE_INFO, status, "Invalid data"));
789 res = -EFAULT;
790 goto end;
791 }
792
793 if (resource->caps.units) {
794 dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME
795 "Unknown units %llu.\n",
796 resource->caps.units);
797 res = -EINVAL;
798 goto end;
799 }
800
801 /* Grab the string data */
802 str = &resource->model_number;
803
804 for (i = 11; i < 14; i++) {
805 union acpi_object *element = &(pss->package.elements[i]);
806
807 if (element->type != ACPI_TYPE_STRING) {
808 res = -EINVAL;
809 goto error;
810 }
811
812 *str = kzalloc(sizeof(u8) * (element->string.length + 1),
813 GFP_KERNEL);
814 if (!*str) {
815 res = -ENOMEM;
816 goto error;
817 }
818
819 strncpy(*str, element->string.pointer, element->string.length);
820 str++;
821 }
822
823 dev_info(&resource->acpi_dev->dev, "Found ACPI power meter.\n");
824 goto end;
825error:
826 str = &resource->model_number;
827 for (i = 0; i < 3; i++, str++)
828 kfree(*str);
829end:
830 kfree(buffer.pointer);
831 return res;
832}
833
834/* Handle ACPI event notifications */
835static void acpi_power_meter_notify(struct acpi_device *device, u32 event)
836{
837 struct acpi_power_meter_resource *resource;
838 int res;
839
840 if (!device || !acpi_driver_data(device))
841 return;
842
843 resource = acpi_driver_data(device);
844
845 mutex_lock(&resource->lock);
846 switch (event) {
847 case METER_NOTIFY_CONFIG:
848 free_capabilities(resource);
849 res = read_capabilities(resource);
850 if (res)
851 break;
852
853 remove_attrs(resource);
854 setup_attrs(resource);
855 break;
856 case METER_NOTIFY_TRIP:
857 sysfs_notify(&device->dev.kobj, NULL, POWER_AVERAGE_NAME);
858 update_meter(resource);
859 break;
860 case METER_NOTIFY_CAP:
861 sysfs_notify(&device->dev.kobj, NULL, POWER_CAP_NAME);
862 update_cap(resource);
863 break;
864 case METER_NOTIFY_INTERVAL:
865 sysfs_notify(&device->dev.kobj, NULL, POWER_AVG_INTERVAL_NAME);
866 update_avg_interval(resource);
867 break;
868 case METER_NOTIFY_CAPPING:
869 sysfs_notify(&device->dev.kobj, NULL, POWER_ALARM_NAME);
870 dev_info(&device->dev, "Capping in progress.\n");
871 break;
872 default:
873 BUG();
874 }
875 mutex_unlock(&resource->lock);
876
877 acpi_bus_generate_netlink_event(ACPI_POWER_METER_CLASS,
878 dev_name(&device->dev), event, 0);
879}
880
881static int acpi_power_meter_add(struct acpi_device *device)
882{
883 int res;
884 struct acpi_power_meter_resource *resource;
885
886 if (!device)
887 return -EINVAL;
888
889 resource = kzalloc(sizeof(struct acpi_power_meter_resource),
890 GFP_KERNEL);
891 if (!resource)
892 return -ENOMEM;
893
894 resource->sensors_valid = 0;
895 resource->acpi_dev = device;
896 mutex_init(&resource->lock);
897 strcpy(acpi_device_name(device), ACPI_POWER_METER_DEVICE_NAME);
898 strcpy(acpi_device_class(device), ACPI_POWER_METER_CLASS);
899 device->driver_data = resource;
900
901 free_capabilities(resource);
902 res = read_capabilities(resource);
903 if (res)
904 goto exit_free;
905
906 resource->trip[0] = resource->trip[1] = -1;
907
908 res = setup_attrs(resource);
909 if (res)
910 goto exit_free;
911
912 resource->hwmon_dev = hwmon_device_register(&device->dev);
913 if (IS_ERR(resource->hwmon_dev)) {
914 res = PTR_ERR(resource->hwmon_dev);
915 goto exit_remove;
916 }
917
918 res = 0;
919 goto exit;
920
921exit_remove:
922 remove_attrs(resource);
923exit_free:
924 kfree(resource);
925exit:
926 return res;
927}
928
929static int acpi_power_meter_remove(struct acpi_device *device, int type)
930{
931 struct acpi_power_meter_resource *resource;
932
933 if (!device || !acpi_driver_data(device))
934 return -EINVAL;
935
936 resource = acpi_driver_data(device);
937 hwmon_device_unregister(resource->hwmon_dev);
938
939 free_capabilities(resource);
940 remove_attrs(resource);
941
942 kfree(resource);
943 return 0;
944}
945
946static int acpi_power_meter_resume(struct acpi_device *device)
947{
948 struct acpi_power_meter_resource *resource;
949
950 if (!device || !acpi_driver_data(device))
951 return -EINVAL;
952
953 resource = acpi_driver_data(device);
954 free_capabilities(resource);
955 read_capabilities(resource);
956
957 return 0;
958}
959
960static struct acpi_driver acpi_power_meter_driver = {
961 .name = "power_meter",
962 .class = ACPI_POWER_METER_CLASS,
963 .ids = power_meter_ids,
964 .ops = {
965 .add = acpi_power_meter_add,
966 .remove = acpi_power_meter_remove,
967 .resume = acpi_power_meter_resume,
968 .notify = acpi_power_meter_notify,
969 },
970};
971
972/* Module init/exit routines */
973static int __init enable_cap_knobs(const struct dmi_system_id *d)
974{
975 cap_in_hardware = 1;
976 return 0;
977}
978
979static struct dmi_system_id __initdata pm_dmi_table[] = {
980 {
981 enable_cap_knobs, "IBM Active Energy Manager",
982 {
983 DMI_MATCH(DMI_SYS_VENDOR, "IBM")
984 },
985 },
986 {}
987};
988
989static int __init acpi_power_meter_init(void)
990{
991 int result;
992
993 if (acpi_disabled)
994 return -ENODEV;
995
996 dmi_check_system(pm_dmi_table);
997
998 result = acpi_bus_register_driver(&acpi_power_meter_driver);
999 if (result < 0)
1000 return -ENODEV;
1001
1002 return 0;
1003}
1004
1005static void __exit acpi_power_meter_exit(void)
1006{
1007 acpi_bus_unregister_driver(&acpi_power_meter_driver);
1008}
1009
1010MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
1011MODULE_DESCRIPTION("ACPI 4.0 power meter driver");
1012MODULE_LICENSE("GPL");
1013
1014module_param(force_cap_on, bool, 0644);
1015MODULE_PARM_DESC(force_cap_on, "Enable power cap even it is unsafe to do so.");
1016
1017module_init(acpi_power_meter_init);
1018module_exit(acpi_power_meter_exit);