18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2012-2014 Intel Corporation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: 68c2ecf20Sopenharmony_ci * Xiaoyan Zhang <xiaoyan.zhang@intel.com> 78c2ecf20Sopenharmony_ci * Jiang Liu <jiang.liu@linux.intel.com> 88c2ecf20Sopenharmony_ci * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Maintained by: <tpmdd-devel@lists.sourceforge.net> 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This file contains implementation of the sysfs interface for PPI. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/acpi.h> 178c2ecf20Sopenharmony_ci#include "tpm.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define TPM_PPI_REVISION_ID_1 1 208c2ecf20Sopenharmony_ci#define TPM_PPI_REVISION_ID_2 2 218c2ecf20Sopenharmony_ci#define TPM_PPI_FN_VERSION 1 228c2ecf20Sopenharmony_ci#define TPM_PPI_FN_SUBREQ 2 238c2ecf20Sopenharmony_ci#define TPM_PPI_FN_GETREQ 3 248c2ecf20Sopenharmony_ci#define TPM_PPI_FN_GETACT 4 258c2ecf20Sopenharmony_ci#define TPM_PPI_FN_GETRSP 5 268c2ecf20Sopenharmony_ci#define TPM_PPI_FN_SUBREQ2 7 278c2ecf20Sopenharmony_ci#define TPM_PPI_FN_GETOPR 8 288c2ecf20Sopenharmony_ci#define PPI_TPM_REQ_MAX 101 /* PPI 1.3 for TPM 2 */ 298c2ecf20Sopenharmony_ci#define PPI_VS_REQ_START 128 308c2ecf20Sopenharmony_ci#define PPI_VS_REQ_END 255 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic const guid_t tpm_ppi_guid = 338c2ecf20Sopenharmony_ci GUID_INIT(0x3DDDFAA6, 0x361B, 0x4EB4, 348c2ecf20Sopenharmony_ci 0xA4, 0x24, 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic bool tpm_ppi_req_has_parameter(u64 req) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci return req == 23; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic inline union acpi_object * 428c2ecf20Sopenharmony_citpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type, 438c2ecf20Sopenharmony_ci union acpi_object *argv4, u64 rev) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci BUG_ON(!ppi_handle); 468c2ecf20Sopenharmony_ci return acpi_evaluate_dsm_typed(ppi_handle, &tpm_ppi_guid, 478c2ecf20Sopenharmony_ci rev, func, argv4, type); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic ssize_t tpm_show_ppi_version(struct device *dev, 518c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct tpm_chip *chip = to_tpm_chip(dev); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic ssize_t tpm_show_ppi_request(struct device *dev, 598c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci ssize_t size = -EINVAL; 628c2ecf20Sopenharmony_ci union acpi_object *obj; 638c2ecf20Sopenharmony_ci struct tpm_chip *chip = to_tpm_chip(dev); 648c2ecf20Sopenharmony_ci u64 rev = TPM_PPI_REVISION_ID_2; 658c2ecf20Sopenharmony_ci u64 req; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (strcmp(chip->ppi_version, "1.2") < 0) 688c2ecf20Sopenharmony_ci rev = TPM_PPI_REVISION_ID_1; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ, 718c2ecf20Sopenharmony_ci ACPI_TYPE_PACKAGE, NULL, rev); 728c2ecf20Sopenharmony_ci if (!obj) 738c2ecf20Sopenharmony_ci return -ENXIO; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* 768c2ecf20Sopenharmony_ci * output.pointer should be of package type, including two integers. 778c2ecf20Sopenharmony_ci * The first is function return code, 0 means success and 1 means 788c2ecf20Sopenharmony_ci * error. The second is pending TPM operation requested by the OS, 0 798c2ecf20Sopenharmony_ci * means none and >0 means operation value. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci if (obj->package.count == 3 && 828c2ecf20Sopenharmony_ci obj->package.elements[0].type == ACPI_TYPE_INTEGER && 838c2ecf20Sopenharmony_ci obj->package.elements[1].type == ACPI_TYPE_INTEGER && 848c2ecf20Sopenharmony_ci obj->package.elements[2].type == ACPI_TYPE_INTEGER) { 858c2ecf20Sopenharmony_ci if (obj->package.elements[0].integer.value) 868c2ecf20Sopenharmony_ci size = -EFAULT; 878c2ecf20Sopenharmony_ci else { 888c2ecf20Sopenharmony_ci req = obj->package.elements[1].integer.value; 898c2ecf20Sopenharmony_ci if (tpm_ppi_req_has_parameter(req)) 908c2ecf20Sopenharmony_ci size = scnprintf(buf, PAGE_SIZE, 918c2ecf20Sopenharmony_ci "%llu %llu\n", req, 928c2ecf20Sopenharmony_ci obj->package.elements[2].integer.value); 938c2ecf20Sopenharmony_ci else 948c2ecf20Sopenharmony_ci size = scnprintf(buf, PAGE_SIZE, 958c2ecf20Sopenharmony_ci "%llu\n", req); 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci } else if (obj->package.count == 2 && 988c2ecf20Sopenharmony_ci obj->package.elements[0].type == ACPI_TYPE_INTEGER && 998c2ecf20Sopenharmony_ci obj->package.elements[1].type == ACPI_TYPE_INTEGER) { 1008c2ecf20Sopenharmony_ci if (obj->package.elements[0].integer.value) 1018c2ecf20Sopenharmony_ci size = -EFAULT; 1028c2ecf20Sopenharmony_ci else 1038c2ecf20Sopenharmony_ci size = scnprintf(buf, PAGE_SIZE, "%llu\n", 1048c2ecf20Sopenharmony_ci obj->package.elements[1].integer.value); 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci ACPI_FREE(obj); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return size; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic ssize_t tpm_store_ppi_request(struct device *dev, 1138c2ecf20Sopenharmony_ci struct device_attribute *attr, 1148c2ecf20Sopenharmony_ci const char *buf, size_t count) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci u32 req; 1178c2ecf20Sopenharmony_ci u64 ret; 1188c2ecf20Sopenharmony_ci int func = TPM_PPI_FN_SUBREQ; 1198c2ecf20Sopenharmony_ci union acpi_object *obj, tmp[2]; 1208c2ecf20Sopenharmony_ci union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(2, tmp); 1218c2ecf20Sopenharmony_ci struct tpm_chip *chip = to_tpm_chip(dev); 1228c2ecf20Sopenharmony_ci u64 rev = TPM_PPI_REVISION_ID_1; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* 1258c2ecf20Sopenharmony_ci * the function to submit TPM operation request to pre-os environment 1268c2ecf20Sopenharmony_ci * is updated with function index from SUBREQ to SUBREQ2 since PPI 1278c2ecf20Sopenharmony_ci * version 1.1 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ci if (acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid, 1308c2ecf20Sopenharmony_ci TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_SUBREQ2)) 1318c2ecf20Sopenharmony_ci func = TPM_PPI_FN_SUBREQ2; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* 1348c2ecf20Sopenharmony_ci * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS 1358c2ecf20Sopenharmony_ci * accept buffer/string/integer type, but some BIOS accept buffer/ 1368c2ecf20Sopenharmony_ci * string/package type. For PPI version 1.0 and 1.1, use buffer type 1378c2ecf20Sopenharmony_ci * for compatibility, and use package type since 1.2 according to spec. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci if (strcmp(chip->ppi_version, "1.3") == 0) { 1408c2ecf20Sopenharmony_ci if (sscanf(buf, "%llu %llu", &tmp[0].integer.value, 1418c2ecf20Sopenharmony_ci &tmp[1].integer.value) != 2) 1428c2ecf20Sopenharmony_ci goto ppi12; 1438c2ecf20Sopenharmony_ci rev = TPM_PPI_REVISION_ID_2; 1448c2ecf20Sopenharmony_ci tmp[0].type = ACPI_TYPE_INTEGER; 1458c2ecf20Sopenharmony_ci tmp[1].type = ACPI_TYPE_INTEGER; 1468c2ecf20Sopenharmony_ci } else if (strcmp(chip->ppi_version, "1.2") < 0) { 1478c2ecf20Sopenharmony_ci if (sscanf(buf, "%d", &req) != 1) 1488c2ecf20Sopenharmony_ci return -EINVAL; 1498c2ecf20Sopenharmony_ci argv4.type = ACPI_TYPE_BUFFER; 1508c2ecf20Sopenharmony_ci argv4.buffer.length = sizeof(req); 1518c2ecf20Sopenharmony_ci argv4.buffer.pointer = (u8 *)&req; 1528c2ecf20Sopenharmony_ci } else { 1538c2ecf20Sopenharmony_cippi12: 1548c2ecf20Sopenharmony_ci argv4.package.count = 1; 1558c2ecf20Sopenharmony_ci tmp[0].type = ACPI_TYPE_INTEGER; 1568c2ecf20Sopenharmony_ci if (sscanf(buf, "%llu", &tmp[0].integer.value) != 1) 1578c2ecf20Sopenharmony_ci return -EINVAL; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER, 1618c2ecf20Sopenharmony_ci &argv4, rev); 1628c2ecf20Sopenharmony_ci if (!obj) { 1638c2ecf20Sopenharmony_ci return -ENXIO; 1648c2ecf20Sopenharmony_ci } else { 1658c2ecf20Sopenharmony_ci ret = obj->integer.value; 1668c2ecf20Sopenharmony_ci ACPI_FREE(obj); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (ret == 0) 1708c2ecf20Sopenharmony_ci return (acpi_status)count; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return (ret == 1) ? -EPERM : -EFAULT; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic ssize_t tpm_show_ppi_transition_action(struct device *dev, 1768c2ecf20Sopenharmony_ci struct device_attribute *attr, 1778c2ecf20Sopenharmony_ci char *buf) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci u32 ret; 1808c2ecf20Sopenharmony_ci acpi_status status; 1818c2ecf20Sopenharmony_ci union acpi_object *obj = NULL; 1828c2ecf20Sopenharmony_ci union acpi_object tmp = { 1838c2ecf20Sopenharmony_ci .buffer.type = ACPI_TYPE_BUFFER, 1848c2ecf20Sopenharmony_ci .buffer.length = 0, 1858c2ecf20Sopenharmony_ci .buffer.pointer = NULL 1868c2ecf20Sopenharmony_ci }; 1878c2ecf20Sopenharmony_ci struct tpm_chip *chip = to_tpm_chip(dev); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci static char *info[] = { 1908c2ecf20Sopenharmony_ci "None", 1918c2ecf20Sopenharmony_ci "Shutdown", 1928c2ecf20Sopenharmony_ci "Reboot", 1938c2ecf20Sopenharmony_ci "OS Vendor-specific", 1948c2ecf20Sopenharmony_ci "Error", 1958c2ecf20Sopenharmony_ci }; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* 1988c2ecf20Sopenharmony_ci * PPI spec defines params[3].type as empty package, but some platforms 1998c2ecf20Sopenharmony_ci * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for 2008c2ecf20Sopenharmony_ci * compatibility, define params[3].type as buffer, if PPI version < 1.2 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci if (strcmp(chip->ppi_version, "1.2") < 0) 2038c2ecf20Sopenharmony_ci obj = &tmp; 2048c2ecf20Sopenharmony_ci obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT, 2058c2ecf20Sopenharmony_ci ACPI_TYPE_INTEGER, obj, TPM_PPI_REVISION_ID_1); 2068c2ecf20Sopenharmony_ci if (!obj) { 2078c2ecf20Sopenharmony_ci return -ENXIO; 2088c2ecf20Sopenharmony_ci } else { 2098c2ecf20Sopenharmony_ci ret = obj->integer.value; 2108c2ecf20Sopenharmony_ci ACPI_FREE(obj); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (ret < ARRAY_SIZE(info) - 1) 2148c2ecf20Sopenharmony_ci status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); 2158c2ecf20Sopenharmony_ci else 2168c2ecf20Sopenharmony_ci status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, 2178c2ecf20Sopenharmony_ci info[ARRAY_SIZE(info)-1]); 2188c2ecf20Sopenharmony_ci return status; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic ssize_t tpm_show_ppi_response(struct device *dev, 2228c2ecf20Sopenharmony_ci struct device_attribute *attr, 2238c2ecf20Sopenharmony_ci char *buf) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci acpi_status status = -EINVAL; 2268c2ecf20Sopenharmony_ci union acpi_object *obj, *ret_obj; 2278c2ecf20Sopenharmony_ci u64 req, res; 2288c2ecf20Sopenharmony_ci struct tpm_chip *chip = to_tpm_chip(dev); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP, 2318c2ecf20Sopenharmony_ci ACPI_TYPE_PACKAGE, NULL, TPM_PPI_REVISION_ID_1); 2328c2ecf20Sopenharmony_ci if (!obj) 2338c2ecf20Sopenharmony_ci return -ENXIO; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* 2368c2ecf20Sopenharmony_ci * parameter output.pointer should be of package type, including 2378c2ecf20Sopenharmony_ci * 3 integers. The first means function return code, the second means 2388c2ecf20Sopenharmony_ci * most recent TPM operation request, and the last means response to 2398c2ecf20Sopenharmony_ci * the most recent TPM operation request. Only if the first is 0, and 2408c2ecf20Sopenharmony_ci * the second integer is not 0, the response makes sense. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ci ret_obj = obj->package.elements; 2438c2ecf20Sopenharmony_ci if (obj->package.count < 3 || 2448c2ecf20Sopenharmony_ci ret_obj[0].type != ACPI_TYPE_INTEGER || 2458c2ecf20Sopenharmony_ci ret_obj[1].type != ACPI_TYPE_INTEGER || 2468c2ecf20Sopenharmony_ci ret_obj[2].type != ACPI_TYPE_INTEGER) 2478c2ecf20Sopenharmony_ci goto cleanup; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (ret_obj[0].integer.value) { 2508c2ecf20Sopenharmony_ci status = -EFAULT; 2518c2ecf20Sopenharmony_ci goto cleanup; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci req = ret_obj[1].integer.value; 2558c2ecf20Sopenharmony_ci res = ret_obj[2].integer.value; 2568c2ecf20Sopenharmony_ci if (req) { 2578c2ecf20Sopenharmony_ci if (res == 0) 2588c2ecf20Sopenharmony_ci status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 2598c2ecf20Sopenharmony_ci "0: Success"); 2608c2ecf20Sopenharmony_ci else if (res == 0xFFFFFFF0) 2618c2ecf20Sopenharmony_ci status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 2628c2ecf20Sopenharmony_ci "0xFFFFFFF0: User Abort"); 2638c2ecf20Sopenharmony_ci else if (res == 0xFFFFFFF1) 2648c2ecf20Sopenharmony_ci status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 2658c2ecf20Sopenharmony_ci "0xFFFFFFF1: BIOS Failure"); 2668c2ecf20Sopenharmony_ci else if (res >= 1 && res <= 0x00000FFF) 2678c2ecf20Sopenharmony_ci status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 2688c2ecf20Sopenharmony_ci req, res, "Corresponding TPM error"); 2698c2ecf20Sopenharmony_ci else 2708c2ecf20Sopenharmony_ci status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 2718c2ecf20Sopenharmony_ci req, res, "Error"); 2728c2ecf20Sopenharmony_ci } else { 2738c2ecf20Sopenharmony_ci status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", 2748c2ecf20Sopenharmony_ci req, "No Recent Request"); 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cicleanup: 2788c2ecf20Sopenharmony_ci ACPI_FREE(obj); 2798c2ecf20Sopenharmony_ci return status; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start, 2838c2ecf20Sopenharmony_ci u32 end) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci int i; 2868c2ecf20Sopenharmony_ci u32 ret; 2878c2ecf20Sopenharmony_ci char *str = buf; 2888c2ecf20Sopenharmony_ci union acpi_object *obj, tmp; 2898c2ecf20Sopenharmony_ci union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci static char *info[] = { 2928c2ecf20Sopenharmony_ci "Not implemented", 2938c2ecf20Sopenharmony_ci "BIOS only", 2948c2ecf20Sopenharmony_ci "Blocked for OS by BIOS", 2958c2ecf20Sopenharmony_ci "User required", 2968c2ecf20Sopenharmony_ci "User not required", 2978c2ecf20Sopenharmony_ci }; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (!acpi_check_dsm(dev_handle, &tpm_ppi_guid, TPM_PPI_REVISION_ID_1, 3008c2ecf20Sopenharmony_ci 1 << TPM_PPI_FN_GETOPR)) 3018c2ecf20Sopenharmony_ci return -EPERM; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci tmp.integer.type = ACPI_TYPE_INTEGER; 3048c2ecf20Sopenharmony_ci for (i = start; i <= end; i++) { 3058c2ecf20Sopenharmony_ci tmp.integer.value = i; 3068c2ecf20Sopenharmony_ci obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR, 3078c2ecf20Sopenharmony_ci ACPI_TYPE_INTEGER, &argv, 3088c2ecf20Sopenharmony_ci TPM_PPI_REVISION_ID_1); 3098c2ecf20Sopenharmony_ci if (!obj) { 3108c2ecf20Sopenharmony_ci return -ENOMEM; 3118c2ecf20Sopenharmony_ci } else { 3128c2ecf20Sopenharmony_ci ret = obj->integer.value; 3138c2ecf20Sopenharmony_ci ACPI_FREE(obj); 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (ret > 0 && ret < ARRAY_SIZE(info)) 3178c2ecf20Sopenharmony_ci str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", 3188c2ecf20Sopenharmony_ci i, ret, info[ret]); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return str - buf; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic ssize_t tpm_show_ppi_tcg_operations(struct device *dev, 3258c2ecf20Sopenharmony_ci struct device_attribute *attr, 3268c2ecf20Sopenharmony_ci char *buf) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct tpm_chip *chip = to_tpm_chip(dev); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return show_ppi_operations(chip->acpi_dev_handle, buf, 0, 3318c2ecf20Sopenharmony_ci PPI_TPM_REQ_MAX); 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic ssize_t tpm_show_ppi_vs_operations(struct device *dev, 3358c2ecf20Sopenharmony_ci struct device_attribute *attr, 3368c2ecf20Sopenharmony_ci char *buf) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct tpm_chip *chip = to_tpm_chip(dev); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START, 3418c2ecf20Sopenharmony_ci PPI_VS_REQ_END); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL); 3458c2ecf20Sopenharmony_cistatic DEVICE_ATTR(request, S_IRUGO | S_IWUSR | S_IWGRP, 3468c2ecf20Sopenharmony_ci tpm_show_ppi_request, tpm_store_ppi_request); 3478c2ecf20Sopenharmony_cistatic DEVICE_ATTR(transition_action, S_IRUGO, 3488c2ecf20Sopenharmony_ci tpm_show_ppi_transition_action, NULL); 3498c2ecf20Sopenharmony_cistatic DEVICE_ATTR(response, S_IRUGO, tpm_show_ppi_response, NULL); 3508c2ecf20Sopenharmony_cistatic DEVICE_ATTR(tcg_operations, S_IRUGO, tpm_show_ppi_tcg_operations, NULL); 3518c2ecf20Sopenharmony_cistatic DEVICE_ATTR(vs_operations, S_IRUGO, tpm_show_ppi_vs_operations, NULL); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic struct attribute *ppi_attrs[] = { 3548c2ecf20Sopenharmony_ci &dev_attr_version.attr, 3558c2ecf20Sopenharmony_ci &dev_attr_request.attr, 3568c2ecf20Sopenharmony_ci &dev_attr_transition_action.attr, 3578c2ecf20Sopenharmony_ci &dev_attr_response.attr, 3588c2ecf20Sopenharmony_ci &dev_attr_tcg_operations.attr, 3598c2ecf20Sopenharmony_ci &dev_attr_vs_operations.attr, NULL, 3608c2ecf20Sopenharmony_ci}; 3618c2ecf20Sopenharmony_cistatic struct attribute_group ppi_attr_grp = { 3628c2ecf20Sopenharmony_ci .name = "ppi", 3638c2ecf20Sopenharmony_ci .attrs = ppi_attrs 3648c2ecf20Sopenharmony_ci}; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_civoid tpm_add_ppi(struct tpm_chip *chip) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci union acpi_object *obj; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (!chip->acpi_dev_handle) 3718c2ecf20Sopenharmony_ci return; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (!acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid, 3748c2ecf20Sopenharmony_ci TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_VERSION)) 3758c2ecf20Sopenharmony_ci return; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* Cache PPI version string. */ 3788c2ecf20Sopenharmony_ci obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, &tpm_ppi_guid, 3798c2ecf20Sopenharmony_ci TPM_PPI_REVISION_ID_1, 3808c2ecf20Sopenharmony_ci TPM_PPI_FN_VERSION, 3818c2ecf20Sopenharmony_ci NULL, ACPI_TYPE_STRING); 3828c2ecf20Sopenharmony_ci if (obj) { 3838c2ecf20Sopenharmony_ci strlcpy(chip->ppi_version, obj->string.pointer, 3848c2ecf20Sopenharmony_ci sizeof(chip->ppi_version)); 3858c2ecf20Sopenharmony_ci ACPI_FREE(obj); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci chip->groups[chip->groups_cnt++] = &ppi_attr_grp; 3898c2ecf20Sopenharmony_ci} 390