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 23f84fdff0SXiaoyan Zhang #define TPM_PPI_REVISION_ID 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 31f84fdff0SXiaoyan Zhang #define PPI_TPM_REQ_MAX 22 32f84fdff0SXiaoyan Zhang #define PPI_VS_REQ_START 128 33f84fdff0SXiaoyan Zhang #define PPI_VS_REQ_END 255 34f84fdff0SXiaoyan Zhang 35*94116f81SAndy Shevchenko static const guid_t tpm_ppi_guid = 36*94116f81SAndy Shevchenko GUID_INIT(0x3DDDFAA6, 0x361B, 0x4EB4, 37*94116f81SAndy 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, 410dc55365SJarkko Sakkinen union acpi_object *argv4) 42f84fdff0SXiaoyan Zhang { 430dc55365SJarkko Sakkinen BUG_ON(!ppi_handle); 44*94116f81SAndy Shevchenko return acpi_evaluate_dsm_typed(ppi_handle, &tpm_ppi_guid, 450dc55365SJarkko Sakkinen TPM_PPI_REVISION_ID, 460dc55365SJarkko Sakkinen func, argv4, type); 47f84fdff0SXiaoyan Zhang } 48f84fdff0SXiaoyan Zhang 4981198078SXiaoyan Zhang static ssize_t tpm_show_ppi_version(struct device *dev, 5081198078SXiaoyan Zhang struct device_attribute *attr, char *buf) 51f84fdff0SXiaoyan Zhang { 529b774d5cSJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 530dc55365SJarkko Sakkinen 540dc55365SJarkko Sakkinen return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version); 55f84fdff0SXiaoyan Zhang } 56f84fdff0SXiaoyan Zhang 5781198078SXiaoyan Zhang static ssize_t tpm_show_ppi_request(struct device *dev, 5881198078SXiaoyan Zhang struct device_attribute *attr, char *buf) 59f84fdff0SXiaoyan Zhang { 6084b1667dSJiang Liu ssize_t size = -EINVAL; 6184b1667dSJiang Liu union acpi_object *obj; 629b774d5cSJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 63f84fdff0SXiaoyan Zhang 640dc55365SJarkko Sakkinen obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ, 650dc55365SJarkko Sakkinen ACPI_TYPE_PACKAGE, NULL); 6684b1667dSJiang Liu if (!obj) 67f84fdff0SXiaoyan Zhang return -ENXIO; 68f84fdff0SXiaoyan Zhang 69f84fdff0SXiaoyan Zhang /* 70f84fdff0SXiaoyan Zhang * output.pointer should be of package type, including two integers. 71f84fdff0SXiaoyan Zhang * The first is function return code, 0 means success and 1 means 72f84fdff0SXiaoyan Zhang * error. The second is pending TPM operation requested by the OS, 0 73f84fdff0SXiaoyan Zhang * means none and >0 means operation value. 74f84fdff0SXiaoyan Zhang */ 7584b1667dSJiang Liu if (obj->package.count == 2 && 7684b1667dSJiang Liu obj->package.elements[0].type == ACPI_TYPE_INTEGER && 7784b1667dSJiang Liu obj->package.elements[1].type == ACPI_TYPE_INTEGER) { 7884b1667dSJiang Liu if (obj->package.elements[0].integer.value) 7984b1667dSJiang Liu size = -EFAULT; 80f84fdff0SXiaoyan Zhang else 8184b1667dSJiang Liu size = scnprintf(buf, PAGE_SIZE, "%llu\n", 8284b1667dSJiang Liu obj->package.elements[1].integer.value); 83f84fdff0SXiaoyan Zhang } 8484b1667dSJiang Liu 8584b1667dSJiang Liu ACPI_FREE(obj); 8684b1667dSJiang Liu 8784b1667dSJiang Liu return size; 88f84fdff0SXiaoyan Zhang } 89f84fdff0SXiaoyan Zhang 9081198078SXiaoyan Zhang static ssize_t tpm_store_ppi_request(struct device *dev, 91f84fdff0SXiaoyan Zhang struct device_attribute *attr, 92f84fdff0SXiaoyan Zhang const char *buf, size_t count) 93f84fdff0SXiaoyan Zhang { 94f84fdff0SXiaoyan Zhang u32 req; 95f84fdff0SXiaoyan Zhang u64 ret; 9684b1667dSJiang Liu int func = TPM_PPI_FN_SUBREQ; 9784b1667dSJiang Liu union acpi_object *obj, tmp; 9884b1667dSJiang Liu union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp); 999b774d5cSJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 100f84fdff0SXiaoyan Zhang 101f84fdff0SXiaoyan Zhang /* 102f84fdff0SXiaoyan Zhang * the function to submit TPM operation request to pre-os environment 103f84fdff0SXiaoyan Zhang * is updated with function index from SUBREQ to SUBREQ2 since PPI 104f84fdff0SXiaoyan Zhang * version 1.1 105f84fdff0SXiaoyan Zhang */ 106*94116f81SAndy Shevchenko if (acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid, 1070dc55365SJarkko Sakkinen TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2)) 10884b1667dSJiang Liu func = TPM_PPI_FN_SUBREQ2; 10984b1667dSJiang Liu 110f84fdff0SXiaoyan Zhang /* 111f84fdff0SXiaoyan Zhang * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS 112f84fdff0SXiaoyan Zhang * accept buffer/string/integer type, but some BIOS accept buffer/ 113f84fdff0SXiaoyan Zhang * string/package type. For PPI version 1.0 and 1.1, use buffer type 114f84fdff0SXiaoyan Zhang * for compatibility, and use package type since 1.2 according to spec. 115f84fdff0SXiaoyan Zhang */ 1160dc55365SJarkko Sakkinen if (strcmp(chip->ppi_version, "1.2") < 0) { 11784b1667dSJiang Liu if (sscanf(buf, "%d", &req) != 1) 11884b1667dSJiang Liu return -EINVAL; 11984b1667dSJiang Liu argv4.type = ACPI_TYPE_BUFFER; 12084b1667dSJiang Liu argv4.buffer.length = sizeof(req); 12184b1667dSJiang Liu argv4.buffer.pointer = (u8 *)&req; 122f84fdff0SXiaoyan Zhang } else { 12384b1667dSJiang Liu tmp.type = ACPI_TYPE_INTEGER; 12484b1667dSJiang Liu if (sscanf(buf, "%llu", &tmp.integer.value) != 1) 12584b1667dSJiang Liu return -EINVAL; 126f84fdff0SXiaoyan Zhang } 127f84fdff0SXiaoyan Zhang 1280dc55365SJarkko Sakkinen obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER, 1290dc55365SJarkko Sakkinen &argv4); 13084b1667dSJiang Liu if (!obj) { 13184b1667dSJiang Liu return -ENXIO; 13284b1667dSJiang Liu } else { 13384b1667dSJiang Liu ret = obj->integer.value; 13484b1667dSJiang Liu ACPI_FREE(obj); 13584b1667dSJiang Liu } 13684b1667dSJiang Liu 137f84fdff0SXiaoyan Zhang if (ret == 0) 13884b1667dSJiang Liu return (acpi_status)count; 13984b1667dSJiang Liu 14084b1667dSJiang Liu return (ret == 1) ? -EPERM : -EFAULT; 141f84fdff0SXiaoyan Zhang } 142f84fdff0SXiaoyan Zhang 14381198078SXiaoyan Zhang static ssize_t tpm_show_ppi_transition_action(struct device *dev, 144f84fdff0SXiaoyan Zhang struct device_attribute *attr, 145f84fdff0SXiaoyan Zhang char *buf) 146f84fdff0SXiaoyan Zhang { 147f84fdff0SXiaoyan Zhang u32 ret; 14884b1667dSJiang Liu acpi_status status; 14984b1667dSJiang Liu union acpi_object *obj = NULL; 15084b1667dSJiang Liu union acpi_object tmp = { 15184b1667dSJiang Liu .buffer.type = ACPI_TYPE_BUFFER, 15284b1667dSJiang Liu .buffer.length = 0, 15384b1667dSJiang Liu .buffer.pointer = NULL 15484b1667dSJiang Liu }; 1559b774d5cSJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 15684b1667dSJiang Liu 15784b1667dSJiang Liu static char *info[] = { 158f84fdff0SXiaoyan Zhang "None", 159f84fdff0SXiaoyan Zhang "Shutdown", 160f84fdff0SXiaoyan Zhang "Reboot", 161f84fdff0SXiaoyan Zhang "OS Vendor-specific", 162f84fdff0SXiaoyan Zhang "Error", 163f84fdff0SXiaoyan Zhang }; 164f84fdff0SXiaoyan Zhang 165f84fdff0SXiaoyan Zhang /* 166f84fdff0SXiaoyan Zhang * PPI spec defines params[3].type as empty package, but some platforms 167f84fdff0SXiaoyan Zhang * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for 168f84fdff0SXiaoyan Zhang * compatibility, define params[3].type as buffer, if PPI version < 1.2 169f84fdff0SXiaoyan Zhang */ 1700dc55365SJarkko Sakkinen if (strcmp(chip->ppi_version, "1.2") < 0) 17184b1667dSJiang Liu obj = &tmp; 1720dc55365SJarkko Sakkinen obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT, 1730dc55365SJarkko Sakkinen ACPI_TYPE_INTEGER, obj); 17484b1667dSJiang Liu if (!obj) { 17584b1667dSJiang Liu return -ENXIO; 17684b1667dSJiang Liu } else { 17784b1667dSJiang Liu ret = obj->integer.value; 17884b1667dSJiang Liu ACPI_FREE(obj); 179f84fdff0SXiaoyan Zhang } 18084b1667dSJiang Liu 181f84fdff0SXiaoyan Zhang if (ret < ARRAY_SIZE(info) - 1) 182f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); 183f84fdff0SXiaoyan Zhang else 184f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, 185f84fdff0SXiaoyan Zhang info[ARRAY_SIZE(info)-1]); 186f84fdff0SXiaoyan Zhang return status; 187f84fdff0SXiaoyan Zhang } 188f84fdff0SXiaoyan Zhang 18981198078SXiaoyan Zhang static ssize_t tpm_show_ppi_response(struct device *dev, 190f84fdff0SXiaoyan Zhang struct device_attribute *attr, 191f84fdff0SXiaoyan Zhang char *buf) 192f84fdff0SXiaoyan Zhang { 19384b1667dSJiang Liu acpi_status status = -EINVAL; 19484b1667dSJiang Liu union acpi_object *obj, *ret_obj; 19584b1667dSJiang Liu u64 req, res; 1969b774d5cSJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 197f84fdff0SXiaoyan Zhang 1980dc55365SJarkko Sakkinen obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP, 1990dc55365SJarkko Sakkinen ACPI_TYPE_PACKAGE, NULL); 20084b1667dSJiang Liu if (!obj) 201f84fdff0SXiaoyan Zhang return -ENXIO; 202f84fdff0SXiaoyan Zhang 203f84fdff0SXiaoyan Zhang /* 204f84fdff0SXiaoyan Zhang * parameter output.pointer should be of package type, including 205f84fdff0SXiaoyan Zhang * 3 integers. The first means function return code, the second means 206f84fdff0SXiaoyan Zhang * most recent TPM operation request, and the last means response to 207f84fdff0SXiaoyan Zhang * the most recent TPM operation request. Only if the first is 0, and 208f84fdff0SXiaoyan Zhang * the second integer is not 0, the response makes sense. 209f84fdff0SXiaoyan Zhang */ 21084b1667dSJiang Liu ret_obj = obj->package.elements; 21184b1667dSJiang Liu if (obj->package.count < 3 || 21284b1667dSJiang Liu ret_obj[0].type != ACPI_TYPE_INTEGER || 21384b1667dSJiang Liu ret_obj[1].type != ACPI_TYPE_INTEGER || 21484b1667dSJiang Liu ret_obj[2].type != ACPI_TYPE_INTEGER) 215f84fdff0SXiaoyan Zhang goto cleanup; 21684b1667dSJiang Liu 21784b1667dSJiang Liu if (ret_obj[0].integer.value) { 218f84fdff0SXiaoyan Zhang status = -EFAULT; 219f84fdff0SXiaoyan Zhang goto cleanup; 220f84fdff0SXiaoyan Zhang } 22184b1667dSJiang Liu 22284b1667dSJiang Liu req = ret_obj[1].integer.value; 22384b1667dSJiang Liu res = ret_obj[2].integer.value; 22484b1667dSJiang Liu if (req) { 22584b1667dSJiang Liu if (res == 0) 226f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 227f84fdff0SXiaoyan Zhang "0: Success"); 22884b1667dSJiang Liu else if (res == 0xFFFFFFF0) 229f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 230f84fdff0SXiaoyan Zhang "0xFFFFFFF0: User Abort"); 23184b1667dSJiang Liu else if (res == 0xFFFFFFF1) 232f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 233f84fdff0SXiaoyan Zhang "0xFFFFFFF1: BIOS Failure"); 23484b1667dSJiang Liu else if (res >= 1 && res <= 0x00000FFF) 235f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 23684b1667dSJiang Liu req, res, "Corresponding TPM error"); 237f84fdff0SXiaoyan Zhang else 238f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 23984b1667dSJiang Liu req, res, "Error"); 240f84fdff0SXiaoyan Zhang } else { 241f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", 24284b1667dSJiang Liu req, "No Recent Request"); 243f84fdff0SXiaoyan Zhang } 24484b1667dSJiang Liu 245f84fdff0SXiaoyan Zhang cleanup: 24684b1667dSJiang Liu ACPI_FREE(obj); 247f84fdff0SXiaoyan Zhang return status; 248f84fdff0SXiaoyan Zhang } 249f84fdff0SXiaoyan Zhang 2500dc55365SJarkko Sakkinen static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start, 2510dc55365SJarkko Sakkinen u32 end) 252f84fdff0SXiaoyan Zhang { 253f84fdff0SXiaoyan Zhang int i; 254f84fdff0SXiaoyan Zhang u32 ret; 25584b1667dSJiang Liu char *str = buf; 25684b1667dSJiang Liu union acpi_object *obj, tmp; 25784b1667dSJiang Liu union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp); 25884b1667dSJiang Liu 25984b1667dSJiang Liu static char *info[] = { 260f84fdff0SXiaoyan Zhang "Not implemented", 261f84fdff0SXiaoyan Zhang "BIOS only", 262f84fdff0SXiaoyan Zhang "Blocked for OS by BIOS", 263f84fdff0SXiaoyan Zhang "User required", 264f84fdff0SXiaoyan Zhang "User not required", 265f84fdff0SXiaoyan Zhang }; 266f84fdff0SXiaoyan Zhang 267*94116f81SAndy Shevchenko if (!acpi_check_dsm(dev_handle, &tpm_ppi_guid, TPM_PPI_REVISION_ID, 2681569a4c4SJiang Liu 1 << TPM_PPI_FN_GETOPR)) 269f84fdff0SXiaoyan Zhang return -EPERM; 270f84fdff0SXiaoyan Zhang 27184b1667dSJiang Liu tmp.integer.type = ACPI_TYPE_INTEGER; 272f84fdff0SXiaoyan Zhang for (i = start; i <= end; i++) { 27384b1667dSJiang Liu tmp.integer.value = i; 2740dc55365SJarkko Sakkinen obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR, 2750dc55365SJarkko Sakkinen ACPI_TYPE_INTEGER, &argv); 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 340*94116f81SAndy Shevchenko if (!acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid, 3410dc55365SJarkko Sakkinen TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION)) 3429b774d5cSJarkko Sakkinen return; 3430dc55365SJarkko Sakkinen 3440dc55365SJarkko Sakkinen /* Cache PPI version string. */ 345*94116f81SAndy Shevchenko obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, &tpm_ppi_guid, 3460dc55365SJarkko Sakkinen TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, 3470dc55365SJarkko Sakkinen NULL, ACPI_TYPE_STRING); 3480dc55365SJarkko Sakkinen if (obj) { 3490dc55365SJarkko Sakkinen strlcpy(chip->ppi_version, obj->string.pointer, 3500dc55365SJarkko Sakkinen sizeof(chip->ppi_version)); 3510dc55365SJarkko Sakkinen ACPI_FREE(obj); 352f84fdff0SXiaoyan Zhang } 3531631cfb7SGang Wei 3549b774d5cSJarkko Sakkinen chip->groups[chip->groups_cnt++] = &ppi_attr_grp; 3551631cfb7SGang Wei } 356