970 lines · 25.1 KB · C
RawDownload
/* * sysfs.c - ACPI sysfs interface to userspace. */ #include <linux/init.h>#include <linux/kernel.h>#include <linux/moduleparam.h>#include <linux/acpi.h> #include "internal.h" #define _COMPONENT		ACPI_SYSTEM_COMPONENTACPI_MODULE_NAME("sysfs"); #ifdef CONFIG_ACPI_DEBUG/* * ACPI debug sysfs I/F, including: * /sys/modules/acpi/parameters/debug_layer * /sys/modules/acpi/parameters/debug_level * /sys/modules/acpi/parameters/trace_method_name * /sys/modules/acpi/parameters/trace_state * /sys/modules/acpi/parameters/trace_debug_layer * /sys/modules/acpi/parameters/trace_debug_level */ struct acpi_dlayer {	const char *name;	unsigned long value;};struct acpi_dlevel {	const char *name;	unsigned long value;};#define ACPI_DEBUG_INIT(v)	{ .name = #v, .value = v } static const struct acpi_dlayer acpi_debug_layers[] = {	ACPI_DEBUG_INIT(ACPI_UTILITIES),	ACPI_DEBUG_INIT(ACPI_HARDWARE),	ACPI_DEBUG_INIT(ACPI_EVENTS),	ACPI_DEBUG_INIT(ACPI_TABLES),	ACPI_DEBUG_INIT(ACPI_NAMESPACE),	ACPI_DEBUG_INIT(ACPI_PARSER),	ACPI_DEBUG_INIT(ACPI_DISPATCHER),	ACPI_DEBUG_INIT(ACPI_EXECUTER),	ACPI_DEBUG_INIT(ACPI_RESOURCES),	ACPI_DEBUG_INIT(ACPI_CA_DEBUGGER),	ACPI_DEBUG_INIT(ACPI_OS_SERVICES),	ACPI_DEBUG_INIT(ACPI_CA_DISASSEMBLER),	ACPI_DEBUG_INIT(ACPI_COMPILER),	ACPI_DEBUG_INIT(ACPI_TOOLS), 	ACPI_DEBUG_INIT(ACPI_BUS_COMPONENT),	ACPI_DEBUG_INIT(ACPI_AC_COMPONENT),	ACPI_DEBUG_INIT(ACPI_BATTERY_COMPONENT),	ACPI_DEBUG_INIT(ACPI_BUTTON_COMPONENT),	ACPI_DEBUG_INIT(ACPI_SBS_COMPONENT),	ACPI_DEBUG_INIT(ACPI_FAN_COMPONENT),	ACPI_DEBUG_INIT(ACPI_PCI_COMPONENT),	ACPI_DEBUG_INIT(ACPI_POWER_COMPONENT),	ACPI_DEBUG_INIT(ACPI_CONTAINER_COMPONENT),	ACPI_DEBUG_INIT(ACPI_SYSTEM_COMPONENT),	ACPI_DEBUG_INIT(ACPI_THERMAL_COMPONENT),	ACPI_DEBUG_INIT(ACPI_MEMORY_DEVICE_COMPONENT),	ACPI_DEBUG_INIT(ACPI_VIDEO_COMPONENT),	ACPI_DEBUG_INIT(ACPI_PROCESSOR_COMPONENT),}; static const struct acpi_dlevel acpi_debug_levels[] = {	ACPI_DEBUG_INIT(ACPI_LV_INIT),	ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT),	ACPI_DEBUG_INIT(ACPI_LV_INFO),	ACPI_DEBUG_INIT(ACPI_LV_REPAIR),	ACPI_DEBUG_INIT(ACPI_LV_TRACE_POINT), 	ACPI_DEBUG_INIT(ACPI_LV_INIT_NAMES),	ACPI_DEBUG_INIT(ACPI_LV_PARSE),	ACPI_DEBUG_INIT(ACPI_LV_LOAD),	ACPI_DEBUG_INIT(ACPI_LV_DISPATCH),	ACPI_DEBUG_INIT(ACPI_LV_EXEC),	ACPI_DEBUG_INIT(ACPI_LV_NAMES),	ACPI_DEBUG_INIT(ACPI_LV_OPREGION),	ACPI_DEBUG_INIT(ACPI_LV_BFIELD),	ACPI_DEBUG_INIT(ACPI_LV_TABLES),	ACPI_DEBUG_INIT(ACPI_LV_VALUES),	ACPI_DEBUG_INIT(ACPI_LV_OBJECTS),	ACPI_DEBUG_INIT(ACPI_LV_RESOURCES),	ACPI_DEBUG_INIT(ACPI_LV_USER_REQUESTS),	ACPI_DEBUG_INIT(ACPI_LV_PACKAGE), 	ACPI_DEBUG_INIT(ACPI_LV_ALLOCATIONS),	ACPI_DEBUG_INIT(ACPI_LV_FUNCTIONS),	ACPI_DEBUG_INIT(ACPI_LV_OPTIMIZATIONS), 	ACPI_DEBUG_INIT(ACPI_LV_MUTEX),	ACPI_DEBUG_INIT(ACPI_LV_THREADS),	ACPI_DEBUG_INIT(ACPI_LV_IO),	ACPI_DEBUG_INIT(ACPI_LV_INTERRUPTS), 	ACPI_DEBUG_INIT(ACPI_LV_AML_DISASSEMBLE),	ACPI_DEBUG_INIT(ACPI_LV_VERBOSE_INFO),	ACPI_DEBUG_INIT(ACPI_LV_FULL_TABLES),	ACPI_DEBUG_INIT(ACPI_LV_EVENTS),}; static int param_get_debug_layer(char *buffer, const struct kernel_param *kp){	int result = 0;	int i; 	result = sprintf(buffer, "%-25s\tHex        SET\n", "Description"); 	for (i = 0; i < ARRAY_SIZE(acpi_debug_layers); i++) {		result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n",				  acpi_debug_layers[i].name,				  acpi_debug_layers[i].value,				  (acpi_dbg_layer & acpi_debug_layers[i].value)				  ? '*' : ' ');	}	result +=	    sprintf(buffer + result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",		    ACPI_ALL_DRIVERS,		    (acpi_dbg_layer & ACPI_ALL_DRIVERS) ==		    ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS)		    == 0 ? ' ' : '-');	result +=	    sprintf(buffer + result,		    "--\ndebug_layer = 0x%08X ( * = enabled)\n",		    acpi_dbg_layer); 	return result;} static int param_get_debug_level(char *buffer, const struct kernel_param *kp){	int result = 0;	int i; 	result = sprintf(buffer, "%-25s\tHex        SET\n", "Description"); 	for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) {		result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n",				  acpi_debug_levels[i].name,				  acpi_debug_levels[i].value,				  (acpi_dbg_level & acpi_debug_levels[i].value)				  ? '*' : ' ');	}	result +=	    sprintf(buffer + result, "--\ndebug_level = 0x%08X (* = enabled)\n",		    acpi_dbg_level); 	return result;} static const struct kernel_param_ops param_ops_debug_layer = {	.set = param_set_uint,	.get = param_get_debug_layer,}; static const struct kernel_param_ops param_ops_debug_level = {	.set = param_set_uint,	.get = param_get_debug_level,}; module_param_cb(debug_layer, &param_ops_debug_layer, &acpi_dbg_layer, 0644);module_param_cb(debug_level, &param_ops_debug_level, &acpi_dbg_level, 0644); static char trace_method_name[1024]; int param_set_trace_method_name(const char *val, const struct kernel_param *kp){	u32 saved_flags = 0;	bool is_abs_path = true; 	if (*val != '\\')		is_abs_path = false; 	if ((is_abs_path && strlen(val) > 1023) ||	    (!is_abs_path && strlen(val) > 1022)) {		pr_err("%s: string parameter too long\n", kp->name);		return -ENOSPC;	} 	/*	 * It's not safe to update acpi_gbl_trace_method_name without	 * having the tracer stopped, so we save the original tracer	 * state and disable it.	 */	saved_flags = acpi_gbl_trace_flags;	(void)acpi_debug_trace(NULL,			       acpi_gbl_trace_dbg_level,			       acpi_gbl_trace_dbg_layer,			       0); 	/* This is a hack.  We can't kmalloc in early boot. */	if (is_abs_path)		strcpy(trace_method_name, val);	else {		trace_method_name[0] = '\\';		strcpy(trace_method_name+1, val);	} 	/* Restore the original tracer state */	(void)acpi_debug_trace(trace_method_name,			       acpi_gbl_trace_dbg_level,			       acpi_gbl_trace_dbg_layer,			       saved_flags); 	return 0;} static int param_get_trace_method_name(char *buffer, const struct kernel_param *kp){	return scnprintf(buffer, PAGE_SIZE, "%s", acpi_gbl_trace_method_name);} static const struct kernel_param_ops param_ops_trace_method = {	.set = param_set_trace_method_name,	.get = param_get_trace_method_name,}; static const struct kernel_param_ops param_ops_trace_attrib = {	.set = param_set_uint,	.get = param_get_uint,}; module_param_cb(trace_method_name, &param_ops_trace_method, &trace_method_name, 0644);module_param_cb(trace_debug_layer, &param_ops_trace_attrib, &acpi_gbl_trace_dbg_layer, 0644);module_param_cb(trace_debug_level, &param_ops_trace_attrib, &acpi_gbl_trace_dbg_level, 0644); static int param_set_trace_state(const char *val, struct kernel_param *kp){	acpi_status status;	const char *method = trace_method_name;	u32 flags = 0; /* So "xxx-once" comparison should go prior than "xxx" comparison */#define acpi_compare_param(val, key)	\	strncmp((val), (key), sizeof(key) - 1) 	if (!acpi_compare_param(val, "enable")) {		method = NULL;		flags = ACPI_TRACE_ENABLED;	} else if (!acpi_compare_param(val, "disable"))		method = NULL;	else if (!acpi_compare_param(val, "method-once"))		flags = ACPI_TRACE_ENABLED | ACPI_TRACE_ONESHOT;	else if (!acpi_compare_param(val, "method"))		flags = ACPI_TRACE_ENABLED;	else if (!acpi_compare_param(val, "opcode-once"))		flags = ACPI_TRACE_ENABLED | ACPI_TRACE_ONESHOT | ACPI_TRACE_OPCODE;	else if (!acpi_compare_param(val, "opcode"))		flags = ACPI_TRACE_ENABLED | ACPI_TRACE_OPCODE;	else		return -EINVAL; 	status = acpi_debug_trace(method,				  acpi_gbl_trace_dbg_level,				  acpi_gbl_trace_dbg_layer,				  flags);	if (ACPI_FAILURE(status))		return -EBUSY; 	return 0;} static int param_get_trace_state(char *buffer, struct kernel_param *kp){	if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED))		return sprintf(buffer, "disable");	else {		if (acpi_gbl_trace_method_name) {			if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT)				return sprintf(buffer, "method-once");			else				return sprintf(buffer, "method");		} else			return sprintf(buffer, "enable");	}	return 0;} module_param_call(trace_state, param_set_trace_state, param_get_trace_state,		  NULL, 0644);#endif /* CONFIG_ACPI_DEBUG */  /* /sys/modules/acpi/parameters/aml_debug_output */ module_param_named(aml_debug_output, acpi_gbl_enable_aml_debug_object,		   byte, 0644);MODULE_PARM_DESC(aml_debug_output,		 "To enable/disable the ACPI Debug Object output."); /* /sys/module/acpi/parameters/acpica_version */static int param_get_acpica_version(char *buffer, struct kernel_param *kp){	int result; 	result = sprintf(buffer, "%x", ACPI_CA_VERSION); 	return result;} module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); /* * ACPI table sysfs I/F: * /sys/firmware/acpi/tables/ * /sys/firmware/acpi/tables/dynamic/ */ static LIST_HEAD(acpi_table_attr_list);static struct kobject *tables_kobj;static struct kobject *dynamic_tables_kobj;static struct kobject *hotplug_kobj; #define ACPI_MAX_TABLE_INSTANCES	999#define ACPI_INST_SIZE			4 /* including trailing 0 */ struct acpi_table_attr {	struct bin_attribute attr;	char name[ACPI_NAME_SIZE];	int instance;	char filename[ACPI_NAME_SIZE+ACPI_INST_SIZE];	struct list_head node;}; static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj,			       struct bin_attribute *bin_attr, char *buf,			       loff_t offset, size_t count){	struct acpi_table_attr *table_attr =	    container_of(bin_attr, struct acpi_table_attr, attr);	struct acpi_table_header *table_header = NULL;	acpi_status status;	ssize_t rc; 	status = acpi_get_table(table_attr->name, table_attr->instance,				&table_header);	if (ACPI_FAILURE(status))		return -ENODEV; 	rc = memory_read_from_buffer(buf, count, &offset, table_header,			table_header->length);	acpi_put_table(table_header);	return rc;} static int acpi_table_attr_init(struct kobject *tables_obj,				struct acpi_table_attr *table_attr,				struct acpi_table_header *table_header){	struct acpi_table_header *header = NULL;	struct acpi_table_attr *attr = NULL;	char instance_str[ACPI_INST_SIZE]; 	sysfs_attr_init(&table_attr->attr.attr);	ACPI_MOVE_NAME(table_attr->name, table_header->signature); 	list_for_each_entry(attr, &acpi_table_attr_list, node) {		if (ACPI_COMPARE_NAME(table_attr->name, attr->name))			if (table_attr->instance < attr->instance)				table_attr->instance = attr->instance;	}	table_attr->instance++;	if (table_attr->instance > ACPI_MAX_TABLE_INSTANCES) {		pr_warn("%4.4s: too many table instances\n",			table_attr->name);		return -ERANGE;	} 	ACPI_MOVE_NAME(table_attr->filename, table_header->signature);	table_attr->filename[ACPI_NAME_SIZE] = '\0';	if (table_attr->instance > 1 || (table_attr->instance == 1 &&					 !acpi_get_table					 (table_header->signature, 2, &header))) {		snprintf(instance_str, sizeof(instance_str), "%u",			 table_attr->instance);		strcat(table_attr->filename, instance_str);	} 	table_attr->attr.size = table_header->length;	table_attr->attr.read = acpi_table_show;	table_attr->attr.attr.name = table_attr->filename;	table_attr->attr.attr.mode = 0400; 	return sysfs_create_bin_file(tables_obj, &table_attr->attr);} acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context){	struct acpi_table_attr *table_attr; 	switch (event) {	case ACPI_TABLE_EVENT_INSTALL:		table_attr =		    kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL);		if (!table_attr)			return AE_NO_MEMORY; 		if (acpi_table_attr_init(dynamic_tables_kobj,					 table_attr, table)) {			kfree(table_attr);			return AE_ERROR;		}		list_add_tail(&table_attr->node, &acpi_table_attr_list);		break;	case ACPI_TABLE_EVENT_LOAD:	case ACPI_TABLE_EVENT_UNLOAD:	case ACPI_TABLE_EVENT_UNINSTALL:		/*		 * we do not need to do anything right now		 * because the table is not deleted from the		 * global table list when unloading it.		 */		break;	default:		return AE_BAD_PARAMETER;	}	return AE_OK;} static int acpi_tables_sysfs_init(void){	struct acpi_table_attr *table_attr;	struct acpi_table_header *table_header = NULL;	int table_index;	acpi_status status;	int ret; 	tables_kobj = kobject_create_and_add("tables", acpi_kobj);	if (!tables_kobj)		goto err; 	dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj);	if (!dynamic_tables_kobj)		goto err_dynamic_tables; 	for (table_index = 0;; table_index++) {		status = acpi_get_table_by_index(table_index, &table_header); 		if (status == AE_BAD_PARAMETER)			break; 		if (ACPI_FAILURE(status))			continue; 		table_attr = kzalloc(sizeof(*table_attr), GFP_KERNEL);		if (!table_attr)			return -ENOMEM; 		ret = acpi_table_attr_init(tables_kobj,					   table_attr, table_header);		if (ret) {			kfree(table_attr);			return ret;		}		list_add_tail(&table_attr->node, &acpi_table_attr_list);	} 	kobject_uevent(tables_kobj, KOBJ_ADD);	kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); 	return 0;err_dynamic_tables:	kobject_put(tables_kobj);err:	return -ENOMEM;} /* * Detailed ACPI IRQ counters: * /sys/firmware/acpi/interrupts/ */ u32 acpi_irq_handled;u32 acpi_irq_not_handled; #define COUNT_GPE 0#define COUNT_SCI 1		/* acpi_irq_handled */#define COUNT_SCI_NOT 2		/* acpi_irq_not_handled */#define COUNT_ERROR 3		/* other */#define NUM_COUNTERS_EXTRA 4 struct event_counter {	u32 count;	u32 flags;}; static struct event_counter *all_counters;static u32 num_gpes;static u32 num_counters;static struct attribute **all_attrs;static u32 acpi_gpe_count; static struct attribute_group interrupt_stats_attr_group = {	.name = "interrupts",}; static struct kobj_attribute *counter_attrs;

Lines 1–500 of 970.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t