11c8fce27SZhang Rui /* 21c8fce27SZhang Rui * sysfs.c - ACPI sysfs interface to userspace. 31c8fce27SZhang Rui */ 41c8fce27SZhang Rui 51c8fce27SZhang Rui #include <linux/init.h> 61c8fce27SZhang Rui #include <linux/kernel.h> 71c8fce27SZhang Rui #include <linux/moduleparam.h> 81c8fce27SZhang Rui #include <acpi/acpi_drivers.h> 91c8fce27SZhang Rui 101c8fce27SZhang Rui #define _COMPONENT ACPI_SYSTEM_COMPONENT 111c8fce27SZhang Rui ACPI_MODULE_NAME("sysfs"); 121c8fce27SZhang Rui 131c8fce27SZhang Rui #define PREFIX "ACPI: " 141c8fce27SZhang Rui 151c8fce27SZhang Rui #ifdef CONFIG_ACPI_DEBUG 161c8fce27SZhang Rui /* 171c8fce27SZhang Rui * ACPI debug sysfs I/F, including: 181c8fce27SZhang Rui * /sys/modules/acpi/parameters/debug_layer 191c8fce27SZhang Rui * /sys/modules/acpi/parameters/debug_level 201c8fce27SZhang Rui * /sys/modules/acpi/parameters/trace_method_name 211c8fce27SZhang Rui * /sys/modules/acpi/parameters/trace_state 221c8fce27SZhang Rui * /sys/modules/acpi/parameters/trace_debug_layer 231c8fce27SZhang Rui * /sys/modules/acpi/parameters/trace_debug_level 241c8fce27SZhang Rui */ 251c8fce27SZhang Rui 261c8fce27SZhang Rui struct acpi_dlayer { 271c8fce27SZhang Rui const char *name; 281c8fce27SZhang Rui unsigned long value; 291c8fce27SZhang Rui }; 301c8fce27SZhang Rui struct acpi_dlevel { 311c8fce27SZhang Rui const char *name; 321c8fce27SZhang Rui unsigned long value; 331c8fce27SZhang Rui }; 341c8fce27SZhang Rui #define ACPI_DEBUG_INIT(v) { .name = #v, .value = v } 351c8fce27SZhang Rui 361c8fce27SZhang Rui static const struct acpi_dlayer acpi_debug_layers[] = { 371c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_UTILITIES), 381c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_HARDWARE), 391c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_EVENTS), 401c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_TABLES), 411c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_NAMESPACE), 421c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_PARSER), 431c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_DISPATCHER), 441c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_EXECUTER), 451c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_RESOURCES), 461c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_CA_DEBUGGER), 471c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_OS_SERVICES), 481c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_CA_DISASSEMBLER), 491c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_COMPILER), 501c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_TOOLS), 511c8fce27SZhang Rui 521c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_BUS_COMPONENT), 531c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_AC_COMPONENT), 541c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_BATTERY_COMPONENT), 551c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_BUTTON_COMPONENT), 561c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_SBS_COMPONENT), 571c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_FAN_COMPONENT), 581c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_PCI_COMPONENT), 591c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_POWER_COMPONENT), 601c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_CONTAINER_COMPONENT), 611c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_SYSTEM_COMPONENT), 621c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_THERMAL_COMPONENT), 631c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_MEMORY_DEVICE_COMPONENT), 641c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_VIDEO_COMPONENT), 651c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_PROCESSOR_COMPONENT), 661c8fce27SZhang Rui }; 671c8fce27SZhang Rui 681c8fce27SZhang Rui static const struct acpi_dlevel acpi_debug_levels[] = { 691c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_INIT), 701c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT), 711c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_INFO), 721c8fce27SZhang Rui 731c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_INIT_NAMES), 741c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_PARSE), 751c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_LOAD), 761c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_DISPATCH), 771c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_EXEC), 781c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_NAMES), 791c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_OPREGION), 801c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_BFIELD), 811c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_TABLES), 821c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_VALUES), 831c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_OBJECTS), 841c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_RESOURCES), 851c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_USER_REQUESTS), 861c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_PACKAGE), 871c8fce27SZhang Rui 881c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_ALLOCATIONS), 891c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_FUNCTIONS), 901c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_OPTIMIZATIONS), 911c8fce27SZhang Rui 921c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_MUTEX), 931c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_THREADS), 941c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_IO), 951c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_INTERRUPTS), 961c8fce27SZhang Rui 971c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_AML_DISASSEMBLE), 981c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_VERBOSE_INFO), 991c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_FULL_TABLES), 1001c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_EVENTS), 1011c8fce27SZhang Rui }; 1021c8fce27SZhang Rui 103ec652b35SZhang Rui static int param_get_debug_layer(char *buffer, const struct kernel_param *kp) 1041c8fce27SZhang Rui { 1051c8fce27SZhang Rui int result = 0; 1061c8fce27SZhang Rui int i; 1071c8fce27SZhang Rui 1081c8fce27SZhang Rui result = sprintf(buffer, "%-25s\tHex SET\n", "Description"); 1091c8fce27SZhang Rui 1101c8fce27SZhang Rui for (i = 0; i < ARRAY_SIZE(acpi_debug_layers); i++) { 1111c8fce27SZhang Rui result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n", 1121c8fce27SZhang Rui acpi_debug_layers[i].name, 1131c8fce27SZhang Rui acpi_debug_layers[i].value, 1141c8fce27SZhang Rui (acpi_dbg_layer & acpi_debug_layers[i].value) 1151c8fce27SZhang Rui ? '*' : ' '); 1161c8fce27SZhang Rui } 1171c8fce27SZhang Rui result += 1181c8fce27SZhang Rui sprintf(buffer + result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS", 1191c8fce27SZhang Rui ACPI_ALL_DRIVERS, 1201c8fce27SZhang Rui (acpi_dbg_layer & ACPI_ALL_DRIVERS) == 1211c8fce27SZhang Rui ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS) 1221c8fce27SZhang Rui == 0 ? ' ' : '-'); 1231c8fce27SZhang Rui result += 1241c8fce27SZhang Rui sprintf(buffer + result, 1251c8fce27SZhang Rui "--\ndebug_layer = 0x%08X ( * = enabled)\n", 1261c8fce27SZhang Rui acpi_dbg_layer); 1271c8fce27SZhang Rui 1281c8fce27SZhang Rui return result; 1291c8fce27SZhang Rui } 1301c8fce27SZhang Rui 131ec652b35SZhang Rui static int param_get_debug_level(char *buffer, const struct kernel_param *kp) 1321c8fce27SZhang Rui { 1331c8fce27SZhang Rui int result = 0; 1341c8fce27SZhang Rui int i; 1351c8fce27SZhang Rui 1361c8fce27SZhang Rui result = sprintf(buffer, "%-25s\tHex SET\n", "Description"); 1371c8fce27SZhang Rui 1381c8fce27SZhang Rui for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) { 1391c8fce27SZhang Rui result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n", 1401c8fce27SZhang Rui acpi_debug_levels[i].name, 1411c8fce27SZhang Rui acpi_debug_levels[i].value, 1421c8fce27SZhang Rui (acpi_dbg_level & acpi_debug_levels[i].value) 1431c8fce27SZhang Rui ? '*' : ' '); 1441c8fce27SZhang Rui } 1451c8fce27SZhang Rui result += 1461c8fce27SZhang Rui sprintf(buffer + result, "--\ndebug_level = 0x%08X (* = enabled)\n", 1471c8fce27SZhang Rui acpi_dbg_level); 1481c8fce27SZhang Rui 1491c8fce27SZhang Rui return result; 1501c8fce27SZhang Rui } 1511c8fce27SZhang Rui 1529c8b04beSVasiliy Kulikov static const struct kernel_param_ops param_ops_debug_layer = { 153ec652b35SZhang Rui .set = param_set_uint, 154ec652b35SZhang Rui .get = param_get_debug_layer, 155ec652b35SZhang Rui }; 156ec652b35SZhang Rui 1579c8b04beSVasiliy Kulikov static const struct kernel_param_ops param_ops_debug_level = { 158ec652b35SZhang Rui .set = param_set_uint, 159ec652b35SZhang Rui .get = param_get_debug_level, 160ec652b35SZhang Rui }; 161ec652b35SZhang Rui 162ec652b35SZhang Rui module_param_cb(debug_layer, ¶m_ops_debug_layer, &acpi_dbg_layer, 0644); 163ec652b35SZhang Rui module_param_cb(debug_level, ¶m_ops_debug_level, &acpi_dbg_level, 0644); 1641c8fce27SZhang Rui 1651c8fce27SZhang Rui static char trace_method_name[6]; 1661c8fce27SZhang Rui module_param_string(trace_method_name, trace_method_name, 6, 0644); 1671c8fce27SZhang Rui static unsigned int trace_debug_layer; 1681c8fce27SZhang Rui module_param(trace_debug_layer, uint, 0644); 1691c8fce27SZhang Rui static unsigned int trace_debug_level; 1701c8fce27SZhang Rui module_param(trace_debug_level, uint, 0644); 1711c8fce27SZhang Rui 1721c8fce27SZhang Rui static int param_set_trace_state(const char *val, struct kernel_param *kp) 1731c8fce27SZhang Rui { 1741c8fce27SZhang Rui int result = 0; 1751c8fce27SZhang Rui 176869639f9SLen Brown if (!strncmp(val, "enable", sizeof("enable") - 1)) { 1771c8fce27SZhang Rui result = acpi_debug_trace(trace_method_name, trace_debug_level, 1781c8fce27SZhang Rui trace_debug_layer, 0); 1791c8fce27SZhang Rui if (result) 1801c8fce27SZhang Rui result = -EBUSY; 1811c8fce27SZhang Rui goto exit; 1821c8fce27SZhang Rui } 1831c8fce27SZhang Rui 184869639f9SLen Brown if (!strncmp(val, "disable", sizeof("disable") - 1)) { 1851c8fce27SZhang Rui int name = 0; 1861c8fce27SZhang Rui result = acpi_debug_trace((char *)&name, trace_debug_level, 1871c8fce27SZhang Rui trace_debug_layer, 0); 1881c8fce27SZhang Rui if (result) 1891c8fce27SZhang Rui result = -EBUSY; 1901c8fce27SZhang Rui goto exit; 1911c8fce27SZhang Rui } 1921c8fce27SZhang Rui 1931c8fce27SZhang Rui if (!strncmp(val, "1", 1)) { 1941c8fce27SZhang Rui result = acpi_debug_trace(trace_method_name, trace_debug_level, 1951c8fce27SZhang Rui trace_debug_layer, 1); 1961c8fce27SZhang Rui if (result) 1971c8fce27SZhang Rui result = -EBUSY; 1981c8fce27SZhang Rui goto exit; 1991c8fce27SZhang Rui } 2001c8fce27SZhang Rui 2011c8fce27SZhang Rui result = -EINVAL; 2021c8fce27SZhang Rui exit: 2031c8fce27SZhang Rui return result; 2041c8fce27SZhang Rui } 2051c8fce27SZhang Rui 2061c8fce27SZhang Rui static int param_get_trace_state(char *buffer, struct kernel_param *kp) 2071c8fce27SZhang Rui { 2081c8fce27SZhang Rui if (!acpi_gbl_trace_method_name) 2091c8fce27SZhang Rui return sprintf(buffer, "disable"); 2101c8fce27SZhang Rui else { 2111c8fce27SZhang Rui if (acpi_gbl_trace_flags & 1) 2121c8fce27SZhang Rui return sprintf(buffer, "1"); 2131c8fce27SZhang Rui else 2141c8fce27SZhang Rui return sprintf(buffer, "enable"); 2151c8fce27SZhang Rui } 2161c8fce27SZhang Rui return 0; 2171c8fce27SZhang Rui } 2181c8fce27SZhang Rui 2191c8fce27SZhang Rui module_param_call(trace_state, param_set_trace_state, param_get_trace_state, 2201c8fce27SZhang Rui NULL, 0644); 2211c8fce27SZhang Rui #endif /* CONFIG_ACPI_DEBUG */ 2221c8fce27SZhang Rui 223aecad432SThomas Renninger 224aecad432SThomas Renninger /* /sys/modules/acpi/parameters/aml_debug_output */ 225aecad432SThomas Renninger 226aecad432SThomas Renninger module_param_named(aml_debug_output, acpi_gbl_enable_aml_debug_object, 227aecad432SThomas Renninger bool, 0644); 228aecad432SThomas Renninger MODULE_PARM_DESC(aml_debug_output, 229aecad432SThomas Renninger "To enable/disable the ACPI Debug Object output."); 230aecad432SThomas Renninger 2311c8fce27SZhang Rui /* /sys/module/acpi/parameters/acpica_version */ 2321c8fce27SZhang Rui static int param_get_acpica_version(char *buffer, struct kernel_param *kp) 2331c8fce27SZhang Rui { 2341c8fce27SZhang Rui int result; 2351c8fce27SZhang Rui 2361c8fce27SZhang Rui result = sprintf(buffer, "%x", ACPI_CA_VERSION); 2371c8fce27SZhang Rui 2381c8fce27SZhang Rui return result; 2391c8fce27SZhang Rui } 2401c8fce27SZhang Rui 2411c8fce27SZhang Rui module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); 2421c8fce27SZhang Rui 2431c8fce27SZhang Rui /* 2441c8fce27SZhang Rui * ACPI table sysfs I/F: 2451c8fce27SZhang Rui * /sys/firmware/acpi/tables/ 2461c8fce27SZhang Rui * /sys/firmware/acpi/tables/dynamic/ 2471c8fce27SZhang Rui */ 2481c8fce27SZhang Rui 2491c8fce27SZhang Rui static LIST_HEAD(acpi_table_attr_list); 2501c8fce27SZhang Rui static struct kobject *tables_kobj; 2511c8fce27SZhang Rui static struct kobject *dynamic_tables_kobj; 2521c8fce27SZhang Rui 2531c8fce27SZhang Rui struct acpi_table_attr { 2541c8fce27SZhang Rui struct bin_attribute attr; 2551c8fce27SZhang Rui char name[8]; 2561c8fce27SZhang Rui int instance; 2571c8fce27SZhang Rui struct list_head node; 2581c8fce27SZhang Rui }; 2591c8fce27SZhang Rui 2601c8fce27SZhang Rui static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj, 2611c8fce27SZhang Rui struct bin_attribute *bin_attr, char *buf, 2621c8fce27SZhang Rui loff_t offset, size_t count) 2631c8fce27SZhang Rui { 2641c8fce27SZhang Rui struct acpi_table_attr *table_attr = 2651c8fce27SZhang Rui container_of(bin_attr, struct acpi_table_attr, attr); 2661c8fce27SZhang Rui struct acpi_table_header *table_header = NULL; 2671c8fce27SZhang Rui acpi_status status; 2681c8fce27SZhang Rui char name[ACPI_NAME_SIZE]; 2691c8fce27SZhang Rui 2701c8fce27SZhang Rui if (strncmp(table_attr->name, "NULL", 4)) 2711c8fce27SZhang Rui memcpy(name, table_attr->name, ACPI_NAME_SIZE); 2721c8fce27SZhang Rui else 2731c8fce27SZhang Rui memcpy(name, "\0\0\0\0", 4); 2741c8fce27SZhang Rui 2751c8fce27SZhang Rui status = acpi_get_table(name, table_attr->instance, &table_header); 2761c8fce27SZhang Rui if (ACPI_FAILURE(status)) 2771c8fce27SZhang Rui return -ENODEV; 2781c8fce27SZhang Rui 2791c8fce27SZhang Rui return memory_read_from_buffer(buf, count, &offset, 2801c8fce27SZhang Rui table_header, table_header->length); 2811c8fce27SZhang Rui } 2821c8fce27SZhang Rui 2831c8fce27SZhang Rui static void acpi_table_attr_init(struct acpi_table_attr *table_attr, 2841c8fce27SZhang Rui struct acpi_table_header *table_header) 2851c8fce27SZhang Rui { 2861c8fce27SZhang Rui struct acpi_table_header *header = NULL; 2871c8fce27SZhang Rui struct acpi_table_attr *attr = NULL; 2881c8fce27SZhang Rui 2891c8fce27SZhang Rui sysfs_attr_init(&table_attr->attr.attr); 2901c8fce27SZhang Rui if (table_header->signature[0] != '\0') 2911c8fce27SZhang Rui memcpy(table_attr->name, table_header->signature, 2921c8fce27SZhang Rui ACPI_NAME_SIZE); 2931c8fce27SZhang Rui else 2941c8fce27SZhang Rui memcpy(table_attr->name, "NULL", 4); 2951c8fce27SZhang Rui 2961c8fce27SZhang Rui list_for_each_entry(attr, &acpi_table_attr_list, node) { 2971c8fce27SZhang Rui if (!memcmp(table_attr->name, attr->name, ACPI_NAME_SIZE)) 2981c8fce27SZhang Rui if (table_attr->instance < attr->instance) 2991c8fce27SZhang Rui table_attr->instance = attr->instance; 3001c8fce27SZhang Rui } 3011c8fce27SZhang Rui table_attr->instance++; 3021c8fce27SZhang Rui 3031c8fce27SZhang Rui if (table_attr->instance > 1 || (table_attr->instance == 1 && 3041c8fce27SZhang Rui !acpi_get_table 3051c8fce27SZhang Rui (table_header->signature, 2, &header))) 3061c8fce27SZhang Rui sprintf(table_attr->name + ACPI_NAME_SIZE, "%d", 3071c8fce27SZhang Rui table_attr->instance); 3081c8fce27SZhang Rui 3091c8fce27SZhang Rui table_attr->attr.size = 0; 3101c8fce27SZhang Rui table_attr->attr.read = acpi_table_show; 3111c8fce27SZhang Rui table_attr->attr.attr.name = table_attr->name; 3121c8fce27SZhang Rui table_attr->attr.attr.mode = 0400; 3131c8fce27SZhang Rui 3141c8fce27SZhang Rui return; 3151c8fce27SZhang Rui } 3161c8fce27SZhang Rui 3171c8fce27SZhang Rui static acpi_status 3181c8fce27SZhang Rui acpi_sysfs_table_handler(u32 event, void *table, void *context) 3191c8fce27SZhang Rui { 3201c8fce27SZhang Rui struct acpi_table_attr *table_attr; 3211c8fce27SZhang Rui 3221c8fce27SZhang Rui switch (event) { 3231c8fce27SZhang Rui case ACPI_TABLE_EVENT_LOAD: 3241c8fce27SZhang Rui table_attr = 3251c8fce27SZhang Rui kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL); 3261c8fce27SZhang Rui if (!table_attr) 3271c8fce27SZhang Rui return AE_NO_MEMORY; 3281c8fce27SZhang Rui 3291c8fce27SZhang Rui acpi_table_attr_init(table_attr, table); 3301c8fce27SZhang Rui if (sysfs_create_bin_file(dynamic_tables_kobj, 3311c8fce27SZhang Rui &table_attr->attr)) { 3321c8fce27SZhang Rui kfree(table_attr); 3331c8fce27SZhang Rui return AE_ERROR; 3341c8fce27SZhang Rui } else 3351c8fce27SZhang Rui list_add_tail(&table_attr->node, &acpi_table_attr_list); 3361c8fce27SZhang Rui break; 3371c8fce27SZhang Rui case ACPI_TABLE_EVENT_UNLOAD: 3381c8fce27SZhang Rui /* 3391c8fce27SZhang Rui * we do not need to do anything right now 3401c8fce27SZhang Rui * because the table is not deleted from the 3411c8fce27SZhang Rui * global table list when unloading it. 3421c8fce27SZhang Rui */ 3431c8fce27SZhang Rui break; 3441c8fce27SZhang Rui default: 3451c8fce27SZhang Rui return AE_BAD_PARAMETER; 3461c8fce27SZhang Rui } 3471c8fce27SZhang Rui return AE_OK; 3481c8fce27SZhang Rui } 3491c8fce27SZhang Rui 3501c8fce27SZhang Rui static int acpi_tables_sysfs_init(void) 3511c8fce27SZhang Rui { 3521c8fce27SZhang Rui struct acpi_table_attr *table_attr; 3531c8fce27SZhang Rui struct acpi_table_header *table_header = NULL; 3541c8fce27SZhang Rui int table_index = 0; 3551c8fce27SZhang Rui int result; 3561c8fce27SZhang Rui 3571c8fce27SZhang Rui tables_kobj = kobject_create_and_add("tables", acpi_kobj); 3581c8fce27SZhang Rui if (!tables_kobj) 3591c8fce27SZhang Rui goto err; 3601c8fce27SZhang Rui 3611c8fce27SZhang Rui dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj); 3621c8fce27SZhang Rui if (!dynamic_tables_kobj) 3631c8fce27SZhang Rui goto err_dynamic_tables; 3641c8fce27SZhang Rui 3651c8fce27SZhang Rui do { 3661c8fce27SZhang Rui result = acpi_get_table_by_index(table_index, &table_header); 3671c8fce27SZhang Rui if (!result) { 3681c8fce27SZhang Rui table_index++; 3691c8fce27SZhang Rui table_attr = NULL; 3701c8fce27SZhang Rui table_attr = 3711c8fce27SZhang Rui kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL); 3721c8fce27SZhang Rui if (!table_attr) 3731c8fce27SZhang Rui return -ENOMEM; 3741c8fce27SZhang Rui 3751c8fce27SZhang Rui acpi_table_attr_init(table_attr, table_header); 3761c8fce27SZhang Rui result = 3771c8fce27SZhang Rui sysfs_create_bin_file(tables_kobj, 3781c8fce27SZhang Rui &table_attr->attr); 3791c8fce27SZhang Rui if (result) { 3801c8fce27SZhang Rui kfree(table_attr); 3811c8fce27SZhang Rui return result; 3821c8fce27SZhang Rui } else 3831c8fce27SZhang Rui list_add_tail(&table_attr->node, 3841c8fce27SZhang Rui &acpi_table_attr_list); 3851c8fce27SZhang Rui } 3861c8fce27SZhang Rui } while (!result); 3871c8fce27SZhang Rui kobject_uevent(tables_kobj, KOBJ_ADD); 3881c8fce27SZhang Rui kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); 3891c8fce27SZhang Rui result = acpi_install_table_handler(acpi_sysfs_table_handler, NULL); 3901c8fce27SZhang Rui 3911c8fce27SZhang Rui return result == AE_OK ? 0 : -EINVAL; 3921c8fce27SZhang Rui err_dynamic_tables: 3931c8fce27SZhang Rui kobject_put(tables_kobj); 3941c8fce27SZhang Rui err: 3951c8fce27SZhang Rui return -ENOMEM; 3961c8fce27SZhang Rui } 3971c8fce27SZhang Rui 3981c8fce27SZhang Rui /* 3991c8fce27SZhang Rui * Detailed ACPI IRQ counters: 4001c8fce27SZhang Rui * /sys/firmware/acpi/interrupts/ 4011c8fce27SZhang Rui */ 4021c8fce27SZhang Rui 4031c8fce27SZhang Rui u32 acpi_irq_handled; 4041c8fce27SZhang Rui u32 acpi_irq_not_handled; 4051c8fce27SZhang Rui 4061c8fce27SZhang Rui #define COUNT_GPE 0 4071c8fce27SZhang Rui #define COUNT_SCI 1 /* acpi_irq_handled */ 4081c8fce27SZhang Rui #define COUNT_SCI_NOT 2 /* acpi_irq_not_handled */ 4091c8fce27SZhang Rui #define COUNT_ERROR 3 /* other */ 4101c8fce27SZhang Rui #define NUM_COUNTERS_EXTRA 4 4111c8fce27SZhang Rui 4121c8fce27SZhang Rui struct event_counter { 4131c8fce27SZhang Rui u32 count; 4141c8fce27SZhang Rui u32 flags; 4151c8fce27SZhang Rui }; 4161c8fce27SZhang Rui 4171c8fce27SZhang Rui static struct event_counter *all_counters; 4181c8fce27SZhang Rui static u32 num_gpes; 4191c8fce27SZhang Rui static u32 num_counters; 4201c8fce27SZhang Rui static struct attribute **all_attrs; 4211c8fce27SZhang Rui static u32 acpi_gpe_count; 4221c8fce27SZhang Rui 4231c8fce27SZhang Rui static struct attribute_group interrupt_stats_attr_group = { 4241c8fce27SZhang Rui .name = "interrupts", 4251c8fce27SZhang Rui }; 4261c8fce27SZhang Rui 4271c8fce27SZhang Rui static struct kobj_attribute *counter_attrs; 4281c8fce27SZhang Rui 4291c8fce27SZhang Rui static void delete_gpe_attr_array(void) 4301c8fce27SZhang Rui { 4311c8fce27SZhang Rui struct event_counter *tmp = all_counters; 4321c8fce27SZhang Rui 4331c8fce27SZhang Rui all_counters = NULL; 4341c8fce27SZhang Rui kfree(tmp); 4351c8fce27SZhang Rui 4361c8fce27SZhang Rui if (counter_attrs) { 4371c8fce27SZhang Rui int i; 4381c8fce27SZhang Rui 4391c8fce27SZhang Rui for (i = 0; i < num_gpes; i++) 4401c8fce27SZhang Rui kfree(counter_attrs[i].attr.name); 4411c8fce27SZhang Rui 4421c8fce27SZhang Rui kfree(counter_attrs); 4431c8fce27SZhang Rui } 4441c8fce27SZhang Rui kfree(all_attrs); 4451c8fce27SZhang Rui 4461c8fce27SZhang Rui return; 4471c8fce27SZhang Rui } 4481c8fce27SZhang Rui 449a0fcdb23SLin Ming static void gpe_count(u32 gpe_number) 4501c8fce27SZhang Rui { 4511c8fce27SZhang Rui acpi_gpe_count++; 4521c8fce27SZhang Rui 4531c8fce27SZhang Rui if (!all_counters) 4541c8fce27SZhang Rui return; 4551c8fce27SZhang Rui 4561c8fce27SZhang Rui if (gpe_number < num_gpes) 4571c8fce27SZhang Rui all_counters[gpe_number].count++; 4581c8fce27SZhang Rui else 4591c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + 4601c8fce27SZhang Rui COUNT_ERROR].count++; 4611c8fce27SZhang Rui 4621c8fce27SZhang Rui return; 4631c8fce27SZhang Rui } 4641c8fce27SZhang Rui 465a0fcdb23SLin Ming static void fixed_event_count(u32 event_number) 4661c8fce27SZhang Rui { 4671c8fce27SZhang Rui if (!all_counters) 4681c8fce27SZhang Rui return; 4691c8fce27SZhang Rui 4701c8fce27SZhang Rui if (event_number < ACPI_NUM_FIXED_EVENTS) 4711c8fce27SZhang Rui all_counters[num_gpes + event_number].count++; 4721c8fce27SZhang Rui else 4731c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + 4741c8fce27SZhang Rui COUNT_ERROR].count++; 4751c8fce27SZhang Rui 4761c8fce27SZhang Rui return; 4771c8fce27SZhang Rui } 4781c8fce27SZhang Rui 479644ef74eSLv Zheng static void acpi_global_event_handler(u32 event_type, acpi_handle device, 480a0fcdb23SLin Ming u32 event_number, void *context) 481a0fcdb23SLin Ming { 482a0fcdb23SLin Ming if (event_type == ACPI_EVENT_TYPE_GPE) 483a0fcdb23SLin Ming gpe_count(event_number); 484a0fcdb23SLin Ming 485a0fcdb23SLin Ming if (event_type == ACPI_EVENT_TYPE_FIXED) 486a0fcdb23SLin Ming fixed_event_count(event_number); 487a0fcdb23SLin Ming } 488a0fcdb23SLin Ming 4891c8fce27SZhang Rui static int get_status(u32 index, acpi_event_status *status, 4901c8fce27SZhang Rui acpi_handle *handle) 4911c8fce27SZhang Rui { 4921c8fce27SZhang Rui int result = 0; 4931c8fce27SZhang Rui 4941c8fce27SZhang Rui if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS) 4951c8fce27SZhang Rui goto end; 4961c8fce27SZhang Rui 4971c8fce27SZhang Rui if (index < num_gpes) { 4981c8fce27SZhang Rui result = acpi_get_gpe_device(index, handle); 4991c8fce27SZhang Rui if (result) { 5001c8fce27SZhang Rui ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND, 501c6284237SColin Ian King "Invalid GPE 0x%x", index)); 5021c8fce27SZhang Rui goto end; 5031c8fce27SZhang Rui } 5041c8fce27SZhang Rui result = acpi_get_gpe_status(*handle, index, status); 5051c8fce27SZhang Rui } else if (index < (num_gpes + ACPI_NUM_FIXED_EVENTS)) 5061c8fce27SZhang Rui result = acpi_get_event_status(index - num_gpes, status); 5071c8fce27SZhang Rui 5081c8fce27SZhang Rui end: 5091c8fce27SZhang Rui return result; 5101c8fce27SZhang Rui } 5111c8fce27SZhang Rui 5121c8fce27SZhang Rui static ssize_t counter_show(struct kobject *kobj, 5131c8fce27SZhang Rui struct kobj_attribute *attr, char *buf) 5141c8fce27SZhang Rui { 5151c8fce27SZhang Rui int index = attr - counter_attrs; 5161c8fce27SZhang Rui int size; 5171c8fce27SZhang Rui acpi_handle handle; 5181c8fce27SZhang Rui acpi_event_status status; 5191c8fce27SZhang Rui int result = 0; 5201c8fce27SZhang Rui 5211c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI].count = 5221c8fce27SZhang Rui acpi_irq_handled; 5231c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI_NOT].count = 5241c8fce27SZhang Rui acpi_irq_not_handled; 5251c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE].count = 5261c8fce27SZhang Rui acpi_gpe_count; 5271c8fce27SZhang Rui size = sprintf(buf, "%8d", all_counters[index].count); 5281c8fce27SZhang Rui 5291c8fce27SZhang Rui /* "gpe_all" or "sci" */ 5301c8fce27SZhang Rui if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS) 5311c8fce27SZhang Rui goto end; 5321c8fce27SZhang Rui 5331c8fce27SZhang Rui result = get_status(index, &status, &handle); 5341c8fce27SZhang Rui if (result) 5351c8fce27SZhang Rui goto end; 5361c8fce27SZhang Rui 5371c8fce27SZhang Rui if (!(status & ACPI_EVENT_FLAG_HANDLE)) 5381c8fce27SZhang Rui size += sprintf(buf + size, " invalid"); 5391c8fce27SZhang Rui else if (status & ACPI_EVENT_FLAG_ENABLED) 5401c8fce27SZhang Rui size += sprintf(buf + size, " enabled"); 5411c8fce27SZhang Rui else if (status & ACPI_EVENT_FLAG_WAKE_ENABLED) 5421c8fce27SZhang Rui size += sprintf(buf + size, " wake_enabled"); 5431c8fce27SZhang Rui else 5441c8fce27SZhang Rui size += sprintf(buf + size, " disabled"); 5451c8fce27SZhang Rui 5461c8fce27SZhang Rui end: 5471c8fce27SZhang Rui size += sprintf(buf + size, "\n"); 5481c8fce27SZhang Rui return result ? result : size; 5491c8fce27SZhang Rui } 5501c8fce27SZhang Rui 5511c8fce27SZhang Rui /* 5521c8fce27SZhang Rui * counter_set() sets the specified counter. 5531c8fce27SZhang Rui * setting the total "sci" file to any value clears all counters. 5541c8fce27SZhang Rui * enable/disable/clear a gpe/fixed event in user space. 5551c8fce27SZhang Rui */ 5561c8fce27SZhang Rui static ssize_t counter_set(struct kobject *kobj, 5571c8fce27SZhang Rui struct kobj_attribute *attr, const char *buf, 5581c8fce27SZhang Rui size_t size) 5591c8fce27SZhang Rui { 5601c8fce27SZhang Rui int index = attr - counter_attrs; 5611c8fce27SZhang Rui acpi_event_status status; 5621c8fce27SZhang Rui acpi_handle handle; 5631c8fce27SZhang Rui int result = 0; 5641c8fce27SZhang Rui 5651c8fce27SZhang Rui if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) { 5661c8fce27SZhang Rui int i; 5671c8fce27SZhang Rui for (i = 0; i < num_counters; ++i) 5681c8fce27SZhang Rui all_counters[i].count = 0; 5691c8fce27SZhang Rui acpi_gpe_count = 0; 5701c8fce27SZhang Rui acpi_irq_handled = 0; 5711c8fce27SZhang Rui acpi_irq_not_handled = 0; 5721c8fce27SZhang Rui goto end; 5731c8fce27SZhang Rui } 5741c8fce27SZhang Rui 5751c8fce27SZhang Rui /* show the event status for both GPEs and Fixed Events */ 5761c8fce27SZhang Rui result = get_status(index, &status, &handle); 5771c8fce27SZhang Rui if (result) 5781c8fce27SZhang Rui goto end; 5791c8fce27SZhang Rui 5801c8fce27SZhang Rui if (!(status & ACPI_EVENT_FLAG_HANDLE)) { 5811c8fce27SZhang Rui printk(KERN_WARNING PREFIX 5821c8fce27SZhang Rui "Can not change Invalid GPE/Fixed Event status\n"); 5831c8fce27SZhang Rui return -EINVAL; 5841c8fce27SZhang Rui } 5851c8fce27SZhang Rui 5861c8fce27SZhang Rui if (index < num_gpes) { 5871c8fce27SZhang Rui if (!strcmp(buf, "disable\n") && 5881c8fce27SZhang Rui (status & ACPI_EVENT_FLAG_ENABLED)) 5891c8fce27SZhang Rui result = acpi_disable_gpe(handle, index); 5901c8fce27SZhang Rui else if (!strcmp(buf, "enable\n") && 5911c8fce27SZhang Rui !(status & ACPI_EVENT_FLAG_ENABLED)) 5921c8fce27SZhang Rui result = acpi_enable_gpe(handle, index); 5931c8fce27SZhang Rui else if (!strcmp(buf, "clear\n") && 5941c8fce27SZhang Rui (status & ACPI_EVENT_FLAG_SET)) 5951c8fce27SZhang Rui result = acpi_clear_gpe(handle, index); 5961c8fce27SZhang Rui else 5971c8fce27SZhang Rui all_counters[index].count = strtoul(buf, NULL, 0); 5981c8fce27SZhang Rui } else if (index < num_gpes + ACPI_NUM_FIXED_EVENTS) { 5991c8fce27SZhang Rui int event = index - num_gpes; 6001c8fce27SZhang Rui if (!strcmp(buf, "disable\n") && 6011c8fce27SZhang Rui (status & ACPI_EVENT_FLAG_ENABLED)) 6021c8fce27SZhang Rui result = acpi_disable_event(event, ACPI_NOT_ISR); 6031c8fce27SZhang Rui else if (!strcmp(buf, "enable\n") && 6041c8fce27SZhang Rui !(status & ACPI_EVENT_FLAG_ENABLED)) 6051c8fce27SZhang Rui result = acpi_enable_event(event, ACPI_NOT_ISR); 6061c8fce27SZhang Rui else if (!strcmp(buf, "clear\n") && 6071c8fce27SZhang Rui (status & ACPI_EVENT_FLAG_SET)) 6081c8fce27SZhang Rui result = acpi_clear_event(event); 6091c8fce27SZhang Rui else 6101c8fce27SZhang Rui all_counters[index].count = strtoul(buf, NULL, 0); 6111c8fce27SZhang Rui } else 6121c8fce27SZhang Rui all_counters[index].count = strtoul(buf, NULL, 0); 6131c8fce27SZhang Rui 6141c8fce27SZhang Rui if (ACPI_FAILURE(result)) 6151c8fce27SZhang Rui result = -EINVAL; 6161c8fce27SZhang Rui end: 6171c8fce27SZhang Rui return result ? result : size; 6181c8fce27SZhang Rui } 6191c8fce27SZhang Rui 6201c8fce27SZhang Rui void acpi_irq_stats_init(void) 6211c8fce27SZhang Rui { 622a0fcdb23SLin Ming acpi_status status; 6231c8fce27SZhang Rui int i; 6241c8fce27SZhang Rui 6251c8fce27SZhang Rui if (all_counters) 6261c8fce27SZhang Rui return; 6271c8fce27SZhang Rui 6281c8fce27SZhang Rui num_gpes = acpi_current_gpe_count; 6291c8fce27SZhang Rui num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA; 6301c8fce27SZhang Rui 6311c8fce27SZhang Rui all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1), 6321c8fce27SZhang Rui GFP_KERNEL); 6331c8fce27SZhang Rui if (all_attrs == NULL) 6341c8fce27SZhang Rui return; 6351c8fce27SZhang Rui 6361c8fce27SZhang Rui all_counters = kzalloc(sizeof(struct event_counter) * (num_counters), 6371c8fce27SZhang Rui GFP_KERNEL); 6381c8fce27SZhang Rui if (all_counters == NULL) 6391c8fce27SZhang Rui goto fail; 6401c8fce27SZhang Rui 641644ef74eSLv Zheng status = acpi_install_global_event_handler(acpi_global_event_handler, NULL); 642a0fcdb23SLin Ming if (ACPI_FAILURE(status)) 643a0fcdb23SLin Ming goto fail; 644a0fcdb23SLin Ming 6451c8fce27SZhang Rui counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters), 6461c8fce27SZhang Rui GFP_KERNEL); 6471c8fce27SZhang Rui if (counter_attrs == NULL) 6481c8fce27SZhang Rui goto fail; 6491c8fce27SZhang Rui 6501c8fce27SZhang Rui for (i = 0; i < num_counters; ++i) { 6511c8fce27SZhang Rui char buffer[12]; 6521c8fce27SZhang Rui char *name; 6531c8fce27SZhang Rui 6541c8fce27SZhang Rui if (i < num_gpes) 6551c8fce27SZhang Rui sprintf(buffer, "gpe%02X", i); 6561c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_PMTIMER) 6571c8fce27SZhang Rui sprintf(buffer, "ff_pmtimer"); 6581c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_GLOBAL) 6591c8fce27SZhang Rui sprintf(buffer, "ff_gbl_lock"); 6601c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_POWER_BUTTON) 6611c8fce27SZhang Rui sprintf(buffer, "ff_pwr_btn"); 6621c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_SLEEP_BUTTON) 6631c8fce27SZhang Rui sprintf(buffer, "ff_slp_btn"); 6641c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_RTC) 6651c8fce27SZhang Rui sprintf(buffer, "ff_rt_clk"); 6661c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE) 6671c8fce27SZhang Rui sprintf(buffer, "gpe_all"); 6681c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) 6691c8fce27SZhang Rui sprintf(buffer, "sci"); 6701c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI_NOT) 6711c8fce27SZhang Rui sprintf(buffer, "sci_not"); 6721c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR) 6731c8fce27SZhang Rui sprintf(buffer, "error"); 6741c8fce27SZhang Rui else 6751c8fce27SZhang Rui sprintf(buffer, "bug%02X", i); 6761c8fce27SZhang Rui 6771c8fce27SZhang Rui name = kzalloc(strlen(buffer) + 1, GFP_KERNEL); 6781c8fce27SZhang Rui if (name == NULL) 6791c8fce27SZhang Rui goto fail; 6801c8fce27SZhang Rui strncpy(name, buffer, strlen(buffer) + 1); 6811c8fce27SZhang Rui 6821c8fce27SZhang Rui sysfs_attr_init(&counter_attrs[i].attr); 6831c8fce27SZhang Rui counter_attrs[i].attr.name = name; 6841c8fce27SZhang Rui counter_attrs[i].attr.mode = 0644; 6851c8fce27SZhang Rui counter_attrs[i].show = counter_show; 6861c8fce27SZhang Rui counter_attrs[i].store = counter_set; 6871c8fce27SZhang Rui 6881c8fce27SZhang Rui all_attrs[i] = &counter_attrs[i].attr; 6891c8fce27SZhang Rui } 6901c8fce27SZhang Rui 6911c8fce27SZhang Rui interrupt_stats_attr_group.attrs = all_attrs; 6921c8fce27SZhang Rui if (!sysfs_create_group(acpi_kobj, &interrupt_stats_attr_group)) 6931c8fce27SZhang Rui return; 6941c8fce27SZhang Rui 6951c8fce27SZhang Rui fail: 6961c8fce27SZhang Rui delete_gpe_attr_array(); 6971c8fce27SZhang Rui return; 6981c8fce27SZhang Rui } 6991c8fce27SZhang Rui 7001c8fce27SZhang Rui static void __exit interrupt_stats_exit(void) 7011c8fce27SZhang Rui { 7021c8fce27SZhang Rui sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group); 7031c8fce27SZhang Rui 7041c8fce27SZhang Rui delete_gpe_attr_array(); 7051c8fce27SZhang Rui 7061c8fce27SZhang Rui return; 7071c8fce27SZhang Rui } 7081c8fce27SZhang Rui 709362b6460SThomas Renninger static ssize_t 710362b6460SThomas Renninger acpi_show_profile(struct device *dev, struct device_attribute *attr, 711362b6460SThomas Renninger char *buf) 712362b6460SThomas Renninger { 713362b6460SThomas Renninger return sprintf(buf, "%d\n", acpi_gbl_FADT.preferred_profile); 714362b6460SThomas Renninger } 715362b6460SThomas Renninger 716362b6460SThomas Renninger static const struct device_attribute pm_profile_attr = 717362b6460SThomas Renninger __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL); 718362b6460SThomas Renninger 7191c8fce27SZhang Rui int __init acpi_sysfs_init(void) 7201c8fce27SZhang Rui { 7211c8fce27SZhang Rui int result; 7221c8fce27SZhang Rui 7231c8fce27SZhang Rui result = acpi_tables_sysfs_init(); 724362b6460SThomas Renninger if (result) 725362b6460SThomas Renninger return result; 726362b6460SThomas Renninger result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr); 7271c8fce27SZhang Rui return result; 7281c8fce27SZhang Rui } 729