1*0dc55365SJarkko Sakkinen /* 2*0dc55365SJarkko Sakkinen * Copyright (C) 2012-2014 Intel Corporation 3*0dc55365SJarkko Sakkinen * 4*0dc55365SJarkko Sakkinen * Authors: 5*0dc55365SJarkko Sakkinen * Xiaoyan Zhang <xiaoyan.zhang@intel.com> 6*0dc55365SJarkko Sakkinen * Jiang Liu <jiang.liu@linux.intel.com> 7*0dc55365SJarkko Sakkinen * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> 8*0dc55365SJarkko Sakkinen * 9*0dc55365SJarkko Sakkinen * Maintained by: <tpmdd-devel@lists.sourceforge.net> 10*0dc55365SJarkko Sakkinen * 11*0dc55365SJarkko Sakkinen * This file contains implementation of the sysfs interface for PPI. 12*0dc55365SJarkko Sakkinen * 13*0dc55365SJarkko Sakkinen * This program is free software; you can redistribute it and/or 14*0dc55365SJarkko Sakkinen * modify it under the terms of the GNU General Public License 15*0dc55365SJarkko Sakkinen * as published by the Free Software Foundation; version 2 16*0dc55365SJarkko Sakkinen * of the License. 17*0dc55365SJarkko Sakkinen */ 18*0dc55365SJarkko Sakkinen 19*0dc55365SJarkko 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 3584b1667dSJiang Liu static const u8 tpm_ppi_uuid[] = { 3684b1667dSJiang Liu 0xA6, 0xFA, 0xDD, 0x3D, 3784b1667dSJiang Liu 0x1B, 0x36, 3884b1667dSJiang Liu 0xB4, 0x4E, 3984b1667dSJiang Liu 0xA4, 0x24, 4084b1667dSJiang Liu 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 4184b1667dSJiang Liu }; 4284b1667dSJiang Liu 4384b1667dSJiang Liu static inline union acpi_object * 44*0dc55365SJarkko Sakkinen tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type, 45*0dc55365SJarkko Sakkinen union acpi_object *argv4) 46f84fdff0SXiaoyan Zhang { 47*0dc55365SJarkko Sakkinen BUG_ON(!ppi_handle); 48*0dc55365SJarkko Sakkinen return acpi_evaluate_dsm_typed(ppi_handle, tpm_ppi_uuid, 49*0dc55365SJarkko Sakkinen TPM_PPI_REVISION_ID, 50*0dc55365SJarkko Sakkinen func, argv4, type); 51f84fdff0SXiaoyan Zhang } 52f84fdff0SXiaoyan Zhang 5381198078SXiaoyan Zhang static ssize_t tpm_show_ppi_version(struct device *dev, 5481198078SXiaoyan Zhang struct device_attribute *attr, char *buf) 55f84fdff0SXiaoyan Zhang { 56*0dc55365SJarkko Sakkinen struct tpm_chip *chip = dev_get_drvdata(dev); 57*0dc55365SJarkko Sakkinen 58*0dc55365SJarkko Sakkinen return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version); 59f84fdff0SXiaoyan Zhang } 60f84fdff0SXiaoyan Zhang 6181198078SXiaoyan Zhang static ssize_t tpm_show_ppi_request(struct device *dev, 6281198078SXiaoyan Zhang struct device_attribute *attr, char *buf) 63f84fdff0SXiaoyan Zhang { 6484b1667dSJiang Liu ssize_t size = -EINVAL; 6584b1667dSJiang Liu union acpi_object *obj; 66*0dc55365SJarkko Sakkinen struct tpm_chip *chip = dev_get_drvdata(dev); 67f84fdff0SXiaoyan Zhang 68*0dc55365SJarkko Sakkinen obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ, 69*0dc55365SJarkko Sakkinen ACPI_TYPE_PACKAGE, NULL); 7084b1667dSJiang Liu if (!obj) 71f84fdff0SXiaoyan Zhang return -ENXIO; 72f84fdff0SXiaoyan Zhang 73f84fdff0SXiaoyan Zhang /* 74f84fdff0SXiaoyan Zhang * output.pointer should be of package type, including two integers. 75f84fdff0SXiaoyan Zhang * The first is function return code, 0 means success and 1 means 76f84fdff0SXiaoyan Zhang * error. The second is pending TPM operation requested by the OS, 0 77f84fdff0SXiaoyan Zhang * means none and >0 means operation value. 78f84fdff0SXiaoyan Zhang */ 7984b1667dSJiang Liu if (obj->package.count == 2 && 8084b1667dSJiang Liu obj->package.elements[0].type == ACPI_TYPE_INTEGER && 8184b1667dSJiang Liu obj->package.elements[1].type == ACPI_TYPE_INTEGER) { 8284b1667dSJiang Liu if (obj->package.elements[0].integer.value) 8384b1667dSJiang Liu size = -EFAULT; 84f84fdff0SXiaoyan Zhang else 8584b1667dSJiang Liu size = scnprintf(buf, PAGE_SIZE, "%llu\n", 8684b1667dSJiang Liu obj->package.elements[1].integer.value); 87f84fdff0SXiaoyan Zhang } 8884b1667dSJiang Liu 8984b1667dSJiang Liu ACPI_FREE(obj); 9084b1667dSJiang Liu 9184b1667dSJiang Liu return size; 92f84fdff0SXiaoyan Zhang } 93f84fdff0SXiaoyan Zhang 9481198078SXiaoyan Zhang static ssize_t tpm_store_ppi_request(struct device *dev, 95f84fdff0SXiaoyan Zhang struct device_attribute *attr, 96f84fdff0SXiaoyan Zhang const char *buf, size_t count) 97f84fdff0SXiaoyan Zhang { 98f84fdff0SXiaoyan Zhang u32 req; 99f84fdff0SXiaoyan Zhang u64 ret; 10084b1667dSJiang Liu int func = TPM_PPI_FN_SUBREQ; 10184b1667dSJiang Liu union acpi_object *obj, tmp; 10284b1667dSJiang Liu union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp); 103*0dc55365SJarkko Sakkinen struct tpm_chip *chip = dev_get_drvdata(dev); 104f84fdff0SXiaoyan Zhang 105f84fdff0SXiaoyan Zhang /* 106f84fdff0SXiaoyan Zhang * the function to submit TPM operation request to pre-os environment 107f84fdff0SXiaoyan Zhang * is updated with function index from SUBREQ to SUBREQ2 since PPI 108f84fdff0SXiaoyan Zhang * version 1.1 109f84fdff0SXiaoyan Zhang */ 110*0dc55365SJarkko Sakkinen if (acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid, 111*0dc55365SJarkko Sakkinen TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2)) 11284b1667dSJiang Liu func = TPM_PPI_FN_SUBREQ2; 11384b1667dSJiang Liu 114f84fdff0SXiaoyan Zhang /* 115f84fdff0SXiaoyan Zhang * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS 116f84fdff0SXiaoyan Zhang * accept buffer/string/integer type, but some BIOS accept buffer/ 117f84fdff0SXiaoyan Zhang * string/package type. For PPI version 1.0 and 1.1, use buffer type 118f84fdff0SXiaoyan Zhang * for compatibility, and use package type since 1.2 according to spec. 119f84fdff0SXiaoyan Zhang */ 120*0dc55365SJarkko Sakkinen if (strcmp(chip->ppi_version, "1.2") < 0) { 12184b1667dSJiang Liu if (sscanf(buf, "%d", &req) != 1) 12284b1667dSJiang Liu return -EINVAL; 12384b1667dSJiang Liu argv4.type = ACPI_TYPE_BUFFER; 12484b1667dSJiang Liu argv4.buffer.length = sizeof(req); 12584b1667dSJiang Liu argv4.buffer.pointer = (u8 *)&req; 126f84fdff0SXiaoyan Zhang } else { 12784b1667dSJiang Liu tmp.type = ACPI_TYPE_INTEGER; 12884b1667dSJiang Liu if (sscanf(buf, "%llu", &tmp.integer.value) != 1) 12984b1667dSJiang Liu return -EINVAL; 130f84fdff0SXiaoyan Zhang } 131f84fdff0SXiaoyan Zhang 132*0dc55365SJarkko Sakkinen obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER, 133*0dc55365SJarkko Sakkinen &argv4); 13484b1667dSJiang Liu if (!obj) { 13584b1667dSJiang Liu return -ENXIO; 13684b1667dSJiang Liu } else { 13784b1667dSJiang Liu ret = obj->integer.value; 13884b1667dSJiang Liu ACPI_FREE(obj); 13984b1667dSJiang Liu } 14084b1667dSJiang Liu 141f84fdff0SXiaoyan Zhang if (ret == 0) 14284b1667dSJiang Liu return (acpi_status)count; 14384b1667dSJiang Liu 14484b1667dSJiang Liu return (ret == 1) ? -EPERM : -EFAULT; 145f84fdff0SXiaoyan Zhang } 146f84fdff0SXiaoyan Zhang 14781198078SXiaoyan Zhang static ssize_t tpm_show_ppi_transition_action(struct device *dev, 148f84fdff0SXiaoyan Zhang struct device_attribute *attr, 149f84fdff0SXiaoyan Zhang char *buf) 150f84fdff0SXiaoyan Zhang { 151f84fdff0SXiaoyan Zhang u32 ret; 15284b1667dSJiang Liu acpi_status status; 15384b1667dSJiang Liu union acpi_object *obj = NULL; 15484b1667dSJiang Liu union acpi_object tmp = { 15584b1667dSJiang Liu .buffer.type = ACPI_TYPE_BUFFER, 15684b1667dSJiang Liu .buffer.length = 0, 15784b1667dSJiang Liu .buffer.pointer = NULL 15884b1667dSJiang Liu }; 159*0dc55365SJarkko Sakkinen struct tpm_chip *chip = dev_get_drvdata(dev); 16084b1667dSJiang Liu 16184b1667dSJiang Liu static char *info[] = { 162f84fdff0SXiaoyan Zhang "None", 163f84fdff0SXiaoyan Zhang "Shutdown", 164f84fdff0SXiaoyan Zhang "Reboot", 165f84fdff0SXiaoyan Zhang "OS Vendor-specific", 166f84fdff0SXiaoyan Zhang "Error", 167f84fdff0SXiaoyan Zhang }; 168f84fdff0SXiaoyan Zhang 169f84fdff0SXiaoyan Zhang /* 170f84fdff0SXiaoyan Zhang * PPI spec defines params[3].type as empty package, but some platforms 171f84fdff0SXiaoyan Zhang * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for 172f84fdff0SXiaoyan Zhang * compatibility, define params[3].type as buffer, if PPI version < 1.2 173f84fdff0SXiaoyan Zhang */ 174*0dc55365SJarkko Sakkinen if (strcmp(chip->ppi_version, "1.2") < 0) 17584b1667dSJiang Liu obj = &tmp; 176*0dc55365SJarkko Sakkinen obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT, 177*0dc55365SJarkko Sakkinen ACPI_TYPE_INTEGER, obj); 17884b1667dSJiang Liu if (!obj) { 17984b1667dSJiang Liu return -ENXIO; 18084b1667dSJiang Liu } else { 18184b1667dSJiang Liu ret = obj->integer.value; 18284b1667dSJiang Liu ACPI_FREE(obj); 183f84fdff0SXiaoyan Zhang } 18484b1667dSJiang Liu 185f84fdff0SXiaoyan Zhang if (ret < ARRAY_SIZE(info) - 1) 186f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); 187f84fdff0SXiaoyan Zhang else 188f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, 189f84fdff0SXiaoyan Zhang info[ARRAY_SIZE(info)-1]); 190f84fdff0SXiaoyan Zhang return status; 191f84fdff0SXiaoyan Zhang } 192f84fdff0SXiaoyan Zhang 19381198078SXiaoyan Zhang static ssize_t tpm_show_ppi_response(struct device *dev, 194f84fdff0SXiaoyan Zhang struct device_attribute *attr, 195f84fdff0SXiaoyan Zhang char *buf) 196f84fdff0SXiaoyan Zhang { 19784b1667dSJiang Liu acpi_status status = -EINVAL; 19884b1667dSJiang Liu union acpi_object *obj, *ret_obj; 19984b1667dSJiang Liu u64 req, res; 200*0dc55365SJarkko Sakkinen struct tpm_chip *chip = dev_get_drvdata(dev); 201f84fdff0SXiaoyan Zhang 202*0dc55365SJarkko Sakkinen obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP, 203*0dc55365SJarkko Sakkinen ACPI_TYPE_PACKAGE, NULL); 20484b1667dSJiang Liu if (!obj) 205f84fdff0SXiaoyan Zhang return -ENXIO; 206f84fdff0SXiaoyan Zhang 207f84fdff0SXiaoyan Zhang /* 208f84fdff0SXiaoyan Zhang * parameter output.pointer should be of package type, including 209f84fdff0SXiaoyan Zhang * 3 integers. The first means function return code, the second means 210f84fdff0SXiaoyan Zhang * most recent TPM operation request, and the last means response to 211f84fdff0SXiaoyan Zhang * the most recent TPM operation request. Only if the first is 0, and 212f84fdff0SXiaoyan Zhang * the second integer is not 0, the response makes sense. 213f84fdff0SXiaoyan Zhang */ 21484b1667dSJiang Liu ret_obj = obj->package.elements; 21584b1667dSJiang Liu if (obj->package.count < 3 || 21684b1667dSJiang Liu ret_obj[0].type != ACPI_TYPE_INTEGER || 21784b1667dSJiang Liu ret_obj[1].type != ACPI_TYPE_INTEGER || 21884b1667dSJiang Liu ret_obj[2].type != ACPI_TYPE_INTEGER) 219f84fdff0SXiaoyan Zhang goto cleanup; 22084b1667dSJiang Liu 22184b1667dSJiang Liu if (ret_obj[0].integer.value) { 222f84fdff0SXiaoyan Zhang status = -EFAULT; 223f84fdff0SXiaoyan Zhang goto cleanup; 224f84fdff0SXiaoyan Zhang } 22584b1667dSJiang Liu 22684b1667dSJiang Liu req = ret_obj[1].integer.value; 22784b1667dSJiang Liu res = ret_obj[2].integer.value; 22884b1667dSJiang Liu if (req) { 22984b1667dSJiang Liu if (res == 0) 230f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 231f84fdff0SXiaoyan Zhang "0: Success"); 23284b1667dSJiang Liu else if (res == 0xFFFFFFF0) 233f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 234f84fdff0SXiaoyan Zhang "0xFFFFFFF0: User Abort"); 23584b1667dSJiang Liu else if (res == 0xFFFFFFF1) 236f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 237f84fdff0SXiaoyan Zhang "0xFFFFFFF1: BIOS Failure"); 23884b1667dSJiang Liu else if (res >= 1 && res <= 0x00000FFF) 239f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 24084b1667dSJiang Liu req, res, "Corresponding TPM error"); 241f84fdff0SXiaoyan Zhang else 242f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 24384b1667dSJiang Liu req, res, "Error"); 244f84fdff0SXiaoyan Zhang } else { 245f84fdff0SXiaoyan Zhang status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", 24684b1667dSJiang Liu req, "No Recent Request"); 247f84fdff0SXiaoyan Zhang } 24884b1667dSJiang Liu 249f84fdff0SXiaoyan Zhang cleanup: 25084b1667dSJiang Liu ACPI_FREE(obj); 251f84fdff0SXiaoyan Zhang return status; 252f84fdff0SXiaoyan Zhang } 253f84fdff0SXiaoyan Zhang 254*0dc55365SJarkko Sakkinen static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start, 255*0dc55365SJarkko Sakkinen u32 end) 256f84fdff0SXiaoyan Zhang { 257f84fdff0SXiaoyan Zhang int i; 258f84fdff0SXiaoyan Zhang u32 ret; 25984b1667dSJiang Liu char *str = buf; 26084b1667dSJiang Liu union acpi_object *obj, tmp; 26184b1667dSJiang Liu union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp); 26284b1667dSJiang Liu 26384b1667dSJiang Liu static char *info[] = { 264f84fdff0SXiaoyan Zhang "Not implemented", 265f84fdff0SXiaoyan Zhang "BIOS only", 266f84fdff0SXiaoyan Zhang "Blocked for OS by BIOS", 267f84fdff0SXiaoyan Zhang "User required", 268f84fdff0SXiaoyan Zhang "User not required", 269f84fdff0SXiaoyan Zhang }; 270f84fdff0SXiaoyan Zhang 271*0dc55365SJarkko Sakkinen if (!acpi_check_dsm(dev_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, 2721569a4c4SJiang Liu 1 << TPM_PPI_FN_GETOPR)) 273f84fdff0SXiaoyan Zhang return -EPERM; 274f84fdff0SXiaoyan Zhang 27584b1667dSJiang Liu tmp.integer.type = ACPI_TYPE_INTEGER; 276f84fdff0SXiaoyan Zhang for (i = start; i <= end; i++) { 27784b1667dSJiang Liu tmp.integer.value = i; 278*0dc55365SJarkko Sakkinen obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR, 279*0dc55365SJarkko Sakkinen ACPI_TYPE_INTEGER, &argv); 28084b1667dSJiang Liu if (!obj) { 281f84fdff0SXiaoyan Zhang return -ENOMEM; 28284b1667dSJiang Liu } else { 28384b1667dSJiang Liu ret = obj->integer.value; 28484b1667dSJiang Liu ACPI_FREE(obj); 28584b1667dSJiang Liu } 286f84fdff0SXiaoyan Zhang 287f84fdff0SXiaoyan Zhang if (ret > 0 && ret < ARRAY_SIZE(info)) 288f84fdff0SXiaoyan Zhang str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", 289f84fdff0SXiaoyan Zhang i, ret, info[ret]); 290f84fdff0SXiaoyan Zhang } 29184b1667dSJiang Liu 292f84fdff0SXiaoyan Zhang return str - buf; 293f84fdff0SXiaoyan Zhang } 294f84fdff0SXiaoyan Zhang 29581198078SXiaoyan Zhang static ssize_t tpm_show_ppi_tcg_operations(struct device *dev, 29681198078SXiaoyan Zhang struct device_attribute *attr, 29781198078SXiaoyan Zhang char *buf) 298f84fdff0SXiaoyan Zhang { 299*0dc55365SJarkko Sakkinen struct tpm_chip *chip = dev_get_drvdata(dev); 300*0dc55365SJarkko Sakkinen 301*0dc55365SJarkko Sakkinen return show_ppi_operations(chip->acpi_dev_handle, buf, 0, 302*0dc55365SJarkko Sakkinen PPI_TPM_REQ_MAX); 303f84fdff0SXiaoyan Zhang } 304f84fdff0SXiaoyan Zhang 30581198078SXiaoyan Zhang static ssize_t tpm_show_ppi_vs_operations(struct device *dev, 30681198078SXiaoyan Zhang struct device_attribute *attr, 30781198078SXiaoyan Zhang char *buf) 308f84fdff0SXiaoyan Zhang { 309*0dc55365SJarkko Sakkinen struct tpm_chip *chip = dev_get_drvdata(dev); 310*0dc55365SJarkko Sakkinen 311*0dc55365SJarkko Sakkinen return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START, 312*0dc55365SJarkko Sakkinen PPI_VS_REQ_END); 313f84fdff0SXiaoyan Zhang } 314f84fdff0SXiaoyan Zhang 315f84fdff0SXiaoyan Zhang static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL); 316f84fdff0SXiaoyan Zhang static DEVICE_ATTR(request, S_IRUGO | S_IWUSR | S_IWGRP, 317f84fdff0SXiaoyan Zhang tpm_show_ppi_request, tpm_store_ppi_request); 318f84fdff0SXiaoyan Zhang static DEVICE_ATTR(transition_action, S_IRUGO, 319f84fdff0SXiaoyan Zhang tpm_show_ppi_transition_action, NULL); 320f84fdff0SXiaoyan Zhang static DEVICE_ATTR(response, S_IRUGO, tpm_show_ppi_response, NULL); 321f84fdff0SXiaoyan Zhang static DEVICE_ATTR(tcg_operations, S_IRUGO, tpm_show_ppi_tcg_operations, NULL); 322f84fdff0SXiaoyan Zhang static DEVICE_ATTR(vs_operations, S_IRUGO, tpm_show_ppi_vs_operations, NULL); 323f84fdff0SXiaoyan Zhang 324f84fdff0SXiaoyan Zhang static struct attribute *ppi_attrs[] = { 325f84fdff0SXiaoyan Zhang &dev_attr_version.attr, 326f84fdff0SXiaoyan Zhang &dev_attr_request.attr, 327f84fdff0SXiaoyan Zhang &dev_attr_transition_action.attr, 328f84fdff0SXiaoyan Zhang &dev_attr_response.attr, 329f84fdff0SXiaoyan Zhang &dev_attr_tcg_operations.attr, 330f84fdff0SXiaoyan Zhang &dev_attr_vs_operations.attr, NULL, 331f84fdff0SXiaoyan Zhang }; 332f84fdff0SXiaoyan Zhang static struct attribute_group ppi_attr_grp = { 3331631cfb7SGang Wei .name = "ppi", 334f84fdff0SXiaoyan Zhang .attrs = ppi_attrs 335f84fdff0SXiaoyan Zhang }; 336f84fdff0SXiaoyan Zhang 337*0dc55365SJarkko Sakkinen int tpm_add_ppi(struct tpm_chip *chip) 338f84fdff0SXiaoyan Zhang { 339*0dc55365SJarkko Sakkinen union acpi_object *obj; 340*0dc55365SJarkko Sakkinen int rc; 341*0dc55365SJarkko Sakkinen 342*0dc55365SJarkko Sakkinen if (!chip->acpi_dev_handle) 343*0dc55365SJarkko Sakkinen return 0; 344*0dc55365SJarkko Sakkinen 345*0dc55365SJarkko Sakkinen if (!acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid, 346*0dc55365SJarkko Sakkinen TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION)) 347*0dc55365SJarkko Sakkinen return 0; 348*0dc55365SJarkko Sakkinen 349*0dc55365SJarkko Sakkinen /* Cache PPI version string. */ 350*0dc55365SJarkko Sakkinen obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, tpm_ppi_uuid, 351*0dc55365SJarkko Sakkinen TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, 352*0dc55365SJarkko Sakkinen NULL, ACPI_TYPE_STRING); 353*0dc55365SJarkko Sakkinen if (obj) { 354*0dc55365SJarkko Sakkinen strlcpy(chip->ppi_version, obj->string.pointer, 355*0dc55365SJarkko Sakkinen sizeof(chip->ppi_version)); 356*0dc55365SJarkko Sakkinen ACPI_FREE(obj); 357f84fdff0SXiaoyan Zhang } 3581631cfb7SGang Wei 359*0dc55365SJarkko Sakkinen rc = sysfs_create_group(&chip->dev->kobj, &ppi_attr_grp); 360*0dc55365SJarkko Sakkinen 361*0dc55365SJarkko Sakkinen if (!rc) 362*0dc55365SJarkko Sakkinen chip->flags |= TPM_CHIP_FLAG_PPI; 363*0dc55365SJarkko Sakkinen 364*0dc55365SJarkko Sakkinen return rc; 365*0dc55365SJarkko Sakkinen } 366*0dc55365SJarkko Sakkinen 367*0dc55365SJarkko Sakkinen void tpm_remove_ppi(struct tpm_chip *chip) 3681631cfb7SGang Wei { 369*0dc55365SJarkko Sakkinen if (chip->flags & TPM_CHIP_FLAG_PPI) 370*0dc55365SJarkko Sakkinen sysfs_remove_group(&chip->dev->kobj, &ppi_attr_grp); 3711631cfb7SGang Wei } 372