xref: /dpdk/drivers/crypto/ipsec_mb/pmd_aesni_gcm.c (revision 2a440d6ab362de705d99c6740b27a3e0755a87f4)
1746825e5SPiotr Bronowski /* SPDX-License-Identifier: BSD-3-Clause
2746825e5SPiotr Bronowski  * Copyright(c) 2016-2021 Intel Corporation
3746825e5SPiotr Bronowski  */
4746825e5SPiotr Bronowski 
5746825e5SPiotr Bronowski #include "pmd_aesni_gcm_priv.h"
6746825e5SPiotr Bronowski 
7746825e5SPiotr Bronowski static void
aesni_gcm_set_ops(struct aesni_gcm_ops * ops,IMB_MGR * mb_mgr)8746825e5SPiotr Bronowski aesni_gcm_set_ops(struct aesni_gcm_ops *ops, IMB_MGR *mb_mgr)
9746825e5SPiotr Bronowski {
10746825e5SPiotr Bronowski 	/* Set 128 bit function pointers. */
11746825e5SPiotr Bronowski 	ops[GCM_KEY_128].pre = mb_mgr->gcm128_pre;
12746825e5SPiotr Bronowski 	ops[GCM_KEY_128].init = mb_mgr->gcm128_init;
13746825e5SPiotr Bronowski 
14746825e5SPiotr Bronowski 	ops[GCM_KEY_128].enc = mb_mgr->gcm128_enc;
15746825e5SPiotr Bronowski 	ops[GCM_KEY_128].update_enc = mb_mgr->gcm128_enc_update;
16746825e5SPiotr Bronowski 	ops[GCM_KEY_128].finalize_enc = mb_mgr->gcm128_enc_finalize;
17746825e5SPiotr Bronowski 
18746825e5SPiotr Bronowski 	ops[GCM_KEY_128].dec = mb_mgr->gcm128_dec;
19746825e5SPiotr Bronowski 	ops[GCM_KEY_128].update_dec = mb_mgr->gcm128_dec_update;
20746825e5SPiotr Bronowski 	ops[GCM_KEY_128].finalize_dec = mb_mgr->gcm128_dec_finalize;
21746825e5SPiotr Bronowski 
22746825e5SPiotr Bronowski 	ops[GCM_KEY_128].gmac_init = mb_mgr->gmac128_init;
23746825e5SPiotr Bronowski 	ops[GCM_KEY_128].gmac_update = mb_mgr->gmac128_update;
24746825e5SPiotr Bronowski 	ops[GCM_KEY_128].gmac_finalize = mb_mgr->gmac128_finalize;
25746825e5SPiotr Bronowski 
26746825e5SPiotr Bronowski 	/* Set 192 bit function pointers. */
27746825e5SPiotr Bronowski 	ops[GCM_KEY_192].pre = mb_mgr->gcm192_pre;
28746825e5SPiotr Bronowski 	ops[GCM_KEY_192].init = mb_mgr->gcm192_init;
29746825e5SPiotr Bronowski 
30746825e5SPiotr Bronowski 	ops[GCM_KEY_192].enc = mb_mgr->gcm192_enc;
31746825e5SPiotr Bronowski 	ops[GCM_KEY_192].update_enc = mb_mgr->gcm192_enc_update;
32746825e5SPiotr Bronowski 	ops[GCM_KEY_192].finalize_enc = mb_mgr->gcm192_enc_finalize;
33746825e5SPiotr Bronowski 
34746825e5SPiotr Bronowski 	ops[GCM_KEY_192].dec = mb_mgr->gcm192_dec;
35746825e5SPiotr Bronowski 	ops[GCM_KEY_192].update_dec = mb_mgr->gcm192_dec_update;
36746825e5SPiotr Bronowski 	ops[GCM_KEY_192].finalize_dec = mb_mgr->gcm192_dec_finalize;
37746825e5SPiotr Bronowski 
38746825e5SPiotr Bronowski 	ops[GCM_KEY_192].gmac_init = mb_mgr->gmac192_init;
39746825e5SPiotr Bronowski 	ops[GCM_KEY_192].gmac_update = mb_mgr->gmac192_update;
40746825e5SPiotr Bronowski 	ops[GCM_KEY_192].gmac_finalize = mb_mgr->gmac192_finalize;
41746825e5SPiotr Bronowski 
42746825e5SPiotr Bronowski 	/* Set 256 bit function pointers. */
43746825e5SPiotr Bronowski 	ops[GCM_KEY_256].pre = mb_mgr->gcm256_pre;
44746825e5SPiotr Bronowski 	ops[GCM_KEY_256].init = mb_mgr->gcm256_init;
45746825e5SPiotr Bronowski 
46746825e5SPiotr Bronowski 	ops[GCM_KEY_256].enc = mb_mgr->gcm256_enc;
47746825e5SPiotr Bronowski 	ops[GCM_KEY_256].update_enc = mb_mgr->gcm256_enc_update;
48746825e5SPiotr Bronowski 	ops[GCM_KEY_256].finalize_enc = mb_mgr->gcm256_enc_finalize;
49746825e5SPiotr Bronowski 
50746825e5SPiotr Bronowski 	ops[GCM_KEY_256].dec = mb_mgr->gcm256_dec;
51746825e5SPiotr Bronowski 	ops[GCM_KEY_256].update_dec = mb_mgr->gcm256_dec_update;
52746825e5SPiotr Bronowski 	ops[GCM_KEY_256].finalize_dec = mb_mgr->gcm256_dec_finalize;
53746825e5SPiotr Bronowski 
54746825e5SPiotr Bronowski 	ops[GCM_KEY_256].gmac_init = mb_mgr->gmac256_init;
55746825e5SPiotr Bronowski 	ops[GCM_KEY_256].gmac_update = mb_mgr->gmac256_update;
56746825e5SPiotr Bronowski 	ops[GCM_KEY_256].gmac_finalize = mb_mgr->gmac256_finalize;
57746825e5SPiotr Bronowski }
58746825e5SPiotr Bronowski 
59746825e5SPiotr Bronowski static int
aesni_gcm_session_configure(IMB_MGR * mb_mgr,void * session,const struct rte_crypto_sym_xform * xform)60746825e5SPiotr Bronowski aesni_gcm_session_configure(IMB_MGR *mb_mgr, void *session,
61746825e5SPiotr Bronowski 			    const struct rte_crypto_sym_xform *xform)
62746825e5SPiotr Bronowski {
63746825e5SPiotr Bronowski 	struct aesni_gcm_session *sess = session;
64746825e5SPiotr Bronowski 	const struct rte_crypto_sym_xform *auth_xform;
65746825e5SPiotr Bronowski 	const struct rte_crypto_sym_xform *cipher_xform;
66746825e5SPiotr Bronowski 	const struct rte_crypto_sym_xform *aead_xform;
67746825e5SPiotr Bronowski 
68746825e5SPiotr Bronowski 	uint8_t key_length;
69746825e5SPiotr Bronowski 	const uint8_t *key;
70746825e5SPiotr Bronowski 	enum ipsec_mb_operation mode;
71746825e5SPiotr Bronowski 	int ret = 0;
72746825e5SPiotr Bronowski 
73746825e5SPiotr Bronowski 	ret = ipsec_mb_parse_xform(xform, &mode, &auth_xform,
74746825e5SPiotr Bronowski 				&cipher_xform, &aead_xform);
75746825e5SPiotr Bronowski 	if (ret)
76746825e5SPiotr Bronowski 		return ret;
77746825e5SPiotr Bronowski 
78746825e5SPiotr Bronowski 	/**< GCM key type */
79746825e5SPiotr Bronowski 
80746825e5SPiotr Bronowski 	sess->op = mode;
81746825e5SPiotr Bronowski 
82746825e5SPiotr Bronowski 	switch (sess->op) {
83746825e5SPiotr Bronowski 	case IPSEC_MB_OP_HASH_GEN_ONLY:
84746825e5SPiotr Bronowski 	case IPSEC_MB_OP_HASH_VERIFY_ONLY:
85746825e5SPiotr Bronowski 		/* AES-GMAC
86746825e5SPiotr Bronowski 		 * auth_xform = xform;
87746825e5SPiotr Bronowski 		 */
88746825e5SPiotr Bronowski 		if (auth_xform->auth.algo != RTE_CRYPTO_AUTH_AES_GMAC) {
89746825e5SPiotr Bronowski 			IPSEC_MB_LOG(ERR,
90746825e5SPiotr Bronowski 	"Only AES GMAC is supported as an authentication only algorithm");
91746825e5SPiotr Bronowski 			ret = -ENOTSUP;
92746825e5SPiotr Bronowski 			goto error_exit;
93746825e5SPiotr Bronowski 		}
94746825e5SPiotr Bronowski 		/* Set IV parameters */
95746825e5SPiotr Bronowski 		sess->iv.offset = auth_xform->auth.iv.offset;
96746825e5SPiotr Bronowski 		sess->iv.length = auth_xform->auth.iv.length;
97746825e5SPiotr Bronowski 		key_length = auth_xform->auth.key.length;
98746825e5SPiotr Bronowski 		key = auth_xform->auth.key.data;
992c6b3438SPiotr Bronowski 		sess->req_digest_length =
1002c6b3438SPiotr Bronowski 		    RTE_MIN(auth_xform->auth.digest_length,
1012c6b3438SPiotr Bronowski 				DIGEST_LENGTH_MAX);
102746825e5SPiotr Bronowski 		break;
103746825e5SPiotr Bronowski 	case IPSEC_MB_OP_AEAD_AUTHENTICATED_ENCRYPT:
104746825e5SPiotr Bronowski 	case IPSEC_MB_OP_AEAD_AUTHENTICATED_DECRYPT:
105746825e5SPiotr Bronowski 		/* AES-GCM
106746825e5SPiotr Bronowski 		 * aead_xform = xform;
107746825e5SPiotr Bronowski 		 */
108746825e5SPiotr Bronowski 
109746825e5SPiotr Bronowski 		if (aead_xform->aead.algo != RTE_CRYPTO_AEAD_AES_GCM) {
110746825e5SPiotr Bronowski 			IPSEC_MB_LOG(ERR,
111746825e5SPiotr Bronowski 			"The only combined operation supported is AES GCM");
112746825e5SPiotr Bronowski 			ret = -ENOTSUP;
113746825e5SPiotr Bronowski 			goto error_exit;
114746825e5SPiotr Bronowski 		}
115746825e5SPiotr Bronowski 		/* Set IV parameters */
116746825e5SPiotr Bronowski 		sess->iv.offset = aead_xform->aead.iv.offset;
117746825e5SPiotr Bronowski 		sess->iv.length = aead_xform->aead.iv.length;
118746825e5SPiotr Bronowski 		key_length = aead_xform->aead.key.length;
119746825e5SPiotr Bronowski 		key = aead_xform->aead.key.data;
120746825e5SPiotr Bronowski 		sess->aad_length = aead_xform->aead.aad_length;
1212c6b3438SPiotr Bronowski 		sess->req_digest_length =
1222c6b3438SPiotr Bronowski 			RTE_MIN(aead_xform->aead.digest_length,
1232c6b3438SPiotr Bronowski 				DIGEST_LENGTH_MAX);
124746825e5SPiotr Bronowski 		break;
125746825e5SPiotr Bronowski 	default:
126746825e5SPiotr Bronowski 		IPSEC_MB_LOG(
127746825e5SPiotr Bronowski 		    ERR, "Wrong xform type, has to be AEAD or authentication");
128746825e5SPiotr Bronowski 		ret = -ENOTSUP;
129746825e5SPiotr Bronowski 		goto error_exit;
130746825e5SPiotr Bronowski 	}
131746825e5SPiotr Bronowski 
132746825e5SPiotr Bronowski 	/* Check key length, and calculate GCM pre-compute. */
133746825e5SPiotr Bronowski 	switch (key_length) {
134746825e5SPiotr Bronowski 	case 16:
135746825e5SPiotr Bronowski 		sess->key_length = GCM_KEY_128;
136746825e5SPiotr Bronowski 		mb_mgr->gcm128_pre(key, &sess->gdata_key);
137746825e5SPiotr Bronowski 		break;
138746825e5SPiotr Bronowski 	case 24:
139746825e5SPiotr Bronowski 		sess->key_length = GCM_KEY_192;
140746825e5SPiotr Bronowski 		mb_mgr->gcm192_pre(key, &sess->gdata_key);
141746825e5SPiotr Bronowski 		break;
142746825e5SPiotr Bronowski 	case 32:
143746825e5SPiotr Bronowski 		sess->key_length = GCM_KEY_256;
144746825e5SPiotr Bronowski 		mb_mgr->gcm256_pre(key, &sess->gdata_key);
145746825e5SPiotr Bronowski 		break;
146746825e5SPiotr Bronowski 	default:
147746825e5SPiotr Bronowski 		IPSEC_MB_LOG(ERR, "Invalid key length");
148746825e5SPiotr Bronowski 		ret = -EINVAL;
149746825e5SPiotr Bronowski 		goto error_exit;
150746825e5SPiotr Bronowski 	}
151746825e5SPiotr Bronowski 
152746825e5SPiotr Bronowski 	/* Digest check */
153746825e5SPiotr Bronowski 	if (sess->req_digest_length > 16) {
154746825e5SPiotr Bronowski 		IPSEC_MB_LOG(ERR, "Invalid digest length");
155746825e5SPiotr Bronowski 		ret = -EINVAL;
156746825e5SPiotr Bronowski 		goto error_exit;
157746825e5SPiotr Bronowski 	}
158746825e5SPiotr Bronowski 	/*
159746825e5SPiotr Bronowski 	 * If size requested is different, generate the full digest
160746825e5SPiotr Bronowski 	 * (16 bytes) in a temporary location and then memcpy
161746825e5SPiotr Bronowski 	 * the requested number of bytes.
162746825e5SPiotr Bronowski 	 */
163746825e5SPiotr Bronowski 	if (sess->req_digest_length < 4)
164746825e5SPiotr Bronowski 		sess->gen_digest_length = 16;
165746825e5SPiotr Bronowski 	else
166746825e5SPiotr Bronowski 		sess->gen_digest_length = sess->req_digest_length;
167746825e5SPiotr Bronowski 
168746825e5SPiotr Bronowski error_exit:
169746825e5SPiotr Bronowski 	return ret;
170746825e5SPiotr Bronowski }
171746825e5SPiotr Bronowski 
172746825e5SPiotr Bronowski /**
173746825e5SPiotr Bronowski  * Process a completed job and return rte_mbuf which job processed
174746825e5SPiotr Bronowski  *
175746825e5SPiotr Bronowski  * @param job	IMB_JOB job to process
176746825e5SPiotr Bronowski  *
177746825e5SPiotr Bronowski  * @return
178746825e5SPiotr Bronowski  * - Returns processed mbuf which is trimmed of output digest used in
179746825e5SPiotr Bronowski  * verification of supplied digest in the case of a HASH_CIPHER operation
180746825e5SPiotr Bronowski  * - Returns NULL on invalid job
181746825e5SPiotr Bronowski  */
182746825e5SPiotr Bronowski static void
post_process_gcm_crypto_op(struct ipsec_mb_qp * qp,struct rte_crypto_op * op,struct aesni_gcm_session * session)183746825e5SPiotr Bronowski post_process_gcm_crypto_op(struct ipsec_mb_qp *qp,
184746825e5SPiotr Bronowski 		struct rte_crypto_op *op,
185746825e5SPiotr Bronowski 		struct aesni_gcm_session *session)
186746825e5SPiotr Bronowski {
187746825e5SPiotr Bronowski 	struct aesni_gcm_qp_data *qp_data = ipsec_mb_get_qp_private_data(qp);
188746825e5SPiotr Bronowski 
189746825e5SPiotr Bronowski 	op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
190746825e5SPiotr Bronowski 	/* Verify digest if required */
191746825e5SPiotr Bronowski 	if (session->op == IPSEC_MB_OP_AEAD_AUTHENTICATED_DECRYPT ||
192746825e5SPiotr Bronowski 			session->op == IPSEC_MB_OP_HASH_VERIFY_ONLY) {
193746825e5SPiotr Bronowski 		uint8_t *digest;
194746825e5SPiotr Bronowski 
195746825e5SPiotr Bronowski 		uint8_t *tag = qp_data->temp_digest;
196746825e5SPiotr Bronowski 
197746825e5SPiotr Bronowski 		if (session->op == IPSEC_MB_OP_HASH_VERIFY_ONLY)
198746825e5SPiotr Bronowski 			digest = op->sym->auth.digest.data;
199746825e5SPiotr Bronowski 		else
200746825e5SPiotr Bronowski 			digest = op->sym->aead.digest.data;
201746825e5SPiotr Bronowski 
202746825e5SPiotr Bronowski #ifdef RTE_LIBRTE_PMD_AESNI_GCM_DEBUG
203746825e5SPiotr Bronowski 		rte_hexdump(stdout, "auth tag (orig):",
204746825e5SPiotr Bronowski 				digest, session->req_digest_length);
205746825e5SPiotr Bronowski 		rte_hexdump(stdout, "auth tag (calc):",
206746825e5SPiotr Bronowski 				tag, session->req_digest_length);
207746825e5SPiotr Bronowski #endif
208746825e5SPiotr Bronowski 
209746825e5SPiotr Bronowski 		if (memcmp(tag, digest,	session->req_digest_length) != 0)
210746825e5SPiotr Bronowski 			op->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
211746825e5SPiotr Bronowski 	} else {
212746825e5SPiotr Bronowski 		if (session->req_digest_length != session->gen_digest_length) {
213746825e5SPiotr Bronowski 			if (session->op ==
214746825e5SPiotr Bronowski 				IPSEC_MB_OP_AEAD_AUTHENTICATED_ENCRYPT)
215746825e5SPiotr Bronowski 				memcpy(op->sym->aead.digest.data,
216746825e5SPiotr Bronowski 					qp_data->temp_digest,
217746825e5SPiotr Bronowski 					session->req_digest_length);
218746825e5SPiotr Bronowski 			else
219746825e5SPiotr Bronowski 				memcpy(op->sym->auth.digest.data,
220746825e5SPiotr Bronowski 					qp_data->temp_digest,
221746825e5SPiotr Bronowski 					session->req_digest_length);
222746825e5SPiotr Bronowski 		}
223746825e5SPiotr Bronowski 	}
224746825e5SPiotr Bronowski }
225746825e5SPiotr Bronowski 
226746825e5SPiotr Bronowski /**
227746825e5SPiotr Bronowski  * Process a completed GCM request
228746825e5SPiotr Bronowski  *
229746825e5SPiotr Bronowski  * @param qp		Queue Pair to process
230746825e5SPiotr Bronowski  * @param op		Crypto operation
231746825e5SPiotr Bronowski  * @param sess		AESNI-GCM session
232746825e5SPiotr Bronowski  *
233746825e5SPiotr Bronowski  */
234746825e5SPiotr Bronowski static void
handle_completed_gcm_crypto_op(struct ipsec_mb_qp * qp,struct rte_crypto_op * op,struct aesni_gcm_session * sess)235746825e5SPiotr Bronowski handle_completed_gcm_crypto_op(struct ipsec_mb_qp *qp,
236746825e5SPiotr Bronowski 		struct rte_crypto_op *op,
237746825e5SPiotr Bronowski 		struct aesni_gcm_session *sess)
238746825e5SPiotr Bronowski {
239746825e5SPiotr Bronowski 	post_process_gcm_crypto_op(qp, op, sess);
240746825e5SPiotr Bronowski 
241746825e5SPiotr Bronowski 	/* Free session if a session-less crypto op */
242746825e5SPiotr Bronowski 	if (op->sess_type == RTE_CRYPTO_OP_SESSIONLESS) {
243746825e5SPiotr Bronowski 		memset(sess, 0, sizeof(struct aesni_gcm_session));
244746825e5SPiotr Bronowski 		rte_mempool_put(qp->sess_mp, op->sym->session);
245746825e5SPiotr Bronowski 		op->sym->session = NULL;
246746825e5SPiotr Bronowski 	}
247746825e5SPiotr Bronowski }
248746825e5SPiotr Bronowski 
249746825e5SPiotr Bronowski /**
250746825e5SPiotr Bronowski  * Process a crypto operation, calling
251746825e5SPiotr Bronowski  * the GCM API from the multi buffer library.
252746825e5SPiotr Bronowski  *
253746825e5SPiotr Bronowski  * @param	qp		queue pair
254746825e5SPiotr Bronowski  * @param	op		symmetric crypto operation
255746825e5SPiotr Bronowski  * @param	session		GCM session
256746825e5SPiotr Bronowski  *
257746825e5SPiotr Bronowski  * @return
258746825e5SPiotr Bronowski  *  0 on success
259746825e5SPiotr Bronowski  */
260746825e5SPiotr Bronowski static int
process_gcm_crypto_op(struct ipsec_mb_qp * qp,struct rte_crypto_op * op,struct aesni_gcm_session * session)261746825e5SPiotr Bronowski process_gcm_crypto_op(struct ipsec_mb_qp *qp, struct rte_crypto_op *op,
262746825e5SPiotr Bronowski 		struct aesni_gcm_session *session)
263746825e5SPiotr Bronowski {
264746825e5SPiotr Bronowski 	struct aesni_gcm_qp_data *qp_data = ipsec_mb_get_qp_private_data(qp);
265746825e5SPiotr Bronowski 	uint8_t *src, *dst;
266746825e5SPiotr Bronowski 	uint8_t *iv_ptr;
267746825e5SPiotr Bronowski 	struct rte_crypto_sym_op *sym_op = op->sym;
268746825e5SPiotr Bronowski 	struct rte_mbuf *m_src = sym_op->m_src;
269746825e5SPiotr Bronowski 	uint32_t offset, data_offset, data_length;
270746825e5SPiotr Bronowski 	uint32_t part_len, total_len, data_len;
271746825e5SPiotr Bronowski 	uint8_t *tag;
272746825e5SPiotr Bronowski 	unsigned int oop = 0;
273746825e5SPiotr Bronowski 	struct aesni_gcm_ops *ops = &qp_data->ops[session->key_length];
274746825e5SPiotr Bronowski 
275746825e5SPiotr Bronowski 	if (session->op == IPSEC_MB_OP_AEAD_AUTHENTICATED_ENCRYPT ||
276746825e5SPiotr Bronowski 			session->op == IPSEC_MB_OP_AEAD_AUTHENTICATED_DECRYPT) {
277746825e5SPiotr Bronowski 		offset = sym_op->aead.data.offset;
278746825e5SPiotr Bronowski 		data_offset = offset;
279746825e5SPiotr Bronowski 		data_length = sym_op->aead.data.length;
280746825e5SPiotr Bronowski 	} else {
281746825e5SPiotr Bronowski 		offset = sym_op->auth.data.offset;
282746825e5SPiotr Bronowski 		data_offset = offset;
283746825e5SPiotr Bronowski 		data_length = sym_op->auth.data.length;
284746825e5SPiotr Bronowski 	}
285746825e5SPiotr Bronowski 
286746825e5SPiotr Bronowski 	RTE_ASSERT(m_src != NULL);
287746825e5SPiotr Bronowski 
288746825e5SPiotr Bronowski 	while (offset >= m_src->data_len && data_length != 0) {
289746825e5SPiotr Bronowski 		offset -= m_src->data_len;
290746825e5SPiotr Bronowski 		m_src = m_src->next;
291746825e5SPiotr Bronowski 
292746825e5SPiotr Bronowski 		RTE_ASSERT(m_src != NULL);
293746825e5SPiotr Bronowski 	}
294746825e5SPiotr Bronowski 
295746825e5SPiotr Bronowski 	src = rte_pktmbuf_mtod_offset(m_src, uint8_t *, offset);
296746825e5SPiotr Bronowski 
297746825e5SPiotr Bronowski 	data_len = m_src->data_len - offset;
298746825e5SPiotr Bronowski 	part_len = (data_len < data_length) ? data_len :
299746825e5SPiotr Bronowski 			data_length;
300746825e5SPiotr Bronowski 
301746825e5SPiotr Bronowski 	RTE_ASSERT((sym_op->m_dst == NULL) ||
302746825e5SPiotr Bronowski 			((sym_op->m_dst != NULL) &&
303746825e5SPiotr Bronowski 				rte_pktmbuf_is_contiguous(sym_op->m_dst)));
304746825e5SPiotr Bronowski 
305746825e5SPiotr Bronowski 	/* In-place */
306746825e5SPiotr Bronowski 	if (sym_op->m_dst == NULL || (sym_op->m_dst == sym_op->m_src))
307746825e5SPiotr Bronowski 		dst = src;
308746825e5SPiotr Bronowski 	/* Out-of-place */
309746825e5SPiotr Bronowski 	else {
310746825e5SPiotr Bronowski 		oop = 1;
311746825e5SPiotr Bronowski 		/* Segmented destination buffer is not supported
312746825e5SPiotr Bronowski 		 * if operation is Out-of-place
313746825e5SPiotr Bronowski 		 */
314746825e5SPiotr Bronowski 		RTE_ASSERT(rte_pktmbuf_is_contiguous(sym_op->m_dst));
315746825e5SPiotr Bronowski 		dst = rte_pktmbuf_mtod_offset(sym_op->m_dst, uint8_t *,
316746825e5SPiotr Bronowski 					data_offset);
317746825e5SPiotr Bronowski 	}
318746825e5SPiotr Bronowski 
319746825e5SPiotr Bronowski 	iv_ptr = rte_crypto_op_ctod_offset(op, uint8_t *,
320746825e5SPiotr Bronowski 				session->iv.offset);
321746825e5SPiotr Bronowski 
322746825e5SPiotr Bronowski 	if (session->op == IPSEC_MB_OP_AEAD_AUTHENTICATED_ENCRYPT) {
323746825e5SPiotr Bronowski 		ops->init(&session->gdata_key, &qp_data->gcm_ctx_data, iv_ptr,
324746825e5SPiotr Bronowski 				sym_op->aead.aad.data,
325746825e5SPiotr Bronowski 				(uint64_t)session->aad_length);
326746825e5SPiotr Bronowski 
327746825e5SPiotr Bronowski 		ops->update_enc(&session->gdata_key, &qp_data->gcm_ctx_data,
328746825e5SPiotr Bronowski 				dst, src, (uint64_t)part_len);
329746825e5SPiotr Bronowski 		total_len = data_length - part_len;
330746825e5SPiotr Bronowski 
331746825e5SPiotr Bronowski 		while (total_len) {
332746825e5SPiotr Bronowski 			m_src = m_src->next;
333746825e5SPiotr Bronowski 
334746825e5SPiotr Bronowski 			RTE_ASSERT(m_src != NULL);
335746825e5SPiotr Bronowski 
336746825e5SPiotr Bronowski 			src = rte_pktmbuf_mtod(m_src, uint8_t *);
337746825e5SPiotr Bronowski 			if (oop)
338746825e5SPiotr Bronowski 				dst += part_len;
339746825e5SPiotr Bronowski 			else
340746825e5SPiotr Bronowski 				dst = src;
341746825e5SPiotr Bronowski 			part_len = (m_src->data_len < total_len) ?
342746825e5SPiotr Bronowski 					m_src->data_len : total_len;
343746825e5SPiotr Bronowski 
344746825e5SPiotr Bronowski 			ops->update_enc(&session->gdata_key,
345746825e5SPiotr Bronowski 					&qp_data->gcm_ctx_data,
346746825e5SPiotr Bronowski 					dst, src, (uint64_t)part_len);
347746825e5SPiotr Bronowski 			total_len -= part_len;
348746825e5SPiotr Bronowski 		}
349746825e5SPiotr Bronowski 
350746825e5SPiotr Bronowski 		if (session->req_digest_length != session->gen_digest_length)
351746825e5SPiotr Bronowski 			tag = qp_data->temp_digest;
352746825e5SPiotr Bronowski 		else
353746825e5SPiotr Bronowski 			tag = sym_op->aead.digest.data;
354746825e5SPiotr Bronowski 
355746825e5SPiotr Bronowski 		ops->finalize_enc(&session->gdata_key, &qp_data->gcm_ctx_data,
356746825e5SPiotr Bronowski 				tag, session->gen_digest_length);
357746825e5SPiotr Bronowski 	} else if (session->op == IPSEC_MB_OP_AEAD_AUTHENTICATED_DECRYPT) {
358746825e5SPiotr Bronowski 		ops->init(&session->gdata_key, &qp_data->gcm_ctx_data, iv_ptr,
359746825e5SPiotr Bronowski 				sym_op->aead.aad.data,
360746825e5SPiotr Bronowski 				(uint64_t)session->aad_length);
361746825e5SPiotr Bronowski 
362746825e5SPiotr Bronowski 		ops->update_dec(&session->gdata_key, &qp_data->gcm_ctx_data,
363746825e5SPiotr Bronowski 				dst, src, (uint64_t)part_len);
364746825e5SPiotr Bronowski 		total_len = data_length - part_len;
365746825e5SPiotr Bronowski 
366746825e5SPiotr Bronowski 		while (total_len) {
367746825e5SPiotr Bronowski 			m_src = m_src->next;
368746825e5SPiotr Bronowski 
369746825e5SPiotr Bronowski 			RTE_ASSERT(m_src != NULL);
370746825e5SPiotr Bronowski 
371746825e5SPiotr Bronowski 			src = rte_pktmbuf_mtod(m_src, uint8_t *);
372746825e5SPiotr Bronowski 			if (oop)
373746825e5SPiotr Bronowski 				dst += part_len;
374746825e5SPiotr Bronowski 			else
375746825e5SPiotr Bronowski 				dst = src;
376746825e5SPiotr Bronowski 			part_len = (m_src->data_len < total_len) ?
377746825e5SPiotr Bronowski 					m_src->data_len : total_len;
378746825e5SPiotr Bronowski 
379746825e5SPiotr Bronowski 			ops->update_dec(&session->gdata_key,
380746825e5SPiotr Bronowski 					&qp_data->gcm_ctx_data,
381746825e5SPiotr Bronowski 					dst, src, (uint64_t)part_len);
382746825e5SPiotr Bronowski 			total_len -= part_len;
383746825e5SPiotr Bronowski 		}
384746825e5SPiotr Bronowski 
385746825e5SPiotr Bronowski 		tag = qp_data->temp_digest;
386746825e5SPiotr Bronowski 		ops->finalize_dec(&session->gdata_key, &qp_data->gcm_ctx_data,
387746825e5SPiotr Bronowski 				tag, session->gen_digest_length);
388746825e5SPiotr Bronowski 	} else if (session->op == IPSEC_MB_OP_HASH_GEN_ONLY) {
389746825e5SPiotr Bronowski 		ops->gmac_init(&session->gdata_key, &qp_data->gcm_ctx_data,
390746825e5SPiotr Bronowski 				iv_ptr, session->iv.length);
391746825e5SPiotr Bronowski 
392746825e5SPiotr Bronowski 		ops->gmac_update(&session->gdata_key, &qp_data->gcm_ctx_data,
393746825e5SPiotr Bronowski 				src, (uint64_t)part_len);
394746825e5SPiotr Bronowski 		total_len = data_length - part_len;
395746825e5SPiotr Bronowski 
396746825e5SPiotr Bronowski 		while (total_len) {
397746825e5SPiotr Bronowski 			m_src = m_src->next;
398746825e5SPiotr Bronowski 
399746825e5SPiotr Bronowski 			RTE_ASSERT(m_src != NULL);
400746825e5SPiotr Bronowski 
401746825e5SPiotr Bronowski 			src = rte_pktmbuf_mtod(m_src, uint8_t *);
402746825e5SPiotr Bronowski 			part_len = (m_src->data_len < total_len) ?
403746825e5SPiotr Bronowski 					m_src->data_len : total_len;
404746825e5SPiotr Bronowski 
405746825e5SPiotr Bronowski 			ops->gmac_update(&session->gdata_key,
406746825e5SPiotr Bronowski 					&qp_data->gcm_ctx_data, src,
407746825e5SPiotr Bronowski 					(uint64_t)part_len);
408746825e5SPiotr Bronowski 			total_len -= part_len;
409746825e5SPiotr Bronowski 		}
410746825e5SPiotr Bronowski 
411746825e5SPiotr Bronowski 		if (session->req_digest_length != session->gen_digest_length)
412746825e5SPiotr Bronowski 			tag = qp_data->temp_digest;
413746825e5SPiotr Bronowski 		else
414746825e5SPiotr Bronowski 			tag = sym_op->auth.digest.data;
415746825e5SPiotr Bronowski 
416746825e5SPiotr Bronowski 		ops->gmac_finalize(&session->gdata_key, &qp_data->gcm_ctx_data,
417746825e5SPiotr Bronowski 				tag, session->gen_digest_length);
418746825e5SPiotr Bronowski 	} else { /* IPSEC_MB_OP_HASH_VERIFY_ONLY */
419746825e5SPiotr Bronowski 		ops->gmac_init(&session->gdata_key, &qp_data->gcm_ctx_data,
420746825e5SPiotr Bronowski 				iv_ptr, session->iv.length);
421746825e5SPiotr Bronowski 
422746825e5SPiotr Bronowski 		ops->gmac_update(&session->gdata_key, &qp_data->gcm_ctx_data,
423746825e5SPiotr Bronowski 				src, (uint64_t)part_len);
424746825e5SPiotr Bronowski 		total_len = data_length - part_len;
425746825e5SPiotr Bronowski 
426746825e5SPiotr Bronowski 		while (total_len) {
427746825e5SPiotr Bronowski 			m_src = m_src->next;
428746825e5SPiotr Bronowski 
429746825e5SPiotr Bronowski 			RTE_ASSERT(m_src != NULL);
430746825e5SPiotr Bronowski 
431746825e5SPiotr Bronowski 			src = rte_pktmbuf_mtod(m_src, uint8_t *);
432746825e5SPiotr Bronowski 			part_len = (m_src->data_len < total_len) ?
433746825e5SPiotr Bronowski 					m_src->data_len : total_len;
434746825e5SPiotr Bronowski 
435746825e5SPiotr Bronowski 			ops->gmac_update(&session->gdata_key,
436746825e5SPiotr Bronowski 					&qp_data->gcm_ctx_data, src,
437746825e5SPiotr Bronowski 					(uint64_t)part_len);
438746825e5SPiotr Bronowski 			total_len -= part_len;
439746825e5SPiotr Bronowski 		}
440746825e5SPiotr Bronowski 
441746825e5SPiotr Bronowski 		tag = qp_data->temp_digest;
442746825e5SPiotr Bronowski 
443746825e5SPiotr Bronowski 		ops->gmac_finalize(&session->gdata_key, &qp_data->gcm_ctx_data,
444746825e5SPiotr Bronowski 				tag, session->gen_digest_length);
445746825e5SPiotr Bronowski 	}
446746825e5SPiotr Bronowski 	return 0;
447746825e5SPiotr Bronowski }
448746825e5SPiotr Bronowski 
449746825e5SPiotr Bronowski /** Get gcm session */
450746825e5SPiotr Bronowski static inline struct aesni_gcm_session *
aesni_gcm_get_session(struct ipsec_mb_qp * qp,struct rte_crypto_op * op)451746825e5SPiotr Bronowski aesni_gcm_get_session(struct ipsec_mb_qp *qp,
452746825e5SPiotr Bronowski 	     struct rte_crypto_op *op)
453746825e5SPiotr Bronowski {
454bdce2564SAkhil Goyal 	struct rte_cryptodev_sym_session *sess = NULL;
455746825e5SPiotr Bronowski 	struct rte_crypto_sym_op *sym_op = op->sym;
456746825e5SPiotr Bronowski 
457746825e5SPiotr Bronowski 	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
458746825e5SPiotr Bronowski 		if (likely(sym_op->session != NULL))
459bdce2564SAkhil Goyal 			sess = sym_op->session;
460746825e5SPiotr Bronowski 	} else {
461bdce2564SAkhil Goyal 		if (rte_mempool_get(qp->sess_mp, (void **)&sess))
462746825e5SPiotr Bronowski 			return NULL;
463746825e5SPiotr Bronowski 
464bdce2564SAkhil Goyal 		if (unlikely(sess->sess_data_sz <
465bdce2564SAkhil Goyal 				sizeof(struct aesni_gcm_session))) {
466bdce2564SAkhil Goyal 			rte_mempool_put(qp->sess_mp, sess);
467746825e5SPiotr Bronowski 			return NULL;
468bdce2564SAkhil Goyal 		}
469746825e5SPiotr Bronowski 
470746825e5SPiotr Bronowski 		if (unlikely(aesni_gcm_session_configure(qp->mb_mgr,
471*2a440d6aSAkhil Goyal 				CRYPTODEV_GET_SYM_SESS_PRIV(sess),
472bdce2564SAkhil Goyal 				sym_op->xform) != 0)) {
473bdce2564SAkhil Goyal 			rte_mempool_put(qp->sess_mp, sess);
474746825e5SPiotr Bronowski 			sess = NULL;
475746825e5SPiotr Bronowski 		}
476bdce2564SAkhil Goyal 		sym_op->session = sess;
477746825e5SPiotr Bronowski 	}
478746825e5SPiotr Bronowski 
479746825e5SPiotr Bronowski 	if (unlikely(sess == NULL))
480746825e5SPiotr Bronowski 		op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
481746825e5SPiotr Bronowski 
482*2a440d6aSAkhil Goyal 	return CRYPTODEV_GET_SYM_SESS_PRIV(sess);
483746825e5SPiotr Bronowski }
484746825e5SPiotr Bronowski 
485746825e5SPiotr Bronowski static uint16_t
aesni_gcm_pmd_dequeue_burst(void * queue_pair,struct rte_crypto_op ** ops,uint16_t nb_ops)486746825e5SPiotr Bronowski aesni_gcm_pmd_dequeue_burst(void *queue_pair,
487746825e5SPiotr Bronowski 		struct rte_crypto_op **ops, uint16_t nb_ops)
488746825e5SPiotr Bronowski {
489746825e5SPiotr Bronowski 	struct aesni_gcm_session *sess;
490746825e5SPiotr Bronowski 	struct ipsec_mb_qp *qp = queue_pair;
491746825e5SPiotr Bronowski 
492746825e5SPiotr Bronowski 	int retval = 0;
493746825e5SPiotr Bronowski 	unsigned int i, nb_dequeued;
494746825e5SPiotr Bronowski 
495746825e5SPiotr Bronowski 	nb_dequeued = rte_ring_dequeue_burst(qp->ingress_queue,
496746825e5SPiotr Bronowski 			(void **)ops, nb_ops, NULL);
497746825e5SPiotr Bronowski 
498746825e5SPiotr Bronowski 	for (i = 0; i < nb_dequeued; i++) {
499746825e5SPiotr Bronowski 
500746825e5SPiotr Bronowski 		sess = aesni_gcm_get_session(qp, ops[i]);
501746825e5SPiotr Bronowski 		if (unlikely(sess == NULL)) {
502746825e5SPiotr Bronowski 			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
503746825e5SPiotr Bronowski 			qp->stats.dequeue_err_count++;
504746825e5SPiotr Bronowski 			break;
505746825e5SPiotr Bronowski 		}
506746825e5SPiotr Bronowski 
507746825e5SPiotr Bronowski 		retval = process_gcm_crypto_op(qp, ops[i], sess);
508746825e5SPiotr Bronowski 		if (retval < 0) {
509746825e5SPiotr Bronowski 			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
510746825e5SPiotr Bronowski 			qp->stats.dequeue_err_count++;
511746825e5SPiotr Bronowski 			break;
512746825e5SPiotr Bronowski 		}
513746825e5SPiotr Bronowski 
514746825e5SPiotr Bronowski 		handle_completed_gcm_crypto_op(qp, ops[i], sess);
515746825e5SPiotr Bronowski 	}
516746825e5SPiotr Bronowski 
517746825e5SPiotr Bronowski 	qp->stats.dequeued_count += i;
518746825e5SPiotr Bronowski 
519746825e5SPiotr Bronowski 	return i;
520746825e5SPiotr Bronowski }
521746825e5SPiotr Bronowski 
522746825e5SPiotr Bronowski static inline void
aesni_gcm_fill_error_code(struct rte_crypto_sym_vec * vec,int32_t errnum)523746825e5SPiotr Bronowski aesni_gcm_fill_error_code(struct rte_crypto_sym_vec *vec,
524746825e5SPiotr Bronowski 			  int32_t errnum)
525746825e5SPiotr Bronowski {
526746825e5SPiotr Bronowski 	uint32_t i;
527746825e5SPiotr Bronowski 
528746825e5SPiotr Bronowski 	for (i = 0; i < vec->num; i++)
529746825e5SPiotr Bronowski 		vec->status[i] = errnum;
530746825e5SPiotr Bronowski }
531746825e5SPiotr Bronowski 
532746825e5SPiotr Bronowski static inline int32_t
aesni_gcm_sgl_op_finalize_encryption(const struct aesni_gcm_session * s,struct gcm_context_data * gdata_ctx,uint8_t * digest,struct aesni_gcm_ops ops)533746825e5SPiotr Bronowski aesni_gcm_sgl_op_finalize_encryption(const struct aesni_gcm_session *s,
534746825e5SPiotr Bronowski 				     struct gcm_context_data *gdata_ctx,
535746825e5SPiotr Bronowski 				     uint8_t *digest, struct aesni_gcm_ops ops)
536746825e5SPiotr Bronowski {
537746825e5SPiotr Bronowski 	if (s->req_digest_length != s->gen_digest_length) {
538746825e5SPiotr Bronowski 		uint8_t tmpdigest[s->gen_digest_length];
539746825e5SPiotr Bronowski 
540746825e5SPiotr Bronowski 		ops.finalize_enc(&s->gdata_key, gdata_ctx, tmpdigest,
541746825e5SPiotr Bronowski 				s->gen_digest_length);
542746825e5SPiotr Bronowski 		memcpy(digest, tmpdigest, s->req_digest_length);
543746825e5SPiotr Bronowski 	} else {
544746825e5SPiotr Bronowski 		ops.finalize_enc(&s->gdata_key, gdata_ctx, digest,
545746825e5SPiotr Bronowski 				s->gen_digest_length);
546746825e5SPiotr Bronowski 	}
547746825e5SPiotr Bronowski 
548746825e5SPiotr Bronowski 	return 0;
549746825e5SPiotr Bronowski }
550746825e5SPiotr Bronowski 
551746825e5SPiotr Bronowski static inline int32_t
aesni_gcm_sgl_op_finalize_decryption(const struct aesni_gcm_session * s,struct gcm_context_data * gdata_ctx,uint8_t * digest,struct aesni_gcm_ops ops)552746825e5SPiotr Bronowski aesni_gcm_sgl_op_finalize_decryption(const struct aesni_gcm_session *s,
553746825e5SPiotr Bronowski 				     struct gcm_context_data *gdata_ctx,
554746825e5SPiotr Bronowski 				     uint8_t *digest, struct aesni_gcm_ops ops)
555746825e5SPiotr Bronowski {
556746825e5SPiotr Bronowski 	uint8_t tmpdigest[s->gen_digest_length];
557746825e5SPiotr Bronowski 
558746825e5SPiotr Bronowski 	ops.finalize_dec(&s->gdata_key, gdata_ctx, tmpdigest,
559746825e5SPiotr Bronowski 			s->gen_digest_length);
560746825e5SPiotr Bronowski 
561746825e5SPiotr Bronowski 	return memcmp(digest, tmpdigest, s->req_digest_length) == 0 ? 0
562746825e5SPiotr Bronowski 								    : EBADMSG;
563746825e5SPiotr Bronowski }
564746825e5SPiotr Bronowski 
565746825e5SPiotr Bronowski static inline void
aesni_gcm_process_gcm_sgl_op(const struct aesni_gcm_session * s,struct gcm_context_data * gdata_ctx,struct rte_crypto_sgl * sgl,void * iv,void * aad,struct aesni_gcm_ops ops)566746825e5SPiotr Bronowski aesni_gcm_process_gcm_sgl_op(const struct aesni_gcm_session *s,
567746825e5SPiotr Bronowski 			     struct gcm_context_data *gdata_ctx,
568746825e5SPiotr Bronowski 			     struct rte_crypto_sgl *sgl, void *iv, void *aad,
569746825e5SPiotr Bronowski 			     struct aesni_gcm_ops ops)
570746825e5SPiotr Bronowski {
571746825e5SPiotr Bronowski 	uint32_t i;
572746825e5SPiotr Bronowski 
573746825e5SPiotr Bronowski 	/* init crypto operation */
574746825e5SPiotr Bronowski 	ops.init(&s->gdata_key, gdata_ctx, iv, aad,
575746825e5SPiotr Bronowski 		    (uint64_t)s->aad_length);
576746825e5SPiotr Bronowski 
577746825e5SPiotr Bronowski 	/* update with sgl data */
578746825e5SPiotr Bronowski 	for (i = 0; i < sgl->num; i++) {
579746825e5SPiotr Bronowski 		struct rte_crypto_vec *vec = &sgl->vec[i];
580746825e5SPiotr Bronowski 
581746825e5SPiotr Bronowski 		switch (s->op) {
582746825e5SPiotr Bronowski 		case IPSEC_MB_OP_AEAD_AUTHENTICATED_ENCRYPT:
583746825e5SPiotr Bronowski 			ops.update_enc(&s->gdata_key, gdata_ctx,
584746825e5SPiotr Bronowski 			      vec->base, vec->base, vec->len);
585746825e5SPiotr Bronowski 			break;
586746825e5SPiotr Bronowski 		case IPSEC_MB_OP_AEAD_AUTHENTICATED_DECRYPT:
587746825e5SPiotr Bronowski 			ops.update_dec(&s->gdata_key, gdata_ctx,
588746825e5SPiotr Bronowski 			      vec->base, vec->base, vec->len);
589746825e5SPiotr Bronowski 			break;
590746825e5SPiotr Bronowski 		default:
591746825e5SPiotr Bronowski 			IPSEC_MB_LOG(ERR, "Invalid session op");
592746825e5SPiotr Bronowski 			break;
593746825e5SPiotr Bronowski 		}
594746825e5SPiotr Bronowski 
595746825e5SPiotr Bronowski 	}
596746825e5SPiotr Bronowski }
597746825e5SPiotr Bronowski 
598746825e5SPiotr Bronowski static inline void
aesni_gcm_process_gmac_sgl_op(const struct aesni_gcm_session * s,struct gcm_context_data * gdata_ctx,struct rte_crypto_sgl * sgl,void * iv,struct aesni_gcm_ops ops)599746825e5SPiotr Bronowski aesni_gcm_process_gmac_sgl_op(const struct aesni_gcm_session *s,
600746825e5SPiotr Bronowski 			      struct gcm_context_data *gdata_ctx,
601746825e5SPiotr Bronowski 			      struct rte_crypto_sgl *sgl, void *iv,
602746825e5SPiotr Bronowski 			      struct aesni_gcm_ops ops)
603746825e5SPiotr Bronowski {
604746825e5SPiotr Bronowski 	ops.init(&s->gdata_key, gdata_ctx, iv, sgl->vec[0].base,
605746825e5SPiotr Bronowski 		    sgl->vec[0].len);
606746825e5SPiotr Bronowski }
607746825e5SPiotr Bronowski 
608746825e5SPiotr Bronowski static inline uint32_t
aesni_gcm_sgl_encrypt(struct aesni_gcm_session * s,struct gcm_context_data * gdata_ctx,struct rte_crypto_sym_vec * vec,struct aesni_gcm_ops ops)609746825e5SPiotr Bronowski aesni_gcm_sgl_encrypt(struct aesni_gcm_session *s,
610746825e5SPiotr Bronowski 		      struct gcm_context_data *gdata_ctx,
611746825e5SPiotr Bronowski 		      struct rte_crypto_sym_vec *vec,
612746825e5SPiotr Bronowski 		      struct aesni_gcm_ops ops)
613746825e5SPiotr Bronowski {
614746825e5SPiotr Bronowski 	uint32_t i, processed;
615746825e5SPiotr Bronowski 
616746825e5SPiotr Bronowski 	processed = 0;
617746825e5SPiotr Bronowski 	for (i = 0; i < vec->num; ++i) {
618746825e5SPiotr Bronowski 		aesni_gcm_process_gcm_sgl_op(s, gdata_ctx, &vec->src_sgl[i],
619746825e5SPiotr Bronowski 					     vec->iv[i].va, vec->aad[i].va,
620746825e5SPiotr Bronowski 					     ops);
621746825e5SPiotr Bronowski 		vec->status[i] = aesni_gcm_sgl_op_finalize_encryption(
622746825e5SPiotr Bronowski 		    s, gdata_ctx, vec->digest[i].va, ops);
623746825e5SPiotr Bronowski 		processed += (vec->status[i] == 0);
624746825e5SPiotr Bronowski 	}
625746825e5SPiotr Bronowski 
626746825e5SPiotr Bronowski 	return processed;
627746825e5SPiotr Bronowski }
628746825e5SPiotr Bronowski 
629746825e5SPiotr Bronowski static inline uint32_t
aesni_gcm_sgl_decrypt(struct aesni_gcm_session * s,struct gcm_context_data * gdata_ctx,struct rte_crypto_sym_vec * vec,struct aesni_gcm_ops ops)630746825e5SPiotr Bronowski aesni_gcm_sgl_decrypt(struct aesni_gcm_session *s,
631746825e5SPiotr Bronowski 		      struct gcm_context_data *gdata_ctx,
632746825e5SPiotr Bronowski 		      struct rte_crypto_sym_vec *vec,
633746825e5SPiotr Bronowski 		      struct aesni_gcm_ops ops)
634746825e5SPiotr Bronowski {
635746825e5SPiotr Bronowski 	uint32_t i, processed;
636746825e5SPiotr Bronowski 
637746825e5SPiotr Bronowski 	processed = 0;
638746825e5SPiotr Bronowski 	for (i = 0; i < vec->num; ++i) {
639746825e5SPiotr Bronowski 		aesni_gcm_process_gcm_sgl_op(s, gdata_ctx, &vec->src_sgl[i],
640746825e5SPiotr Bronowski 					     vec->iv[i].va, vec->aad[i].va,
641746825e5SPiotr Bronowski 					     ops);
642746825e5SPiotr Bronowski 		vec->status[i] = aesni_gcm_sgl_op_finalize_decryption(
643746825e5SPiotr Bronowski 		    s, gdata_ctx, vec->digest[i].va, ops);
644746825e5SPiotr Bronowski 		processed += (vec->status[i] == 0);
645746825e5SPiotr Bronowski 	}
646746825e5SPiotr Bronowski 
647746825e5SPiotr Bronowski 	return processed;
648746825e5SPiotr Bronowski }
649746825e5SPiotr Bronowski 
650746825e5SPiotr Bronowski static inline uint32_t
aesni_gmac_sgl_generate(struct aesni_gcm_session * s,struct gcm_context_data * gdata_ctx,struct rte_crypto_sym_vec * vec,struct aesni_gcm_ops ops)651746825e5SPiotr Bronowski aesni_gmac_sgl_generate(struct aesni_gcm_session *s,
652746825e5SPiotr Bronowski 			struct gcm_context_data *gdata_ctx,
653746825e5SPiotr Bronowski 			struct rte_crypto_sym_vec *vec,
654746825e5SPiotr Bronowski 			struct aesni_gcm_ops ops)
655746825e5SPiotr Bronowski {
656746825e5SPiotr Bronowski 	uint32_t i, processed;
657746825e5SPiotr Bronowski 
658746825e5SPiotr Bronowski 	processed = 0;
659746825e5SPiotr Bronowski 	for (i = 0; i < vec->num; ++i) {
660746825e5SPiotr Bronowski 		if (vec->src_sgl[i].num != 1) {
661746825e5SPiotr Bronowski 			vec->status[i] = ENOTSUP;
662746825e5SPiotr Bronowski 			continue;
663746825e5SPiotr Bronowski 		}
664746825e5SPiotr Bronowski 
665746825e5SPiotr Bronowski 		aesni_gcm_process_gmac_sgl_op(s, gdata_ctx, &vec->src_sgl[i],
666746825e5SPiotr Bronowski 					      vec->iv[i].va, ops);
667746825e5SPiotr Bronowski 		vec->status[i] = aesni_gcm_sgl_op_finalize_encryption(
668746825e5SPiotr Bronowski 		    s, gdata_ctx, vec->digest[i].va, ops);
669746825e5SPiotr Bronowski 		processed += (vec->status[i] == 0);
670746825e5SPiotr Bronowski 	}
671746825e5SPiotr Bronowski 
672746825e5SPiotr Bronowski 	return processed;
673746825e5SPiotr Bronowski }
674746825e5SPiotr Bronowski 
675746825e5SPiotr Bronowski static inline uint32_t
aesni_gmac_sgl_verify(struct aesni_gcm_session * s,struct gcm_context_data * gdata_ctx,struct rte_crypto_sym_vec * vec,struct aesni_gcm_ops ops)676746825e5SPiotr Bronowski aesni_gmac_sgl_verify(struct aesni_gcm_session *s,
677746825e5SPiotr Bronowski 		      struct gcm_context_data *gdata_ctx,
678746825e5SPiotr Bronowski 		      struct rte_crypto_sym_vec *vec,
679746825e5SPiotr Bronowski 		      struct aesni_gcm_ops ops)
680746825e5SPiotr Bronowski {
681746825e5SPiotr Bronowski 	uint32_t i, processed;
682746825e5SPiotr Bronowski 
683746825e5SPiotr Bronowski 	processed = 0;
684746825e5SPiotr Bronowski 	for (i = 0; i < vec->num; ++i) {
685746825e5SPiotr Bronowski 		if (vec->src_sgl[i].num != 1) {
686746825e5SPiotr Bronowski 			vec->status[i] = ENOTSUP;
687746825e5SPiotr Bronowski 			continue;
688746825e5SPiotr Bronowski 		}
689746825e5SPiotr Bronowski 
690746825e5SPiotr Bronowski 		aesni_gcm_process_gmac_sgl_op(s, gdata_ctx, &vec->src_sgl[i],
691746825e5SPiotr Bronowski 					      vec->iv[i].va, ops);
692746825e5SPiotr Bronowski 		vec->status[i] = aesni_gcm_sgl_op_finalize_decryption(
693746825e5SPiotr Bronowski 		    s, gdata_ctx, vec->digest[i].va, ops);
694746825e5SPiotr Bronowski 		processed += (vec->status[i] == 0);
695746825e5SPiotr Bronowski 	}
696746825e5SPiotr Bronowski 
697746825e5SPiotr Bronowski 	return processed;
698746825e5SPiotr Bronowski }
699746825e5SPiotr Bronowski 
700746825e5SPiotr Bronowski /** Process CPU crypto bulk operations */
701746825e5SPiotr Bronowski static uint32_t
aesni_gcm_process_bulk(struct rte_cryptodev * dev __rte_unused,struct rte_cryptodev_sym_session * sess,__rte_unused union rte_crypto_sym_ofs ofs,struct rte_crypto_sym_vec * vec)702bdce2564SAkhil Goyal aesni_gcm_process_bulk(struct rte_cryptodev *dev __rte_unused,
703746825e5SPiotr Bronowski 			struct rte_cryptodev_sym_session *sess,
704746825e5SPiotr Bronowski 			__rte_unused union rte_crypto_sym_ofs ofs,
705746825e5SPiotr Bronowski 			struct rte_crypto_sym_vec *vec)
706746825e5SPiotr Bronowski {
707*2a440d6aSAkhil Goyal 	struct aesni_gcm_session *s = CRYPTODEV_GET_SYM_SESS_PRIV(sess);
708746825e5SPiotr Bronowski 	struct gcm_context_data gdata_ctx;
709746825e5SPiotr Bronowski 	IMB_MGR *mb_mgr;
710746825e5SPiotr Bronowski 
711746825e5SPiotr Bronowski 	/* get per-thread MB MGR, create one if needed */
712746825e5SPiotr Bronowski 	mb_mgr = get_per_thread_mb_mgr();
713746825e5SPiotr Bronowski 	if (unlikely(mb_mgr == NULL))
714746825e5SPiotr Bronowski 		return 0;
715746825e5SPiotr Bronowski 
716746825e5SPiotr Bronowski 	/* Check if function pointers have been set for this thread ops. */
717746825e5SPiotr Bronowski 	if (unlikely(RTE_PER_LCORE(gcm_ops)[s->key_length].init == NULL))
718746825e5SPiotr Bronowski 		aesni_gcm_set_ops(RTE_PER_LCORE(gcm_ops), mb_mgr);
719746825e5SPiotr Bronowski 
720746825e5SPiotr Bronowski 	switch (s->op) {
721746825e5SPiotr Bronowski 	case IPSEC_MB_OP_AEAD_AUTHENTICATED_ENCRYPT:
722746825e5SPiotr Bronowski 		return aesni_gcm_sgl_encrypt(s, &gdata_ctx, vec,
723746825e5SPiotr Bronowski 				RTE_PER_LCORE(gcm_ops)[s->key_length]);
724746825e5SPiotr Bronowski 	case IPSEC_MB_OP_AEAD_AUTHENTICATED_DECRYPT:
725746825e5SPiotr Bronowski 		return aesni_gcm_sgl_decrypt(s, &gdata_ctx, vec,
726746825e5SPiotr Bronowski 				RTE_PER_LCORE(gcm_ops)[s->key_length]);
727746825e5SPiotr Bronowski 	case IPSEC_MB_OP_HASH_GEN_ONLY:
728746825e5SPiotr Bronowski 		return aesni_gmac_sgl_generate(s, &gdata_ctx, vec,
729746825e5SPiotr Bronowski 				RTE_PER_LCORE(gcm_ops)[s->key_length]);
730746825e5SPiotr Bronowski 	case IPSEC_MB_OP_HASH_VERIFY_ONLY:
731746825e5SPiotr Bronowski 		return aesni_gmac_sgl_verify(s, &gdata_ctx, vec,
732746825e5SPiotr Bronowski 				RTE_PER_LCORE(gcm_ops)[s->key_length]);
733746825e5SPiotr Bronowski 	default:
734746825e5SPiotr Bronowski 		aesni_gcm_fill_error_code(vec, EINVAL);
735746825e5SPiotr Bronowski 		return 0;
736746825e5SPiotr Bronowski 	}
737746825e5SPiotr Bronowski }
738746825e5SPiotr Bronowski 
739746825e5SPiotr Bronowski static int
aesni_gcm_qp_setup(struct rte_cryptodev * dev,uint16_t qp_id,const struct rte_cryptodev_qp_conf * qp_conf,int socket_id)740746825e5SPiotr Bronowski aesni_gcm_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
741746825e5SPiotr Bronowski 				const struct rte_cryptodev_qp_conf *qp_conf,
742746825e5SPiotr Bronowski 				int socket_id)
743746825e5SPiotr Bronowski {
744746825e5SPiotr Bronowski 	int ret = ipsec_mb_qp_setup(dev, qp_id, qp_conf, socket_id);
745746825e5SPiotr Bronowski 	if (ret < 0)
746746825e5SPiotr Bronowski 		return ret;
747746825e5SPiotr Bronowski 
748746825e5SPiotr Bronowski 	struct ipsec_mb_qp *qp = dev->data->queue_pairs[qp_id];
749746825e5SPiotr Bronowski 	struct aesni_gcm_qp_data *qp_data = ipsec_mb_get_qp_private_data(qp);
750746825e5SPiotr Bronowski 	aesni_gcm_set_ops(qp_data->ops, qp->mb_mgr);
751746825e5SPiotr Bronowski 	return 0;
752746825e5SPiotr Bronowski }
753746825e5SPiotr Bronowski 
754746825e5SPiotr Bronowski struct rte_cryptodev_ops aesni_gcm_pmd_ops = {
755746825e5SPiotr Bronowski 	.dev_configure = ipsec_mb_config,
756746825e5SPiotr Bronowski 	.dev_start = ipsec_mb_start,
757746825e5SPiotr Bronowski 	.dev_stop = ipsec_mb_stop,
758746825e5SPiotr Bronowski 	.dev_close = ipsec_mb_close,
759746825e5SPiotr Bronowski 
760746825e5SPiotr Bronowski 	.stats_get = ipsec_mb_stats_get,
761746825e5SPiotr Bronowski 	.stats_reset = ipsec_mb_stats_reset,
762746825e5SPiotr Bronowski 
763746825e5SPiotr Bronowski 	.dev_infos_get = ipsec_mb_info_get,
764746825e5SPiotr Bronowski 
765746825e5SPiotr Bronowski 	.queue_pair_setup = aesni_gcm_qp_setup,
766746825e5SPiotr Bronowski 	.queue_pair_release = ipsec_mb_qp_release,
767746825e5SPiotr Bronowski 
768746825e5SPiotr Bronowski 	.sym_cpu_process = aesni_gcm_process_bulk,
769746825e5SPiotr Bronowski 
770746825e5SPiotr Bronowski 	.sym_session_get_size = ipsec_mb_sym_session_get_size,
771746825e5SPiotr Bronowski 	.sym_session_configure = ipsec_mb_sym_session_configure,
772746825e5SPiotr Bronowski 	.sym_session_clear = ipsec_mb_sym_session_clear
773746825e5SPiotr Bronowski };
774746825e5SPiotr Bronowski 
775746825e5SPiotr Bronowski static int
aesni_gcm_probe(struct rte_vdev_device * vdev)776746825e5SPiotr Bronowski aesni_gcm_probe(struct rte_vdev_device *vdev)
777746825e5SPiotr Bronowski {
778746825e5SPiotr Bronowski 	return ipsec_mb_create(vdev, IPSEC_MB_PMD_TYPE_AESNI_GCM);
779746825e5SPiotr Bronowski }
780746825e5SPiotr Bronowski 
781746825e5SPiotr Bronowski static struct rte_vdev_driver cryptodev_aesni_gcm_pmd_drv = {
782746825e5SPiotr Bronowski 	.probe = aesni_gcm_probe,
783746825e5SPiotr Bronowski 	.remove = ipsec_mb_remove
784746825e5SPiotr Bronowski };
785746825e5SPiotr Bronowski 
786746825e5SPiotr Bronowski static struct cryptodev_driver aesni_gcm_crypto_drv;
787746825e5SPiotr Bronowski 
788746825e5SPiotr Bronowski RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_AESNI_GCM_PMD,
789746825e5SPiotr Bronowski 		      cryptodev_aesni_gcm_pmd_drv);
790746825e5SPiotr Bronowski RTE_PMD_REGISTER_ALIAS(CRYPTODEV_NAME_AESNI_GCM_PMD, cryptodev_aesni_gcm_pmd);
791746825e5SPiotr Bronowski RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_AESNI_GCM_PMD,
792746825e5SPiotr Bronowski 			      "max_nb_queue_pairs=<int> socket_id=<int>");
793746825e5SPiotr Bronowski RTE_PMD_REGISTER_CRYPTO_DRIVER(aesni_gcm_crypto_drv,
794746825e5SPiotr Bronowski 			       cryptodev_aesni_gcm_pmd_drv.driver,
795746825e5SPiotr Bronowski 			       pmd_driver_id_aesni_gcm);
796746825e5SPiotr Bronowski 
797746825e5SPiotr Bronowski /* Constructor function to register aesni-gcm PMD */
RTE_INIT(ipsec_mb_register_aesni_gcm)798746825e5SPiotr Bronowski RTE_INIT(ipsec_mb_register_aesni_gcm)
799746825e5SPiotr Bronowski {
800746825e5SPiotr Bronowski 	struct ipsec_mb_internals *aesni_gcm_data =
801746825e5SPiotr Bronowski 		&ipsec_mb_pmds[IPSEC_MB_PMD_TYPE_AESNI_GCM];
802746825e5SPiotr Bronowski 
803746825e5SPiotr Bronowski 	aesni_gcm_data->caps = aesni_gcm_capabilities;
804746825e5SPiotr Bronowski 	aesni_gcm_data->dequeue_burst = aesni_gcm_pmd_dequeue_burst;
805746825e5SPiotr Bronowski 	aesni_gcm_data->feature_flags =
806746825e5SPiotr Bronowski 		RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO |
807746825e5SPiotr Bronowski 		RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING |
808746825e5SPiotr Bronowski 		RTE_CRYPTODEV_FF_IN_PLACE_SGL |
809746825e5SPiotr Bronowski 		RTE_CRYPTODEV_FF_OOP_SGL_IN_LB_OUT |
810746825e5SPiotr Bronowski 		RTE_CRYPTODEV_FF_OOP_LB_IN_LB_OUT |
811746825e5SPiotr Bronowski 		RTE_CRYPTODEV_FF_SYM_CPU_CRYPTO |
812746825e5SPiotr Bronowski 		RTE_CRYPTODEV_FF_SYM_SESSIONLESS;
813746825e5SPiotr Bronowski 	aesni_gcm_data->internals_priv_size = 0;
814746825e5SPiotr Bronowski 	aesni_gcm_data->ops = &aesni_gcm_pmd_ops;
815746825e5SPiotr Bronowski 	aesni_gcm_data->qp_priv_size = sizeof(struct aesni_gcm_qp_data);
816746825e5SPiotr Bronowski 	aesni_gcm_data->queue_pair_configure = NULL;
817746825e5SPiotr Bronowski 	aesni_gcm_data->session_configure = aesni_gcm_session_configure;
818746825e5SPiotr Bronowski 	aesni_gcm_data->session_priv_size = sizeof(struct aesni_gcm_session);
819746825e5SPiotr Bronowski }
820