18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AMD Trusted Execution Environment (TEE) interface 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Rijo Thomas <Rijo-john.Thomas@amd.com> 68c2ecf20Sopenharmony_ci * Author: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright 2019 Advanced Micro Devices, Inc. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/mutex.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/gfp.h> 168c2ecf20Sopenharmony_ci#include <linux/psp-sev.h> 178c2ecf20Sopenharmony_ci#include <linux/psp-tee.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "psp-dev.h" 208c2ecf20Sopenharmony_ci#include "tee-dev.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic bool psp_dead; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic int tee_alloc_ring(struct psp_tee_device *tee, int ring_size) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct ring_buf_manager *rb_mgr = &tee->rb_mgr; 278c2ecf20Sopenharmony_ci void *start_addr; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci if (!ring_size) 308c2ecf20Sopenharmony_ci return -EINVAL; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci /* We need actual physical address instead of DMA address, since 338c2ecf20Sopenharmony_ci * Trusted OS running on AMD Secure Processor will map this region 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci start_addr = (void *)__get_free_pages(GFP_KERNEL, get_order(ring_size)); 368c2ecf20Sopenharmony_ci if (!start_addr) 378c2ecf20Sopenharmony_ci return -ENOMEM; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci memset(start_addr, 0x0, ring_size); 408c2ecf20Sopenharmony_ci rb_mgr->ring_start = start_addr; 418c2ecf20Sopenharmony_ci rb_mgr->ring_size = ring_size; 428c2ecf20Sopenharmony_ci rb_mgr->ring_pa = __psp_pa(start_addr); 438c2ecf20Sopenharmony_ci mutex_init(&rb_mgr->mutex); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return 0; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic void tee_free_ring(struct psp_tee_device *tee) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct ring_buf_manager *rb_mgr = &tee->rb_mgr; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (!rb_mgr->ring_start) 538c2ecf20Sopenharmony_ci return; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci free_pages((unsigned long)rb_mgr->ring_start, 568c2ecf20Sopenharmony_ci get_order(rb_mgr->ring_size)); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci rb_mgr->ring_start = NULL; 598c2ecf20Sopenharmony_ci rb_mgr->ring_size = 0; 608c2ecf20Sopenharmony_ci rb_mgr->ring_pa = 0; 618c2ecf20Sopenharmony_ci mutex_destroy(&rb_mgr->mutex); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int tee_wait_cmd_poll(struct psp_tee_device *tee, unsigned int timeout, 658c2ecf20Sopenharmony_ci unsigned int *reg) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci /* ~10ms sleep per loop => nloop = timeout * 100 */ 688c2ecf20Sopenharmony_ci int nloop = timeout * 100; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci while (--nloop) { 718c2ecf20Sopenharmony_ci *reg = ioread32(tee->io_regs + tee->vdata->cmdresp_reg); 728c2ecf20Sopenharmony_ci if (*reg & PSP_CMDRESP_RESP) 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci usleep_range(10000, 10100); 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci dev_err(tee->dev, "tee: command timed out, disabling PSP\n"); 798c2ecf20Sopenharmony_ci psp_dead = true; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return -ETIMEDOUT; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic 858c2ecf20Sopenharmony_cistruct tee_init_ring_cmd *tee_alloc_cmd_buffer(struct psp_tee_device *tee) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct tee_init_ring_cmd *cmd; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 908c2ecf20Sopenharmony_ci if (!cmd) 918c2ecf20Sopenharmony_ci return NULL; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci cmd->hi_addr = upper_32_bits(tee->rb_mgr.ring_pa); 948c2ecf20Sopenharmony_ci cmd->low_addr = lower_32_bits(tee->rb_mgr.ring_pa); 958c2ecf20Sopenharmony_ci cmd->size = tee->rb_mgr.ring_size; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci dev_dbg(tee->dev, "tee: ring address: high = 0x%x low = 0x%x size = %u\n", 988c2ecf20Sopenharmony_ci cmd->hi_addr, cmd->low_addr, cmd->size); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return cmd; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic inline void tee_free_cmd_buffer(struct tee_init_ring_cmd *cmd) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci kfree(cmd); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int tee_init_ring(struct psp_tee_device *tee) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd); 1118c2ecf20Sopenharmony_ci struct tee_init_ring_cmd *cmd; 1128c2ecf20Sopenharmony_ci phys_addr_t cmd_buffer; 1138c2ecf20Sopenharmony_ci unsigned int reg; 1148c2ecf20Sopenharmony_ci int ret; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct tee_ring_cmd) != 1024); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci ret = tee_alloc_ring(tee, ring_size); 1198c2ecf20Sopenharmony_ci if (ret) { 1208c2ecf20Sopenharmony_ci dev_err(tee->dev, "tee: ring allocation failed %d\n", ret); 1218c2ecf20Sopenharmony_ci return ret; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci tee->rb_mgr.wptr = 0; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci cmd = tee_alloc_cmd_buffer(tee); 1278c2ecf20Sopenharmony_ci if (!cmd) { 1288c2ecf20Sopenharmony_ci tee_free_ring(tee); 1298c2ecf20Sopenharmony_ci return -ENOMEM; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci cmd_buffer = __psp_pa((void *)cmd); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* Send command buffer details to Trusted OS by writing to 1358c2ecf20Sopenharmony_ci * CPU-PSP message registers 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci iowrite32(lower_32_bits(cmd_buffer), 1398c2ecf20Sopenharmony_ci tee->io_regs + tee->vdata->cmdbuff_addr_lo_reg); 1408c2ecf20Sopenharmony_ci iowrite32(upper_32_bits(cmd_buffer), 1418c2ecf20Sopenharmony_ci tee->io_regs + tee->vdata->cmdbuff_addr_hi_reg); 1428c2ecf20Sopenharmony_ci iowrite32(TEE_RING_INIT_CMD, 1438c2ecf20Sopenharmony_ci tee->io_regs + tee->vdata->cmdresp_reg); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, ®); 1468c2ecf20Sopenharmony_ci if (ret) { 1478c2ecf20Sopenharmony_ci dev_err(tee->dev, "tee: ring init command timed out\n"); 1488c2ecf20Sopenharmony_ci tee_free_ring(tee); 1498c2ecf20Sopenharmony_ci goto free_buf; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (reg & PSP_CMDRESP_ERR_MASK) { 1538c2ecf20Sopenharmony_ci dev_err(tee->dev, "tee: ring init command failed (%#010x)\n", 1548c2ecf20Sopenharmony_ci reg & PSP_CMDRESP_ERR_MASK); 1558c2ecf20Sopenharmony_ci tee_free_ring(tee); 1568c2ecf20Sopenharmony_ci ret = -EIO; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cifree_buf: 1608c2ecf20Sopenharmony_ci tee_free_cmd_buffer(cmd); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return ret; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void tee_destroy_ring(struct psp_tee_device *tee) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci unsigned int reg; 1688c2ecf20Sopenharmony_ci int ret; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (!tee->rb_mgr.ring_start) 1718c2ecf20Sopenharmony_ci return; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (psp_dead) 1748c2ecf20Sopenharmony_ci goto free_ring; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci iowrite32(TEE_RING_DESTROY_CMD, 1778c2ecf20Sopenharmony_ci tee->io_regs + tee->vdata->cmdresp_reg); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, ®); 1808c2ecf20Sopenharmony_ci if (ret) { 1818c2ecf20Sopenharmony_ci dev_err(tee->dev, "tee: ring destroy command timed out\n"); 1828c2ecf20Sopenharmony_ci } else if (reg & PSP_CMDRESP_ERR_MASK) { 1838c2ecf20Sopenharmony_ci dev_err(tee->dev, "tee: ring destroy command failed (%#010x)\n", 1848c2ecf20Sopenharmony_ci reg & PSP_CMDRESP_ERR_MASK); 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cifree_ring: 1888c2ecf20Sopenharmony_ci tee_free_ring(tee); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ciint tee_dev_init(struct psp_device *psp) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct device *dev = psp->dev; 1948c2ecf20Sopenharmony_ci struct psp_tee_device *tee; 1958c2ecf20Sopenharmony_ci int ret; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci ret = -ENOMEM; 1988c2ecf20Sopenharmony_ci tee = devm_kzalloc(dev, sizeof(*tee), GFP_KERNEL); 1998c2ecf20Sopenharmony_ci if (!tee) 2008c2ecf20Sopenharmony_ci goto e_err; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci psp->tee_data = tee; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci tee->dev = dev; 2058c2ecf20Sopenharmony_ci tee->psp = psp; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci tee->io_regs = psp->io_regs; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci tee->vdata = (struct tee_vdata *)psp->vdata->tee; 2108c2ecf20Sopenharmony_ci if (!tee->vdata) { 2118c2ecf20Sopenharmony_ci ret = -ENODEV; 2128c2ecf20Sopenharmony_ci dev_err(dev, "tee: missing driver data\n"); 2138c2ecf20Sopenharmony_ci goto e_err; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci ret = tee_init_ring(tee); 2178c2ecf20Sopenharmony_ci if (ret) { 2188c2ecf20Sopenharmony_ci dev_err(dev, "tee: failed to init ring buffer\n"); 2198c2ecf20Sopenharmony_ci goto e_err; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci dev_notice(dev, "tee enabled\n"); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cie_err: 2278c2ecf20Sopenharmony_ci psp->tee_data = NULL; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci dev_notice(dev, "tee initialization failed\n"); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return ret; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_civoid tee_dev_destroy(struct psp_device *psp) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct psp_tee_device *tee = psp->tee_data; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (!tee) 2398c2ecf20Sopenharmony_ci return; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci tee_destroy_ring(tee); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int tee_submit_cmd(struct psp_tee_device *tee, enum tee_cmd_id cmd_id, 2458c2ecf20Sopenharmony_ci void *buf, size_t len, struct tee_ring_cmd **resp) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci struct tee_ring_cmd *cmd; 2488c2ecf20Sopenharmony_ci int nloop = 1000, ret = 0; 2498c2ecf20Sopenharmony_ci u32 rptr; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci *resp = NULL; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci mutex_lock(&tee->rb_mgr.mutex); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* Loop until empty entry found in ring buffer */ 2568c2ecf20Sopenharmony_ci do { 2578c2ecf20Sopenharmony_ci /* Get pointer to ring buffer command entry */ 2588c2ecf20Sopenharmony_ci cmd = (struct tee_ring_cmd *) 2598c2ecf20Sopenharmony_ci (tee->rb_mgr.ring_start + tee->rb_mgr.wptr); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci rptr = ioread32(tee->io_regs + tee->vdata->ring_rptr_reg); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* Check if ring buffer is full or command entry is waiting 2648c2ecf20Sopenharmony_ci * for response from TEE 2658c2ecf20Sopenharmony_ci */ 2668c2ecf20Sopenharmony_ci if (!(tee->rb_mgr.wptr + sizeof(struct tee_ring_cmd) == rptr || 2678c2ecf20Sopenharmony_ci cmd->flag == CMD_WAITING_FOR_RESPONSE)) 2688c2ecf20Sopenharmony_ci break; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci dev_dbg(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n", 2718c2ecf20Sopenharmony_ci rptr, tee->rb_mgr.wptr); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* Wait if ring buffer is full or TEE is processing data */ 2748c2ecf20Sopenharmony_ci mutex_unlock(&tee->rb_mgr.mutex); 2758c2ecf20Sopenharmony_ci schedule_timeout_interruptible(msecs_to_jiffies(10)); 2768c2ecf20Sopenharmony_ci mutex_lock(&tee->rb_mgr.mutex); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci } while (--nloop); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (!nloop && 2818c2ecf20Sopenharmony_ci (tee->rb_mgr.wptr + sizeof(struct tee_ring_cmd) == rptr || 2828c2ecf20Sopenharmony_ci cmd->flag == CMD_WAITING_FOR_RESPONSE)) { 2838c2ecf20Sopenharmony_ci dev_err(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u response flag %u\n", 2848c2ecf20Sopenharmony_ci rptr, tee->rb_mgr.wptr, cmd->flag); 2858c2ecf20Sopenharmony_ci ret = -EBUSY; 2868c2ecf20Sopenharmony_ci goto unlock; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* Do not submit command if PSP got disabled while processing any 2908c2ecf20Sopenharmony_ci * command in another thread 2918c2ecf20Sopenharmony_ci */ 2928c2ecf20Sopenharmony_ci if (psp_dead) { 2938c2ecf20Sopenharmony_ci ret = -EBUSY; 2948c2ecf20Sopenharmony_ci goto unlock; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* Write command data into ring buffer */ 2988c2ecf20Sopenharmony_ci cmd->cmd_id = cmd_id; 2998c2ecf20Sopenharmony_ci cmd->cmd_state = TEE_CMD_STATE_INIT; 3008c2ecf20Sopenharmony_ci memset(&cmd->buf[0], 0, sizeof(cmd->buf)); 3018c2ecf20Sopenharmony_ci memcpy(&cmd->buf[0], buf, len); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* Indicate driver is waiting for response */ 3048c2ecf20Sopenharmony_ci cmd->flag = CMD_WAITING_FOR_RESPONSE; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* Update local copy of write pointer */ 3078c2ecf20Sopenharmony_ci tee->rb_mgr.wptr += sizeof(struct tee_ring_cmd); 3088c2ecf20Sopenharmony_ci if (tee->rb_mgr.wptr >= tee->rb_mgr.ring_size) 3098c2ecf20Sopenharmony_ci tee->rb_mgr.wptr = 0; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* Trigger interrupt to Trusted OS */ 3128c2ecf20Sopenharmony_ci iowrite32(tee->rb_mgr.wptr, tee->io_regs + tee->vdata->ring_wptr_reg); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* The response is provided by Trusted OS in same 3158c2ecf20Sopenharmony_ci * location as submitted data entry within ring buffer. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci *resp = cmd; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ciunlock: 3208c2ecf20Sopenharmony_ci mutex_unlock(&tee->rb_mgr.mutex); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return ret; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int tee_wait_cmd_completion(struct psp_tee_device *tee, 3268c2ecf20Sopenharmony_ci struct tee_ring_cmd *resp, 3278c2ecf20Sopenharmony_ci unsigned int timeout) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci /* ~5ms sleep per loop => nloop = timeout * 200 */ 3308c2ecf20Sopenharmony_ci int nloop = timeout * 200; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci while (--nloop) { 3338c2ecf20Sopenharmony_ci if (resp->cmd_state == TEE_CMD_STATE_COMPLETED) 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci usleep_range(5000, 5100); 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci dev_err(tee->dev, "tee: command 0x%x timed out, disabling PSP\n", 3408c2ecf20Sopenharmony_ci resp->cmd_id); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci psp_dead = true; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ciint psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf, size_t len, 3488c2ecf20Sopenharmony_ci u32 *status) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct psp_device *psp = psp_get_master_device(); 3518c2ecf20Sopenharmony_ci struct psp_tee_device *tee; 3528c2ecf20Sopenharmony_ci struct tee_ring_cmd *resp; 3538c2ecf20Sopenharmony_ci int ret; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (!buf || !status || !len || len > sizeof(resp->buf)) 3568c2ecf20Sopenharmony_ci return -EINVAL; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci *status = 0; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (!psp || !psp->tee_data) 3618c2ecf20Sopenharmony_ci return -ENODEV; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (psp_dead) 3648c2ecf20Sopenharmony_ci return -EBUSY; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci tee = psp->tee_data; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci ret = tee_submit_cmd(tee, cmd_id, buf, len, &resp); 3698c2ecf20Sopenharmony_ci if (ret) 3708c2ecf20Sopenharmony_ci return ret; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci ret = tee_wait_cmd_completion(tee, resp, TEE_DEFAULT_TIMEOUT); 3738c2ecf20Sopenharmony_ci if (ret) { 3748c2ecf20Sopenharmony_ci resp->flag = CMD_RESPONSE_TIMEDOUT; 3758c2ecf20Sopenharmony_ci return ret; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci memcpy(buf, &resp->buf[0], len); 3798c2ecf20Sopenharmony_ci *status = resp->status; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci resp->flag = CMD_RESPONSE_COPIED; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(psp_tee_process_cmd); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ciint psp_check_tee_status(void) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct psp_device *psp = psp_get_master_device(); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (!psp || !psp->tee_data) 3928c2ecf20Sopenharmony_ci return -ENODEV; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(psp_check_tee_status); 397