From: Md Sadre Alam <quic_mdalam@xxxxxxxxxxx> Add BAM/DMA support infrastructure. These interfaces will allow us to port the algorithm implementations to use DMA for transaction with BAM locking. Signed-off-by: Md Sadre Alam <quic_mdalam@xxxxxxxxxxx> [Bartosz: remove unused code, rework coding style, shuffle code around for better readability, simplify resource management, many other tweaks] Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@xxxxxxxxxx> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@xxxxxxxxxx> --- drivers/crypto/qce/dma.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/crypto/qce/dma.h | 17 ++++++ 2 files changed, 156 insertions(+) diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c index 6ac2efb7c2f7..71b191944e3f 100644 --- a/drivers/crypto/qce/dma.c +++ b/drivers/crypto/qce/dma.c @@ -5,10 +5,135 @@ #include <linux/device.h> #include <linux/dmaengine.h> +#include <linux/dma-mapping.h> #include <crypto/scatterwalk.h> +#include "core.h" #include "dma.h" +struct qce_bam_transaction { + struct bam_cmd_element qce_bam_ce[QCE_BAM_CMD_ELEMENT_SIZE]; + struct scatterlist qce_reg_write_sgl[QCE_BAM_CMD_SGL_SIZE]; + struct qce_desc_info *qce_desc; + u32 qce_bam_ce_index; + u32 qce_pre_bam_ce_index; + u32 qce_write_sgl_cnt; +}; + +void qce_clear_bam_transaction(struct qce_device *qce) +{ + struct qce_bam_transaction *qce_bam_txn = qce->dma.qce_bam_txn; + + memset(&qce_bam_txn->qce_bam_ce_index, 0, sizeof(u32) * 8); +} + +static int qce_dma_prep_cmd_sg(struct qce_device *qce, struct dma_chan *chan, + struct scatterlist *qce_bam_sgl, + int qce_sgl_cnt, unsigned long flags, + enum dma_transfer_direction dir_eng, + dma_async_tx_callback cb, void *cb_param) +{ + struct dma_async_tx_descriptor *dma_desc; + struct qce_desc_info *desc; + dma_cookie_t cookie; + + desc = qce->dma.qce_bam_txn->qce_desc; + + if (dir_eng == DMA_MEM_TO_DEV) + desc->dir = DMA_TO_DEVICE; + if (dir_eng == DMA_DEV_TO_MEM) + desc->dir = DMA_FROM_DEVICE; + + if (!qce_bam_sgl || !qce_sgl_cnt) + return -EINVAL; + + if (!dma_map_sg(qce->dev, qce_bam_sgl, + qce_sgl_cnt, desc->dir)) { + dev_err(qce->dev, "failure in mapping sgl for cmd desc\n"); + return -ENOMEM; + } + + dma_desc = dmaengine_prep_slave_sg(chan, qce_bam_sgl, qce_sgl_cnt, + dir_eng, flags); + if (!dma_desc) { + dev_err(qce->dev, "failed to prepare the command descriptor\n"); + dma_unmap_sg(qce->dev, qce_bam_sgl, qce_sgl_cnt, desc->dir); + kfree(desc); + return -EINVAL; + } + + desc->dma_desc = dma_desc; + desc->dma_desc->callback = cb; + desc->dma_desc->callback_param = cb_param; + + cookie = dmaengine_submit(desc->dma_desc); + + return dma_submit_error(cookie); +} + +int qce_submit_cmd_desc(struct qce_device *qce, unsigned long flags) +{ + struct qce_bam_transaction *qce_bam_txn = qce->dma.qce_bam_txn; + struct dma_chan *chan = qce->dma.rxchan; + unsigned long desc_flags; + int ret = 0; + + desc_flags = DMA_PREP_CMD; + + /* + * The HPG recommends always using the consumer pipe for command + * descriptors. + */ + if (qce_bam_txn->qce_write_sgl_cnt) + ret = qce_dma_prep_cmd_sg(qce, chan, qce_bam_txn->qce_reg_write_sgl, + qce_bam_txn->qce_write_sgl_cnt, + desc_flags, DMA_MEM_TO_DEV, + NULL, NULL); + if (ret) { + dev_err(qce->dev, + "error while submitting the command descriptor for TX: %d\n", + ret); + return ret; + } + + qce_dma_issue_pending(&qce->dma); + + if (qce_bam_txn->qce_write_sgl_cnt) + dma_unmap_sg(qce->dev, qce_bam_txn->qce_reg_write_sgl, + qce_bam_txn->qce_write_sgl_cnt, + DMA_TO_DEVICE); + + return ret; +} + +static __maybe_unused void +qce_prep_dma_command_desc(struct qce_device *qce, struct qce_dma_data *dma, + unsigned int addr, void *buff) +{ + struct qce_bam_transaction *qce_bam_txn = dma->qce_bam_txn; + struct bam_cmd_element *qce_bam_ce_buffer; + int qce_bam_ce_size, cnt, index; + + index = qce_bam_txn->qce_bam_ce_index; + qce_bam_ce_buffer = &qce_bam_txn->qce_bam_ce[index]; + bam_prep_ce_le32(qce_bam_ce_buffer, addr, BAM_WRITE_COMMAND, + *((__le32 *)buff)); + + cnt = qce_bam_txn->qce_write_sgl_cnt; + qce_bam_ce_buffer = + &qce_bam_txn->qce_bam_ce[qce_bam_txn->qce_pre_bam_ce_index]; + ++qce_bam_txn->qce_bam_ce_index; + qce_bam_ce_size = (qce_bam_txn->qce_bam_ce_index - + qce_bam_txn->qce_pre_bam_ce_index) * + sizeof(struct bam_cmd_element); + + sg_set_buf(&qce_bam_txn->qce_reg_write_sgl[cnt], qce_bam_ce_buffer, + qce_bam_ce_size); + + ++qce_bam_txn->qce_write_sgl_cnt; + qce_bam_txn->qce_pre_bam_ce_index = qce_bam_txn->qce_bam_ce_index; +} + static void qce_dma_release(void *data) { struct qce_dma_data *dma = data; @@ -19,6 +144,7 @@ static void qce_dma_release(void *data) int devm_qce_dma_request(struct device *dev, struct qce_dma_data *dma) { + struct qce_bam_transaction *qce_bam_txn; int ret; dma->txchan = dma_request_chan(dev, "tx"); @@ -43,6 +169,19 @@ int devm_qce_dma_request(struct device *dev, struct qce_dma_data *dma) dma->ignore_buf = dma->result_buf + QCE_RESULT_BUF_SZ; + dma->qce_bam_txn = devm_kmalloc(dev, sizeof(*qce_bam_txn), GFP_KERNEL); + if (!dma->qce_bam_txn) + return -ENOMEM; + + dma->qce_bam_txn->qce_desc = devm_kzalloc(dev, + sizeof(*dma->qce_bam_txn->qce_desc), + GFP_KERNEL); + if (!dma->qce_bam_txn->qce_desc) + return -ENOMEM; + + sg_init_table(dma->qce_bam_txn->qce_reg_write_sgl, + QCE_BAM_CMD_SGL_SIZE); + return 0; } diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h index 31629185000e..7d9d58b414ed 100644 --- a/drivers/crypto/qce/dma.h +++ b/drivers/crypto/qce/dma.h @@ -6,14 +6,22 @@ #ifndef _DMA_H_ #define _DMA_H_ +#include <linux/dma/qcom_bam_dma.h> #include <linux/dmaengine.h> +struct qce_device; + /* maximum data transfer block size between BAM and CE */ #define QCE_BAM_BURST_SIZE 64 #define QCE_AUTHIV_REGS_CNT 16 #define QCE_AUTH_BYTECOUNT_REGS_CNT 4 #define QCE_CNTRIV_REGS_CNT 4 +#define QCE_BAM_CMD_SGL_SIZE 64 +#define QCE_BAM_CMD_ELEMENT_SIZE 64 +#define QCE_DMA_DESC_FLAG_BAM_NWD (0x0004) +#define QCE_MAX_REG_READ 8 + struct qce_result_dump { u32 auth_iv[QCE_AUTHIV_REGS_CNT]; @@ -31,9 +39,15 @@ struct qce_dma_data { struct dma_chan *txchan; struct dma_chan *rxchan; struct qce_result_dump *result_buf; + struct qce_bam_transaction *qce_bam_txn; void *ignore_buf; }; +struct qce_desc_info { + struct dma_async_tx_descriptor *dma_desc; + enum dma_data_direction dir; +}; + int devm_qce_dma_request(struct device *dev, struct qce_dma_data *dma); int qce_dma_prep_sgs(struct qce_dma_data *dma, struct scatterlist *sg_in, int in_ents, struct scatterlist *sg_out, int out_ents, @@ -44,4 +58,7 @@ struct scatterlist * qce_sgtable_add(struct sg_table *sgt, struct scatterlist *sg_add, unsigned int max_len); +void qce_clear_bam_transaction(struct qce_device *qce); +int qce_submit_cmd_desc(struct qce_device *qce, unsigned long flags); + #endif /* _DMA_H_ */ -- 2.45.2