safexcel_ring.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2017 Marvell
  4. *
  5. * Antoine Tenart <[email protected]>
  6. */
  7. #include <linux/dma-mapping.h>
  8. #include <linux/spinlock.h>
  9. #include "safexcel.h"
  10. int safexcel_init_ring_descriptors(struct safexcel_crypto_priv *priv,
  11. struct safexcel_desc_ring *cdr,
  12. struct safexcel_desc_ring *rdr)
  13. {
  14. int i;
  15. struct safexcel_command_desc *cdesc;
  16. dma_addr_t atok;
  17. /* Actual command descriptor ring */
  18. cdr->offset = priv->config.cd_offset;
  19. cdr->base = dmam_alloc_coherent(priv->dev,
  20. cdr->offset * EIP197_DEFAULT_RING_SIZE,
  21. &cdr->base_dma, GFP_KERNEL);
  22. if (!cdr->base)
  23. return -ENOMEM;
  24. cdr->write = cdr->base;
  25. cdr->base_end = cdr->base + cdr->offset * (EIP197_DEFAULT_RING_SIZE - 1);
  26. cdr->read = cdr->base;
  27. /* Command descriptor shadow ring for storing additional token data */
  28. cdr->shoffset = priv->config.cdsh_offset;
  29. cdr->shbase = dmam_alloc_coherent(priv->dev,
  30. cdr->shoffset *
  31. EIP197_DEFAULT_RING_SIZE,
  32. &cdr->shbase_dma, GFP_KERNEL);
  33. if (!cdr->shbase)
  34. return -ENOMEM;
  35. cdr->shwrite = cdr->shbase;
  36. cdr->shbase_end = cdr->shbase + cdr->shoffset *
  37. (EIP197_DEFAULT_RING_SIZE - 1);
  38. /*
  39. * Populate command descriptors with physical pointers to shadow descs.
  40. * Note that we only need to do this once if we don't overwrite them.
  41. */
  42. cdesc = cdr->base;
  43. atok = cdr->shbase_dma;
  44. for (i = 0; i < EIP197_DEFAULT_RING_SIZE; i++) {
  45. cdesc->atok_lo = lower_32_bits(atok);
  46. cdesc->atok_hi = upper_32_bits(atok);
  47. cdesc = (void *)cdesc + cdr->offset;
  48. atok += cdr->shoffset;
  49. }
  50. rdr->offset = priv->config.rd_offset;
  51. /* Use shoffset for result token offset here */
  52. rdr->shoffset = priv->config.res_offset;
  53. rdr->base = dmam_alloc_coherent(priv->dev,
  54. rdr->offset * EIP197_DEFAULT_RING_SIZE,
  55. &rdr->base_dma, GFP_KERNEL);
  56. if (!rdr->base)
  57. return -ENOMEM;
  58. rdr->write = rdr->base;
  59. rdr->base_end = rdr->base + rdr->offset * (EIP197_DEFAULT_RING_SIZE - 1);
  60. rdr->read = rdr->base;
  61. return 0;
  62. }
  63. inline int safexcel_select_ring(struct safexcel_crypto_priv *priv)
  64. {
  65. return (atomic_inc_return(&priv->ring_used) % priv->config.rings);
  66. }
  67. static void *safexcel_ring_next_cwptr(struct safexcel_crypto_priv *priv,
  68. struct safexcel_desc_ring *ring,
  69. bool first,
  70. struct safexcel_token **atoken)
  71. {
  72. void *ptr = ring->write;
  73. if (first)
  74. *atoken = ring->shwrite;
  75. if ((ring->write == ring->read - ring->offset) ||
  76. (ring->read == ring->base && ring->write == ring->base_end))
  77. return ERR_PTR(-ENOMEM);
  78. if (ring->write == ring->base_end) {
  79. ring->write = ring->base;
  80. ring->shwrite = ring->shbase;
  81. } else {
  82. ring->write += ring->offset;
  83. ring->shwrite += ring->shoffset;
  84. }
  85. return ptr;
  86. }
  87. static void *safexcel_ring_next_rwptr(struct safexcel_crypto_priv *priv,
  88. struct safexcel_desc_ring *ring,
  89. struct result_data_desc **rtoken)
  90. {
  91. void *ptr = ring->write;
  92. /* Result token at relative offset shoffset */
  93. *rtoken = ring->write + ring->shoffset;
  94. if ((ring->write == ring->read - ring->offset) ||
  95. (ring->read == ring->base && ring->write == ring->base_end))
  96. return ERR_PTR(-ENOMEM);
  97. if (ring->write == ring->base_end)
  98. ring->write = ring->base;
  99. else
  100. ring->write += ring->offset;
  101. return ptr;
  102. }
  103. void *safexcel_ring_next_rptr(struct safexcel_crypto_priv *priv,
  104. struct safexcel_desc_ring *ring)
  105. {
  106. void *ptr = ring->read;
  107. if (ring->write == ring->read)
  108. return ERR_PTR(-ENOENT);
  109. if (ring->read == ring->base_end)
  110. ring->read = ring->base;
  111. else
  112. ring->read += ring->offset;
  113. return ptr;
  114. }
  115. inline void *safexcel_ring_curr_rptr(struct safexcel_crypto_priv *priv,
  116. int ring)
  117. {
  118. struct safexcel_desc_ring *rdr = &priv->ring[ring].rdr;
  119. return rdr->read;
  120. }
  121. inline int safexcel_ring_first_rdr_index(struct safexcel_crypto_priv *priv,
  122. int ring)
  123. {
  124. struct safexcel_desc_ring *rdr = &priv->ring[ring].rdr;
  125. return (rdr->read - rdr->base) / rdr->offset;
  126. }
  127. inline int safexcel_ring_rdr_rdesc_index(struct safexcel_crypto_priv *priv,
  128. int ring,
  129. struct safexcel_result_desc *rdesc)
  130. {
  131. struct safexcel_desc_ring *rdr = &priv->ring[ring].rdr;
  132. return ((void *)rdesc - rdr->base) / rdr->offset;
  133. }
  134. void safexcel_ring_rollback_wptr(struct safexcel_crypto_priv *priv,
  135. struct safexcel_desc_ring *ring)
  136. {
  137. if (ring->write == ring->read)
  138. return;
  139. if (ring->write == ring->base) {
  140. ring->write = ring->base_end;
  141. ring->shwrite = ring->shbase_end;
  142. } else {
  143. ring->write -= ring->offset;
  144. ring->shwrite -= ring->shoffset;
  145. }
  146. }
  147. struct safexcel_command_desc *safexcel_add_cdesc(struct safexcel_crypto_priv *priv,
  148. int ring_id,
  149. bool first, bool last,
  150. dma_addr_t data, u32 data_len,
  151. u32 full_data_len,
  152. dma_addr_t context,
  153. struct safexcel_token **atoken)
  154. {
  155. struct safexcel_command_desc *cdesc;
  156. cdesc = safexcel_ring_next_cwptr(priv, &priv->ring[ring_id].cdr,
  157. first, atoken);
  158. if (IS_ERR(cdesc))
  159. return cdesc;
  160. cdesc->particle_size = data_len;
  161. cdesc->rsvd0 = 0;
  162. cdesc->last_seg = last;
  163. cdesc->first_seg = first;
  164. cdesc->additional_cdata_size = 0;
  165. cdesc->rsvd1 = 0;
  166. cdesc->data_lo = lower_32_bits(data);
  167. cdesc->data_hi = upper_32_bits(data);
  168. if (first) {
  169. /*
  170. * Note that the length here MUST be >0 or else the EIP(1)97
  171. * may hang. Newer EIP197 firmware actually incorporates this
  172. * fix already, but that doesn't help the EIP97 and we may
  173. * also be running older firmware.
  174. */
  175. cdesc->control_data.packet_length = full_data_len ?: 1;
  176. cdesc->control_data.options = EIP197_OPTION_MAGIC_VALUE |
  177. EIP197_OPTION_64BIT_CTX |
  178. EIP197_OPTION_CTX_CTRL_IN_CMD |
  179. EIP197_OPTION_RC_AUTO;
  180. cdesc->control_data.type = EIP197_TYPE_BCLA;
  181. cdesc->control_data.context_lo = lower_32_bits(context) |
  182. EIP197_CONTEXT_SMALL;
  183. cdesc->control_data.context_hi = upper_32_bits(context);
  184. }
  185. return cdesc;
  186. }
  187. struct safexcel_result_desc *safexcel_add_rdesc(struct safexcel_crypto_priv *priv,
  188. int ring_id,
  189. bool first, bool last,
  190. dma_addr_t data, u32 len)
  191. {
  192. struct safexcel_result_desc *rdesc;
  193. struct result_data_desc *rtoken;
  194. rdesc = safexcel_ring_next_rwptr(priv, &priv->ring[ring_id].rdr,
  195. &rtoken);
  196. if (IS_ERR(rdesc))
  197. return rdesc;
  198. rdesc->particle_size = len;
  199. rdesc->rsvd0 = 0;
  200. rdesc->descriptor_overflow = 1; /* assume error */
  201. rdesc->buffer_overflow = 1; /* assume error */
  202. rdesc->last_seg = last;
  203. rdesc->first_seg = first;
  204. rdesc->result_size = EIP197_RD64_RESULT_SIZE;
  205. rdesc->rsvd1 = 0;
  206. rdesc->data_lo = lower_32_bits(data);
  207. rdesc->data_hi = upper_32_bits(data);
  208. /* Clear length in result token */
  209. rtoken->packet_length = 0;
  210. /* Assume errors - HW will clear if not the case */
  211. rtoken->error_code = 0x7fff;
  212. return rdesc;
  213. }