826 lines · 20.7 KB · C
RawDownload
/* * sysfs.c - ACPI sysfs interface to userspace. */ #include <linux/init.h>#include <linux/kernel.h>#include <linux/moduleparam.h>#include <acpi/acpi_drivers.h> #include "internal.h" #define _COMPONENT		ACPI_SYSTEM_COMPONENTACPI_MODULE_NAME("sysfs"); #define PREFIX "ACPI: " #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_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[6];module_param_string(trace_method_name, trace_method_name, 6, 0644);static unsigned int trace_debug_layer;module_param(trace_debug_layer, uint, 0644);static unsigned int trace_debug_level;module_param(trace_debug_level, uint, 0644); static int param_set_trace_state(const char *val, struct kernel_param *kp){	int result = 0; 	if (!strncmp(val, "enable", sizeof("enable") - 1)) {		result = acpi_debug_trace(trace_method_name, trace_debug_level,					  trace_debug_layer, 0);		if (result)			result = -EBUSY;		goto exit;	} 	if (!strncmp(val, "disable", sizeof("disable") - 1)) {		int name = 0;		result = acpi_debug_trace((char *)&name, trace_debug_level,					  trace_debug_layer, 0);		if (result)			result = -EBUSY;		goto exit;	} 	if (!strncmp(val, "1", 1)) {		result = acpi_debug_trace(trace_method_name, trace_debug_level,					  trace_debug_layer, 1);		if (result)			result = -EBUSY;		goto exit;	} 	result = -EINVAL;exit:	return result;} static int param_get_trace_state(char *buffer, struct kernel_param *kp){	if (!acpi_gbl_trace_method_name)		return sprintf(buffer, "disable");	else {		if (acpi_gbl_trace_flags & 1)			return sprintf(buffer, "1");		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,		   bool, 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; struct acpi_table_attr {	struct bin_attribute attr;	char name[8];	int instance;	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;	char name[ACPI_NAME_SIZE]; 	if (strncmp(table_attr->name, "NULL", 4))		memcpy(name, table_attr->name, ACPI_NAME_SIZE);	else		memcpy(name, "\0\0\0\0", 4); 	status = acpi_get_table(name, table_attr->instance, &table_header);	if (ACPI_FAILURE(status))		return -ENODEV; 	return memory_read_from_buffer(buf, count, &offset,				       table_header, table_header->length);} static void acpi_table_attr_init(struct acpi_table_attr *table_attr,				 struct acpi_table_header *table_header){	struct acpi_table_header *header = NULL;	struct acpi_table_attr *attr = NULL; 	sysfs_attr_init(&table_attr->attr.attr);	if (table_header->signature[0] != '\0')		memcpy(table_attr->name, table_header->signature,		       ACPI_NAME_SIZE);	else		memcpy(table_attr->name, "NULL", 4); 	list_for_each_entry(attr, &acpi_table_attr_list, node) {		if (!memcmp(table_attr->name, attr->name, ACPI_NAME_SIZE))			if (table_attr->instance < attr->instance)				table_attr->instance = attr->instance;	}	table_attr->instance++; 	if (table_attr->instance > 1 || (table_attr->instance == 1 &&					 !acpi_get_table					 (table_header->signature, 2, &header)))		sprintf(table_attr->name + ACPI_NAME_SIZE, "%d",			table_attr->instance); 	table_attr->attr.size = table_header->length;	table_attr->attr.read = acpi_table_show;	table_attr->attr.attr.name = table_attr->name;	table_attr->attr.attr.mode = 0400; 	return;} static acpi_statusacpi_sysfs_table_handler(u32 event, void *table, void *context){	struct acpi_table_attr *table_attr; 	switch (event) {	case ACPI_TABLE_EVENT_LOAD:		table_attr =		    kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL);		if (!table_attr)			return AE_NO_MEMORY; 		acpi_table_attr_init(table_attr, table);		if (sysfs_create_bin_file(dynamic_tables_kobj,					  &table_attr->attr)) {			kfree(table_attr);			return AE_ERROR;		} else			list_add_tail(&table_attr->node, &acpi_table_attr_list);		break;	case ACPI_TABLE_EVENT_UNLOAD:		/*		 * 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 = NULL;		table_attr = kzalloc(sizeof(*table_attr), GFP_KERNEL);		if (!table_attr)			return -ENOMEM; 		acpi_table_attr_init(table_attr, table_header);		ret = sysfs_create_bin_file(tables_kobj, &table_attr->attr);		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);	status = acpi_install_table_handler(acpi_sysfs_table_handler, NULL); 	return ACPI_FAILURE(status) ? -EINVAL : 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; static void delete_gpe_attr_array(void){	struct event_counter *tmp = all_counters; 	all_counters = NULL;	kfree(tmp); 	if (counter_attrs) {		int i; 		for (i = 0; i < num_gpes; i++)			kfree(counter_attrs[i].attr.name); 		kfree(counter_attrs);	}	kfree(all_attrs); 	return;} static void gpe_count(u32 gpe_number){	acpi_gpe_count++; 	if (!all_counters)		return; 	if (gpe_number < num_gpes)		all_counters[gpe_number].count++;	else		all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS +			     COUNT_ERROR].count++; 	return;} static void fixed_event_count(u32 event_number){	if (!all_counters)		return; 	if (event_number < ACPI_NUM_FIXED_EVENTS)		all_counters[num_gpes + event_number].count++;	else		all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS +			     COUNT_ERROR].count++; 	return;} static void acpi_global_event_handler(u32 event_type, acpi_handle device,	u32 event_number, void *context){	if (event_type == ACPI_EVENT_TYPE_GPE)		gpe_count(event_number); 	if (event_type == ACPI_EVENT_TYPE_FIXED)		fixed_event_count(event_number);} static int get_status(u32 index, acpi_event_status *status,		      acpi_handle *handle){	int result = 0; 	if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS)		goto end;

Lines 1–500 of 826.