diff options
| -rw-r--r-- | drivers/acpi/acpi_extlog.c | 61 | ||||
| -rw-r--r-- | drivers/acpi/utils.c | 97 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm_ppi.c | 405 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_acpi.c | 144 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/mxm/base.c | 48 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_acpi.c | 131 | ||||
| -rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 26 | ||||
| -rw-r--r-- | drivers/pci/pci-label.c | 129 | ||||
| -rw-r--r-- | include/acpi/acpi_bus.h | 26 |
9 files changed, 403 insertions, 664 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); | ||
diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index 70dbee4b50e9..b3ea223585bd 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c | |||
| @@ -1,15 +1,6 @@ | |||
| 1 | #include <linux/acpi.h> | 1 | #include <linux/acpi.h> |
| 2 | #include "tpm.h" | 2 | #include "tpm.h" |
| 3 | 3 | ||
| 4 | static const u8 tpm_ppi_uuid[] = { | ||
| 5 | 0xA6, 0xFA, 0xDD, 0x3D, | ||
| 6 | 0x1B, 0x36, | ||
| 7 | 0xB4, 0x4E, | ||
| 8 | 0xA4, 0x24, | ||
| 9 | 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 | ||
| 10 | }; | ||
| 11 | static char *tpm_device_name = "TPM"; | ||
| 12 | |||
| 13 | #define TPM_PPI_REVISION_ID 1 | 4 | #define TPM_PPI_REVISION_ID 1 |
| 14 | #define TPM_PPI_FN_VERSION 1 | 5 | #define TPM_PPI_FN_VERSION 1 |
| 15 | #define TPM_PPI_FN_SUBREQ 2 | 6 | #define TPM_PPI_FN_SUBREQ 2 |
| @@ -23,250 +14,178 @@ static char *tpm_device_name = "TPM"; | |||
| 23 | #define PPI_VS_REQ_END 255 | 14 | #define PPI_VS_REQ_END 255 |
| 24 | #define PPI_VERSION_LEN 3 | 15 | #define PPI_VERSION_LEN 3 |
| 25 | 16 | ||
| 17 | static const u8 tpm_ppi_uuid[] = { | ||
| 18 | 0xA6, 0xFA, 0xDD, 0x3D, | ||
| 19 | 0x1B, 0x36, | ||
| 20 | 0xB4, 0x4E, | ||
| 21 | 0xA4, 0x24, | ||
| 22 | 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 | ||
| 23 | }; | ||
| 24 | |||
| 25 | static char tpm_ppi_version[PPI_VERSION_LEN + 1]; | ||
| 26 | static acpi_handle tpm_ppi_handle; | ||
| 27 | |||
| 26 | static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, | 28 | static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, |
| 27 | void **return_value) | 29 | void **return_value) |
| 28 | { | 30 | { |
| 29 | acpi_status status = AE_OK; | 31 | union acpi_object *obj; |
| 30 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 31 | 32 | ||
| 32 | if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) { | 33 | if (!acpi_check_dsm(handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, |
| 33 | if (strstr(buffer.pointer, context) != NULL) { | 34 | 1 << TPM_PPI_FN_VERSION)) |
| 34 | *return_value = handle; | 35 | return AE_OK; |
| 35 | status = AE_CTRL_TERMINATE; | 36 | |
| 36 | } | 37 | /* Cache version string */ |
| 37 | kfree(buffer.pointer); | 38 | obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid, |
| 39 | TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, | ||
| 40 | NULL, ACPI_TYPE_STRING); | ||
| 41 | if (obj) { | ||
| 42 | strlcpy(tpm_ppi_version, obj->string.pointer, | ||
| 43 | PPI_VERSION_LEN + 1); | ||
| 44 | ACPI_FREE(obj); | ||
| 38 | } | 45 | } |
| 39 | 46 | ||
| 40 | return status; | 47 | *return_value = handle; |
| 48 | |||
| 49 | return AE_CTRL_TERMINATE; | ||
| 41 | } | 50 | } |
| 42 | 51 | ||
| 43 | static inline void ppi_assign_params(union acpi_object params[4], | 52 | static inline union acpi_object * |
| 44 | u64 function_num) | 53 | tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4) |
| 45 | { | 54 | { |
| 46 | params[0].type = ACPI_TYPE_BUFFER; | 55 | BUG_ON(!tpm_ppi_handle); |
| 47 | params[0].buffer.length = sizeof(tpm_ppi_uuid); | 56 | return acpi_evaluate_dsm_typed(tpm_ppi_handle, tpm_ppi_uuid, |
| 48 | params[0].buffer.pointer = (char *)tpm_ppi_uuid; | 57 | TPM_PPI_REVISION_ID, func, argv4, type); |
| 49 | params[1].type = ACPI_TYPE_INTEGER; | ||
| 50 | params[1].integer.value = TPM_PPI_REVISION_ID; | ||
| 51 | params[2].type = ACPI_TYPE_INTEGER; | ||
| 52 | params[2].integer.value = function_num; | ||
| 53 | params[3].type = ACPI_TYPE_PACKAGE; | ||
| 54 | params[3].package.count = 0; | ||
| 55 | params[3].package.elements = NULL; | ||
| 56 | } | 58 | } |
| 57 | 59 | ||
| 58 | static ssize_t tpm_show_ppi_version(struct device *dev, | 60 | static ssize_t tpm_show_ppi_version(struct device *dev, |
| 59 | struct device_attribute *attr, char *buf) | 61 | struct device_attribute *attr, char *buf) |
| 60 | { | 62 | { |
| 61 | acpi_handle handle; | 63 | return scnprintf(buf, PAGE_SIZE, "%s\n", tpm_ppi_version); |
| 62 | acpi_status status; | ||
| 63 | struct acpi_object_list input; | ||
| 64 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 65 | union acpi_object params[4]; | ||
| 66 | union acpi_object *obj; | ||
| 67 | |||
| 68 | input.count = 4; | ||
| 69 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
| 70 | input.pointer = params; | ||
| 71 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
| 72 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
| 73 | tpm_device_name, &handle); | ||
| 74 | if (ACPI_FAILURE(status)) | ||
| 75 | return -ENXIO; | ||
| 76 | |||
| 77 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 78 | ACPI_TYPE_STRING); | ||
| 79 | if (ACPI_FAILURE(status)) | ||
| 80 | return -ENOMEM; | ||
| 81 | obj = (union acpi_object *)output.pointer; | ||
| 82 | status = scnprintf(buf, PAGE_SIZE, "%s\n", obj->string.pointer); | ||
| 83 | kfree(output.pointer); | ||
| 84 | return status; | ||
| 85 | } | 64 | } |
| 86 | 65 | ||
| 87 | static ssize_t tpm_show_ppi_request(struct device *dev, | 66 | static ssize_t tpm_show_ppi_request(struct device *dev, |
| 88 | struct device_attribute *attr, char *buf) | 67 | struct device_attribute *attr, char *buf) |
| 89 | { | 68 | { |
| 90 | acpi_handle handle; | 69 | ssize_t size = -EINVAL; |
| 91 | acpi_status status; | 70 | union acpi_object *obj; |
| 92 | struct acpi_object_list input; | 71 | |
| 93 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | 72 | obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL); |
| 94 | union acpi_object params[4]; | 73 | if (!obj) |
| 95 | union acpi_object *ret_obj; | ||
| 96 | |||
| 97 | input.count = 4; | ||
| 98 | ppi_assign_params(params, TPM_PPI_FN_GETREQ); | ||
| 99 | input.pointer = params; | ||
| 100 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
| 101 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
| 102 | tpm_device_name, &handle); | ||
| 103 | if (ACPI_FAILURE(status)) | ||
| 104 | return -ENXIO; | 74 | return -ENXIO; |
| 105 | 75 | ||
| 106 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 107 | ACPI_TYPE_PACKAGE); | ||
| 108 | if (ACPI_FAILURE(status)) | ||
| 109 | return -ENOMEM; | ||
| 110 | /* | 76 | /* |
| 111 | * output.pointer should be of package type, including two integers. | 77 | * output.pointer should be of package type, including two integers. |
| 112 | * The first is function return code, 0 means success and 1 means | 78 | * The first is function return code, 0 means success and 1 means |
| 113 | * error. The second is pending TPM operation requested by the OS, 0 | 79 | * error. The second is pending TPM operation requested by the OS, 0 |
| 114 | * means none and >0 means operation value. | 80 | * means none and >0 means operation value. |
| 115 | */ | 81 | */ |
| 116 | ret_obj = ((union acpi_object *)output.pointer)->package.elements; | 82 | if (obj->package.count == 2 && |
| 117 | if (ret_obj->type == ACPI_TYPE_INTEGER) { | 83 | obj->package.elements[0].type == ACPI_TYPE_INTEGER && |
| 118 | if (ret_obj->integer.value) { | 84 | obj->package.elements[1].type == ACPI_TYPE_INTEGER) { |
| 119 | status = -EFAULT; | 85 | if (obj->package.elements[0].integer.value) |
| 120 | goto cleanup; | 86 | size = -EFAULT; |
| 121 | } | ||
| 122 | ret_obj++; | ||
| 123 | if (ret_obj->type == ACPI_TYPE_INTEGER) | ||
| 124 | status = scnprintf(buf, PAGE_SIZE, "%llu\n", | ||
| 125 | ret_obj->integer.value); | ||
| 126 | else | 87 | else |
| 127 | status = -EINVAL; | 88 | size = scnprintf(buf, PAGE_SIZE, "%llu\n", |
| 128 | } else { | 89 | obj->package.elements[1].integer.value); |
| 129 | status = -EINVAL; | ||
| 130 | } | 90 | } |
| 131 | cleanup: | 91 | |
| 132 | kfree(output.pointer); | 92 | ACPI_FREE(obj); |
| 133 | return status; | 93 | |
| 94 | return size; | ||
| 134 | } | 95 | } |
| 135 | 96 | ||
| 136 | static ssize_t tpm_store_ppi_request(struct device *dev, | 97 | static ssize_t tpm_store_ppi_request(struct device *dev, |
| 137 | struct device_attribute *attr, | 98 | struct device_attribute *attr, |
| 138 | const char *buf, size_t count) | 99 | const char *buf, size_t count) |
| 139 | { | 100 | { |
| 140 | char version[PPI_VERSION_LEN + 1]; | ||
| 141 | acpi_handle handle; | ||
| 142 | acpi_status status; | ||
| 143 | struct acpi_object_list input; | ||
| 144 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 145 | union acpi_object params[4]; | ||
| 146 | union acpi_object obj; | ||
| 147 | u32 req; | 101 | u32 req; |
| 148 | u64 ret; | 102 | u64 ret; |
| 103 | int func = TPM_PPI_FN_SUBREQ; | ||
| 104 | union acpi_object *obj, tmp; | ||
| 105 | union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp); | ||
| 149 | 106 | ||
| 150 | input.count = 4; | ||
| 151 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
| 152 | input.pointer = params; | ||
| 153 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
| 154 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
| 155 | tpm_device_name, &handle); | ||
| 156 | if (ACPI_FAILURE(status)) | ||
| 157 | return -ENXIO; | ||
| 158 | |||
| 159 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 160 | ACPI_TYPE_STRING); | ||
| 161 | if (ACPI_FAILURE(status)) | ||
| 162 | return -ENOMEM; | ||
| 163 | strlcpy(version, | ||
| 164 | ((union acpi_object *)output.pointer)->string.pointer, | ||
| 165 | PPI_VERSION_LEN + 1); | ||
| 166 | kfree(output.pointer); | ||
| 167 | output.length = ACPI_ALLOCATE_BUFFER; | ||
| 168 | output.pointer = NULL; | ||
| 169 | /* | 107 | /* |
| 170 | * the function to submit TPM operation request to pre-os environment | 108 | * the function to submit TPM operation request to pre-os environment |
| 171 | * is updated with function index from SUBREQ to SUBREQ2 since PPI | 109 | * is updated with function index from SUBREQ to SUBREQ2 since PPI |
| 172 | * version 1.1 | 110 | * version 1.1 |
| 173 | */ | 111 | */ |
| 174 | if (strcmp(version, "1.1") == -1) | 112 | if (acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, |
| 175 | params[2].integer.value = TPM_PPI_FN_SUBREQ; | 113 | 1 << TPM_PPI_FN_SUBREQ2)) |
| 176 | else | 114 | func = TPM_PPI_FN_SUBREQ2; |
| 177 | params[2].integer.value = TPM_PPI_FN_SUBREQ2; | 115 | |
| 178 | /* | 116 | /* |
| 179 | * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS | 117 | * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS |
| 180 | * accept buffer/string/integer type, but some BIOS accept buffer/ | 118 | * accept buffer/string/integer type, but some BIOS accept buffer/ |
| 181 | * string/package type. For PPI version 1.0 and 1.1, use buffer type | 119 | * string/package type. For PPI version 1.0 and 1.1, use buffer type |
| 182 | * for compatibility, and use package type since 1.2 according to spec. | 120 | * for compatibility, and use package type since 1.2 according to spec. |
| 183 | */ | 121 | */ |
| 184 | if (strcmp(version, "1.2") == -1) { | 122 | if (strcmp(tpm_ppi_version, "1.2") < 0) { |
| 185 | params[3].type = ACPI_TYPE_BUFFER; | 123 | if (sscanf(buf, "%d", &req) != 1) |
| 186 | params[3].buffer.length = sizeof(req); | 124 | return -EINVAL; |
| 187 | sscanf(buf, "%d", &req); | 125 | argv4.type = ACPI_TYPE_BUFFER; |
| 188 | params[3].buffer.pointer = (char *)&req; | 126 | argv4.buffer.length = sizeof(req); |
| 127 | argv4.buffer.pointer = (u8 *)&req; | ||
| 128 | } else { | ||
| 129 | tmp.type = ACPI_TYPE_INTEGER; | ||
| 130 | if (sscanf(buf, "%llu", &tmp.integer.value) != 1) | ||
| 131 | return -EINVAL; | ||
| 132 | } | ||
| 133 | |||
| 134 | obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4); | ||
| 135 | if (!obj) { | ||
| 136 | return -ENXIO; | ||
| 189 | } else { | 137 | } else { |
| 190 | params[3].package.count = 1; | 138 | ret = obj->integer.value; |
| 191 | obj.type = ACPI_TYPE_INTEGER; | 139 | ACPI_FREE(obj); |
| 192 | sscanf(buf, "%llu", &obj.integer.value); | ||
| 193 | params[3].package.elements = &obj; | ||
| 194 | } | 140 | } |
| 195 | 141 | ||
| 196 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 197 | ACPI_TYPE_INTEGER); | ||
| 198 | if (ACPI_FAILURE(status)) | ||
| 199 | return -ENOMEM; | ||
| 200 | ret = ((union acpi_object *)output.pointer)->integer.value; | ||
| 201 | if (ret == 0) | 142 | if (ret == 0) |
| 202 | status = (acpi_status)count; | 143 | return (acpi_status)count; |
| 203 | else if (ret == 1) | 144 | |
| 204 | status = -EPERM; | 145 | return (ret == 1) ? -EPERM : -EFAULT; |
| 205 | else | ||
| 206 | status = -EFAULT; | ||
| 207 | kfree(output.pointer); | ||
| 208 | return status; | ||
| 209 | } | 146 | } |
| 210 | 147 | ||
| 211 | static ssize_t tpm_show_ppi_transition_action(struct device *dev, | 148 | static ssize_t tpm_show_ppi_transition_action(struct device *dev, |
| 212 | struct device_attribute *attr, | 149 | struct device_attribute *attr, |
| 213 | char *buf) | 150 | char *buf) |
| 214 | { | 151 | { |
| 215 | char version[PPI_VERSION_LEN + 1]; | ||
| 216 | acpi_handle handle; | ||
| 217 | acpi_status status; | ||
| 218 | struct acpi_object_list input; | ||
| 219 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 220 | union acpi_object params[4]; | ||
| 221 | u32 ret; | 152 | u32 ret; |
| 222 | char *info[] = { | 153 | acpi_status status; |
| 154 | union acpi_object *obj = NULL; | ||
| 155 | union acpi_object tmp = { | ||
| 156 | .buffer.type = ACPI_TYPE_BUFFER, | ||
| 157 | .buffer.length = 0, | ||
| 158 | .buffer.pointer = NULL | ||
| 159 | }; | ||
| 160 | |||
| 161 | static char *info[] = { | ||
| 223 | "None", | 162 | "None", |
| 224 | "Shutdown", | 163 | "Shutdown", |
| 225 | "Reboot", | 164 | "Reboot", |
| 226 | "OS Vendor-specific", | 165 | "OS Vendor-specific", |
| 227 | "Error", | 166 | "Error", |
| 228 | }; | 167 | }; |
| 229 | input.count = 4; | ||
| 230 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
| 231 | input.pointer = params; | ||
| 232 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
| 233 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
| 234 | tpm_device_name, &handle); | ||
| 235 | if (ACPI_FAILURE(status)) | ||
| 236 | return -ENXIO; | ||
| 237 | 168 | ||
| 238 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 239 | ACPI_TYPE_STRING); | ||
| 240 | if (ACPI_FAILURE(status)) | ||
| 241 | return -ENOMEM; | ||
| 242 | strlcpy(version, | ||
| 243 | ((union acpi_object *)output.pointer)->string.pointer, | ||
| 244 | PPI_VERSION_LEN + 1); | ||
| 245 | /* | 169 | /* |
| 246 | * PPI spec defines params[3].type as empty package, but some platforms | 170 | * PPI spec defines params[3].type as empty package, but some platforms |
| 247 | * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for | 171 | * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for |
| 248 | * compatibility, define params[3].type as buffer, if PPI version < 1.2 | 172 | * compatibility, define params[3].type as buffer, if PPI version < 1.2 |
| 249 | */ | 173 | */ |
| 250 | if (strcmp(version, "1.2") == -1) { | 174 | if (strcmp(tpm_ppi_version, "1.2") < 0) |
| 251 | params[3].type = ACPI_TYPE_BUFFER; | 175 | obj = &tmp; |
| 252 | params[3].buffer.length = 0; | 176 | obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj); |
| 253 | params[3].buffer.pointer = NULL; | 177 | if (!obj) { |
| 178 | return -ENXIO; | ||
| 179 | } else { | ||
| 180 | ret = obj->integer.value; | ||
| 181 | ACPI_FREE(obj); | ||
| 254 | } | 182 | } |
| 255 | params[2].integer.value = TPM_PPI_FN_GETACT; | 183 | |
| 256 | kfree(output.pointer); | ||
| 257 | output.length = ACPI_ALLOCATE_BUFFER; | ||
| 258 | output.pointer = NULL; | ||
| 259 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 260 | ACPI_TYPE_INTEGER); | ||
| 261 | if (ACPI_FAILURE(status)) | ||
| 262 | return -ENOMEM; | ||
| 263 | ret = ((union acpi_object *)output.pointer)->integer.value; | ||
| 264 | if (ret < ARRAY_SIZE(info) - 1) | 184 | if (ret < ARRAY_SIZE(info) - 1) |
| 265 | status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); | 185 | status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); |
| 266 | else | 186 | else |
| 267 | status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, | 187 | status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, |
| 268 | info[ARRAY_SIZE(info)-1]); | 188 | info[ARRAY_SIZE(info)-1]); |
| 269 | kfree(output.pointer); | ||
| 270 | return status; | 189 | return status; |
| 271 | } | 190 | } |
| 272 | 191 | ||
| @@ -274,27 +193,14 @@ static ssize_t tpm_show_ppi_response(struct device *dev, | |||
| 274 | struct device_attribute *attr, | 193 | struct device_attribute *attr, |
| 275 | char *buf) | 194 | char *buf) |
| 276 | { | 195 | { |
| 277 | acpi_handle handle; | 196 | acpi_status status = -EINVAL; |
| 278 | acpi_status status; | 197 | union acpi_object *obj, *ret_obj; |
| 279 | struct acpi_object_list input; | 198 | u64 req, res; |
| 280 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | 199 | |
| 281 | union acpi_object params[4]; | 200 | obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL); |
| 282 | union acpi_object *ret_obj; | 201 | if (!obj) |
| 283 | u64 req; | ||
| 284 | |||
| 285 | input.count = 4; | ||
| 286 | ppi_assign_params(params, TPM_PPI_FN_GETRSP); | ||
| 287 | input.pointer = params; | ||
| 288 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
| 289 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
| 290 | tpm_device_name, &handle); | ||
| 291 | if (ACPI_FAILURE(status)) | ||
| 292 | return -ENXIO; | 202 | return -ENXIO; |
| 293 | 203 | ||
| 294 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 295 | ACPI_TYPE_PACKAGE); | ||
| 296 | if (ACPI_FAILURE(status)) | ||
| 297 | return -ENOMEM; | ||
| 298 | /* | 204 | /* |
| 299 | * parameter output.pointer should be of package type, including | 205 | * parameter output.pointer should be of package type, including |
| 300 | * 3 integers. The first means function return code, the second means | 206 | * 3 integers. The first means function return code, the second means |
| @@ -302,115 +208,82 @@ static ssize_t tpm_show_ppi_response(struct device *dev, | |||
| 302 | * the most recent TPM operation request. Only if the first is 0, and | 208 | * the most recent TPM operation request. Only if the first is 0, and |
| 303 | * the second integer is not 0, the response makes sense. | 209 | * the second integer is not 0, the response makes sense. |
| 304 | */ | 210 | */ |
| 305 | ret_obj = ((union acpi_object *)output.pointer)->package.elements; | 211 | ret_obj = obj->package.elements; |
| 306 | if (ret_obj->type != ACPI_TYPE_INTEGER) { | 212 | if (obj->package.count < 3 || |
| 307 | status = -EINVAL; | 213 | ret_obj[0].type != ACPI_TYPE_INTEGER || |
| 214 | ret_obj[1].type != ACPI_TYPE_INTEGER || | ||
| 215 | ret_obj[2].type != ACPI_TYPE_INTEGER) | ||
| 308 | goto cleanup; | 216 | goto cleanup; |
| 309 | } | 217 | |
| 310 | if (ret_obj->integer.value) { | 218 | if (ret_obj[0].integer.value) { |
| 311 | status = -EFAULT; | 219 | status = -EFAULT; |
| 312 | goto cleanup; | 220 | goto cleanup; |
| 313 | } | 221 | } |
| 314 | ret_obj++; | 222 | |
| 315 | if (ret_obj->type != ACPI_TYPE_INTEGER) { | 223 | req = ret_obj[1].integer.value; |
| 316 | status = -EINVAL; | 224 | res = ret_obj[2].integer.value; |
| 317 | goto cleanup; | 225 | if (req) { |
| 318 | } | 226 | if (res == 0) |
| 319 | if (ret_obj->integer.value) { | ||
| 320 | req = ret_obj->integer.value; | ||
| 321 | ret_obj++; | ||
| 322 | if (ret_obj->type != ACPI_TYPE_INTEGER) { | ||
| 323 | status = -EINVAL; | ||
| 324 | goto cleanup; | ||
| 325 | } | ||
| 326 | if (ret_obj->integer.value == 0) | ||
| 327 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, | 227 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, |
| 328 | "0: Success"); | 228 | "0: Success"); |
| 329 | else if (ret_obj->integer.value == 0xFFFFFFF0) | 229 | else if (res == 0xFFFFFFF0) |
| 330 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, | 230 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, |
| 331 | "0xFFFFFFF0: User Abort"); | 231 | "0xFFFFFFF0: User Abort"); |
| 332 | else if (ret_obj->integer.value == 0xFFFFFFF1) | 232 | else if (res == 0xFFFFFFF1) |
| 333 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, | 233 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, |
| 334 | "0xFFFFFFF1: BIOS Failure"); | 234 | "0xFFFFFFF1: BIOS Failure"); |
| 335 | else if (ret_obj->integer.value >= 1 && | 235 | else if (res >= 1 && res <= 0x00000FFF) |
| 336 | ret_obj->integer.value <= 0x00000FFF) | ||
| 337 | status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", | 236 | status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", |
| 338 | req, ret_obj->integer.value, | 237 | req, res, "Corresponding TPM error"); |
| 339 | "Corresponding TPM error"); | ||
| 340 | else | 238 | else |
| 341 | status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", | 239 | status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", |
| 342 | req, ret_obj->integer.value, | 240 | req, res, "Error"); |
| 343 | "Error"); | ||
| 344 | } else { | 241 | } else { |
| 345 | status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", | 242 | status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", |
| 346 | ret_obj->integer.value, "No Recent Request"); | 243 | req, "No Recent Request"); |
| 347 | } | 244 | } |
| 245 | |||
| 348 | cleanup: | 246 | cleanup: |
| 349 | kfree(output.pointer); | 247 | ACPI_FREE(obj); |
| 350 | return status; | 248 | return status; |
| 351 | } | 249 | } |
| 352 | 250 | ||
| 353 | static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) | 251 | static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) |
| 354 | { | 252 | { |
| 355 | char *str = buf; | ||
| 356 | char version[PPI_VERSION_LEN + 1]; | ||
| 357 | acpi_handle handle; | ||
| 358 | acpi_status status; | ||
| 359 | struct acpi_object_list input; | ||
| 360 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 361 | union acpi_object params[4]; | ||
| 362 | union acpi_object obj; | ||
| 363 | int i; | 253 | int i; |
| 364 | u32 ret; | 254 | u32 ret; |
| 365 | char *info[] = { | 255 | char *str = buf; |
| 256 | union acpi_object *obj, tmp; | ||
| 257 | union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp); | ||
| 258 | |||
| 259 | static char *info[] = { | ||
| 366 | "Not implemented", | 260 | "Not implemented", |
| 367 | "BIOS only", | 261 | "BIOS only", |
| 368 | "Blocked for OS by BIOS", | 262 | "Blocked for OS by BIOS", |
| 369 | "User required", | 263 | "User required", |
| 370 | "User not required", | 264 | "User not required", |
| 371 | }; | 265 | }; |
| 372 | input.count = 4; | ||
| 373 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
| 374 | input.pointer = params; | ||
| 375 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
| 376 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
| 377 | tpm_device_name, &handle); | ||
| 378 | if (ACPI_FAILURE(status)) | ||
| 379 | return -ENXIO; | ||
| 380 | 266 | ||
| 381 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | 267 | if (!acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, |
| 382 | ACPI_TYPE_STRING); | 268 | 1 << TPM_PPI_FN_GETOPR)) |
| 383 | if (ACPI_FAILURE(status)) | ||
| 384 | return -ENOMEM; | ||
| 385 | |||
| 386 | strlcpy(version, | ||
| 387 | ((union acpi_object *)output.pointer)->string.pointer, | ||
| 388 | PPI_VERSION_LEN + 1); | ||
| 389 | kfree(output.pointer); | ||
| 390 | output.length = ACPI_ALLOCATE_BUFFER; | ||
| 391 | output.pointer = NULL; | ||
| 392 | if (strcmp(version, "1.2") == -1) | ||
| 393 | return -EPERM; | 269 | return -EPERM; |
| 394 | 270 | ||
| 395 | params[2].integer.value = TPM_PPI_FN_GETOPR; | 271 | tmp.integer.type = ACPI_TYPE_INTEGER; |
| 396 | params[3].package.count = 1; | ||
| 397 | obj.type = ACPI_TYPE_INTEGER; | ||
| 398 | params[3].package.elements = &obj; | ||
| 399 | for (i = start; i <= end; i++) { | 272 | for (i = start; i <= end; i++) { |
| 400 | obj.integer.value = i; | 273 | tmp.integer.value = i; |
| 401 | status = acpi_evaluate_object_typed(handle, "_DSM", | 274 | obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv); |
| 402 | &input, &output, ACPI_TYPE_INTEGER); | 275 | if (!obj) { |
| 403 | if (ACPI_FAILURE(status)) | ||
| 404 | return -ENOMEM; | 276 | return -ENOMEM; |
| 277 | } else { | ||
| 278 | ret = obj->integer.value; | ||
| 279 | ACPI_FREE(obj); | ||
| 280 | } | ||
| 405 | 281 | ||
| 406 | ret = ((union acpi_object *)output.pointer)->integer.value; | ||
| 407 | if (ret > 0 && ret < ARRAY_SIZE(info)) | 282 | if (ret > 0 && ret < ARRAY_SIZE(info)) |
| 408 | str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", | 283 | str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", |
| 409 | i, ret, info[ret]); | 284 | i, ret, info[ret]); |
| 410 | kfree(output.pointer); | ||
| 411 | output.length = ACPI_ALLOCATE_BUFFER; | ||
| 412 | output.pointer = NULL; | ||
| 413 | } | 285 | } |
| 286 | |||
| 414 | return str - buf; | 287 | return str - buf; |
| 415 | } | 288 | } |
| 416 | 289 | ||
| @@ -452,6 +325,12 @@ static struct attribute_group ppi_attr_grp = { | |||
| 452 | 325 | ||
| 453 | int tpm_add_ppi(struct kobject *parent) | 326 | int tpm_add_ppi(struct kobject *parent) |
| 454 | { | 327 | { |
| 328 | /* Cache TPM ACPI handle and version string */ | ||
| 329 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, | ||
| 330 | ppi_callback, NULL, NULL, &tpm_ppi_handle); | ||
| 331 | if (tpm_ppi_handle == NULL) | ||
| 332 | return -ENODEV; | ||
| 333 | |||
| 455 | return sysfs_create_group(parent, &ppi_attr_grp); | 334 | return sysfs_create_group(parent, &ppi_attr_grp); |
| 456 | } | 335 | } |
| 457 | 336 | ||
diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c index 5325b25ccbb4..d96eee1ae9c5 100644 --- a/drivers/gpu/drm/i915/intel_acpi.c +++ b/drivers/gpu/drm/i915/intel_acpi.c | |||
| @@ -10,8 +10,6 @@ | |||
| 10 | #include "i915_drv.h" | 10 | #include "i915_drv.h" |
| 11 | 11 | ||
| 12 | #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ | 12 | #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ |
| 13 | |||
| 14 | #define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */ | ||
| 15 | #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */ | 13 | #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */ |
| 16 | 14 | ||
| 17 | static struct intel_dsm_priv { | 15 | static struct intel_dsm_priv { |
| @@ -26,61 +24,6 @@ static const u8 intel_dsm_guid[] = { | |||
| 26 | 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c | 24 | 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c |
| 27 | }; | 25 | }; |
| 28 | 26 | ||
| 29 | static int intel_dsm(acpi_handle handle, int func) | ||
| 30 | { | ||
| 31 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 32 | struct acpi_object_list input; | ||
| 33 | union acpi_object params[4]; | ||
| 34 | union acpi_object *obj; | ||
| 35 | u32 result; | ||
| 36 | int ret = 0; | ||
| 37 | |||
| 38 | input.count = 4; | ||
| 39 | input.pointer = params; | ||
| 40 | params[0].type = ACPI_TYPE_BUFFER; | ||
| 41 | params[0].buffer.length = sizeof(intel_dsm_guid); | ||
| 42 | params[0].buffer.pointer = (char *)intel_dsm_guid; | ||
| 43 | params[1].type = ACPI_TYPE_INTEGER; | ||
| 44 | params[1].integer.value = INTEL_DSM_REVISION_ID; | ||
| 45 | params[2].type = ACPI_TYPE_INTEGER; | ||
| 46 | params[2].integer.value = func; | ||
| 47 | params[3].type = ACPI_TYPE_PACKAGE; | ||
| 48 | params[3].package.count = 0; | ||
| 49 | params[3].package.elements = NULL; | ||
| 50 | |||
| 51 | ret = acpi_evaluate_object(handle, "_DSM", &input, &output); | ||
| 52 | if (ret) { | ||
| 53 | DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret); | ||
| 54 | return ret; | ||
| 55 | } | ||
| 56 | |||
| 57 | obj = (union acpi_object *)output.pointer; | ||
| 58 | |||
| 59 | result = 0; | ||
| 60 | switch (obj->type) { | ||
| 61 | case ACPI_TYPE_INTEGER: | ||
| 62 | result = obj->integer.value; | ||
| 63 | break; | ||
| 64 | |||
| 65 | case ACPI_TYPE_BUFFER: | ||
| 66 | if (obj->buffer.length == 4) { | ||
| 67 | result = (obj->buffer.pointer[0] | | ||
| 68 | (obj->buffer.pointer[1] << 8) | | ||
| 69 | (obj->buffer.pointer[2] << 16) | | ||
| 70 | (obj->buffer.pointer[3] << 24)); | ||
| 71 | break; | ||
| 72 | } | ||
| 73 | default: | ||
| 74 | ret = -EINVAL; | ||
| 75 | break; | ||
| 76 | } | ||
| 77 | if (result == 0x80000002) | ||
| 78 | ret = -ENODEV; | ||
| 79 | |||
| 80 | kfree(output.pointer); | ||
| 81 | return ret; | ||
| 82 | } | ||
| 83 | |||
| 84 | static char *intel_dsm_port_name(u8 id) | 27 | static char *intel_dsm_port_name(u8 id) |
| 85 | { | 28 | { |
| 86 | switch (id) { | 29 | switch (id) { |
| @@ -135,83 +78,56 @@ static char *intel_dsm_mux_type(u8 type) | |||
| 135 | 78 | ||
| 136 | static void intel_dsm_platform_mux_info(void) | 79 | static void intel_dsm_platform_mux_info(void) |
| 137 | { | 80 | { |
| 138 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | 81 | int i; |
| 139 | struct acpi_object_list input; | 82 | union acpi_object *pkg, *connector_count; |
| 140 | union acpi_object params[4]; | 83 | |
| 141 | union acpi_object *pkg; | 84 | pkg = acpi_evaluate_dsm_typed(intel_dsm_priv.dhandle, intel_dsm_guid, |
| 142 | int i, ret; | 85 | INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO, |
| 143 | 86 | NULL, ACPI_TYPE_PACKAGE); | |
| 144 | input.count = 4; | 87 | if (!pkg) { |
| 145 | input.pointer = params; | 88 | DRM_DEBUG_DRIVER("failed to evaluate _DSM\n"); |
| 146 | params[0].type = ACPI_TYPE_BUFFER; | 89 | return; |
| 147 | params[0].buffer.length = sizeof(intel_dsm_guid); | ||
| 148 | params[0].buffer.pointer = (char *)intel_dsm_guid; | ||
| 149 | params[1].type = ACPI_TYPE_INTEGER; | ||
| 150 | params[1].integer.value = INTEL_DSM_REVISION_ID; | ||
| 151 | params[2].type = ACPI_TYPE_INTEGER; | ||
| 152 | params[2].integer.value = INTEL_DSM_FN_PLATFORM_MUX_INFO; | ||
| 153 | params[3].type = ACPI_TYPE_PACKAGE; | ||
| 154 | params[3].package.count = 0; | ||
| 155 | params[3].package.elements = NULL; | ||
| 156 | |||
| 157 | ret = acpi_evaluate_object(intel_dsm_priv.dhandle, "_DSM", &input, | ||
| 158 | &output); | ||
| 159 | if (ret) { | ||
| 160 | DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret); | ||
| 161 | goto out; | ||
| 162 | } | 90 | } |
| 163 | 91 | ||
| 164 | pkg = (union acpi_object *)output.pointer; | 92 | connector_count = &pkg->package.elements[0]; |
| 165 | 93 | DRM_DEBUG_DRIVER("MUX info connectors: %lld\n", | |
| 166 | if (pkg->type == ACPI_TYPE_PACKAGE) { | 94 | (unsigned long long)connector_count->integer.value); |
| 167 | union acpi_object *connector_count = &pkg->package.elements[0]; | 95 | for (i = 1; i < pkg->package.count; i++) { |
| 168 | DRM_DEBUG_DRIVER("MUX info connectors: %lld\n", | 96 | union acpi_object *obj = &pkg->package.elements[i]; |
| 169 | (unsigned long long)connector_count->integer.value); | 97 | union acpi_object *connector_id = &obj->package.elements[0]; |
| 170 | for (i = 1; i < pkg->package.count; i++) { | 98 | union acpi_object *info = &obj->package.elements[1]; |
| 171 | union acpi_object *obj = &pkg->package.elements[i]; | 99 | DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n", |
| 172 | union acpi_object *connector_id = | 100 | (unsigned long long)connector_id->integer.value); |
| 173 | &obj->package.elements[0]; | 101 | DRM_DEBUG_DRIVER(" port id: %s\n", |
| 174 | union acpi_object *info = &obj->package.elements[1]; | 102 | intel_dsm_port_name(info->buffer.pointer[0])); |
| 175 | DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n", | 103 | DRM_DEBUG_DRIVER(" display mux info: %s\n", |
| 176 | (unsigned long long)connector_id->integer.value); | 104 | intel_dsm_mux_type(info->buffer.pointer[1])); |
| 177 | DRM_DEBUG_DRIVER(" port id: %s\n", | 105 | DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n", |
| 178 | intel_dsm_port_name(info->buffer.pointer[0])); | 106 | intel_dsm_mux_type(info->buffer.pointer[2])); |
| 179 | DRM_DEBUG_DRIVER(" display mux info: %s\n", | 107 | DRM_DEBUG_DRIVER(" hpd mux info: %s\n", |
| 180 | intel_dsm_mux_type(info->buffer.pointer[1])); | 108 | intel_dsm_mux_type(info->buffer.pointer[3])); |
| 181 | DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n", | ||
| 182 | intel_dsm_mux_type(info->buffer.pointer[2])); | ||
| 183 | DRM_DEBUG_DRIVER(" hpd mux info: %s\n", | ||
| 184 | intel_dsm_mux_type(info->buffer.pointer[3])); | ||
| 185 | } | ||
| 186 | } | 109 | } |
| 187 | 110 | ||
| 188 | out: | 111 | ACPI_FREE(pkg); |
| 189 | kfree(output.pointer); | ||
| 190 | } | 112 | } |
| 191 | 113 | ||
| 192 | static bool intel_dsm_pci_probe(struct pci_dev *pdev) | 114 | static bool intel_dsm_pci_probe(struct pci_dev *pdev) |
| 193 | { | 115 | { |
| 194 | acpi_handle dhandle; | 116 | acpi_handle dhandle; |
| 195 | int ret; | ||
| 196 | 117 | ||
| 197 | dhandle = ACPI_HANDLE(&pdev->dev); | 118 | dhandle = ACPI_HANDLE(&pdev->dev); |
| 198 | if (!dhandle) | 119 | if (!dhandle) |
| 199 | return false; | 120 | return false; |
| 200 | 121 | ||
| 201 | if (!acpi_has_method(dhandle, "_DSM")) { | 122 | if (!acpi_check_dsm(dhandle, intel_dsm_guid, INTEL_DSM_REVISION_ID, |
| 123 | 1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) { | ||
| 202 | DRM_DEBUG_KMS("no _DSM method for intel device\n"); | 124 | DRM_DEBUG_KMS("no _DSM method for intel device\n"); |
| 203 | return false; | 125 | return false; |
| 204 | } | 126 | } |
| 205 | 127 | ||
| 206 | ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS); | ||
| 207 | if (ret < 0) { | ||
| 208 | DRM_DEBUG_KMS("failed to get supported _DSM functions\n"); | ||
| 209 | return false; | ||
| 210 | } | ||
| 211 | |||
| 212 | intel_dsm_priv.dhandle = dhandle; | 128 | intel_dsm_priv.dhandle = dhandle; |
| 213 | |||
| 214 | intel_dsm_platform_mux_info(); | 129 | intel_dsm_platform_mux_info(); |
| 130 | |||
| 215 | return true; | 131 | return true; |
| 216 | } | 132 | } |
| 217 | 133 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c index 129120473f6c..13c5af88a601 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c | |||
| @@ -87,55 +87,39 @@ mxm_shadow_dsm(struct nouveau_mxm *mxm, u8 version) | |||
| 87 | 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65 | 87 | 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65 |
| 88 | }; | 88 | }; |
| 89 | u32 mxms_args[] = { 0x00000000 }; | 89 | u32 mxms_args[] = { 0x00000000 }; |
| 90 | union acpi_object args[4] = { | 90 | union acpi_object argv4 = { |
| 91 | /* _DSM MUID */ | 91 | .buffer.type = ACPI_TYPE_BUFFER, |
| 92 | { .buffer.type = 3, | 92 | .buffer.length = sizeof(mxms_args), |
| 93 | .buffer.length = sizeof(muid), | 93 | .buffer.pointer = (char *)mxms_args, |
| 94 | .buffer.pointer = muid, | ||
| 95 | }, | ||
| 96 | /* spec says this can be zero to mean "highest revision", but | ||
| 97 | * of course there's at least one bios out there which fails | ||
| 98 | * unless you pass in exactly the version it supports.. | ||
| 99 | */ | ||
| 100 | { .integer.type = ACPI_TYPE_INTEGER, | ||
| 101 | .integer.value = (version & 0xf0) << 4 | (version & 0x0f), | ||
| 102 | }, | ||
| 103 | /* MXMS function */ | ||
| 104 | { .integer.type = ACPI_TYPE_INTEGER, | ||
| 105 | .integer.value = 0x00000010, | ||
| 106 | }, | ||
| 107 | /* Pointer to MXMS arguments */ | ||
| 108 | { .buffer.type = ACPI_TYPE_BUFFER, | ||
| 109 | .buffer.length = sizeof(mxms_args), | ||
| 110 | .buffer.pointer = (char *)mxms_args, | ||
| 111 | }, | ||
| 112 | }; | 94 | }; |
| 113 | struct acpi_object_list list = { ARRAY_SIZE(args), args }; | ||
| 114 | struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 115 | union acpi_object *obj; | 95 | union acpi_object *obj; |
| 116 | acpi_handle handle; | 96 | acpi_handle handle; |
| 117 | int ret; | 97 | int rev; |
| 118 | 98 | ||
| 119 | handle = ACPI_HANDLE(&device->pdev->dev); | 99 | handle = ACPI_HANDLE(&device->pdev->dev); |
| 120 | if (!handle) | 100 | if (!handle) |
| 121 | return false; | 101 | return false; |
| 122 | 102 | ||
| 123 | ret = acpi_evaluate_object(handle, "_DSM", &list, &retn); | 103 | /* |
| 124 | if (ret) { | 104 | * spec says this can be zero to mean "highest revision", but |
| 125 | nv_debug(mxm, "DSM MXMS failed: %d\n", ret); | 105 | * of course there's at least one bios out there which fails |
| 106 | * unless you pass in exactly the version it supports.. | ||
| 107 | */ | ||
| 108 | rev = (version & 0xf0) << 4 | (version & 0x0f); | ||
| 109 | obj = acpi_evaluate_dsm(handle, muid, rev, 0x00000010, &argv4); | ||
| 110 | if (!obj) { | ||
| 111 | nv_debug(mxm, "DSM MXMS failed\n"); | ||
| 126 | return false; | 112 | return false; |
| 127 | } | 113 | } |
| 128 | 114 | ||
| 129 | obj = retn.pointer; | ||
| 130 | if (obj->type == ACPI_TYPE_BUFFER) { | 115 | if (obj->type == ACPI_TYPE_BUFFER) { |
| 131 | mxm->mxms = kmemdup(obj->buffer.pointer, | 116 | mxm->mxms = kmemdup(obj->buffer.pointer, |
| 132 | obj->buffer.length, GFP_KERNEL); | 117 | obj->buffer.length, GFP_KERNEL); |
| 133 | } else | 118 | } else if (obj->type == ACPI_TYPE_INTEGER) { |
| 134 | if (obj->type == ACPI_TYPE_INTEGER) { | ||
| 135 | nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value); | 119 | nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value); |
| 136 | } | 120 | } |
| 137 | 121 | ||
| 138 | kfree(obj); | 122 | ACPI_FREE(obj); |
| 139 | return mxm->mxms != NULL; | 123 | return mxm->mxms != NULL; |
| 140 | } | 124 | } |
| 141 | #endif | 125 | #endif |
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 1bc996c4f121..3c149617cfcb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c | |||
| @@ -73,124 +73,66 @@ static const char nouveau_op_dsm_muid[] = { | |||
| 73 | 73 | ||
| 74 | static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result) | 74 | static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result) |
| 75 | { | 75 | { |
| 76 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | 76 | int i; |
| 77 | struct acpi_object_list input; | ||
| 78 | union acpi_object params[4]; | ||
| 79 | union acpi_object *obj; | 77 | union acpi_object *obj; |
| 80 | int i, err; | ||
| 81 | char args_buff[4]; | 78 | char args_buff[4]; |
| 79 | union acpi_object argv4 = { | ||
| 80 | .buffer.type = ACPI_TYPE_BUFFER, | ||
| 81 | .buffer.length = 4, | ||
| 82 | .buffer.pointer = args_buff | ||
| 83 | }; | ||
| 82 | 84 | ||
| 83 | input.count = 4; | ||
| 84 | input.pointer = params; | ||
| 85 | params[0].type = ACPI_TYPE_BUFFER; | ||
| 86 | params[0].buffer.length = sizeof(nouveau_op_dsm_muid); | ||
| 87 | params[0].buffer.pointer = (char *)nouveau_op_dsm_muid; | ||
| 88 | params[1].type = ACPI_TYPE_INTEGER; | ||
| 89 | params[1].integer.value = 0x00000100; | ||
| 90 | params[2].type = ACPI_TYPE_INTEGER; | ||
| 91 | params[2].integer.value = func; | ||
| 92 | params[3].type = ACPI_TYPE_BUFFER; | ||
| 93 | params[3].buffer.length = 4; | ||
| 94 | /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */ | 85 | /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */ |
| 95 | for (i = 0; i < 4; i++) | 86 | for (i = 0; i < 4; i++) |
| 96 | args_buff[i] = (arg >> i * 8) & 0xFF; | 87 | args_buff[i] = (arg >> i * 8) & 0xFF; |
| 97 | params[3].buffer.pointer = args_buff; | ||
| 98 | 88 | ||
| 99 | err = acpi_evaluate_object(handle, "_DSM", &input, &output); | 89 | *result = 0; |
| 100 | if (err) { | 90 | obj = acpi_evaluate_dsm_typed(handle, nouveau_op_dsm_muid, 0x00000100, |
| 101 | printk(KERN_INFO "failed to evaluate _DSM: %d\n", err); | 91 | func, &argv4, ACPI_TYPE_BUFFER); |
| 102 | return err; | 92 | if (!obj) { |
| 103 | } | 93 | acpi_handle_info(handle, "failed to evaluate _DSM\n"); |
| 104 | 94 | return AE_ERROR; | |
| 105 | obj = (union acpi_object *)output.pointer; | 95 | } else { |
| 106 | 96 | if (obj->buffer.length == 4) { | |
| 107 | if (obj->type == ACPI_TYPE_INTEGER) | ||
| 108 | if (obj->integer.value == 0x80000002) { | ||
| 109 | return -ENODEV; | ||
| 110 | } | ||
| 111 | |||
| 112 | if (obj->type == ACPI_TYPE_BUFFER) { | ||
| 113 | if (obj->buffer.length == 4 && result) { | ||
| 114 | *result = 0; | ||
| 115 | *result |= obj->buffer.pointer[0]; | 97 | *result |= obj->buffer.pointer[0]; |
| 116 | *result |= (obj->buffer.pointer[1] << 8); | 98 | *result |= (obj->buffer.pointer[1] << 8); |
| 117 | *result |= (obj->buffer.pointer[2] << 16); | 99 | *result |= (obj->buffer.pointer[2] << 16); |
| 118 | *result |= (obj->buffer.pointer[3] << 24); | 100 | *result |= (obj->buffer.pointer[3] << 24); |
| 119 | } | 101 | } |
| 102 | ACPI_FREE(obj); | ||
| 120 | } | 103 | } |
| 121 | 104 | ||
| 122 | kfree(output.pointer); | ||
| 123 | return 0; | 105 | return 0; |
| 124 | } | 106 | } |
| 125 | 107 | ||
| 126 | static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) | 108 | static int nouveau_dsm(acpi_handle handle, int func, int arg) |
| 127 | { | 109 | { |
| 128 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | 110 | int ret = 0; |
| 129 | struct acpi_object_list input; | ||
| 130 | union acpi_object params[4]; | ||
| 131 | union acpi_object *obj; | 111 | union acpi_object *obj; |
| 132 | int err; | 112 | union acpi_object argv4 = { |
| 133 | 113 | .integer.type = ACPI_TYPE_INTEGER, | |
| 134 | input.count = 4; | 114 | .integer.value = arg, |
| 135 | input.pointer = params; | 115 | }; |
| 136 | params[0].type = ACPI_TYPE_BUFFER; | 116 | |
| 137 | params[0].buffer.length = sizeof(nouveau_dsm_muid); | 117 | obj = acpi_evaluate_dsm_typed(handle, nouveau_dsm_muid, 0x00000102, |
| 138 | params[0].buffer.pointer = (char *)nouveau_dsm_muid; | 118 | func, &argv4, ACPI_TYPE_INTEGER); |
| 139 | params[1].type = ACPI_TYPE_INTEGER; | 119 | if (!obj) { |
| 140 | params[1].integer.value = 0x00000102; | 120 | acpi_handle_info(handle, "failed to evaluate _DSM\n"); |
| 141 | params[2].type = ACPI_TYPE_INTEGER; | 121 | return AE_ERROR; |
| 142 | params[2].integer.value = func; | 122 | } else { |
| 143 | params[3].type = ACPI_TYPE_INTEGER; | ||
| 144 | params[3].integer.value = arg; | ||
| 145 | |||
| 146 | err = acpi_evaluate_object(handle, "_DSM", &input, &output); | ||
| 147 | if (err) { | ||
| 148 | printk(KERN_INFO "failed to evaluate _DSM: %d\n", err); | ||
| 149 | return err; | ||
| 150 | } | ||
| 151 | |||
| 152 | obj = (union acpi_object *)output.pointer; | ||
| 153 | |||
| 154 | if (obj->type == ACPI_TYPE_INTEGER) | ||
| 155 | if (obj->integer.value == 0x80000002) | 123 | if (obj->integer.value == 0x80000002) |
| 156 | return -ENODEV; | 124 | ret = -ENODEV; |
| 157 | 125 | ACPI_FREE(obj); | |
| 158 | if (obj->type == ACPI_TYPE_BUFFER) { | ||
| 159 | if (obj->buffer.length == 4 && result) { | ||
| 160 | *result = 0; | ||
| 161 | *result |= obj->buffer.pointer[0]; | ||
| 162 | *result |= (obj->buffer.pointer[1] << 8); | ||
| 163 | *result |= (obj->buffer.pointer[2] << 16); | ||
| 164 | *result |= (obj->buffer.pointer[3] << 24); | ||
| 165 | } | ||
| 166 | } | 126 | } |
| 167 | 127 | ||
| 168 | kfree(output.pointer); | 128 | return ret; |
| 169 | return 0; | ||
| 170 | } | ||
| 171 | |||
| 172 | /* Returns 1 if a DSM function is usable and 0 otherwise */ | ||
| 173 | static int nouveau_test_dsm(acpi_handle test_handle, | ||
| 174 | int (*dsm_func)(acpi_handle, int, int, uint32_t *), | ||
| 175 | int sfnc) | ||
| 176 | { | ||
| 177 | u32 result = 0; | ||
| 178 | |||
| 179 | /* Function 0 returns a Buffer containing available functions. The args | ||
| 180 | * parameter is ignored for function 0, so just put 0 in it */ | ||
| 181 | if (dsm_func(test_handle, 0, 0, &result)) | ||
| 182 | return 0; | ||
| 183 | |||
| 184 | /* ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. If | ||
| 185 | * the n-th bit is enabled, function n is supported */ | ||
| 186 | return result & 1 && result & (1 << sfnc); | ||
| 187 | } | 129 | } |
| 188 | 130 | ||
| 189 | static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id) | 131 | static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id) |
| 190 | { | 132 | { |
| 191 | mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); | 133 | mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); |
| 192 | mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); | 134 | mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); |
| 193 | return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL); | 135 | return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id); |
| 194 | } | 136 | } |
| 195 | 137 | ||
| 196 | static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state) | 138 | static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state) |
| @@ -200,7 +142,7 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero | |||
| 200 | arg = NOUVEAU_DSM_POWER_SPEED; | 142 | arg = NOUVEAU_DSM_POWER_SPEED; |
| 201 | else | 143 | else |
| 202 | arg = NOUVEAU_DSM_POWER_STAMINA; | 144 | arg = NOUVEAU_DSM_POWER_STAMINA; |
| 203 | nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg, NULL); | 145 | nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg); |
| 204 | return 0; | 146 | return 0; |
| 205 | } | 147 | } |
| 206 | 148 | ||
| @@ -260,11 +202,12 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev) | |||
| 260 | nouveau_dsm_priv.other_handle = dhandle; | 202 | nouveau_dsm_priv.other_handle = dhandle; |
| 261 | return false; | 203 | return false; |
| 262 | } | 204 | } |
| 263 | if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER)) | 205 | if (acpi_check_dsm(dhandle, nouveau_dsm_muid, 0x00000102, |
| 206 | 1 << NOUVEAU_DSM_POWER)) | ||
| 264 | retval |= NOUVEAU_DSM_HAS_MUX; | 207 | retval |= NOUVEAU_DSM_HAS_MUX; |
| 265 | 208 | ||
| 266 | if (nouveau_test_dsm(dhandle, nouveau_optimus_dsm, | 209 | if (acpi_check_dsm(dhandle, nouveau_op_dsm_muid, 0x00000100, |
| 267 | NOUVEAU_DSM_OPTIMUS_CAPS)) | 210 | 1 << NOUVEAU_DSM_OPTIMUS_CAPS)) |
| 268 | retval |= NOUVEAU_DSM_HAS_OPT; | 211 | retval |= NOUVEAU_DSM_HAS_OPT; |
| 269 | 212 | ||
| 270 | if (retval & NOUVEAU_DSM_HAS_OPT) { | 213 | if (retval & NOUVEAU_DSM_HAS_OPT) { |
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 5f7e55f4b7f0..d22668f7d982 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c | |||
| @@ -850,37 +850,23 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client, | |||
| 850 | 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45, | 850 | 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45, |
| 851 | 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE, | 851 | 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE, |
| 852 | }; | 852 | }; |
| 853 | union acpi_object params[4]; | 853 | union acpi_object *obj; |
| 854 | struct acpi_object_list input; | ||
| 855 | struct acpi_device *adev; | 854 | struct acpi_device *adev; |
| 856 | unsigned long long value; | ||
| 857 | acpi_handle handle; | 855 | acpi_handle handle; |
| 858 | 856 | ||
| 859 | handle = ACPI_HANDLE(&client->dev); | 857 | handle = ACPI_HANDLE(&client->dev); |
| 860 | if (!handle || acpi_bus_get_device(handle, &adev)) | 858 | if (!handle || acpi_bus_get_device(handle, &adev)) |
| 861 | return -ENODEV; | 859 | return -ENODEV; |
| 862 | 860 | ||
| 863 | input.count = ARRAY_SIZE(params); | 861 | obj = acpi_evaluate_dsm_typed(handle, i2c_hid_guid, 1, 1, NULL, |
| 864 | input.pointer = params; | 862 | ACPI_TYPE_INTEGER); |
| 865 | 863 | if (!obj) { | |
| 866 | params[0].type = ACPI_TYPE_BUFFER; | ||
| 867 | params[0].buffer.length = sizeof(i2c_hid_guid); | ||
| 868 | params[0].buffer.pointer = i2c_hid_guid; | ||
| 869 | params[1].type = ACPI_TYPE_INTEGER; | ||
| 870 | params[1].integer.value = 1; | ||
| 871 | params[2].type = ACPI_TYPE_INTEGER; | ||
| 872 | params[2].integer.value = 1; /* HID function */ | ||
| 873 | params[3].type = ACPI_TYPE_PACKAGE; | ||
| 874 | params[3].package.count = 0; | ||
| 875 | params[3].package.elements = NULL; | ||
| 876 | |||
| 877 | if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_DSM", &input, | ||
| 878 | &value))) { | ||
| 879 | dev_err(&client->dev, "device _DSM execution failed\n"); | 864 | dev_err(&client->dev, "device _DSM execution failed\n"); |
| 880 | return -ENODEV; | 865 | return -ENODEV; |
| 881 | } | 866 | } |
| 882 | 867 | ||
| 883 | pdata->hid_descriptor_address = value; | 868 | pdata->hid_descriptor_address = obj->integer.value; |
| 869 | ACPI_FREE(obj); | ||
| 884 | 870 | ||
| 885 | return 0; | 871 | return 0; |
| 886 | } | 872 | } |
diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index dbafcc8ef673..d2d1ceccad4b 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c | |||
| @@ -186,7 +186,6 @@ static const char device_label_dsm_uuid[] = { | |||
| 186 | }; | 186 | }; |
| 187 | 187 | ||
| 188 | enum acpi_attr_enum { | 188 | enum acpi_attr_enum { |
| 189 | ACPI_ATTR_NONE = 0, | ||
| 190 | ACPI_ATTR_LABEL_SHOW, | 189 | ACPI_ATTR_LABEL_SHOW, |
| 191 | ACPI_ATTR_INDEX_SHOW, | 190 | ACPI_ATTR_INDEX_SHOW, |
| 192 | }; | 191 | }; |
| @@ -194,84 +193,61 @@ enum acpi_attr_enum { | |||
| 194 | static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf) | 193 | static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf) |
| 195 | { | 194 | { |
| 196 | int len; | 195 | int len; |
| 197 | len = utf16s_to_utf8s((const wchar_t *)obj-> | 196 | len = utf16s_to_utf8s((const wchar_t *)obj->string.pointer, |
| 198 | package.elements[1].string.pointer, | 197 | obj->string.length, |
| 199 | obj->package.elements[1].string.length, | ||
| 200 | UTF16_LITTLE_ENDIAN, | 198 | UTF16_LITTLE_ENDIAN, |
| 201 | buf, PAGE_SIZE); | 199 | buf, PAGE_SIZE); |
| 202 | buf[len] = '\n'; | 200 | buf[len] = '\n'; |
| 203 | } | 201 | } |
| 204 | 202 | ||
| 205 | static int | 203 | static int |
| 206 | dsm_get_label(acpi_handle handle, int func, | 204 | dsm_get_label(struct device *dev, char *buf, enum acpi_attr_enum attr) |
| 207 | struct acpi_buffer *output, | ||
| 208 | char *buf, enum acpi_attr_enum attribute) | ||
| 209 | { | 205 | { |
| 210 | struct acpi_object_list input; | 206 | acpi_handle handle; |
| 211 | union acpi_object params[4]; | 207 | union acpi_object *obj, *tmp; |
| 212 | union acpi_object *obj; | 208 | int len = -1; |
| 213 | int len = 0; | 209 | |
| 214 | 210 | handle = ACPI_HANDLE(dev); | |
| 215 | int err; | 211 | if (!handle) |
| 216 | |||
| 217 | input.count = 4; | ||
| 218 | input.pointer = params; | ||
| 219 | params[0].type = ACPI_TYPE_BUFFER; | ||
| 220 | params[0].buffer.length = sizeof(device_label_dsm_uuid); | ||
| 221 | params[0].buffer.pointer = (char *)device_label_dsm_uuid; | ||
| 222 | params[1].type = ACPI_TYPE_INTEGER; | ||
| 223 | params[1].integer.value = 0x02; | ||
| 224 | params[2].type = ACPI_TYPE_INTEGER; | ||
| 225 | params[2].integer.value = func; | ||
| 226 | params[3].type = ACPI_TYPE_PACKAGE; | ||
| 227 | params[3].package.count = 0; | ||
| 228 | params[3].package.elements = NULL; | ||
| 229 | |||
| 230 | err = acpi_evaluate_object(handle, "_DSM", &input, output); | ||
| 231 | if (err) | ||
| 232 | return -1; | 212 | return -1; |
| 233 | 213 | ||
| 234 | obj = (union acpi_object *)output->pointer; | 214 | obj = acpi_evaluate_dsm(handle, device_label_dsm_uuid, 0x2, |
| 235 | 215 | DEVICE_LABEL_DSM, NULL); | |
| 236 | switch (obj->type) { | 216 | if (!obj) |
| 237 | case ACPI_TYPE_PACKAGE: | 217 | return -1; |
| 238 | if (obj->package.count != 2) | 218 | |
| 239 | break; | 219 | tmp = obj->package.elements; |
| 240 | len = obj->package.elements[0].integer.value; | 220 | if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 2 && |
| 241 | if (buf) { | 221 | tmp[0].type == ACPI_TYPE_INTEGER && |
| 242 | if (attribute == ACPI_ATTR_INDEX_SHOW) | 222 | tmp[1].type == ACPI_TYPE_STRING) { |
| 243 | scnprintf(buf, PAGE_SIZE, "%llu\n", | 223 | /* |
| 244 | obj->package.elements[0].integer.value); | 224 | * The second string element is optional even when |
| 245 | else if (attribute == ACPI_ATTR_LABEL_SHOW) | 225 | * this _DSM is implemented; when not implemented, |
| 246 | dsm_label_utf16s_to_utf8s(obj, buf); | 226 | * this entry must return a null string. |
| 247 | kfree(output->pointer); | 227 | */ |
| 248 | return strlen(buf); | 228 | if (attr == ACPI_ATTR_INDEX_SHOW) |
| 249 | } | 229 | scnprintf(buf, PAGE_SIZE, "%llu\n", tmp->integer.value); |
| 250 | kfree(output->pointer); | 230 | else if (attr == ACPI_ATTR_LABEL_SHOW) |
| 251 | return len; | 231 | dsm_label_utf16s_to_utf8s(tmp + 1, buf); |
| 252 | break; | 232 | len = strlen(buf) > 0 ? strlen(buf) : -1; |
| 253 | default: | ||
| 254 | kfree(output->pointer); | ||
| 255 | } | 233 | } |
| 256 | return -1; | 234 | |
| 235 | ACPI_FREE(obj); | ||
| 236 | |||
| 237 | return len; | ||
| 257 | } | 238 | } |
| 258 | 239 | ||
| 259 | static bool | 240 | static bool |
| 260 | device_has_dsm(struct device *dev) | 241 | device_has_dsm(struct device *dev) |
| 261 | { | 242 | { |
| 262 | acpi_handle handle; | 243 | acpi_handle handle; |
| 263 | struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
| 264 | 244 | ||
| 265 | handle = ACPI_HANDLE(dev); | 245 | handle = ACPI_HANDLE(dev); |
| 266 | |||
| 267 | if (!handle) | 246 | if (!handle) |
| 268 | return FALSE; | 247 | return false; |
| 269 | 248 | ||
| 270 | if (dsm_get_label(handle, DEVICE_LABEL_DSM, &output, NULL, | 249 | return !!acpi_check_dsm(handle, device_label_dsm_uuid, 0x2, |
| 271 | ACPI_ATTR_NONE) > 0) | 250 | 1 << DEVICE_LABEL_DSM); |
| 272 | return TRUE; | ||
| 273 | |||
| 274 | return FALSE; | ||
| 275 | } | 251 | } |
| 276 | 252 | ||
| 277 | static umode_t | 253 | static umode_t |
| @@ -290,44 +266,13 @@ acpi_index_string_exist(struct kobject *kobj, struct attribute *attr, int n) | |||
| 290 | static ssize_t | 266 | static ssize_t |
| 291 | acpilabel_show(struct device *dev, struct device_attribute *attr, char *buf) | 267 | acpilabel_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 292 | { | 268 | { |
| 293 | struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; | 269 | return dsm_get_label(dev, buf, ACPI_ATTR_LABEL_SHOW); |
| 294 | acpi_handle handle; | ||
| 295 | int length; | ||
| 296 | |||
| 297 | handle = ACPI_HANDLE(dev); | ||
| 298 | |||
| 299 | if (!handle) | ||
| 300 | return -1; | ||
| 301 | |||
| 302 | length = dsm_get_label(handle, DEVICE_LABEL_DSM, | ||
| 303 | &output, buf, ACPI_ATTR_LABEL_SHOW); | ||
| 304 | |||
| 305 | if (length < 1) | ||
| 306 | return -1; | ||
| 307 | |||
| 308 | return length; | ||
| 309 | } | 270 | } |
| 310 | 271 | ||
| 311 | static ssize_t | 272 | static ssize_t |
| 312 | acpiindex_show(struct device *dev, struct device_attribute *attr, char *buf) | 273 | acpiindex_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 313 | { | 274 | { |
| 314 | struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; | 275 | return dsm_get_label(dev, buf, ACPI_ATTR_INDEX_SHOW); |
| 315 | acpi_handle handle; | ||
| 316 | int length; | ||
| 317 | |||
| 318 | handle = ACPI_HANDLE(dev); | ||
| 319 | |||
| 320 | if (!handle) | ||
| 321 | return -1; | ||
| 322 | |||
| 323 | length = dsm_get_label(handle, DEVICE_LABEL_DSM, | ||
| 324 | &output, buf, ACPI_ATTR_INDEX_SHOW); | ||
| 325 | |||
| 326 | if (length < 0) | ||
| 327 | return -1; | ||
| 328 | |||
| 329 | return length; | ||
| 330 | |||
| 331 | } | 276 | } |
| 332 | 277 | ||
| 333 | static struct device_attribute acpi_attr_label = { | 278 | static struct device_attribute acpi_attr_label = { |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index e4ab7be65637..8256eb4ad057 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
| @@ -64,6 +64,32 @@ bool acpi_ata_match(acpi_handle handle); | |||
| 64 | bool acpi_bay_match(acpi_handle handle); | 64 | bool acpi_bay_match(acpi_handle handle); |
| 65 | bool acpi_dock_match(acpi_handle handle); | 65 | bool acpi_dock_match(acpi_handle handle); |
| 66 | 66 | ||
| 67 | bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs); | ||
| 68 | union acpi_object *acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, | ||
| 69 | int rev, int func, union acpi_object *argv4); | ||
| 70 | |||
| 71 | static inline union acpi_object * | ||
| 72 | acpi_evaluate_dsm_typed(acpi_handle handle, const u8 *uuid, int rev, int func, | ||
| 73 | union acpi_object *argv4, acpi_object_type type) | ||
| 74 | { | ||
| 75 | union acpi_object *obj; | ||
| 76 | |||
| 77 | obj = acpi_evaluate_dsm(handle, uuid, rev, func, argv4); | ||
| 78 | if (obj && obj->type != type) { | ||
| 79 | ACPI_FREE(obj); | ||
| 80 | obj = NULL; | ||
| 81 | } | ||
| 82 | |||
| 83 | return obj; | ||
| 84 | } | ||
| 85 | |||
| 86 | #define ACPI_INIT_DSM_ARGV4(cnt, eles) \ | ||
| 87 | { \ | ||
| 88 | .package.type = ACPI_TYPE_PACKAGE, \ | ||
| 89 | .package.count = (cnt), \ | ||
| 90 | .package.elements = (eles) \ | ||
| 91 | } | ||
| 92 | |||
| 67 | #ifdef CONFIG_ACPI | 93 | #ifdef CONFIG_ACPI |
| 68 | 94 | ||
| 69 | #include <linux/proc_fs.h> | 95 | #include <linux/proc_fs.h> |
