1 /*
2 * Copyright (c) International Business Machines Corp., 2001
3 * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /*
21 * HISTORY:
22 * 06/09/2003 Initial creation mridge@us.ibm.com
23 * -Ported
24 * updated - 01/09/2005 Updates from Intel to add functionality
25 *
26 * 01/03/2009 Márton Németh <nm127@freemail.hu>
27 * - Updated for Linux kernel 2.6.28
28 */
29
30 #include <linux/kernel.h>
31 #include <linux/module.h>
32 #include <linux/init.h>
33 #include <linux/types.h>
34 #include <linux/fs.h>
35 #include <linux/blkdev.h>
36 #include <linux/ioctl.h>
37 #include <linux/pm.h>
38 #include <linux/acpi.h>
39 #include <linux/genhd.h>
40 #include <linux/dmi.h>
41 #include <linux/nls.h>
42
43 #include "ltp_acpi.h"
44
45 MODULE_AUTHOR("Martin Ridgeway <mridge@us.ibm.com>");
46 MODULE_AUTHOR("Alexey Kodanev <alexey.kodanev@oracle.com>");
47 MODULE_DESCRIPTION("ACPI LTP Test Driver");
48 MODULE_LICENSE("GPL");
49 ACPI_MODULE_NAME("LTP_ACPI")
50
51 #define prk_err(fmt, ...) \
52 pr_err(ACPI_TEST_NAME ": " fmt "\n", ##__VA_ARGS__)
53 #define prk_alert(fmt, ...) \
54 pr_alert(ACPI_TEST_NAME ": " fmt "\n", ##__VA_ARGS__)
55 #define prk_info(fmt, ...) \
56 pr_info(ACPI_TEST_NAME ": " fmt "\n", ##__VA_ARGS__)
57
acpi_failure(acpi_status status,const char * name)58 static int acpi_failure(acpi_status status, const char *name)
59 {
60 if (ACPI_FAILURE(status)) {
61 ACPI_EXCEPTION((AE_INFO, status, name));
62 return 1;
63 }
64 return 0;
65 }
66
67 /* points to the string of the last found object _STR */
68 static char *str_obj_result;
69
70 /* sysfs device path of the last found device */
71 static char *sysfs_path;
72
73 /* first found device with _CRS */
74 static acpi_handle res_handle;
75
get_str_object(acpi_handle handle)76 static acpi_status get_str_object(acpi_handle handle)
77 {
78 int res;
79 acpi_status status;
80 acpi_handle temp = 0;
81 union acpi_object *str_obj;
82 char *buf = NULL;
83
84 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
85
86 status = acpi_get_handle(handle, "_STR", &temp);
87
88 if (ACPI_SUCCESS(status) &&
89 !acpi_evaluate_object(handle, "_STR", NULL, &buffer)) {
90
91 str_obj = buffer.pointer;
92
93 buf = kmalloc(str_obj->buffer.length / 2, GFP_KERNEL);
94 if (!buf) {
95 kfree(str_obj);
96 return AE_NO_MEMORY;
97 }
98
99 res = utf16s_to_utf8s((wchar_t *)str_obj->buffer.pointer,
100 str_obj->buffer.length, UTF16_LITTLE_ENDIAN, buf,
101 str_obj->buffer.length / 2);
102
103 buf[res] = '\0';
104
105 kfree(str_obj_result);
106 str_obj_result = buf;
107 kfree(str_obj);
108 }
109
110 return status;
111 }
112
get_crs_object(acpi_handle handle)113 static void get_crs_object(acpi_handle handle)
114 {
115 acpi_status status;
116 acpi_handle temp;
117 if (!res_handle) {
118 status = acpi_get_handle(handle, METHOD_NAME__CRS, &temp);
119 if (ACPI_SUCCESS(status))
120 res_handle = handle;
121 }
122 }
123
get_sysfs_path(acpi_handle handle)124 static void get_sysfs_path(acpi_handle handle)
125 {
126 acpi_status status;
127 struct acpi_device *device;
128
129 kfree(sysfs_path);
130 sysfs_path = NULL;
131
132 status = acpi_bus_get_device(handle, &device);
133 if (ACPI_SUCCESS(status))
134 sysfs_path = kobject_get_path(&device->dev.kobj, GFP_KERNEL);
135 }
136
137 /* acpi handle of the last visited device */
138 static acpi_handle start_parent;
139
acpi_traverse(acpi_handle parent,acpi_handle child)140 static int acpi_traverse(acpi_handle parent, acpi_handle child)
141 {
142 static char indent[64];
143 const char * const ind_end = indent + 63;
144 static const char *ind = ind_end;
145 acpi_status status;
146 struct acpi_device_info *dev_info;
147 acpi_handle new_child;
148
149 if (!indent[0])
150 memset(indent, 0x20, 63);
151
152 while (parent) {
153 status = acpi_get_next_object(ACPI_TYPE_DEVICE,
154 parent, child, &new_child);
155
156 if (ACPI_FAILURE(status)) {
157 ind += 4;
158
159 child = parent;
160 status = acpi_get_parent(child, &parent);
161
162 /* no more devices */
163 if (ACPI_FAILURE(status)) {
164 start_parent = 0;
165 kfree(str_obj_result);
166 str_obj_result = NULL;
167 return 0;
168 }
169 continue;
170 }
171
172 status = acpi_get_object_info(new_child, &dev_info);
173 if (acpi_failure(status, "acpi_object_info failed"))
174 return 1;
175
176 get_sysfs_path(new_child);
177
178 get_crs_object(new_child);
179
180 if (ind < indent)
181 ind = indent;
182 else if (ind > ind_end)
183 ind = ind_end;
184
185 /*
186 * if we find _STR object we will stop here
187 * and save last visited child
188 */
189 if (ACPI_SUCCESS(get_str_object(new_child))) {
190 prk_info("%s%4.4s: has '_STR' '%s' path '%s'",
191 ind, (char *)&dev_info->name, str_obj_result,
192 (sysfs_path) ? sysfs_path : "no path");
193 ind -= 4;
194 start_parent = new_child;
195 kfree(dev_info);
196 return 0;
197 }
198 prk_info("%s%4.4s: path '%s'", ind, (char *)&dev_info->name,
199 (sysfs_path) ? sysfs_path : "no path");
200
201 ind -= 4;
202 parent = new_child;
203 child = 0;
204 kfree(dev_info);
205 }
206
207 return 0;
208 }
209
acpi_traverse_from_root(void)210 static int acpi_traverse_from_root(void)
211 {
212 acpi_status status;
213 struct acpi_device_info *dev_info;
214 acpi_handle parent = 0, child = 0;
215
216 if (!start_parent) {
217 status = acpi_get_handle(NULL, ACPI_NS_ROOT_PATH, &parent);
218 if (acpi_failure(status, "acpi_get_handle"))
219 return 1;
220 status = acpi_get_object_info(parent, &dev_info);
221 if (acpi_failure(status, "acpi_object_info failed"))
222 return 1;
223 prk_info("start from %4.4s", (char *)&dev_info->name);
224 kfree(dev_info);
225 } else {
226 /* continue with the last visited child */
227 parent = start_parent;
228 }
229
230 return acpi_traverse(parent, child);
231 }
232
233 /* first found device with _STR */
234 static acpi_handle dev_handle;
235 static int acpi_hw_reduced;
236
237 /* check if PM2 control register supported */
238 static bool pm2_supported;
239
acpi_init(void)240 static int acpi_init(void)
241 {
242 acpi_status status;
243 acpi_handle parent_handle;
244 struct acpi_table_fadt *fadt;
245 struct acpi_table_header *table;
246 struct acpi_device_info *dev_info;
247 pm2_supported = true;
248
249 status = acpi_get_table(ACPI_SIG_FADT, 0, &table);
250 if (ACPI_SUCCESS(status)) {
251 fadt = (struct acpi_table_fadt *)table;
252 if (fadt->flags & ACPI_FADT_HW_REDUCED)
253 acpi_hw_reduced = 1;
254 if (fadt->pm2_control_block == 0 || fadt->pm2_control_length == 0)
255 pm2_supported = false;
256 }
257 if (acpi_hw_reduced)
258 prk_alert("Detected the Hardware-reduced ACPI mode");
259
260 prk_alert("TEST -- acpi_get_handle ");
261 status = acpi_get_handle(NULL, "\\_SB", &parent_handle);
262 if (acpi_failure(status, "acpi_get_handle"))
263 return 1;
264
265 /* get first device on SYS bus, it will be used in other tests */
266 while (acpi_get_next_object(ACPI_TYPE_DEVICE,
267 parent_handle, 0, &dev_handle) == 0) {
268 parent_handle = dev_handle;
269 }
270
271 status = acpi_get_object_info(dev_handle, &dev_info);
272 if (acpi_failure(status, "acpi_object_info failed"))
273 return 1;
274
275 prk_alert("ACPI object name %4.4s, type %d", (char *)&dev_info->name,
276 dev_info->type);
277 kfree(dev_info);
278
279 prk_alert("TEST -- acpi_get_parent ");
280 status = acpi_get_parent(dev_handle, &parent_handle);
281 return acpi_failure(status, "acpi_get_parent failed");
282 }
283
284 /*
285 * acpi_bus_notify
286 * ---------------
287 * Callback for all 'system-level' device notifications (values 0x00-0x7F).
288 */
acpi_bus_notify(acpi_handle handle,u32 type,void * data)289 static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
290 {
291 prk_alert("Register ACPI Bus Notify callback function");
292 }
293
acpi_test_notify_handler(void)294 static int acpi_test_notify_handler(void)
295 {
296 acpi_status status;
297
298 prk_alert("TEST -- acpi_install_notify_handler");
299
300 status = acpi_install_notify_handler(dev_handle,
301 ACPI_SYSTEM_NOTIFY, &acpi_bus_notify, NULL);
302
303 if (ACPI_SUCCESS(status)) {
304 prk_alert("TEST -- acpi_remove_notify_handler");
305 status = acpi_remove_notify_handler(dev_handle,
306 ACPI_SYSTEM_NOTIFY, &acpi_bus_notify);
307 return acpi_failure(status, "acpi_remove_notify_handler");
308 } else if (status != AE_ALREADY_EXISTS) {
309 return acpi_failure(status, "acpi_install_notify_handler");
310 }
311
312 return 0;
313 }
314
ltp_test_power_button_ev_handler(void * context)315 static u32 ltp_test_power_button_ev_handler(void *context)
316 {
317 prk_alert("ltp_test_power_button_ev_handler");
318 return 1;
319 }
320
ltp_test_sleep_button_ev_handler(void * context)321 static u32 ltp_test_sleep_button_ev_handler(void *context)
322 {
323 prk_alert("ltp_test_sleep_button_ev_handler");
324 return 1;
325 }
326
acpi_test_event_handler(void)327 static int acpi_test_event_handler(void)
328 {
329 int err = 0;
330 acpi_status status;
331
332 prk_alert("TEST -- acpi_install_fixed_event_handler");
333 if (acpi_hw_reduced) {
334 prk_alert("Skipped due to the HW-reduced mode");
335 return 0;
336 }
337 status = acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
338 ltp_test_power_button_ev_handler, NULL);
339
340 if (ACPI_SUCCESS(status)) {
341 prk_alert("TEST -- acpi_remove_fixed_event_handler");
342 status = acpi_remove_fixed_event_handler(
343 ACPI_EVENT_POWER_BUTTON,
344 ltp_test_power_button_ev_handler);
345 err = acpi_failure(status, "remove fixed event handler");
346 } else if (status != AE_ALREADY_EXISTS) {
347 err = acpi_failure(status, "install fixed event handler");
348 }
349
350 prk_alert("TEST -- acpi_install_fixed_event_handler");
351 status = acpi_install_fixed_event_handler(ACPI_EVENT_RTC,
352 ltp_test_sleep_button_ev_handler, NULL);
353
354 if (ACPI_SUCCESS(status)) {
355 prk_alert("TEST -- acpi_remove_fixed_event_handler");
356 status = acpi_remove_fixed_event_handler(
357 ACPI_EVENT_RTC,
358 ltp_test_sleep_button_ev_handler);
359 err |= acpi_failure(status, "remove fixed event handler");
360 } else if (status != AE_ALREADY_EXISTS) {
361 err |= acpi_failure(status, "install fixed event handler");
362 }
363
364 return err;
365 }
366
367 #ifndef ACPI_EC_UDELAY_GLK
368 #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
369 #endif
370
acpi_global_lock(void)371 static int acpi_global_lock(void)
372 {
373 acpi_status status;
374 u32 global_lock = 0;
375
376 prk_alert("TEST -- acpi_acquire_global_lock ");
377 if (acpi_hw_reduced) {
378 prk_alert("Skipped due to the HW-reduced mode");
379 return 0;
380 }
381 status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &global_lock);
382 if (acpi_failure(status, "acpi_acquire_global_lock"))
383 return 1;
384
385 prk_alert("TEST -- acpi_release_global_lock ");
386 status = acpi_release_global_lock(global_lock);
387 return acpi_failure(status, "acpi_release_global_lock");
388 }
389
acpi_test_bus(void)390 static int acpi_test_bus(void)
391 {
392 int state = 0;
393 acpi_status status;
394 acpi_handle bus_handle;
395 struct acpi_device *device;
396
397 status = acpi_get_handle(NULL, "\\_SB", &bus_handle);
398 if (acpi_failure(status, "acpi_get_handle"))
399 return 1;
400
401 prk_alert("TEST -- acpi_bus_get_device");
402 status = acpi_bus_get_device(bus_handle, &device);
403 if (acpi_failure(status, "acpi_bus_get_device"))
404 return 1;
405
406 prk_alert("TEST -- acpi_bus_update_power ");
407 status = acpi_bus_update_power(device->handle, &state);
408 if (acpi_failure(status, "error reading power state"))
409 return 1;
410
411 prk_info("acpi bus power state is %d", state);
412 return 0;
413 }
414
acpi_ec_io_ports(struct acpi_resource * resource,void * context)415 static acpi_status acpi_ec_io_ports(struct acpi_resource *resource,
416 void *context)
417 {
418 return 0;
419 }
420
acpi_test_resources(void)421 static int acpi_test_resources(void)
422 {
423 int err = 0;
424 acpi_status status;
425 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
426
427 /* skip if we don't find device with _CRC */
428 if (res_handle == 0)
429 return 0;
430
431 prk_alert("TEST -- acpi_get_current_resources");
432 status = acpi_get_current_resources(res_handle, &buffer);
433 err = acpi_failure(status, "failed get_current_resources");
434 ACPI_FREE(buffer.pointer);
435
436 #ifdef ACPI_FUTURE_USAGE
437 prk_alert("TEST -- acpi_get_possible_resources");
438 status = acpi_get_possible_resources(res_handle, &buffer);
439 err |= acpi_failure(status, "get_possible_resources");
440 #endif
441
442 prk_alert("TEST -- acpi_walk_resources ");
443 status = acpi_walk_resources(res_handle, METHOD_NAME__CRS,
444 acpi_ec_io_ports, NULL);
445 err |= acpi_failure(status, "Failed walk_resources");
446
447 return err;
448 }
449
acpi_sleep_test(void)450 static int acpi_sleep_test(void)
451 {
452 int err = 0;
453 acpi_status status;
454 u32 i;
455 u8 type_a, type_b;
456 prk_alert("TEST -- acpi_get_sleep_type_data ");
457
458 for (i = 0; i < ACPI_S_STATE_COUNT; ++i) {
459 status = acpi_get_sleep_type_data(i, &type_a, &type_b);
460 if (ACPI_SUCCESS(status)) {
461 prk_info("get_sleep_type_data S%d a:%d b:%d",
462 i, type_a, type_b);
463 } else if (status != AE_NOT_FOUND) {
464 err |= 1;
465 }
466 }
467
468 return err;
469 }
470
acpi_test_register(void)471 static int acpi_test_register(void)
472 {
473 int i, err = 0;
474 u32 val;
475 acpi_status status;
476
477 prk_alert("TEST -- acpi_read_bit_register");
478 if (acpi_hw_reduced) {
479 prk_alert("Skipped due to the HW-reduced mode");
480 return 0;
481 }
482 /*
483 * ACPICA: Remove obsolete Flags parameter.
484 * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;
485 * a=commitdiff;h=d8c71b6d3b21cf21ad775e1cf6da95bf87bd5ad4
486 *
487 * ACPICA: Rename ACPI bit register access functions
488 * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/
489 * commit/?id=50ffba1bd3120b069617455545bc27bcf3cf7579
490 */
491 for (i = 0; i < ACPI_NUM_BITREG; ++i) {
492 if (i == ACPI_BITREG_ARB_DISABLE && !pm2_supported)
493 continue;
494 status = acpi_read_bit_register(i, &val);
495 err |= acpi_failure(status, "acpi_read_bit_register");
496 if (ACPI_SUCCESS(status))
497 prk_alert("get register: %02x val: %04x", i, val);
498 }
499
500 return err;
501 }
502
ltp_get_dev_callback(acpi_handle obj,u32 depth,void * context,void ** ret)503 static acpi_status ltp_get_dev_callback(acpi_handle obj, u32 depth,
504 void *context, void **ret)
505 {
506 char *name = context;
507 char fullname[20];
508
509 /*
510 * Only SBA shows up in ACPI namespace, so its CSR space
511 * includes both SBA and IOC. Make SBA and IOC show up
512 * separately in PCI space.
513 */
514 sprintf(fullname, "%s SBA", name);
515 prk_info("get_dev_callback SBA name %s", fullname);
516 sprintf(fullname, "%s IOC", name);
517 prk_info("get_dev_callback IOC name %s", fullname);
518
519 return 0;
520 }
521
acpi_test_dev_callback(void)522 static int acpi_test_dev_callback(void)
523 {
524 acpi_status status;
525 prk_alert("TEST -- acpi_get_devices ");
526 status = acpi_get_devices(NULL, ltp_get_dev_callback, "LTP0001", NULL);
527 return acpi_failure(status, "acpi_get_devices");
528 }
529
530 static int current_test_case;
531 static int test_result;
532
device_release(struct device * dev)533 static void device_release(struct device *dev)
534 {
535 prk_info("device released");
536 }
537
538 static struct device tdev = {
539 .init_name = ACPI_TEST_NAME,
540 .release = device_release,
541 };
542
543 /* print test result to sysfs file */
sys_result(struct device * dev,struct device_attribute * attr,char * buf)544 static ssize_t sys_result(struct device *dev,
545 struct device_attribute *attr, char *buf)
546 {
547 return scnprintf(buf, PAGE_SIZE, "%d\n", test_result);
548 }
549 static DEVICE_ATTR(result, S_IRUSR, sys_result, NULL);
550
551 /* print found device description */
sys_str(struct device * dev,struct device_attribute * attr,char * buf)552 static ssize_t sys_str(struct device *dev,
553 struct device_attribute *attr, char *buf)
554 {
555 if (str_obj_result)
556 return scnprintf(buf, PAGE_SIZE, "%s", str_obj_result);
557 else
558 return 0;
559 }
560 static DEVICE_ATTR(str, S_IRUSR, sys_str, NULL);
561
562 /* print found device's sysfs path */
sys_path(struct device * dev,struct device_attribute * attr,char * buf)563 static ssize_t sys_path(struct device *dev,
564 struct device_attribute *attr, char *buf)
565 {
566 if (sysfs_path)
567 return scnprintf(buf, PAGE_SIZE, "%s", sysfs_path);
568 else
569 return 0;
570 }
571 static DEVICE_ATTR(path, S_IRUSR, sys_path, NULL);
572
sys_acpi_disabled(struct device * dev,struct device_attribute * attr,char * buf)573 static ssize_t sys_acpi_disabled(struct device *dev,
574 struct device_attribute *attr, char *buf)
575 {
576 return scnprintf(buf, PAGE_SIZE, "%d", acpi_disabled);
577 }
578 static DEVICE_ATTR(acpi_disabled, S_IRUSR, sys_acpi_disabled, NULL);
579
sys_tcase(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)580 static ssize_t sys_tcase(struct device *dev,
581 struct device_attribute *attr, const char *buf, size_t count)
582 {
583 sscanf(buf, "%d", ¤t_test_case);
584 prk_info("test-case %d", current_test_case);
585
586 switch (current_test_case) {
587 case ACPI_INIT:
588 test_result = acpi_init();
589 break;
590 case ACPI_TRAVERSE:
591 test_result = acpi_traverse_from_root();
592 break;
593 case ACPI_NOTIFY_HANDLER:
594 test_result = acpi_test_notify_handler();
595 break;
596 case ACPI_EVENT_HANDLER:
597 test_result = acpi_test_event_handler();
598 break;
599 case ACPI_GLOBAL_LOCK:
600 test_result = acpi_global_lock();
601 break;
602 case ACPI_TEST_BUS:
603 test_result = acpi_test_bus();
604 break;
605 case ACPI_TEST_RESOURCES:
606 test_result = acpi_test_resources();
607 break;
608 case ACPI_SLEEP_TEST:
609 test_result = acpi_sleep_test();
610 break;
611 case ACPI_TEST_REGISTER:
612 test_result = acpi_test_register();
613 break;
614 case ACPI_TEST_DEV_CALLBACK:
615 test_result = acpi_test_dev_callback();
616 break;
617 }
618
619 return count;
620 }
621 static DEVICE_ATTR(tcase, S_IWUSR, NULL, sys_tcase);
622
init_module(void)623 int init_module(void)
624 {
625 int err = 0;
626 prk_info("Starting module");
627
628 err = device_register(&tdev);
629 if (err) {
630 prk_err("Unable to register device");
631 goto err0;
632 }
633 prk_info("device registered");
634
635 err = device_create_file(&tdev, &dev_attr_result);
636 if (err) {
637 prk_err("Can't create sysfs file 'result'");
638 goto err1;
639 }
640
641 err = device_create_file(&tdev, &dev_attr_str);
642 if (err) {
643 prk_err("Can't create sysfs file 'str'");
644 goto err2;
645 }
646
647 err = device_create_file(&tdev, &dev_attr_tcase);
648 if (err) {
649 prk_err(": Can't create sysfs file 'tc'");
650 goto err3;
651 }
652
653 err = device_create_file(&tdev, &dev_attr_path);
654 if (err) {
655 prk_err(": Can't create sysfs file 'path'");
656 goto err4;
657 }
658
659 err = device_create_file(&tdev, &dev_attr_acpi_disabled);
660 if (err) {
661 prk_err("Can't create sysfs file 'acpi_disabled'");
662 goto err5;
663 }
664
665 return 0;
666
667 err5:
668 device_remove_file(&tdev, &dev_attr_path);
669 err4:
670 device_remove_file(&tdev, &dev_attr_tcase);
671 err3:
672 device_remove_file(&tdev, &dev_attr_str);
673 err2:
674 device_remove_file(&tdev, &dev_attr_result);
675 err1:
676 device_unregister(&tdev);
677 err0:
678 return err;
679 }
680
cleanup_module(void)681 void cleanup_module(void)
682 {
683 prk_info("Unloading module\n");
684
685 kfree(str_obj_result);
686 kfree(sysfs_path);
687
688 device_remove_file(&tdev, &dev_attr_result);
689 device_remove_file(&tdev, &dev_attr_str);
690 device_remove_file(&tdev, &dev_attr_tcase);
691 device_remove_file(&tdev, &dev_attr_path);
692 device_unregister(&tdev);
693 }
694