File Index
Files and directories
Sign in
FILE

ipsec_offload.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c C
  1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2/* Copyright (c) 2017, Mellanox Technologies inc. All rights reserved. */
  3
  4#include "mlx5_core.h"
  5#include "en.h"
  6#include "ipsec.h"
  7#include "lib/crypto.h"
  8#include "lib/ipsec_fs_roce.h"
  9#include "fs_core.h"
 10#include "eswitch.h"
 11
 12enum {
 13	MLX5_IPSEC_ASO_REMOVE_FLOW_PKT_CNT_OFFSET,
 14	MLX5_IPSEC_ASO_REMOVE_FLOW_SOFT_LFT_OFFSET,
 15};
 16
 17u32 mlx5_ipsec_device_caps(struct mlx5_core_dev *mdev)
 18{
 19	u32 caps = 0;
 20
 21	if (!MLX5_CAP_GEN(mdev, ipsec_offload))
 22		return 0;
 23
 24	if (!MLX5_CAP_GEN(mdev, log_max_dek))
 25		return 0;
 26
 27	if (!(MLX5_CAP_GEN_64(mdev, general_obj_types) &
 28	    MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_IPSEC))
 29		return 0;
 30
 31	if (!MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ipsec_encrypt) ||
 32	    !MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ipsec_decrypt))
 33		return 0;
 34
 35	if (!MLX5_CAP_IPSEC(mdev, ipsec_crypto_esp_aes_gcm_128_encrypt) ||
 36	    !MLX5_CAP_IPSEC(mdev, ipsec_crypto_esp_aes_gcm_128_decrypt))
 37		return 0;
 38
 39	if (MLX5_CAP_IPSEC(mdev, ipsec_crypto_offload) &&
 40	    MLX5_CAP_ETH(mdev, insert_trailer) && MLX5_CAP_ETH(mdev, swp))
 41		caps |= MLX5_IPSEC_CAP_CRYPTO;
 42
 43	if (MLX5_CAP_IPSEC(mdev, ipsec_full_offload) &&
 44	    (mdev->priv.steering->mode == MLX5_FLOW_STEERING_MODE_DMFS ||
 45	     is_mdev_legacy_mode(mdev))) {
 46		if (MLX5_CAP_FLOWTABLE_NIC_TX(mdev,
 47					      reformat_add_esp_trasport) &&
 48		    MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
 49					      reformat_del_esp_trasport) &&
 50		    MLX5_CAP_FLOWTABLE_NIC_RX(mdev, decap))
 51			caps |= MLX5_IPSEC_CAP_PACKET_OFFLOAD;
 52
 53		if (IS_ENABLED(CONFIG_MLX5_CLS_ACT) &&
 54		    ((MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ignore_flow_level) &&
 55		      MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ignore_flow_level)) ||
 56		     MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, ignore_flow_level)))
 57			caps |= MLX5_IPSEC_CAP_PRIO;
 58
 59		if (MLX5_CAP_FLOWTABLE_NIC_TX(mdev,
 60					      reformat_l2_to_l3_esp_tunnel) &&
 61		    MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
 62					      reformat_l3_esp_tunnel_to_l2))
 63			caps |= MLX5_IPSEC_CAP_TUNNEL;
 64
 65		if (MLX5_CAP_FLOWTABLE_NIC_TX(mdev,
 66					      reformat_add_esp_transport_over_udp) &&
 67		    MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
 68					      reformat_del_esp_transport_over_udp))
 69			caps |= MLX5_IPSEC_CAP_ESPINUDP;
 70	}
 71
 72	if (mlx5_get_roce_state(mdev) && mlx5_ipsec_fs_is_mpv_roce_supported(mdev) &&
 73	    MLX5_CAP_GEN_2(mdev, flow_table_type_2_type) & MLX5_FT_NIC_RX_2_NIC_RX_RDMA &&
 74	    MLX5_CAP_GEN_2(mdev, flow_table_type_2_type) & MLX5_FT_NIC_TX_RDMA_2_NIC_TX)
 75		caps |= MLX5_IPSEC_CAP_ROCE;
 76
 77	if (!caps)
 78		return 0;
 79
 80	if (MLX5_CAP_IPSEC(mdev, ipsec_esn))
 81		caps |= MLX5_IPSEC_CAP_ESN;
 82
 83	/* We can accommodate up to 2^24 different IPsec objects
 84	 * because we use up to 24 bit in flow table metadata
 85	 * to hold the IPsec Object unique handle.
 86	 */
 87	WARN_ON_ONCE(MLX5_CAP_IPSEC(mdev, log_max_ipsec_offload) > 24);
 88	return caps;
 89}
 90EXPORT_SYMBOL_GPL(mlx5_ipsec_device_caps);
 91
 92static void mlx5e_ipsec_packet_setup(void *obj, u32 pdn,
 93				     struct mlx5e_ipsec_sa_entry *sa_entry)
 94{
 95	struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
 96	void *aso_ctx;
 97
 98	aso_ctx = MLX5_ADDR_OF(ipsec_obj, obj, ipsec_aso);
 99	if (attrs->replay_esn.trigger) {
100		MLX5_SET(ipsec_aso, aso_ctx, esn_event_arm, 1);
101
102		if (attrs->dir == XFRM_DEV_OFFLOAD_IN) {
103			MLX5_SET(ipsec_aso, aso_ctx, window_sz,
104				 attrs->replay_esn.replay_window);
105			MLX5_SET(ipsec_aso, aso_ctx, mode,
106				 MLX5_IPSEC_ASO_REPLAY_PROTECTION);
107		}
108		MLX5_SET(ipsec_aso, aso_ctx, mode_parameter,
109			 attrs->replay_esn.esn);
110	}
111
112	/* ASO context */
113	MLX5_SET(ipsec_obj, obj, ipsec_aso_access_pd, pdn);
114	MLX5_SET(ipsec_obj, obj, full_offload, 1);
115	MLX5_SET(ipsec_aso, aso_ctx, valid, 1);
116	/* MLX5_IPSEC_ASO_REG_C_4_5 is type C register that is used
117	 * in flow steering to perform matching against. Please be
118	 * aware that this register was chosen arbitrary and can't
119	 * be used in other places as long as IPsec packet offload
120	 * active.
121	 */
122	MLX5_SET(ipsec_obj, obj, aso_return_reg, MLX5_IPSEC_ASO_REG_C_4_5);
123	if (attrs->dir == XFRM_DEV_OFFLOAD_OUT) {
124		MLX5_SET(ipsec_aso, aso_ctx, mode, MLX5_IPSEC_ASO_INC_SN);
125		if (!attrs->replay_esn.trigger)
126			MLX5_SET(ipsec_aso, aso_ctx, mode_parameter,
127				 sa_entry->esn_state.esn);
128	}
129
130	if (attrs->lft.hard_packet_limit != XFRM_INF) {
131		MLX5_SET(ipsec_aso, aso_ctx, remove_flow_pkt_cnt,
132			 attrs->lft.hard_packet_limit);
133		MLX5_SET(ipsec_aso, aso_ctx, hard_lft_arm, 1);
134		MLX5_SET(ipsec_aso, aso_ctx, remove_flow_enable, 1);
135	}
136
137	if (attrs->lft.soft_packet_limit != XFRM_INF) {
138		MLX5_SET(ipsec_aso, aso_ctx, remove_flow_soft_lft,
139			 attrs->lft.soft_packet_limit);
140
141		MLX5_SET(ipsec_aso, aso_ctx, soft_lft_arm, 1);
142	}
143}
144
145static int mlx5_create_ipsec_obj(struct mlx5e_ipsec_sa_entry *sa_entry)
146{
147	struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
148	struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
149	struct aes_gcm_keymat *aes_gcm = &attrs->aes_gcm;
150	u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
151	u32 in[MLX5_ST_SZ_DW(create_ipsec_obj_in)] = {};
152	void *obj, *salt_p, *salt_iv_p;
153	struct mlx5e_hw_objs *res;
154	int err;
155
156	obj = MLX5_ADDR_OF(create_ipsec_obj_in, in, ipsec_object);
157
158	/* salt and seq_iv */
159	salt_p = MLX5_ADDR_OF(ipsec_obj, obj, salt);
160	memcpy(salt_p, &aes_gcm->salt, sizeof(aes_gcm->salt));
161
162	MLX5_SET(ipsec_obj, obj, icv_length, MLX5_IPSEC_OBJECT_ICV_LEN_16B);
163	salt_iv_p = MLX5_ADDR_OF(ipsec_obj, obj, implicit_iv);
164	memcpy(salt_iv_p, &aes_gcm->seq_iv, sizeof(aes_gcm->seq_iv));
165	/* esn */
166	if (attrs->replay_esn.trigger) {
167		MLX5_SET(ipsec_obj, obj, esn_en, 1);
168		MLX5_SET(ipsec_obj, obj, esn_msb, attrs->replay_esn.esn_msb);
169		MLX5_SET(ipsec_obj, obj, esn_overlap, attrs->replay_esn.overlap);
170	}
171
172	MLX5_SET(ipsec_obj, obj, dekn, sa_entry->enc_key_id);
173
174	/* general object fields set */
175	MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
176		 MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
177	MLX5_SET(general_obj_in_cmd_hdr, in, obj_type,
178		 MLX5_GENERAL_OBJECT_TYPES_IPSEC);
179
180	res = &mdev->mlx5e_res.hw_objs;
181	if (attrs->type == XFRM_DEV_OFFLOAD_PACKET)
182		mlx5e_ipsec_packet_setup(obj, res->pdn, sa_entry);
183
184	err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
185	if (!err)
186		sa_entry->ipsec_obj_id =
187			MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
188
189	return err;
190}
191
192static void mlx5_destroy_ipsec_obj(struct mlx5e_ipsec_sa_entry *sa_entry)
193{
194	struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
195	u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
196	u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
197
198	MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
199		 MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
200	MLX5_SET(general_obj_in_cmd_hdr, in, obj_type,
201		 MLX5_GENERAL_OBJECT_TYPES_IPSEC);
202	MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, sa_entry->ipsec_obj_id);
203
204	mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
205}
206
207int mlx5_ipsec_create_sa_ctx(struct mlx5e_ipsec_sa_entry *sa_entry)
208{
209	struct aes_gcm_keymat *aes_gcm = &sa_entry->attrs.aes_gcm;
210	struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
211	int err;
212
213	/* key */
214	err = mlx5_create_encryption_key(mdev, aes_gcm->aes_key,
215					 aes_gcm->key_len / BITS_PER_BYTE,
216					 MLX5_ACCEL_OBJ_IPSEC_KEY,
217					 &sa_entry->enc_key_id);
218	if (err) {
219		mlx5_core_dbg(mdev, "Failed to create encryption key (err = %d)\n", err);
220		return err;
221	}
222
223	err = mlx5_create_ipsec_obj(sa_entry);
224	if (err) {
225		mlx5_core_dbg(mdev, "Failed to create IPsec object (err = %d)\n", err);
226		goto err_enc_key;
227	}
228
229	return 0;
230
231err_enc_key:
232	mlx5_destroy_encryption_key(mdev, sa_entry->enc_key_id);
233	return err;
234}
235
236void mlx5_ipsec_free_sa_ctx(struct mlx5e_ipsec_sa_entry *sa_entry)
237{
238	struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
239
240	mlx5_destroy_ipsec_obj(sa_entry);
241	mlx5_destroy_encryption_key(mdev, sa_entry->enc_key_id);
242}
243
244static int mlx5_modify_ipsec_obj(struct mlx5e_ipsec_sa_entry *sa_entry,
245				 const struct mlx5_accel_esp_xfrm_attrs *attrs)
246{
247	struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
248	u32 in[MLX5_ST_SZ_DW(modify_ipsec_obj_in)] = {};
249	u32 out[MLX5_ST_SZ_DW(query_ipsec_obj_out)];
250	u64 modify_field_select = 0;
251	u64 general_obj_types;
252	void *obj;
253	int err;
254
255	general_obj_types = MLX5_CAP_GEN_64(mdev, general_obj_types);
256	if (!(general_obj_types & MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_IPSEC))
257		return -EINVAL;
258
259	/* general object fields set */
260	MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_QUERY_GENERAL_OBJECT);
261	MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_GENERAL_OBJECT_TYPES_IPSEC);
262	MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, sa_entry->ipsec_obj_id);
263	err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
264	if (err) {
265		mlx5_core_err(mdev, "Query IPsec object failed (Object id %d), err = %d\n",
266			      sa_entry->ipsec_obj_id, err);
267		return err;
268	}
269
270	obj = MLX5_ADDR_OF(query_ipsec_obj_out, out, ipsec_object);
271	modify_field_select = MLX5_GET64(ipsec_obj, obj, modify_field_select);
272
273	/* esn */
274	if (!(modify_field_select & MLX5_MODIFY_IPSEC_BITMASK_ESN_OVERLAP) ||
275	    !(modify_field_select & MLX5_MODIFY_IPSEC_BITMASK_ESN_MSB))
276		return -EOPNOTSUPP;
277
278	obj = MLX5_ADDR_OF(modify_ipsec_obj_in, in, ipsec_object);
279	MLX5_SET64(ipsec_obj, obj, modify_field_select,
280		   MLX5_MODIFY_IPSEC_BITMASK_ESN_OVERLAP |
281			   MLX5_MODIFY_IPSEC_BITMASK_ESN_MSB);
282	MLX5_SET(ipsec_obj, obj, esn_msb, attrs->replay_esn.esn_msb);
283	MLX5_SET(ipsec_obj, obj, esn_overlap, attrs->replay_esn.overlap);
284
285	/* general object fields set */
286	MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_MODIFY_GENERAL_OBJECT);
287
288	return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
289}
290
291void mlx5_accel_esp_modify_xfrm(struct mlx5e_ipsec_sa_entry *sa_entry,
292				const struct mlx5_accel_esp_xfrm_attrs *attrs)
293{
294	int err;
295
296	err = mlx5_modify_ipsec_obj(sa_entry, attrs);
297	if (err)
298		return;
299
300	memcpy(&sa_entry->attrs, attrs, sizeof(sa_entry->attrs));
301}
302
303static void mlx5e_ipsec_aso_update(struct mlx5e_ipsec_sa_entry *sa_entry,
304				   struct mlx5_wqe_aso_ctrl_seg *data)
305{
306	data->data_mask_mode = MLX5_ASO_DATA_MASK_MODE_BITWISE_64BIT << 6;
307	data->condition_1_0_operand = MLX5_ASO_ALWAYS_TRUE |
308				      MLX5_ASO_ALWAYS_TRUE << 4;
309
310	mlx5e_ipsec_aso_query(sa_entry, data);
311}
312
313static void
314mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry,
315			     u32 mode_param,
316			     struct mlx5_accel_esp_xfrm_attrs *attrs)
317{
318	struct mlx5_wqe_aso_ctrl_seg data = {};
319
320	if (mode_param < MLX5E_IPSEC_ESN_SCOPE_MID) {
321		sa_entry->esn_state.esn_msb++;
322		sa_entry->esn_state.overlap = 0;
323	} else {
324		sa_entry->esn_state.overlap = 1;
325	}
326
327	mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, attrs);
328
329	data.data_offset_condition_operand =
330		MLX5_IPSEC_ASO_REMOVE_FLOW_PKT_CNT_OFFSET;
331	data.bitwise_data = cpu_to_be64(BIT_ULL(54));
332	data.data_mask = data.bitwise_data;
333
334	mlx5e_ipsec_aso_update(sa_entry, &data);
335}
336
337static void mlx5e_ipsec_aso_update_hard(struct mlx5e_ipsec_sa_entry *sa_entry)
338{
339	struct mlx5_wqe_aso_ctrl_seg data = {};
340
341	data.data_offset_condition_operand =
342		MLX5_IPSEC_ASO_REMOVE_FLOW_PKT_CNT_OFFSET;
343	data.bitwise_data = cpu_to_be64(BIT_ULL(57) + BIT_ULL(31));
344	data.data_mask = data.bitwise_data;
345	mlx5e_ipsec_aso_update(sa_entry, &data);
346}
347
348static void mlx5e_ipsec_aso_update_soft(struct mlx5e_ipsec_sa_entry *sa_entry,
349					u32 val)
350{
351	struct mlx5_wqe_aso_ctrl_seg data = {};
352
353	data.data_offset_condition_operand =
354		MLX5_IPSEC_ASO_REMOVE_FLOW_SOFT_LFT_OFFSET;
355	data.bitwise_data = cpu_to_be64(val);
356	data.data_mask = cpu_to_be64(U32_MAX);
357	mlx5e_ipsec_aso_update(sa_entry, &data);
358}
359
360static void mlx5e_ipsec_handle_limits(struct mlx5e_ipsec_sa_entry *sa_entry)
361{
362	struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
363	bool soft_arm, hard_arm;
364	u64 hard_cnt;
365
366	lockdep_assert_held(&sa_entry->x->lock);
367
368	soft_arm = !MLX5_GET(ipsec_aso, sa_entry->ctx, soft_lft_arm);
369	hard_arm = !MLX5_GET(ipsec_aso, sa_entry->ctx, hard_lft_arm);
370	if (!soft_arm && !hard_arm)
371		/* It is not lifetime event */
372		return;
373
374	hard_cnt = MLX5_GET(ipsec_aso, sa_entry->ctx, remove_flow_pkt_cnt);
375	if (!hard_cnt || hard_arm) {
376		/* It is possible to see packet counter equal to zero without
377		 * hard limit event armed. Such situation can be if packet
378		 * decreased, while we handled soft limit event.
379		 *
380		 * However it will be HW/FW bug if hard limit event is raised
381		 * and packet counter is not zero.
382		 */
383		WARN_ON_ONCE(hard_arm && hard_cnt);
384
385		/* Notify about hard limit */
386		xfrm_state_check_expire(sa_entry->x);
387		return;
388	}
389
390	/* We are in soft limit event. */
391	if (!sa_entry->limits.soft_limit_hit &&
392	    sa_entry->limits.round == attrs->lft.numb_rounds_soft) {
393		sa_entry->limits.soft_limit_hit = true;
394		/* Notify about soft limit */
395		xfrm_state_check_expire(sa_entry->x);
396
397		if (sa_entry->limits.round == attrs->lft.numb_rounds_hard)
398			goto hard;
399
400		if (attrs->lft.soft_packet_limit > BIT_ULL(31)) {
401			/* We cannot avoid a soft_value that might have the high
402			 * bit set. For instance soft_value=2^31+1 cannot be
403			 * adjusted to the low bit clear version of soft_value=1
404			 * because it is too close to 0.
405			 *
406			 * Thus we have this corner case where we can hit the
407			 * soft_limit with the high bit set, but cannot adjust
408			 * the counter. Thus we set a temporary interrupt_value
409			 * at least 2^30 away from here and do the adjustment
410			 * then.
411			 */
412			mlx5e_ipsec_aso_update_soft(sa_entry,
413						    BIT_ULL(31) - BIT_ULL(30));
414			sa_entry->limits.fix_limit = true;
415			return;
416		}
417
418		sa_entry->limits.fix_limit = true;
419	}
420
421hard:
422	if (sa_entry->limits.round == attrs->lft.numb_rounds_hard) {
423		mlx5e_ipsec_aso_update_soft(sa_entry, 0);
424		attrs->lft.soft_packet_limit = XFRM_INF;
425		return;
426	}
427
428	mlx5e_ipsec_aso_update_hard(sa_entry);
429	sa_entry->limits.round++;
430	if (sa_entry->limits.round == attrs->lft.numb_rounds_soft)
431		mlx5e_ipsec_aso_update_soft(sa_entry,
432					    attrs->lft.soft_packet_limit);
433	if (sa_entry->limits.fix_limit) {
434		sa_entry->limits.fix_limit = false;
435		mlx5e_ipsec_aso_update_soft(sa_entry, BIT_ULL(31) - 1);
436	}
437}
438
439static void mlx5e_ipsec_handle_event(struct work_struct *_work)
440{
441	struct mlx5e_ipsec_work *work =
442		container_of(_work, struct mlx5e_ipsec_work, work);
443	struct mlx5e_ipsec_sa_entry *sa_entry = work->data;
444	struct mlx5_accel_esp_xfrm_attrs tmp = {};
445	struct mlx5_accel_esp_xfrm_attrs *attrs;
446	bool need_modify = false;
447	int ret;
448
449	attrs = &sa_entry->attrs;
450
451	spin_lock_bh(&sa_entry->x->lock);
452	ret = mlx5e_ipsec_aso_query(sa_entry, NULL);
453	if (ret)
454		goto unlock;
455
456	if (attrs->lft.soft_packet_limit != XFRM_INF)
457		mlx5e_ipsec_handle_limits(sa_entry);
458
459	if (attrs->replay_esn.trigger &&
460	    !MLX5_GET(ipsec_aso, sa_entry->ctx, esn_event_arm)) {
461		u32 mode_param = MLX5_GET(ipsec_aso, sa_entry->ctx,
462					  mode_parameter);
463
464		mlx5e_ipsec_update_esn_state(sa_entry, mode_param, &tmp);
465		need_modify = true;
466	}
467
468unlock:
469	spin_unlock_bh(&sa_entry->x->lock);
470	if (need_modify)
471		mlx5_accel_esp_modify_xfrm(sa_entry, &tmp);
472	kfree(work);
473}
474
475static int mlx5e_ipsec_event(struct notifier_block *nb, unsigned long event,
476			     void *data)
477{
478	struct mlx5e_ipsec *ipsec = container_of(nb, struct mlx5e_ipsec, nb);
479	struct mlx5e_ipsec_sa_entry *sa_entry;
480	struct mlx5_eqe_obj_change *object;
481	struct mlx5e_ipsec_work *work;
482	struct mlx5_eqe *eqe = data;
483	u16 type;
484
485	if (event != MLX5_EVENT_TYPE_OBJECT_CHANGE)
486		return NOTIFY_DONE;
487
488	object = &eqe->data.obj_change;
489	type = be16_to_cpu(object->obj_type);
490
491	if (type != MLX5_GENERAL_OBJECT_TYPES_IPSEC)
492		return NOTIFY_DONE;
493
494	sa_entry = xa_load(&ipsec->sadb, be32_to_cpu(object->obj_id));
495	if (!sa_entry)
496		return NOTIFY_DONE;
497
498	work = kmalloc(sizeof(*work), GFP_ATOMIC);
499	if (!work)
500		return NOTIFY_DONE;
501
502	INIT_WORK(&work->work, mlx5e_ipsec_handle_event);
503	work->data = sa_entry;
504
505	queue_work(ipsec->wq, &work->work);
506	return NOTIFY_OK;
507}
508
509int mlx5e_ipsec_aso_init(struct mlx5e_ipsec *ipsec)
510{
511	struct mlx5_core_dev *mdev = ipsec->mdev;
512	struct mlx5e_ipsec_aso *aso;
513	struct mlx5e_hw_objs *res;
514	struct device *pdev;
515	int err;
516
517	aso = kzalloc(sizeof(*ipsec->aso), GFP_KERNEL);
518	if (!aso)
519		return -ENOMEM;
520
521	res = &mdev->mlx5e_res.hw_objs;
522
523	pdev = mlx5_core_dma_dev(mdev);
524	aso->dma_addr = dma_map_single(pdev, aso->ctx, sizeof(aso->ctx),
525				       DMA_BIDIRECTIONAL);
526	err = dma_mapping_error(pdev, aso->dma_addr);
527	if (err)
528		goto err_dma;
529
530	aso->aso = mlx5_aso_create(mdev, res->pdn);
531	if (IS_ERR(aso->aso)) {
532		err = PTR_ERR(aso->aso);
533		goto err_aso_create;
534	}
535
536	spin_lock_init(&aso->lock);
537	ipsec->nb.notifier_call = mlx5e_ipsec_event;
538	mlx5_notifier_register(mdev, &ipsec->nb);
539
540	ipsec->aso = aso;
541	return 0;
542
543err_aso_create:
544	dma_unmap_single(pdev, aso->dma_addr, sizeof(aso->ctx),
545			 DMA_BIDIRECTIONAL);
546err_dma:
547	kfree(aso);
548	return err;
549}
550
551void mlx5e_ipsec_aso_cleanup(struct mlx5e_ipsec *ipsec)
552{
553	struct mlx5_core_dev *mdev = ipsec->mdev;
554	struct mlx5e_ipsec_aso *aso;
555	struct device *pdev;
556
557	aso = ipsec->aso;
558	pdev = mlx5_core_dma_dev(mdev);
559
560	mlx5_notifier_unregister(mdev, &ipsec->nb);
561	mlx5_aso_destroy(aso->aso);
562	dma_unmap_single(pdev, aso->dma_addr, sizeof(aso->ctx),
563			 DMA_BIDIRECTIONAL);
564	kfree(aso);
565	ipsec->aso = NULL;
566}
567
568static void mlx5e_ipsec_aso_copy(struct mlx5_wqe_aso_ctrl_seg *ctrl,
569				 struct mlx5_wqe_aso_ctrl_seg *data)
570{
571	if (!data)
572		return;
573
574	ctrl->data_mask_mode = data->data_mask_mode;
575	ctrl->condition_1_0_operand = data->condition_1_0_operand;
576	ctrl->condition_1_0_offset = data->condition_1_0_offset;
577	ctrl->data_offset_condition_operand = data->data_offset_condition_operand;
578	ctrl->condition_0_data = data->condition_0_data;
579	ctrl->condition_0_mask = data->condition_0_mask;
580	ctrl->condition_1_data = data->condition_1_data;
581	ctrl->condition_1_mask = data->condition_1_mask;
582	ctrl->bitwise_data = data->bitwise_data;
583	ctrl->data_mask = data->data_mask;
584}
585
586int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry,
587			  struct mlx5_wqe_aso_ctrl_seg *data)
588{
589	struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
590	struct mlx5e_ipsec_aso *aso = ipsec->aso;
591	struct mlx5_core_dev *mdev = ipsec->mdev;
592	struct mlx5_wqe_aso_ctrl_seg *ctrl;
593	struct mlx5e_hw_objs *res;
594	struct mlx5_aso_wqe *wqe;
595	unsigned long expires;
596	u8 ds_cnt;
597	int ret;
598
599	lockdep_assert_held(&sa_entry->x->lock);
600	res = &mdev->mlx5e_res.hw_objs;
601
602	spin_lock_bh(&aso->lock);
603	memset(aso->ctx, 0, sizeof(aso->ctx));
604	wqe = mlx5_aso_get_wqe(aso->aso);
605	ds_cnt = DIV_ROUND_UP(sizeof(*wqe), MLX5_SEND_WQE_DS);
606	mlx5_aso_build_wqe(aso->aso, ds_cnt, wqe, sa_entry->ipsec_obj_id,
607			   MLX5_ACCESS_ASO_OPC_MOD_IPSEC);
608
609	ctrl = &wqe->aso_ctrl;
610	ctrl->va_l =
611		cpu_to_be32(lower_32_bits(aso->dma_addr) | ASO_CTRL_READ_EN);
612	ctrl->va_h = cpu_to_be32(upper_32_bits(aso->dma_addr));
613	ctrl->l_key = cpu_to_be32(res->mkey);
614	mlx5e_ipsec_aso_copy(ctrl, data);
615
616	mlx5_aso_post_wqe(aso->aso, false, &wqe->ctrl);
617	expires = jiffies + msecs_to_jiffies(10);
618	do {
619		ret = mlx5_aso_poll_cq(aso->aso, false);
620		if (ret)
621			/* We are in atomic context */
622			udelay(10);
623	} while (ret && time_is_after_jiffies(expires));
624	if (!ret)
625		memcpy(sa_entry->ctx, aso->ctx, MLX5_ST_SZ_BYTES(ipsec_aso));
626	spin_unlock_bh(&aso->lock);
627	return ret;
628}
~/ Read-only file preview.