mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 17:08:10 +00:00
ACPICA: New: AcpiInstallMethod - install a single control method
This interface enables the override or creation of a single control method. Useful to repair a bug or install a missing method. Signed-off-by: Lin Ming <ming.m.lin@intel.com> Signed-off-by: Bob Moore <robert.moore@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
e0be6f5a98
commit
b2f7ddcfcb
7 changed files with 168 additions and 4 deletions
|
@ -205,6 +205,7 @@ struct acpi_namespace_node {
|
|||
#define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */
|
||||
#define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */
|
||||
#define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */
|
||||
#define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (install_method) */
|
||||
|
||||
#define ANOBJ_IS_EXTERNAL 0x08 /* i_aSL only: This object created via External() */
|
||||
#define ANOBJ_METHOD_NO_RETVAL 0x10 /* i_aSL only: Method has no return value */
|
||||
|
|
|
@ -483,7 +483,7 @@ typedef enum {
|
|||
|
||||
#define AML_METHOD_ARG_COUNT 0x07
|
||||
#define AML_METHOD_SERIALIZED 0x08
|
||||
#define AML_METHOD_SYNCH_LEVEL 0xF0
|
||||
#define AML_METHOD_SYNC_LEVEL 0xF0
|
||||
|
||||
/* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */
|
||||
|
||||
|
|
|
@ -502,7 +502,7 @@ acpi_ex_create_method(u8 * aml_start,
|
|||
* ACPI 2.0: sync_level = sync_level in method declaration
|
||||
*/
|
||||
obj_desc->method.sync_level = (u8)
|
||||
((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4);
|
||||
((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);
|
||||
}
|
||||
|
||||
/* Attach the new object to the method Node */
|
||||
|
|
|
@ -120,9 +120,11 @@ static struct acpi_exdump_info acpi_ex_dump_event[2] = {
|
|||
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(event.os_semaphore), "OsSemaphore"}
|
||||
};
|
||||
|
||||
static struct acpi_exdump_info acpi_ex_dump_method[8] = {
|
||||
static struct acpi_exdump_info acpi_ex_dump_method[9] = {
|
||||
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL},
|
||||
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), "ParamCount"},
|
||||
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.method_flags), "Method Flags"},
|
||||
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count),
|
||||
"Parameter Count"},
|
||||
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"},
|
||||
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.mutex), "Mutex"},
|
||||
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"},
|
||||
|
|
|
@ -213,6 +213,15 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node)
|
|||
return_VOID;
|
||||
}
|
||||
|
||||
if (node->flags & ANOBJ_ALLOCATED_BUFFER) {
|
||||
|
||||
/* Free the dynamic aml buffer */
|
||||
|
||||
if (obj_desc->common.type == ACPI_TYPE_METHOD) {
|
||||
ACPI_FREE(obj_desc->method.aml_start);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the entry in all cases */
|
||||
|
||||
node->object = NULL;
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
#include <acpi/acpi.h>
|
||||
#include "accommon.h"
|
||||
#include "acnamesp.h"
|
||||
#include "acparser.h"
|
||||
#include "amlcode.h"
|
||||
|
||||
#define _COMPONENT ACPI_NAMESPACE
|
||||
ACPI_MODULE_NAME("nsxfname")
|
||||
|
@ -358,3 +360,151 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
|
|||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_get_object_info)
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_install_method
|
||||
*
|
||||
* PARAMETERS: Buffer - An ACPI table containing one control method
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Install a control method into the namespace. If the method
|
||||
* name already exists in the namespace, it is overwritten. The
|
||||
* input buffer must contain a valid DSDT or SSDT containing a
|
||||
* single control method.
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status acpi_install_method(u8 *buffer)
|
||||
{
|
||||
struct acpi_table_header *table =
|
||||
ACPI_CAST_PTR(struct acpi_table_header, buffer);
|
||||
u8 *aml_buffer;
|
||||
u8 *aml_start;
|
||||
char *path;
|
||||
struct acpi_namespace_node *node;
|
||||
union acpi_operand_object *method_obj;
|
||||
struct acpi_parse_state parser_state;
|
||||
u32 aml_length;
|
||||
u16 opcode;
|
||||
u8 method_flags;
|
||||
acpi_status status;
|
||||
|
||||
/* Parameter validation */
|
||||
|
||||
if (!buffer) {
|
||||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
/* Table must be a DSDT or SSDT */
|
||||
|
||||
if (!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) &&
|
||||
!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) {
|
||||
return AE_BAD_HEADER;
|
||||
}
|
||||
|
||||
/* First AML opcode in the table must be a control method */
|
||||
|
||||
parser_state.aml = buffer + sizeof(struct acpi_table_header);
|
||||
opcode = acpi_ps_peek_opcode(&parser_state);
|
||||
if (opcode != AML_METHOD_OP) {
|
||||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
/* Extract method information from the raw AML */
|
||||
|
||||
parser_state.aml += acpi_ps_get_opcode_size(opcode);
|
||||
parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state);
|
||||
path = acpi_ps_get_next_namestring(&parser_state);
|
||||
method_flags = *parser_state.aml++;
|
||||
aml_start = parser_state.aml;
|
||||
aml_length = ACPI_PTR_DIFF(parser_state.pkg_end, aml_start);
|
||||
|
||||
/*
|
||||
* Allocate resources up-front. We don't want to have to delete a new
|
||||
* node from the namespace if we cannot allocate memory.
|
||||
*/
|
||||
aml_buffer = ACPI_ALLOCATE(aml_length);
|
||||
if (!aml_buffer) {
|
||||
return AE_NO_MEMORY;
|
||||
}
|
||||
|
||||
method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
|
||||
if (!method_obj) {
|
||||
ACPI_FREE(aml_buffer);
|
||||
return AE_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Lock namespace for acpi_ns_lookup, we may be creating a new node */
|
||||
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
/* The lookup either returns an existing node or creates a new one */
|
||||
|
||||
status =
|
||||
acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1,
|
||||
ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND,
|
||||
NULL, &node);
|
||||
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
|
||||
if (ACPI_FAILURE(status)) { /* ns_lookup */
|
||||
if (status != AE_ALREADY_EXISTS) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
/* Node existed previously, make sure it is a method node */
|
||||
|
||||
if (node->type != ACPI_TYPE_METHOD) {
|
||||
status = AE_TYPE;
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the method AML to the local buffer */
|
||||
|
||||
ACPI_MEMCPY(aml_buffer, aml_start, aml_length);
|
||||
|
||||
/* Initialize the method object with the new method's information */
|
||||
|
||||
method_obj->method.aml_start = aml_buffer;
|
||||
method_obj->method.aml_length = aml_length;
|
||||
|
||||
method_obj->method.param_count = (u8)
|
||||
(method_flags & AML_METHOD_ARG_COUNT);
|
||||
|
||||
method_obj->method.method_flags = (u8)
|
||||
(method_flags & ~AML_METHOD_ARG_COUNT);
|
||||
|
||||
if (method_flags & AML_METHOD_SERIALIZED) {
|
||||
method_obj->method.sync_level = (u8)
|
||||
((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that it is complete, we can attach the new method object to
|
||||
* the method Node (detaches/deletes any existing object)
|
||||
*/
|
||||
status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD);
|
||||
|
||||
/*
|
||||
* Flag indicates AML buffer is dynamic, must be deleted later.
|
||||
* Must be set only after attach above.
|
||||
*/
|
||||
node->flags |= ANOBJ_ALLOCATED_BUFFER;
|
||||
|
||||
/* Remove local reference to the method object */
|
||||
|
||||
acpi_ut_remove_reference(method_obj);
|
||||
return status;
|
||||
|
||||
error_exit:
|
||||
|
||||
ACPI_FREE(aml_buffer);
|
||||
ACPI_FREE(method_obj);
|
||||
return status;
|
||||
}
|
||||
ACPI_EXPORT_SYMBOL(acpi_install_method)
|
||||
|
|
|
@ -201,6 +201,8 @@ acpi_evaluate_object_typed(acpi_handle object,
|
|||
acpi_status
|
||||
acpi_get_object_info(acpi_handle handle, struct acpi_buffer *return_buffer);
|
||||
|
||||
acpi_status acpi_install_method(u8 *buffer);
|
||||
|
||||
acpi_status
|
||||
acpi_get_next_object(acpi_object_type type,
|
||||
acpi_handle parent,
|
||||
|
|
Loading…
Reference in a new issue