diff options
Diffstat (limited to 'drivers/crypto/ccp/tee-dev.c')
| -rw-r--r-- | drivers/crypto/ccp/tee-dev.c | 57 | 
1 files changed, 39 insertions, 18 deletions
| diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c index 5e697a90ea7f..5c9d47f3be37 100644 --- a/drivers/crypto/ccp/tee-dev.c +++ b/drivers/crypto/ccp/tee-dev.c @@ -5,7 +5,7 @@   * Author: Rijo Thomas <Rijo-john.Thomas@amd.com>   * Author: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>   * - * Copyright 2019 Advanced Micro Devices, Inc. + * Copyright (C) 2019,2021 Advanced Micro Devices, Inc.   */  #include <linux/types.h> @@ -36,6 +36,7 @@ static int tee_alloc_ring(struct psp_tee_device *tee, int 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); @@ -244,41 +245,54 @@ 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; -	u32 rptr, wptr;  	int nloop = 1000, ret = 0; +	u32 rptr;  	*resp = NULL;  	mutex_lock(&tee->rb_mgr.mutex); -	wptr = tee->rb_mgr.wptr; - -	/* Check if ring buffer is full */ +	/* 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); -		if (!(wptr + sizeof(struct tee_ring_cmd) == rptr)) +		/* 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_info(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n", -			 rptr, wptr); +		dev_dbg(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n", +			rptr, tee->rb_mgr.wptr); -		/* Wait if ring buffer is full */ +		/* 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 && (wptr + sizeof(struct tee_ring_cmd) == rptr)) { -		dev_err(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n", -			rptr, wptr); +	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;  	} -	/* Pointer to empty data entry in ring buffer */ -	cmd = (struct tee_ring_cmd *)(tee->rb_mgr.ring_start + wptr); +	/* 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; @@ -286,6 +300,9 @@ static int tee_submit_cmd(struct psp_tee_device *tee, enum tee_cmd_id cmd_id,  	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) @@ -309,14 +326,14 @@ static int tee_wait_cmd_completion(struct psp_tee_device *tee,  				   struct tee_ring_cmd *resp,  				   unsigned int timeout)  { -	/* ~5ms sleep per loop => nloop = timeout * 200 */ -	int nloop = timeout * 200; +	/* ~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(5000, 5100); +		usleep_range(1000, 1100);  	}  	dev_err(tee->dev, "tee: command 0x%x timed out, disabling PSP\n", @@ -353,12 +370,16 @@ int psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf, size_t len,  		return ret;  	ret = tee_wait_cmd_completion(tee, resp, TEE_DEFAULT_TIMEOUT); -	if (ret) +	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); | 
