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
This commit is contained in:
Rafael J. Wysocki
2014-01-12 23:45:52 +01:00
9 changed files with 397 additions and 658 deletions

View File

@@ -19,11 +19,9 @@
#define EXT_ELOG_ENTRY_MASK GENMASK_ULL(51, 0) /* elog entry address mask */ #define EXT_ELOG_ENTRY_MASK GENMASK_ULL(51, 0) /* elog entry address mask */
#define EXTLOG_DSM_REV 0x0 #define EXTLOG_DSM_REV 0x0
#define EXTLOG_FN_QUERY 0x0
#define EXTLOG_FN_ADDR 0x1 #define EXTLOG_FN_ADDR 0x1
#define FLAG_OS_OPTIN BIT(0) #define FLAG_OS_OPTIN BIT(0)
#define EXTLOG_QUERY_L1_EXIST BIT(1)
#define ELOG_ENTRY_VALID (1ULL<<63) #define ELOG_ENTRY_VALID (1ULL<<63)
#define ELOG_ENTRY_LEN 0x1000 #define ELOG_ENTRY_LEN 0x1000
@@ -42,7 +40,7 @@ struct extlog_l1_head {
u8 rev1[12]; 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 */ /* L1 table related physical address */
static u64 elog_base; static u64 elog_base;
@@ -152,62 +150,27 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
return NOTIFY_DONE; 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]; u8 uuid[16];
int i; acpi_handle handle;
union acpi_object *obj;
acpi_str_to_uuid(extlog_dsm_uuid, uuid); 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))) if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)))
return false; return false;
if (!acpi_check_dsm(handle, uuid, EXTLOG_DSM_REV, 1 << EXTLOG_FN_ADDR))
if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_QUERY, &ret) ||
!(ret & EXTLOG_QUERY_L1_EXIST))
return false; return false;
obj = acpi_evaluate_dsm_typed(handle, uuid, EXTLOG_DSM_REV,
if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_ADDR, &ret)) EXTLOG_FN_ADDR, NULL, ACPI_TYPE_INTEGER);
if (!obj) {
return false; 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 */ /* Spec says L1 directory must be 4K aligned, bail out if it isn't */
if (l1_dirbase & ((1 << 12) - 1)) { if (l1_dirbase & ((1 << 12) - 1)) {
pr_warn(FW_BUG "L1 Directory is invalid at physical %llx\n", pr_warn(FW_BUG "L1 Directory is invalid at physical %llx\n",

View File

@@ -572,3 +572,100 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock)
return status; 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);

View File

@@ -1,15 +1,6 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include "tpm.h" #include "tpm.h"
static const u8 tpm_ppi_uuid[] = {
0xA6, 0xFA, 0xDD, 0x3D,
0x1B, 0x36,
0xB4, 0x4E,
0xA4, 0x24,
0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
};
static char *tpm_device_name = "TPM";
#define TPM_PPI_REVISION_ID 1 #define TPM_PPI_REVISION_ID 1
#define TPM_PPI_FN_VERSION 1 #define TPM_PPI_FN_VERSION 1
#define TPM_PPI_FN_SUBREQ 2 #define TPM_PPI_FN_SUBREQ 2
@@ -23,250 +14,178 @@ static char *tpm_device_name = "TPM";
#define PPI_VS_REQ_END 255 #define PPI_VS_REQ_END 255
#define PPI_VERSION_LEN 3 #define PPI_VERSION_LEN 3
static const u8 tpm_ppi_uuid[] = {
0xA6, 0xFA, 0xDD, 0x3D,
0x1B, 0x36,
0xB4, 0x4E,
0xA4, 0x24,
0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
};
static char tpm_ppi_version[PPI_VERSION_LEN + 1];
static acpi_handle tpm_ppi_handle;
static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context,
void **return_value) void **return_value)
{ {
acpi_status status = AE_OK; union acpi_object *obj;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) { if (!acpi_check_dsm(handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
if (strstr(buffer.pointer, context) != NULL) { 1 << TPM_PPI_FN_VERSION))
*return_value = handle; return AE_OK;
status = AE_CTRL_TERMINATE;
} /* Cache version string */
kfree(buffer.pointer); obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid,
TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
NULL, ACPI_TYPE_STRING);
if (obj) {
strlcpy(tpm_ppi_version, obj->string.pointer,
PPI_VERSION_LEN + 1);
ACPI_FREE(obj);
} }
return status; *return_value = handle;
return AE_CTRL_TERMINATE;
} }
static inline void ppi_assign_params(union acpi_object params[4], static inline union acpi_object *
u64 function_num) tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4)
{ {
params[0].type = ACPI_TYPE_BUFFER; BUG_ON(!tpm_ppi_handle);
params[0].buffer.length = sizeof(tpm_ppi_uuid); return acpi_evaluate_dsm_typed(tpm_ppi_handle, tpm_ppi_uuid,
params[0].buffer.pointer = (char *)tpm_ppi_uuid; TPM_PPI_REVISION_ID, func, argv4, type);
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = TPM_PPI_REVISION_ID;
params[2].type = ACPI_TYPE_INTEGER;
params[2].integer.value = function_num;
params[3].type = ACPI_TYPE_PACKAGE;
params[3].package.count = 0;
params[3].package.elements = NULL;
} }
static ssize_t tpm_show_ppi_version(struct device *dev, static ssize_t tpm_show_ppi_version(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
acpi_handle handle; return scnprintf(buf, PAGE_SIZE, "%s\n", tpm_ppi_version);
acpi_status status;
struct acpi_object_list input;
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object params[4];
union acpi_object *obj;
input.count = 4;
ppi_assign_params(params, TPM_PPI_FN_VERSION);
input.pointer = params;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, ppi_callback, NULL,
tpm_device_name, &handle);
if (ACPI_FAILURE(status))
return -ENXIO;
status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
ACPI_TYPE_STRING);
if (ACPI_FAILURE(status))
return -ENOMEM;
obj = (union acpi_object *)output.pointer;
status = scnprintf(buf, PAGE_SIZE, "%s\n", obj->string.pointer);
kfree(output.pointer);
return status;
} }
static ssize_t tpm_show_ppi_request(struct device *dev, static ssize_t tpm_show_ppi_request(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
acpi_handle handle; ssize_t size = -EINVAL;
acpi_status status; union acpi_object *obj;
struct acpi_object_list input;
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object params[4];
union acpi_object *ret_obj;
input.count = 4; obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL);
ppi_assign_params(params, TPM_PPI_FN_GETREQ); if (!obj)
input.pointer = params;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, ppi_callback, NULL,
tpm_device_name, &handle);
if (ACPI_FAILURE(status))
return -ENXIO; return -ENXIO;
status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
ACPI_TYPE_PACKAGE);
if (ACPI_FAILURE(status))
return -ENOMEM;
/* /*
* output.pointer should be of package type, including two integers. * output.pointer should be of package type, including two integers.
* The first is function return code, 0 means success and 1 means * The first is function return code, 0 means success and 1 means
* error. The second is pending TPM operation requested by the OS, 0 * error. The second is pending TPM operation requested by the OS, 0
* means none and >0 means operation value. * means none and >0 means operation value.
*/ */
ret_obj = ((union acpi_object *)output.pointer)->package.elements; if (obj->package.count == 2 &&
if (ret_obj->type == ACPI_TYPE_INTEGER) { obj->package.elements[0].type == ACPI_TYPE_INTEGER &&
if (ret_obj->integer.value) { obj->package.elements[1].type == ACPI_TYPE_INTEGER) {
status = -EFAULT; if (obj->package.elements[0].integer.value)
goto cleanup; size = -EFAULT;
}
ret_obj++;
if (ret_obj->type == ACPI_TYPE_INTEGER)
status = scnprintf(buf, PAGE_SIZE, "%llu\n",
ret_obj->integer.value);
else else
status = -EINVAL; size = scnprintf(buf, PAGE_SIZE, "%llu\n",
} else { obj->package.elements[1].integer.value);
status = -EINVAL;
} }
cleanup:
kfree(output.pointer); ACPI_FREE(obj);
return status;
return size;
} }
static ssize_t tpm_store_ppi_request(struct device *dev, static ssize_t tpm_store_ppi_request(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
char version[PPI_VERSION_LEN + 1];
acpi_handle handle;
acpi_status status;
struct acpi_object_list input;
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object params[4];
union acpi_object obj;
u32 req; u32 req;
u64 ret; u64 ret;
int func = TPM_PPI_FN_SUBREQ;
union acpi_object *obj, tmp;
union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
input.count = 4;
ppi_assign_params(params, TPM_PPI_FN_VERSION);
input.pointer = params;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, ppi_callback, NULL,
tpm_device_name, &handle);
if (ACPI_FAILURE(status))
return -ENXIO;
status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
ACPI_TYPE_STRING);
if (ACPI_FAILURE(status))
return -ENOMEM;
strlcpy(version,
((union acpi_object *)output.pointer)->string.pointer,
PPI_VERSION_LEN + 1);
kfree(output.pointer);
output.length = ACPI_ALLOCATE_BUFFER;
output.pointer = NULL;
/* /*
* the function to submit TPM operation request to pre-os environment * the function to submit TPM operation request to pre-os environment
* is updated with function index from SUBREQ to SUBREQ2 since PPI * is updated with function index from SUBREQ to SUBREQ2 since PPI
* version 1.1 * version 1.1
*/ */
if (strcmp(version, "1.1") == -1) if (acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
params[2].integer.value = TPM_PPI_FN_SUBREQ; 1 << TPM_PPI_FN_SUBREQ2))
else func = TPM_PPI_FN_SUBREQ2;
params[2].integer.value = TPM_PPI_FN_SUBREQ2;
/* /*
* PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS
* accept buffer/string/integer type, but some BIOS accept buffer/ * accept buffer/string/integer type, but some BIOS accept buffer/
* string/package type. For PPI version 1.0 and 1.1, use buffer type * string/package type. For PPI version 1.0 and 1.1, use buffer type
* for compatibility, and use package type since 1.2 according to spec. * for compatibility, and use package type since 1.2 according to spec.
*/ */
if (strcmp(version, "1.2") == -1) { if (strcmp(tpm_ppi_version, "1.2") < 0) {
params[3].type = ACPI_TYPE_BUFFER; if (sscanf(buf, "%d", &req) != 1)
params[3].buffer.length = sizeof(req); return -EINVAL;
sscanf(buf, "%d", &req); argv4.type = ACPI_TYPE_BUFFER;
params[3].buffer.pointer = (char *)&req; argv4.buffer.length = sizeof(req);
argv4.buffer.pointer = (u8 *)&req;
} else { } else {
params[3].package.count = 1; tmp.type = ACPI_TYPE_INTEGER;
obj.type = ACPI_TYPE_INTEGER; if (sscanf(buf, "%llu", &tmp.integer.value) != 1)
sscanf(buf, "%llu", &obj.integer.value); return -EINVAL;
params[3].package.elements = &obj; }
obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4);
if (!obj) {
return -ENXIO;
} else {
ret = obj->integer.value;
ACPI_FREE(obj);
} }
status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
ACPI_TYPE_INTEGER);
if (ACPI_FAILURE(status))
return -ENOMEM;
ret = ((union acpi_object *)output.pointer)->integer.value;
if (ret == 0) if (ret == 0)
status = (acpi_status)count; return (acpi_status)count;
else if (ret == 1)
status = -EPERM; return (ret == 1) ? -EPERM : -EFAULT;
else
status = -EFAULT;
kfree(output.pointer);
return status;
} }
static ssize_t tpm_show_ppi_transition_action(struct device *dev, static ssize_t tpm_show_ppi_transition_action(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
char version[PPI_VERSION_LEN + 1];
acpi_handle handle;
acpi_status status;
struct acpi_object_list input;
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object params[4];
u32 ret; u32 ret;
char *info[] = { acpi_status status;
union acpi_object *obj = NULL;
union acpi_object tmp = {
.buffer.type = ACPI_TYPE_BUFFER,
.buffer.length = 0,
.buffer.pointer = NULL
};
static char *info[] = {
"None", "None",
"Shutdown", "Shutdown",
"Reboot", "Reboot",
"OS Vendor-specific", "OS Vendor-specific",
"Error", "Error",
}; };
input.count = 4;
ppi_assign_params(params, TPM_PPI_FN_VERSION);
input.pointer = params;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, ppi_callback, NULL,
tpm_device_name, &handle);
if (ACPI_FAILURE(status))
return -ENXIO;
status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
ACPI_TYPE_STRING);
if (ACPI_FAILURE(status))
return -ENOMEM;
strlcpy(version,
((union acpi_object *)output.pointer)->string.pointer,
PPI_VERSION_LEN + 1);
/* /*
* PPI spec defines params[3].type as empty package, but some platforms * PPI spec defines params[3].type as empty package, but some platforms
* (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
* compatibility, define params[3].type as buffer, if PPI version < 1.2 * compatibility, define params[3].type as buffer, if PPI version < 1.2
*/ */
if (strcmp(version, "1.2") == -1) { if (strcmp(tpm_ppi_version, "1.2") < 0)
params[3].type = ACPI_TYPE_BUFFER; obj = &tmp;
params[3].buffer.length = 0; obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj);
params[3].buffer.pointer = NULL; if (!obj) {
return -ENXIO;
} else {
ret = obj->integer.value;
ACPI_FREE(obj);
} }
params[2].integer.value = TPM_PPI_FN_GETACT;
kfree(output.pointer);
output.length = ACPI_ALLOCATE_BUFFER;
output.pointer = NULL;
status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
ACPI_TYPE_INTEGER);
if (ACPI_FAILURE(status))
return -ENOMEM;
ret = ((union acpi_object *)output.pointer)->integer.value;
if (ret < ARRAY_SIZE(info) - 1) if (ret < ARRAY_SIZE(info) - 1)
status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]);
else else
status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret,
info[ARRAY_SIZE(info)-1]); info[ARRAY_SIZE(info)-1]);
kfree(output.pointer);
return status; return status;
} }
@@ -274,27 +193,14 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
acpi_handle handle; acpi_status status = -EINVAL;
acpi_status status; union acpi_object *obj, *ret_obj;
struct acpi_object_list input; u64 req, res;
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object params[4];
union acpi_object *ret_obj;
u64 req;
input.count = 4; obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL);
ppi_assign_params(params, TPM_PPI_FN_GETRSP); if (!obj)
input.pointer = params;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, ppi_callback, NULL,
tpm_device_name, &handle);
if (ACPI_FAILURE(status))
return -ENXIO; return -ENXIO;
status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
ACPI_TYPE_PACKAGE);
if (ACPI_FAILURE(status))
return -ENOMEM;
/* /*
* parameter output.pointer should be of package type, including * parameter output.pointer should be of package type, including
* 3 integers. The first means function return code, the second means * 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,
* the most recent TPM operation request. Only if the first is 0, and * the most recent TPM operation request. Only if the first is 0, and
* the second integer is not 0, the response makes sense. * the second integer is not 0, the response makes sense.
*/ */
ret_obj = ((union acpi_object *)output.pointer)->package.elements; ret_obj = obj->package.elements;
if (ret_obj->type != ACPI_TYPE_INTEGER) { if (obj->package.count < 3 ||
status = -EINVAL; ret_obj[0].type != ACPI_TYPE_INTEGER ||
ret_obj[1].type != ACPI_TYPE_INTEGER ||
ret_obj[2].type != ACPI_TYPE_INTEGER)
goto cleanup; goto cleanup;
}
if (ret_obj->integer.value) { if (ret_obj[0].integer.value) {
status = -EFAULT; status = -EFAULT;
goto cleanup; goto cleanup;
} }
ret_obj++;
if (ret_obj->type != ACPI_TYPE_INTEGER) { req = ret_obj[1].integer.value;
status = -EINVAL; res = ret_obj[2].integer.value;
goto cleanup; if (req) {
} if (res == 0)
if (ret_obj->integer.value) {
req = ret_obj->integer.value;
ret_obj++;
if (ret_obj->type != ACPI_TYPE_INTEGER) {
status = -EINVAL;
goto cleanup;
}
if (ret_obj->integer.value == 0)
status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,
"0: Success"); "0: Success");
else if (ret_obj->integer.value == 0xFFFFFFF0) else if (res == 0xFFFFFFF0)
status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,
"0xFFFFFFF0: User Abort"); "0xFFFFFFF0: User Abort");
else if (ret_obj->integer.value == 0xFFFFFFF1) else if (res == 0xFFFFFFF1)
status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,
"0xFFFFFFF1: BIOS Failure"); "0xFFFFFFF1: BIOS Failure");
else if (ret_obj->integer.value >= 1 && else if (res >= 1 && res <= 0x00000FFF)
ret_obj->integer.value <= 0x00000FFF)
status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n",
req, ret_obj->integer.value, req, res, "Corresponding TPM error");
"Corresponding TPM error");
else else
status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n",
req, ret_obj->integer.value, req, res, "Error");
"Error");
} else { } else {
status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n",
ret_obj->integer.value, "No Recent Request"); req, "No Recent Request");
} }
cleanup: cleanup:
kfree(output.pointer); ACPI_FREE(obj);
return status; return status;
} }
static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
{ {
char *str = buf;
char version[PPI_VERSION_LEN + 1];
acpi_handle handle;
acpi_status status;
struct acpi_object_list input;
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object params[4];
union acpi_object obj;
int i; int i;
u32 ret; u32 ret;
char *info[] = { char *str = buf;
union acpi_object *obj, tmp;
union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp);
static char *info[] = {
"Not implemented", "Not implemented",
"BIOS only", "BIOS only",
"Blocked for OS by BIOS", "Blocked for OS by BIOS",
"User required", "User required",
"User not required", "User not required",
}; };
input.count = 4;
ppi_assign_params(params, TPM_PPI_FN_VERSION);
input.pointer = params;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, ppi_callback, NULL,
tpm_device_name, &handle);
if (ACPI_FAILURE(status))
return -ENXIO;
status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, if (!acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
ACPI_TYPE_STRING); 1 << TPM_PPI_FN_GETOPR))
if (ACPI_FAILURE(status))
return -ENOMEM;
strlcpy(version,
((union acpi_object *)output.pointer)->string.pointer,
PPI_VERSION_LEN + 1);
kfree(output.pointer);
output.length = ACPI_ALLOCATE_BUFFER;
output.pointer = NULL;
if (strcmp(version, "1.2") == -1)
return -EPERM; return -EPERM;
params[2].integer.value = TPM_PPI_FN_GETOPR; tmp.integer.type = ACPI_TYPE_INTEGER;
params[3].package.count = 1;
obj.type = ACPI_TYPE_INTEGER;
params[3].package.elements = &obj;
for (i = start; i <= end; i++) { for (i = start; i <= end; i++) {
obj.integer.value = i; tmp.integer.value = i;
status = acpi_evaluate_object_typed(handle, "_DSM", obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv);
&input, &output, ACPI_TYPE_INTEGER); if (!obj) {
if (ACPI_FAILURE(status))
return -ENOMEM; return -ENOMEM;
} else {
ret = obj->integer.value;
ACPI_FREE(obj);
}
ret = ((union acpi_object *)output.pointer)->integer.value;
if (ret > 0 && ret < ARRAY_SIZE(info)) if (ret > 0 && ret < ARRAY_SIZE(info))
str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n",
i, ret, info[ret]); i, ret, info[ret]);
kfree(output.pointer);
output.length = ACPI_ALLOCATE_BUFFER;
output.pointer = NULL;
} }
return str - buf; return str - buf;
} }
@@ -452,6 +325,12 @@ static struct attribute_group ppi_attr_grp = {
int tpm_add_ppi(struct kobject *parent) int tpm_add_ppi(struct kobject *parent)
{ {
/* Cache TPM ACPI handle and version string */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
ppi_callback, NULL, NULL, &tpm_ppi_handle);
if (tpm_ppi_handle == NULL)
return -ENODEV;
return sysfs_create_group(parent, &ppi_attr_grp); return sysfs_create_group(parent, &ppi_attr_grp);
} }

View File

@@ -10,8 +10,6 @@
#include "i915_drv.h" #include "i915_drv.h"
#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
#define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */
#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */ #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
static struct intel_dsm_priv { static struct intel_dsm_priv {
@@ -26,61 +24,6 @@ static const u8 intel_dsm_guid[] = {
0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c
}; };
static int intel_dsm(acpi_handle handle, int func)
{
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_object_list input;
union acpi_object params[4];
union acpi_object *obj;
u32 result;
int ret = 0;
input.count = 4;
input.pointer = params;
params[0].type = ACPI_TYPE_BUFFER;
params[0].buffer.length = sizeof(intel_dsm_guid);
params[0].buffer.pointer = (char *)intel_dsm_guid;
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = INTEL_DSM_REVISION_ID;
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;
ret = acpi_evaluate_object(handle, "_DSM", &input, &output);
if (ret) {
DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
return ret;
}
obj = (union acpi_object *)output.pointer;
result = 0;
switch (obj->type) {
case ACPI_TYPE_INTEGER:
result = obj->integer.value;
break;
case ACPI_TYPE_BUFFER:
if (obj->buffer.length == 4) {
result = (obj->buffer.pointer[0] |
(obj->buffer.pointer[1] << 8) |
(obj->buffer.pointer[2] << 16) |
(obj->buffer.pointer[3] << 24));
break;
}
default:
ret = -EINVAL;
break;
}
if (result == 0x80000002)
ret = -ENODEV;
kfree(output.pointer);
return ret;
}
static char *intel_dsm_port_name(u8 id) static char *intel_dsm_port_name(u8 id)
{ {
switch (id) { switch (id) {
@@ -135,83 +78,56 @@ static char *intel_dsm_mux_type(u8 type)
static void intel_dsm_platform_mux_info(void) static void intel_dsm_platform_mux_info(void)
{ {
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; int i;
struct acpi_object_list input; union acpi_object *pkg, *connector_count;
union acpi_object params[4];
union acpi_object *pkg;
int i, ret;
input.count = 4; pkg = acpi_evaluate_dsm_typed(intel_dsm_priv.dhandle, intel_dsm_guid,
input.pointer = params; INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO,
params[0].type = ACPI_TYPE_BUFFER; NULL, ACPI_TYPE_PACKAGE);
params[0].buffer.length = sizeof(intel_dsm_guid); if (!pkg) {
params[0].buffer.pointer = (char *)intel_dsm_guid; DRM_DEBUG_DRIVER("failed to evaluate _DSM\n");
params[1].type = ACPI_TYPE_INTEGER; return;
params[1].integer.value = INTEL_DSM_REVISION_ID;
params[2].type = ACPI_TYPE_INTEGER;
params[2].integer.value = INTEL_DSM_FN_PLATFORM_MUX_INFO;
params[3].type = ACPI_TYPE_PACKAGE;
params[3].package.count = 0;
params[3].package.elements = NULL;
ret = acpi_evaluate_object(intel_dsm_priv.dhandle, "_DSM", &input,
&output);
if (ret) {
DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
goto out;
} }
pkg = (union acpi_object *)output.pointer; connector_count = &pkg->package.elements[0];
DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
if (pkg->type == ACPI_TYPE_PACKAGE) { (unsigned long long)connector_count->integer.value);
union acpi_object *connector_count = &pkg->package.elements[0]; for (i = 1; i < pkg->package.count; i++) {
DRM_DEBUG_DRIVER("MUX info connectors: %lld\n", union acpi_object *obj = &pkg->package.elements[i];
(unsigned long long)connector_count->integer.value); union acpi_object *connector_id = &obj->package.elements[0];
for (i = 1; i < pkg->package.count; i++) { union acpi_object *info = &obj->package.elements[1];
union acpi_object *obj = &pkg->package.elements[i]; DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
union acpi_object *connector_id = (unsigned long long)connector_id->integer.value);
&obj->package.elements[0]; DRM_DEBUG_DRIVER(" port id: %s\n",
union acpi_object *info = &obj->package.elements[1]; intel_dsm_port_name(info->buffer.pointer[0]));
DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n", DRM_DEBUG_DRIVER(" display mux info: %s\n",
(unsigned long long)connector_id->integer.value); intel_dsm_mux_type(info->buffer.pointer[1]));
DRM_DEBUG_DRIVER(" port id: %s\n", DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n",
intel_dsm_port_name(info->buffer.pointer[0])); intel_dsm_mux_type(info->buffer.pointer[2]));
DRM_DEBUG_DRIVER(" display mux info: %s\n", DRM_DEBUG_DRIVER(" hpd mux info: %s\n",
intel_dsm_mux_type(info->buffer.pointer[1])); intel_dsm_mux_type(info->buffer.pointer[3]));
DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n",
intel_dsm_mux_type(info->buffer.pointer[2]));
DRM_DEBUG_DRIVER(" hpd mux info: %s\n",
intel_dsm_mux_type(info->buffer.pointer[3]));
}
} }
out: ACPI_FREE(pkg);
kfree(output.pointer);
} }
static bool intel_dsm_pci_probe(struct pci_dev *pdev) static bool intel_dsm_pci_probe(struct pci_dev *pdev)
{ {
acpi_handle dhandle; acpi_handle dhandle;
int ret;
dhandle = ACPI_HANDLE(&pdev->dev); dhandle = ACPI_HANDLE(&pdev->dev);
if (!dhandle) if (!dhandle)
return false; return false;
if (!acpi_has_method(dhandle, "_DSM")) { if (!acpi_check_dsm(dhandle, intel_dsm_guid, INTEL_DSM_REVISION_ID,
1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) {
DRM_DEBUG_KMS("no _DSM method for intel device\n"); DRM_DEBUG_KMS("no _DSM method for intel device\n");
return false; return false;
} }
ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS);
if (ret < 0) {
DRM_DEBUG_KMS("failed to get supported _DSM functions\n");
return false;
}
intel_dsm_priv.dhandle = dhandle; intel_dsm_priv.dhandle = dhandle;
intel_dsm_platform_mux_info(); intel_dsm_platform_mux_info();
return true; return true;
} }

View File

@@ -87,55 +87,39 @@ mxm_shadow_dsm(struct nouveau_mxm *mxm, u8 version)
0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65
}; };
u32 mxms_args[] = { 0x00000000 }; u32 mxms_args[] = { 0x00000000 };
union acpi_object args[4] = { union acpi_object argv4 = {
/* _DSM MUID */ .buffer.type = ACPI_TYPE_BUFFER,
{ .buffer.type = 3, .buffer.length = sizeof(mxms_args),
.buffer.length = sizeof(muid), .buffer.pointer = (char *)mxms_args,
.buffer.pointer = muid,
},
/* spec says this can be zero to mean "highest revision", but
* of course there's at least one bios out there which fails
* unless you pass in exactly the version it supports..
*/
{ .integer.type = ACPI_TYPE_INTEGER,
.integer.value = (version & 0xf0) << 4 | (version & 0x0f),
},
/* MXMS function */
{ .integer.type = ACPI_TYPE_INTEGER,
.integer.value = 0x00000010,
},
/* Pointer to MXMS arguments */
{ .buffer.type = ACPI_TYPE_BUFFER,
.buffer.length = sizeof(mxms_args),
.buffer.pointer = (char *)mxms_args,
},
}; };
struct acpi_object_list list = { ARRAY_SIZE(args), args };
struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj; union acpi_object *obj;
acpi_handle handle; acpi_handle handle;
int ret; int rev;
handle = ACPI_HANDLE(&device->pdev->dev); handle = ACPI_HANDLE(&device->pdev->dev);
if (!handle) if (!handle)
return false; return false;
ret = acpi_evaluate_object(handle, "_DSM", &list, &retn); /*
if (ret) { * spec says this can be zero to mean "highest revision", but
nv_debug(mxm, "DSM MXMS failed: %d\n", ret); * of course there's at least one bios out there which fails
* unless you pass in exactly the version it supports..
*/
rev = (version & 0xf0) << 4 | (version & 0x0f);
obj = acpi_evaluate_dsm(handle, muid, rev, 0x00000010, &argv4);
if (!obj) {
nv_debug(mxm, "DSM MXMS failed\n");
return false; return false;
} }
obj = retn.pointer;
if (obj->type == ACPI_TYPE_BUFFER) { if (obj->type == ACPI_TYPE_BUFFER) {
mxm->mxms = kmemdup(obj->buffer.pointer, mxm->mxms = kmemdup(obj->buffer.pointer,
obj->buffer.length, GFP_KERNEL); obj->buffer.length, GFP_KERNEL);
} else } else if (obj->type == ACPI_TYPE_INTEGER) {
if (obj->type == ACPI_TYPE_INTEGER) {
nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value); nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value);
} }
kfree(obj); ACPI_FREE(obj);
return mxm->mxms != NULL; return mxm->mxms != NULL;
} }
#endif #endif

View File

@@ -73,124 +73,66 @@ static const char nouveau_op_dsm_muid[] = {
static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result) static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
{ {
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; int i;
struct acpi_object_list input;
union acpi_object params[4];
union acpi_object *obj; union acpi_object *obj;
int i, err;
char args_buff[4]; char args_buff[4];
union acpi_object argv4 = {
.buffer.type = ACPI_TYPE_BUFFER,
.buffer.length = 4,
.buffer.pointer = args_buff
};
input.count = 4;
input.pointer = params;
params[0].type = ACPI_TYPE_BUFFER;
params[0].buffer.length = sizeof(nouveau_op_dsm_muid);
params[0].buffer.pointer = (char *)nouveau_op_dsm_muid;
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = 0x00000100;
params[2].type = ACPI_TYPE_INTEGER;
params[2].integer.value = func;
params[3].type = ACPI_TYPE_BUFFER;
params[3].buffer.length = 4;
/* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */ /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
args_buff[i] = (arg >> i * 8) & 0xFF; args_buff[i] = (arg >> i * 8) & 0xFF;
params[3].buffer.pointer = args_buff;
err = acpi_evaluate_object(handle, "_DSM", &input, &output); *result = 0;
if (err) { obj = acpi_evaluate_dsm_typed(handle, nouveau_op_dsm_muid, 0x00000100,
printk(KERN_INFO "failed to evaluate _DSM: %d\n", err); func, &argv4, ACPI_TYPE_BUFFER);
return err; if (!obj) {
} acpi_handle_info(handle, "failed to evaluate _DSM\n");
return AE_ERROR;
obj = (union acpi_object *)output.pointer; } else {
if (obj->buffer.length == 4) {
if (obj->type == ACPI_TYPE_INTEGER)
if (obj->integer.value == 0x80000002) {
return -ENODEV;
}
if (obj->type == ACPI_TYPE_BUFFER) {
if (obj->buffer.length == 4 && result) {
*result = 0;
*result |= obj->buffer.pointer[0]; *result |= obj->buffer.pointer[0];
*result |= (obj->buffer.pointer[1] << 8); *result |= (obj->buffer.pointer[1] << 8);
*result |= (obj->buffer.pointer[2] << 16); *result |= (obj->buffer.pointer[2] << 16);
*result |= (obj->buffer.pointer[3] << 24); *result |= (obj->buffer.pointer[3] << 24);
} }
ACPI_FREE(obj);
} }
kfree(output.pointer);
return 0; return 0;
} }
static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) static int nouveau_dsm(acpi_handle handle, int func, int arg)
{ {
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; int ret = 0;
struct acpi_object_list input;
union acpi_object params[4];
union acpi_object *obj; union acpi_object *obj;
int err; union acpi_object argv4 = {
.integer.type = ACPI_TYPE_INTEGER,
.integer.value = arg,
};
input.count = 4; obj = acpi_evaluate_dsm_typed(handle, nouveau_dsm_muid, 0x00000102,
input.pointer = params; func, &argv4, ACPI_TYPE_INTEGER);
params[0].type = ACPI_TYPE_BUFFER; if (!obj) {
params[0].buffer.length = sizeof(nouveau_dsm_muid); acpi_handle_info(handle, "failed to evaluate _DSM\n");
params[0].buffer.pointer = (char *)nouveau_dsm_muid; return AE_ERROR;
params[1].type = ACPI_TYPE_INTEGER; } else {
params[1].integer.value = 0x00000102;
params[2].type = ACPI_TYPE_INTEGER;
params[2].integer.value = func;
params[3].type = ACPI_TYPE_INTEGER;
params[3].integer.value = arg;
err = acpi_evaluate_object(handle, "_DSM", &input, &output);
if (err) {
printk(KERN_INFO "failed to evaluate _DSM: %d\n", err);
return err;
}
obj = (union acpi_object *)output.pointer;
if (obj->type == ACPI_TYPE_INTEGER)
if (obj->integer.value == 0x80000002) if (obj->integer.value == 0x80000002)
return -ENODEV; ret = -ENODEV;
ACPI_FREE(obj);
if (obj->type == ACPI_TYPE_BUFFER) {
if (obj->buffer.length == 4 && result) {
*result = 0;
*result |= obj->buffer.pointer[0];
*result |= (obj->buffer.pointer[1] << 8);
*result |= (obj->buffer.pointer[2] << 16);
*result |= (obj->buffer.pointer[3] << 24);
}
} }
kfree(output.pointer); return ret;
return 0;
}
/* Returns 1 if a DSM function is usable and 0 otherwise */
static int nouveau_test_dsm(acpi_handle test_handle,
int (*dsm_func)(acpi_handle, int, int, uint32_t *),
int sfnc)
{
u32 result = 0;
/* Function 0 returns a Buffer containing available functions. The args
* parameter is ignored for function 0, so just put 0 in it */
if (dsm_func(test_handle, 0, 0, &result))
return 0;
/* ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. If
* the n-th bit is enabled, function n is supported */
return result & 1 && result & (1 << sfnc);
} }
static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id) static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
{ {
mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL); return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id);
} }
static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state) 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
arg = NOUVEAU_DSM_POWER_SPEED; arg = NOUVEAU_DSM_POWER_SPEED;
else else
arg = NOUVEAU_DSM_POWER_STAMINA; arg = NOUVEAU_DSM_POWER_STAMINA;
nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg, NULL); nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg);
return 0; return 0;
} }
@@ -260,11 +202,12 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
nouveau_dsm_priv.other_handle = dhandle; nouveau_dsm_priv.other_handle = dhandle;
return false; return false;
} }
if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER)) if (acpi_check_dsm(dhandle, nouveau_dsm_muid, 0x00000102,
1 << NOUVEAU_DSM_POWER))
retval |= NOUVEAU_DSM_HAS_MUX; retval |= NOUVEAU_DSM_HAS_MUX;
if (nouveau_test_dsm(dhandle, nouveau_optimus_dsm, if (acpi_check_dsm(dhandle, nouveau_op_dsm_muid, 0x00000100,
NOUVEAU_DSM_OPTIMUS_CAPS)) 1 << NOUVEAU_DSM_OPTIMUS_CAPS))
retval |= NOUVEAU_DSM_HAS_OPT; retval |= NOUVEAU_DSM_HAS_OPT;
if (retval & NOUVEAU_DSM_HAS_OPT) { if (retval & NOUVEAU_DSM_HAS_OPT) {

View File

@@ -850,37 +850,23 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client,
0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45, 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45,
0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE, 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE,
}; };
union acpi_object params[4]; union acpi_object *obj;
struct acpi_object_list input;
struct acpi_device *adev; struct acpi_device *adev;
unsigned long long value;
acpi_handle handle; acpi_handle handle;
handle = ACPI_HANDLE(&client->dev); handle = ACPI_HANDLE(&client->dev);
if (!handle || acpi_bus_get_device(handle, &adev)) if (!handle || acpi_bus_get_device(handle, &adev))
return -ENODEV; return -ENODEV;
input.count = ARRAY_SIZE(params); obj = acpi_evaluate_dsm_typed(handle, i2c_hid_guid, 1, 1, NULL,
input.pointer = params; ACPI_TYPE_INTEGER);
if (!obj) {
params[0].type = ACPI_TYPE_BUFFER;
params[0].buffer.length = sizeof(i2c_hid_guid);
params[0].buffer.pointer = i2c_hid_guid;
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = 1;
params[2].type = ACPI_TYPE_INTEGER;
params[2].integer.value = 1; /* HID function */
params[3].type = ACPI_TYPE_PACKAGE;
params[3].package.count = 0;
params[3].package.elements = NULL;
if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_DSM", &input,
&value))) {
dev_err(&client->dev, "device _DSM execution failed\n"); dev_err(&client->dev, "device _DSM execution failed\n");
return -ENODEV; return -ENODEV;
} }
pdata->hid_descriptor_address = value; pdata->hid_descriptor_address = obj->integer.value;
ACPI_FREE(obj);
return 0; return 0;
} }

View File

@@ -186,7 +186,6 @@ static const char device_label_dsm_uuid[] = {
}; };
enum acpi_attr_enum { enum acpi_attr_enum {
ACPI_ATTR_NONE = 0,
ACPI_ATTR_LABEL_SHOW, ACPI_ATTR_LABEL_SHOW,
ACPI_ATTR_INDEX_SHOW, ACPI_ATTR_INDEX_SHOW,
}; };
@@ -194,84 +193,61 @@ enum acpi_attr_enum {
static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf) static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf)
{ {
int len; int len;
len = utf16s_to_utf8s((const wchar_t *)obj-> len = utf16s_to_utf8s((const wchar_t *)obj->string.pointer,
package.elements[1].string.pointer, obj->string.length,
obj->package.elements[1].string.length,
UTF16_LITTLE_ENDIAN, UTF16_LITTLE_ENDIAN,
buf, PAGE_SIZE); buf, PAGE_SIZE);
buf[len] = '\n'; buf[len] = '\n';
} }
static int static int
dsm_get_label(acpi_handle handle, int func, dsm_get_label(struct device *dev, char *buf, enum acpi_attr_enum attr)
struct acpi_buffer *output,
char *buf, enum acpi_attr_enum attribute)
{ {
struct acpi_object_list input; acpi_handle handle;
union acpi_object params[4]; union acpi_object *obj, *tmp;
union acpi_object *obj; int len = -1;
int len = 0;
int err; handle = ACPI_HANDLE(dev);
if (!handle)
input.count = 4;
input.pointer = params;
params[0].type = ACPI_TYPE_BUFFER;
params[0].buffer.length = sizeof(device_label_dsm_uuid);
params[0].buffer.pointer = (char *)device_label_dsm_uuid;
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = 0x02;
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;
err = acpi_evaluate_object(handle, "_DSM", &input, output);
if (err)
return -1; return -1;
obj = (union acpi_object *)output->pointer; obj = acpi_evaluate_dsm(handle, device_label_dsm_uuid, 0x2,
DEVICE_LABEL_DSM, NULL);
if (!obj)
return -1;
switch (obj->type) { tmp = obj->package.elements;
case ACPI_TYPE_PACKAGE: if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 2 &&
if (obj->package.count != 2) tmp[0].type == ACPI_TYPE_INTEGER &&
break; tmp[1].type == ACPI_TYPE_STRING) {
len = obj->package.elements[0].integer.value; /*
if (buf) { * The second string element is optional even when
if (attribute == ACPI_ATTR_INDEX_SHOW) * this _DSM is implemented; when not implemented,
scnprintf(buf, PAGE_SIZE, "%llu\n", * this entry must return a null string.
obj->package.elements[0].integer.value); */
else if (attribute == ACPI_ATTR_LABEL_SHOW) if (attr == ACPI_ATTR_INDEX_SHOW)
dsm_label_utf16s_to_utf8s(obj, buf); scnprintf(buf, PAGE_SIZE, "%llu\n", tmp->integer.value);
kfree(output->pointer); else if (attr == ACPI_ATTR_LABEL_SHOW)
return strlen(buf); dsm_label_utf16s_to_utf8s(tmp + 1, buf);
} len = strlen(buf) > 0 ? strlen(buf) : -1;
kfree(output->pointer);
return len;
break;
default:
kfree(output->pointer);
} }
return -1;
ACPI_FREE(obj);
return len;
} }
static bool static bool
device_has_dsm(struct device *dev) device_has_dsm(struct device *dev)
{ {
acpi_handle handle; acpi_handle handle;
struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
handle = ACPI_HANDLE(dev); handle = ACPI_HANDLE(dev);
if (!handle) if (!handle)
return FALSE; return false;
if (dsm_get_label(handle, DEVICE_LABEL_DSM, &output, NULL, return !!acpi_check_dsm(handle, device_label_dsm_uuid, 0x2,
ACPI_ATTR_NONE) > 0) 1 << DEVICE_LABEL_DSM);
return TRUE;
return FALSE;
} }
static umode_t static umode_t
@@ -290,44 +266,13 @@ acpi_index_string_exist(struct kobject *kobj, struct attribute *attr, int n)
static ssize_t static ssize_t
acpilabel_show(struct device *dev, struct device_attribute *attr, char *buf) acpilabel_show(struct device *dev, struct device_attribute *attr, char *buf)
{ {
struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; return dsm_get_label(dev, buf, ACPI_ATTR_LABEL_SHOW);
acpi_handle handle;
int length;
handle = ACPI_HANDLE(dev);
if (!handle)
return -1;
length = dsm_get_label(handle, DEVICE_LABEL_DSM,
&output, buf, ACPI_ATTR_LABEL_SHOW);
if (length < 1)
return -1;
return length;
} }
static ssize_t static ssize_t
acpiindex_show(struct device *dev, struct device_attribute *attr, char *buf) acpiindex_show(struct device *dev, struct device_attribute *attr, char *buf)
{ {
struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; return dsm_get_label(dev, buf, ACPI_ATTR_INDEX_SHOW);
acpi_handle handle;
int length;
handle = ACPI_HANDLE(dev);
if (!handle)
return -1;
length = dsm_get_label(handle, DEVICE_LABEL_DSM,
&output, buf, ACPI_ATTR_INDEX_SHOW);
if (length < 0)
return -1;
return length;
} }
static struct device_attribute acpi_attr_label = { static struct device_attribute acpi_attr_label = {

View File

@@ -64,6 +64,32 @@ bool acpi_ata_match(acpi_handle handle);
bool acpi_bay_match(acpi_handle handle); bool acpi_bay_match(acpi_handle handle);
bool acpi_dock_match(acpi_handle handle); bool acpi_dock_match(acpi_handle handle);
bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs);
union acpi_object *acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid,
int rev, int func, union acpi_object *argv4);
static inline union acpi_object *
acpi_evaluate_dsm_typed(acpi_handle handle, const u8 *uuid, int rev, int func,
union acpi_object *argv4, acpi_object_type type)
{
union acpi_object *obj;
obj = acpi_evaluate_dsm(handle, uuid, rev, func, argv4);
if (obj && obj->type != type) {
ACPI_FREE(obj);
obj = NULL;
}
return obj;
}
#define ACPI_INIT_DSM_ARGV4(cnt, eles) \
{ \
.package.type = ACPI_TYPE_PACKAGE, \
.package.count = (cnt), \
.package.elements = (eles) \
}
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
#include <linux/proc_fs.h> #include <linux/proc_fs.h>