1 /* 2 * Copyright (C) 2017 Marvell 3 * 4 * Antoine Tenart <antoine.tenart@free-electrons.com> 5 * 6 * This file is licensed under the terms of the GNU General Public 7 * License version 2. This program is licensed "as is" without any 8 * warranty of any kind, whether express or implied. 9 */ 10 11 #include <linux/dma-mapping.h> 12 #include <linux/spinlock.h> 13 14 #include "safexcel.h" 15 16 int safexcel_init_ring_descriptors(struct safexcel_crypto_priv *priv, 17 struct safexcel_ring *cdr, 18 struct safexcel_ring *rdr) 19 { 20 cdr->offset = sizeof(u32) * priv->config.cd_offset; 21 cdr->base = dmam_alloc_coherent(priv->dev, 22 cdr->offset * EIP197_DEFAULT_RING_SIZE, 23 &cdr->base_dma, GFP_KERNEL); 24 if (!cdr->base) 25 return -ENOMEM; 26 cdr->write = cdr->base; 27 cdr->base_end = cdr->base + cdr->offset * EIP197_DEFAULT_RING_SIZE; 28 cdr->read = cdr->base; 29 30 rdr->offset = sizeof(u32) * priv->config.rd_offset; 31 rdr->base = dmam_alloc_coherent(priv->dev, 32 rdr->offset * EIP197_DEFAULT_RING_SIZE, 33 &rdr->base_dma, GFP_KERNEL); 34 if (!rdr->base) 35 return -ENOMEM; 36 rdr->write = rdr->base; 37 rdr->base_end = rdr->base + rdr->offset * EIP197_DEFAULT_RING_SIZE; 38 rdr->read = rdr->base; 39 40 return 0; 41 } 42 43 inline int safexcel_select_ring(struct safexcel_crypto_priv *priv) 44 { 45 return (atomic_inc_return(&priv->ring_used) % priv->config.rings); 46 } 47 48 static void *safexcel_ring_next_wptr(struct safexcel_crypto_priv *priv, 49 struct safexcel_ring *ring) 50 { 51 void *ptr = ring->write; 52 53 if (ring->nr == EIP197_DEFAULT_RING_SIZE - 1) 54 return ERR_PTR(-ENOMEM); 55 56 ring->write += ring->offset; 57 if (ring->write == ring->base_end) 58 ring->write = ring->base; 59 60 ring->nr++; 61 return ptr; 62 } 63 64 void *safexcel_ring_next_rptr(struct safexcel_crypto_priv *priv, 65 struct safexcel_ring *ring) 66 { 67 void *ptr = ring->read; 68 69 if (!ring->nr) 70 return ERR_PTR(-ENOENT); 71 72 ring->read += ring->offset; 73 if (ring->read == ring->base_end) 74 ring->read = ring->base; 75 76 ring->nr--; 77 return ptr; 78 } 79 80 void safexcel_ring_rollback_wptr(struct safexcel_crypto_priv *priv, 81 struct safexcel_ring *ring) 82 { 83 if (!ring->nr) 84 return; 85 86 if (ring->write == ring->base) 87 ring->write += (EIP197_DEFAULT_RING_SIZE - 1) * ring->offset; 88 else 89 ring->write -= ring->offset; 90 91 ring->nr--; 92 } 93 94 struct safexcel_command_desc *safexcel_add_cdesc(struct safexcel_crypto_priv *priv, 95 int ring_id, 96 bool first, bool last, 97 dma_addr_t data, u32 data_len, 98 u32 full_data_len, 99 dma_addr_t context) { 100 struct safexcel_command_desc *cdesc; 101 int i; 102 103 cdesc = safexcel_ring_next_wptr(priv, &priv->ring[ring_id].cdr); 104 if (IS_ERR(cdesc)) 105 return cdesc; 106 107 memset(cdesc, 0, sizeof(struct safexcel_command_desc)); 108 109 cdesc->first_seg = first; 110 cdesc->last_seg = last; 111 cdesc->particle_size = data_len; 112 cdesc->data_lo = lower_32_bits(data); 113 cdesc->data_hi = upper_32_bits(data); 114 115 if (first && context) { 116 struct safexcel_token *token = 117 (struct safexcel_token *)cdesc->control_data.token; 118 119 cdesc->control_data.packet_length = full_data_len; 120 cdesc->control_data.options = EIP197_OPTION_MAGIC_VALUE | 121 EIP197_OPTION_64BIT_CTX | 122 EIP197_OPTION_CTX_CTRL_IN_CMD; 123 cdesc->control_data.context_lo = 124 (lower_32_bits(context) & GENMASK(31, 2)) >> 2; 125 cdesc->control_data.context_hi = upper_32_bits(context); 126 127 /* TODO: large xform HMAC with SHA-384/512 uses refresh = 3 */ 128 cdesc->control_data.refresh = 2; 129 130 for (i = 0; i < EIP197_MAX_TOKENS; i++) 131 eip197_noop_token(&token[i]); 132 } 133 134 return cdesc; 135 } 136 137 struct safexcel_result_desc *safexcel_add_rdesc(struct safexcel_crypto_priv *priv, 138 int ring_id, 139 bool first, bool last, 140 dma_addr_t data, u32 len) 141 { 142 struct safexcel_result_desc *rdesc; 143 144 rdesc = safexcel_ring_next_wptr(priv, &priv->ring[ring_id].rdr); 145 if (IS_ERR(rdesc)) 146 return rdesc; 147 148 memset(rdesc, 0, sizeof(struct safexcel_result_desc)); 149 150 rdesc->first_seg = first; 151 rdesc->last_seg = last; 152 rdesc->particle_size = len; 153 rdesc->data_lo = lower_32_bits(data); 154 rdesc->data_hi = upper_32_bits(data); 155 156 return rdesc; 157 } 158