| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- // SPDX-License-Identifier: MIT
- /*
- * AMD Trusted Execution Environment (TEE) interface
- *
- * Author: Rijo Thomas <Rijo-john.Thomas@amd.com>
- * Author: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
- *
- * Copyright (C) 2019,2021 Advanced Micro Devices, Inc.
- */
- #include <linux/bitfield.h>
- #include <linux/types.h>
- #include <linux/mutex.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
- #include <linux/gfp.h>
- #include <linux/psp.h>
- #include <linux/psp-tee.h>
- #include "psp-dev.h"
- #include "tee-dev.h"
- static bool psp_dead;
- static int tee_alloc_ring(struct psp_tee_device *tee, int ring_size)
- {
- struct ring_buf_manager *rb_mgr = &tee->rb_mgr;
- void *start_addr;
- if (!ring_size)
- return -EINVAL;
- /* We need actual physical address instead of DMA address, since
- * Trusted OS running on AMD Secure Processor will map this region
- */
- start_addr = (void *)__get_free_pages(GFP_KERNEL, get_order(ring_size));
- if (!start_addr)
- return -ENOMEM;
- memset(start_addr, 0x0, ring_size);
- rb_mgr->ring_start = start_addr;
- rb_mgr->ring_size = ring_size;
- rb_mgr->ring_pa = __psp_pa(start_addr);
- mutex_init(&rb_mgr->mutex);
- return 0;
- }
- static void tee_free_ring(struct psp_tee_device *tee)
- {
- struct ring_buf_manager *rb_mgr = &tee->rb_mgr;
- if (!rb_mgr->ring_start)
- return;
- free_pages((unsigned long)rb_mgr->ring_start,
- get_order(rb_mgr->ring_size));
- rb_mgr->ring_start = NULL;
- rb_mgr->ring_size = 0;
- rb_mgr->ring_pa = 0;
- mutex_destroy(&rb_mgr->mutex);
- }
- static
- struct tee_init_ring_cmd *tee_alloc_cmd_buffer(struct psp_tee_device *tee)
- {
- struct tee_init_ring_cmd *cmd;
- cmd = kzalloc_obj(*cmd);
- if (!cmd)
- return NULL;
- cmd->hi_addr = upper_32_bits(tee->rb_mgr.ring_pa);
- cmd->low_addr = lower_32_bits(tee->rb_mgr.ring_pa);
- cmd->size = tee->rb_mgr.ring_size;
- dev_dbg(tee->dev, "tee: ring address: high = 0x%x low = 0x%x size = %u\n",
- cmd->hi_addr, cmd->low_addr, cmd->size);
- return cmd;
- }
- static inline void tee_free_cmd_buffer(struct tee_init_ring_cmd *cmd)
- {
- kfree(cmd);
- }
- static bool tee_send_destroy_cmd(struct psp_tee_device *tee)
- {
- unsigned int reg;
- int ret;
- ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_DESTROY, NULL,
- TEE_DEFAULT_CMD_TIMEOUT, ®);
- if (ret) {
- dev_err(tee->dev, "tee: ring destroy command timed out, disabling TEE support\n");
- psp_dead = true;
- return false;
- }
- if (FIELD_GET(PSP_CMDRESP_STS, reg)) {
- dev_err(tee->dev, "tee: ring destroy command failed (%#010lx)\n",
- FIELD_GET(PSP_CMDRESP_STS, reg));
- psp_dead = true;
- return false;
- }
- return true;
- }
- static int tee_init_ring(struct psp_tee_device *tee)
- {
- int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd);
- struct tee_init_ring_cmd *cmd;
- bool retry = false;
- unsigned int reg;
- int ret;
- BUILD_BUG_ON(sizeof(struct tee_ring_cmd) != 1024);
- ret = tee_alloc_ring(tee, ring_size);
- if (ret) {
- dev_err(tee->dev, "tee: ring allocation failed %d\n", ret);
- return ret;
- }
- tee->rb_mgr.wptr = 0;
- cmd = tee_alloc_cmd_buffer(tee);
- if (!cmd) {
- tee_free_ring(tee);
- return -ENOMEM;
- }
- /* Send command buffer details to Trusted OS by writing to
- * CPU-PSP message registers
- */
- retry_init:
- ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_INIT, cmd,
- TEE_DEFAULT_CMD_TIMEOUT, ®);
- if (ret) {
- dev_err(tee->dev, "tee: ring init command timed out, disabling TEE support\n");
- tee_free_ring(tee);
- psp_dead = true;
- goto free_buf;
- }
- if (FIELD_GET(PSP_CMDRESP_STS, reg)) {
- /*
- * During the hibernate resume sequence driver may have gotten loaded
- * but the ring not properly destroyed. If the ring doesn't work, try
- * to destroy and re-init once.
- */
- if (!retry && FIELD_GET(PSP_CMDRESP_STS, reg) == PSP_TEE_STS_RING_BUSY) {
- dev_info(tee->dev, "tee: ring init command failed with busy status, retrying\n");
- if (tee_send_destroy_cmd(tee)) {
- retry = true;
- goto retry_init;
- }
- }
- dev_err(tee->dev, "tee: ring init command failed (%#010lx)\n",
- FIELD_GET(PSP_CMDRESP_STS, reg));
- tee_free_ring(tee);
- psp_dead = true;
- ret = -EIO;
- }
- free_buf:
- tee_free_cmd_buffer(cmd);
- return ret;
- }
- static void tee_destroy_ring(struct psp_tee_device *tee)
- {
- if (!tee->rb_mgr.ring_start)
- return;
- if (psp_dead)
- goto free_ring;
- tee_send_destroy_cmd(tee);
- free_ring:
- tee_free_ring(tee);
- }
- int tee_dev_init(struct psp_device *psp)
- {
- struct device *dev = psp->dev;
- struct psp_tee_device *tee;
- int ret;
- ret = -ENOMEM;
- tee = devm_kzalloc(dev, sizeof(*tee), GFP_KERNEL);
- if (!tee)
- goto e_err;
- psp->tee_data = tee;
- tee->dev = dev;
- tee->psp = psp;
- tee->io_regs = psp->io_regs;
- tee->vdata = (struct tee_vdata *)psp->vdata->tee;
- if (!tee->vdata) {
- ret = -ENODEV;
- dev_err(dev, "tee: missing driver data\n");
- goto e_err;
- }
- ret = tee_init_ring(tee);
- if (ret) {
- dev_err(dev, "tee: failed to init ring buffer\n");
- goto e_err;
- }
- dev_notice(dev, "tee enabled\n");
- return 0;
- e_err:
- psp->tee_data = NULL;
- dev_notice(dev, "tee initialization failed\n");
- return ret;
- }
- void tee_dev_destroy(struct psp_device *psp)
- {
- struct psp_tee_device *tee = psp->tee_data;
- if (!tee)
- return;
- tee_destroy_ring(tee);
- }
- static int tee_submit_cmd(struct psp_tee_device *tee, enum tee_cmd_id cmd_id,
- void *buf, size_t len, struct tee_ring_cmd **resp)
- {
- struct tee_ring_cmd *cmd;
- int nloop = 1000, ret = 0;
- u32 rptr;
- *resp = NULL;
- mutex_lock(&tee->rb_mgr.mutex);
- /* Loop until empty entry found in ring buffer */
- do {
- /* Get pointer to ring buffer command entry */
- cmd = (struct tee_ring_cmd *)
- (tee->rb_mgr.ring_start + tee->rb_mgr.wptr);
- rptr = ioread32(tee->io_regs + tee->vdata->ring_rptr_reg);
- /* Check if ring buffer is full or command entry is waiting
- * for response from TEE
- */
- if (!(tee->rb_mgr.wptr + sizeof(struct tee_ring_cmd) == rptr ||
- cmd->flag == CMD_WAITING_FOR_RESPONSE))
- break;
- dev_dbg(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n",
- rptr, tee->rb_mgr.wptr);
- /* Wait if ring buffer is full or TEE is processing data */
- mutex_unlock(&tee->rb_mgr.mutex);
- schedule_timeout_interruptible(msecs_to_jiffies(10));
- mutex_lock(&tee->rb_mgr.mutex);
- } while (--nloop);
- if (!nloop &&
- (tee->rb_mgr.wptr + sizeof(struct tee_ring_cmd) == rptr ||
- cmd->flag == CMD_WAITING_FOR_RESPONSE)) {
- dev_err(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u response flag %u\n",
- rptr, tee->rb_mgr.wptr, cmd->flag);
- ret = -EBUSY;
- goto unlock;
- }
- /* Do not submit command if PSP got disabled while processing any
- * command in another thread
- */
- if (psp_dead) {
- ret = -EBUSY;
- goto unlock;
- }
- /* Write command data into ring buffer */
- cmd->cmd_id = cmd_id;
- cmd->cmd_state = TEE_CMD_STATE_INIT;
- memset(&cmd->buf[0], 0, sizeof(cmd->buf));
- memcpy(&cmd->buf[0], buf, len);
- /* Indicate driver is waiting for response */
- cmd->flag = CMD_WAITING_FOR_RESPONSE;
- /* Update local copy of write pointer */
- tee->rb_mgr.wptr += sizeof(struct tee_ring_cmd);
- if (tee->rb_mgr.wptr >= tee->rb_mgr.ring_size)
- tee->rb_mgr.wptr = 0;
- /* Trigger interrupt to Trusted OS */
- iowrite32(tee->rb_mgr.wptr, tee->io_regs + tee->vdata->ring_wptr_reg);
- /* The response is provided by Trusted OS in same
- * location as submitted data entry within ring buffer.
- */
- *resp = cmd;
- unlock:
- mutex_unlock(&tee->rb_mgr.mutex);
- return ret;
- }
- static int tee_wait_cmd_completion(struct psp_tee_device *tee,
- struct tee_ring_cmd *resp,
- unsigned int timeout)
- {
- /* ~1ms sleep per loop => nloop = timeout * 1000 */
- int nloop = timeout * 1000;
- while (--nloop) {
- if (resp->cmd_state == TEE_CMD_STATE_COMPLETED)
- return 0;
- usleep_range(1000, 1100);
- }
- dev_err(tee->dev, "tee: command 0x%x timed out, disabling PSP\n",
- resp->cmd_id);
- psp_dead = true;
- return -ETIMEDOUT;
- }
- int psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf, size_t len,
- u32 *status)
- {
- struct psp_device *psp = psp_get_master_device();
- struct psp_tee_device *tee;
- struct tee_ring_cmd *resp;
- int ret;
- if (!buf || !status || !len || len > sizeof(resp->buf))
- return -EINVAL;
- *status = 0;
- if (!psp || !psp->tee_data)
- return -ENODEV;
- if (psp_dead)
- return -EBUSY;
- tee = psp->tee_data;
- ret = tee_submit_cmd(tee, cmd_id, buf, len, &resp);
- if (ret)
- return ret;
- ret = tee_wait_cmd_completion(tee, resp, TEE_DEFAULT_RING_TIMEOUT);
- if (ret) {
- resp->flag = CMD_RESPONSE_TIMEDOUT;
- return ret;
- }
- memcpy(buf, &resp->buf[0], len);
- *status = resp->status;
- resp->flag = CMD_RESPONSE_COPIED;
- return 0;
- }
- EXPORT_SYMBOL(psp_tee_process_cmd);
- int psp_check_tee_status(void)
- {
- struct psp_device *psp = psp_get_master_device();
- if (!psp || !psp->tee_data)
- return -ENODEV;
- return 0;
- }
- EXPORT_SYMBOL(psp_check_tee_status);
- int tee_restore(struct psp_device *psp)
- {
- return tee_init_ring(psp->tee_data);
- }
|