diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-01-12 17:45:52 -0500 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-01-12 17:45:52 -0500 |
| 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 @@ | |||
| 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 | ||
| 45 | static u8 extlog_dsm_uuid[] = "663E35AF-CC10-41A4-88EA-5470AF055295"; | 43 | static u8 extlog_dsm_uuid[] __initdata = "663E35AF-CC10-41A4-88EA-5470AF055295"; |
| 46 | 44 | ||
| 47 | /* L1 table related physical address */ | 45 | /* L1 table related physical address */ |
| 48 | static u64 elog_base; | 46 | static 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 | ||
| 155 | static int extlog_get_dsm(acpi_handle handle, int rev, int func, u64 *ret) | 153 | static 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 | |||
| 195 | static 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 | */ | ||
| 590 | union acpi_object * | ||
| 591 | acpi_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 | } | ||
| 627 | EXPORT_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 | */ | ||
| 641 | bool 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 | } | ||
| 671 | EXPORT_SYMBOL(acpi_check_dsm); | ||
