162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Provide TDMA helper functions used by cipher and hash algorithm 462306a36Sopenharmony_ci * implementations. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Author: Boris Brezillon <boris.brezillon@free-electrons.com> 762306a36Sopenharmony_ci * Author: Arnaud Ebalard <arno@natisbad.org> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This work is based on an initial version written by 1062306a36Sopenharmony_ci * Sebastian Andrzej Siewior < sebastian at breakpoint dot cc > 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "cesa.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cibool mv_cesa_req_dma_iter_next_transfer(struct mv_cesa_dma_iter *iter, 1662306a36Sopenharmony_ci struct mv_cesa_sg_dma_iter *sgiter, 1762306a36Sopenharmony_ci unsigned int len) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci if (!sgiter->sg) 2062306a36Sopenharmony_ci return false; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci sgiter->op_offset += len; 2362306a36Sopenharmony_ci sgiter->offset += len; 2462306a36Sopenharmony_ci if (sgiter->offset == sg_dma_len(sgiter->sg)) { 2562306a36Sopenharmony_ci if (sg_is_last(sgiter->sg)) 2662306a36Sopenharmony_ci return false; 2762306a36Sopenharmony_ci sgiter->offset = 0; 2862306a36Sopenharmony_ci sgiter->sg = sg_next(sgiter->sg); 2962306a36Sopenharmony_ci } 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci if (sgiter->op_offset == iter->op_len) 3262306a36Sopenharmony_ci return false; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci return true; 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_civoid mv_cesa_dma_step(struct mv_cesa_req *dreq) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct mv_cesa_engine *engine = dreq->engine; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci writel_relaxed(0, engine->regs + CESA_SA_CFG); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci mv_cesa_set_int_mask(engine, CESA_SA_INT_ACC0_IDMA_DONE); 4462306a36Sopenharmony_ci writel_relaxed(CESA_TDMA_DST_BURST_128B | CESA_TDMA_SRC_BURST_128B | 4562306a36Sopenharmony_ci CESA_TDMA_NO_BYTE_SWAP | CESA_TDMA_EN, 4662306a36Sopenharmony_ci engine->regs + CESA_TDMA_CONTROL); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci writel_relaxed(CESA_SA_CFG_ACT_CH0_IDMA | CESA_SA_CFG_MULTI_PKT | 4962306a36Sopenharmony_ci CESA_SA_CFG_CH0_W_IDMA | CESA_SA_CFG_PARA_DIS, 5062306a36Sopenharmony_ci engine->regs + CESA_SA_CFG); 5162306a36Sopenharmony_ci writel_relaxed(dreq->chain.first->cur_dma, 5262306a36Sopenharmony_ci engine->regs + CESA_TDMA_NEXT_ADDR); 5362306a36Sopenharmony_ci WARN_ON(readl(engine->regs + CESA_SA_CMD) & 5462306a36Sopenharmony_ci CESA_SA_CMD_EN_CESA_SA_ACCL0); 5562306a36Sopenharmony_ci writel(CESA_SA_CMD_EN_CESA_SA_ACCL0, engine->regs + CESA_SA_CMD); 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_civoid mv_cesa_dma_cleanup(struct mv_cesa_req *dreq) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct mv_cesa_tdma_desc *tdma; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci for (tdma = dreq->chain.first; tdma;) { 6362306a36Sopenharmony_ci struct mv_cesa_tdma_desc *old_tdma = tdma; 6462306a36Sopenharmony_ci u32 type = tdma->flags & CESA_TDMA_TYPE_MSK; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (type == CESA_TDMA_OP) 6762306a36Sopenharmony_ci dma_pool_free(cesa_dev->dma->op_pool, tdma->op, 6862306a36Sopenharmony_ci le32_to_cpu(tdma->src)); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci tdma = tdma->next; 7162306a36Sopenharmony_ci dma_pool_free(cesa_dev->dma->tdma_desc_pool, old_tdma, 7262306a36Sopenharmony_ci old_tdma->cur_dma); 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci dreq->chain.first = NULL; 7662306a36Sopenharmony_ci dreq->chain.last = NULL; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_civoid mv_cesa_dma_prepare(struct mv_cesa_req *dreq, 8062306a36Sopenharmony_ci struct mv_cesa_engine *engine) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci struct mv_cesa_tdma_desc *tdma; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci for (tdma = dreq->chain.first; tdma; tdma = tdma->next) { 8562306a36Sopenharmony_ci if (tdma->flags & CESA_TDMA_DST_IN_SRAM) 8662306a36Sopenharmony_ci tdma->dst = cpu_to_le32(tdma->dst_dma + engine->sram_dma); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (tdma->flags & CESA_TDMA_SRC_IN_SRAM) 8962306a36Sopenharmony_ci tdma->src = cpu_to_le32(tdma->src_dma + engine->sram_dma); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if ((tdma->flags & CESA_TDMA_TYPE_MSK) == CESA_TDMA_OP) 9262306a36Sopenharmony_ci mv_cesa_adjust_op(engine, tdma->op); 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_civoid mv_cesa_tdma_chain(struct mv_cesa_engine *engine, 9762306a36Sopenharmony_ci struct mv_cesa_req *dreq) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci if (engine->chain.first == NULL && engine->chain.last == NULL) { 10062306a36Sopenharmony_ci engine->chain.first = dreq->chain.first; 10162306a36Sopenharmony_ci engine->chain.last = dreq->chain.last; 10262306a36Sopenharmony_ci } else { 10362306a36Sopenharmony_ci struct mv_cesa_tdma_desc *last; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci last = engine->chain.last; 10662306a36Sopenharmony_ci last->next = dreq->chain.first; 10762306a36Sopenharmony_ci engine->chain.last = dreq->chain.last; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* 11062306a36Sopenharmony_ci * Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on 11162306a36Sopenharmony_ci * the last element of the current chain, or if the request 11262306a36Sopenharmony_ci * being queued needs the IV regs to be set before lauching 11362306a36Sopenharmony_ci * the request. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci if (!(last->flags & CESA_TDMA_BREAK_CHAIN) && 11662306a36Sopenharmony_ci !(dreq->chain.first->flags & CESA_TDMA_SET_STATE)) 11762306a36Sopenharmony_ci last->next_dma = cpu_to_le32(dreq->chain.first->cur_dma); 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ciint mv_cesa_tdma_process(struct mv_cesa_engine *engine, u32 status) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct crypto_async_request *req = NULL; 12462306a36Sopenharmony_ci struct mv_cesa_tdma_desc *tdma = NULL, *next = NULL; 12562306a36Sopenharmony_ci dma_addr_t tdma_cur; 12662306a36Sopenharmony_ci int res = 0; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci tdma_cur = readl(engine->regs + CESA_TDMA_CUR); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci for (tdma = engine->chain.first; tdma; tdma = next) { 13162306a36Sopenharmony_ci spin_lock_bh(&engine->lock); 13262306a36Sopenharmony_ci next = tdma->next; 13362306a36Sopenharmony_ci spin_unlock_bh(&engine->lock); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (tdma->flags & CESA_TDMA_END_OF_REQ) { 13662306a36Sopenharmony_ci struct crypto_async_request *backlog = NULL; 13762306a36Sopenharmony_ci struct mv_cesa_ctx *ctx; 13862306a36Sopenharmony_ci u32 current_status; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci spin_lock_bh(&engine->lock); 14162306a36Sopenharmony_ci /* 14262306a36Sopenharmony_ci * if req is NULL, this means we're processing the 14362306a36Sopenharmony_ci * request in engine->req. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci if (!req) 14662306a36Sopenharmony_ci req = engine->req; 14762306a36Sopenharmony_ci else 14862306a36Sopenharmony_ci req = mv_cesa_dequeue_req_locked(engine, 14962306a36Sopenharmony_ci &backlog); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Re-chaining to the next request */ 15262306a36Sopenharmony_ci engine->chain.first = tdma->next; 15362306a36Sopenharmony_ci tdma->next = NULL; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* If this is the last request, clear the chain */ 15662306a36Sopenharmony_ci if (engine->chain.first == NULL) 15762306a36Sopenharmony_ci engine->chain.last = NULL; 15862306a36Sopenharmony_ci spin_unlock_bh(&engine->lock); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci ctx = crypto_tfm_ctx(req->tfm); 16162306a36Sopenharmony_ci current_status = (tdma->cur_dma == tdma_cur) ? 16262306a36Sopenharmony_ci status : CESA_SA_INT_ACC0_IDMA_DONE; 16362306a36Sopenharmony_ci res = ctx->ops->process(req, current_status); 16462306a36Sopenharmony_ci ctx->ops->complete(req); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (res == 0) 16762306a36Sopenharmony_ci mv_cesa_engine_enqueue_complete_request(engine, 16862306a36Sopenharmony_ci req); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (backlog) 17162306a36Sopenharmony_ci crypto_request_complete(backlog, -EINPROGRESS); 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (res || tdma->cur_dma == tdma_cur) 17562306a36Sopenharmony_ci break; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* 17962306a36Sopenharmony_ci * Save the last request in error to engine->req, so that the core 18062306a36Sopenharmony_ci * knows which request was faulty 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci if (res) { 18362306a36Sopenharmony_ci spin_lock_bh(&engine->lock); 18462306a36Sopenharmony_ci engine->req = req; 18562306a36Sopenharmony_ci spin_unlock_bh(&engine->lock); 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci return res; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic struct mv_cesa_tdma_desc * 19262306a36Sopenharmony_cimv_cesa_dma_add_desc(struct mv_cesa_tdma_chain *chain, gfp_t flags) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct mv_cesa_tdma_desc *new_tdma = NULL; 19562306a36Sopenharmony_ci dma_addr_t dma_handle; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci new_tdma = dma_pool_zalloc(cesa_dev->dma->tdma_desc_pool, flags, 19862306a36Sopenharmony_ci &dma_handle); 19962306a36Sopenharmony_ci if (!new_tdma) 20062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci new_tdma->cur_dma = dma_handle; 20362306a36Sopenharmony_ci if (chain->last) { 20462306a36Sopenharmony_ci chain->last->next_dma = cpu_to_le32(dma_handle); 20562306a36Sopenharmony_ci chain->last->next = new_tdma; 20662306a36Sopenharmony_ci } else { 20762306a36Sopenharmony_ci chain->first = new_tdma; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci chain->last = new_tdma; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci return new_tdma; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ciint mv_cesa_dma_add_result_op(struct mv_cesa_tdma_chain *chain, dma_addr_t src, 21662306a36Sopenharmony_ci u32 size, u32 flags, gfp_t gfp_flags) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci struct mv_cesa_tdma_desc *tdma, *op_desc; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci tdma = mv_cesa_dma_add_desc(chain, gfp_flags); 22162306a36Sopenharmony_ci if (IS_ERR(tdma)) 22262306a36Sopenharmony_ci return PTR_ERR(tdma); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* We re-use an existing op_desc object to retrieve the context 22562306a36Sopenharmony_ci * and result instead of allocating a new one. 22662306a36Sopenharmony_ci * There is at least one object of this type in a CESA crypto 22762306a36Sopenharmony_ci * req, just pick the first one in the chain. 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_ci for (op_desc = chain->first; op_desc; op_desc = op_desc->next) { 23062306a36Sopenharmony_ci u32 type = op_desc->flags & CESA_TDMA_TYPE_MSK; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (type == CESA_TDMA_OP) 23362306a36Sopenharmony_ci break; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (!op_desc) 23762306a36Sopenharmony_ci return -EIO; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci tdma->byte_cnt = cpu_to_le32(size | BIT(31)); 24062306a36Sopenharmony_ci tdma->src_dma = src; 24162306a36Sopenharmony_ci tdma->dst_dma = op_desc->src_dma; 24262306a36Sopenharmony_ci tdma->op = op_desc->op; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci flags &= (CESA_TDMA_DST_IN_SRAM | CESA_TDMA_SRC_IN_SRAM); 24562306a36Sopenharmony_ci tdma->flags = flags | CESA_TDMA_RESULT; 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistruct mv_cesa_op_ctx *mv_cesa_dma_add_op(struct mv_cesa_tdma_chain *chain, 25062306a36Sopenharmony_ci const struct mv_cesa_op_ctx *op_templ, 25162306a36Sopenharmony_ci bool skip_ctx, 25262306a36Sopenharmony_ci gfp_t flags) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct mv_cesa_tdma_desc *tdma; 25562306a36Sopenharmony_ci struct mv_cesa_op_ctx *op; 25662306a36Sopenharmony_ci dma_addr_t dma_handle; 25762306a36Sopenharmony_ci unsigned int size; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci tdma = mv_cesa_dma_add_desc(chain, flags); 26062306a36Sopenharmony_ci if (IS_ERR(tdma)) 26162306a36Sopenharmony_ci return ERR_CAST(tdma); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci op = dma_pool_alloc(cesa_dev->dma->op_pool, flags, &dma_handle); 26462306a36Sopenharmony_ci if (!op) 26562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci *op = *op_templ; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci size = skip_ctx ? sizeof(op->desc) : sizeof(*op); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci tdma = chain->last; 27262306a36Sopenharmony_ci tdma->op = op; 27362306a36Sopenharmony_ci tdma->byte_cnt = cpu_to_le32(size | BIT(31)); 27462306a36Sopenharmony_ci tdma->src = cpu_to_le32(dma_handle); 27562306a36Sopenharmony_ci tdma->dst_dma = CESA_SA_CFG_SRAM_OFFSET; 27662306a36Sopenharmony_ci tdma->flags = CESA_TDMA_DST_IN_SRAM | CESA_TDMA_OP; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return op; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ciint mv_cesa_dma_add_data_transfer(struct mv_cesa_tdma_chain *chain, 28262306a36Sopenharmony_ci dma_addr_t dst, dma_addr_t src, u32 size, 28362306a36Sopenharmony_ci u32 flags, gfp_t gfp_flags) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct mv_cesa_tdma_desc *tdma; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci tdma = mv_cesa_dma_add_desc(chain, gfp_flags); 28862306a36Sopenharmony_ci if (IS_ERR(tdma)) 28962306a36Sopenharmony_ci return PTR_ERR(tdma); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci tdma->byte_cnt = cpu_to_le32(size | BIT(31)); 29262306a36Sopenharmony_ci tdma->src_dma = src; 29362306a36Sopenharmony_ci tdma->dst_dma = dst; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci flags &= (CESA_TDMA_DST_IN_SRAM | CESA_TDMA_SRC_IN_SRAM); 29662306a36Sopenharmony_ci tdma->flags = flags | CESA_TDMA_DATA; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return 0; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ciint mv_cesa_dma_add_dummy_launch(struct mv_cesa_tdma_chain *chain, gfp_t flags) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct mv_cesa_tdma_desc *tdma; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci tdma = mv_cesa_dma_add_desc(chain, flags); 30662306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(tdma); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ciint mv_cesa_dma_add_dummy_end(struct mv_cesa_tdma_chain *chain, gfp_t flags) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct mv_cesa_tdma_desc *tdma; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci tdma = mv_cesa_dma_add_desc(chain, flags); 31462306a36Sopenharmony_ci if (IS_ERR(tdma)) 31562306a36Sopenharmony_ci return PTR_ERR(tdma); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci tdma->byte_cnt = cpu_to_le32(BIT(31)); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci return 0; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ciint mv_cesa_dma_add_op_transfers(struct mv_cesa_tdma_chain *chain, 32362306a36Sopenharmony_ci struct mv_cesa_dma_iter *dma_iter, 32462306a36Sopenharmony_ci struct mv_cesa_sg_dma_iter *sgiter, 32562306a36Sopenharmony_ci gfp_t gfp_flags) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci u32 flags = sgiter->dir == DMA_TO_DEVICE ? 32862306a36Sopenharmony_ci CESA_TDMA_DST_IN_SRAM : CESA_TDMA_SRC_IN_SRAM; 32962306a36Sopenharmony_ci unsigned int len; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci do { 33262306a36Sopenharmony_ci dma_addr_t dst, src; 33362306a36Sopenharmony_ci int ret; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci len = mv_cesa_req_dma_iter_transfer_len(dma_iter, sgiter); 33662306a36Sopenharmony_ci if (sgiter->dir == DMA_TO_DEVICE) { 33762306a36Sopenharmony_ci dst = CESA_SA_DATA_SRAM_OFFSET + sgiter->op_offset; 33862306a36Sopenharmony_ci src = sg_dma_address(sgiter->sg) + sgiter->offset; 33962306a36Sopenharmony_ci } else { 34062306a36Sopenharmony_ci dst = sg_dma_address(sgiter->sg) + sgiter->offset; 34162306a36Sopenharmony_ci src = CESA_SA_DATA_SRAM_OFFSET + sgiter->op_offset; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci ret = mv_cesa_dma_add_data_transfer(chain, dst, src, len, 34562306a36Sopenharmony_ci flags, gfp_flags); 34662306a36Sopenharmony_ci if (ret) 34762306a36Sopenharmony_ci return ret; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci } while (mv_cesa_req_dma_iter_next_transfer(dma_iter, sgiter, len)); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return 0; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cisize_t mv_cesa_sg_copy(struct mv_cesa_engine *engine, 35562306a36Sopenharmony_ci struct scatterlist *sgl, unsigned int nents, 35662306a36Sopenharmony_ci unsigned int sram_off, size_t buflen, off_t skip, 35762306a36Sopenharmony_ci bool to_sram) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci unsigned int sg_flags = SG_MITER_ATOMIC; 36062306a36Sopenharmony_ci struct sg_mapping_iter miter; 36162306a36Sopenharmony_ci unsigned int offset = 0; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (to_sram) 36462306a36Sopenharmony_ci sg_flags |= SG_MITER_FROM_SG; 36562306a36Sopenharmony_ci else 36662306a36Sopenharmony_ci sg_flags |= SG_MITER_TO_SG; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci sg_miter_start(&miter, sgl, nents, sg_flags); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (!sg_miter_skip(&miter, skip)) 37162306a36Sopenharmony_ci return 0; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci while ((offset < buflen) && sg_miter_next(&miter)) { 37462306a36Sopenharmony_ci unsigned int len; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci len = min(miter.length, buflen - offset); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (to_sram) { 37962306a36Sopenharmony_ci if (engine->pool) 38062306a36Sopenharmony_ci memcpy(engine->sram_pool + sram_off + offset, 38162306a36Sopenharmony_ci miter.addr, len); 38262306a36Sopenharmony_ci else 38362306a36Sopenharmony_ci memcpy_toio(engine->sram + sram_off + offset, 38462306a36Sopenharmony_ci miter.addr, len); 38562306a36Sopenharmony_ci } else { 38662306a36Sopenharmony_ci if (engine->pool) 38762306a36Sopenharmony_ci memcpy(miter.addr, 38862306a36Sopenharmony_ci engine->sram_pool + sram_off + offset, 38962306a36Sopenharmony_ci len); 39062306a36Sopenharmony_ci else 39162306a36Sopenharmony_ci memcpy_fromio(miter.addr, 39262306a36Sopenharmony_ci engine->sram + sram_off + offset, 39362306a36Sopenharmony_ci len); 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci offset += len; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci sg_miter_stop(&miter); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return offset; 40262306a36Sopenharmony_ci} 403