diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-01-12 23:45:52 +0100 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-01-12 23:45:52 +0100 |
commit | fbb9c10d40f88011ac72f855c97e3bdd981026a9 (patch) | |
tree | 255b3c21fd859004310bfad0a829ea4392d4851b /drivers/acpi | |
parent | 3e7cc142c1e040fd4629ad34a54b1c5b46dc3dd3 (diff) | |
parent | 7ede9f8a1805b26b3141730c9deaea8bc95a64bc (diff) |
Merge branch 'acpi-dsm'
* acpi-dsm:
ACPI / extlog: replace open-coded _DSM code with helper functions
ACPI / nouveau: replace open-coded _DSM code with helper functions
nouveau / ACPI: fix memory leak in ACPI _DSM related code
ACPI / i915: replace open-coded _DSM code with helper functions
ACPI / i2c-hid: replace open-coded _DSM code with helper functions
ACPI / TPM: detect PPI features by checking availability of _DSM functions
ACPI / TPM: replace open-coded _DSM code with helper functions
ACPI / TPM: match node name instead of full path when searching for TPM device
PCI / pci-label: treat PCI label with index 0 as valid label
ACPI / PCI: replace open-coded _DSM code with helper functions
PCI / pci-label: release allocated ACPI object on error recovery path
ACPI: introduce helper interfaces for _DSM method
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/acpi_extlog.c | 61 | ||||
-rw-r--r-- | drivers/acpi/utils.c | 97 |
2 files changed, 109 insertions, 49 deletions
diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index 2635a01c5b3e..94166680b3a3 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -19,11 +19,9 @@ #define EXT_ELOG_ENTRY_MASK GENMASK_ULL(51, 0) /* elog entry address mask */ #define EXTLOG_DSM_REV 0x0 -#define EXTLOG_FN_QUERY 0x0 #define EXTLOG_FN_ADDR 0x1 #define FLAG_OS_OPTIN BIT(0) -#define EXTLOG_QUERY_L1_EXIST BIT(1) #define ELOG_ENTRY_VALID (1ULL<<63) #define ELOG_ENTRY_LEN 0x1000 @@ -42,7 +40,7 @@ struct extlog_l1_head { u8 rev1[12]; }; -static u8 extlog_dsm_uuid[] = "663E35AF-CC10-41A4-88EA-5470AF055295"; +static u8 extlog_dsm_uuid[] __initdata = "663E35AF-CC10-41A4-88EA-5470AF055295"; /* L1 table related physical address */ static u64 elog_base; @@ -152,62 +150,27 @@ static int extlog_print(struct notifier_block *nb, unsigned long val, return NOTIFY_DONE; } -static int extlog_get_dsm(acpi_handle handle, int rev, int func, u64 *ret) +static bool __init extlog_get_l1addr(void) { - struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; - struct acpi_object_list input; - union acpi_object params[4], *obj; u8 uuid[16]; - int i; + acpi_handle handle; + union acpi_object *obj; acpi_str_to_uuid(extlog_dsm_uuid, uuid); - input.count = 4; - input.pointer = params; - params[0].type = ACPI_TYPE_BUFFER; - params[0].buffer.length = 16; - params[0].buffer.pointer = uuid; - params[1].type = ACPI_TYPE_INTEGER; - params[1].integer.value = rev; - params[2].type = ACPI_TYPE_INTEGER; - params[2].integer.value = func; - params[3].type = ACPI_TYPE_PACKAGE; - params[3].package.count = 0; - params[3].package.elements = NULL; - - if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DSM", &input, &buf))) - return -1; - - *ret = 0; - obj = (union acpi_object *)buf.pointer; - if (obj->type == ACPI_TYPE_INTEGER) { - *ret = obj->integer.value; - } else if (obj->type == ACPI_TYPE_BUFFER) { - if (obj->buffer.length <= 8) { - for (i = 0; i < obj->buffer.length; i++) - *ret |= (obj->buffer.pointer[i] << (i * 8)); - } - } - kfree(buf.pointer); - - return 0; -} - -static bool extlog_get_l1addr(void) -{ - acpi_handle handle; - u64 ret; if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) return false; - - if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_QUERY, &ret) || - !(ret & EXTLOG_QUERY_L1_EXIST)) + if (!acpi_check_dsm(handle, uuid, EXTLOG_DSM_REV, 1 << EXTLOG_FN_ADDR)) return false; - - if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_ADDR, &ret)) + obj = acpi_evaluate_dsm_typed(handle, uuid, EXTLOG_DSM_REV, + EXTLOG_FN_ADDR, NULL, ACPI_TYPE_INTEGER); + if (!obj) { return false; + } else { + l1_dirbase = obj->integer.value; + ACPI_FREE(obj); + } - l1_dirbase = ret; /* Spec says L1 directory must be 4K aligned, bail out if it isn't */ if (l1_dirbase & ((1 << 12) - 1)) { pr_warn(FW_BUG "L1 Directory is invalid at physical %llx\n", diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 1336b9151479..0347a37eb438 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -572,3 +572,100 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock) return status; } + +/** + * acpi_evaluate_dsm - evaluate device's _DSM method + * @handle: ACPI device handle + * @uuid: UUID of requested functions, should be 16 bytes + * @rev: revision number of requested function + * @func: requested function number + * @argv4: the function specific parameter + * + * Evaluate device's _DSM method with specified UUID, revision id and + * function number. Caller needs to free the returned object. + * + * Though ACPI defines the fourth parameter for _DSM should be a package, + * some old BIOSes do expect a buffer or an integer etc. + */ +union acpi_object * +acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, int rev, int func, + union acpi_object *argv4) +{ + acpi_status ret; + struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object params[4]; + struct acpi_object_list input = { + .count = 4, + .pointer = params, + }; + + params[0].type = ACPI_TYPE_BUFFER; + params[0].buffer.length = 16; + params[0].buffer.pointer = (char *)uuid; + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = rev; + params[2].type = ACPI_TYPE_INTEGER; + params[2].integer.value = func; + if (argv4) { + params[3] = *argv4; + } else { + params[3].type = ACPI_TYPE_PACKAGE; + params[3].package.count = 0; + params[3].package.elements = NULL; + } + + ret = acpi_evaluate_object(handle, "_DSM", &input, &buf); + if (ACPI_SUCCESS(ret)) + return (union acpi_object *)buf.pointer; + + if (ret != AE_NOT_FOUND) + acpi_handle_warn(handle, + "failed to evaluate _DSM (0x%x)\n", ret); + + return NULL; +} +EXPORT_SYMBOL(acpi_evaluate_dsm); + +/** + * acpi_check_dsm - check if _DSM method supports requested functions. + * @handle: ACPI device handle + * @uuid: UUID of requested functions, should be 16 bytes at least + * @rev: revision number of requested functions + * @funcs: bitmap of requested functions + * @exclude: excluding special value, used to support i915 and nouveau + * + * Evaluate device's _DSM method to check whether it supports requested + * functions. Currently only support 64 functions at maximum, should be + * enough for now. + */ +bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs) +{ + int i; + u64 mask = 0; + union acpi_object *obj; + + if (funcs == 0) + return false; + + obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL); + if (!obj) + return false; + + /* For compatibility, old BIOSes may return an integer */ + if (obj->type == ACPI_TYPE_INTEGER) + mask = obj->integer.value; + else if (obj->type == ACPI_TYPE_BUFFER) + for (i = 0; i < obj->buffer.length && i < 8; i++) + mask |= (((u8)obj->buffer.pointer[i]) << (i * 8)); + ACPI_FREE(obj); + + /* + * Bit 0 indicates whether there's support for any functions other than + * function 0 for the specified UUID and revision. + */ + if ((mask & 0x1) && (mask & funcs) == funcs) + return true; + + return false; +} +EXPORT_SYMBOL(acpi_check_dsm); |