1*33960accSRijo Thomas // SPDX-License-Identifier: MIT 2*33960accSRijo Thomas /* 3*33960accSRijo Thomas * AMD Trusted Execution Environment (TEE) interface 4*33960accSRijo Thomas * 5*33960accSRijo Thomas * Author: Rijo Thomas <Rijo-john.Thomas@amd.com> 6*33960accSRijo Thomas * Author: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com> 7*33960accSRijo Thomas * 8*33960accSRijo Thomas * Copyright 2019 Advanced Micro Devices, Inc. 9*33960accSRijo Thomas */ 10*33960accSRijo Thomas 11*33960accSRijo Thomas #include <linux/types.h> 12*33960accSRijo Thomas #include <linux/mutex.h> 13*33960accSRijo Thomas #include <linux/delay.h> 14*33960accSRijo Thomas #include <linux/slab.h> 15*33960accSRijo Thomas #include <linux/gfp.h> 16*33960accSRijo Thomas #include <linux/psp-sev.h> 17*33960accSRijo Thomas 18*33960accSRijo Thomas #include "psp-dev.h" 19*33960accSRijo Thomas #include "tee-dev.h" 20*33960accSRijo Thomas 21*33960accSRijo Thomas static bool psp_dead; 22*33960accSRijo Thomas 23*33960accSRijo Thomas static int tee_alloc_ring(struct psp_tee_device *tee, int ring_size) 24*33960accSRijo Thomas { 25*33960accSRijo Thomas struct ring_buf_manager *rb_mgr = &tee->rb_mgr; 26*33960accSRijo Thomas void *start_addr; 27*33960accSRijo Thomas 28*33960accSRijo Thomas if (!ring_size) 29*33960accSRijo Thomas return -EINVAL; 30*33960accSRijo Thomas 31*33960accSRijo Thomas /* We need actual physical address instead of DMA address, since 32*33960accSRijo Thomas * Trusted OS running on AMD Secure Processor will map this region 33*33960accSRijo Thomas */ 34*33960accSRijo Thomas start_addr = (void *)__get_free_pages(GFP_KERNEL, get_order(ring_size)); 35*33960accSRijo Thomas if (!start_addr) 36*33960accSRijo Thomas return -ENOMEM; 37*33960accSRijo Thomas 38*33960accSRijo Thomas rb_mgr->ring_start = start_addr; 39*33960accSRijo Thomas rb_mgr->ring_size = ring_size; 40*33960accSRijo Thomas rb_mgr->ring_pa = __psp_pa(start_addr); 41*33960accSRijo Thomas 42*33960accSRijo Thomas return 0; 43*33960accSRijo Thomas } 44*33960accSRijo Thomas 45*33960accSRijo Thomas static void tee_free_ring(struct psp_tee_device *tee) 46*33960accSRijo Thomas { 47*33960accSRijo Thomas struct ring_buf_manager *rb_mgr = &tee->rb_mgr; 48*33960accSRijo Thomas 49*33960accSRijo Thomas if (!rb_mgr->ring_start) 50*33960accSRijo Thomas return; 51*33960accSRijo Thomas 52*33960accSRijo Thomas free_pages((unsigned long)rb_mgr->ring_start, 53*33960accSRijo Thomas get_order(rb_mgr->ring_size)); 54*33960accSRijo Thomas 55*33960accSRijo Thomas rb_mgr->ring_start = NULL; 56*33960accSRijo Thomas rb_mgr->ring_size = 0; 57*33960accSRijo Thomas rb_mgr->ring_pa = 0; 58*33960accSRijo Thomas } 59*33960accSRijo Thomas 60*33960accSRijo Thomas static int tee_wait_cmd_poll(struct psp_tee_device *tee, unsigned int timeout, 61*33960accSRijo Thomas unsigned int *reg) 62*33960accSRijo Thomas { 63*33960accSRijo Thomas /* ~10ms sleep per loop => nloop = timeout * 100 */ 64*33960accSRijo Thomas int nloop = timeout * 100; 65*33960accSRijo Thomas 66*33960accSRijo Thomas while (--nloop) { 67*33960accSRijo Thomas *reg = ioread32(tee->io_regs + tee->vdata->cmdresp_reg); 68*33960accSRijo Thomas if (*reg & PSP_CMDRESP_RESP) 69*33960accSRijo Thomas return 0; 70*33960accSRijo Thomas 71*33960accSRijo Thomas usleep_range(10000, 10100); 72*33960accSRijo Thomas } 73*33960accSRijo Thomas 74*33960accSRijo Thomas dev_err(tee->dev, "tee: command timed out, disabling PSP\n"); 75*33960accSRijo Thomas psp_dead = true; 76*33960accSRijo Thomas 77*33960accSRijo Thomas return -ETIMEDOUT; 78*33960accSRijo Thomas } 79*33960accSRijo Thomas 80*33960accSRijo Thomas static 81*33960accSRijo Thomas struct tee_init_ring_cmd *tee_alloc_cmd_buffer(struct psp_tee_device *tee) 82*33960accSRijo Thomas { 83*33960accSRijo Thomas struct tee_init_ring_cmd *cmd; 84*33960accSRijo Thomas 85*33960accSRijo Thomas cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 86*33960accSRijo Thomas if (!cmd) 87*33960accSRijo Thomas return NULL; 88*33960accSRijo Thomas 89*33960accSRijo Thomas cmd->hi_addr = upper_32_bits(tee->rb_mgr.ring_pa); 90*33960accSRijo Thomas cmd->low_addr = lower_32_bits(tee->rb_mgr.ring_pa); 91*33960accSRijo Thomas cmd->size = tee->rb_mgr.ring_size; 92*33960accSRijo Thomas 93*33960accSRijo Thomas dev_dbg(tee->dev, "tee: ring address: high = 0x%x low = 0x%x size = %u\n", 94*33960accSRijo Thomas cmd->hi_addr, cmd->low_addr, cmd->size); 95*33960accSRijo Thomas 96*33960accSRijo Thomas return cmd; 97*33960accSRijo Thomas } 98*33960accSRijo Thomas 99*33960accSRijo Thomas static inline void tee_free_cmd_buffer(struct tee_init_ring_cmd *cmd) 100*33960accSRijo Thomas { 101*33960accSRijo Thomas kfree(cmd); 102*33960accSRijo Thomas } 103*33960accSRijo Thomas 104*33960accSRijo Thomas static int tee_init_ring(struct psp_tee_device *tee) 105*33960accSRijo Thomas { 106*33960accSRijo Thomas int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd); 107*33960accSRijo Thomas struct tee_init_ring_cmd *cmd; 108*33960accSRijo Thomas phys_addr_t cmd_buffer; 109*33960accSRijo Thomas unsigned int reg; 110*33960accSRijo Thomas int ret; 111*33960accSRijo Thomas 112*33960accSRijo Thomas BUILD_BUG_ON(sizeof(struct tee_ring_cmd) != 1024); 113*33960accSRijo Thomas 114*33960accSRijo Thomas ret = tee_alloc_ring(tee, ring_size); 115*33960accSRijo Thomas if (ret) { 116*33960accSRijo Thomas dev_err(tee->dev, "tee: ring allocation failed %d\n", ret); 117*33960accSRijo Thomas return ret; 118*33960accSRijo Thomas } 119*33960accSRijo Thomas 120*33960accSRijo Thomas tee->rb_mgr.wptr = 0; 121*33960accSRijo Thomas 122*33960accSRijo Thomas cmd = tee_alloc_cmd_buffer(tee); 123*33960accSRijo Thomas if (!cmd) { 124*33960accSRijo Thomas tee_free_ring(tee); 125*33960accSRijo Thomas return -ENOMEM; 126*33960accSRijo Thomas } 127*33960accSRijo Thomas 128*33960accSRijo Thomas cmd_buffer = __psp_pa((void *)cmd); 129*33960accSRijo Thomas 130*33960accSRijo Thomas /* Send command buffer details to Trusted OS by writing to 131*33960accSRijo Thomas * CPU-PSP message registers 132*33960accSRijo Thomas */ 133*33960accSRijo Thomas 134*33960accSRijo Thomas iowrite32(lower_32_bits(cmd_buffer), 135*33960accSRijo Thomas tee->io_regs + tee->vdata->cmdbuff_addr_lo_reg); 136*33960accSRijo Thomas iowrite32(upper_32_bits(cmd_buffer), 137*33960accSRijo Thomas tee->io_regs + tee->vdata->cmdbuff_addr_hi_reg); 138*33960accSRijo Thomas iowrite32(TEE_RING_INIT_CMD, 139*33960accSRijo Thomas tee->io_regs + tee->vdata->cmdresp_reg); 140*33960accSRijo Thomas 141*33960accSRijo Thomas ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, ®); 142*33960accSRijo Thomas if (ret) { 143*33960accSRijo Thomas dev_err(tee->dev, "tee: ring init command timed out\n"); 144*33960accSRijo Thomas tee_free_ring(tee); 145*33960accSRijo Thomas goto free_buf; 146*33960accSRijo Thomas } 147*33960accSRijo Thomas 148*33960accSRijo Thomas if (reg & PSP_CMDRESP_ERR_MASK) { 149*33960accSRijo Thomas dev_err(tee->dev, "tee: ring init command failed (%#010x)\n", 150*33960accSRijo Thomas reg & PSP_CMDRESP_ERR_MASK); 151*33960accSRijo Thomas tee_free_ring(tee); 152*33960accSRijo Thomas ret = -EIO; 153*33960accSRijo Thomas } 154*33960accSRijo Thomas 155*33960accSRijo Thomas free_buf: 156*33960accSRijo Thomas tee_free_cmd_buffer(cmd); 157*33960accSRijo Thomas 158*33960accSRijo Thomas return ret; 159*33960accSRijo Thomas } 160*33960accSRijo Thomas 161*33960accSRijo Thomas static void tee_destroy_ring(struct psp_tee_device *tee) 162*33960accSRijo Thomas { 163*33960accSRijo Thomas unsigned int reg; 164*33960accSRijo Thomas int ret; 165*33960accSRijo Thomas 166*33960accSRijo Thomas if (!tee->rb_mgr.ring_start) 167*33960accSRijo Thomas return; 168*33960accSRijo Thomas 169*33960accSRijo Thomas if (psp_dead) 170*33960accSRijo Thomas goto free_ring; 171*33960accSRijo Thomas 172*33960accSRijo Thomas iowrite32(TEE_RING_DESTROY_CMD, 173*33960accSRijo Thomas tee->io_regs + tee->vdata->cmdresp_reg); 174*33960accSRijo Thomas 175*33960accSRijo Thomas ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, ®); 176*33960accSRijo Thomas if (ret) { 177*33960accSRijo Thomas dev_err(tee->dev, "tee: ring destroy command timed out\n"); 178*33960accSRijo Thomas } else if (reg & PSP_CMDRESP_ERR_MASK) { 179*33960accSRijo Thomas dev_err(tee->dev, "tee: ring destroy command failed (%#010x)\n", 180*33960accSRijo Thomas reg & PSP_CMDRESP_ERR_MASK); 181*33960accSRijo Thomas } 182*33960accSRijo Thomas 183*33960accSRijo Thomas free_ring: 184*33960accSRijo Thomas tee_free_ring(tee); 185*33960accSRijo Thomas } 186*33960accSRijo Thomas 187*33960accSRijo Thomas int tee_dev_init(struct psp_device *psp) 188*33960accSRijo Thomas { 189*33960accSRijo Thomas struct device *dev = psp->dev; 190*33960accSRijo Thomas struct psp_tee_device *tee; 191*33960accSRijo Thomas int ret; 192*33960accSRijo Thomas 193*33960accSRijo Thomas ret = -ENOMEM; 194*33960accSRijo Thomas tee = devm_kzalloc(dev, sizeof(*tee), GFP_KERNEL); 195*33960accSRijo Thomas if (!tee) 196*33960accSRijo Thomas goto e_err; 197*33960accSRijo Thomas 198*33960accSRijo Thomas psp->tee_data = tee; 199*33960accSRijo Thomas 200*33960accSRijo Thomas tee->dev = dev; 201*33960accSRijo Thomas tee->psp = psp; 202*33960accSRijo Thomas 203*33960accSRijo Thomas tee->io_regs = psp->io_regs; 204*33960accSRijo Thomas 205*33960accSRijo Thomas tee->vdata = (struct tee_vdata *)psp->vdata->tee; 206*33960accSRijo Thomas if (!tee->vdata) { 207*33960accSRijo Thomas ret = -ENODEV; 208*33960accSRijo Thomas dev_err(dev, "tee: missing driver data\n"); 209*33960accSRijo Thomas goto e_err; 210*33960accSRijo Thomas } 211*33960accSRijo Thomas 212*33960accSRijo Thomas ret = tee_init_ring(tee); 213*33960accSRijo Thomas if (ret) { 214*33960accSRijo Thomas dev_err(dev, "tee: failed to init ring buffer\n"); 215*33960accSRijo Thomas goto e_err; 216*33960accSRijo Thomas } 217*33960accSRijo Thomas 218*33960accSRijo Thomas dev_notice(dev, "tee enabled\n"); 219*33960accSRijo Thomas 220*33960accSRijo Thomas return 0; 221*33960accSRijo Thomas 222*33960accSRijo Thomas e_err: 223*33960accSRijo Thomas psp->tee_data = NULL; 224*33960accSRijo Thomas 225*33960accSRijo Thomas dev_notice(dev, "tee initialization failed\n"); 226*33960accSRijo Thomas 227*33960accSRijo Thomas return ret; 228*33960accSRijo Thomas } 229*33960accSRijo Thomas 230*33960accSRijo Thomas void tee_dev_destroy(struct psp_device *psp) 231*33960accSRijo Thomas { 232*33960accSRijo Thomas struct psp_tee_device *tee = psp->tee_data; 233*33960accSRijo Thomas 234*33960accSRijo Thomas if (!tee) 235*33960accSRijo Thomas return; 236*33960accSRijo Thomas 237*33960accSRijo Thomas tee_destroy_ring(tee); 238*33960accSRijo Thomas } 239