summaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-01-12 23:45:52 +0100
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-01-12 23:45:52 +0100
commitfbb9c10d40f88011ac72f855c97e3bdd981026a9 (patch)
tree255b3c21fd859004310bfad0a829ea4392d4851b /drivers/acpi
parent3e7cc142c1e040fd4629ad34a54b1c5b46dc3dd3 (diff)
parent7ede9f8a1805b26b3141730c9deaea8bc95a64bc (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.c61
-rw-r--r--drivers/acpi/utils.c97
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);