10dc55365SJarkko Sakkinen /* 20dc55365SJarkko Sakkinen * Copyright (C) 2012-2014 Intel Corporation 30dc55365SJarkko Sakkinen * 40dc55365SJarkko Sakkinen * Authors: 50dc55365SJarkko Sakkinen * Xiaoyan Zhang <xiaoyan.zhang@intel.com> 60dc55365SJarkko Sakkinen * Jiang Liu <jiang.liu@linux.intel.com> 70dc55365SJarkko Sakkinen * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> 80dc55365SJarkko Sakkinen * 90dc55365SJarkko Sakkinen * Maintained by: <tpmdd-devel@lists.sourceforge.net> 100dc55365SJarkko Sakkinen * 110dc55365SJarkko Sakkinen * This file contains implementation of the sysfs interface for PPI. 120dc55365SJarkko Sakkinen * 130dc55365SJarkko Sakkinen * This program is free software; you can redistribute it and/or 140dc55365SJarkko Sakkinen * modify it under the terms of the GNU General Public License 150dc55365SJarkko Sakkinen * as published by the Free Software Foundation; version 2 160dc55365SJarkko Sakkinen * of the License. 170dc55365SJarkko Sakkinen */ 180dc55365SJarkko Sakkinen 190dc55365SJarkko Sakkinen 20f84fdff0SXiaoyan Zhang #include <linux/acpi.h> 21f84fdff0SXiaoyan Zhang #include "tpm.h" 22f84fdff0SXiaoyan Zhang 2309fe1b42SStefan Berger #define TPM_PPI_REVISION_ID_1 1 24f84fdff0SXiaoyan Zhang #define TPM_PPI_FN_VERSION 1 25f84fdff0SXiaoyan Zhang #define TPM_PPI_FN_SUBREQ 2 26f84fdff0SXiaoyan Zhang #define TPM_PPI_FN_GETREQ 3 27f84fdff0SXiaoyan Zhang #define TPM_PPI_FN_GETACT 4 28f84fdff0SXiaoyan Zhang #define TPM_PPI_FN_GETRSP 5 29f84fdff0SXiaoyan Zhang #define TPM_PPI_FN_SUBREQ2 7 30f84fdff0SXiaoyan Zhang #define TPM_PPI_FN_GETOPR 8 31*9d4023edSStefan Berger #define PPI_TPM_REQ_MAX 101 /* PPI 1.3 for TPM 2 */ 32f84fdff0SXiaoyan Zhang #define PPI_VS_REQ_START 128 33f84fdff0SXiaoyan Zhang #define PPI_VS_REQ_END 255 34f84fdff0SXiaoyan Zhang 3594116f81SAndy Shevchenko static const guid_t tpm_ppi_guid = 3694116f81SAndy Shevchenko GUID_INIT(0x3DDDFAA6, 0x361B, 0x4EB4, 3794116f81SAndy Shevchenko 0xA4, 0x24, 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53); 3884b1667dSJiang Liu 3984b1667dSJiang Liu static inline union acpi_object * 400dc55365SJarkko Sakkinen tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type, 41587bad77SStefan Berger union acpi_object *argv4, u64 rev) 42f84fdff0SXiaoyan Zhang { 430dc55365SJarkko Sakkinen BUG_ON(!ppi_handle); 4494116f81SAndy Shevchenko return acpi_evaluate_dsm_typed(ppi_handle, &tpm_ppi_guid, 45587bad77SStefan Berger rev, func, argv4, type); 46f84fdff0SXiaoyan Zhang } 47f84fdff0SXiaoyan Zhang 4881198078SXiaoyan Zhang static ssize_t tpm_show_ppi_version(struct device *dev, 4981198078SXiaoyan Zhang struct device_attribute *attr, char *buf) 50f84fdff0SXiaoyan Zhang { 519b774d5cSJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 520dc55365SJarkko Sakkinen 530dc55365SJarkko Sakkinen return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version); 54f84fdff0SXiaoyan Zhang } 55f84fdff0SXiaoyan Zhang 5681198078SXiaoyan Zhang static ssize_t tpm_show_ppi_request(struct device *dev, 5781198078SXiaoyan Zhang struct device_attribute *attr, char *buf) 58f84fdff0SXiaoyan Zhang { 5984b1667dSJiang Liu ssize_t size = -EINVAL; 6084b1667dSJiang Liu union acpi_object *obj; 619b774d5cSJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 62f84fdff0SXiaoyan Zhang 630dc55365SJarkko Sakkinen obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ, 6409fe1b42SStefan Berger ACPI_TYPE_PACKAGE, NULL, TPM_PPI_REVISION_ID_1); 6584b1667dSJiang Liu if (!obj) 66f84fdff0SXiaoyan Zhang return -ENXIO; 67f84fdff0SXiaoyan Zhang 68f84fdff0SXiaoyan Zhang /* 69f84fdff0SXiaoyan Zhang * output.pointer should be of package type, including two integers. 70f84fdff0SXiaoyan Zhang * The first is function return code, 0 means success and 1 means 71f84fdff0SXiaoyan Zhang * error. The second is pending TPM operation requested by the OS, 0 72f84fdff0SXiaoyan Zhang * means none and >0 means operation value. 73f84fdff0SXiaoyan Zhang */ 7484b1667dSJiang Liu if (obj->package.count == 2 && 7584b1667dSJiang Liu obj->package.elements[0].type == ACPI_TYPE_INTEGER && 7684b1667dSJiang Liu obj->package.elements[1].type == ACPI_TYPE_INTEGER) { 7784b1667dSJiang Liu if (obj->package.elements[0].integer.value) 7884b1667dSJiang Liu size = -EFAULT; 79f84fdff0SXiaoyan Zhang else 8084b1667dSJiang Liu size = scnprintf(buf, PAGE_SIZE, "%llu\n", 8184b1667dSJiang Liu obj->package.elements[1].integer.value); 82f84fdff0SXiaoyan Zhang } 8384b1667dSJiang Liu 8484b1667dSJiang Liu ACPI_FREE(obj); 8584b1667dSJiang Liu 8684b1667dSJiang Liu return size; 87f84fdff0SXiaoyan Zhang } 88f84fdff0SXiaoyan Zhang 8981198078SXiaoyan Zhang static ssize_t tpm_store_ppi_request(struct device *dev, 90f84fdff0SXiaoyan Zhang struct device_attribute *attr, 91f84fdff0SXiaoyan Zhang const char *buf, size_t count) 92f84fdff0SXiaoyan Zhang { 93f84fdff0SXiaoyan Zhang u32 req; 94f84fdff0SXiaoyan Zhang u64 ret; 9584b1667dSJiang Liu int func = TPM_PPI_FN_SUBREQ; 9684b1667dSJiang Liu union acpi_object *obj, tmp; 9784b1667dSJiang Liu union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp); 989b774d5cSJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 99f84fdff0SXiaoyan Zhang 100f84fdff0SXiaoyan Zhang /* 101f84fdff0SXiaoyan Zhang * the function to submit TPM operation request to pre-os environment 102f84fdff0SXiaoyan Zhang * is updated with function index from SUBREQ to SUBREQ2 since PPI 103f84fdff0SXiaoyan Zhang * version 1.1 104f84fdff0SXiaoyan Zhang */ 10594116f81SAndy Shevchenko if (acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid, 10609fe1b42SStefan Berger TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_SUBREQ2)) 10784b1667dSJiang Liu func = TPM_PPI_FN_SUBREQ2; 10884b1667dSJiang Liu 109f84fdff0SXiaoyan Zhang /* 110f84fdff0SXiaoyan Zhang * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS 111f84fdff0SXiaoyan Zhang * accept buffer/string/integer type, but some BIOS accept buffer/ 112f84fdff0SXiaoyan Zhang * string/package type. For PPI version 1.0 and 1.1, use buffer type 113f84fdff0SXiaoyan Zhang * for compatibility, and use package type since 1.2 according to spec. 114f84fdff0SXiaoyan Zhang */ 1150dc55365SJarkko Sakkinen if (strcmp(chip->ppi_version, "1.2") < 0) { 11684b1667dSJiang Liu if (sscanf(buf, "%d", &req) != 1) 11784b1667dSJiang Liu return -EINVAL; 11884b1667dSJiang Liu argv4.type = ACPI_TYPE_BUFFER; 11984b1667dSJiang Liu argv4.buffer.length = sizeof(req); 12084b1667dSJiang Liu argv4.buffer.pointer = (u8 *)&req; 121f84fdff0SXiaoyan Zhang } else { 12284b1667dSJiang Liu tmp.type = ACPI_TYPE_INTEGER; 12384b1667dSJiang Liu if (sscanf(buf, "%llu", &tmp.integer.value) != 1) 12484b1667dSJiang Liu return -EINVAL; 125f84fdff0SXiaoyan Zhang } 126f84fdff0SXiaoyan Zhang 1270dc55365SJarkko Sakkinen obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER, 12809fe1b42SStefan Berger &argv4, TPM_PPI_REVISION_ID_1); 12984b1667dSJiang Liu if (!obj) { 13084b1667dSJiang Liu return -ENXIO; 13184b1667dSJiang Liu } else { 13284b1667dSJiang Liu ret = obj->integer.value; 13384b1667dSJiang Liu ACPI_FREE(obj); 13484b1667dSJiang Liu } 13584b1667dSJiang Liu 136f84fdff0SXiaoyan Zhang if (ret == 0) 13784b1667dSJiang Liu return (acpi_status)count; 13884b1667dSJiang Liu 13984b1667dSJiang Liu return (ret == 1) ? -EPERM : -EFAULT; 140f84fdff0SXiaoyan Zhang } 141f84fdff0SXiaoyan Zhang 14281198078SXiaoyan Zhang static ssize_t tpm_show_ppi_transition_action(struct device *dev, 143f84fdff0SXiaoyan Zhang struct device_attribute *attr, 144f84fdff0SXiaoyan Zhang char *buf) 145f84fdff0SXiaoyan Zhang { 146f84fdff0SXiaoyan Zhang u32 ret; 14784b1667dSJiang Liu acpi_status status; 14884b1667dSJiang Liu union acpi_object *obj = NULL; 14984b1667dSJiang Liu union acpi_object tmp = { 15084b1667dSJiang Liu .buffer.type = ACPI_TYPE_BUFFER, 15184b1667dSJiang Liu .buffer.length = 0, 15284b1667dSJiang Liu .buffer.pointer = NULL 15384b1667dSJiang Liu }; 1549b774d5cSJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 15584b1667dSJiang Liu 15684b1667dSJiang Liu static char *info[] = { 157f84fdff0SXiaoyan Zhang "None", 158f84fdff0SXiaoyan Zhang "Shutdown", 159f84fdff0SXiaoyan Zhang "Reboot", 160f84fdff0SXiaoyan Zhang "OS Vendor-specific", 161f84fdff0SXiaoyan Zhang "Error", 162f84fdff0SXiaoyan Zhang }; 163f84fdff0SXiaoyan Zhang 164f84fdff0SXiaoyan Zhang /* 165f84fdff0SXiaoyan Zhang * PPI spec defines params[3].type as empty package, but some platforms 166f84fdff0SXiaoyan Zhang * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for 167f84fdff0SXiaoyan Zhang * compatibility, define params[3].type as buffer, if PPI version < 1.2 168f84fdff0SXiaoyan Zhang */ 1690dc55365SJarkko Sakkinen if (strcmp(chip->ppi_version, "1.2") < 0) 17084b1667dSJiang Liu obj = &tmp; 1710dc55365SJarkko Sakkinen obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT, 17209fe1b42SStefan Berger ACPI_TYPE_INTEGER, obj, TPM_PPI_REVISION_ID_1); 17384b1667dSJiang Liu if (!obj) { 17484b1667dSJiang Liu return -ENXIO; 17584b1667dSJiang Liu } else { 17684b1667dSJiang Liu ret = obj->integer.value; 17784b1667dSJiang Liu ACPI_FREE(obj); 178f84fdff0SXiaoyan Zhang } 17984b1667dSJiang Liu 180f84fdff0SXiaoyan Zhang if (ret < ARRAY_SIZE(info) - 1) 181f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); 182f84fdff0SXiaoyan Zhang else 183f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, 184f84fdff0SXiaoyan Zhang info[ARRAY_SIZE(info)-1]); 185f84fdff0SXiaoyan Zhang return status; 186f84fdff0SXiaoyan Zhang } 187f84fdff0SXiaoyan Zhang 18881198078SXiaoyan Zhang static ssize_t tpm_show_ppi_response(struct device *dev, 189f84fdff0SXiaoyan Zhang struct device_attribute *attr, 190f84fdff0SXiaoyan Zhang char *buf) 191f84fdff0SXiaoyan Zhang { 19284b1667dSJiang Liu acpi_status status = -EINVAL; 19384b1667dSJiang Liu union acpi_object *obj, *ret_obj; 19484b1667dSJiang Liu u64 req, res; 1959b774d5cSJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 196f84fdff0SXiaoyan Zhang 1970dc55365SJarkko Sakkinen obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP, 19809fe1b42SStefan Berger ACPI_TYPE_PACKAGE, NULL, TPM_PPI_REVISION_ID_1); 19984b1667dSJiang Liu if (!obj) 200f84fdff0SXiaoyan Zhang return -ENXIO; 201f84fdff0SXiaoyan Zhang 202f84fdff0SXiaoyan Zhang /* 203f84fdff0SXiaoyan Zhang * parameter output.pointer should be of package type, including 204f84fdff0SXiaoyan Zhang * 3 integers. The first means function return code, the second means 205f84fdff0SXiaoyan Zhang * most recent TPM operation request, and the last means response to 206f84fdff0SXiaoyan Zhang * the most recent TPM operation request. Only if the first is 0, and 207f84fdff0SXiaoyan Zhang * the second integer is not 0, the response makes sense. 208f84fdff0SXiaoyan Zhang */ 20984b1667dSJiang Liu ret_obj = obj->package.elements; 21084b1667dSJiang Liu if (obj->package.count < 3 || 21184b1667dSJiang Liu ret_obj[0].type != ACPI_TYPE_INTEGER || 21284b1667dSJiang Liu ret_obj[1].type != ACPI_TYPE_INTEGER || 21384b1667dSJiang Liu ret_obj[2].type != ACPI_TYPE_INTEGER) 214f84fdff0SXiaoyan Zhang goto cleanup; 21584b1667dSJiang Liu 21684b1667dSJiang Liu if (ret_obj[0].integer.value) { 217f84fdff0SXiaoyan Zhang status = -EFAULT; 218f84fdff0SXiaoyan Zhang goto cleanup; 219f84fdff0SXiaoyan Zhang } 22084b1667dSJiang Liu 22184b1667dSJiang Liu req = ret_obj[1].integer.value; 22284b1667dSJiang Liu res = ret_obj[2].integer.value; 22384b1667dSJiang Liu if (req) { 22484b1667dSJiang Liu if (res == 0) 225f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 226f84fdff0SXiaoyan Zhang "0: Success"); 22784b1667dSJiang Liu else if (res == 0xFFFFFFF0) 228f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 229f84fdff0SXiaoyan Zhang "0xFFFFFFF0: User Abort"); 23084b1667dSJiang Liu else if (res == 0xFFFFFFF1) 231f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 232f84fdff0SXiaoyan Zhang "0xFFFFFFF1: BIOS Failure"); 23384b1667dSJiang Liu else if (res >= 1 && res <= 0x00000FFF) 234f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 23584b1667dSJiang Liu req, res, "Corresponding TPM error"); 236f84fdff0SXiaoyan Zhang else 237f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 23884b1667dSJiang Liu req, res, "Error"); 239f84fdff0SXiaoyan Zhang } else { 240f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", 24184b1667dSJiang Liu req, "No Recent Request"); 242f84fdff0SXiaoyan Zhang } 24384b1667dSJiang Liu 244f84fdff0SXiaoyan Zhang cleanup: 24584b1667dSJiang Liu ACPI_FREE(obj); 246f84fdff0SXiaoyan Zhang return status; 247f84fdff0SXiaoyan Zhang } 248f84fdff0SXiaoyan Zhang 2490dc55365SJarkko Sakkinen static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start, 2500dc55365SJarkko Sakkinen u32 end) 251f84fdff0SXiaoyan Zhang { 252f84fdff0SXiaoyan Zhang int i; 253f84fdff0SXiaoyan Zhang u32 ret; 25484b1667dSJiang Liu char *str = buf; 25584b1667dSJiang Liu union acpi_object *obj, tmp; 25684b1667dSJiang Liu union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp); 25784b1667dSJiang Liu 25884b1667dSJiang Liu static char *info[] = { 259f84fdff0SXiaoyan Zhang "Not implemented", 260f84fdff0SXiaoyan Zhang "BIOS only", 261f84fdff0SXiaoyan Zhang "Blocked for OS by BIOS", 262f84fdff0SXiaoyan Zhang "User required", 263f84fdff0SXiaoyan Zhang "User not required", 264f84fdff0SXiaoyan Zhang }; 265f84fdff0SXiaoyan Zhang 26609fe1b42SStefan Berger if (!acpi_check_dsm(dev_handle, &tpm_ppi_guid, TPM_PPI_REVISION_ID_1, 2671569a4c4SJiang Liu 1 << TPM_PPI_FN_GETOPR)) 268f84fdff0SXiaoyan Zhang return -EPERM; 269f84fdff0SXiaoyan Zhang 27084b1667dSJiang Liu tmp.integer.type = ACPI_TYPE_INTEGER; 271f84fdff0SXiaoyan Zhang for (i = start; i <= end; i++) { 27284b1667dSJiang Liu tmp.integer.value = i; 2730dc55365SJarkko Sakkinen obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR, 274587bad77SStefan Berger ACPI_TYPE_INTEGER, &argv, 27509fe1b42SStefan Berger TPM_PPI_REVISION_ID_1); 27684b1667dSJiang Liu if (!obj) { 277f84fdff0SXiaoyan Zhang return -ENOMEM; 27884b1667dSJiang Liu } else { 27984b1667dSJiang Liu ret = obj->integer.value; 28084b1667dSJiang Liu ACPI_FREE(obj); 28184b1667dSJiang Liu } 282f84fdff0SXiaoyan Zhang 283f84fdff0SXiaoyan Zhang if (ret > 0 && ret < ARRAY_SIZE(info)) 284f84fdff0SXiaoyan Zhang str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", 285f84fdff0SXiaoyan Zhang i, ret, info[ret]); 286f84fdff0SXiaoyan Zhang } 28784b1667dSJiang Liu 288f84fdff0SXiaoyan Zhang return str - buf; 289f84fdff0SXiaoyan Zhang } 290f84fdff0SXiaoyan Zhang 29181198078SXiaoyan Zhang static ssize_t tpm_show_ppi_tcg_operations(struct device *dev, 29281198078SXiaoyan Zhang struct device_attribute *attr, 29381198078SXiaoyan Zhang char *buf) 294f84fdff0SXiaoyan Zhang { 2959b774d5cSJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 2960dc55365SJarkko Sakkinen 2970dc55365SJarkko Sakkinen return show_ppi_operations(chip->acpi_dev_handle, buf, 0, 2980dc55365SJarkko Sakkinen PPI_TPM_REQ_MAX); 299f84fdff0SXiaoyan Zhang } 300f84fdff0SXiaoyan Zhang 30181198078SXiaoyan Zhang static ssize_t tpm_show_ppi_vs_operations(struct device *dev, 30281198078SXiaoyan Zhang struct device_attribute *attr, 30381198078SXiaoyan Zhang char *buf) 304f84fdff0SXiaoyan Zhang { 3059b774d5cSJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 3060dc55365SJarkko Sakkinen 3070dc55365SJarkko Sakkinen return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START, 3080dc55365SJarkko Sakkinen PPI_VS_REQ_END); 309f84fdff0SXiaoyan Zhang } 310f84fdff0SXiaoyan Zhang 311f84fdff0SXiaoyan Zhang static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL); 312f84fdff0SXiaoyan Zhang static DEVICE_ATTR(request, S_IRUGO | S_IWUSR | S_IWGRP, 313f84fdff0SXiaoyan Zhang tpm_show_ppi_request, tpm_store_ppi_request); 314f84fdff0SXiaoyan Zhang static DEVICE_ATTR(transition_action, S_IRUGO, 315f84fdff0SXiaoyan Zhang tpm_show_ppi_transition_action, NULL); 316f84fdff0SXiaoyan Zhang static DEVICE_ATTR(response, S_IRUGO, tpm_show_ppi_response, NULL); 317f84fdff0SXiaoyan Zhang static DEVICE_ATTR(tcg_operations, S_IRUGO, tpm_show_ppi_tcg_operations, NULL); 318f84fdff0SXiaoyan Zhang static DEVICE_ATTR(vs_operations, S_IRUGO, tpm_show_ppi_vs_operations, NULL); 319f84fdff0SXiaoyan Zhang 320f84fdff0SXiaoyan Zhang static struct attribute *ppi_attrs[] = { 321f84fdff0SXiaoyan Zhang &dev_attr_version.attr, 322f84fdff0SXiaoyan Zhang &dev_attr_request.attr, 323f84fdff0SXiaoyan Zhang &dev_attr_transition_action.attr, 324f84fdff0SXiaoyan Zhang &dev_attr_response.attr, 325f84fdff0SXiaoyan Zhang &dev_attr_tcg_operations.attr, 326f84fdff0SXiaoyan Zhang &dev_attr_vs_operations.attr, NULL, 327f84fdff0SXiaoyan Zhang }; 328f84fdff0SXiaoyan Zhang static struct attribute_group ppi_attr_grp = { 3291631cfb7SGang Wei .name = "ppi", 330f84fdff0SXiaoyan Zhang .attrs = ppi_attrs 331f84fdff0SXiaoyan Zhang }; 332f84fdff0SXiaoyan Zhang 3339b774d5cSJarkko Sakkinen void tpm_add_ppi(struct tpm_chip *chip) 334f84fdff0SXiaoyan Zhang { 3350dc55365SJarkko Sakkinen union acpi_object *obj; 3360dc55365SJarkko Sakkinen 3370dc55365SJarkko Sakkinen if (!chip->acpi_dev_handle) 3389b774d5cSJarkko Sakkinen return; 3390dc55365SJarkko Sakkinen 34094116f81SAndy Shevchenko if (!acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid, 34109fe1b42SStefan Berger TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_VERSION)) 3429b774d5cSJarkko Sakkinen return; 3430dc55365SJarkko Sakkinen 3440dc55365SJarkko Sakkinen /* Cache PPI version string. */ 34594116f81SAndy Shevchenko obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, &tpm_ppi_guid, 34609fe1b42SStefan Berger TPM_PPI_REVISION_ID_1, 34709fe1b42SStefan Berger TPM_PPI_FN_VERSION, 3480dc55365SJarkko Sakkinen NULL, ACPI_TYPE_STRING); 3490dc55365SJarkko Sakkinen if (obj) { 3500dc55365SJarkko Sakkinen strlcpy(chip->ppi_version, obj->string.pointer, 3510dc55365SJarkko Sakkinen sizeof(chip->ppi_version)); 3520dc55365SJarkko Sakkinen ACPI_FREE(obj); 353f84fdff0SXiaoyan Zhang } 3541631cfb7SGang Wei 3559b774d5cSJarkko Sakkinen chip->groups[chip->groups_cnt++] = &ppi_attr_grp; 3561631cfb7SGang Wei } 357