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) { 3861c8fce27SZhang Rui case ACPI_TABLE_EVENT_LOAD: 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; 4001c8fce27SZhang Rui case ACPI_TABLE_EVENT_UNLOAD: 4011c8fce27SZhang Rui /* 4021c8fce27SZhang Rui * we do not need to do anything right now 4031c8fce27SZhang Rui * because the table is not deleted from the 4041c8fce27SZhang Rui * global table list when unloading it. 4051c8fce27SZhang Rui */ 4061c8fce27SZhang Rui break; 4071c8fce27SZhang Rui default: 4081c8fce27SZhang Rui return AE_BAD_PARAMETER; 4091c8fce27SZhang Rui } 4101c8fce27SZhang Rui return AE_OK; 4111c8fce27SZhang Rui } 4121c8fce27SZhang Rui 4131c8fce27SZhang Rui static int acpi_tables_sysfs_init(void) 4141c8fce27SZhang Rui { 4151c8fce27SZhang Rui struct acpi_table_attr *table_attr; 4161c8fce27SZhang Rui struct acpi_table_header *table_header = NULL; 417de03beedSJeremy Compostella int table_index; 418de03beedSJeremy Compostella acpi_status status; 419de03beedSJeremy Compostella int ret; 4201c8fce27SZhang Rui 4211c8fce27SZhang Rui tables_kobj = kobject_create_and_add("tables", acpi_kobj); 4221c8fce27SZhang Rui if (!tables_kobj) 4231c8fce27SZhang Rui goto err; 4241c8fce27SZhang Rui 4251c8fce27SZhang Rui dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj); 4261c8fce27SZhang Rui if (!dynamic_tables_kobj) 4271c8fce27SZhang Rui goto err_dynamic_tables; 4281c8fce27SZhang Rui 429de03beedSJeremy Compostella for (table_index = 0;; table_index++) { 430de03beedSJeremy Compostella status = acpi_get_table_by_index(table_index, &table_header); 431de03beedSJeremy Compostella 432de03beedSJeremy Compostella if (status == AE_BAD_PARAMETER) 433de03beedSJeremy Compostella break; 434de03beedSJeremy Compostella 435de03beedSJeremy Compostella if (ACPI_FAILURE(status)) 436de03beedSJeremy Compostella continue; 437de03beedSJeremy Compostella 4381c8fce27SZhang Rui table_attr = NULL; 439de03beedSJeremy Compostella table_attr = kzalloc(sizeof(*table_attr), GFP_KERNEL); 4401c8fce27SZhang Rui if (!table_attr) 4411c8fce27SZhang Rui return -ENOMEM; 4421c8fce27SZhang Rui 4431c8fce27SZhang Rui acpi_table_attr_init(table_attr, table_header); 444de03beedSJeremy Compostella ret = sysfs_create_bin_file(tables_kobj, &table_attr->attr); 445de03beedSJeremy Compostella if (ret) { 4461c8fce27SZhang Rui kfree(table_attr); 447de03beedSJeremy Compostella return ret; 4481c8fce27SZhang Rui } 449de03beedSJeremy Compostella list_add_tail(&table_attr->node, &acpi_table_attr_list); 450de03beedSJeremy Compostella } 451de03beedSJeremy Compostella 4521c8fce27SZhang Rui kobject_uevent(tables_kobj, KOBJ_ADD); 4531c8fce27SZhang Rui kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); 4541c8fce27SZhang Rui 45568bdb677SOctavian Purdila return 0; 4561c8fce27SZhang Rui err_dynamic_tables: 4571c8fce27SZhang Rui kobject_put(tables_kobj); 4581c8fce27SZhang Rui err: 4591c8fce27SZhang Rui return -ENOMEM; 4601c8fce27SZhang Rui } 4611c8fce27SZhang Rui 4621c8fce27SZhang Rui /* 4631c8fce27SZhang Rui * Detailed ACPI IRQ counters: 4641c8fce27SZhang Rui * /sys/firmware/acpi/interrupts/ 4651c8fce27SZhang Rui */ 4661c8fce27SZhang Rui 4671c8fce27SZhang Rui u32 acpi_irq_handled; 4681c8fce27SZhang Rui u32 acpi_irq_not_handled; 4691c8fce27SZhang Rui 4701c8fce27SZhang Rui #define COUNT_GPE 0 4711c8fce27SZhang Rui #define COUNT_SCI 1 /* acpi_irq_handled */ 4721c8fce27SZhang Rui #define COUNT_SCI_NOT 2 /* acpi_irq_not_handled */ 4731c8fce27SZhang Rui #define COUNT_ERROR 3 /* other */ 4741c8fce27SZhang Rui #define NUM_COUNTERS_EXTRA 4 4751c8fce27SZhang Rui 4761c8fce27SZhang Rui struct event_counter { 4771c8fce27SZhang Rui u32 count; 4781c8fce27SZhang Rui u32 flags; 4791c8fce27SZhang Rui }; 4801c8fce27SZhang Rui 4811c8fce27SZhang Rui static struct event_counter *all_counters; 4821c8fce27SZhang Rui static u32 num_gpes; 4831c8fce27SZhang Rui static u32 num_counters; 4841c8fce27SZhang Rui static struct attribute **all_attrs; 4851c8fce27SZhang Rui static u32 acpi_gpe_count; 4861c8fce27SZhang Rui 4871c8fce27SZhang Rui static struct attribute_group interrupt_stats_attr_group = { 4881c8fce27SZhang Rui .name = "interrupts", 4891c8fce27SZhang Rui }; 4901c8fce27SZhang Rui 4911c8fce27SZhang Rui static struct kobj_attribute *counter_attrs; 4921c8fce27SZhang Rui 4931c8fce27SZhang Rui static void delete_gpe_attr_array(void) 4941c8fce27SZhang Rui { 4951c8fce27SZhang Rui struct event_counter *tmp = all_counters; 4961c8fce27SZhang Rui 4971c8fce27SZhang Rui all_counters = NULL; 4981c8fce27SZhang Rui kfree(tmp); 4991c8fce27SZhang Rui 5001c8fce27SZhang Rui if (counter_attrs) { 5011c8fce27SZhang Rui int i; 5021c8fce27SZhang Rui 5031c8fce27SZhang Rui for (i = 0; i < num_gpes; i++) 5041c8fce27SZhang Rui kfree(counter_attrs[i].attr.name); 5051c8fce27SZhang Rui 5061c8fce27SZhang Rui kfree(counter_attrs); 5071c8fce27SZhang Rui } 5081c8fce27SZhang Rui kfree(all_attrs); 5091c8fce27SZhang Rui 5101c8fce27SZhang Rui return; 5111c8fce27SZhang Rui } 5121c8fce27SZhang Rui 513a0fcdb23SLin Ming static void gpe_count(u32 gpe_number) 5141c8fce27SZhang Rui { 5151c8fce27SZhang Rui acpi_gpe_count++; 5161c8fce27SZhang Rui 5171c8fce27SZhang Rui if (!all_counters) 5181c8fce27SZhang Rui return; 5191c8fce27SZhang Rui 5201c8fce27SZhang Rui if (gpe_number < num_gpes) 5211c8fce27SZhang Rui all_counters[gpe_number].count++; 5221c8fce27SZhang Rui else 5231c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + 5241c8fce27SZhang Rui COUNT_ERROR].count++; 5251c8fce27SZhang Rui 5261c8fce27SZhang Rui return; 5271c8fce27SZhang Rui } 5281c8fce27SZhang Rui 529a0fcdb23SLin Ming static void fixed_event_count(u32 event_number) 5301c8fce27SZhang Rui { 5311c8fce27SZhang Rui if (!all_counters) 5321c8fce27SZhang Rui return; 5331c8fce27SZhang Rui 5341c8fce27SZhang Rui if (event_number < ACPI_NUM_FIXED_EVENTS) 5351c8fce27SZhang Rui all_counters[num_gpes + event_number].count++; 5361c8fce27SZhang Rui else 5371c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + 5381c8fce27SZhang Rui COUNT_ERROR].count++; 5391c8fce27SZhang Rui 5401c8fce27SZhang Rui return; 5411c8fce27SZhang Rui } 5421c8fce27SZhang Rui 543644ef74eSLv Zheng static void acpi_global_event_handler(u32 event_type, acpi_handle device, 544a0fcdb23SLin Ming u32 event_number, void *context) 545a0fcdb23SLin Ming { 546a0fcdb23SLin Ming if (event_type == ACPI_EVENT_TYPE_GPE) 547a0fcdb23SLin Ming gpe_count(event_number); 548a0fcdb23SLin Ming 549a0fcdb23SLin Ming if (event_type == ACPI_EVENT_TYPE_FIXED) 550a0fcdb23SLin Ming fixed_event_count(event_number); 551a0fcdb23SLin Ming } 552a0fcdb23SLin Ming 5531c8fce27SZhang Rui static int get_status(u32 index, acpi_event_status *status, 5541c8fce27SZhang Rui acpi_handle *handle) 5551c8fce27SZhang Rui { 556f18ebc21SDan Carpenter int result; 5571c8fce27SZhang Rui 5581c8fce27SZhang Rui if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS) 559f18ebc21SDan Carpenter return -EINVAL; 5601c8fce27SZhang Rui 5611c8fce27SZhang Rui if (index < num_gpes) { 5621c8fce27SZhang Rui result = acpi_get_gpe_device(index, handle); 5631c8fce27SZhang Rui if (result) { 5641c8fce27SZhang Rui ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND, 565c6284237SColin Ian King "Invalid GPE 0x%x", index)); 566f18ebc21SDan Carpenter return result; 5671c8fce27SZhang Rui } 5681c8fce27SZhang Rui result = acpi_get_gpe_status(*handle, index, status); 5691c8fce27SZhang Rui } else if (index < (num_gpes + ACPI_NUM_FIXED_EVENTS)) 5701c8fce27SZhang Rui result = acpi_get_event_status(index - num_gpes, status); 5711c8fce27SZhang Rui 5721c8fce27SZhang Rui return result; 5731c8fce27SZhang Rui } 5741c8fce27SZhang Rui 5751c8fce27SZhang Rui static ssize_t counter_show(struct kobject *kobj, 5761c8fce27SZhang Rui struct kobj_attribute *attr, char *buf) 5771c8fce27SZhang Rui { 5781c8fce27SZhang Rui int index = attr - counter_attrs; 5791c8fce27SZhang Rui int size; 5801c8fce27SZhang Rui acpi_handle handle; 5811c8fce27SZhang Rui acpi_event_status status; 5821c8fce27SZhang Rui int result = 0; 5831c8fce27SZhang Rui 5841c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI].count = 5851c8fce27SZhang Rui acpi_irq_handled; 5861c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI_NOT].count = 5871c8fce27SZhang Rui acpi_irq_not_handled; 5881c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE].count = 5891c8fce27SZhang Rui acpi_gpe_count; 5907b1a1322SNan Li size = sprintf(buf, "%8u", all_counters[index].count); 5911c8fce27SZhang Rui 5921c8fce27SZhang Rui /* "gpe_all" or "sci" */ 5931c8fce27SZhang Rui if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS) 5941c8fce27SZhang Rui goto end; 5951c8fce27SZhang Rui 5961c8fce27SZhang Rui result = get_status(index, &status, &handle); 5971c8fce27SZhang Rui if (result) 5981c8fce27SZhang Rui goto end; 5991c8fce27SZhang Rui 60018864cc4SLv Zheng if (status & ACPI_EVENT_FLAG_ENABLE_SET) 60118864cc4SLv Zheng size += sprintf(buf + size, " EN"); 60218864cc4SLv Zheng else 60318864cc4SLv Zheng size += sprintf(buf + size, " "); 60418864cc4SLv Zheng if (status & ACPI_EVENT_FLAG_STATUS_SET) 60518864cc4SLv Zheng size += sprintf(buf + size, " STS"); 60618864cc4SLv Zheng else 60718864cc4SLv Zheng size += sprintf(buf + size, " "); 60818864cc4SLv Zheng 6092f857234SLv Zheng if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER)) 6101c8fce27SZhang Rui size += sprintf(buf + size, " invalid "); 6111c8fce27SZhang Rui else if (status & ACPI_EVENT_FLAG_ENABLED) 6121c8fce27SZhang Rui size += sprintf(buf + size, " enabled "); 6131c8fce27SZhang Rui else if (status & ACPI_EVENT_FLAG_WAKE_ENABLED) 6141c8fce27SZhang Rui size += sprintf(buf + size, " wake_enabled"); 6151c8fce27SZhang Rui else 6161c8fce27SZhang Rui size += sprintf(buf + size, " disabled "); 61718864cc4SLv Zheng if (status & ACPI_EVENT_FLAG_MASKED) 61818864cc4SLv Zheng size += sprintf(buf + size, " masked "); 61918864cc4SLv Zheng else 62018864cc4SLv Zheng size += sprintf(buf + size, " unmasked"); 6211c8fce27SZhang Rui 6221c8fce27SZhang Rui end: 6231c8fce27SZhang Rui size += sprintf(buf + size, "\n"); 6241c8fce27SZhang Rui return result ? result : size; 6251c8fce27SZhang Rui } 6261c8fce27SZhang Rui 6271c8fce27SZhang Rui /* 6281c8fce27SZhang Rui * counter_set() sets the specified counter. 6291c8fce27SZhang Rui * setting the total "sci" file to any value clears all counters. 6301c8fce27SZhang Rui * enable/disable/clear a gpe/fixed event in user space. 6311c8fce27SZhang Rui */ 6321c8fce27SZhang Rui static ssize_t counter_set(struct kobject *kobj, 6331c8fce27SZhang Rui struct kobj_attribute *attr, const char *buf, 6341c8fce27SZhang Rui size_t size) 6351c8fce27SZhang Rui { 6361c8fce27SZhang Rui int index = attr - counter_attrs; 6371c8fce27SZhang Rui acpi_event_status status; 6381c8fce27SZhang Rui acpi_handle handle; 6391c8fce27SZhang Rui int result = 0; 640c48b1565SLan Tianyu unsigned long tmp; 6411c8fce27SZhang Rui 6421c8fce27SZhang Rui if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) { 6431c8fce27SZhang Rui int i; 6441c8fce27SZhang Rui for (i = 0; i < num_counters; ++i) 6451c8fce27SZhang Rui all_counters[i].count = 0; 6461c8fce27SZhang Rui acpi_gpe_count = 0; 6471c8fce27SZhang Rui acpi_irq_handled = 0; 6481c8fce27SZhang Rui acpi_irq_not_handled = 0; 6491c8fce27SZhang Rui goto end; 6501c8fce27SZhang Rui } 6511c8fce27SZhang Rui 6521c8fce27SZhang Rui /* show the event status for both GPEs and Fixed Events */ 6531c8fce27SZhang Rui result = get_status(index, &status, &handle); 6541c8fce27SZhang Rui if (result) 6551c8fce27SZhang Rui goto end; 6561c8fce27SZhang Rui 6572f857234SLv Zheng if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER)) { 6581c8fce27SZhang Rui printk(KERN_WARNING PREFIX 6591c8fce27SZhang Rui "Can not change Invalid GPE/Fixed Event status\n"); 6601c8fce27SZhang Rui return -EINVAL; 6611c8fce27SZhang Rui } 6621c8fce27SZhang Rui 6631c8fce27SZhang Rui if (index < num_gpes) { 6641c8fce27SZhang Rui if (!strcmp(buf, "disable\n") && 6651c8fce27SZhang Rui (status & ACPI_EVENT_FLAG_ENABLED)) 6661c8fce27SZhang Rui result = acpi_disable_gpe(handle, index); 6671c8fce27SZhang Rui else if (!strcmp(buf, "enable\n") && 6681c8fce27SZhang Rui !(status & ACPI_EVENT_FLAG_ENABLED)) 6691c8fce27SZhang Rui result = acpi_enable_gpe(handle, index); 6701c8fce27SZhang Rui else if (!strcmp(buf, "clear\n") && 67118864cc4SLv Zheng (status & ACPI_EVENT_FLAG_STATUS_SET)) 6721c8fce27SZhang Rui result = acpi_clear_gpe(handle, index); 67318864cc4SLv Zheng else if (!strcmp(buf, "mask\n")) 67418864cc4SLv Zheng result = acpi_mask_gpe(handle, index, TRUE); 67518864cc4SLv Zheng else if (!strcmp(buf, "unmask\n")) 67618864cc4SLv Zheng result = acpi_mask_gpe(handle, index, FALSE); 677c48b1565SLan Tianyu else if (!kstrtoul(buf, 0, &tmp)) 678c48b1565SLan Tianyu all_counters[index].count = tmp; 6791c8fce27SZhang Rui else 680c48b1565SLan Tianyu result = -EINVAL; 6811c8fce27SZhang Rui } else if (index < num_gpes + ACPI_NUM_FIXED_EVENTS) { 6821c8fce27SZhang Rui int event = index - num_gpes; 6831c8fce27SZhang Rui if (!strcmp(buf, "disable\n") && 68418864cc4SLv Zheng (status & ACPI_EVENT_FLAG_ENABLE_SET)) 6851c8fce27SZhang Rui result = acpi_disable_event(event, ACPI_NOT_ISR); 6861c8fce27SZhang Rui else if (!strcmp(buf, "enable\n") && 68718864cc4SLv Zheng !(status & ACPI_EVENT_FLAG_ENABLE_SET)) 6881c8fce27SZhang Rui result = acpi_enable_event(event, ACPI_NOT_ISR); 6891c8fce27SZhang Rui else if (!strcmp(buf, "clear\n") && 69018864cc4SLv Zheng (status & ACPI_EVENT_FLAG_STATUS_SET)) 6911c8fce27SZhang Rui result = acpi_clear_event(event); 692c48b1565SLan Tianyu else if (!kstrtoul(buf, 0, &tmp)) 693c48b1565SLan Tianyu all_counters[index].count = tmp; 6941c8fce27SZhang Rui else 695c48b1565SLan Tianyu result = -EINVAL; 6961c8fce27SZhang Rui } else 6971c8fce27SZhang Rui all_counters[index].count = strtoul(buf, NULL, 0); 6981c8fce27SZhang Rui 6991c8fce27SZhang Rui if (ACPI_FAILURE(result)) 7001c8fce27SZhang Rui result = -EINVAL; 7011c8fce27SZhang Rui end: 7021c8fce27SZhang Rui return result ? result : size; 7031c8fce27SZhang Rui } 7041c8fce27SZhang Rui 7051c8fce27SZhang Rui void acpi_irq_stats_init(void) 7061c8fce27SZhang Rui { 707a0fcdb23SLin Ming acpi_status status; 7081c8fce27SZhang Rui int i; 7091c8fce27SZhang Rui 7101c8fce27SZhang Rui if (all_counters) 7111c8fce27SZhang Rui return; 7121c8fce27SZhang Rui 7131c8fce27SZhang Rui num_gpes = acpi_current_gpe_count; 7141c8fce27SZhang Rui num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA; 7151c8fce27SZhang Rui 7161c8fce27SZhang Rui all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1), 7171c8fce27SZhang Rui GFP_KERNEL); 7181c8fce27SZhang Rui if (all_attrs == NULL) 7191c8fce27SZhang Rui return; 7201c8fce27SZhang Rui 7211c8fce27SZhang Rui all_counters = kzalloc(sizeof(struct event_counter) * (num_counters), 7221c8fce27SZhang Rui GFP_KERNEL); 7231c8fce27SZhang Rui if (all_counters == NULL) 7241c8fce27SZhang Rui goto fail; 7251c8fce27SZhang Rui 726644ef74eSLv Zheng status = acpi_install_global_event_handler(acpi_global_event_handler, NULL); 727a0fcdb23SLin Ming if (ACPI_FAILURE(status)) 728a0fcdb23SLin Ming goto fail; 729a0fcdb23SLin Ming 7301c8fce27SZhang Rui counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters), 7311c8fce27SZhang Rui GFP_KERNEL); 7321c8fce27SZhang Rui if (counter_attrs == NULL) 7331c8fce27SZhang Rui goto fail; 7341c8fce27SZhang Rui 7351c8fce27SZhang Rui for (i = 0; i < num_counters; ++i) { 7361c8fce27SZhang Rui char buffer[12]; 7371c8fce27SZhang Rui char *name; 7381c8fce27SZhang Rui 7391c8fce27SZhang Rui if (i < num_gpes) 7401c8fce27SZhang Rui sprintf(buffer, "gpe%02X", i); 7411c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_PMTIMER) 7421c8fce27SZhang Rui sprintf(buffer, "ff_pmtimer"); 7431c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_GLOBAL) 7441c8fce27SZhang Rui sprintf(buffer, "ff_gbl_lock"); 7451c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_POWER_BUTTON) 7461c8fce27SZhang Rui sprintf(buffer, "ff_pwr_btn"); 7471c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_SLEEP_BUTTON) 7481c8fce27SZhang Rui sprintf(buffer, "ff_slp_btn"); 7491c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_RTC) 7501c8fce27SZhang Rui sprintf(buffer, "ff_rt_clk"); 7511c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE) 7521c8fce27SZhang Rui sprintf(buffer, "gpe_all"); 7531c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) 7541c8fce27SZhang Rui sprintf(buffer, "sci"); 7551c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI_NOT) 7561c8fce27SZhang Rui sprintf(buffer, "sci_not"); 7571c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR) 7581c8fce27SZhang Rui sprintf(buffer, "error"); 7591c8fce27SZhang Rui else 7601c8fce27SZhang Rui sprintf(buffer, "bug%02X", i); 7611c8fce27SZhang Rui 762096a8aacSKees Cook name = kstrdup(buffer, GFP_KERNEL); 7631c8fce27SZhang Rui if (name == NULL) 7641c8fce27SZhang Rui goto fail; 7651c8fce27SZhang Rui 7661c8fce27SZhang Rui sysfs_attr_init(&counter_attrs[i].attr); 7671c8fce27SZhang Rui counter_attrs[i].attr.name = name; 7681c8fce27SZhang Rui counter_attrs[i].attr.mode = 0644; 7691c8fce27SZhang Rui counter_attrs[i].show = counter_show; 7701c8fce27SZhang Rui counter_attrs[i].store = counter_set; 7711c8fce27SZhang Rui 7721c8fce27SZhang Rui all_attrs[i] = &counter_attrs[i].attr; 7731c8fce27SZhang Rui } 7741c8fce27SZhang Rui 7751c8fce27SZhang Rui interrupt_stats_attr_group.attrs = all_attrs; 7761c8fce27SZhang Rui if (!sysfs_create_group(acpi_kobj, &interrupt_stats_attr_group)) 7771c8fce27SZhang Rui return; 7781c8fce27SZhang Rui 7791c8fce27SZhang Rui fail: 7801c8fce27SZhang Rui delete_gpe_attr_array(); 7811c8fce27SZhang Rui return; 7821c8fce27SZhang Rui } 7831c8fce27SZhang Rui 7841c8fce27SZhang Rui static void __exit interrupt_stats_exit(void) 7851c8fce27SZhang Rui { 7861c8fce27SZhang Rui sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group); 7871c8fce27SZhang Rui 7881c8fce27SZhang Rui delete_gpe_attr_array(); 7891c8fce27SZhang Rui 7901c8fce27SZhang Rui return; 7911c8fce27SZhang Rui } 7921c8fce27SZhang Rui 793362b6460SThomas Renninger static ssize_t 794362b6460SThomas Renninger acpi_show_profile(struct device *dev, struct device_attribute *attr, 795362b6460SThomas Renninger char *buf) 796362b6460SThomas Renninger { 797362b6460SThomas Renninger return sprintf(buf, "%d\n", acpi_gbl_FADT.preferred_profile); 798362b6460SThomas Renninger } 799362b6460SThomas Renninger 800362b6460SThomas Renninger static const struct device_attribute pm_profile_attr = 801362b6460SThomas Renninger __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL); 802362b6460SThomas Renninger 8033f8055c3SRafael J. Wysocki static ssize_t hotplug_enabled_show(struct kobject *kobj, 8043f8055c3SRafael J. Wysocki struct kobj_attribute *attr, char *buf) 8053f8055c3SRafael J. Wysocki { 8063f8055c3SRafael J. Wysocki struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj); 8073f8055c3SRafael J. Wysocki 8083f8055c3SRafael J. Wysocki return sprintf(buf, "%d\n", hotplug->enabled); 8093f8055c3SRafael J. Wysocki } 8103f8055c3SRafael J. Wysocki 8113f8055c3SRafael J. Wysocki static ssize_t hotplug_enabled_store(struct kobject *kobj, 8123f8055c3SRafael J. Wysocki struct kobj_attribute *attr, 8133f8055c3SRafael J. Wysocki const char *buf, size_t size) 8143f8055c3SRafael J. Wysocki { 8153f8055c3SRafael J. Wysocki struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj); 8163f8055c3SRafael J. Wysocki unsigned int val; 8173f8055c3SRafael J. Wysocki 8183f8055c3SRafael J. Wysocki if (kstrtouint(buf, 10, &val) || val > 1) 8193f8055c3SRafael J. Wysocki return -EINVAL; 8203f8055c3SRafael J. Wysocki 8213f8055c3SRafael J. Wysocki acpi_scan_hotplug_enabled(hotplug, val); 8223f8055c3SRafael J. Wysocki return size; 8233f8055c3SRafael J. Wysocki } 8243f8055c3SRafael J. Wysocki 8253f8055c3SRafael J. Wysocki static struct kobj_attribute hotplug_enabled_attr = 8263f8055c3SRafael J. Wysocki __ATTR(enabled, S_IRUGO | S_IWUSR, hotplug_enabled_show, 8273f8055c3SRafael J. Wysocki hotplug_enabled_store); 8283f8055c3SRafael J. Wysocki 8293f8055c3SRafael J. Wysocki static struct attribute *hotplug_profile_attrs[] = { 8303f8055c3SRafael J. Wysocki &hotplug_enabled_attr.attr, 8313f8055c3SRafael J. Wysocki NULL 8323f8055c3SRafael J. Wysocki }; 8333f8055c3SRafael J. Wysocki 834b09753ecSRafael J. Wysocki static struct kobj_type acpi_hotplug_profile_ktype = { 8353f8055c3SRafael J. Wysocki .sysfs_ops = &kobj_sysfs_ops, 8363f8055c3SRafael J. Wysocki .default_attrs = hotplug_profile_attrs, 8373f8055c3SRafael J. Wysocki }; 8383f8055c3SRafael J. Wysocki 8393f8055c3SRafael J. Wysocki void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, 8403f8055c3SRafael J. Wysocki const char *name) 8413f8055c3SRafael J. Wysocki { 8423f8055c3SRafael J. Wysocki int error; 8433f8055c3SRafael J. Wysocki 8443f8055c3SRafael J. Wysocki if (!hotplug_kobj) 8453f8055c3SRafael J. Wysocki goto err_out; 8463f8055c3SRafael J. Wysocki 847acd3e2c9SBjorn Helgaas error = kobject_init_and_add(&hotplug->kobj, 848acd3e2c9SBjorn Helgaas &acpi_hotplug_profile_ktype, hotplug_kobj, "%s", name); 8493f8055c3SRafael J. Wysocki if (error) 8503f8055c3SRafael J. Wysocki goto err_out; 8513f8055c3SRafael J. Wysocki 8523f8055c3SRafael J. Wysocki kobject_uevent(&hotplug->kobj, KOBJ_ADD); 8533f8055c3SRafael J. Wysocki return; 8543f8055c3SRafael J. Wysocki 8553f8055c3SRafael J. Wysocki err_out: 8563f8055c3SRafael J. Wysocki pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name); 8573f8055c3SRafael J. Wysocki } 8583f8055c3SRafael J. Wysocki 859683058e3SRafael J. Wysocki static ssize_t force_remove_show(struct kobject *kobj, 860683058e3SRafael J. Wysocki struct kobj_attribute *attr, char *buf) 861683058e3SRafael J. Wysocki { 862683058e3SRafael J. Wysocki return sprintf(buf, "%d\n", !!acpi_force_hot_remove); 863683058e3SRafael J. Wysocki } 864683058e3SRafael J. Wysocki 865683058e3SRafael J. Wysocki static ssize_t force_remove_store(struct kobject *kobj, 866683058e3SRafael J. Wysocki struct kobj_attribute *attr, 867683058e3SRafael J. Wysocki const char *buf, size_t size) 868683058e3SRafael J. Wysocki { 869683058e3SRafael J. Wysocki bool val; 870683058e3SRafael J. Wysocki int ret; 871683058e3SRafael J. Wysocki 872683058e3SRafael J. Wysocki ret = strtobool(buf, &val); 873683058e3SRafael J. Wysocki if (ret < 0) 874683058e3SRafael J. Wysocki return ret; 875683058e3SRafael J. Wysocki 876683058e3SRafael J. Wysocki lock_device_hotplug(); 877683058e3SRafael J. Wysocki acpi_force_hot_remove = val; 878683058e3SRafael J. Wysocki unlock_device_hotplug(); 879683058e3SRafael J. Wysocki return size; 880683058e3SRafael J. Wysocki } 881683058e3SRafael J. Wysocki 882683058e3SRafael J. Wysocki static const struct kobj_attribute force_remove_attr = 883683058e3SRafael J. Wysocki __ATTR(force_remove, S_IRUGO | S_IWUSR, force_remove_show, 884683058e3SRafael J. Wysocki force_remove_store); 885683058e3SRafael J. Wysocki 8861c8fce27SZhang Rui int __init acpi_sysfs_init(void) 8871c8fce27SZhang Rui { 8881c8fce27SZhang Rui int result; 8891c8fce27SZhang Rui 8901c8fce27SZhang Rui result = acpi_tables_sysfs_init(); 891362b6460SThomas Renninger if (result) 892362b6460SThomas Renninger return result; 8933f8055c3SRafael J. Wysocki 8943f8055c3SRafael J. Wysocki hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj); 895bc1e49dfSInsu Yun if (!hotplug_kobj) 896bc1e49dfSInsu Yun return -ENOMEM; 897bc1e49dfSInsu Yun 898683058e3SRafael J. Wysocki result = sysfs_create_file(hotplug_kobj, &force_remove_attr.attr); 899683058e3SRafael J. Wysocki if (result) 900683058e3SRafael J. Wysocki return result; 901683058e3SRafael J. Wysocki 902362b6460SThomas Renninger result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr); 9031c8fce27SZhang Rui return result; 9041c8fce27SZhang Rui } 905