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> 88b48463fSLv Zheng #include <linux/acpi.h> 91c8fce27SZhang Rui 103f8055c3SRafael J. Wysocki #include "internal.h" 113f8055c3SRafael J. Wysocki 121c8fce27SZhang Rui #define _COMPONENT ACPI_SYSTEM_COMPONENT 131c8fce27SZhang Rui ACPI_MODULE_NAME("sysfs"); 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), 7293d98831SLv Zheng ACPI_DEBUG_INIT(ACPI_LV_REPAIR), 737901a052SLv Zheng ACPI_DEBUG_INIT(ACPI_LV_TRACE_POINT), 741c8fce27SZhang Rui 751c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_INIT_NAMES), 761c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_PARSE), 771c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_LOAD), 781c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_DISPATCH), 791c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_EXEC), 801c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_NAMES), 811c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_OPREGION), 821c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_BFIELD), 831c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_TABLES), 841c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_VALUES), 851c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_OBJECTS), 861c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_RESOURCES), 871c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_USER_REQUESTS), 881c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_PACKAGE), 891c8fce27SZhang Rui 901c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_ALLOCATIONS), 911c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_FUNCTIONS), 921c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_OPTIMIZATIONS), 931c8fce27SZhang Rui 941c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_MUTEX), 951c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_THREADS), 961c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_IO), 971c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_INTERRUPTS), 981c8fce27SZhang Rui 991c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_AML_DISASSEMBLE), 1001c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_VERBOSE_INFO), 1011c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_FULL_TABLES), 1021c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_EVENTS), 1031c8fce27SZhang Rui }; 1041c8fce27SZhang Rui 105ec652b35SZhang Rui static int param_get_debug_layer(char *buffer, const struct kernel_param *kp) 1061c8fce27SZhang Rui { 1071c8fce27SZhang Rui int result = 0; 1081c8fce27SZhang Rui int i; 1091c8fce27SZhang Rui 1101c8fce27SZhang Rui result = sprintf(buffer, "%-25s\tHex SET\n", "Description"); 1111c8fce27SZhang Rui 1121c8fce27SZhang Rui for (i = 0; i < ARRAY_SIZE(acpi_debug_layers); i++) { 1131c8fce27SZhang Rui result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n", 1141c8fce27SZhang Rui acpi_debug_layers[i].name, 1151c8fce27SZhang Rui acpi_debug_layers[i].value, 1161c8fce27SZhang Rui (acpi_dbg_layer & acpi_debug_layers[i].value) 1171c8fce27SZhang Rui ? '*' : ' '); 1181c8fce27SZhang Rui } 1191c8fce27SZhang Rui result += 1201c8fce27SZhang Rui sprintf(buffer + result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS", 1211c8fce27SZhang Rui ACPI_ALL_DRIVERS, 1221c8fce27SZhang Rui (acpi_dbg_layer & ACPI_ALL_DRIVERS) == 1231c8fce27SZhang Rui ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS) 1241c8fce27SZhang Rui == 0 ? ' ' : '-'); 1251c8fce27SZhang Rui result += 1261c8fce27SZhang Rui sprintf(buffer + result, 1271c8fce27SZhang Rui "--\ndebug_layer = 0x%08X ( * = enabled)\n", 1281c8fce27SZhang Rui acpi_dbg_layer); 1291c8fce27SZhang Rui 1301c8fce27SZhang Rui return result; 1311c8fce27SZhang Rui } 1321c8fce27SZhang Rui 133ec652b35SZhang Rui static int param_get_debug_level(char *buffer, const struct kernel_param *kp) 1341c8fce27SZhang Rui { 1351c8fce27SZhang Rui int result = 0; 1361c8fce27SZhang Rui int i; 1371c8fce27SZhang Rui 1381c8fce27SZhang Rui result = sprintf(buffer, "%-25s\tHex SET\n", "Description"); 1391c8fce27SZhang Rui 1401c8fce27SZhang Rui for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) { 1411c8fce27SZhang Rui result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n", 1421c8fce27SZhang Rui acpi_debug_levels[i].name, 1431c8fce27SZhang Rui acpi_debug_levels[i].value, 1441c8fce27SZhang Rui (acpi_dbg_level & acpi_debug_levels[i].value) 1451c8fce27SZhang Rui ? '*' : ' '); 1461c8fce27SZhang Rui } 1471c8fce27SZhang Rui result += 1481c8fce27SZhang Rui sprintf(buffer + result, "--\ndebug_level = 0x%08X (* = enabled)\n", 1491c8fce27SZhang Rui acpi_dbg_level); 1501c8fce27SZhang Rui 1511c8fce27SZhang Rui return result; 1521c8fce27SZhang Rui } 1531c8fce27SZhang Rui 1549c8b04beSVasiliy Kulikov static const struct kernel_param_ops param_ops_debug_layer = { 155ec652b35SZhang Rui .set = param_set_uint, 156ec652b35SZhang Rui .get = param_get_debug_layer, 157ec652b35SZhang Rui }; 158ec652b35SZhang Rui 1599c8b04beSVasiliy Kulikov static const struct kernel_param_ops param_ops_debug_level = { 160ec652b35SZhang Rui .set = param_set_uint, 161ec652b35SZhang Rui .get = param_get_debug_level, 162ec652b35SZhang Rui }; 163ec652b35SZhang Rui 164ec652b35SZhang Rui module_param_cb(debug_layer, ¶m_ops_debug_layer, &acpi_dbg_layer, 0644); 165ec652b35SZhang Rui module_param_cb(debug_level, ¶m_ops_debug_level, &acpi_dbg_level, 0644); 1661c8fce27SZhang Rui 167a0186bcfSLv Zheng static char trace_method_name[1024]; 1687901a052SLv Zheng 1697901a052SLv Zheng int param_set_trace_method_name(const char *val, const struct kernel_param *kp) 1707901a052SLv Zheng { 1717901a052SLv Zheng u32 saved_flags = 0; 172a0186bcfSLv Zheng bool is_abs_path = true; 1737901a052SLv Zheng 174a0186bcfSLv Zheng if (*val != '\\') 175a0186bcfSLv Zheng is_abs_path = false; 176a0186bcfSLv Zheng 177a0186bcfSLv Zheng if ((is_abs_path && strlen(val) > 1023) || 178a0186bcfSLv Zheng (!is_abs_path && strlen(val) > 1022)) { 1797901a052SLv Zheng pr_err("%s: string parameter too long\n", kp->name); 1807901a052SLv Zheng return -ENOSPC; 1817901a052SLv Zheng } 1827901a052SLv Zheng 1837901a052SLv Zheng /* 1847901a052SLv Zheng * It's not safe to update acpi_gbl_trace_method_name without 1857901a052SLv Zheng * having the tracer stopped, so we save the original tracer 1867901a052SLv Zheng * state and disable it. 1877901a052SLv Zheng */ 1887901a052SLv Zheng saved_flags = acpi_gbl_trace_flags; 1897901a052SLv Zheng (void)acpi_debug_trace(NULL, 1907901a052SLv Zheng acpi_gbl_trace_dbg_level, 1917901a052SLv Zheng acpi_gbl_trace_dbg_layer, 1927901a052SLv Zheng 0); 1937901a052SLv Zheng 1947901a052SLv Zheng /* This is a hack. We can't kmalloc in early boot. */ 195a0186bcfSLv Zheng if (is_abs_path) 196a0186bcfSLv Zheng strcpy(trace_method_name, val); 197a0186bcfSLv Zheng else { 198a0186bcfSLv Zheng trace_method_name[0] = '\\'; 199a0186bcfSLv Zheng strcpy(trace_method_name+1, val); 200a0186bcfSLv Zheng } 2017901a052SLv Zheng 2027901a052SLv Zheng /* Restore the original tracer state */ 2037901a052SLv Zheng (void)acpi_debug_trace(trace_method_name, 2047901a052SLv Zheng acpi_gbl_trace_dbg_level, 2057901a052SLv Zheng acpi_gbl_trace_dbg_layer, 2067901a052SLv Zheng saved_flags); 2077901a052SLv Zheng 2087901a052SLv Zheng return 0; 2097901a052SLv Zheng } 2107901a052SLv Zheng 2117901a052SLv Zheng static int param_get_trace_method_name(char *buffer, const struct kernel_param *kp) 2127901a052SLv Zheng { 2137901a052SLv Zheng return scnprintf(buffer, PAGE_SIZE, "%s", acpi_gbl_trace_method_name); 2147901a052SLv Zheng } 2157901a052SLv Zheng 2167901a052SLv Zheng static const struct kernel_param_ops param_ops_trace_method = { 2177901a052SLv Zheng .set = param_set_trace_method_name, 2187901a052SLv Zheng .get = param_get_trace_method_name, 2197901a052SLv Zheng }; 2207901a052SLv Zheng 2217901a052SLv Zheng static const struct kernel_param_ops param_ops_trace_attrib = { 2227901a052SLv Zheng .set = param_set_uint, 2237901a052SLv Zheng .get = param_get_uint, 2247901a052SLv Zheng }; 2257901a052SLv Zheng 2267901a052SLv Zheng module_param_cb(trace_method_name, ¶m_ops_trace_method, &trace_method_name, 0644); 2277901a052SLv Zheng module_param_cb(trace_debug_layer, ¶m_ops_trace_attrib, &acpi_gbl_trace_dbg_layer, 0644); 2287901a052SLv Zheng module_param_cb(trace_debug_level, ¶m_ops_trace_attrib, &acpi_gbl_trace_dbg_level, 0644); 2291c8fce27SZhang Rui 2301c8fce27SZhang Rui static int param_set_trace_state(const char *val, struct kernel_param *kp) 2311c8fce27SZhang Rui { 2327901a052SLv Zheng acpi_status status; 2337901a052SLv Zheng const char *method = trace_method_name; 2347901a052SLv Zheng u32 flags = 0; 2351c8fce27SZhang Rui 2367901a052SLv Zheng /* So "xxx-once" comparison should go prior than "xxx" comparison */ 2377901a052SLv Zheng #define acpi_compare_param(val, key) \ 2387901a052SLv Zheng strncmp((val), (key), sizeof(key) - 1) 2391c8fce27SZhang Rui 2407901a052SLv Zheng if (!acpi_compare_param(val, "enable")) { 2417901a052SLv Zheng method = NULL; 2427901a052SLv Zheng flags = ACPI_TRACE_ENABLED; 2437901a052SLv Zheng } else if (!acpi_compare_param(val, "disable")) 2447901a052SLv Zheng method = NULL; 2457901a052SLv Zheng else if (!acpi_compare_param(val, "method-once")) 2467901a052SLv Zheng flags = ACPI_TRACE_ENABLED | ACPI_TRACE_ONESHOT; 2477901a052SLv Zheng else if (!acpi_compare_param(val, "method")) 2487901a052SLv Zheng flags = ACPI_TRACE_ENABLED; 2497901a052SLv Zheng else if (!acpi_compare_param(val, "opcode-once")) 2507901a052SLv Zheng flags = ACPI_TRACE_ENABLED | ACPI_TRACE_ONESHOT | ACPI_TRACE_OPCODE; 2517901a052SLv Zheng else if (!acpi_compare_param(val, "opcode")) 2527901a052SLv Zheng flags = ACPI_TRACE_ENABLED | ACPI_TRACE_OPCODE; 2537901a052SLv Zheng else 2547901a052SLv Zheng return -EINVAL; 2551c8fce27SZhang Rui 2567901a052SLv Zheng status = acpi_debug_trace(method, 2577901a052SLv Zheng acpi_gbl_trace_dbg_level, 2587901a052SLv Zheng acpi_gbl_trace_dbg_layer, 2597901a052SLv Zheng flags); 2607901a052SLv Zheng if (ACPI_FAILURE(status)) 2617901a052SLv Zheng return -EBUSY; 2621c8fce27SZhang Rui 2637901a052SLv Zheng return 0; 2641c8fce27SZhang Rui } 2651c8fce27SZhang Rui 2661c8fce27SZhang Rui static int param_get_trace_state(char *buffer, struct kernel_param *kp) 2671c8fce27SZhang Rui { 2687901a052SLv Zheng if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED)) 2691c8fce27SZhang Rui return sprintf(buffer, "disable"); 2701c8fce27SZhang Rui else { 2717901a052SLv Zheng if (acpi_gbl_trace_method_name) { 2727901a052SLv Zheng if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) 2737901a052SLv Zheng return sprintf(buffer, "method-once"); 2741c8fce27SZhang Rui else 2757901a052SLv Zheng return sprintf(buffer, "method"); 2767901a052SLv Zheng } else 2771c8fce27SZhang Rui return sprintf(buffer, "enable"); 2781c8fce27SZhang Rui } 2791c8fce27SZhang Rui return 0; 2801c8fce27SZhang Rui } 2811c8fce27SZhang Rui 2821c8fce27SZhang Rui module_param_call(trace_state, param_set_trace_state, param_get_trace_state, 2831c8fce27SZhang Rui NULL, 0644); 2841c8fce27SZhang Rui #endif /* CONFIG_ACPI_DEBUG */ 2851c8fce27SZhang Rui 286aecad432SThomas Renninger 287aecad432SThomas Renninger /* /sys/modules/acpi/parameters/aml_debug_output */ 288aecad432SThomas Renninger 289aecad432SThomas Renninger module_param_named(aml_debug_output, acpi_gbl_enable_aml_debug_object, 290481c1381SLv Zheng byte, 0644); 291aecad432SThomas Renninger MODULE_PARM_DESC(aml_debug_output, 292aecad432SThomas Renninger "To enable/disable the ACPI Debug Object output."); 293aecad432SThomas Renninger 2941c8fce27SZhang Rui /* /sys/module/acpi/parameters/acpica_version */ 2951c8fce27SZhang Rui static int param_get_acpica_version(char *buffer, struct kernel_param *kp) 2961c8fce27SZhang Rui { 2971c8fce27SZhang Rui int result; 2981c8fce27SZhang Rui 2991c8fce27SZhang Rui result = sprintf(buffer, "%x", ACPI_CA_VERSION); 3001c8fce27SZhang Rui 3011c8fce27SZhang Rui return result; 3021c8fce27SZhang Rui } 3031c8fce27SZhang Rui 3041c8fce27SZhang Rui module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); 3051c8fce27SZhang Rui 3061c8fce27SZhang Rui /* 3071c8fce27SZhang Rui * ACPI table sysfs I/F: 3081c8fce27SZhang Rui * /sys/firmware/acpi/tables/ 3091c8fce27SZhang Rui * /sys/firmware/acpi/tables/dynamic/ 3101c8fce27SZhang Rui */ 3111c8fce27SZhang Rui 3121c8fce27SZhang Rui static LIST_HEAD(acpi_table_attr_list); 3131c8fce27SZhang Rui static struct kobject *tables_kobj; 3141c8fce27SZhang Rui static struct kobject *dynamic_tables_kobj; 3153f8055c3SRafael J. Wysocki static struct kobject *hotplug_kobj; 3161c8fce27SZhang Rui 3171c8fce27SZhang Rui struct acpi_table_attr { 3181c8fce27SZhang Rui struct bin_attribute attr; 3191c8fce27SZhang Rui char name[8]; 3201c8fce27SZhang Rui int instance; 3211c8fce27SZhang Rui struct list_head node; 3221c8fce27SZhang Rui }; 3231c8fce27SZhang Rui 3241c8fce27SZhang Rui static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj, 3251c8fce27SZhang Rui struct bin_attribute *bin_attr, char *buf, 3261c8fce27SZhang Rui loff_t offset, size_t count) 3271c8fce27SZhang Rui { 3281c8fce27SZhang Rui struct acpi_table_attr *table_attr = 3291c8fce27SZhang Rui container_of(bin_attr, struct acpi_table_attr, attr); 3301c8fce27SZhang Rui struct acpi_table_header *table_header = NULL; 3311c8fce27SZhang Rui acpi_status status; 3321c8fce27SZhang Rui char name[ACPI_NAME_SIZE]; 3331c8fce27SZhang Rui 3341c8fce27SZhang Rui if (strncmp(table_attr->name, "NULL", 4)) 3351c8fce27SZhang Rui memcpy(name, table_attr->name, ACPI_NAME_SIZE); 3361c8fce27SZhang Rui else 3371c8fce27SZhang Rui memcpy(name, "\0\0\0\0", 4); 3381c8fce27SZhang Rui 3391c8fce27SZhang Rui status = acpi_get_table(name, table_attr->instance, &table_header); 3401c8fce27SZhang Rui if (ACPI_FAILURE(status)) 3411c8fce27SZhang Rui return -ENODEV; 3421c8fce27SZhang Rui 3431c8fce27SZhang Rui return memory_read_from_buffer(buf, count, &offset, 3441c8fce27SZhang Rui table_header, table_header->length); 3451c8fce27SZhang Rui } 3461c8fce27SZhang Rui 3471c8fce27SZhang Rui static void acpi_table_attr_init(struct acpi_table_attr *table_attr, 3481c8fce27SZhang Rui struct acpi_table_header *table_header) 3491c8fce27SZhang Rui { 3501c8fce27SZhang Rui struct acpi_table_header *header = NULL; 3511c8fce27SZhang Rui struct acpi_table_attr *attr = NULL; 3521c8fce27SZhang Rui 3531c8fce27SZhang Rui sysfs_attr_init(&table_attr->attr.attr); 3541c8fce27SZhang Rui if (table_header->signature[0] != '\0') 3551c8fce27SZhang Rui memcpy(table_attr->name, table_header->signature, 3561c8fce27SZhang Rui ACPI_NAME_SIZE); 3571c8fce27SZhang Rui else 3581c8fce27SZhang Rui memcpy(table_attr->name, "NULL", 4); 3591c8fce27SZhang Rui 3601c8fce27SZhang Rui list_for_each_entry(attr, &acpi_table_attr_list, node) { 3611c8fce27SZhang Rui if (!memcmp(table_attr->name, attr->name, ACPI_NAME_SIZE)) 3621c8fce27SZhang Rui if (table_attr->instance < attr->instance) 3631c8fce27SZhang Rui table_attr->instance = attr->instance; 3641c8fce27SZhang Rui } 3651c8fce27SZhang Rui table_attr->instance++; 3661c8fce27SZhang Rui 3671c8fce27SZhang Rui if (table_attr->instance > 1 || (table_attr->instance == 1 && 3681c8fce27SZhang Rui !acpi_get_table 3691c8fce27SZhang Rui (table_header->signature, 2, &header))) 3701c8fce27SZhang Rui sprintf(table_attr->name + ACPI_NAME_SIZE, "%d", 3711c8fce27SZhang Rui table_attr->instance); 3721c8fce27SZhang Rui 373083ca8c4SDaisuke HATAYAMA table_attr->attr.size = table_header->length; 3741c8fce27SZhang Rui table_attr->attr.read = acpi_table_show; 3751c8fce27SZhang Rui table_attr->attr.attr.name = table_attr->name; 3761c8fce27SZhang Rui table_attr->attr.attr.mode = 0400; 3771c8fce27SZhang Rui 3781c8fce27SZhang Rui return; 3791c8fce27SZhang Rui } 3801c8fce27SZhang Rui 38168bdb677SOctavian Purdila acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context) 3821c8fce27SZhang Rui { 3831c8fce27SZhang Rui struct acpi_table_attr *table_attr; 3841c8fce27SZhang Rui 3851c8fce27SZhang Rui switch (event) { 386*307ecb0aSLv Zheng case ACPI_TABLE_EVENT_INSTALL: 3871c8fce27SZhang Rui table_attr = 3881c8fce27SZhang Rui kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL); 3891c8fce27SZhang Rui if (!table_attr) 3901c8fce27SZhang Rui return AE_NO_MEMORY; 3911c8fce27SZhang Rui 3921c8fce27SZhang Rui acpi_table_attr_init(table_attr, table); 3931c8fce27SZhang Rui if (sysfs_create_bin_file(dynamic_tables_kobj, 3941c8fce27SZhang Rui &table_attr->attr)) { 3951c8fce27SZhang Rui kfree(table_attr); 3961c8fce27SZhang Rui return AE_ERROR; 3971c8fce27SZhang Rui } else 3981c8fce27SZhang Rui list_add_tail(&table_attr->node, &acpi_table_attr_list); 3991c8fce27SZhang Rui break; 400*307ecb0aSLv Zheng case ACPI_TABLE_EVENT_LOAD: 4011c8fce27SZhang Rui case ACPI_TABLE_EVENT_UNLOAD: 402*307ecb0aSLv Zheng case ACPI_TABLE_EVENT_UNINSTALL: 4031c8fce27SZhang Rui /* 4041c8fce27SZhang Rui * we do not need to do anything right now 4051c8fce27SZhang Rui * because the table is not deleted from the 4061c8fce27SZhang Rui * global table list when unloading it. 4071c8fce27SZhang Rui */ 4081c8fce27SZhang Rui break; 4091c8fce27SZhang Rui default: 4101c8fce27SZhang Rui return AE_BAD_PARAMETER; 4111c8fce27SZhang Rui } 4121c8fce27SZhang Rui return AE_OK; 4131c8fce27SZhang Rui } 4141c8fce27SZhang Rui 4151c8fce27SZhang Rui static int acpi_tables_sysfs_init(void) 4161c8fce27SZhang Rui { 4171c8fce27SZhang Rui struct acpi_table_attr *table_attr; 4181c8fce27SZhang Rui struct acpi_table_header *table_header = NULL; 419de03beedSJeremy Compostella int table_index; 420de03beedSJeremy Compostella acpi_status status; 421de03beedSJeremy Compostella int ret; 4221c8fce27SZhang Rui 4231c8fce27SZhang Rui tables_kobj = kobject_create_and_add("tables", acpi_kobj); 4241c8fce27SZhang Rui if (!tables_kobj) 4251c8fce27SZhang Rui goto err; 4261c8fce27SZhang Rui 4271c8fce27SZhang Rui dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj); 4281c8fce27SZhang Rui if (!dynamic_tables_kobj) 4291c8fce27SZhang Rui goto err_dynamic_tables; 4301c8fce27SZhang Rui 431de03beedSJeremy Compostella for (table_index = 0;; table_index++) { 432de03beedSJeremy Compostella status = acpi_get_table_by_index(table_index, &table_header); 433de03beedSJeremy Compostella 434de03beedSJeremy Compostella if (status == AE_BAD_PARAMETER) 435de03beedSJeremy Compostella break; 436de03beedSJeremy Compostella 437de03beedSJeremy Compostella if (ACPI_FAILURE(status)) 438de03beedSJeremy Compostella continue; 439de03beedSJeremy Compostella 4401c8fce27SZhang Rui table_attr = NULL; 441de03beedSJeremy Compostella table_attr = kzalloc(sizeof(*table_attr), GFP_KERNEL); 4421c8fce27SZhang Rui if (!table_attr) 4431c8fce27SZhang Rui return -ENOMEM; 4441c8fce27SZhang Rui 4451c8fce27SZhang Rui acpi_table_attr_init(table_attr, table_header); 446de03beedSJeremy Compostella ret = sysfs_create_bin_file(tables_kobj, &table_attr->attr); 447de03beedSJeremy Compostella if (ret) { 4481c8fce27SZhang Rui kfree(table_attr); 449de03beedSJeremy Compostella return ret; 4501c8fce27SZhang Rui } 451de03beedSJeremy Compostella list_add_tail(&table_attr->node, &acpi_table_attr_list); 452de03beedSJeremy Compostella } 453de03beedSJeremy Compostella 4541c8fce27SZhang Rui kobject_uevent(tables_kobj, KOBJ_ADD); 4551c8fce27SZhang Rui kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); 4561c8fce27SZhang Rui 45768bdb677SOctavian Purdila return 0; 4581c8fce27SZhang Rui err_dynamic_tables: 4591c8fce27SZhang Rui kobject_put(tables_kobj); 4601c8fce27SZhang Rui err: 4611c8fce27SZhang Rui return -ENOMEM; 4621c8fce27SZhang Rui } 4631c8fce27SZhang Rui 4641c8fce27SZhang Rui /* 4651c8fce27SZhang Rui * Detailed ACPI IRQ counters: 4661c8fce27SZhang Rui * /sys/firmware/acpi/interrupts/ 4671c8fce27SZhang Rui */ 4681c8fce27SZhang Rui 4691c8fce27SZhang Rui u32 acpi_irq_handled; 4701c8fce27SZhang Rui u32 acpi_irq_not_handled; 4711c8fce27SZhang Rui 4721c8fce27SZhang Rui #define COUNT_GPE 0 4731c8fce27SZhang Rui #define COUNT_SCI 1 /* acpi_irq_handled */ 4741c8fce27SZhang Rui #define COUNT_SCI_NOT 2 /* acpi_irq_not_handled */ 4751c8fce27SZhang Rui #define COUNT_ERROR 3 /* other */ 4761c8fce27SZhang Rui #define NUM_COUNTERS_EXTRA 4 4771c8fce27SZhang Rui 4781c8fce27SZhang Rui struct event_counter { 4791c8fce27SZhang Rui u32 count; 4801c8fce27SZhang Rui u32 flags; 4811c8fce27SZhang Rui }; 4821c8fce27SZhang Rui 4831c8fce27SZhang Rui static struct event_counter *all_counters; 4841c8fce27SZhang Rui static u32 num_gpes; 4851c8fce27SZhang Rui static u32 num_counters; 4861c8fce27SZhang Rui static struct attribute **all_attrs; 4871c8fce27SZhang Rui static u32 acpi_gpe_count; 4881c8fce27SZhang Rui 4891c8fce27SZhang Rui static struct attribute_group interrupt_stats_attr_group = { 4901c8fce27SZhang Rui .name = "interrupts", 4911c8fce27SZhang Rui }; 4921c8fce27SZhang Rui 4931c8fce27SZhang Rui static struct kobj_attribute *counter_attrs; 4941c8fce27SZhang Rui 4951c8fce27SZhang Rui static void delete_gpe_attr_array(void) 4961c8fce27SZhang Rui { 4971c8fce27SZhang Rui struct event_counter *tmp = all_counters; 4981c8fce27SZhang Rui 4991c8fce27SZhang Rui all_counters = NULL; 5001c8fce27SZhang Rui kfree(tmp); 5011c8fce27SZhang Rui 5021c8fce27SZhang Rui if (counter_attrs) { 5031c8fce27SZhang Rui int i; 5041c8fce27SZhang Rui 5051c8fce27SZhang Rui for (i = 0; i < num_gpes; i++) 5061c8fce27SZhang Rui kfree(counter_attrs[i].attr.name); 5071c8fce27SZhang Rui 5081c8fce27SZhang Rui kfree(counter_attrs); 5091c8fce27SZhang Rui } 5101c8fce27SZhang Rui kfree(all_attrs); 5111c8fce27SZhang Rui 5121c8fce27SZhang Rui return; 5131c8fce27SZhang Rui } 5141c8fce27SZhang Rui 515a0fcdb23SLin Ming static void gpe_count(u32 gpe_number) 5161c8fce27SZhang Rui { 5171c8fce27SZhang Rui acpi_gpe_count++; 5181c8fce27SZhang Rui 5191c8fce27SZhang Rui if (!all_counters) 5201c8fce27SZhang Rui return; 5211c8fce27SZhang Rui 5221c8fce27SZhang Rui if (gpe_number < num_gpes) 5231c8fce27SZhang Rui all_counters[gpe_number].count++; 5241c8fce27SZhang Rui else 5251c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + 5261c8fce27SZhang Rui COUNT_ERROR].count++; 5271c8fce27SZhang Rui 5281c8fce27SZhang Rui return; 5291c8fce27SZhang Rui } 5301c8fce27SZhang Rui 531a0fcdb23SLin Ming static void fixed_event_count(u32 event_number) 5321c8fce27SZhang Rui { 5331c8fce27SZhang Rui if (!all_counters) 5341c8fce27SZhang Rui return; 5351c8fce27SZhang Rui 5361c8fce27SZhang Rui if (event_number < ACPI_NUM_FIXED_EVENTS) 5371c8fce27SZhang Rui all_counters[num_gpes + event_number].count++; 5381c8fce27SZhang Rui else 5391c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + 5401c8fce27SZhang Rui COUNT_ERROR].count++; 5411c8fce27SZhang Rui 5421c8fce27SZhang Rui return; 5431c8fce27SZhang Rui } 5441c8fce27SZhang Rui 545644ef74eSLv Zheng static void acpi_global_event_handler(u32 event_type, acpi_handle device, 546a0fcdb23SLin Ming u32 event_number, void *context) 547a0fcdb23SLin Ming { 548a0fcdb23SLin Ming if (event_type == ACPI_EVENT_TYPE_GPE) 549a0fcdb23SLin Ming gpe_count(event_number); 550a0fcdb23SLin Ming 551a0fcdb23SLin Ming if (event_type == ACPI_EVENT_TYPE_FIXED) 552a0fcdb23SLin Ming fixed_event_count(event_number); 553a0fcdb23SLin Ming } 554a0fcdb23SLin Ming 5551c8fce27SZhang Rui static int get_status(u32 index, acpi_event_status *status, 5561c8fce27SZhang Rui acpi_handle *handle) 5571c8fce27SZhang Rui { 558f18ebc21SDan Carpenter int result; 5591c8fce27SZhang Rui 5601c8fce27SZhang Rui if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS) 561f18ebc21SDan Carpenter return -EINVAL; 5621c8fce27SZhang Rui 5631c8fce27SZhang Rui if (index < num_gpes) { 5641c8fce27SZhang Rui result = acpi_get_gpe_device(index, handle); 5651c8fce27SZhang Rui if (result) { 5661c8fce27SZhang Rui ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND, 567c6284237SColin Ian King "Invalid GPE 0x%x", index)); 568f18ebc21SDan Carpenter return result; 5691c8fce27SZhang Rui } 5701c8fce27SZhang Rui result = acpi_get_gpe_status(*handle, index, status); 5711c8fce27SZhang Rui } else if (index < (num_gpes + ACPI_NUM_FIXED_EVENTS)) 5721c8fce27SZhang Rui result = acpi_get_event_status(index - num_gpes, status); 5731c8fce27SZhang Rui 5741c8fce27SZhang Rui return result; 5751c8fce27SZhang Rui } 5761c8fce27SZhang Rui 5771c8fce27SZhang Rui static ssize_t counter_show(struct kobject *kobj, 5781c8fce27SZhang Rui struct kobj_attribute *attr, char *buf) 5791c8fce27SZhang Rui { 5801c8fce27SZhang Rui int index = attr - counter_attrs; 5811c8fce27SZhang Rui int size; 5821c8fce27SZhang Rui acpi_handle handle; 5831c8fce27SZhang Rui acpi_event_status status; 5841c8fce27SZhang Rui int result = 0; 5851c8fce27SZhang Rui 5861c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI].count = 5871c8fce27SZhang Rui acpi_irq_handled; 5881c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI_NOT].count = 5891c8fce27SZhang Rui acpi_irq_not_handled; 5901c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE].count = 5911c8fce27SZhang Rui acpi_gpe_count; 5927b1a1322SNan Li size = sprintf(buf, "%8u", all_counters[index].count); 5931c8fce27SZhang Rui 5941c8fce27SZhang Rui /* "gpe_all" or "sci" */ 5951c8fce27SZhang Rui if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS) 5961c8fce27SZhang Rui goto end; 5971c8fce27SZhang Rui 5981c8fce27SZhang Rui result = get_status(index, &status, &handle); 5991c8fce27SZhang Rui if (result) 6001c8fce27SZhang Rui goto end; 6011c8fce27SZhang Rui 60218864cc4SLv Zheng if (status & ACPI_EVENT_FLAG_ENABLE_SET) 60318864cc4SLv Zheng size += sprintf(buf + size, " EN"); 60418864cc4SLv Zheng else 60518864cc4SLv Zheng size += sprintf(buf + size, " "); 60618864cc4SLv Zheng if (status & ACPI_EVENT_FLAG_STATUS_SET) 60718864cc4SLv Zheng size += sprintf(buf + size, " STS"); 60818864cc4SLv Zheng else 60918864cc4SLv Zheng size += sprintf(buf + size, " "); 61018864cc4SLv Zheng 6112f857234SLv Zheng if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER)) 6121c8fce27SZhang Rui size += sprintf(buf + size, " invalid "); 6131c8fce27SZhang Rui else if (status & ACPI_EVENT_FLAG_ENABLED) 6141c8fce27SZhang Rui size += sprintf(buf + size, " enabled "); 6151c8fce27SZhang Rui else if (status & ACPI_EVENT_FLAG_WAKE_ENABLED) 6161c8fce27SZhang Rui size += sprintf(buf + size, " wake_enabled"); 6171c8fce27SZhang Rui else 6181c8fce27SZhang Rui size += sprintf(buf + size, " disabled "); 61918864cc4SLv Zheng if (status & ACPI_EVENT_FLAG_MASKED) 62018864cc4SLv Zheng size += sprintf(buf + size, " masked "); 62118864cc4SLv Zheng else 62218864cc4SLv Zheng size += sprintf(buf + size, " unmasked"); 6231c8fce27SZhang Rui 6241c8fce27SZhang Rui end: 6251c8fce27SZhang Rui size += sprintf(buf + size, "\n"); 6261c8fce27SZhang Rui return result ? result : size; 6271c8fce27SZhang Rui } 6281c8fce27SZhang Rui 6291c8fce27SZhang Rui /* 6301c8fce27SZhang Rui * counter_set() sets the specified counter. 6311c8fce27SZhang Rui * setting the total "sci" file to any value clears all counters. 6321c8fce27SZhang Rui * enable/disable/clear a gpe/fixed event in user space. 6331c8fce27SZhang Rui */ 6341c8fce27SZhang Rui static ssize_t counter_set(struct kobject *kobj, 6351c8fce27SZhang Rui struct kobj_attribute *attr, const char *buf, 6361c8fce27SZhang Rui size_t size) 6371c8fce27SZhang Rui { 6381c8fce27SZhang Rui int index = attr - counter_attrs; 6391c8fce27SZhang Rui acpi_event_status status; 6401c8fce27SZhang Rui acpi_handle handle; 6411c8fce27SZhang Rui int result = 0; 642c48b1565SLan Tianyu unsigned long tmp; 6431c8fce27SZhang Rui 6441c8fce27SZhang Rui if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) { 6451c8fce27SZhang Rui int i; 6461c8fce27SZhang Rui for (i = 0; i < num_counters; ++i) 6471c8fce27SZhang Rui all_counters[i].count = 0; 6481c8fce27SZhang Rui acpi_gpe_count = 0; 6491c8fce27SZhang Rui acpi_irq_handled = 0; 6501c8fce27SZhang Rui acpi_irq_not_handled = 0; 6511c8fce27SZhang Rui goto end; 6521c8fce27SZhang Rui } 6531c8fce27SZhang Rui 6541c8fce27SZhang Rui /* show the event status for both GPEs and Fixed Events */ 6551c8fce27SZhang Rui result = get_status(index, &status, &handle); 6561c8fce27SZhang Rui if (result) 6571c8fce27SZhang Rui goto end; 6581c8fce27SZhang Rui 6592f857234SLv Zheng if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER)) { 6601c8fce27SZhang Rui printk(KERN_WARNING PREFIX 6611c8fce27SZhang Rui "Can not change Invalid GPE/Fixed Event status\n"); 6621c8fce27SZhang Rui return -EINVAL; 6631c8fce27SZhang Rui } 6641c8fce27SZhang Rui 6651c8fce27SZhang Rui if (index < num_gpes) { 6661c8fce27SZhang Rui if (!strcmp(buf, "disable\n") && 6671c8fce27SZhang Rui (status & ACPI_EVENT_FLAG_ENABLED)) 6681c8fce27SZhang Rui result = acpi_disable_gpe(handle, index); 6691c8fce27SZhang Rui else if (!strcmp(buf, "enable\n") && 6701c8fce27SZhang Rui !(status & ACPI_EVENT_FLAG_ENABLED)) 6711c8fce27SZhang Rui result = acpi_enable_gpe(handle, index); 6721c8fce27SZhang Rui else if (!strcmp(buf, "clear\n") && 67318864cc4SLv Zheng (status & ACPI_EVENT_FLAG_STATUS_SET)) 6741c8fce27SZhang Rui result = acpi_clear_gpe(handle, index); 67518864cc4SLv Zheng else if (!strcmp(buf, "mask\n")) 67618864cc4SLv Zheng result = acpi_mask_gpe(handle, index, TRUE); 67718864cc4SLv Zheng else if (!strcmp(buf, "unmask\n")) 67818864cc4SLv Zheng result = acpi_mask_gpe(handle, index, FALSE); 679c48b1565SLan Tianyu else if (!kstrtoul(buf, 0, &tmp)) 680c48b1565SLan Tianyu all_counters[index].count = tmp; 6811c8fce27SZhang Rui else 682c48b1565SLan Tianyu result = -EINVAL; 6831c8fce27SZhang Rui } else if (index < num_gpes + ACPI_NUM_FIXED_EVENTS) { 6841c8fce27SZhang Rui int event = index - num_gpes; 6851c8fce27SZhang Rui if (!strcmp(buf, "disable\n") && 68618864cc4SLv Zheng (status & ACPI_EVENT_FLAG_ENABLE_SET)) 6871c8fce27SZhang Rui result = acpi_disable_event(event, ACPI_NOT_ISR); 6881c8fce27SZhang Rui else if (!strcmp(buf, "enable\n") && 68918864cc4SLv Zheng !(status & ACPI_EVENT_FLAG_ENABLE_SET)) 6901c8fce27SZhang Rui result = acpi_enable_event(event, ACPI_NOT_ISR); 6911c8fce27SZhang Rui else if (!strcmp(buf, "clear\n") && 69218864cc4SLv Zheng (status & ACPI_EVENT_FLAG_STATUS_SET)) 6931c8fce27SZhang Rui result = acpi_clear_event(event); 694c48b1565SLan Tianyu else if (!kstrtoul(buf, 0, &tmp)) 695c48b1565SLan Tianyu all_counters[index].count = tmp; 6961c8fce27SZhang Rui else 697c48b1565SLan Tianyu result = -EINVAL; 6981c8fce27SZhang Rui } else 6991c8fce27SZhang Rui all_counters[index].count = strtoul(buf, NULL, 0); 7001c8fce27SZhang Rui 7011c8fce27SZhang Rui if (ACPI_FAILURE(result)) 7021c8fce27SZhang Rui result = -EINVAL; 7031c8fce27SZhang Rui end: 7041c8fce27SZhang Rui return result ? result : size; 7051c8fce27SZhang Rui } 7061c8fce27SZhang Rui 7071c8fce27SZhang Rui void acpi_irq_stats_init(void) 7081c8fce27SZhang Rui { 709a0fcdb23SLin Ming acpi_status status; 7101c8fce27SZhang Rui int i; 7111c8fce27SZhang Rui 7121c8fce27SZhang Rui if (all_counters) 7131c8fce27SZhang Rui return; 7141c8fce27SZhang Rui 7151c8fce27SZhang Rui num_gpes = acpi_current_gpe_count; 7161c8fce27SZhang Rui num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA; 7171c8fce27SZhang Rui 7181c8fce27SZhang Rui all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1), 7191c8fce27SZhang Rui GFP_KERNEL); 7201c8fce27SZhang Rui if (all_attrs == NULL) 7211c8fce27SZhang Rui return; 7221c8fce27SZhang Rui 7231c8fce27SZhang Rui all_counters = kzalloc(sizeof(struct event_counter) * (num_counters), 7241c8fce27SZhang Rui GFP_KERNEL); 7251c8fce27SZhang Rui if (all_counters == NULL) 7261c8fce27SZhang Rui goto fail; 7271c8fce27SZhang Rui 728644ef74eSLv Zheng status = acpi_install_global_event_handler(acpi_global_event_handler, NULL); 729a0fcdb23SLin Ming if (ACPI_FAILURE(status)) 730a0fcdb23SLin Ming goto fail; 731a0fcdb23SLin Ming 7321c8fce27SZhang Rui counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters), 7331c8fce27SZhang Rui GFP_KERNEL); 7341c8fce27SZhang Rui if (counter_attrs == NULL) 7351c8fce27SZhang Rui goto fail; 7361c8fce27SZhang Rui 7371c8fce27SZhang Rui for (i = 0; i < num_counters; ++i) { 7381c8fce27SZhang Rui char buffer[12]; 7391c8fce27SZhang Rui char *name; 7401c8fce27SZhang Rui 7411c8fce27SZhang Rui if (i < num_gpes) 7421c8fce27SZhang Rui sprintf(buffer, "gpe%02X", i); 7431c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_PMTIMER) 7441c8fce27SZhang Rui sprintf(buffer, "ff_pmtimer"); 7451c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_GLOBAL) 7461c8fce27SZhang Rui sprintf(buffer, "ff_gbl_lock"); 7471c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_POWER_BUTTON) 7481c8fce27SZhang Rui sprintf(buffer, "ff_pwr_btn"); 7491c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_SLEEP_BUTTON) 7501c8fce27SZhang Rui sprintf(buffer, "ff_slp_btn"); 7511c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_RTC) 7521c8fce27SZhang Rui sprintf(buffer, "ff_rt_clk"); 7531c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE) 7541c8fce27SZhang Rui sprintf(buffer, "gpe_all"); 7551c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) 7561c8fce27SZhang Rui sprintf(buffer, "sci"); 7571c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI_NOT) 7581c8fce27SZhang Rui sprintf(buffer, "sci_not"); 7591c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR) 7601c8fce27SZhang Rui sprintf(buffer, "error"); 7611c8fce27SZhang Rui else 7621c8fce27SZhang Rui sprintf(buffer, "bug%02X", i); 7631c8fce27SZhang Rui 764096a8aacSKees Cook name = kstrdup(buffer, GFP_KERNEL); 7651c8fce27SZhang Rui if (name == NULL) 7661c8fce27SZhang Rui goto fail; 7671c8fce27SZhang Rui 7681c8fce27SZhang Rui sysfs_attr_init(&counter_attrs[i].attr); 7691c8fce27SZhang Rui counter_attrs[i].attr.name = name; 7701c8fce27SZhang Rui counter_attrs[i].attr.mode = 0644; 7711c8fce27SZhang Rui counter_attrs[i].show = counter_show; 7721c8fce27SZhang Rui counter_attrs[i].store = counter_set; 7731c8fce27SZhang Rui 7741c8fce27SZhang Rui all_attrs[i] = &counter_attrs[i].attr; 7751c8fce27SZhang Rui } 7761c8fce27SZhang Rui 7771c8fce27SZhang Rui interrupt_stats_attr_group.attrs = all_attrs; 7781c8fce27SZhang Rui if (!sysfs_create_group(acpi_kobj, &interrupt_stats_attr_group)) 7791c8fce27SZhang Rui return; 7801c8fce27SZhang Rui 7811c8fce27SZhang Rui fail: 7821c8fce27SZhang Rui delete_gpe_attr_array(); 7831c8fce27SZhang Rui return; 7841c8fce27SZhang Rui } 7851c8fce27SZhang Rui 7861c8fce27SZhang Rui static void __exit interrupt_stats_exit(void) 7871c8fce27SZhang Rui { 7881c8fce27SZhang Rui sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group); 7891c8fce27SZhang Rui 7901c8fce27SZhang Rui delete_gpe_attr_array(); 7911c8fce27SZhang Rui 7921c8fce27SZhang Rui return; 7931c8fce27SZhang Rui } 7941c8fce27SZhang Rui 795362b6460SThomas Renninger static ssize_t 796362b6460SThomas Renninger acpi_show_profile(struct device *dev, struct device_attribute *attr, 797362b6460SThomas Renninger char *buf) 798362b6460SThomas Renninger { 799362b6460SThomas Renninger return sprintf(buf, "%d\n", acpi_gbl_FADT.preferred_profile); 800362b6460SThomas Renninger } 801362b6460SThomas Renninger 802362b6460SThomas Renninger static const struct device_attribute pm_profile_attr = 803362b6460SThomas Renninger __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL); 804362b6460SThomas Renninger 8053f8055c3SRafael J. Wysocki static ssize_t hotplug_enabled_show(struct kobject *kobj, 8063f8055c3SRafael J. Wysocki struct kobj_attribute *attr, char *buf) 8073f8055c3SRafael J. Wysocki { 8083f8055c3SRafael J. Wysocki struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj); 8093f8055c3SRafael J. Wysocki 8103f8055c3SRafael J. Wysocki return sprintf(buf, "%d\n", hotplug->enabled); 8113f8055c3SRafael J. Wysocki } 8123f8055c3SRafael J. Wysocki 8133f8055c3SRafael J. Wysocki static ssize_t hotplug_enabled_store(struct kobject *kobj, 8143f8055c3SRafael J. Wysocki struct kobj_attribute *attr, 8153f8055c3SRafael J. Wysocki const char *buf, size_t size) 8163f8055c3SRafael J. Wysocki { 8173f8055c3SRafael J. Wysocki struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj); 8183f8055c3SRafael J. Wysocki unsigned int val; 8193f8055c3SRafael J. Wysocki 8203f8055c3SRafael J. Wysocki if (kstrtouint(buf, 10, &val) || val > 1) 8213f8055c3SRafael J. Wysocki return -EINVAL; 8223f8055c3SRafael J. Wysocki 8233f8055c3SRafael J. Wysocki acpi_scan_hotplug_enabled(hotplug, val); 8243f8055c3SRafael J. Wysocki return size; 8253f8055c3SRafael J. Wysocki } 8263f8055c3SRafael J. Wysocki 8273f8055c3SRafael J. Wysocki static struct kobj_attribute hotplug_enabled_attr = 8283f8055c3SRafael J. Wysocki __ATTR(enabled, S_IRUGO | S_IWUSR, hotplug_enabled_show, 8293f8055c3SRafael J. Wysocki hotplug_enabled_store); 8303f8055c3SRafael J. Wysocki 8313f8055c3SRafael J. Wysocki static struct attribute *hotplug_profile_attrs[] = { 8323f8055c3SRafael J. Wysocki &hotplug_enabled_attr.attr, 8333f8055c3SRafael J. Wysocki NULL 8343f8055c3SRafael J. Wysocki }; 8353f8055c3SRafael J. Wysocki 836b09753ecSRafael J. Wysocki static struct kobj_type acpi_hotplug_profile_ktype = { 8373f8055c3SRafael J. Wysocki .sysfs_ops = &kobj_sysfs_ops, 8383f8055c3SRafael J. Wysocki .default_attrs = hotplug_profile_attrs, 8393f8055c3SRafael J. Wysocki }; 8403f8055c3SRafael J. Wysocki 8413f8055c3SRafael J. Wysocki void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, 8423f8055c3SRafael J. Wysocki const char *name) 8433f8055c3SRafael J. Wysocki { 8443f8055c3SRafael J. Wysocki int error; 8453f8055c3SRafael J. Wysocki 8463f8055c3SRafael J. Wysocki if (!hotplug_kobj) 8473f8055c3SRafael J. Wysocki goto err_out; 8483f8055c3SRafael J. Wysocki 849acd3e2c9SBjorn Helgaas error = kobject_init_and_add(&hotplug->kobj, 850acd3e2c9SBjorn Helgaas &acpi_hotplug_profile_ktype, hotplug_kobj, "%s", name); 8513f8055c3SRafael J. Wysocki if (error) 8523f8055c3SRafael J. Wysocki goto err_out; 8533f8055c3SRafael J. Wysocki 8543f8055c3SRafael J. Wysocki kobject_uevent(&hotplug->kobj, KOBJ_ADD); 8553f8055c3SRafael J. Wysocki return; 8563f8055c3SRafael J. Wysocki 8573f8055c3SRafael J. Wysocki err_out: 8583f8055c3SRafael J. Wysocki pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name); 8593f8055c3SRafael J. Wysocki } 8603f8055c3SRafael J. Wysocki 861683058e3SRafael J. Wysocki static ssize_t force_remove_show(struct kobject *kobj, 862683058e3SRafael J. Wysocki struct kobj_attribute *attr, char *buf) 863683058e3SRafael J. Wysocki { 864683058e3SRafael J. Wysocki return sprintf(buf, "%d\n", !!acpi_force_hot_remove); 865683058e3SRafael J. Wysocki } 866683058e3SRafael J. Wysocki 867683058e3SRafael J. Wysocki static ssize_t force_remove_store(struct kobject *kobj, 868683058e3SRafael J. Wysocki struct kobj_attribute *attr, 869683058e3SRafael J. Wysocki const char *buf, size_t size) 870683058e3SRafael J. Wysocki { 871683058e3SRafael J. Wysocki bool val; 872683058e3SRafael J. Wysocki int ret; 873683058e3SRafael J. Wysocki 874683058e3SRafael J. Wysocki ret = strtobool(buf, &val); 875683058e3SRafael J. Wysocki if (ret < 0) 876683058e3SRafael J. Wysocki return ret; 877683058e3SRafael J. Wysocki 878683058e3SRafael J. Wysocki lock_device_hotplug(); 879683058e3SRafael J. Wysocki acpi_force_hot_remove = val; 880683058e3SRafael J. Wysocki unlock_device_hotplug(); 881683058e3SRafael J. Wysocki return size; 882683058e3SRafael J. Wysocki } 883683058e3SRafael J. Wysocki 884683058e3SRafael J. Wysocki static const struct kobj_attribute force_remove_attr = 885683058e3SRafael J. Wysocki __ATTR(force_remove, S_IRUGO | S_IWUSR, force_remove_show, 886683058e3SRafael J. Wysocki force_remove_store); 887683058e3SRafael J. Wysocki 8881c8fce27SZhang Rui int __init acpi_sysfs_init(void) 8891c8fce27SZhang Rui { 8901c8fce27SZhang Rui int result; 8911c8fce27SZhang Rui 8921c8fce27SZhang Rui result = acpi_tables_sysfs_init(); 893362b6460SThomas Renninger if (result) 894362b6460SThomas Renninger return result; 8953f8055c3SRafael J. Wysocki 8963f8055c3SRafael J. Wysocki hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj); 897bc1e49dfSInsu Yun if (!hotplug_kobj) 898bc1e49dfSInsu Yun return -ENOMEM; 899bc1e49dfSInsu Yun 900683058e3SRafael J. Wysocki result = sysfs_create_file(hotplug_kobj, &force_remove_attr.attr); 901683058e3SRafael J. Wysocki if (result) 902683058e3SRafael J. Wysocki return result; 903683058e3SRafael J. Wysocki 904362b6460SThomas Renninger result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr); 9051c8fce27SZhang Rui return result; 9061c8fce27SZhang Rui } 907