Introduce ACPI _DSM helper functions to simplify code
Subsystems (9)
v2 cover Introduce ACPI _DSM helper functions to simplify code
There are several drivers making use of ACPI _DSM method to detect and invoke device specific methods. Currently every driver has implemented its private version to support ACPI _DSM method. So this patch introduces three helper functions to support ACPI _DSM method, which will be used to replace open-coded versions. It helps to simplify code and improve code readability.
It also includes some bugfixes for TPM/nouveau drivers.
It applies to the mainstream kernel on top of
b0031f2 Merge tag 's2mps11-build' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
Due to lacking of hardware platform, I have only tested the ACPI _DSM helper functions and TPM related changes, but haven't tested changes to other drivers yet. So appreciate help to review and test these patches.
V1->V2
1) fix an issue in initializing acpi_object structure
Jiang Liu (13):
ACPI: introduce helper interfaces to support ACPI _DSM method ACPI, extlog: replace open-coded _DSM specific code with helper
functions
PCI, pci-label: release allocated ACPI object on error recovery path ACPI, PCI: replace open-coded _DSM specific code with helper
functions
PCI, pci-label: treat PCI label with index 0 as valid label ACPI, TPM: fix memory leak when walking ACPI namespace ACPI, TPM: matching node name instead of full path when searching for
TPM device
ACPI, TPM: replace open-coded _DSM specific code with helper
functions
ACPI, TPM: detecting PPI features by checking availability of _DSM
functions
ACPI, i2c-hid: replace open-coded _DSM specific code with helper
functions
ACPI, i915: replace open-coded _DSM specific code with helper
functions
nouveau: fix memory leak in ACPI _DSM related code
ACPI, nouveau: replace open-coded _DSM specific code with helper
functions
drivers/acpi/acpi_extlog.c | 61 +--- drivers/acpi/utils.c | 98 ++++++ drivers/char/tpm/tpm_ppi.c | 406 +++++++++--------------- drivers/gpu/drm/i915/intel_acpi.c | 144 ++------- drivers/gpu/drm/nouveau/core/subdev/mxm/base.c | 48 +-- drivers/gpu/drm/nouveau/nouveau_acpi.c | 134 +++----- drivers/hid/i2c-hid/i2c-hid.c | 26 +- drivers/pci/pci-label.c | 129 +++----- include/acpi/acpi_bus.h | 26 ++ 9 files changed, 406 insertions(+), 666 deletions(-)
Signature · 1 line
1.7.10.4
PATCH v2 1/13 ACPI: introduce helper interfaces to support ACPI _DSM method
There are several drivers making use of ACPI _DSM method to detect and invoke device specific methods. Currently every driver has implemented its private version to support ACPI _DSM method. So this patch introduces three helper functions to support ACPI _DSM method, which will be used to replace open-coded versions.
It helps to simplify code and improve code readability.
--- drivers/acpi/utils.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_bus.h | 26 +++++++++++++ 2 files changed, 124 insertions(+)
drivers/acpi/utils.c +98 -0
@@ -574,3 +574,101 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock)return status; } + +/** +* acpi_evaluate_dsm: evaluate device's _DSM method +* @handle: ACPI device handle +* @uuid: UUID of requested functions, should be 16 bytes +* @rev: revision number of requested function +* @func: requested function number +* @argv4: the function specific parameter +* +* Evaluate device's _DSM method with specified UUID, revision id and +* function number. Caller needs to free the returned object. +* +* Though ACPI defines the fourth parameter for _DSM should be a package, +* some old BIOSes do expect a buffer or an integer etc. +*/ +union acpi_object * +acpi_evaluate_dsm (acpi_handle handle,const u8 *uuid,int rev,int func, +union acpi_object *argv4) +{ +acpi_status ret; +struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER ,NULL }; +union acpi_object params[4 ]; +struct acpi_object_list input = { + .count =4 , + .pointer = params, + }; + + params[0 ].type =ACPI_TYPE_BUFFER ; + params[0 ].buffer.length =16 ; + params[0 ].buffer.pointer = (char *)uuid; + params[1 ].type =ACPI_TYPE_INTEGER ; + params[1 ].integer.value = rev; + params[2 ].type =ACPI_TYPE_INTEGER ; + params[2 ].integer.value = func; +if (argv4) { + params[3 ] = *argv4; + }else { + params[3 ].type =ACPI_TYPE_PACKAGE ; + params[3 ].package.count =0 ; + params[3 ].package.elements =NULL ; + } + + ret =acpi_evaluate_object (handle,"_DSM" , &input, &buf); +if (ACPI_SUCCESS (ret)) +return (union acpi_object *)buf.pointer; + +if (ret !=AE_NOT_FOUND ) +acpi_handle_warn (handle, +"failed to evaluate _DSM method (0x%x)\n" , ret); + +return NULL ; +} +EXPORT_SYMBOL (acpi_evaluate_dsm); + +/** +* acpi_check_dsm: check whether _DSM method under @handle 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);
include/acpi/acpi_bus.h +26 -0
@@ -66,6 +66,32 @@ bool acpi_ata_match(acpi_handle handle);bool acpi_bay_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 #include <linux/proc_fs.h>
Signature · 1 line
1.7.10.4
PATCH v2 3/13 PCI, pci-label: release allocated ACPI object on error recovery path
In reply to Jiang LiuFunction dsm_get_label() leaks the returned ACPI object if obj->package.count is not 2, so fix the possible memory leak.
--- drivers/pci/pci-label.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
drivers/pci/pci-label.c +4 -8
@@ -233,11 +233,7 @@ dsm_get_label(acpi_handle handle, int func,return -1 ; obj = (union acpi_object *)output->pointer; - -switch (obj->type) { -case ACPI_TYPE_PACKAGE : -if (obj->package.count !=2 ) -break ; +if (obj->type ==ACPI_TYPE_PACKAGE && obj->package.count ==2 ) { len = obj->package.elements[0 ].integer.value;if (buf) {if (attribute ==ACPI_ATTR_INDEX_SHOW )
@@ -250,10 +246,10 @@ dsm_get_label(acpi_handle handle, int func, }kfree (output->pointer);return len; -break ; -default : -kfree (output->pointer); } + +kfree (output->pointer); +return -1 ; }
Signature · 1 line
1.7.10.4
Bjorn Helgaas
maintainerRe: [Patch v2 03/13] PCI, pci-label: release allocated ACPI object on error recovery path
Quoted 4 lines · Jiang Liu
Function
dsm_get_label()leaks the returned ACPI object ifobj->package.countis not 2, so fix the possible memory leak.Signed-off-by Jiang Liu <[email protected]>
Rafael, if you want to take these through your tree, feel free. I'm guessing it probably makes sense to keep the whole series together.
Quoted 38 lines
--- drivers/pci/pci-label.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)drivers/pci/pci-label.c +4
-9@@ -233,11 +233,7 @@ dsm_get_label(acpi_handle handle, int func,return -1 ; obj = (union acpi_object *)output->pointer; - -switch (obj->type) { -case ACPI_TYPE_PACKAGE : -if (obj->package.count !=2 ) -break ; +if (obj->type ==ACPI_TYPE_PACKAGE && obj->package.count ==2 ) { len = obj->package.elements[0 ].integer.value;if (buf) {if (attribute ==ACPI_ATTR_INDEX_SHOW )@@ -250,10 +246,10 @@ dsm_get_label(acpi_handle handle, int func, }kfree (output->pointer);return len; -break ; -default : -kfree (output->pointer); } + +kfree (output->pointer); +return -1 ; } --1.7.10.4
Re: [Patch v2 03/13] PCI, pci-label: release allocated ACPI object on error recovery path
Quoted 7 lines · Bjorn Helgaas
Quoted 4 lines · Jiang Liu
Function
dsm_get_label()leaks the returned ACPI object ifobj->package.countis not 2, so fix the possible memory leak.Signed-off-by Jiang Liu <[email protected]>Rafael, if you want to take these through your tree, feel free.
I'm going to do that, thanks!
Quoted 1 line
I'm guessing it probably makes sense to keep the whole series together.
Agreed.
Quoted 42 lines
Quoted 36 lines
--- drivers/pci/pci-label.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)drivers/pci/pci-label.c +4
-9@@ -233,11 +233,7 @@ dsm_get_label(acpi_handle handle, int func,return -1 ; obj = (union acpi_object *)output->pointer; - -switch (obj->type) { -case ACPI_TYPE_PACKAGE : -if (obj->package.count !=2 ) -break ; +if (obj->type ==ACPI_TYPE_PACKAGE && obj->package.count ==2 ) { len = obj->package.elements[0 ].integer.value;if (buf) {if (attribute ==ACPI_ATTR_INDEX_SHOW )@@ -250,10 +246,10 @@ dsm_get_label(acpi_handle handle, int func, }kfree (output->pointer);return len; -break ; -default : -kfree (output->pointer); } + +kfree (output->pointer); +return -1 ; } --Quoted 2 lines
1.7.10.4
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center.
PATCH v2 4/13 ACPI, PCI: replace open-coded _DSM specific code with helper functions
In reply to Jiang LiuUse helper functions to simplify _DSM related code in pci-label driver. Also enforce more strict checks on objects returned by _DSM method.
--- drivers/pci/pci-label.c | 121 +++++++++++++---------------------------------- 1 file changed, 34 insertions(+), 87 deletions(-)
drivers/pci/pci-label.c +34 -87
@@ -195,80 +195,58 @@ enum acpi_attr_enum {static void dsm_label_utf16s_to_utf8s (union acpi_object *obj,char *buf) {int len; - len =utf16s_to_utf8s ((const wchar_t *)obj-> - package.elements[1 ].string.pointer, - obj->package.elements[1 ].string.length, + len =utf16s_to_utf8s ((const wchar_t *)obj->string.pointer, + obj->string.length,UTF16_LITTLE_ENDIAN , buf,PAGE_SIZE ); buf[len] ='\n' ; }static int -dsm_get_label (acpi_handle handle,int func, -struct acpi_buffer *output, -char *buf,enum acpi_attr_enum attribute) +dsm_get_label (struct device *dev,char *buf,enum acpi_attr_enum attr) { -struct acpi_object_list input; -union acpi_object params[4 ]; -union acpi_object *obj; -int len =0 ; - -int err; - - 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) +acpi_handle handle; +union acpi_object *obj, *tmp; +int len =-1 ; + + handle =ACPI_HANDLE (dev); +if (!handle)return -1 ; - obj = (union acpi_object *)output->pointer; -if (obj->type ==ACPI_TYPE_PACKAGE && obj->package.count ==2 ) { - len = obj->package.elements[0 ].integer.value; + obj =acpi_evaluate_dsm (handle, device_label_dsm_uuid,0x2 , +DEVICE_LABEL_DSM ,NULL ); +if (!obj) +return -1 ; + + tmp = obj->package.elements; +if (obj->type ==ACPI_TYPE_PACKAGE && obj->package.count ==2 && + tmp[0 ].type ==ACPI_TYPE_INTEGER && + tmp[1 ].type ==ACPI_TYPE_STRING ) { + len = tmp[0 ].integer.value;if (buf) { -if (attribute ==ACPI_ATTR_INDEX_SHOW ) +/* +* This second string element is optional even when +* this _DSM is implemented; when not implemented, +* this entry must return a null string. +*/ +if (attr ==ACPI_ATTR_INDEX_SHOW )scnprintf (buf,PAGE_SIZE ,"%llu\n" , - obj->package.elements[0 ].integer.value); -else if (attribute ==ACPI_ATTR_LABEL_SHOW ) -dsm_label_utf16s_to_utf8s (obj, buf); -kfree (output->pointer); -return strlen (buf); + tmp->integer.value); +else if (attr ==ACPI_ATTR_LABEL_SHOW ) +dsm_label_utf16s_to_utf8s (tmp +1 , buf); + len =strlen (buf) >0 ?strlen (buf) :-1 ; } -kfree (output->pointer); -return len; } -kfree (output->pointer); +ACPI_FREE (obj); -return -1 ; +return len; }static bool device_has_dsm (struct device *dev) { -acpi_handle handle; -struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER ,NULL }; - - handle =ACPI_HANDLE (dev); - -if (!handle) -return FALSE; - -if (dsm_get_label (handle,DEVICE_LABEL_DSM , &output,NULL , -ACPI_ATTR_NONE ) >0 ) -return TRUE; - -return FALSE; +return dsm_get_label (dev,NULL ,ACPI_ATTR_NONE ) >0 ; } static umode_t
@@ -287,44 +265,13 @@ acpi_index_string_exist(struct kobject *kobj, struct attribute *attr, int n)static ssize_t acpilabel_show (struct device *dev,struct device_attribute *attr,char *buf) { -struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER ,NULL }; -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; +return dsm_get_label (dev, buf,ACPI_ATTR_LABEL_SHOW ); }static ssize_t acpiindex_show (struct device *dev,struct device_attribute *attr,char *buf) { -struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER ,NULL }; -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; - +return dsm_get_label (dev, buf,ACPI_ATTR_INDEX_SHOW ); }static struct device_attribute acpi_attr_label = {
Signature · 1 line
1.7.10.4
PATCH v2 5/13 PCI, pci-label: treat PCI label with index 0 as valid label
In reply to Jiang LiuCurrent pci-label driver detects ACPI label by checking label index returned by ACPI _DSM method, and treat it as valid if label index is positive. According to ACPI Firmware specification 3.1, zero is also an valid label index. So change code to detect availability of ACPI slot label by checking availaiblity of ACPI _DSM function for PCI label.
--- drivers/pci/pci-label.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-)
drivers/pci/pci-label.c +18 -16
@@ -187,7 +187,6 @@ static const char device_label_dsm_uuid[] = { };enum acpi_attr_enum { -ACPI_ATTR_NONE =0 ,ACPI_ATTR_LABEL_SHOW ,ACPI_ATTR_INDEX_SHOW , };
@@ -222,20 +221,16 @@ dsm_get_label(struct device *dev, char *buf, enum acpi_attr_enum attr)if (obj->type ==ACPI_TYPE_PACKAGE && obj->package.count ==2 && tmp[0 ].type ==ACPI_TYPE_INTEGER && tmp[1 ].type ==ACPI_TYPE_STRING ) { - len = tmp[0 ].integer.value; -if (buf) { -/* -* This second string element is optional even when -* this _DSM is implemented; when not implemented, -* this entry must return a null string. -*/ -if (attr ==ACPI_ATTR_INDEX_SHOW ) -scnprintf (buf,PAGE_SIZE ,"%llu\n" , - tmp->integer.value); -else if (attr ==ACPI_ATTR_LABEL_SHOW ) -dsm_label_utf16s_to_utf8s (tmp +1 , buf); - len =strlen (buf) >0 ?strlen (buf) :-1 ; - } +/* +* The second string element is optional even when +* this _DSM is implemented; when not implemented, +* this entry must return a null string. +*/ +if (attr ==ACPI_ATTR_INDEX_SHOW ) +scnprintf (buf,PAGE_SIZE ,"%llu\n" , tmp->integer.value); +else if (attr ==ACPI_ATTR_LABEL_SHOW ) +dsm_label_utf16s_to_utf8s (tmp +1 , buf); + len =strlen (buf) >0 ?strlen (buf) :-1 ; }ACPI_FREE (obj);
@@ -246,7 +241,14 @@ dsm_get_label(struct device *dev, char *buf, enum acpi_attr_enum attr)static bool device_has_dsm (struct device *dev) { -return dsm_get_label (dev,NULL ,ACPI_ATTR_NONE ) >0 ; +acpi_handle handle; + + handle =ACPI_HANDLE (dev); +if (!handle) +return false; + +return !!acpi_check_dsm (handle, device_label_dsm_uuid,0x2 , +1 <<DEVICE_LABEL_DSM ); } static umode_t
Signature · 1 line
1.7.10.4
PATCH v2 6/13 ACPI, TPM: fix memory leak when walking ACPI namespace
In reply to Jiang LiuIn function ppi_callback(), memory allocated by acpi_get_name() will get leaked when current device isn't the desired TPM device, so fix the memory leak.
--- drivers/char/tpm/tpm_ppi.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/char/tpm/tpm_ppi.c +9 -6
@@ -27,15 +27,18 @@ static char *tpm_device_name = "TPM";static acpi_status ppi_callback (acpi_handle handle,u32 level,void *context,void **return_value) { -acpi_status status; +acpi_status status =AE_OK ;struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER ,NULL }; - status =acpi_get_name (handle,ACPI_FULL_PATHNAME , &buffer); -if (strstr (buffer.pointer, context) !=NULL ) { - *return_value = handle; + +if (ACPI_SUCCESS (acpi_get_name (handle,ACPI_FULL_PATHNAME , &buffer))) { +if (strstr (buffer.pointer, context) !=NULL ) { + *return_value = handle; + status =AE_CTRL_TERMINATE ; + }kfree (buffer.pointer); -return AE_CTRL_TERMINATE ; } -return AE_OK ; + +return status; } static inline void ppi_assign_params(union acpi_object params[4],
Signature · 1 line
1.7.10.4
PATCH v2 7/13 ACPI, TPM: matching node name instead of full path when searching for TPM device
In reply to Jiang LiuWhen searching ACPI object for TPM device, it should match current ACPI object name instead of the full path.
--- drivers/char/tpm/tpm_ppi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/char/tpm/tpm_ppi.c +1 -1
@@ -30,7 +30,7 @@ static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context,acpi_status status =AE_OK ;struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER ,NULL }; -if (ACPI_SUCCESS (acpi_get_name (handle,ACPI_FULL_PATHNAME , &buffer))) { +if (ACPI_SUCCESS (acpi_get_name (handle,ACPI_SINGLE_NAME , &buffer))) {if (strstr (buffer.pointer, context) !=NULL ) { *return_value = handle; status =AE_CTRL_TERMINATE ;
Signature · 1 line
1.7.10.4
PATCH v2 8/13 ACPI, TPM: replace open-coded _DSM specific code with helper functions
In reply to Jiang LiuUse helper functions to simplify _DSM related code in TPM driver.
This patch also help to get rid of following warning messages:
[ 163.509575] ACPI Error: Incorrect return type [Buffer] requested [Package]
(20130517/nsxfeval-135)
But there is still an warning left.
[ 181.637366] ACPI Warning: \_SB_.IIO0.LPC0.TPM_._DSM: Argument #4 type
mismatch - Found [Buffer], ACPI requires [Package] (20130517/nsarguments-95)
--- drivers/char/tpm/tpm_ppi.c | 404 ++++++++++++++++---------------------------- 1 file changed, 145 insertions(+), 259 deletions(-)
drivers/char/tpm/tpm_ppi.c +145 -259
@@ -2,15 +2,6 @@#include <acpi/acpi_drivers.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_FN_VERSION 1#define TPM_PPI_FN_SUBREQ 2
@@ -24,250 +15,185 @@ static char *tpm_device_name = "TPM";#define PPI_VS_REQ_END 255#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_device_name ="TPM" ; +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,void **return_value) {acpi_status status =AE_OK ;struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER ,NULL }; -if (ACPI_SUCCESS (acpi_get_name (handle,ACPI_SINGLE_NAME , &buffer))) { -if (strstr (buffer.pointer, context) !=NULL ) { - *return_value = handle; - status =AE_CTRL_TERMINATE ; + status =acpi_get_name (handle,ACPI_SINGLE_NAME , &buffer); +if (ACPI_FAILURE (status)) +return AE_OK ; + +if (strstr (buffer.pointer, context) !=NULL ) { +union acpi_object *obj; + +/* Cache version string */ + 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); } -kfree (buffer.pointer); + + *return_value = handle; + status =AE_CTRL_TERMINATE ; } +kfree (buffer.pointer);return status; } -static inline void ppi_assign_params (union acpi_object params[4 ], -u64 function_num) +static inline union acpi_object * +tpm_eval_dsm (int func,acpi_object_type type,union acpi_object *argv4) { - params[0 ].type =ACPI_TYPE_BUFFER ; - params[0 ].buffer.length =sizeof (tpm_ppi_uuid); - params[0 ].buffer.pointer = (char *)tpm_ppi_uuid; - 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 ; +BUG_ON (!tpm_ppi_handle); +return acpi_evaluate_dsm_typed (tpm_ppi_handle, tpm_ppi_uuid, +TPM_PPI_REVISION_ID , func, argv4, type); }static ssize_t tpm_show_ppi_version (struct device *dev,struct device_attribute *attr,char *buf) { -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; - - 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; +return scnprintf (buf,PAGE_SIZE ,"%s\n" , tpm_ppi_version); }static ssize_t tpm_show_ppi_request (struct device *dev,struct device_attribute *attr,char *buf) { -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 *ret_obj; - - input.count =4 ; -ppi_assign_params (params,TPM_PPI_FN_GETREQ ); - 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)) +ssize_t size = -EINVAL ; +union acpi_object *obj; + + obj =tpm_eval_dsm (TPM_PPI_FN_GETREQ ,ACPI_TYPE_PACKAGE ,NULL ); +if (!obj)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. * The first is function return code, 0 means success and 1 means * error. The second is pending TPM operation requested by the OS, 0 * means none and >0 means operation value. */ - ret_obj = ((union acpi_object *)output.pointer)->package.elements; -if (ret_obj->type ==ACPI_TYPE_INTEGER ) { -if (ret_obj->integer.value) { - status = -EFAULT ; - goto cleanup; - } - ret_obj++; -if (ret_obj->type ==ACPI_TYPE_INTEGER ) - status =scnprintf (buf,PAGE_SIZE ,"%llu\n" , - ret_obj->integer.value); +if (obj->package.count ==2 && + obj->package.elements[0 ].type ==ACPI_TYPE_INTEGER && + obj->package.elements[1 ].type ==ACPI_TYPE_INTEGER ) { +if (obj->package.elements[0 ].integer.value) + size = -EFAULT ;else - status = -EINVAL ; - }else { - status = -EINVAL ; + size =scnprintf (buf,PAGE_SIZE ,"%llu\n" , + obj->package.elements[1 ].integer.value); } -cleanup: -kfree (output.pointer); -return status; + +ACPI_FREE (obj); + +return size; }static ssize_t tpm_store_ppi_request (struct device *dev,struct device_attribute *attr,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;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 * is updated with function index from SUBREQ to SUBREQ2 since PPI * version 1.1 */ -if (strcmp (version,"1.1" ) ==-1 ) - params[2 ].integer.value =TPM_PPI_FN_SUBREQ ; -else - params[2 ].integer.value =TPM_PPI_FN_SUBREQ2 ; +if (strcmp (tpm_ppi_version,"1.1" ) >=0 ) + func =TPM_PPI_FN_SUBREQ2 ; +/* * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS * accept buffer/string/integer type, but some BIOS accept buffer/ * 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. */ -if (strcmp (version,"1.2" ) ==-1 ) { - params[3 ].type =ACPI_TYPE_BUFFER ; - params[3 ].buffer.length =sizeof (req); -sscanf (buf,"%d" , &req); - params[3 ].buffer.pointer = (char *)&req; +if (strcmp (tpm_ppi_version,"1.2" ) <0 ) { +if (sscanf (buf,"%d" , &req) !=1 ) +return -EINVAL ; + argv4.type =ACPI_TYPE_BUFFER ; + argv4.buffer.length =sizeof (req); + argv4.buffer.pointer = (u8 *)&req; }else { - params[3 ].package.count =1 ; - obj.type =ACPI_TYPE_INTEGER ; -sscanf (buf,"%llu" , &obj.integer.value); - params[3 ].package.elements = &obj; + tmp.type =ACPI_TYPE_INTEGER ; +if (sscanf (buf,"%llu" , &tmp.integer.value) !=1 ) +return -EINVAL ; + } + + 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 ) - status = (acpi_status )count; -else if (ret ==1 ) - status = -EPERM ; -else - status = -EFAULT ; -kfree (output.pointer); -return status; +return (acpi_status )count; + +return (ret ==1 ) ? -EPERM : -EFAULT ; }static ssize_t tpm_show_ppi_transition_action (struct device *dev,struct device_attribute *attr,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; -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" ,"Shutdown" ,"Reboot" ,"OS Vendor-specific" ,"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 * (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 */ -if (strcmp (version,"1.2" ) ==-1 ) { - params[3 ].type =ACPI_TYPE_BUFFER ; - params[3 ].buffer.length =0 ; - params[3 ].buffer.pointer =NULL ; +if (strcmp (tpm_ppi_version,"1.2" ) <0 ) + obj = &tmp; + obj =tpm_eval_dsm (TPM_PPI_FN_GETACT ,ACPI_TYPE_INTEGER , obj); +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 ) status =scnprintf (buf,PAGE_SIZE ,"%d: %s\n" , ret, info[ret]);else status =scnprintf (buf,PAGE_SIZE ,"%d: %s\n" , ret, info[ARRAY_SIZE (info)-1 ]); -kfree (output.pointer);return status; }
@@ -275,27 +201,14 @@ static ssize_t tpm_show_ppi_response(struct device *dev,struct device_attribute *attr, char *buf) { - 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 *ret_obj; -u64 req; - - input.count =4 ; -ppi_assign_params (params,TPM_PPI_FN_GETRSP ); - 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)) + acpi_status status = -EINVAL; +union acpi_object *obj, *ret_obj; +u64 req, res; + + obj =tpm_eval_dsm (TPM_PPI_FN_GETRSP ,ACPI_TYPE_PACKAGE ,NULL ); +if (!obj)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 * 3 integers. The first means function return code, the second means
@@ -303,115 +216,81 @@ static ssize_t tpm_show_ppi_response(struct device *dev,* the most recent TPM operation request. Only if the first is 0, and * the second integer is not 0, the response makes sense. */ - ret_obj = ((union acpi_object *)output.pointer)->package.elements; -if (ret_obj->type !=ACPI_TYPE_INTEGER ) { - status = -EINVAL ; + ret_obj = obj->package.elements; +if (obj->package.count <3 || + ret_obj[0 ].type !=ACPI_TYPE_INTEGER || + ret_obj[1 ].type !=ACPI_TYPE_INTEGER || + ret_obj[2 ].type !=ACPI_TYPE_INTEGER ) goto cleanup; - } -if (ret_obj->integer.value) { + +if (ret_obj[0 ].integer.value) { status = -EFAULT ; goto cleanup; } - ret_obj++; -if (ret_obj->type !=ACPI_TYPE_INTEGER ) { - status = -EINVAL ; - goto cleanup; - } -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 ) + + req = ret_obj[1 ].integer.value; + res = ret_obj[2 ].integer.value; +if (req) { +if (res ==0 ) status =scnprintf (buf,PAGE_SIZE ,"%llu %s\n" , req,"0: Success" ); -else if (ret_obj->integer.value ==0xFFFFFFF0 ) +else if (res ==0xFFFFFFF0 ) status =scnprintf (buf,PAGE_SIZE ,"%llu %s\n" , req,"0xFFFFFFF0: User Abort" ); -else if (ret_obj->integer.value ==0xFFFFFFF1 ) +else if (res ==0xFFFFFFF1 ) status =scnprintf (buf,PAGE_SIZE ,"%llu %s\n" , req,"0xFFFFFFF1: BIOS Failure" ); -else if (ret_obj->integer.value >=1 && - ret_obj->integer.value <=0x00000FFF ) +else if (res >=1 && res <=0x00000FFF ) status =scnprintf (buf,PAGE_SIZE ,"%llu %llu: %s\n" , - req, ret_obj->integer.value, -"Corresponding TPM error" ); + req, res,"Corresponding TPM error" );else status =scnprintf (buf,PAGE_SIZE ,"%llu %llu: %s\n" , - req, ret_obj->integer.value, -"Error" ); + req, res,"Error" ); }else { status =scnprintf (buf,PAGE_SIZE ,"%llu: %s\n" , - ret_obj->integer.value,"No Recent Request" ); + req,"No Recent Request" ); } + cleanup: -kfree (output.pointer); +ACPI_FREE (obj);return status; }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;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" ,"BIOS only" ,"Blocked for OS by BIOS" ,"User 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, -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 ; -if (strcmp (version,"1.2" ) ==-1 ) +if (strcmp (tpm_ppi_version,"1.2" ) <0 )return -EPERM ; - params[2 ].integer.value =TPM_PPI_FN_GETOPR ; - params[3 ].package.count =1 ; - obj.type =ACPI_TYPE_INTEGER ; - params[3 ].package.elements = &obj; + tmp.integer.type =ACPI_TYPE_INTEGER ;for (i = start; i <= end; i++) { - obj.integer.value = i; - status =acpi_evaluate_object_typed (handle,"_DSM" , - &input, &output,ACPI_TYPE_INTEGER ); -if (ACPI_FAILURE (status)) + tmp.integer.value = i; + obj =tpm_eval_dsm (TPM_PPI_FN_GETOPR ,ACPI_TYPE_INTEGER , &argv); +if (!obj) {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)) str +=scnprintf (str,PAGE_SIZE ,"%d %d: %s\n" , i, ret, info[ret]); -kfree (output.pointer); - output.length =ACPI_ALLOCATE_BUFFER ; - output.pointer =NULL ; } +return str - buf; }
@@ -453,6 +332,13 @@ static struct attribute_group ppi_attr_grp = {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 , + tpm_device_name, &tpm_ppi_handle); +if (tpm_ppi_handle ==NULL ) +return -ENODEV ; +return sysfs_create_group (parent, &ppi_attr_grp); }
Signature · 1 line
1.7.10.4
PATCH v2 9/13 ACPI, TPM: detecting PPI features by checking availability of _DSM functions
In reply to Jiang LiuDetecting physical presence interface features by checking availbility of corresponding ACPI _DSM functions, it should be more accurate than checking TPM version number.
--- drivers/char/tpm/tpm_ppi.c | 45 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 26 deletions(-)
drivers/char/tpm/tpm_ppi.c +19 -26
@@ -23,39 +23,31 @@ static const u8 tpm_ppi_uuid[] = {0x8D ,0x10 ,0x08 ,0x9D ,0x16 ,0x53 }; -static char *tpm_device_name ="TPM" ;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,void **return_value) { -acpi_status status =AE_OK ; -struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER ,NULL }; +union acpi_object *obj; - status =acpi_get_name (handle,ACPI_SINGLE_NAME , &buffer); -if (ACPI_FAILURE (status)) +if (!acpi_check_dsm (handle, tpm_ppi_uuid,TPM_PPI_REVISION_ID , +1 <<TPM_PPI_FN_VERSION ))return AE_OK ; -if (strstr (buffer.pointer, context) !=NULL ) { -union acpi_object *obj; - -/* Cache version string */ - 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_value = handle; - status =AE_CTRL_TERMINATE ; +/* Cache version string */ + 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); } -kfree (buffer.pointer); -return status; + *return_value = handle; + +return AE_CTRL_TERMINATE ; } static inline union acpi_object *
@@ -118,7 +110,8 @@ static ssize_t tpm_store_ppi_request(struct device *dev,* is updated with function index from SUBREQ to SUBREQ2 since PPI * version 1.1 */ -if (strcmp (tpm_ppi_version,"1.1" ) >=0 ) +if (acpi_check_dsm (tpm_ppi_handle, tpm_ppi_uuid,TPM_PPI_REVISION_ID , +1 <<TPM_PPI_FN_SUBREQ2 )) func =TPM_PPI_FN_SUBREQ2 ;/*
@@ -272,7 +265,8 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) "User not required", }; -if (strcmp (tpm_ppi_version,"1.2" ) <0 ) +if (!acpi_check_dsm (tpm_ppi_handle, tpm_ppi_uuid,TPM_PPI_REVISION_ID , +1 <<TPM_PPI_FN_GETOPR ))return -EPERM ; tmp.integer.type =ACPI_TYPE_INTEGER ;
@@ -334,8 +328,7 @@ 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 , - tpm_device_name, &tpm_ppi_handle); + ppi_callback,NULL ,NULL , &tpm_ppi_handle);if (tpm_ppi_handle ==NULL )return -ENODEV ;
Signature · 1 line
1.7.10.4
PATCH v2 10/13 ACPI, i2c-hid: replace open-coded _DSM specific code with helper functions
In reply to Jiang LiuUse helper functions to simplify _DSM related code in i2c-hid driver.
--- drivers/hid/i2c-hid/i2c-hid.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-)
drivers/hid/i2c-hid/i2c-hid.c +6 -20
@@ -850,37 +850,23 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client,0xF7 ,0xF6 ,0xDF ,0x3C ,0x67 ,0x42 ,0x55 ,0x45 , 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE, }; -union acpi_object params[4 ]; -struct acpi_object_list input; +union acpi_object *obj;struct acpi_device *adev; -unsigned long long value;acpi_handle handle; handle =ACPI_HANDLE (&client->dev);if (!handle ||acpi_bus_get_device (handle, &adev))return -ENODEV ; - input.count =ARRAY_SIZE (params); - input.pointer = params; - - 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))) { + obj =acpi_evaluate_dsm_typed (handle, i2c_hid_guid,1 ,1 ,NULL , +ACPI_TYPE_INTEGER ); +if (!obj) {dev_err (&client->dev,"device _DSM execution failed\n" );return -ENODEV ; } - pdata->hid_descriptor_address = value; + pdata->hid_descriptor_address = obj->integer.value; +ACPI_FREE (obj);return 0 ; }
Signature · 1 line
1.7.10.4
PATCH v2 11/13 ACPI, i915: replace open-coded _DSM specific code with helper functions
In reply to Jiang LiuUse helper functions to simplify _DSM related code in i915 driver.
Function intel_dsm() is used to check functions supported by ACPI _DSM method, but it has strange check for special value 0x80000002. After digging into nouveau driver, I think the check is copied from nouveau driver and is useless for i915 driver, so remove it.
--- drivers/gpu/drm/i915/intel_acpi.c | 144 ++++++++----------------------------- 1 file changed, 30 insertions(+), 114 deletions(-)
drivers/gpu/drm/i915/intel_acpi.c +30 -114
@@ -12,8 +12,6 @@#include "i915_drv.h" #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 */ static struct intel_dsm_priv {
@@ -28,61 +26,6 @@ static const u8 intel_dsm_guid[] = { 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) {switch (id) {
@@ -137,83 +80,56 @@ static char *intel_dsm_mux_type(u8 type)static void intel_dsm_platform_mux_info (void ) { -struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER ,NULL }; -struct acpi_object_list input; -union acpi_object params[4 ]; -union acpi_object *pkg; -int i, ret; - - 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 =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; +int i; +union acpi_object *pkg, *connector_count; + + pkg =acpi_evaluate_dsm_typed (intel_dsm_priv.dhandle, intel_dsm_guid, +INTEL_DSM_REVISION_ID ,INTEL_DSM_FN_PLATFORM_MUX_INFO , +NULL ,ACPI_TYPE_PACKAGE ); +if (!pkg) { +DRM_DEBUG_DRIVER ("failed to evaluate _DSM\n" ); +return ; } - pkg = (union acpi_object *)output.pointer; - -if (pkg->type ==ACPI_TYPE_PACKAGE ) { -union acpi_object *connector_count = &pkg->package.elements[0 ]; -DRM_DEBUG_DRIVER ("MUX info connectors: %lld\n" , - (unsigned long long )connector_count->integer.value); -for (i =1 ; i < pkg->package.count; i++) { -union acpi_object *obj = &pkg->package.elements[i]; -union acpi_object *connector_id = - &obj->package.elements[0 ]; -union acpi_object *info = &obj->package.elements[1 ]; -DRM_DEBUG_DRIVER ("Connector id: 0x%016llx\n" , - (unsigned long long )connector_id->integer.value); -DRM_DEBUG_DRIVER (" port id: %s\n" , -intel_dsm_port_name (info->buffer.pointer[0 ])); -DRM_DEBUG_DRIVER (" display mux info: %s\n" , -intel_dsm_mux_type (info->buffer.pointer[1 ])); -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 ])); - } + connector_count = &pkg->package.elements[0 ]; +DRM_DEBUG_DRIVER ("MUX info connectors: %lld\n" , + (unsigned long long )connector_count->integer.value); +for (i =1 ; i < pkg->package.count; i++) { +union acpi_object *obj = &pkg->package.elements[i]; +union acpi_object *connector_id = &obj->package.elements[0 ]; +union acpi_object *info = &obj->package.elements[1 ]; +DRM_DEBUG_DRIVER ("Connector id: 0x%016llx\n" , + (unsigned long long )connector_id->integer.value); +DRM_DEBUG_DRIVER (" port id: %s\n" , +intel_dsm_port_name (info->buffer.pointer[0 ])); +DRM_DEBUG_DRIVER (" display mux info: %s\n" , +intel_dsm_mux_type (info->buffer.pointer[1 ])); +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: -kfree (output.pointer); +ACPI_FREE (pkg); }static bool intel_dsm_pci_probe (struct pci_dev *pdev) {acpi_handle dhandle; -int ret; dhandle =ACPI_HANDLE (&pdev->dev);if (!dhandle)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" );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_platform_mux_info (); +return true; }
Signature · 1 line
1.7.10.4
PATCH v2 12/13 nouveau: fix memory leak in ACPI _DSM related code
In reply to Jiang LiuFix memory leak in function nouveau_optimus_dsm() and nouveau_dsm().
--- drivers/gpu/drm/nouveau/nouveau_acpi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/nouveau/nouveau_acpi.c +4 -1
@@ -110,6 +110,7 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *if (obj->type ==ACPI_TYPE_INTEGER )if (obj->integer.value ==0x80000002 ) { +kfree (output.pointer);return -ENODEV ; }
@@ -156,8 +157,10 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) obj = (union acpi_object *)output.pointer;if (obj->type ==ACPI_TYPE_INTEGER ) -if (obj->integer.value ==0x80000002 ) +if (obj->integer.value ==0x80000002 ) { +kfree (output.pointer);return -ENODEV ; + }if (obj->type ==ACPI_TYPE_BUFFER ) {if (obj->buffer.length ==4 && result) {
Signature · 1 line
1.7.10.4
PATCH v2 13/13 ACPI, nouveau: replace open-coded _DSM specific code with helper functions
In reply to Jiang LiuUse helper functions to simplify _DSM related code in nouveau driver. After analyzing the ACPI _DSM related code, I changed nouveau_optimus_dsm() to expect a buffer and nouveau_dsm() to expect an integer only.
--- drivers/gpu/drm/nouveau/core/subdev/mxm/base.c | 48 +++----- drivers/gpu/drm/nouveau/nouveau_acpi.c | 139 +++++++----------------- 2 files changed, 54 insertions(+), 133 deletions(-)
drivers/gpu/drm/nouveau/core/subdev/mxm/base.c +16 -32
@@ -87,55 +87,39 @@ mxm_shadow_dsm(struct nouveau_mxm *mxm, u8 version)0xB8 ,0x9C ,0x79 ,0xB6 ,0x2F ,0xD5 ,0x56 ,0x65 };u32 mxms_args[] = {0x00000000 }; -union acpi_object args[4 ] = { -/* _DSM MUID */ - { .buffer.type =3 , - .buffer.length =sizeof (muid), - .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, - }, +union acpi_object argv4 = { + .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;acpi_handle handle; -int ret; +int rev; handle =ACPI_HANDLE (&device->pdev->dev);if (!handle)return false; - ret =acpi_evaluate_object (handle,"_DSM" , &list, &retn); -if (ret) { -nv_debug (mxm,"DSM MXMS failed: %d\n" , ret); +/* +* 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.. +*/ + 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; } - obj = retn.pointer;if (obj->type ==ACPI_TYPE_BUFFER ) { mxm->mxms =kmemdup (obj->buffer.pointer, obj->buffer.length,GFP_KERNEL ); - }else -if (obj->type ==ACPI_TYPE_INTEGER ) { + }else if (obj->type ==ACPI_TYPE_INTEGER ) {nv_debug (mxm,"DSM MXMS returned 0x%llx\n" , obj->integer.value); } -kfree (obj); +ACPI_FREE (obj);return mxm->mxms !=NULL ; }#endif
drivers/gpu/drm/nouveau/nouveau_acpi.c +38 -101
186 lines not on this page · raw message
Signature · 1 line
1.7.10.4
Rafael J. Wysocki
AppliedQuoted 42 lines · Jiang Liu
There are several drivers making use of ACPI
_DSMmethod to detect and invoke device specific methods. Currently every driver has implemented its private version to support ACPI_DSMmethod. So this patch introduces three helper functions to support ACPI_DSMmethod, which will be used to replace open-coded versions. It helps to simplify code and improve code readability.It also includes some bugfixes for TPM/nouveau drivers.
It applies to the mainstream kernel on top of
b0031f2 Merge tag 's2mps11-build' ofgit://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulatorDue to lacking of hardware platform, I have only tested the ACPI
_DSMhelper functions and TPM related changes, but haven't tested changes to other drivers yet. So appreciate help to review and test these patches.
V1->V2
1) fix an issue in initializingacpi_objectstructureJiang Liu (13):
ACPI: introduce helper interfaces to support ACPI_DSMmethod ACPI, extlog: replace open-coded_DSMspecific code with helper
functions
PCI, pci-label: release allocated ACPI object on error recovery path ACPI, PCI: replace open-coded_DSMspecific code with helper
functions
PCI, pci-label: treat PCI label with index 0 as valid label ACPI, TPM: fix memory leak when walking ACPI namespace ACPI, TPM: matching node name instead of full path when searching for
TPM device
ACPI, TPM: replace open-coded_DSMspecific code with helper
functions
ACPI, TPM: detecting PPI features by checking availability of_DSM
functions
ACPI, i2c-hid: replace open-coded_DSMspecific code with helper
functions
ACPI, i915: replace open-coded_DSMspecific code with helper
functions
nouveau: fix memory leak in ACPI_DSMrelated code
ACPI, nouveau: replace open-coded_DSMspecific code with helper
functions
Quoted 10 lines
drivers/acpi/acpi_extlog.c | 61 +--- drivers/acpi/utils.c | 98 ++++++ drivers/char/tpm/tpm_ppi.c | 406 +++++++++--------------- drivers/gpu/drm/i915/intel_acpi.c | 144 ++------- drivers/gpu/drm/nouveau/core/subdev/mxm/base.c | 48 +-- drivers/gpu/drm/nouveau/nouveau_acpi.c | 134 +++----- drivers/hid/i2c-hid/i2c-hid.c | 26 +- drivers/pci/pci-label.c | 129 +++----- include/acpi/acpi_bus.h | 26 ++ 9 files changed, 406 insertions(+), 666 deletions(-)
I've queued up the entire series for 3.14, thanks a lot!
Signature · 2 lines
I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center.
Thanks, Rafael!
Quoted 56 lines · Rafael J. Wysocki
Quoted 42 lines · Jiang Liu
There are several drivers making use of ACPI
_DSMmethod to detect and invoke device specific methods. Currently every driver has implemented its private version to support ACPI_DSMmethod. So this patch introduces three helper functions to support ACPI_DSMmethod, which will be used to replace open-coded versions. It helps to simplify code and improve code readability.It also includes some bugfixes for TPM/nouveau drivers.
It applies to the mainstream kernel on top of
b0031f2 Merge tag 's2mps11-build' ofgit://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulatorDue to lacking of hardware platform, I have only tested the ACPI
_DSMhelper functions and TPM related changes, but haven't tested changes to other drivers yet. So appreciate help to review and test these patches.
V1->V2
1) fix an issue in initializingacpi_objectstructureJiang Liu (13):
ACPI: introduce helper interfaces to support ACPI_DSMmethod ACPI, extlog: replace open-coded_DSMspecific code with helper
functions
PCI, pci-label: release allocated ACPI object on error recovery path ACPI, PCI: replace open-coded_DSMspecific code with helper
functions
PCI, pci-label: treat PCI label with index 0 as valid label ACPI, TPM: fix memory leak when walking ACPI namespace ACPI, TPM: matching node name instead of full path when searching for
TPM device
ACPI, TPM: replace open-coded_DSMspecific code with helper
functions
ACPI, TPM: detecting PPI features by checking availability of_DSM
functions
ACPI, i2c-hid: replace open-coded_DSMspecific code with helper
functions
ACPI, i915: replace open-coded_DSMspecific code with helper
functions
nouveau: fix memory leak in ACPI_DSMrelated code
ACPI, nouveau: replace open-coded_DSMspecific code with helper
functionsQuoted 10 lines
drivers/acpi/acpi_extlog.c | 61 +--- drivers/acpi/utils.c | 98 ++++++ drivers/char/tpm/tpm_ppi.c | 406 +++++++++--------------- drivers/gpu/drm/i915/intel_acpi.c | 144 ++------- drivers/gpu/drm/nouveau/core/subdev/mxm/base.c | 48 +-- drivers/gpu/drm/nouveau/nouveau_acpi.c | 134 +++----- drivers/hid/i2c-hid/i2c-hid.c | 26 +- drivers/pci/pci-label.c | 129 +++----- include/acpi/acpi_bus.h | 26 ++ 9 files changed, 406 insertions(+), 666 deletions(-)I've queued up the entire series for 3.14, thanks a lot!