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 45MODULE_AUTHOR("Martin Ridgeway <mridge@us.ibm.com>"); 46MODULE_AUTHOR("Alexey Kodanev <alexey.kodanev@oracle.com>"); 47MODULE_DESCRIPTION("ACPI LTP Test Driver"); 48MODULE_LICENSE("GPL"); 49ACPI_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 58static 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 */ 68static char *str_obj_result; 69 70/* sysfs device path of the last found device */ 71static char *sysfs_path; 72 73/* first found device with _CRS */ 74static acpi_handle res_handle; 75 76static 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 113static 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 124static 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 */ 138static acpi_handle start_parent; 139 140static 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 210static 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 */ 234static acpi_handle dev_handle; 235static int acpi_hw_reduced; 236 237/* check if PM2 control register supported */ 238static bool pm2_supported; 239 240static 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 */ 289static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) 290{ 291 prk_alert("Register ACPI Bus Notify callback function"); 292} 293 294static 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 315static u32 ltp_test_power_button_ev_handler(void *context) 316{ 317 prk_alert("ltp_test_power_button_ev_handler"); 318 return 1; 319} 320 321static u32 ltp_test_sleep_button_ev_handler(void *context) 322{ 323 prk_alert("ltp_test_sleep_button_ev_handler"); 324 return 1; 325} 326 327static 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 371static 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 390static 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 415static acpi_status acpi_ec_io_ports(struct acpi_resource *resource, 416 void *context) 417{ 418 return 0; 419} 420 421static 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 450static 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 471static 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 503static 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 522static 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 530static int current_test_case; 531static int test_result; 532 533static void device_release(struct device *dev) 534{ 535 prk_info("device released"); 536} 537 538static struct device tdev = { 539 .init_name = ACPI_TEST_NAME, 540 .release = device_release, 541}; 542 543/* print test result to sysfs file */ 544static 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} 549static DEVICE_ATTR(result, S_IRUSR, sys_result, NULL); 550 551/* print found device description */ 552static 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} 560static DEVICE_ATTR(str, S_IRUSR, sys_str, NULL); 561 562/* print found device's sysfs path */ 563static 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} 571static DEVICE_ATTR(path, S_IRUSR, sys_path, NULL); 572 573static 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} 578static DEVICE_ATTR(acpi_disabled, S_IRUSR, sys_acpi_disabled, NULL); 579 580static 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} 621static DEVICE_ATTR(tcase, S_IWUSR, NULL, sys_tcase); 622 623int 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 667err5: 668 device_remove_file(&tdev, &dev_attr_path); 669err4: 670 device_remove_file(&tdev, &dev_attr_tcase); 671err3: 672 device_remove_file(&tdev, &dev_attr_str); 673err2: 674 device_remove_file(&tdev, &dev_attr_result); 675err1: 676 device_unregister(&tdev); 677err0: 678 return err; 679} 680 681void 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