xref: /linux/drivers/crypto/inside-secure/safexcel_ring.c (revision 6fdcba32711044c35c0e1b094cbd8f3f0b4472c9)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2017 Marvell
4  *
5  * Antoine Tenart <antoine.tenart@free-electrons.com>
6  */
7 
8 #include <linux/dma-mapping.h>
9 #include <linux/spinlock.h>
10 
11 #include "safexcel.h"
12 
13 int safexcel_init_ring_descriptors(struct safexcel_crypto_priv *priv,
14 				   struct safexcel_desc_ring *cdr,
15 				   struct safexcel_desc_ring *rdr)
16 {
17 	cdr->offset = priv->config.cd_offset;
18 	cdr->base = dmam_alloc_coherent(priv->dev,
19 					cdr->offset * EIP197_DEFAULT_RING_SIZE,
20 					&cdr->base_dma, GFP_KERNEL);
21 	if (!cdr->base)
22 		return -ENOMEM;
23 	cdr->write = cdr->base;
24 	cdr->base_end = cdr->base + cdr->offset * (EIP197_DEFAULT_RING_SIZE - 1);
25 	cdr->read = cdr->base;
26 
27 	rdr->offset = priv->config.rd_offset;
28 	rdr->base = dmam_alloc_coherent(priv->dev,
29 					rdr->offset * EIP197_DEFAULT_RING_SIZE,
30 					&rdr->base_dma, GFP_KERNEL);
31 	if (!rdr->base)
32 		return -ENOMEM;
33 	rdr->write = rdr->base;
34 	rdr->base_end = rdr->base + rdr->offset  * (EIP197_DEFAULT_RING_SIZE - 1);
35 	rdr->read = rdr->base;
36 
37 	return 0;
38 }
39 
40 inline int safexcel_select_ring(struct safexcel_crypto_priv *priv)
41 {
42 	return (atomic_inc_return(&priv->ring_used) % priv->config.rings);
43 }
44 
45 static void *safexcel_ring_next_wptr(struct safexcel_crypto_priv *priv,
46 				     struct safexcel_desc_ring *ring)
47 {
48 	void *ptr = ring->write;
49 
50 	if ((ring->write == ring->read - ring->offset) ||
51 	    (ring->read == ring->base && ring->write == ring->base_end))
52 		return ERR_PTR(-ENOMEM);
53 
54 	if (ring->write == ring->base_end)
55 		ring->write = ring->base;
56 	else
57 		ring->write += ring->offset;
58 
59 	return ptr;
60 }
61 
62 void *safexcel_ring_next_rptr(struct safexcel_crypto_priv *priv,
63 			      struct safexcel_desc_ring *ring)
64 {
65 	void *ptr = ring->read;
66 
67 	if (ring->write == ring->read)
68 		return ERR_PTR(-ENOENT);
69 
70 	if (ring->read == ring->base_end)
71 		ring->read = ring->base;
72 	else
73 		ring->read += ring->offset;
74 
75 	return ptr;
76 }
77 
78 inline void *safexcel_ring_curr_rptr(struct safexcel_crypto_priv *priv,
79 				     int ring)
80 {
81 	struct safexcel_desc_ring *rdr = &priv->ring[ring].rdr;
82 
83 	return rdr->read;
84 }
85 
86 inline int safexcel_ring_first_rdr_index(struct safexcel_crypto_priv *priv,
87 					 int ring)
88 {
89 	struct safexcel_desc_ring *rdr = &priv->ring[ring].rdr;
90 
91 	return (rdr->read - rdr->base) / rdr->offset;
92 }
93 
94 inline int safexcel_ring_rdr_rdesc_index(struct safexcel_crypto_priv *priv,
95 					 int ring,
96 					 struct safexcel_result_desc *rdesc)
97 {
98 	struct safexcel_desc_ring *rdr = &priv->ring[ring].rdr;
99 
100 	return ((void *)rdesc - rdr->base) / rdr->offset;
101 }
102 
103 void safexcel_ring_rollback_wptr(struct safexcel_crypto_priv *priv,
104 				 struct safexcel_desc_ring *ring)
105 {
106 	if (ring->write == ring->read)
107 		return;
108 
109 	if (ring->write == ring->base)
110 		ring->write = ring->base_end;
111 	else
112 		ring->write -= ring->offset;
113 }
114 
115 struct safexcel_command_desc *safexcel_add_cdesc(struct safexcel_crypto_priv *priv,
116 						 int ring_id,
117 						 bool first, bool last,
118 						 dma_addr_t data, u32 data_len,
119 						 u32 full_data_len,
120 						 dma_addr_t context) {
121 	struct safexcel_command_desc *cdesc;
122 	int i;
123 
124 	cdesc = safexcel_ring_next_wptr(priv, &priv->ring[ring_id].cdr);
125 	if (IS_ERR(cdesc))
126 		return cdesc;
127 
128 	memset(cdesc, 0, sizeof(struct safexcel_command_desc));
129 
130 	cdesc->first_seg = first;
131 	cdesc->last_seg = last;
132 	cdesc->particle_size = data_len;
133 	cdesc->data_lo = lower_32_bits(data);
134 	cdesc->data_hi = upper_32_bits(data);
135 
136 	if (first && context) {
137 		struct safexcel_token *token =
138 			(struct safexcel_token *)cdesc->control_data.token;
139 
140 		/*
141 		 * Note that the length here MUST be >0 or else the EIP(1)97
142 		 * may hang. Newer EIP197 firmware actually incorporates this
143 		 * fix already, but that doesn't help the EIP97 and we may
144 		 * also be running older firmware.
145 		 */
146 		cdesc->control_data.packet_length = full_data_len ?: 1;
147 		cdesc->control_data.options = EIP197_OPTION_MAGIC_VALUE |
148 					      EIP197_OPTION_64BIT_CTX |
149 					      EIP197_OPTION_CTX_CTRL_IN_CMD;
150 		cdesc->control_data.context_lo =
151 			(lower_32_bits(context) & GENMASK(31, 2)) >> 2;
152 		cdesc->control_data.context_hi = upper_32_bits(context);
153 
154 		if (priv->version == EIP197B_MRVL ||
155 		    priv->version == EIP197D_MRVL)
156 			cdesc->control_data.options |= EIP197_OPTION_RC_AUTO;
157 
158 		/* TODO: large xform HMAC with SHA-384/512 uses refresh = 3 */
159 		cdesc->control_data.refresh = 2;
160 
161 		for (i = 0; i < EIP197_MAX_TOKENS; i++)
162 			eip197_noop_token(&token[i]);
163 	}
164 
165 	return cdesc;
166 }
167 
168 struct safexcel_result_desc *safexcel_add_rdesc(struct safexcel_crypto_priv *priv,
169 						int ring_id,
170 						bool first, bool last,
171 						dma_addr_t data, u32 len)
172 {
173 	struct safexcel_result_desc *rdesc;
174 
175 	rdesc = safexcel_ring_next_wptr(priv, &priv->ring[ring_id].rdr);
176 	if (IS_ERR(rdesc))
177 		return rdesc;
178 
179 	memset(rdesc, 0, sizeof(struct safexcel_result_desc));
180 
181 	rdesc->first_seg = first;
182 	rdesc->last_seg = last;
183 	rdesc->result_size = EIP197_RD64_RESULT_SIZE;
184 	rdesc->particle_size = len;
185 	rdesc->data_lo = lower_32_bits(data);
186 	rdesc->data_hi = upper_32_bits(data);
187 
188 	return rdesc;
189 }
190