ACPI / sysfs: Update method tracing facility.

This patch updates the method tracing facility as the acpi_debug_trace()
API has been updated to allow it to trace AML interpreter execution, the
meanings and the usages of the API parameters are changed due to the
updates.

The new API:
1. Uses ACPI_TRACE_ENABLED flag to indicate the enabling of the tracer;
2. Allows tracer still can be enabled when method name is not specified so
   that the AML interpreter execution can be traced without knowing the
   method name, which is useful for kernel boot tracing;
3. Supports arbitrary full path name, it doesn't need to be a name related
   to an entrance of acpi_evaluate_object().

Note that the sysfs parameters are also updated so that when reading the
attribute files, ACPICA internal settings are returned.

In order to make the sysfs parameters (acpi.trace_state) available during
boot, this patch adds code to bypass ACPICA semaphore/mutex invocations
when acpi mutex utilities haven't been initialized.

This patch doesn't update documentation of method tracing facility, it will
be updated by further patches.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
Lv Zheng 2015-08-05 16:23:51 +08:00 committed by Rafael J. Wysocki
parent 93d988310b
commit 7901a052a9
2 changed files with 108 additions and 36 deletions

View File

@ -83,6 +83,7 @@ static void *acpi_irq_context;
static struct workqueue_struct *kacpid_wq;
static struct workqueue_struct *kacpi_notify_wq;
static struct workqueue_struct *kacpi_hotplug_wq;
static bool acpi_os_initialized;
/*
* This list of permanent mappings is for memory that may be accessed from
@ -1316,6 +1317,9 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
long jiffies;
int ret = 0;
if (!acpi_os_initialized)
return AE_OK;
if (!sem || (units < 1))
return AE_BAD_PARAMETER;
@ -1355,6 +1359,9 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
{
struct semaphore *sem = (struct semaphore *)handle;
if (!acpi_os_initialized)
return AE_OK;
if (!sem || (units < 1))
return AE_BAD_PARAMETER;
@ -1863,6 +1870,7 @@ acpi_status __init acpi_os_initialize(void)
rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register);
pr_debug(PREFIX "%s: map reset_reg status %d\n", __func__, rv);
}
acpi_os_initialized = true;
return AE_OK;
}

View File

@ -70,6 +70,7 @@ static const struct acpi_dlevel acpi_debug_levels[] = {
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),
@ -163,55 +164,118 @@ static const struct kernel_param_ops param_ops_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 char* trace_method_name;
static bool trace_method_kmalloced;
int param_set_trace_method_name(const char *val, const struct kernel_param *kp)
{
u32 saved_flags = 0;
if (strlen(val) > 1024) {
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);
if (trace_method_kmalloced)
kfree(trace_method_name);
trace_method_name = NULL;
trace_method_kmalloced = false;
/* This is a hack. We can't kmalloc in early boot. */
if (slab_is_available()) {
trace_method_name = kstrdup(val, GFP_KERNEL);
if (!trace_method_name)
return -ENOMEM;
trace_method_kmalloced = true;
} else
trace_method_name = (char *)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)
{
int result = 0;
acpi_status status;
const char *method = trace_method_name;
u32 flags = 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;
}
/* So "xxx-once" comparison should go prior than "xxx" comparison */
#define acpi_compare_param(val, key) \
strncmp((val), (key), sizeof(key) - 1)
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 (!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;
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;
}
status = acpi_debug_trace(method,
acpi_gbl_trace_dbg_level,
acpi_gbl_trace_dbg_layer,
flags);
if (ACPI_FAILURE(status))
return -EBUSY;
result = -EINVAL;
exit:
return result;
return 0;
}
static int param_get_trace_state(char *buffer, struct kernel_param *kp)
{
if (!acpi_gbl_trace_method_name)
if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED))
return sprintf(buffer, "disable");
else {
if (acpi_gbl_trace_flags & 1)
return sprintf(buffer, "1");
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;