1/*-
2 *   BSD LICENSE
3 *
4 *   Copyright(c) 2016 Intel Corporation. All rights reserved.
5 *
6 *   Redistribution and use in source and binary forms, with or without
7 *   modification, are permitted provided that the following conditions
8 *   are met:
9 *
10 *     * Redistributions of source code must retain the above copyright
11 *       notice, this list of conditions and the following disclaimer.
12 *     * Redistributions in binary form must reproduce the above copyright
13 *       notice, this list of conditions and the following disclaimer in
14 *       the documentation and/or other materials provided with the
15 *       distribution.
16 *     * Neither the name of Intel Corporation nor the names of its
17 *       contributors may be used to endorse or promote products derived
18 *       from this software without specific prior written permission.
19 *
20 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <string.h>
34
35#include <rte_common.h>
36#include <rte_malloc.h>
37#include <rte_cryptodev_pmd.h>
38
39#include "null_crypto_pmd_private.h"
40
41static const struct rte_cryptodev_capabilities null_crypto_pmd_capabilities[] = {
42	{	/* NULL (AUTH) */
43		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
44		{.sym = {
45			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
46			{.auth = {
47				.algo = RTE_CRYPTO_AUTH_NULL,
48				.block_size = 1,
49				.key_size = {
50					.min = 0,
51					.max = 0,
52					.increment = 0
53				},
54				.digest_size = {
55					.min = 0,
56					.max = 0,
57					.increment = 0
58				},
59				.aad_size = { 0 }
60			}, },
61		}, },
62	},
63	{	/* NULL (CIPHER) */
64		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
65		{.sym = {
66			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
67			{.cipher = {
68				.algo = RTE_CRYPTO_CIPHER_NULL,
69				.block_size = 1,
70				.key_size = {
71					.min = 0,
72					.max = 0,
73					.increment = 0
74				},
75				.iv_size = {
76					.min = 0,
77					.max = 0,
78					.increment = 0
79				}
80			}, },
81		}, }
82	},
83	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
84};
85
86/** Configure device */
87static int
88null_crypto_pmd_config(__rte_unused struct rte_cryptodev *dev)
89{
90	return 0;
91}
92
93/** Start device */
94static int
95null_crypto_pmd_start(__rte_unused struct rte_cryptodev *dev)
96{
97	return 0;
98}
99
100/** Stop device */
101static void
102null_crypto_pmd_stop(__rte_unused struct rte_cryptodev *dev)
103{
104}
105
106/** Close device */
107static int
108null_crypto_pmd_close(__rte_unused struct rte_cryptodev *dev)
109{
110	return 0;
111}
112
113/** Get device statistics */
114static void
115null_crypto_pmd_stats_get(struct rte_cryptodev *dev,
116		struct rte_cryptodev_stats *stats)
117{
118	int qp_id;
119
120	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
121		struct null_crypto_qp *qp = dev->data->queue_pairs[qp_id];
122
123		stats->enqueued_count += qp->qp_stats.enqueued_count;
124		stats->dequeued_count += qp->qp_stats.dequeued_count;
125
126		stats->enqueue_err_count += qp->qp_stats.enqueue_err_count;
127		stats->dequeue_err_count += qp->qp_stats.dequeue_err_count;
128	}
129}
130
131/** Reset device statistics */
132static void
133null_crypto_pmd_stats_reset(struct rte_cryptodev *dev)
134{
135	int qp_id;
136
137	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
138		struct null_crypto_qp *qp = dev->data->queue_pairs[qp_id];
139
140		memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
141	}
142}
143
144
145/** Get device info */
146static void
147null_crypto_pmd_info_get(struct rte_cryptodev *dev,
148		struct rte_cryptodev_info *dev_info)
149{
150	struct null_crypto_private *internals = dev->data->dev_private;
151
152	if (dev_info != NULL) {
153		dev_info->dev_type = dev->dev_type;
154		dev_info->max_nb_queue_pairs = internals->max_nb_qpairs;
155		dev_info->sym.max_nb_sessions = internals->max_nb_sessions;
156		dev_info->feature_flags = dev->feature_flags;
157		dev_info->capabilities = null_crypto_pmd_capabilities;
158	}
159}
160
161/** Release queue pair */
162static int
163null_crypto_pmd_qp_release(struct rte_cryptodev *dev, uint16_t qp_id)
164{
165	if (dev->data->queue_pairs[qp_id] != NULL) {
166		rte_free(dev->data->queue_pairs[qp_id]);
167		dev->data->queue_pairs[qp_id] = NULL;
168	}
169	return 0;
170}
171
172/** set a unique name for the queue pair based on it's name, dev_id and qp_id */
173static int
174null_crypto_pmd_qp_set_unique_name(struct rte_cryptodev *dev,
175		struct null_crypto_qp *qp)
176{
177	unsigned n = snprintf(qp->name, sizeof(qp->name),
178			"null_crypto_pmd_%u_qp_%u",
179			dev->data->dev_id, qp->id);
180
181	if (n >= sizeof(qp->name))
182		return -1;
183
184	return 0;
185}
186
187/** Create a ring to place process packets on */
188static struct rte_ring *
189null_crypto_pmd_qp_create_processed_pkts_ring(struct null_crypto_qp *qp,
190		unsigned ring_size, int socket_id)
191{
192	struct rte_ring *r;
193
194	r = rte_ring_lookup(qp->name);
195	if (r) {
196		if (r->prod.size >= ring_size) {
197			NULL_CRYPTO_LOG_INFO(
198				"Reusing existing ring %s for processed packets",
199				qp->name);
200			return r;
201		}
202
203		NULL_CRYPTO_LOG_INFO(
204			"Unable to reuse existing ring %s for processed packets",
205			 qp->name);
206		return NULL;
207	}
208
209	return rte_ring_create(qp->name, ring_size, socket_id,
210			RING_F_SP_ENQ | RING_F_SC_DEQ);
211}
212
213/** Setup a queue pair */
214static int
215null_crypto_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
216		const struct rte_cryptodev_qp_conf *qp_conf,
217		 int socket_id)
218{
219	struct null_crypto_private *internals = dev->data->dev_private;
220	struct null_crypto_qp *qp;
221	int retval;
222
223	if (qp_id >= internals->max_nb_qpairs) {
224		NULL_CRYPTO_LOG_ERR("Invalid qp_id %u, greater than maximum "
225				"number of queue pairs supported (%u).",
226				qp_id, internals->max_nb_qpairs);
227		return (-EINVAL);
228	}
229
230	/* Free memory prior to re-allocation if needed. */
231	if (dev->data->queue_pairs[qp_id] != NULL)
232		null_crypto_pmd_qp_release(dev, qp_id);
233
234	/* Allocate the queue pair data structure. */
235	qp = rte_zmalloc_socket("Null Crypto PMD Queue Pair", sizeof(*qp),
236					RTE_CACHE_LINE_SIZE, socket_id);
237	if (qp == NULL) {
238		NULL_CRYPTO_LOG_ERR("Failed to allocate queue pair memory");
239		return (-ENOMEM);
240	}
241
242	qp->id = qp_id;
243	dev->data->queue_pairs[qp_id] = qp;
244
245	retval = null_crypto_pmd_qp_set_unique_name(dev, qp);
246	if (retval) {
247		NULL_CRYPTO_LOG_ERR("Failed to create unique name for null "
248				"crypto device");
249		goto qp_setup_cleanup;
250	}
251
252	qp->processed_pkts = null_crypto_pmd_qp_create_processed_pkts_ring(qp,
253			qp_conf->nb_descriptors, socket_id);
254	if (qp->processed_pkts == NULL) {
255		NULL_CRYPTO_LOG_ERR("Failed to create unique name for null "
256				"crypto device");
257		goto qp_setup_cleanup;
258	}
259
260	qp->sess_mp = dev->data->session_pool;
261
262	memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
263
264	return 0;
265
266qp_setup_cleanup:
267	if (qp)
268		rte_free(qp);
269
270	return -1;
271}
272
273/** Start queue pair */
274static int
275null_crypto_pmd_qp_start(__rte_unused struct rte_cryptodev *dev,
276		__rte_unused uint16_t queue_pair_id)
277{
278	return -ENOTSUP;
279}
280
281/** Stop queue pair */
282static int
283null_crypto_pmd_qp_stop(__rte_unused struct rte_cryptodev *dev,
284		__rte_unused uint16_t queue_pair_id)
285{
286	return -ENOTSUP;
287}
288
289/** Return the number of allocated queue pairs */
290static uint32_t
291null_crypto_pmd_qp_count(struct rte_cryptodev *dev)
292{
293	return dev->data->nb_queue_pairs;
294}
295
296/** Returns the size of the NULL crypto session structure */
297static unsigned
298null_crypto_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
299{
300	return sizeof(struct null_crypto_session);
301}
302
303/** Configure a null crypto session from a crypto xform chain */
304static void *
305null_crypto_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
306		struct rte_crypto_sym_xform *xform, void *sess)
307{
308	int retval;
309
310	if (unlikely(sess == NULL)) {
311		NULL_CRYPTO_LOG_ERR("invalid session struct");
312		return NULL;
313	}
314	retval = null_crypto_set_session_parameters(
315			(struct null_crypto_session *)sess, xform);
316	if (retval != 0) {
317		NULL_CRYPTO_LOG_ERR("failed configure session parameters");
318		return NULL;
319	}
320
321	return sess;
322}
323
324/** Clear the memory of session so it doesn't leave key material behind */
325static void
326null_crypto_pmd_session_clear(struct rte_cryptodev *dev __rte_unused,
327		void *sess)
328{
329	if (sess)
330		memset(sess, 0, sizeof(struct null_crypto_session));
331}
332
333struct rte_cryptodev_ops pmd_ops = {
334		.dev_configure		= null_crypto_pmd_config,
335		.dev_start		= null_crypto_pmd_start,
336		.dev_stop		= null_crypto_pmd_stop,
337		.dev_close		= null_crypto_pmd_close,
338
339		.stats_get		= null_crypto_pmd_stats_get,
340		.stats_reset		= null_crypto_pmd_stats_reset,
341
342		.dev_infos_get		= null_crypto_pmd_info_get,
343
344		.queue_pair_setup	= null_crypto_pmd_qp_setup,
345		.queue_pair_release	= null_crypto_pmd_qp_release,
346		.queue_pair_start	= null_crypto_pmd_qp_start,
347		.queue_pair_stop	= null_crypto_pmd_qp_stop,
348		.queue_pair_count	= null_crypto_pmd_qp_count,
349
350		.session_get_size	= null_crypto_pmd_session_get_size,
351		.session_configure	= null_crypto_pmd_session_configure,
352		.session_clear		= null_crypto_pmd_session_clear
353};
354
355struct rte_cryptodev_ops *null_crypto_pmd_ops = &pmd_ops;
356