xref: /openbmc/linux/drivers/acpi/sysfs.c (revision 4f855dce)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21c8fce27SZhang Rui /*
31c8fce27SZhang Rui  * sysfs.c - ACPI sysfs interface to userspace.
41c8fce27SZhang Rui  */
51c8fce27SZhang Rui 
67db8d1d9SRafael J. Wysocki #define pr_fmt(fmt) "ACPI: " fmt
77db8d1d9SRafael J. Wysocki 
844497fabSAndy Shevchenko #include <linux/acpi.h>
9d3121e64SAndy Shevchenko #include <linux/bitmap.h>
101c8fce27SZhang Rui #include <linux/init.h>
111c8fce27SZhang Rui #include <linux/kernel.h>
124612c7f1SChristophe JAILLET #include <linux/kstrtox.h>
131c8fce27SZhang Rui #include <linux/moduleparam.h>
141c8fce27SZhang Rui 
153f8055c3SRafael J. Wysocki #include "internal.h"
163f8055c3SRafael J. Wysocki 
171c8fce27SZhang Rui #ifdef CONFIG_ACPI_DEBUG
181c8fce27SZhang Rui /*
191c8fce27SZhang Rui  * ACPI debug sysfs I/F, including:
201c8fce27SZhang Rui  * /sys/modules/acpi/parameters/debug_layer
211c8fce27SZhang Rui  * /sys/modules/acpi/parameters/debug_level
221c8fce27SZhang Rui  * /sys/modules/acpi/parameters/trace_method_name
231c8fce27SZhang Rui  * /sys/modules/acpi/parameters/trace_state
241c8fce27SZhang Rui  * /sys/modules/acpi/parameters/trace_debug_layer
251c8fce27SZhang Rui  * /sys/modules/acpi/parameters/trace_debug_level
261c8fce27SZhang Rui  */
271c8fce27SZhang Rui 
281c8fce27SZhang Rui struct acpi_dlayer {
291c8fce27SZhang Rui 	const char *name;
301c8fce27SZhang Rui 	unsigned long value;
311c8fce27SZhang Rui };
321c8fce27SZhang Rui struct acpi_dlevel {
331c8fce27SZhang Rui 	const char *name;
341c8fce27SZhang Rui 	unsigned long value;
351c8fce27SZhang Rui };
361c8fce27SZhang Rui #define ACPI_DEBUG_INIT(v)	{ .name = #v, .value = v }
371c8fce27SZhang Rui 
381c8fce27SZhang Rui static const struct acpi_dlayer acpi_debug_layers[] = {
391c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_UTILITIES),
401c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_HARDWARE),
411c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_EVENTS),
421c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_TABLES),
431c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_NAMESPACE),
441c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_PARSER),
451c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_DISPATCHER),
461c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_EXECUTER),
471c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_RESOURCES),
481c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_CA_DEBUGGER),
491c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_OS_SERVICES),
501c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_CA_DISASSEMBLER),
511c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_COMPILER),
521c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_TOOLS),
531c8fce27SZhang Rui };
541c8fce27SZhang Rui 
551c8fce27SZhang Rui static const struct acpi_dlevel acpi_debug_levels[] = {
561c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_INIT),
571c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT),
581c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_INFO),
5993d98831SLv Zheng 	ACPI_DEBUG_INIT(ACPI_LV_REPAIR),
607901a052SLv Zheng 	ACPI_DEBUG_INIT(ACPI_LV_TRACE_POINT),
611c8fce27SZhang Rui 
621c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_INIT_NAMES),
631c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_PARSE),
641c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_LOAD),
651c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_DISPATCH),
661c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_EXEC),
671c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_NAMES),
681c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_OPREGION),
691c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_BFIELD),
701c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_TABLES),
711c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_VALUES),
721c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_OBJECTS),
731c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_RESOURCES),
741c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_USER_REQUESTS),
751c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_PACKAGE),
761c8fce27SZhang Rui 
771c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_ALLOCATIONS),
781c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_FUNCTIONS),
791c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_OPTIMIZATIONS),
801c8fce27SZhang Rui 
811c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_MUTEX),
821c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_THREADS),
831c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_IO),
841c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_INTERRUPTS),
851c8fce27SZhang Rui 
861c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_AML_DISASSEMBLE),
871c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_VERBOSE_INFO),
881c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_FULL_TABLES),
891c8fce27SZhang Rui 	ACPI_DEBUG_INIT(ACPI_LV_EVENTS),
901c8fce27SZhang Rui };
911c8fce27SZhang Rui 
param_get_debug_layer(char * buffer,const struct kernel_param * kp)92ec652b35SZhang Rui static int param_get_debug_layer(char *buffer, const struct kernel_param *kp)
931c8fce27SZhang Rui {
941c8fce27SZhang Rui 	int result = 0;
951c8fce27SZhang Rui 	int i;
961c8fce27SZhang Rui 
971c8fce27SZhang Rui 	result = sprintf(buffer, "%-25s\tHex        SET\n", "Description");
981c8fce27SZhang Rui 
991c8fce27SZhang Rui 	for (i = 0; i < ARRAY_SIZE(acpi_debug_layers); i++) {
1001c8fce27SZhang Rui 		result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n",
1011c8fce27SZhang Rui 				  acpi_debug_layers[i].name,
1021c8fce27SZhang Rui 				  acpi_debug_layers[i].value,
1031c8fce27SZhang Rui 				  (acpi_dbg_layer & acpi_debug_layers[i].value)
1041c8fce27SZhang Rui 				  ? '*' : ' ');
1051c8fce27SZhang Rui 	}
1061c8fce27SZhang Rui 	result +=
1071c8fce27SZhang Rui 	    sprintf(buffer + result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
1081c8fce27SZhang Rui 		    ACPI_ALL_DRIVERS,
1091c8fce27SZhang Rui 		    (acpi_dbg_layer & ACPI_ALL_DRIVERS) ==
1101c8fce27SZhang Rui 		    ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS)
1111c8fce27SZhang Rui 		    == 0 ? ' ' : '-');
1121c8fce27SZhang Rui 	result +=
1131c8fce27SZhang Rui 	    sprintf(buffer + result,
1141c8fce27SZhang Rui 		    "--\ndebug_layer = 0x%08X ( * = enabled)\n",
1151c8fce27SZhang Rui 		    acpi_dbg_layer);
1161c8fce27SZhang Rui 
1171c8fce27SZhang Rui 	return result;
1181c8fce27SZhang Rui }
1191c8fce27SZhang Rui 
param_get_debug_level(char * buffer,const struct kernel_param * kp)120ec652b35SZhang Rui static int param_get_debug_level(char *buffer, const struct kernel_param *kp)
1211c8fce27SZhang Rui {
1221c8fce27SZhang Rui 	int result = 0;
1231c8fce27SZhang Rui 	int i;
1241c8fce27SZhang Rui 
1251c8fce27SZhang Rui 	result = sprintf(buffer, "%-25s\tHex        SET\n", "Description");
1261c8fce27SZhang Rui 
1271c8fce27SZhang Rui 	for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) {
1281c8fce27SZhang Rui 		result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n",
1291c8fce27SZhang Rui 				  acpi_debug_levels[i].name,
1301c8fce27SZhang Rui 				  acpi_debug_levels[i].value,
1311c8fce27SZhang Rui 				  (acpi_dbg_level & acpi_debug_levels[i].value)
1321c8fce27SZhang Rui 				  ? '*' : ' ');
1331c8fce27SZhang Rui 	}
1341c8fce27SZhang Rui 	result +=
1351c8fce27SZhang Rui 	    sprintf(buffer + result, "--\ndebug_level = 0x%08X (* = enabled)\n",
1361c8fce27SZhang Rui 		    acpi_dbg_level);
1371c8fce27SZhang Rui 
1381c8fce27SZhang Rui 	return result;
1391c8fce27SZhang Rui }
1401c8fce27SZhang Rui 
1419c8b04beSVasiliy Kulikov static const struct kernel_param_ops param_ops_debug_layer = {
142ec652b35SZhang Rui 	.set = param_set_uint,
143ec652b35SZhang Rui 	.get = param_get_debug_layer,
144ec652b35SZhang Rui };
145ec652b35SZhang Rui 
1469c8b04beSVasiliy Kulikov static const struct kernel_param_ops param_ops_debug_level = {
147ec652b35SZhang Rui 	.set = param_set_uint,
148ec652b35SZhang Rui 	.get = param_get_debug_level,
149ec652b35SZhang Rui };
150ec652b35SZhang Rui 
151ec652b35SZhang Rui module_param_cb(debug_layer, &param_ops_debug_layer, &acpi_dbg_layer, 0644);
152ec652b35SZhang Rui module_param_cb(debug_level, &param_ops_debug_level, &acpi_dbg_level, 0644);
1531c8fce27SZhang Rui 
154a0186bcfSLv Zheng static char trace_method_name[1024];
1557901a052SLv Zheng 
param_set_trace_method_name(const char * val,const struct kernel_param * kp)1563e87ead4SColin Ian King static int param_set_trace_method_name(const char *val,
1573e87ead4SColin Ian King 				       const struct kernel_param *kp)
1587901a052SLv Zheng {
1597901a052SLv Zheng 	u32 saved_flags = 0;
160a0186bcfSLv Zheng 	bool is_abs_path = true;
1617901a052SLv Zheng 
162a0186bcfSLv Zheng 	if (*val != '\\')
163a0186bcfSLv Zheng 		is_abs_path = false;
164a0186bcfSLv Zheng 
165a0186bcfSLv Zheng 	if ((is_abs_path && strlen(val) > 1023) ||
166a0186bcfSLv Zheng 	    (!is_abs_path && strlen(val) > 1022)) {
1677901a052SLv Zheng 		pr_err("%s: string parameter too long\n", kp->name);
1687901a052SLv Zheng 		return -ENOSPC;
1697901a052SLv Zheng 	}
1707901a052SLv Zheng 
1717901a052SLv Zheng 	/*
1727901a052SLv Zheng 	 * It's not safe to update acpi_gbl_trace_method_name without
1737901a052SLv Zheng 	 * having the tracer stopped, so we save the original tracer
1747901a052SLv Zheng 	 * state and disable it.
1757901a052SLv Zheng 	 */
1767901a052SLv Zheng 	saved_flags = acpi_gbl_trace_flags;
1777901a052SLv Zheng 	(void)acpi_debug_trace(NULL,
1787901a052SLv Zheng 			       acpi_gbl_trace_dbg_level,
1797901a052SLv Zheng 			       acpi_gbl_trace_dbg_layer,
1807901a052SLv Zheng 			       0);
1817901a052SLv Zheng 
1827901a052SLv Zheng 	/* This is a hack.  We can't kmalloc in early boot. */
183a0186bcfSLv Zheng 	if (is_abs_path)
184a0186bcfSLv Zheng 		strcpy(trace_method_name, val);
185a0186bcfSLv Zheng 	else {
186a0186bcfSLv Zheng 		trace_method_name[0] = '\\';
187a0186bcfSLv Zheng 		strcpy(trace_method_name+1, val);
188a0186bcfSLv Zheng 	}
1897901a052SLv Zheng 
1907901a052SLv Zheng 	/* Restore the original tracer state */
1917901a052SLv Zheng 	(void)acpi_debug_trace(trace_method_name,
1927901a052SLv Zheng 			       acpi_gbl_trace_dbg_level,
1937901a052SLv Zheng 			       acpi_gbl_trace_dbg_layer,
1947901a052SLv Zheng 			       saved_flags);
1957901a052SLv Zheng 
1967901a052SLv Zheng 	return 0;
1977901a052SLv Zheng }
1987901a052SLv Zheng 
param_get_trace_method_name(char * buffer,const struct kernel_param * kp)1997901a052SLv Zheng static int param_get_trace_method_name(char *buffer, const struct kernel_param *kp)
2007901a052SLv Zheng {
20182d08d61SXu Panda 	return sysfs_emit(buffer, "%s\n", acpi_gbl_trace_method_name);
2027901a052SLv Zheng }
2037901a052SLv Zheng 
2047901a052SLv Zheng static const struct kernel_param_ops param_ops_trace_method = {
2057901a052SLv Zheng 	.set = param_set_trace_method_name,
2067901a052SLv Zheng 	.get = param_get_trace_method_name,
2077901a052SLv Zheng };
2087901a052SLv Zheng 
2097901a052SLv Zheng static const struct kernel_param_ops param_ops_trace_attrib = {
2107901a052SLv Zheng 	.set = param_set_uint,
2117901a052SLv Zheng 	.get = param_get_uint,
2127901a052SLv Zheng };
2137901a052SLv Zheng 
2147901a052SLv Zheng module_param_cb(trace_method_name, &param_ops_trace_method, &trace_method_name, 0644);
2157901a052SLv Zheng module_param_cb(trace_debug_layer, &param_ops_trace_attrib, &acpi_gbl_trace_dbg_layer, 0644);
2167901a052SLv Zheng module_param_cb(trace_debug_level, &param_ops_trace_attrib, &acpi_gbl_trace_dbg_level, 0644);
2171c8fce27SZhang Rui 
param_set_trace_state(const char * val,const struct kernel_param * kp)218e4dca7b7SKees Cook static int param_set_trace_state(const char *val,
219e4dca7b7SKees Cook 				 const struct kernel_param *kp)
2201c8fce27SZhang Rui {
2217901a052SLv Zheng 	acpi_status status;
2227901a052SLv Zheng 	const char *method = trace_method_name;
2237901a052SLv Zheng 	u32 flags = 0;
2241c8fce27SZhang Rui 
2257901a052SLv Zheng /* So "xxx-once" comparison should go prior than "xxx" comparison */
2267901a052SLv Zheng #define acpi_compare_param(val, key)	\
2277901a052SLv Zheng 	strncmp((val), (key), sizeof(key) - 1)
2281c8fce27SZhang Rui 
2297901a052SLv Zheng 	if (!acpi_compare_param(val, "enable")) {
2307901a052SLv Zheng 		method = NULL;
2317901a052SLv Zheng 		flags = ACPI_TRACE_ENABLED;
2327901a052SLv Zheng 	} else if (!acpi_compare_param(val, "disable"))
2337901a052SLv Zheng 		method = NULL;
2347901a052SLv Zheng 	else if (!acpi_compare_param(val, "method-once"))
2357901a052SLv Zheng 		flags = ACPI_TRACE_ENABLED | ACPI_TRACE_ONESHOT;
2367901a052SLv Zheng 	else if (!acpi_compare_param(val, "method"))
2377901a052SLv Zheng 		flags = ACPI_TRACE_ENABLED;
2387901a052SLv Zheng 	else if (!acpi_compare_param(val, "opcode-once"))
2397901a052SLv Zheng 		flags = ACPI_TRACE_ENABLED | ACPI_TRACE_ONESHOT | ACPI_TRACE_OPCODE;
2407901a052SLv Zheng 	else if (!acpi_compare_param(val, "opcode"))
2417901a052SLv Zheng 		flags = ACPI_TRACE_ENABLED | ACPI_TRACE_OPCODE;
2427901a052SLv Zheng 	else
2437901a052SLv Zheng 		return -EINVAL;
2441c8fce27SZhang Rui 
2457901a052SLv Zheng 	status = acpi_debug_trace(method,
2467901a052SLv Zheng 				  acpi_gbl_trace_dbg_level,
2477901a052SLv Zheng 				  acpi_gbl_trace_dbg_layer,
2487901a052SLv Zheng 				  flags);
2497901a052SLv Zheng 	if (ACPI_FAILURE(status))
2507901a052SLv Zheng 		return -EBUSY;
2511c8fce27SZhang Rui 
2527901a052SLv Zheng 	return 0;
2531c8fce27SZhang Rui }
2541c8fce27SZhang Rui 
param_get_trace_state(char * buffer,const struct kernel_param * kp)255e4dca7b7SKees Cook static int param_get_trace_state(char *buffer, const struct kernel_param *kp)
2561c8fce27SZhang Rui {
2577901a052SLv Zheng 	if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED))
2585ae318f6SXiongfeng Wang 		return sprintf(buffer, "disable\n");
2590023b28bSAndy Shevchenko 	if (!acpi_gbl_trace_method_name)
2600023b28bSAndy Shevchenko 		return sprintf(buffer, "enable\n");
2617901a052SLv Zheng 	if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT)
2625ae318f6SXiongfeng Wang 		return sprintf(buffer, "method-once\n");
2631c8fce27SZhang Rui 	else
2645ae318f6SXiongfeng Wang 		return sprintf(buffer, "method\n");
2651c8fce27SZhang Rui }
2661c8fce27SZhang Rui 
2671c8fce27SZhang Rui module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
2681c8fce27SZhang Rui 		  NULL, 0644);
2691c8fce27SZhang Rui #endif /* CONFIG_ACPI_DEBUG */
2701c8fce27SZhang Rui 
271aecad432SThomas Renninger 
272aecad432SThomas Renninger /* /sys/modules/acpi/parameters/aml_debug_output */
273aecad432SThomas Renninger 
274aecad432SThomas Renninger module_param_named(aml_debug_output, acpi_gbl_enable_aml_debug_object,
275481c1381SLv Zheng 		   byte, 0644);
276aecad432SThomas Renninger MODULE_PARM_DESC(aml_debug_output,
277aecad432SThomas Renninger 		 "To enable/disable the ACPI Debug Object output.");
278aecad432SThomas Renninger 
2791c8fce27SZhang Rui /* /sys/module/acpi/parameters/acpica_version */
param_get_acpica_version(char * buffer,const struct kernel_param * kp)280e4dca7b7SKees Cook static int param_get_acpica_version(char *buffer,
281e4dca7b7SKees Cook 				    const struct kernel_param *kp)
2821c8fce27SZhang Rui {
2831c8fce27SZhang Rui 	int result;
2841c8fce27SZhang Rui 
2855ae318f6SXiongfeng Wang 	result = sprintf(buffer, "%x\n", ACPI_CA_VERSION);
2861c8fce27SZhang Rui 
2871c8fce27SZhang Rui 	return result;
2881c8fce27SZhang Rui }
2891c8fce27SZhang Rui 
2901c8fce27SZhang Rui module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
2911c8fce27SZhang Rui 
2921c8fce27SZhang Rui /*
2931c8fce27SZhang Rui  * ACPI table sysfs I/F:
2941c8fce27SZhang Rui  * /sys/firmware/acpi/tables/
2957dae6326STony Luck  * /sys/firmware/acpi/tables/data/
2961c8fce27SZhang Rui  * /sys/firmware/acpi/tables/dynamic/
2971c8fce27SZhang Rui  */
2981c8fce27SZhang Rui 
2991c8fce27SZhang Rui static LIST_HEAD(acpi_table_attr_list);
3001c8fce27SZhang Rui static struct kobject *tables_kobj;
3017dae6326STony Luck static struct kobject *tables_data_kobj;
3021c8fce27SZhang Rui static struct kobject *dynamic_tables_kobj;
3033f8055c3SRafael J. Wysocki static struct kobject *hotplug_kobj;
3041c8fce27SZhang Rui 
305914c6194SLv Zheng #define ACPI_MAX_TABLE_INSTANCES	999
306914c6194SLv Zheng #define ACPI_INST_SIZE			4 /* including trailing 0 */
307914c6194SLv Zheng 
3081c8fce27SZhang Rui struct acpi_table_attr {
3091c8fce27SZhang Rui 	struct bin_attribute attr;
31032786755SBob Moore 	char name[ACPI_NAMESEG_SIZE];
3111c8fce27SZhang Rui 	int instance;
31232786755SBob Moore 	char filename[ACPI_NAMESEG_SIZE+ACPI_INST_SIZE];
3131c8fce27SZhang Rui 	struct list_head node;
3141c8fce27SZhang Rui };
3151c8fce27SZhang Rui 
3167dae6326STony Luck struct acpi_data_attr {
3177dae6326STony Luck 	struct bin_attribute attr;
3187dae6326STony Luck 	u64	addr;
3197dae6326STony Luck };
3207dae6326STony Luck 
acpi_table_show(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t offset,size_t count)3211c8fce27SZhang Rui static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj,
3221c8fce27SZhang Rui 			       struct bin_attribute *bin_attr, char *buf,
3231c8fce27SZhang Rui 			       loff_t offset, size_t count)
3241c8fce27SZhang Rui {
3251c8fce27SZhang Rui 	struct acpi_table_attr *table_attr =
3261c8fce27SZhang Rui 	    container_of(bin_attr, struct acpi_table_attr, attr);
3271c8fce27SZhang Rui 	struct acpi_table_header *table_header = NULL;
3281c8fce27SZhang Rui 	acpi_status status;
3290de0e198SDan Williams 	ssize_t rc;
3301c8fce27SZhang Rui 
331914c6194SLv Zheng 	status = acpi_get_table(table_attr->name, table_attr->instance,
332914c6194SLv Zheng 				&table_header);
3331c8fce27SZhang Rui 	if (ACPI_FAILURE(status))
3341c8fce27SZhang Rui 		return -ENODEV;
3351c8fce27SZhang Rui 
3360de0e198SDan Williams 	rc = memory_read_from_buffer(buf, count, &offset, table_header,
3370de0e198SDan Williams 			table_header->length);
3380de0e198SDan Williams 	acpi_put_table(table_header);
3390de0e198SDan Williams 	return rc;
3401c8fce27SZhang Rui }
3411c8fce27SZhang Rui 
acpi_table_attr_init(struct kobject * tables_obj,struct acpi_table_attr * table_attr,struct acpi_table_header * table_header)342914c6194SLv Zheng static int acpi_table_attr_init(struct kobject *tables_obj,
343914c6194SLv Zheng 				struct acpi_table_attr *table_attr,
3441c8fce27SZhang Rui 				struct acpi_table_header *table_header)
3451c8fce27SZhang Rui {
3461c8fce27SZhang Rui 	struct acpi_table_header *header = NULL;
3471c8fce27SZhang Rui 	struct acpi_table_attr *attr = NULL;
348914c6194SLv Zheng 	char instance_str[ACPI_INST_SIZE];
3491c8fce27SZhang Rui 
3501c8fce27SZhang Rui 	sysfs_attr_init(&table_attr->attr.attr);
3515599fb69SBob Moore 	ACPI_COPY_NAMESEG(table_attr->name, table_header->signature);
3521c8fce27SZhang Rui 
3531c8fce27SZhang Rui 	list_for_each_entry(attr, &acpi_table_attr_list, node) {
3545599fb69SBob Moore 		if (ACPI_COMPARE_NAMESEG(table_attr->name, attr->name))
3551c8fce27SZhang Rui 			if (table_attr->instance < attr->instance)
3561c8fce27SZhang Rui 				table_attr->instance = attr->instance;
3571c8fce27SZhang Rui 	}
3581c8fce27SZhang Rui 	table_attr->instance++;
359914c6194SLv Zheng 	if (table_attr->instance > ACPI_MAX_TABLE_INSTANCES) {
36086ca3b0aSHanjun Guo 		pr_warn("%4.4s: too many table instances\n", table_attr->name);
361914c6194SLv Zheng 		return -ERANGE;
362914c6194SLv Zheng 	}
3631c8fce27SZhang Rui 
3645599fb69SBob Moore 	ACPI_COPY_NAMESEG(table_attr->filename, table_header->signature);
36532786755SBob Moore 	table_attr->filename[ACPI_NAMESEG_SIZE] = '\0';
3661c8fce27SZhang Rui 	if (table_attr->instance > 1 || (table_attr->instance == 1 &&
3671c8fce27SZhang Rui 					 !acpi_get_table
368914c6194SLv Zheng 					 (table_header->signature, 2, &header))) {
369914c6194SLv Zheng 		snprintf(instance_str, sizeof(instance_str), "%u",
3701c8fce27SZhang Rui 			 table_attr->instance);
371914c6194SLv Zheng 		strcat(table_attr->filename, instance_str);
372914c6194SLv Zheng 	}
3731c8fce27SZhang Rui 
374083ca8c4SDaisuke HATAYAMA 	table_attr->attr.size = table_header->length;
3751c8fce27SZhang Rui 	table_attr->attr.read = acpi_table_show;
376914c6194SLv Zheng 	table_attr->attr.attr.name = table_attr->filename;
3771c8fce27SZhang Rui 	table_attr->attr.attr.mode = 0400;
3781c8fce27SZhang Rui 
379914c6194SLv Zheng 	return sysfs_create_bin_file(tables_obj, &table_attr->attr);
3801c8fce27SZhang Rui }
3811c8fce27SZhang Rui 
acpi_sysfs_table_handler(u32 event,void * table,void * context)38268bdb677SOctavian Purdila acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context)
3831c8fce27SZhang Rui {
3841c8fce27SZhang Rui 	struct acpi_table_attr *table_attr;
3851c8fce27SZhang Rui 
3861c8fce27SZhang Rui 	switch (event) {
387307ecb0aSLv Zheng 	case ACPI_TABLE_EVENT_INSTALL:
388b272c059SAndy Shevchenko 		table_attr = kzalloc(sizeof(*table_attr), GFP_KERNEL);
3891c8fce27SZhang Rui 		if (!table_attr)
3901c8fce27SZhang Rui 			return AE_NO_MEMORY;
3911c8fce27SZhang Rui 
392914c6194SLv Zheng 		if (acpi_table_attr_init(dynamic_tables_kobj,
393914c6194SLv Zheng 					 table_attr, table)) {
3941c8fce27SZhang Rui 			kfree(table_attr);
3951c8fce27SZhang Rui 			return AE_ERROR;
396914c6194SLv Zheng 		}
3971c8fce27SZhang Rui 		list_add_tail(&table_attr->node, &acpi_table_attr_list);
3981c8fce27SZhang Rui 		break;
399307ecb0aSLv Zheng 	case ACPI_TABLE_EVENT_LOAD:
4001c8fce27SZhang Rui 	case ACPI_TABLE_EVENT_UNLOAD:
401307ecb0aSLv Zheng 	case ACPI_TABLE_EVENT_UNINSTALL:
4021c8fce27SZhang Rui 		/*
4031c8fce27SZhang Rui 		 * we do not need to do anything right now
4041c8fce27SZhang Rui 		 * because the table is not deleted from the
4051c8fce27SZhang Rui 		 * global table list when unloading it.
4061c8fce27SZhang Rui 		 */
4071c8fce27SZhang Rui 		break;
4081c8fce27SZhang Rui 	default:
4091c8fce27SZhang Rui 		return AE_BAD_PARAMETER;
4101c8fce27SZhang Rui 	}
4111c8fce27SZhang Rui 	return AE_OK;
4121c8fce27SZhang Rui }
4131c8fce27SZhang Rui 
acpi_data_show(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t offset,size_t count)4147dae6326STony Luck static ssize_t acpi_data_show(struct file *filp, struct kobject *kobj,
4157dae6326STony Luck 			      struct bin_attribute *bin_attr, char *buf,
4167dae6326STony Luck 			      loff_t offset, size_t count)
4177dae6326STony Luck {
4187dae6326STony Luck 	struct acpi_data_attr *data_attr;
4191bbc2178SLorenzo Pieralisi 	void __iomem *base;
4201bbc2178SLorenzo Pieralisi 	ssize_t size;
4217dae6326STony Luck 
4227dae6326STony Luck 	data_attr = container_of(bin_attr, struct acpi_data_attr, attr);
4231bbc2178SLorenzo Pieralisi 	size = data_attr->attr.size;
4247dae6326STony Luck 
4251bbc2178SLorenzo Pieralisi 	if (offset < 0)
4261bbc2178SLorenzo Pieralisi 		return -EINVAL;
4271bbc2178SLorenzo Pieralisi 
4281bbc2178SLorenzo Pieralisi 	if (offset >= size)
4291bbc2178SLorenzo Pieralisi 		return 0;
4301bbc2178SLorenzo Pieralisi 
4311bbc2178SLorenzo Pieralisi 	if (count > size - offset)
4321bbc2178SLorenzo Pieralisi 		count = size - offset;
4331bbc2178SLorenzo Pieralisi 
4341bbc2178SLorenzo Pieralisi 	base = acpi_os_map_iomem(data_attr->addr, size);
4357dae6326STony Luck 	if (!base)
4367dae6326STony Luck 		return -ENOMEM;
4377dae6326STony Luck 
4381bbc2178SLorenzo Pieralisi 	memcpy_fromio(buf, base + offset, count);
4391bbc2178SLorenzo Pieralisi 
4401bbc2178SLorenzo Pieralisi 	acpi_os_unmap_iomem(base, size);
4411bbc2178SLorenzo Pieralisi 
4421bbc2178SLorenzo Pieralisi 	return count;
4437dae6326STony Luck }
4447dae6326STony Luck 
acpi_bert_data_init(void * th,struct acpi_data_attr * data_attr)4457dae6326STony Luck static int acpi_bert_data_init(void *th, struct acpi_data_attr *data_attr)
4467dae6326STony Luck {
4477dae6326STony Luck 	struct acpi_table_bert *bert = th;
4487dae6326STony Luck 
4497dae6326STony Luck 	if (bert->header.length < sizeof(struct acpi_table_bert) ||
4507dae6326STony Luck 	    bert->region_length < sizeof(struct acpi_hest_generic_status)) {
4517dae6326STony Luck 		kfree(data_attr);
4527dae6326STony Luck 		return -EINVAL;
4537dae6326STony Luck 	}
4547dae6326STony Luck 	data_attr->addr = bert->address;
4557dae6326STony Luck 	data_attr->attr.size = bert->region_length;
4567dae6326STony Luck 	data_attr->attr.attr.name = "BERT";
4577dae6326STony Luck 
4587dae6326STony Luck 	return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr);
4597dae6326STony Luck }
4607dae6326STony Luck 
acpi_ccel_data_init(void * th,struct acpi_data_attr * data_attr)461*4f855dceSKuppuswamy Sathyanarayanan static int acpi_ccel_data_init(void *th, struct acpi_data_attr *data_attr)
462*4f855dceSKuppuswamy Sathyanarayanan {
463*4f855dceSKuppuswamy Sathyanarayanan 	struct acpi_table_ccel *ccel = th;
464*4f855dceSKuppuswamy Sathyanarayanan 
465*4f855dceSKuppuswamy Sathyanarayanan 	if (ccel->header.length < sizeof(struct acpi_table_ccel) ||
466*4f855dceSKuppuswamy Sathyanarayanan 	    !ccel->log_area_start_address || !ccel->log_area_minimum_length) {
467*4f855dceSKuppuswamy Sathyanarayanan 		kfree(data_attr);
468*4f855dceSKuppuswamy Sathyanarayanan 		return -EINVAL;
469*4f855dceSKuppuswamy Sathyanarayanan 	}
470*4f855dceSKuppuswamy Sathyanarayanan 	data_attr->addr = ccel->log_area_start_address;
471*4f855dceSKuppuswamy Sathyanarayanan 	data_attr->attr.size = ccel->log_area_minimum_length;
472*4f855dceSKuppuswamy Sathyanarayanan 	data_attr->attr.attr.name = "CCEL";
473*4f855dceSKuppuswamy Sathyanarayanan 
474*4f855dceSKuppuswamy Sathyanarayanan 	return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr);
475*4f855dceSKuppuswamy Sathyanarayanan }
476*4f855dceSKuppuswamy Sathyanarayanan 
4777dae6326STony Luck static struct acpi_data_obj {
4787dae6326STony Luck 	char *name;
4797dae6326STony Luck 	int (*fn)(void *, struct acpi_data_attr *);
4807dae6326STony Luck } acpi_data_objs[] = {
4817dae6326STony Luck 	{ ACPI_SIG_BERT, acpi_bert_data_init },
482*4f855dceSKuppuswamy Sathyanarayanan 	{ ACPI_SIG_CCEL, acpi_ccel_data_init },
4837dae6326STony Luck };
4847dae6326STony Luck 
4857dae6326STony Luck #define NUM_ACPI_DATA_OBJS ARRAY_SIZE(acpi_data_objs)
4867dae6326STony Luck 
acpi_table_data_init(struct acpi_table_header * th)4877dae6326STony Luck static int acpi_table_data_init(struct acpi_table_header *th)
4887dae6326STony Luck {
4897dae6326STony Luck 	struct acpi_data_attr *data_attr;
4907dae6326STony Luck 	int i;
4917dae6326STony Luck 
4927dae6326STony Luck 	for (i = 0; i < NUM_ACPI_DATA_OBJS; i++) {
4935599fb69SBob Moore 		if (ACPI_COMPARE_NAMESEG(th->signature, acpi_data_objs[i].name)) {
4947dae6326STony Luck 			data_attr = kzalloc(sizeof(*data_attr), GFP_KERNEL);
4957dae6326STony Luck 			if (!data_attr)
4967dae6326STony Luck 				return -ENOMEM;
4977dae6326STony Luck 			sysfs_attr_init(&data_attr->attr.attr);
4987dae6326STony Luck 			data_attr->attr.read = acpi_data_show;
4997dae6326STony Luck 			data_attr->attr.attr.mode = 0400;
5007dae6326STony Luck 			return acpi_data_objs[i].fn(th, data_attr);
5017dae6326STony Luck 		}
5027dae6326STony Luck 	}
5037dae6326STony Luck 	return 0;
5047dae6326STony Luck }
5057dae6326STony Luck 
acpi_tables_sysfs_init(void)5061c8fce27SZhang Rui static int acpi_tables_sysfs_init(void)
5071c8fce27SZhang Rui {
5081c8fce27SZhang Rui 	struct acpi_table_attr *table_attr;
5091c8fce27SZhang Rui 	struct acpi_table_header *table_header = NULL;
510de03beedSJeremy Compostella 	int table_index;
511de03beedSJeremy Compostella 	acpi_status status;
512de03beedSJeremy Compostella 	int ret;
5131c8fce27SZhang Rui 
5141c8fce27SZhang Rui 	tables_kobj = kobject_create_and_add("tables", acpi_kobj);
5151c8fce27SZhang Rui 	if (!tables_kobj)
5161c8fce27SZhang Rui 		goto err;
5171c8fce27SZhang Rui 
5187dae6326STony Luck 	tables_data_kobj = kobject_create_and_add("data", tables_kobj);
5197dae6326STony Luck 	if (!tables_data_kobj)
5207dae6326STony Luck 		goto err_tables_data;
5217dae6326STony Luck 
5221c8fce27SZhang Rui 	dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj);
5231c8fce27SZhang Rui 	if (!dynamic_tables_kobj)
5241c8fce27SZhang Rui 		goto err_dynamic_tables;
5251c8fce27SZhang Rui 
526de03beedSJeremy Compostella 	for (table_index = 0;; table_index++) {
527de03beedSJeremy Compostella 		status = acpi_get_table_by_index(table_index, &table_header);
528de03beedSJeremy Compostella 
529de03beedSJeremy Compostella 		if (status == AE_BAD_PARAMETER)
530de03beedSJeremy Compostella 			break;
531de03beedSJeremy Compostella 
532de03beedSJeremy Compostella 		if (ACPI_FAILURE(status))
533de03beedSJeremy Compostella 			continue;
534de03beedSJeremy Compostella 
535de03beedSJeremy Compostella 		table_attr = kzalloc(sizeof(*table_attr), GFP_KERNEL);
5361c8fce27SZhang Rui 		if (!table_attr)
5371c8fce27SZhang Rui 			return -ENOMEM;
5381c8fce27SZhang Rui 
539914c6194SLv Zheng 		ret = acpi_table_attr_init(tables_kobj,
540914c6194SLv Zheng 					   table_attr, table_header);
541de03beedSJeremy Compostella 		if (ret) {
5421c8fce27SZhang Rui 			kfree(table_attr);
543de03beedSJeremy Compostella 			return ret;
5441c8fce27SZhang Rui 		}
545de03beedSJeremy Compostella 		list_add_tail(&table_attr->node, &acpi_table_attr_list);
5467dae6326STony Luck 		acpi_table_data_init(table_header);
547de03beedSJeremy Compostella 	}
548de03beedSJeremy Compostella 
5491c8fce27SZhang Rui 	kobject_uevent(tables_kobj, KOBJ_ADD);
5507dae6326STony Luck 	kobject_uevent(tables_data_kobj, KOBJ_ADD);
5511c8fce27SZhang Rui 	kobject_uevent(dynamic_tables_kobj, KOBJ_ADD);
5521c8fce27SZhang Rui 
55368bdb677SOctavian Purdila 	return 0;
5541c8fce27SZhang Rui err_dynamic_tables:
5557dae6326STony Luck 	kobject_put(tables_data_kobj);
5567dae6326STony Luck err_tables_data:
5571c8fce27SZhang Rui 	kobject_put(tables_kobj);
5581c8fce27SZhang Rui err:
5591c8fce27SZhang Rui 	return -ENOMEM;
5601c8fce27SZhang Rui }
5611c8fce27SZhang Rui 
5621c8fce27SZhang Rui /*
5631c8fce27SZhang Rui  * Detailed ACPI IRQ counters:
5641c8fce27SZhang Rui  * /sys/firmware/acpi/interrupts/
5651c8fce27SZhang Rui  */
5661c8fce27SZhang Rui 
5671c8fce27SZhang Rui u32 acpi_irq_handled;
5681c8fce27SZhang Rui u32 acpi_irq_not_handled;
5691c8fce27SZhang Rui 
5701c8fce27SZhang Rui #define COUNT_GPE 0
5711c8fce27SZhang Rui #define COUNT_SCI 1		/* acpi_irq_handled */
5721c8fce27SZhang Rui #define COUNT_SCI_NOT 2		/* acpi_irq_not_handled */
5731c8fce27SZhang Rui #define COUNT_ERROR 3		/* other */
5741c8fce27SZhang Rui #define NUM_COUNTERS_EXTRA 4
5751c8fce27SZhang Rui 
5761c8fce27SZhang Rui struct event_counter {
5771c8fce27SZhang Rui 	u32 count;
5781c8fce27SZhang Rui 	u32 flags;
5791c8fce27SZhang Rui };
5801c8fce27SZhang Rui 
5811c8fce27SZhang Rui static struct event_counter *all_counters;
5821c8fce27SZhang Rui static u32 num_gpes;
5831c8fce27SZhang Rui static u32 num_counters;
5841c8fce27SZhang Rui static struct attribute **all_attrs;
5851c8fce27SZhang Rui static u32 acpi_gpe_count;
5861c8fce27SZhang Rui 
5871c8fce27SZhang Rui static struct attribute_group interrupt_stats_attr_group = {
5881c8fce27SZhang Rui 	.name = "interrupts",
5891c8fce27SZhang Rui };
5901c8fce27SZhang Rui 
5911c8fce27SZhang Rui static struct kobj_attribute *counter_attrs;
5921c8fce27SZhang Rui 
delete_gpe_attr_array(void)5931c8fce27SZhang Rui static void delete_gpe_attr_array(void)
5941c8fce27SZhang Rui {
5951c8fce27SZhang Rui 	struct event_counter *tmp = all_counters;
5961c8fce27SZhang Rui 
5971c8fce27SZhang Rui 	all_counters = NULL;
5981c8fce27SZhang Rui 	kfree(tmp);
5991c8fce27SZhang Rui 
6001c8fce27SZhang Rui 	if (counter_attrs) {
6011c8fce27SZhang Rui 		int i;
6021c8fce27SZhang Rui 
6031c8fce27SZhang Rui 		for (i = 0; i < num_gpes; i++)
6041c8fce27SZhang Rui 			kfree(counter_attrs[i].attr.name);
6051c8fce27SZhang Rui 
6061c8fce27SZhang Rui 		kfree(counter_attrs);
6071c8fce27SZhang Rui 	}
6081c8fce27SZhang Rui 	kfree(all_attrs);
6091c8fce27SZhang Rui }
6101c8fce27SZhang Rui 
gpe_count(u32 gpe_number)611a0fcdb23SLin Ming static void gpe_count(u32 gpe_number)
6121c8fce27SZhang Rui {
6131c8fce27SZhang Rui 	acpi_gpe_count++;
6141c8fce27SZhang Rui 
6151c8fce27SZhang Rui 	if (!all_counters)
6161c8fce27SZhang Rui 		return;
6171c8fce27SZhang Rui 
6181c8fce27SZhang Rui 	if (gpe_number < num_gpes)
6191c8fce27SZhang Rui 		all_counters[gpe_number].count++;
6201c8fce27SZhang Rui 	else
6211c8fce27SZhang Rui 		all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS +
6221c8fce27SZhang Rui 			     COUNT_ERROR].count++;
6231c8fce27SZhang Rui }
6241c8fce27SZhang Rui 
fixed_event_count(u32 event_number)625a0fcdb23SLin Ming static void fixed_event_count(u32 event_number)
6261c8fce27SZhang Rui {
6271c8fce27SZhang Rui 	if (!all_counters)
6281c8fce27SZhang Rui 		return;
6291c8fce27SZhang Rui 
6301c8fce27SZhang Rui 	if (event_number < ACPI_NUM_FIXED_EVENTS)
6311c8fce27SZhang Rui 		all_counters[num_gpes + event_number].count++;
6321c8fce27SZhang Rui 	else
6331c8fce27SZhang Rui 		all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS +
6341c8fce27SZhang Rui 			     COUNT_ERROR].count++;
6351c8fce27SZhang Rui }
6361c8fce27SZhang Rui 
acpi_global_event_handler(u32 event_type,acpi_handle device,u32 event_number,void * context)637644ef74eSLv Zheng static void acpi_global_event_handler(u32 event_type, acpi_handle device,
638a0fcdb23SLin Ming 	u32 event_number, void *context)
639a0fcdb23SLin Ming {
6407db8d1d9SRafael J. Wysocki 	if (event_type == ACPI_EVENT_TYPE_GPE) {
641a0fcdb23SLin Ming 		gpe_count(event_number);
6427db8d1d9SRafael J. Wysocki 		pr_debug("GPE event 0x%02x\n", event_number);
6437db8d1d9SRafael J. Wysocki 	} else if (event_type == ACPI_EVENT_TYPE_FIXED) {
644a0fcdb23SLin Ming 		fixed_event_count(event_number);
6457db8d1d9SRafael J. Wysocki 		pr_debug("Fixed event 0x%02x\n", event_number);
6467db8d1d9SRafael J. Wysocki 	} else {
6477db8d1d9SRafael J. Wysocki 		pr_debug("Other event 0x%02x\n", event_number);
6487db8d1d9SRafael J. Wysocki 	}
649a0fcdb23SLin Ming }
650a0fcdb23SLin Ming 
get_status(u32 index,acpi_event_status * ret,acpi_handle * handle)6513fd16d70SRafael J. Wysocki static int get_status(u32 index, acpi_event_status *ret,
6521c8fce27SZhang Rui 		      acpi_handle *handle)
6531c8fce27SZhang Rui {
6543fd16d70SRafael J. Wysocki 	acpi_status status;
6551c8fce27SZhang Rui 
6561c8fce27SZhang Rui 	if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS)
657f18ebc21SDan Carpenter 		return -EINVAL;
6581c8fce27SZhang Rui 
6591c8fce27SZhang Rui 	if (index < num_gpes) {
6603fd16d70SRafael J. Wysocki 		status = acpi_get_gpe_device(index, handle);
6613fd16d70SRafael J. Wysocki 		if (ACPI_FAILURE(status)) {
662e6a55ccbSRafael J. Wysocki 			pr_warn("Invalid GPE 0x%x", index);
6633fd16d70SRafael J. Wysocki 			return -ENXIO;
6641c8fce27SZhang Rui 		}
6653fd16d70SRafael J. Wysocki 		status = acpi_get_gpe_status(*handle, index, ret);
6663fd16d70SRafael J. Wysocki 	} else {
6673fd16d70SRafael J. Wysocki 		status = acpi_get_event_status(index - num_gpes, ret);
6683fd16d70SRafael J. Wysocki 	}
6693fd16d70SRafael J. Wysocki 	if (ACPI_FAILURE(status))
6703fd16d70SRafael J. Wysocki 		return -EIO;
6711c8fce27SZhang Rui 
6723fd16d70SRafael J. Wysocki 	return 0;
6731c8fce27SZhang Rui }
6741c8fce27SZhang Rui 
counter_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)6751c8fce27SZhang Rui static ssize_t counter_show(struct kobject *kobj,
6761c8fce27SZhang Rui 			    struct kobj_attribute *attr, char *buf)
6771c8fce27SZhang Rui {
6781c8fce27SZhang Rui 	int index = attr - counter_attrs;
6791c8fce27SZhang Rui 	int size;
6801c8fce27SZhang Rui 	acpi_handle handle;
6811c8fce27SZhang Rui 	acpi_event_status status;
6821c8fce27SZhang Rui 	int result = 0;
6831c8fce27SZhang Rui 
6841c8fce27SZhang Rui 	all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI].count =
6851c8fce27SZhang Rui 	    acpi_irq_handled;
6861c8fce27SZhang Rui 	all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI_NOT].count =
6871c8fce27SZhang Rui 	    acpi_irq_not_handled;
6881c8fce27SZhang Rui 	all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE].count =
6891c8fce27SZhang Rui 	    acpi_gpe_count;
6907b1a1322SNan Li 	size = sprintf(buf, "%8u", all_counters[index].count);
6911c8fce27SZhang Rui 
6921c8fce27SZhang Rui 	/* "gpe_all" or "sci" */
6931c8fce27SZhang Rui 	if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS)
6941c8fce27SZhang Rui 		goto end;
6951c8fce27SZhang Rui 
6961c8fce27SZhang Rui 	result = get_status(index, &status, &handle);
6971c8fce27SZhang Rui 	if (result)
6981c8fce27SZhang Rui 		goto end;
6991c8fce27SZhang Rui 
70018864cc4SLv Zheng 	if (status & ACPI_EVENT_FLAG_ENABLE_SET)
70118864cc4SLv Zheng 		size += sprintf(buf + size, "  EN");
70218864cc4SLv Zheng 	else
70318864cc4SLv Zheng 		size += sprintf(buf + size, "    ");
70418864cc4SLv Zheng 	if (status & ACPI_EVENT_FLAG_STATUS_SET)
70518864cc4SLv Zheng 		size += sprintf(buf + size, " STS");
70618864cc4SLv Zheng 	else
70718864cc4SLv Zheng 		size += sprintf(buf + size, "    ");
70818864cc4SLv Zheng 
7092f857234SLv Zheng 	if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER))
7101c8fce27SZhang Rui 		size += sprintf(buf + size, " invalid     ");
7111c8fce27SZhang Rui 	else if (status & ACPI_EVENT_FLAG_ENABLED)
7121c8fce27SZhang Rui 		size += sprintf(buf + size, " enabled     ");
7131c8fce27SZhang Rui 	else if (status & ACPI_EVENT_FLAG_WAKE_ENABLED)
7141c8fce27SZhang Rui 		size += sprintf(buf + size, " wake_enabled");
7151c8fce27SZhang Rui 	else
7161c8fce27SZhang Rui 		size += sprintf(buf + size, " disabled    ");
71718864cc4SLv Zheng 	if (status & ACPI_EVENT_FLAG_MASKED)
71818864cc4SLv Zheng 		size += sprintf(buf + size, " masked  ");
71918864cc4SLv Zheng 	else
72018864cc4SLv Zheng 		size += sprintf(buf + size, " unmasked");
7211c8fce27SZhang Rui 
7221c8fce27SZhang Rui end:
7231c8fce27SZhang Rui 	size += sprintf(buf + size, "\n");
7241c8fce27SZhang Rui 	return result ? result : size;
7251c8fce27SZhang Rui }
7261c8fce27SZhang Rui 
7271c8fce27SZhang Rui /*
7281c8fce27SZhang Rui  * counter_set() sets the specified counter.
7291c8fce27SZhang Rui  * setting the total "sci" file to any value clears all counters.
7301c8fce27SZhang Rui  * enable/disable/clear a gpe/fixed event in user space.
7311c8fce27SZhang Rui  */
counter_set(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t size)7321c8fce27SZhang Rui static ssize_t counter_set(struct kobject *kobj,
7331c8fce27SZhang Rui 			   struct kobj_attribute *attr, const char *buf,
7341c8fce27SZhang Rui 			   size_t size)
7351c8fce27SZhang Rui {
7361c8fce27SZhang Rui 	int index = attr - counter_attrs;
7371c8fce27SZhang Rui 	acpi_event_status status;
7381c8fce27SZhang Rui 	acpi_handle handle;
7391c8fce27SZhang Rui 	int result = 0;
740c48b1565SLan Tianyu 	unsigned long tmp;
7411c8fce27SZhang Rui 
7421c8fce27SZhang Rui 	if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) {
7431c8fce27SZhang Rui 		int i;
7441c8fce27SZhang Rui 		for (i = 0; i < num_counters; ++i)
7451c8fce27SZhang Rui 			all_counters[i].count = 0;
7461c8fce27SZhang Rui 		acpi_gpe_count = 0;
7471c8fce27SZhang Rui 		acpi_irq_handled = 0;
7481c8fce27SZhang Rui 		acpi_irq_not_handled = 0;
7491c8fce27SZhang Rui 		goto end;
7501c8fce27SZhang Rui 	}
7511c8fce27SZhang Rui 
7521c8fce27SZhang Rui 	/* show the event status for both GPEs and Fixed Events */
7531c8fce27SZhang Rui 	result = get_status(index, &status, &handle);
7541c8fce27SZhang Rui 	if (result)
7551c8fce27SZhang Rui 		goto end;
7561c8fce27SZhang Rui 
7572f857234SLv Zheng 	if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER)) {
75886ca3b0aSHanjun Guo 		pr_warn("Can not change Invalid GPE/Fixed Event status\n");
7591c8fce27SZhang Rui 		return -EINVAL;
7601c8fce27SZhang Rui 	}
7611c8fce27SZhang Rui 
7621c8fce27SZhang Rui 	if (index < num_gpes) {
7631c8fce27SZhang Rui 		if (!strcmp(buf, "disable\n") &&
7641c8fce27SZhang Rui 		    (status & ACPI_EVENT_FLAG_ENABLED))
7651c8fce27SZhang Rui 			result = acpi_disable_gpe(handle, index);
7661c8fce27SZhang Rui 		else if (!strcmp(buf, "enable\n") &&
7671c8fce27SZhang Rui 			 !(status & ACPI_EVENT_FLAG_ENABLED))
7681c8fce27SZhang Rui 			result = acpi_enable_gpe(handle, index);
7691c8fce27SZhang Rui 		else if (!strcmp(buf, "clear\n") &&
77018864cc4SLv Zheng 			 (status & ACPI_EVENT_FLAG_STATUS_SET))
7711c8fce27SZhang Rui 			result = acpi_clear_gpe(handle, index);
77218864cc4SLv Zheng 		else if (!strcmp(buf, "mask\n"))
77318864cc4SLv Zheng 			result = acpi_mask_gpe(handle, index, TRUE);
77418864cc4SLv Zheng 		else if (!strcmp(buf, "unmask\n"))
77518864cc4SLv Zheng 			result = acpi_mask_gpe(handle, index, FALSE);
776c48b1565SLan Tianyu 		else if (!kstrtoul(buf, 0, &tmp))
777c48b1565SLan Tianyu 			all_counters[index].count = tmp;
7781c8fce27SZhang Rui 		else
779c48b1565SLan Tianyu 			result = -EINVAL;
7801c8fce27SZhang Rui 	} else if (index < num_gpes + ACPI_NUM_FIXED_EVENTS) {
7811c8fce27SZhang Rui 		int event = index - num_gpes;
7821c8fce27SZhang Rui 		if (!strcmp(buf, "disable\n") &&
78318864cc4SLv Zheng 		    (status & ACPI_EVENT_FLAG_ENABLE_SET))
7841c8fce27SZhang Rui 			result = acpi_disable_event(event, ACPI_NOT_ISR);
7851c8fce27SZhang Rui 		else if (!strcmp(buf, "enable\n") &&
78618864cc4SLv Zheng 			 !(status & ACPI_EVENT_FLAG_ENABLE_SET))
7871c8fce27SZhang Rui 			result = acpi_enable_event(event, ACPI_NOT_ISR);
7881c8fce27SZhang Rui 		else if (!strcmp(buf, "clear\n") &&
78918864cc4SLv Zheng 			 (status & ACPI_EVENT_FLAG_STATUS_SET))
7901c8fce27SZhang Rui 			result = acpi_clear_event(event);
791c48b1565SLan Tianyu 		else if (!kstrtoul(buf, 0, &tmp))
792c48b1565SLan Tianyu 			all_counters[index].count = tmp;
7931c8fce27SZhang Rui 		else
794c48b1565SLan Tianyu 			result = -EINVAL;
7951c8fce27SZhang Rui 	} else
7961c8fce27SZhang Rui 		all_counters[index].count = strtoul(buf, NULL, 0);
7971c8fce27SZhang Rui 
7981c8fce27SZhang Rui 	if (ACPI_FAILURE(result))
7991c8fce27SZhang Rui 		result = -EINVAL;
8001c8fce27SZhang Rui end:
8011c8fce27SZhang Rui 	return result ? result : size;
8021c8fce27SZhang Rui }
8031c8fce27SZhang Rui 
8049c4aa1eeSLv Zheng /*
8059c4aa1eeSLv Zheng  * A Quirk Mechanism for GPE Flooding Prevention:
8069c4aa1eeSLv Zheng  *
8079c4aa1eeSLv Zheng  * Quirks may be needed to prevent GPE flooding on a specific GPE. The
8089c4aa1eeSLv Zheng  * flooding typically cannot be detected and automatically prevented by
8099c4aa1eeSLv Zheng  * ACPI_GPE_DISPATCH_NONE check because there is a _Lxx/_Exx prepared in
8109c4aa1eeSLv Zheng  * the AML tables. This normally indicates a feature gap in Linux, thus
8119c4aa1eeSLv Zheng  * instead of providing endless quirk tables, we provide a boot parameter
8129c4aa1eeSLv Zheng  * for those who want this quirk. For example, if the users want to prevent
8139c4aa1eeSLv Zheng  * the GPE flooding for GPE 00, they need to specify the following boot
8149c4aa1eeSLv Zheng  * parameter:
8159c4aa1eeSLv Zheng  *   acpi_mask_gpe=0x00
816d3121e64SAndy Shevchenko  * Note, the parameter can be a list (see bitmap_parselist() for the details).
8179c4aa1eeSLv Zheng  * The masking status can be modified by the following runtime controlling
8189c4aa1eeSLv Zheng  * interface:
8199c4aa1eeSLv Zheng  *   echo unmask > /sys/firmware/acpi/interrupts/gpe00
8209c4aa1eeSLv Zheng  */
821a7583e72SYunfeng Ye #define ACPI_MASKABLE_GPE_MAX	0x100
8220f27cff8SPrarit Bhargava static DECLARE_BITMAP(acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) __initdata;
8239c4aa1eeSLv Zheng 
acpi_gpe_set_masked_gpes(char * val)8249c4aa1eeSLv Zheng static int __init acpi_gpe_set_masked_gpes(char *val)
8259c4aa1eeSLv Zheng {
826d3121e64SAndy Shevchenko 	int ret;
8279c4aa1eeSLv Zheng 	u8 gpe;
8289c4aa1eeSLv Zheng 
829d3121e64SAndy Shevchenko 	ret = kstrtou8(val, 0, &gpe);
830d3121e64SAndy Shevchenko 	if (ret) {
831d3121e64SAndy Shevchenko 		ret = bitmap_parselist(val, acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX);
832d3121e64SAndy Shevchenko 		if (ret)
833d3121e64SAndy Shevchenko 			return ret;
834d3121e64SAndy Shevchenko 	} else
8350f27cff8SPrarit Bhargava 		set_bit(gpe, acpi_masked_gpes_map);
8369c4aa1eeSLv Zheng 
8379c4aa1eeSLv Zheng 	return 1;
8389c4aa1eeSLv Zheng }
8399c4aa1eeSLv Zheng __setup("acpi_mask_gpe=", acpi_gpe_set_masked_gpes);
8409c4aa1eeSLv Zheng 
acpi_gpe_apply_masked_gpes(void)8419c4aa1eeSLv Zheng void __init acpi_gpe_apply_masked_gpes(void)
8429c4aa1eeSLv Zheng {
8439c4aa1eeSLv Zheng 	acpi_handle handle;
8449c4aa1eeSLv Zheng 	acpi_status status;
845a7583e72SYunfeng Ye 	u16 gpe;
8469c4aa1eeSLv Zheng 
8470f27cff8SPrarit Bhargava 	for_each_set_bit(gpe, acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) {
8489c4aa1eeSLv Zheng 		status = acpi_get_gpe_device(gpe, &handle);
8499c4aa1eeSLv Zheng 		if (ACPI_SUCCESS(status)) {
8509c4aa1eeSLv Zheng 			pr_info("Masking GPE 0x%x.\n", gpe);
8519c4aa1eeSLv Zheng 			(void)acpi_mask_gpe(handle, gpe, TRUE);
8529c4aa1eeSLv Zheng 		}
8539c4aa1eeSLv Zheng 	}
8549c4aa1eeSLv Zheng }
8559c4aa1eeSLv Zheng 
acpi_irq_stats_init(void)8561c8fce27SZhang Rui void acpi_irq_stats_init(void)
8571c8fce27SZhang Rui {
858a0fcdb23SLin Ming 	acpi_status status;
8591c8fce27SZhang Rui 	int i;
8601c8fce27SZhang Rui 
8611c8fce27SZhang Rui 	if (all_counters)
8621c8fce27SZhang Rui 		return;
8631c8fce27SZhang Rui 
8641c8fce27SZhang Rui 	num_gpes = acpi_current_gpe_count;
8651c8fce27SZhang Rui 	num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA;
8661c8fce27SZhang Rui 
867b272c059SAndy Shevchenko 	all_attrs = kcalloc(num_counters + 1, sizeof(*all_attrs), GFP_KERNEL);
8681c8fce27SZhang Rui 	if (all_attrs == NULL)
8691c8fce27SZhang Rui 		return;
8701c8fce27SZhang Rui 
871b272c059SAndy Shevchenko 	all_counters = kcalloc(num_counters, sizeof(*all_counters), GFP_KERNEL);
8721c8fce27SZhang Rui 	if (all_counters == NULL)
8731c8fce27SZhang Rui 		goto fail;
8741c8fce27SZhang Rui 
875644ef74eSLv Zheng 	status = acpi_install_global_event_handler(acpi_global_event_handler, NULL);
876a0fcdb23SLin Ming 	if (ACPI_FAILURE(status))
877a0fcdb23SLin Ming 		goto fail;
878a0fcdb23SLin Ming 
879b272c059SAndy Shevchenko 	counter_attrs = kcalloc(num_counters, sizeof(*counter_attrs), GFP_KERNEL);
8801c8fce27SZhang Rui 	if (counter_attrs == NULL)
8811c8fce27SZhang Rui 		goto fail;
8821c8fce27SZhang Rui 
8831c8fce27SZhang Rui 	for (i = 0; i < num_counters; ++i) {
8841c8fce27SZhang Rui 		char buffer[12];
8851c8fce27SZhang Rui 		char *name;
8861c8fce27SZhang Rui 
8871c8fce27SZhang Rui 		if (i < num_gpes)
8881c8fce27SZhang Rui 			sprintf(buffer, "gpe%02X", i);
8891c8fce27SZhang Rui 		else if (i == num_gpes + ACPI_EVENT_PMTIMER)
8901c8fce27SZhang Rui 			sprintf(buffer, "ff_pmtimer");
8911c8fce27SZhang Rui 		else if (i == num_gpes + ACPI_EVENT_GLOBAL)
8921c8fce27SZhang Rui 			sprintf(buffer, "ff_gbl_lock");
8931c8fce27SZhang Rui 		else if (i == num_gpes + ACPI_EVENT_POWER_BUTTON)
8941c8fce27SZhang Rui 			sprintf(buffer, "ff_pwr_btn");
8951c8fce27SZhang Rui 		else if (i == num_gpes + ACPI_EVENT_SLEEP_BUTTON)
8961c8fce27SZhang Rui 			sprintf(buffer, "ff_slp_btn");
8971c8fce27SZhang Rui 		else if (i == num_gpes + ACPI_EVENT_RTC)
8981c8fce27SZhang Rui 			sprintf(buffer, "ff_rt_clk");
8991c8fce27SZhang Rui 		else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE)
9001c8fce27SZhang Rui 			sprintf(buffer, "gpe_all");
9011c8fce27SZhang Rui 		else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI)
9021c8fce27SZhang Rui 			sprintf(buffer, "sci");
9031c8fce27SZhang Rui 		else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI_NOT)
9041c8fce27SZhang Rui 			sprintf(buffer, "sci_not");
9051c8fce27SZhang Rui 		else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR)
9061c8fce27SZhang Rui 			sprintf(buffer, "error");
9071c8fce27SZhang Rui 		else
9081c8fce27SZhang Rui 			sprintf(buffer, "bug%02X", i);
9091c8fce27SZhang Rui 
910096a8aacSKees Cook 		name = kstrdup(buffer, GFP_KERNEL);
9111c8fce27SZhang Rui 		if (name == NULL)
9121c8fce27SZhang Rui 			goto fail;
9131c8fce27SZhang Rui 
9141c8fce27SZhang Rui 		sysfs_attr_init(&counter_attrs[i].attr);
9151c8fce27SZhang Rui 		counter_attrs[i].attr.name = name;
9161c8fce27SZhang Rui 		counter_attrs[i].attr.mode = 0644;
9171c8fce27SZhang Rui 		counter_attrs[i].show = counter_show;
9181c8fce27SZhang Rui 		counter_attrs[i].store = counter_set;
9191c8fce27SZhang Rui 
9201c8fce27SZhang Rui 		all_attrs[i] = &counter_attrs[i].attr;
9211c8fce27SZhang Rui 	}
9221c8fce27SZhang Rui 
9231c8fce27SZhang Rui 	interrupt_stats_attr_group.attrs = all_attrs;
9241c8fce27SZhang Rui 	if (!sysfs_create_group(acpi_kobj, &interrupt_stats_attr_group))
9251c8fce27SZhang Rui 		return;
9261c8fce27SZhang Rui 
9271c8fce27SZhang Rui fail:
9281c8fce27SZhang Rui 	delete_gpe_attr_array();
9291c8fce27SZhang Rui }
9301c8fce27SZhang Rui 
interrupt_stats_exit(void)9311c8fce27SZhang Rui static void __exit interrupt_stats_exit(void)
9321c8fce27SZhang Rui {
9331c8fce27SZhang Rui 	sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group);
9341c8fce27SZhang Rui 
9351c8fce27SZhang Rui 	delete_gpe_attr_array();
9361c8fce27SZhang Rui }
9371c8fce27SZhang Rui 
pm_profile_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)938a9c4cf29SAndy Shevchenko static ssize_t pm_profile_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
939362b6460SThomas Renninger {
940362b6460SThomas Renninger 	return sprintf(buf, "%d\n", acpi_gbl_FADT.preferred_profile);
941362b6460SThomas Renninger }
942362b6460SThomas Renninger 
943a9c4cf29SAndy Shevchenko static const struct kobj_attribute pm_profile_attr = __ATTR_RO(pm_profile);
944362b6460SThomas Renninger 
enabled_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)945a9c4cf29SAndy Shevchenko static ssize_t enabled_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
9463f8055c3SRafael J. Wysocki {
9473f8055c3SRafael J. Wysocki 	struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
9483f8055c3SRafael J. Wysocki 
9493f8055c3SRafael J. Wysocki 	return sprintf(buf, "%d\n", hotplug->enabled);
9503f8055c3SRafael J. Wysocki }
9513f8055c3SRafael J. Wysocki 
enabled_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t size)952a9c4cf29SAndy Shevchenko static ssize_t enabled_store(struct kobject *kobj, struct kobj_attribute *attr,
9533f8055c3SRafael J. Wysocki 			     const char *buf, size_t size)
9543f8055c3SRafael J. Wysocki {
9553f8055c3SRafael J. Wysocki 	struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
9563f8055c3SRafael J. Wysocki 	unsigned int val;
9573f8055c3SRafael J. Wysocki 
9583f8055c3SRafael J. Wysocki 	if (kstrtouint(buf, 10, &val) || val > 1)
9593f8055c3SRafael J. Wysocki 		return -EINVAL;
9603f8055c3SRafael J. Wysocki 
9613f8055c3SRafael J. Wysocki 	acpi_scan_hotplug_enabled(hotplug, val);
9623f8055c3SRafael J. Wysocki 	return size;
9633f8055c3SRafael J. Wysocki }
9643f8055c3SRafael J. Wysocki 
965a9c4cf29SAndy Shevchenko static struct kobj_attribute hotplug_enabled_attr = __ATTR_RW(enabled);
9663f8055c3SRafael J. Wysocki 
9673f8055c3SRafael J. Wysocki static struct attribute *hotplug_profile_attrs[] = {
9683f8055c3SRafael J. Wysocki 	&hotplug_enabled_attr.attr,
9693f8055c3SRafael J. Wysocki 	NULL
9703f8055c3SRafael J. Wysocki };
97117f18417SGreg Kroah-Hartman ATTRIBUTE_GROUPS(hotplug_profile);
9723f8055c3SRafael J. Wysocki 
973a527b011SThomas Weißschuh static const struct kobj_type acpi_hotplug_profile_ktype = {
9743f8055c3SRafael J. Wysocki 	.sysfs_ops = &kobj_sysfs_ops,
97517f18417SGreg Kroah-Hartman 	.default_groups = hotplug_profile_groups,
9763f8055c3SRafael J. Wysocki };
9773f8055c3SRafael J. Wysocki 
acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile * hotplug,const char * name)9783f8055c3SRafael J. Wysocki void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
9793f8055c3SRafael J. Wysocki 				    const char *name)
9803f8055c3SRafael J. Wysocki {
9813f8055c3SRafael J. Wysocki 	int error;
9823f8055c3SRafael J. Wysocki 
9833f8055c3SRafael J. Wysocki 	if (!hotplug_kobj)
9843f8055c3SRafael J. Wysocki 		goto err_out;
9853f8055c3SRafael J. Wysocki 
986acd3e2c9SBjorn Helgaas 	error = kobject_init_and_add(&hotplug->kobj,
987acd3e2c9SBjorn Helgaas 		&acpi_hotplug_profile_ktype, hotplug_kobj, "%s", name);
9886e6c2528SQiushi Wu 	if (error) {
9896e6c2528SQiushi Wu 		kobject_put(&hotplug->kobj);
9903f8055c3SRafael J. Wysocki 		goto err_out;
9916e6c2528SQiushi Wu 	}
9923f8055c3SRafael J. Wysocki 
9933f8055c3SRafael J. Wysocki 	kobject_uevent(&hotplug->kobj, KOBJ_ADD);
9943f8055c3SRafael J. Wysocki 	return;
9953f8055c3SRafael J. Wysocki 
9963f8055c3SRafael J. Wysocki  err_out:
99786ca3b0aSHanjun Guo 	pr_err("Unable to add hotplug profile '%s'\n", name);
9983f8055c3SRafael J. Wysocki }
9993f8055c3SRafael J. Wysocki 
force_remove_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)1000683058e3SRafael J. Wysocki static ssize_t force_remove_show(struct kobject *kobj,
1001683058e3SRafael J. Wysocki 				 struct kobj_attribute *attr, char *buf)
1002683058e3SRafael J. Wysocki {
1003ffc10d82SMichal Hocko 	return sprintf(buf, "%d\n", 0);
1004683058e3SRafael J. Wysocki }
1005683058e3SRafael J. Wysocki 
force_remove_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t size)1006683058e3SRafael J. Wysocki static ssize_t force_remove_store(struct kobject *kobj,
1007683058e3SRafael J. Wysocki 				  struct kobj_attribute *attr,
1008683058e3SRafael J. Wysocki 				  const char *buf, size_t size)
1009683058e3SRafael J. Wysocki {
1010683058e3SRafael J. Wysocki 	bool val;
1011683058e3SRafael J. Wysocki 	int ret;
1012683058e3SRafael J. Wysocki 
10134612c7f1SChristophe JAILLET 	ret = kstrtobool(buf, &val);
1014683058e3SRafael J. Wysocki 	if (ret < 0)
1015683058e3SRafael J. Wysocki 		return ret;
1016683058e3SRafael J. Wysocki 
1017ffc10d82SMichal Hocko 	if (val) {
1018ffc10d82SMichal Hocko 		pr_err("Enabling force_remove is not supported anymore. Please report to linux-acpi@vger.kernel.org if you depend on this functionality\n");
1019ffc10d82SMichal Hocko 		return -EINVAL;
1020ffc10d82SMichal Hocko 	}
1021683058e3SRafael J. Wysocki 	return size;
1022683058e3SRafael J. Wysocki }
1023683058e3SRafael J. Wysocki 
1024a9c4cf29SAndy Shevchenko static const struct kobj_attribute force_remove_attr = __ATTR_RW(force_remove);
1025683058e3SRafael J. Wysocki 
acpi_sysfs_init(void)10261c8fce27SZhang Rui int __init acpi_sysfs_init(void)
10271c8fce27SZhang Rui {
10281c8fce27SZhang Rui 	int result;
10291c8fce27SZhang Rui 
10301c8fce27SZhang Rui 	result = acpi_tables_sysfs_init();
1031362b6460SThomas Renninger 	if (result)
1032362b6460SThomas Renninger 		return result;
10333f8055c3SRafael J. Wysocki 
10343f8055c3SRafael J. Wysocki 	hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj);
1035bc1e49dfSInsu Yun 	if (!hotplug_kobj)
1036bc1e49dfSInsu Yun 		return -ENOMEM;
1037bc1e49dfSInsu Yun 
1038683058e3SRafael J. Wysocki 	result = sysfs_create_file(hotplug_kobj, &force_remove_attr.attr);
1039683058e3SRafael J. Wysocki 	if (result)
1040683058e3SRafael J. Wysocki 		return result;
1041683058e3SRafael J. Wysocki 
1042362b6460SThomas Renninger 	result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr);
10431c8fce27SZhang Rui 	return result;
10441c8fce27SZhang Rui }
1045