1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2017 Marvell
5 * Antoine Tenart <antoine.tenart@free-electrons.com>
8 #include <linux/dma-mapping.h>
9 #include <linux/spinlock.h>
13 int safexcel_init_ring_descriptors(struct safexcel_crypto_priv
*priv
,
14 struct safexcel_desc_ring
*cdr
,
15 struct safexcel_desc_ring
*rdr
)
18 struct safexcel_command_desc
*cdesc
;
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
);
28 cdr
->write
= cdr
->base
;
29 cdr
->base_end
= cdr
->base
+ cdr
->offset
* (EIP197_DEFAULT_RING_SIZE
- 1);
30 cdr
->read
= cdr
->base
;
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
,
36 EIP197_DEFAULT_RING_SIZE
,
37 &cdr
->shbase_dma
, GFP_KERNEL
);
40 cdr
->shwrite
= cdr
->shbase
;
41 cdr
->shbase_end
= cdr
->shbase
+ cdr
->shoffset
*
42 (EIP197_DEFAULT_RING_SIZE
- 1);
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.
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
;
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
);
65 rdr
->write
= rdr
->base
;
66 rdr
->base_end
= rdr
->base
+ rdr
->offset
* (EIP197_DEFAULT_RING_SIZE
- 1);
67 rdr
->read
= rdr
->base
;
72 inline int safexcel_select_ring(struct safexcel_crypto_priv
*priv
)
74 return (atomic_inc_return(&priv
->ring_used
) % priv
->config
.rings
);
77 static void *safexcel_ring_next_cwptr(struct safexcel_crypto_priv
*priv
,
78 struct safexcel_desc_ring
*ring
,
80 struct safexcel_token
**atoken
)
82 void *ptr
= ring
->write
;
85 *atoken
= ring
->shwrite
;
87 if ((ring
->write
== ring
->read
- ring
->offset
) ||
88 (ring
->read
== ring
->base
&& ring
->write
== ring
->base_end
))
89 return ERR_PTR(-ENOMEM
);
91 if (ring
->write
== ring
->base_end
) {
92 ring
->write
= ring
->base
;
93 ring
->shwrite
= ring
->shbase
;
95 ring
->write
+= ring
->offset
;
96 ring
->shwrite
+= ring
->shoffset
;
102 static void *safexcel_ring_next_rwptr(struct safexcel_crypto_priv
*priv
,
103 struct safexcel_desc_ring
*ring
,
104 struct result_data_desc
**rtoken
)
106 void *ptr
= ring
->write
;
108 /* Result token at relative offset shoffset */
109 *rtoken
= ring
->write
+ ring
->shoffset
;
111 if ((ring
->write
== ring
->read
- ring
->offset
) ||
112 (ring
->read
== ring
->base
&& ring
->write
== ring
->base_end
))
113 return ERR_PTR(-ENOMEM
);
115 if (ring
->write
== ring
->base_end
)
116 ring
->write
= ring
->base
;
118 ring
->write
+= ring
->offset
;
123 void *safexcel_ring_next_rptr(struct safexcel_crypto_priv
*priv
,
124 struct safexcel_desc_ring
*ring
)
126 void *ptr
= ring
->read
;
128 if (ring
->write
== ring
->read
)
129 return ERR_PTR(-ENOENT
);
131 if (ring
->read
== ring
->base_end
)
132 ring
->read
= ring
->base
;
134 ring
->read
+= ring
->offset
;
139 inline void *safexcel_ring_curr_rptr(struct safexcel_crypto_priv
*priv
,
142 struct safexcel_desc_ring
*rdr
= &priv
->ring
[ring
].rdr
;
147 inline int safexcel_ring_first_rdr_index(struct safexcel_crypto_priv
*priv
,
150 struct safexcel_desc_ring
*rdr
= &priv
->ring
[ring
].rdr
;
152 return (rdr
->read
- rdr
->base
) / rdr
->offset
;
155 inline int safexcel_ring_rdr_rdesc_index(struct safexcel_crypto_priv
*priv
,
157 struct safexcel_result_desc
*rdesc
)
159 struct safexcel_desc_ring
*rdr
= &priv
->ring
[ring
].rdr
;
161 return ((void *)rdesc
- rdr
->base
) / rdr
->offset
;
164 void safexcel_ring_rollback_wptr(struct safexcel_crypto_priv
*priv
,
165 struct safexcel_desc_ring
*ring
)
167 if (ring
->write
== ring
->read
)
170 if (ring
->write
== ring
->base
) {
171 ring
->write
= ring
->base_end
;
172 ring
->shwrite
= ring
->shbase_end
;
174 ring
->write
-= ring
->offset
;
175 ring
->shwrite
-= ring
->shoffset
;
179 struct safexcel_command_desc
*safexcel_add_cdesc(struct safexcel_crypto_priv
*priv
,
181 bool first
, bool last
,
182 dma_addr_t data
, u32 data_len
,
185 struct safexcel_token
**atoken
)
187 struct safexcel_command_desc
*cdesc
;
189 cdesc
= safexcel_ring_next_cwptr(priv
, &priv
->ring
[ring_id
].cdr
,
194 cdesc
->particle_size
= data_len
;
196 cdesc
->last_seg
= last
;
197 cdesc
->first_seg
= first
;
198 cdesc
->additional_cdata_size
= 0;
200 cdesc
->data_lo
= lower_32_bits(data
);
201 cdesc
->data_hi
= upper_32_bits(data
);
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.
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
);
224 struct safexcel_result_desc
*safexcel_add_rdesc(struct safexcel_crypto_priv
*priv
,
226 bool first
, bool last
,
227 dma_addr_t data
, u32 len
)
229 struct safexcel_result_desc
*rdesc
;
230 struct result_data_desc
*rtoken
;
232 rdesc
= safexcel_ring_next_rwptr(priv
, &priv
->ring
[ring_id
].rdr
,
237 rdesc
->particle_size
= len
;
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
;
245 rdesc
->data_lo
= lower_32_bits(data
);
246 rdesc
->data_hi
= upper_32_bits(data
);
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;