tdma.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Provide TDMA helper functions used by cipher and hash algorithm
  4. * implementations.
  5. *
  6. * Author: Boris Brezillon <[email protected]>
  7. * Author: Arnaud Ebalard <[email protected]>
  8. *
  9. * This work is based on an initial version written by
  10. * Sebastian Andrzej Siewior < sebastian at breakpoint dot cc >
  11. */
  12. #include "cesa.h"
  13. bool mv_cesa_req_dma_iter_next_transfer(struct mv_cesa_dma_iter *iter,
  14. struct mv_cesa_sg_dma_iter *sgiter,
  15. unsigned int len)
  16. {
  17. if (!sgiter->sg)
  18. return false;
  19. sgiter->op_offset += len;
  20. sgiter->offset += len;
  21. if (sgiter->offset == sg_dma_len(sgiter->sg)) {
  22. if (sg_is_last(sgiter->sg))
  23. return false;
  24. sgiter->offset = 0;
  25. sgiter->sg = sg_next(sgiter->sg);
  26. }
  27. if (sgiter->op_offset == iter->op_len)
  28. return false;
  29. return true;
  30. }
  31. void mv_cesa_dma_step(struct mv_cesa_req *dreq)
  32. {
  33. struct mv_cesa_engine *engine = dreq->engine;
  34. writel_relaxed(0, engine->regs + CESA_SA_CFG);
  35. mv_cesa_set_int_mask(engine, CESA_SA_INT_ACC0_IDMA_DONE);
  36. writel_relaxed(CESA_TDMA_DST_BURST_128B | CESA_TDMA_SRC_BURST_128B |
  37. CESA_TDMA_NO_BYTE_SWAP | CESA_TDMA_EN,
  38. engine->regs + CESA_TDMA_CONTROL);
  39. writel_relaxed(CESA_SA_CFG_ACT_CH0_IDMA | CESA_SA_CFG_MULTI_PKT |
  40. CESA_SA_CFG_CH0_W_IDMA | CESA_SA_CFG_PARA_DIS,
  41. engine->regs + CESA_SA_CFG);
  42. writel_relaxed(dreq->chain.first->cur_dma,
  43. engine->regs + CESA_TDMA_NEXT_ADDR);
  44. WARN_ON(readl(engine->regs + CESA_SA_CMD) &
  45. CESA_SA_CMD_EN_CESA_SA_ACCL0);
  46. writel(CESA_SA_CMD_EN_CESA_SA_ACCL0, engine->regs + CESA_SA_CMD);
  47. }
  48. void mv_cesa_dma_cleanup(struct mv_cesa_req *dreq)
  49. {
  50. struct mv_cesa_tdma_desc *tdma;
  51. for (tdma = dreq->chain.first; tdma;) {
  52. struct mv_cesa_tdma_desc *old_tdma = tdma;
  53. u32 type = tdma->flags & CESA_TDMA_TYPE_MSK;
  54. if (type == CESA_TDMA_OP)
  55. dma_pool_free(cesa_dev->dma->op_pool, tdma->op,
  56. le32_to_cpu(tdma->src));
  57. tdma = tdma->next;
  58. dma_pool_free(cesa_dev->dma->tdma_desc_pool, old_tdma,
  59. old_tdma->cur_dma);
  60. }
  61. dreq->chain.first = NULL;
  62. dreq->chain.last = NULL;
  63. }
  64. void mv_cesa_dma_prepare(struct mv_cesa_req *dreq,
  65. struct mv_cesa_engine *engine)
  66. {
  67. struct mv_cesa_tdma_desc *tdma;
  68. for (tdma = dreq->chain.first; tdma; tdma = tdma->next) {
  69. if (tdma->flags & CESA_TDMA_DST_IN_SRAM)
  70. tdma->dst = cpu_to_le32(tdma->dst_dma + engine->sram_dma);
  71. if (tdma->flags & CESA_TDMA_SRC_IN_SRAM)
  72. tdma->src = cpu_to_le32(tdma->src_dma + engine->sram_dma);
  73. if ((tdma->flags & CESA_TDMA_TYPE_MSK) == CESA_TDMA_OP)
  74. mv_cesa_adjust_op(engine, tdma->op);
  75. }
  76. }
  77. void mv_cesa_tdma_chain(struct mv_cesa_engine *engine,
  78. struct mv_cesa_req *dreq)
  79. {
  80. if (engine->chain.first == NULL && engine->chain.last == NULL) {
  81. engine->chain.first = dreq->chain.first;
  82. engine->chain.last = dreq->chain.last;
  83. } else {
  84. struct mv_cesa_tdma_desc *last;
  85. last = engine->chain.last;
  86. last->next = dreq->chain.first;
  87. engine->chain.last = dreq->chain.last;
  88. /*
  89. * Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on
  90. * the last element of the current chain, or if the request
  91. * being queued needs the IV regs to be set before lauching
  92. * the request.
  93. */
  94. if (!(last->flags & CESA_TDMA_BREAK_CHAIN) &&
  95. !(dreq->chain.first->flags & CESA_TDMA_SET_STATE))
  96. last->next_dma = cpu_to_le32(dreq->chain.first->cur_dma);
  97. }
  98. }
  99. int mv_cesa_tdma_process(struct mv_cesa_engine *engine, u32 status)
  100. {
  101. struct crypto_async_request *req = NULL;
  102. struct mv_cesa_tdma_desc *tdma = NULL, *next = NULL;
  103. dma_addr_t tdma_cur;
  104. int res = 0;
  105. tdma_cur = readl(engine->regs + CESA_TDMA_CUR);
  106. for (tdma = engine->chain.first; tdma; tdma = next) {
  107. spin_lock_bh(&engine->lock);
  108. next = tdma->next;
  109. spin_unlock_bh(&engine->lock);
  110. if (tdma->flags & CESA_TDMA_END_OF_REQ) {
  111. struct crypto_async_request *backlog = NULL;
  112. struct mv_cesa_ctx *ctx;
  113. u32 current_status;
  114. spin_lock_bh(&engine->lock);
  115. /*
  116. * if req is NULL, this means we're processing the
  117. * request in engine->req.
  118. */
  119. if (!req)
  120. req = engine->req;
  121. else
  122. req = mv_cesa_dequeue_req_locked(engine,
  123. &backlog);
  124. /* Re-chaining to the next request */
  125. engine->chain.first = tdma->next;
  126. tdma->next = NULL;
  127. /* If this is the last request, clear the chain */
  128. if (engine->chain.first == NULL)
  129. engine->chain.last = NULL;
  130. spin_unlock_bh(&engine->lock);
  131. ctx = crypto_tfm_ctx(req->tfm);
  132. current_status = (tdma->cur_dma == tdma_cur) ?
  133. status : CESA_SA_INT_ACC0_IDMA_DONE;
  134. res = ctx->ops->process(req, current_status);
  135. ctx->ops->complete(req);
  136. if (res == 0)
  137. mv_cesa_engine_enqueue_complete_request(engine,
  138. req);
  139. if (backlog)
  140. backlog->complete(backlog, -EINPROGRESS);
  141. }
  142. if (res || tdma->cur_dma == tdma_cur)
  143. break;
  144. }
  145. /*
  146. * Save the last request in error to engine->req, so that the core
  147. * knows which request was faulty
  148. */
  149. if (res) {
  150. spin_lock_bh(&engine->lock);
  151. engine->req = req;
  152. spin_unlock_bh(&engine->lock);
  153. }
  154. return res;
  155. }
  156. static struct mv_cesa_tdma_desc *
  157. mv_cesa_dma_add_desc(struct mv_cesa_tdma_chain *chain, gfp_t flags)
  158. {
  159. struct mv_cesa_tdma_desc *new_tdma = NULL;
  160. dma_addr_t dma_handle;
  161. new_tdma = dma_pool_zalloc(cesa_dev->dma->tdma_desc_pool, flags,
  162. &dma_handle);
  163. if (!new_tdma)
  164. return ERR_PTR(-ENOMEM);
  165. new_tdma->cur_dma = dma_handle;
  166. if (chain->last) {
  167. chain->last->next_dma = cpu_to_le32(dma_handle);
  168. chain->last->next = new_tdma;
  169. } else {
  170. chain->first = new_tdma;
  171. }
  172. chain->last = new_tdma;
  173. return new_tdma;
  174. }
  175. int mv_cesa_dma_add_result_op(struct mv_cesa_tdma_chain *chain, dma_addr_t src,
  176. u32 size, u32 flags, gfp_t gfp_flags)
  177. {
  178. struct mv_cesa_tdma_desc *tdma, *op_desc;
  179. tdma = mv_cesa_dma_add_desc(chain, gfp_flags);
  180. if (IS_ERR(tdma))
  181. return PTR_ERR(tdma);
  182. /* We re-use an existing op_desc object to retrieve the context
  183. * and result instead of allocating a new one.
  184. * There is at least one object of this type in a CESA crypto
  185. * req, just pick the first one in the chain.
  186. */
  187. for (op_desc = chain->first; op_desc; op_desc = op_desc->next) {
  188. u32 type = op_desc->flags & CESA_TDMA_TYPE_MSK;
  189. if (type == CESA_TDMA_OP)
  190. break;
  191. }
  192. if (!op_desc)
  193. return -EIO;
  194. tdma->byte_cnt = cpu_to_le32(size | BIT(31));
  195. tdma->src_dma = src;
  196. tdma->dst_dma = op_desc->src_dma;
  197. tdma->op = op_desc->op;
  198. flags &= (CESA_TDMA_DST_IN_SRAM | CESA_TDMA_SRC_IN_SRAM);
  199. tdma->flags = flags | CESA_TDMA_RESULT;
  200. return 0;
  201. }
  202. struct mv_cesa_op_ctx *mv_cesa_dma_add_op(struct mv_cesa_tdma_chain *chain,
  203. const struct mv_cesa_op_ctx *op_templ,
  204. bool skip_ctx,
  205. gfp_t flags)
  206. {
  207. struct mv_cesa_tdma_desc *tdma;
  208. struct mv_cesa_op_ctx *op;
  209. dma_addr_t dma_handle;
  210. unsigned int size;
  211. tdma = mv_cesa_dma_add_desc(chain, flags);
  212. if (IS_ERR(tdma))
  213. return ERR_CAST(tdma);
  214. op = dma_pool_alloc(cesa_dev->dma->op_pool, flags, &dma_handle);
  215. if (!op)
  216. return ERR_PTR(-ENOMEM);
  217. *op = *op_templ;
  218. size = skip_ctx ? sizeof(op->desc) : sizeof(*op);
  219. tdma = chain->last;
  220. tdma->op = op;
  221. tdma->byte_cnt = cpu_to_le32(size | BIT(31));
  222. tdma->src = cpu_to_le32(dma_handle);
  223. tdma->dst_dma = CESA_SA_CFG_SRAM_OFFSET;
  224. tdma->flags = CESA_TDMA_DST_IN_SRAM | CESA_TDMA_OP;
  225. return op;
  226. }
  227. int mv_cesa_dma_add_data_transfer(struct mv_cesa_tdma_chain *chain,
  228. dma_addr_t dst, dma_addr_t src, u32 size,
  229. u32 flags, gfp_t gfp_flags)
  230. {
  231. struct mv_cesa_tdma_desc *tdma;
  232. tdma = mv_cesa_dma_add_desc(chain, gfp_flags);
  233. if (IS_ERR(tdma))
  234. return PTR_ERR(tdma);
  235. tdma->byte_cnt = cpu_to_le32(size | BIT(31));
  236. tdma->src_dma = src;
  237. tdma->dst_dma = dst;
  238. flags &= (CESA_TDMA_DST_IN_SRAM | CESA_TDMA_SRC_IN_SRAM);
  239. tdma->flags = flags | CESA_TDMA_DATA;
  240. return 0;
  241. }
  242. int mv_cesa_dma_add_dummy_launch(struct mv_cesa_tdma_chain *chain, gfp_t flags)
  243. {
  244. struct mv_cesa_tdma_desc *tdma;
  245. tdma = mv_cesa_dma_add_desc(chain, flags);
  246. return PTR_ERR_OR_ZERO(tdma);
  247. }
  248. int mv_cesa_dma_add_dummy_end(struct mv_cesa_tdma_chain *chain, gfp_t flags)
  249. {
  250. struct mv_cesa_tdma_desc *tdma;
  251. tdma = mv_cesa_dma_add_desc(chain, flags);
  252. if (IS_ERR(tdma))
  253. return PTR_ERR(tdma);
  254. tdma->byte_cnt = cpu_to_le32(BIT(31));
  255. return 0;
  256. }
  257. int mv_cesa_dma_add_op_transfers(struct mv_cesa_tdma_chain *chain,
  258. struct mv_cesa_dma_iter *dma_iter,
  259. struct mv_cesa_sg_dma_iter *sgiter,
  260. gfp_t gfp_flags)
  261. {
  262. u32 flags = sgiter->dir == DMA_TO_DEVICE ?
  263. CESA_TDMA_DST_IN_SRAM : CESA_TDMA_SRC_IN_SRAM;
  264. unsigned int len;
  265. do {
  266. dma_addr_t dst, src;
  267. int ret;
  268. len = mv_cesa_req_dma_iter_transfer_len(dma_iter, sgiter);
  269. if (sgiter->dir == DMA_TO_DEVICE) {
  270. dst = CESA_SA_DATA_SRAM_OFFSET + sgiter->op_offset;
  271. src = sg_dma_address(sgiter->sg) + sgiter->offset;
  272. } else {
  273. dst = sg_dma_address(sgiter->sg) + sgiter->offset;
  274. src = CESA_SA_DATA_SRAM_OFFSET + sgiter->op_offset;
  275. }
  276. ret = mv_cesa_dma_add_data_transfer(chain, dst, src, len,
  277. flags, gfp_flags);
  278. if (ret)
  279. return ret;
  280. } while (mv_cesa_req_dma_iter_next_transfer(dma_iter, sgiter, len));
  281. return 0;
  282. }
  283. size_t mv_cesa_sg_copy(struct mv_cesa_engine *engine,
  284. struct scatterlist *sgl, unsigned int nents,
  285. unsigned int sram_off, size_t buflen, off_t skip,
  286. bool to_sram)
  287. {
  288. unsigned int sg_flags = SG_MITER_ATOMIC;
  289. struct sg_mapping_iter miter;
  290. unsigned int offset = 0;
  291. if (to_sram)
  292. sg_flags |= SG_MITER_FROM_SG;
  293. else
  294. sg_flags |= SG_MITER_TO_SG;
  295. sg_miter_start(&miter, sgl, nents, sg_flags);
  296. if (!sg_miter_skip(&miter, skip))
  297. return 0;
  298. while ((offset < buflen) && sg_miter_next(&miter)) {
  299. unsigned int len;
  300. len = min(miter.length, buflen - offset);
  301. if (to_sram) {
  302. if (engine->pool)
  303. memcpy(engine->sram_pool + sram_off + offset,
  304. miter.addr, len);
  305. else
  306. memcpy_toio(engine->sram + sram_off + offset,
  307. miter.addr, len);
  308. } else {
  309. if (engine->pool)
  310. memcpy(miter.addr,
  311. engine->sram_pool + sram_off + offset,
  312. len);
  313. else
  314. memcpy_fromio(miter.addr,
  315. engine->sram + sram_off + offset,
  316. len);
  317. }
  318. offset += len;
  319. }
  320. sg_miter_stop(&miter);
  321. return offset;
  322. }