1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 
4 #include "dr_types.h"
5 #include "dr_ste.h"
6 
7 struct dr_definer_object {
8 	u32 id;
9 	u16 format_id;
10 	u8 dw_selectors[MLX5_IFC_DEFINER_DW_SELECTORS_NUM];
11 	u8 byte_selectors[MLX5_IFC_DEFINER_BYTE_SELECTORS_NUM];
12 	u8 match_mask[DR_STE_SIZE_MATCH_TAG];
13 	refcount_t refcount;
14 };
15 
dr_definer_compare(struct dr_definer_object * definer,u16 format_id,u8 * dw_selectors,u8 * byte_selectors,u8 * match_mask)16 static bool dr_definer_compare(struct dr_definer_object *definer,
17 			       u16 format_id, u8 *dw_selectors,
18 			       u8 *byte_selectors, u8 *match_mask)
19 {
20 	int i;
21 
22 	if (definer->format_id != format_id)
23 		return false;
24 
25 	for (i = 0; i < MLX5_IFC_DEFINER_DW_SELECTORS_NUM; i++)
26 		if (definer->dw_selectors[i] != dw_selectors[i])
27 			return false;
28 
29 	for (i = 0; i < MLX5_IFC_DEFINER_BYTE_SELECTORS_NUM; i++)
30 		if (definer->byte_selectors[i] != byte_selectors[i])
31 			return false;
32 
33 	if (memcmp(definer->match_mask, match_mask, DR_STE_SIZE_MATCH_TAG))
34 		return false;
35 
36 	return true;
37 }
38 
39 static struct dr_definer_object *
dr_definer_find_obj(struct mlx5dr_domain * dmn,u16 format_id,u8 * dw_selectors,u8 * byte_selectors,u8 * match_mask)40 dr_definer_find_obj(struct mlx5dr_domain *dmn, u16 format_id,
41 		    u8 *dw_selectors, u8 *byte_selectors, u8 *match_mask)
42 {
43 	struct dr_definer_object *definer_obj;
44 	unsigned long id;
45 
46 	xa_for_each(&dmn->definers_xa, id, definer_obj) {
47 		if (dr_definer_compare(definer_obj, format_id,
48 				       dw_selectors, byte_selectors,
49 				       match_mask))
50 			return definer_obj;
51 	}
52 
53 	return NULL;
54 }
55 
56 static struct dr_definer_object *
dr_definer_create_obj(struct mlx5dr_domain * dmn,u16 format_id,u8 * dw_selectors,u8 * byte_selectors,u8 * match_mask)57 dr_definer_create_obj(struct mlx5dr_domain *dmn, u16 format_id,
58 		      u8 *dw_selectors, u8 *byte_selectors, u8 *match_mask)
59 {
60 	struct dr_definer_object *definer_obj;
61 	int ret = 0;
62 
63 	definer_obj = kzalloc(sizeof(*definer_obj), GFP_KERNEL);
64 	if (!definer_obj)
65 		return NULL;
66 
67 	ret = mlx5dr_cmd_create_definer(dmn->mdev,
68 					format_id,
69 					dw_selectors,
70 					byte_selectors,
71 					match_mask,
72 					&definer_obj->id);
73 	if (ret)
74 		goto err_free_definer_obj;
75 
76 	/* Definer ID can have 32 bits, but STE format
77 	 * supports only definers with 8 bit IDs.
78 	 */
79 	if (definer_obj->id > 0xff) {
80 		mlx5dr_err(dmn, "Unsupported definer ID (%d)\n", definer_obj->id);
81 		goto err_destroy_definer;
82 	}
83 
84 	definer_obj->format_id = format_id;
85 	memcpy(definer_obj->dw_selectors, dw_selectors, sizeof(definer_obj->dw_selectors));
86 	memcpy(definer_obj->byte_selectors, byte_selectors, sizeof(definer_obj->byte_selectors));
87 	memcpy(definer_obj->match_mask, match_mask, sizeof(definer_obj->match_mask));
88 
89 	refcount_set(&definer_obj->refcount, 1);
90 
91 	ret = xa_insert(&dmn->definers_xa, definer_obj->id, definer_obj, GFP_KERNEL);
92 	if (ret) {
93 		mlx5dr_dbg(dmn, "Couldn't insert new definer into xarray (%d)\n", ret);
94 		goto err_destroy_definer;
95 	}
96 
97 	return definer_obj;
98 
99 err_destroy_definer:
100 	mlx5dr_cmd_destroy_definer(dmn->mdev, definer_obj->id);
101 err_free_definer_obj:
102 	kfree(definer_obj);
103 
104 	return NULL;
105 }
106 
dr_definer_destroy_obj(struct mlx5dr_domain * dmn,struct dr_definer_object * definer_obj)107 static void dr_definer_destroy_obj(struct mlx5dr_domain *dmn,
108 				   struct dr_definer_object *definer_obj)
109 {
110 	mlx5dr_cmd_destroy_definer(dmn->mdev, definer_obj->id);
111 	xa_erase(&dmn->definers_xa, definer_obj->id);
112 	kfree(definer_obj);
113 }
114 
mlx5dr_definer_get(struct mlx5dr_domain * dmn,u16 format_id,u8 * dw_selectors,u8 * byte_selectors,u8 * match_mask,u32 * definer_id)115 int mlx5dr_definer_get(struct mlx5dr_domain *dmn, u16 format_id,
116 		       u8 *dw_selectors, u8 *byte_selectors,
117 		       u8 *match_mask, u32 *definer_id)
118 {
119 	struct dr_definer_object *definer_obj;
120 	int ret = 0;
121 
122 	definer_obj = dr_definer_find_obj(dmn, format_id, dw_selectors,
123 					  byte_selectors, match_mask);
124 	if (!definer_obj) {
125 		definer_obj = dr_definer_create_obj(dmn, format_id,
126 						    dw_selectors, byte_selectors,
127 						    match_mask);
128 		if (!definer_obj)
129 			return -ENOMEM;
130 	} else {
131 		refcount_inc(&definer_obj->refcount);
132 	}
133 
134 	*definer_id = definer_obj->id;
135 
136 	return ret;
137 }
138 
mlx5dr_definer_put(struct mlx5dr_domain * dmn,u32 definer_id)139 void mlx5dr_definer_put(struct mlx5dr_domain *dmn, u32 definer_id)
140 {
141 	struct dr_definer_object *definer_obj;
142 
143 	definer_obj = xa_load(&dmn->definers_xa, definer_id);
144 	if (!definer_obj) {
145 		mlx5dr_err(dmn, "Definer ID %d not found\n", definer_id);
146 		return;
147 	}
148 
149 	if (refcount_dec_and_test(&definer_obj->refcount))
150 		dr_definer_destroy_obj(dmn, definer_obj);
151 }
152