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