aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-01-12 17:45:52 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-01-12 17:45:52 -0500
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 @@
19#define EXT_ELOG_ENTRY_MASK GENMASK_ULL(51, 0) /* elog entry address mask */ 19#define EXT_ELOG_ENTRY_MASK GENMASK_ULL(51, 0) /* elog entry address mask */
20 20
21#define EXTLOG_DSM_REV 0x0 21#define EXTLOG_DSM_REV 0x0
22#define EXTLOG_FN_QUERY 0x0
23#define EXTLOG_FN_ADDR 0x1 22#define EXTLOG_FN_ADDR 0x1
24 23
25#define FLAG_OS_OPTIN BIT(0) 24#define FLAG_OS_OPTIN BIT(0)
26#define EXTLOG_QUERY_L1_EXIST BIT(1)
27#define ELOG_ENTRY_VALID (1ULL<<63) 25#define ELOG_ENTRY_VALID (1ULL<<63)
28#define ELOG_ENTRY_LEN 0x1000 26#define ELOG_ENTRY_LEN 0x1000
29 27
@@ -42,7 +40,7 @@ struct extlog_l1_head {
42 u8 rev1[12]; 40 u8 rev1[12];
43}; 41};
44 42
45static u8 extlog_dsm_uuid[] = "663E35AF-CC10-41A4-88EA-5470AF055295"; 43static u8 extlog_dsm_uuid[] __initdata = "663E35AF-CC10-41A4-88EA-5470AF055295";
46 44
47/* L1 table related physical address */ 45/* L1 table related physical address */
48static u64 elog_base; 46static u64 elog_base;
@@ -152,62 +150,27 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
152 return NOTIFY_DONE; 150 return NOTIFY_DONE;
153} 151}
154 152
155static int extlog_get_dsm(acpi_handle handle, int rev, int func, u64 *ret) 153static bool __init extlog_get_l1addr(void)
156{ 154{
157 struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
158 struct acpi_object_list input;
159 union acpi_object params[4], *obj;
160 u8 uuid[16]; 155 u8 uuid[16];
161 int i; 156 acpi_handle handle;
157 union acpi_object *obj;
162 158
163 acpi_str_to_uuid(extlog_dsm_uuid, uuid); 159 acpi_str_to_uuid(extlog_dsm_uuid, uuid);
164 input.count = 4;
165 input.pointer = params;
166 params[0].type = ACPI_TYPE_BUFFER;
167 params[0].buffer.length = 16;
168 params[0].buffer.pointer = uuid;
169 params[1].type = ACPI_TYPE_INTEGER;
170 params[1].integer.value = rev;
171 params[2].type = ACPI_TYPE_INTEGER;
172 params[2].integer.value = func;
173 params[3].type = ACPI_TYPE_PACKAGE;
174 params[3].package.count = 0;
175 params[3].package.elements = NULL;
176
177 if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DSM", &input, &buf)))
178 return -1;
179
180 *ret = 0;
181 obj = (union acpi_object *)buf.pointer;
182 if (obj->type == ACPI_TYPE_INTEGER) {
183 *ret = obj->integer.value;
184 } else if (obj->type == ACPI_TYPE_BUFFER) {
185 if (obj->buffer.length <= 8) {
186 for (i = 0; i < obj->buffer.length; i++)
187 *ret |= (obj->buffer.pointer[i] << (i * 8));
188 }
189 }
190 kfree(buf.pointer);
191
192 return 0;
193}
194
195static bool extlog_get_l1addr(void)
196{
197 acpi_handle handle;
198 u64 ret;
199 160
200 if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) 161 if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)))
201 return false; 162 return false;
202 163 if (!acpi_check_dsm(handle, uuid, EXTLOG_DSM_REV, 1 << EXTLOG_FN_ADDR))
203 if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_QUERY, &ret) ||
204 !(ret & EXTLOG_QUERY_L1_EXIST))
205 return false; 164 return false;
206 165 obj = acpi_evaluate_dsm_typed(handle, uuid, EXTLOG_DSM_REV,
207 if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_ADDR, &ret)) 166 EXTLOG_FN_ADDR, NULL, ACPI_TYPE_INTEGER);
167 if (!obj) {
208 return false; 168 return false;
169 } else {
170 l1_dirbase = obj->integer.value;
171 ACPI_FREE(obj);
172 }
209 173
210 l1_dirbase = ret;
211 /* Spec says L1 directory must be 4K aligned, bail out if it isn't */ 174 /* Spec says L1 directory must be 4K aligned, bail out if it isn't */
212 if (l1_dirbase & ((1 << 12) - 1)) { 175 if (l1_dirbase & ((1 << 12) - 1)) {
213 pr_warn(FW_BUG "L1 Directory is invalid at physical %llx\n", 176 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)
572 572
573 return status; 573 return status;
574} 574}
575
576/**
577 * acpi_evaluate_dsm - evaluate device's _DSM method
578 * @handle: ACPI device handle
579 * @uuid: UUID of requested functions, should be 16 bytes
580 * @rev: revision number of requested function
581 * @func: requested function number
582 * @argv4: the function specific parameter
583 *
584 * Evaluate device's _DSM method with specified UUID, revision id and
585 * function number. Caller needs to free the returned object.
586 *
587 * Though ACPI defines the fourth parameter for _DSM should be a package,
588 * some old BIOSes do expect a buffer or an integer etc.
589 */
590union acpi_object *
591acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, int rev, int func,
592 union acpi_object *argv4)
593{
594 acpi_status ret;
595 struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
596 union acpi_object params[4];
597 struct acpi_object_list input = {
598 .count = 4,
599 .pointer = params,
600 };
601
602 params[0].type = ACPI_TYPE_BUFFER;
603 params[0].buffer.length = 16;
604 params[0].buffer.pointer = (char *)uuid;
605 params[1].type = ACPI_TYPE_INTEGER;
606 params[1].integer.value = rev;
607 params[2].type = ACPI_TYPE_INTEGER;
608 params[2].integer.value = func;
609 if (argv4) {
610 params[3] = *argv4;
611 } else {
612 params[3].type = ACPI_TYPE_PACKAGE;
613 params[3].package.count = 0;
614 params[3].package.elements = NULL;
615 }
616
617 ret = acpi_evaluate_object(handle, "_DSM", &input, &buf);
618 if (ACPI_SUCCESS(ret))
619 return (union acpi_object *)buf.pointer;
620
621 if (ret != AE_NOT_FOUND)
622 acpi_handle_warn(handle,
623 "failed to evaluate _DSM (0x%x)\n", ret);
624
625 return NULL;
626}
627EXPORT_SYMBOL(acpi_evaluate_dsm);
628
629/**
630 * acpi_check_dsm - check if _DSM method supports requested functions.
631 * @handle: ACPI device handle
632 * @uuid: UUID of requested functions, should be 16 bytes at least
633 * @rev: revision number of requested functions
634 * @funcs: bitmap of requested functions
635 * @exclude: excluding special value, used to support i915 and nouveau
636 *
637 * Evaluate device's _DSM method to check whether it supports requested
638 * functions. Currently only support 64 functions at maximum, should be
639 * enough for now.
640 */
641bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs)
642{
643 int i;
644 u64 mask = 0;
645 union acpi_object *obj;
646
647 if (funcs == 0)
648 return false;
649
650 obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL);
651 if (!obj)
652 return false;
653
654 /* For compatibility, old BIOSes may return an integer */
655 if (obj->type == ACPI_TYPE_INTEGER)
656 mask = obj->integer.value;
657 else if (obj->type == ACPI_TYPE_BUFFER)
658 for (i = 0; i < obj->buffer.length && i < 8; i++)
659 mask |= (((u8)obj->buffer.pointer[i]) << (i * 8));
660 ACPI_FREE(obj);
661
662 /*
663 * Bit 0 indicates whether there's support for any functions other than
664 * function 0 for the specified UUID and revision.
665 */
666 if ((mask & 0x1) && (mask & funcs) == funcs)
667 return true;
668
669 return false;
670}
671EXPORT_SYMBOL(acpi_check_dsm);