From deb62ed21a20b42e2b98daa14850ef95428bef1f Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Wed, 2 Dec 2015 23:40:16 -0800 Subject: [PATCH] qseecom: make change to support sg list entry number larger than 512 qseecom_send_modfd_cmd_64 converts non-contiguous ION memory fd to scatter-gather physical address list, and supports up to 512 SG list entries. Now, 512 is not enough if client wants to send large data in a fragmented system. In this change, if SG list entry number is larger than 512, we will allocate a new contiguous kernel buffer, then save all SG entries into this new buffer. Change-Id: Id90eefb98b63bf16db755dae8e1482e448090f47 Signed-off-by: Zhen Kong --- drivers/misc/qseecom.c | 85 ++++++++++++++++++++++++++++++++---- include/uapi/linux/qseecom.h | 18 ++++++++ 2 files changed, 94 insertions(+), 9 deletions(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index b21a85c37682..f9bb5bb720cc 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -66,7 +66,10 @@ #define QSEE_CE_CLK_100MHZ 100000000 #define CE_CLK_DIV 1000000 -#define QSEECOM_MAX_SG_ENTRY 512 +#define QSEECOM_MAX_SG_ENTRY 512 +#define QSEECOM_SG_ENTRY_MSG_BUF_SZ_64BIT \ + (QSEECOM_MAX_SG_ENTRY * SG_ENTRY_SZ_64BIT) + #define QSEECOM_INVALID_KEY_ID 0xff /* Save partition image hash for authentication check */ @@ -2926,6 +2929,53 @@ err: return -ENOMEM; } +static int __qseecom_allocate_sg_list_buffer(struct qseecom_dev_handle *data, + char *field, uint32_t fd_idx, struct sg_table *sg_ptr) +{ + struct scatterlist *sg = sg_ptr->sgl; + struct qseecom_sg_entry_64bit *sg_entry; + struct qseecom_sg_list_buf_hdr_64bit *buf_hdr; + void *buf; + uint i; + size_t size; + dma_addr_t coh_pmem; + + if (fd_idx >= MAX_ION_FD) { + pr_err("fd_idx [%d] is invalid\n", fd_idx); + return -ENOMEM; + } + buf_hdr = (struct qseecom_sg_list_buf_hdr_64bit *)field; + memset((void *)buf_hdr, 0, QSEECOM_SG_LIST_BUF_HDR_SZ_64BIT); + /* Allocate a contiguous kernel buffer */ + size = sg_ptr->nents * SG_ENTRY_SZ_64BIT; + size = (size + PAGE_SIZE) & PAGE_MASK; + buf = dma_alloc_coherent(qseecom.pdev, + size, &coh_pmem, GFP_KERNEL); + if (buf == NULL) { + pr_err("failed to alloc memory for sg buf\n"); + return -ENOMEM; + } + /* update qseecom_sg_list_buf_hdr_64bit */ + buf_hdr->version = QSEECOM_SG_LIST_BUF_FORMAT_VERSION_2; + buf_hdr->new_buf_phys_addr = coh_pmem; + buf_hdr->nents_total = sg_ptr->nents; + /* save the left sg entries into new allocated buf */ + sg_entry = (struct qseecom_sg_entry_64bit *)buf; + for (i = 0; i < sg_ptr->nents; i++) { + sg_entry->phys_addr = (uint64_t)sg_dma_address(sg); + sg_entry->len = sg->length; + sg_entry++; + sg = sg_next(sg); + } + + data->client.sec_buf_fd[fd_idx].is_sec_buf_fd = true; + data->client.sec_buf_fd[fd_idx].vbase = buf; + data->client.sec_buf_fd[fd_idx].pbase = coh_pmem; + data->client.sec_buf_fd[fd_idx].size = size; + + return 0; +} + static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, struct qseecom_dev_handle *data) { @@ -2994,10 +3044,26 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, goto err; } if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) { - pr_err("Num of scattered entries"); - pr_err(" (%d) is greater than max supported %d\n", + pr_warn("Num of scattered entries"); + pr_warn(" (%d) is greater than %d\n", sg_ptr->nents, QSEECOM_MAX_SG_ENTRY); - goto err; + if (cleanup) { + if (data->client.sec_buf_fd[i].is_sec_buf_fd && + data->client.sec_buf_fd[i].vbase) + dma_free_coherent(qseecom.pdev, + data->client.sec_buf_fd[i].size, + data->client.sec_buf_fd[i].vbase, + data->client.sec_buf_fd[i].pbase); + } else { + ret = __qseecom_allocate_sg_list_buffer(data, + field, i, sg_ptr); + if (ret) { + pr_err("Failed to allocate sg list buffer\n"); + goto err; + } + } + len = QSEECOM_SG_LIST_BUF_HDR_SZ_64BIT; + goto cleanup; } sg = sg_ptr->sgl; if (sg_ptr->nents == 1) { @@ -3017,10 +3083,10 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, (req->ifd_data[i].fd > 0)) { if ((req->cmd_req_len < - SG_ENTRY_SZ * sg_ptr->nents) || + SG_ENTRY_SZ_64BIT * sg_ptr->nents) || (req->ifd_data[i].cmd_buf_offset > - (req->cmd_req_len - - SG_ENTRY_SZ * sg_ptr->nents))) { + (req->cmd_req_len - + SG_ENTRY_SZ_64BIT * sg_ptr->nents))) { pr_err("Invalid offset = 0x%x\n", req->ifd_data[i].cmd_buf_offset); goto err; @@ -3030,10 +3096,10 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, (lstnr_resp->ifd_data[i].fd > 0)) { if ((lstnr_resp->resp_len < - SG_ENTRY_SZ * sg_ptr->nents) || + SG_ENTRY_SZ_64BIT * sg_ptr->nents) || (lstnr_resp->ifd_data[i].cmd_buf_offset > (lstnr_resp->resp_len - - SG_ENTRY_SZ * sg_ptr->nents))) { + SG_ENTRY_SZ_64BIT * sg_ptr->nents))) { goto err; } } @@ -3049,6 +3115,7 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, sg = sg_next(sg); } } +cleanup: if (cleanup) msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, diff --git a/include/uapi/linux/qseecom.h b/include/uapi/linux/qseecom.h index 4bdd7035bbf0..5c5761d690dd 100644 --- a/include/uapi/linux/qseecom.h +++ b/include/uapi/linux/qseecom.h @@ -233,6 +233,24 @@ struct qseecom_sg_entry_64bit { uint32_t len; } __attribute__ ((packed)); +/* + * sg list buf format version + * 1: Legacy format to support only 512 SG list entries + * 2: new format to support > 512 entries + */ +#define QSEECOM_SG_LIST_BUF_FORMAT_VERSION_1 1 +#define QSEECOM_SG_LIST_BUF_FORMAT_VERSION_2 2 + +struct qseecom_sg_list_buf_hdr_64bit { + struct qseecom_sg_entry_64bit blank_entry; /* must be all 0 */ + uint32_t version; /* sg list buf format version */ + uint64_t new_buf_phys_addr; /* PA of new buffer */ + uint32_t nents_total; /* Total number of SG entries */ +} __attribute__ ((packed)); + +#define QSEECOM_SG_LIST_BUF_HDR_SZ_64BIT \ + sizeof(struct qseecom_sg_list_buf_hdr_64bit) + #define MAX_CE_PIPE_PAIR_PER_UNIT 3 #define INVALID_CE_INFO_UNIT_NUM 0xffffffff