1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
4 #include <linux/mlx5/device.h>
5 #include <linux/mlx5/vport.h>
6 #include "mlx5_core.h"
7 #include "eswitch.h"
8
esw_ipsec_vf_query_generic(struct mlx5_core_dev * dev,u16 vport_num,bool * result)9 static int esw_ipsec_vf_query_generic(struct mlx5_core_dev *dev, u16 vport_num, bool *result)
10 {
11 int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
12 void *hca_cap, *query_cap;
13 int err;
14
15 if (!MLX5_CAP_GEN(dev, vhca_resource_manager))
16 return -EOPNOTSUPP;
17
18 if (!mlx5_esw_ipsec_vf_offload_supported(dev)) {
19 *result = false;
20 return 0;
21 }
22
23 query_cap = kvzalloc(query_sz, GFP_KERNEL);
24 if (!query_cap)
25 return -ENOMEM;
26
27 err = mlx5_vport_get_other_func_general_cap(dev, vport_num, query_cap);
28 if (err)
29 goto free;
30
31 hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
32 *result = MLX5_GET(cmd_hca_cap, hca_cap, ipsec_offload);
33 free:
34 kvfree(query_cap);
35 return err;
36 }
37
38 enum esw_vport_ipsec_offload {
39 MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD,
40 MLX5_ESW_VPORT_IPSEC_PACKET_OFFLOAD,
41 };
42
mlx5_esw_ipsec_vf_offload_get(struct mlx5_core_dev * dev,struct mlx5_vport * vport)43 int mlx5_esw_ipsec_vf_offload_get(struct mlx5_core_dev *dev, struct mlx5_vport *vport)
44 {
45 int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
46 void *hca_cap, *query_cap;
47 bool ipsec_enabled;
48 int err;
49
50 /* Querying IPsec caps only makes sense when generic ipsec_offload
51 * HCA cap is enabled
52 */
53 err = esw_ipsec_vf_query_generic(dev, vport->vport, &ipsec_enabled);
54 if (err)
55 return err;
56
57 if (!ipsec_enabled) {
58 vport->info.ipsec_crypto_enabled = false;
59 vport->info.ipsec_packet_enabled = false;
60 return 0;
61 }
62
63 query_cap = kvzalloc(query_sz, GFP_KERNEL);
64 if (!query_cap)
65 return -ENOMEM;
66
67 err = mlx5_vport_get_other_func_cap(dev, vport->vport, query_cap, MLX5_CAP_IPSEC);
68 if (err)
69 goto free;
70
71 hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
72 vport->info.ipsec_crypto_enabled =
73 MLX5_GET(ipsec_cap, hca_cap, ipsec_crypto_offload);
74 vport->info.ipsec_packet_enabled =
75 MLX5_GET(ipsec_cap, hca_cap, ipsec_full_offload);
76 free:
77 kvfree(query_cap);
78 return err;
79 }
80
esw_ipsec_vf_set_generic(struct mlx5_core_dev * dev,u16 vport_num,bool ipsec_ofld)81 static int esw_ipsec_vf_set_generic(struct mlx5_core_dev *dev, u16 vport_num, bool ipsec_ofld)
82 {
83 int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
84 int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in);
85 void *hca_cap, *query_cap, *cap;
86 int ret;
87
88 if (!MLX5_CAP_GEN(dev, vhca_resource_manager))
89 return -EOPNOTSUPP;
90
91 query_cap = kvzalloc(query_sz, GFP_KERNEL);
92 hca_cap = kvzalloc(set_sz, GFP_KERNEL);
93 if (!hca_cap || !query_cap) {
94 ret = -ENOMEM;
95 goto free;
96 }
97
98 ret = mlx5_vport_get_other_func_general_cap(dev, vport_num, query_cap);
99 if (ret)
100 goto free;
101
102 cap = MLX5_ADDR_OF(set_hca_cap_in, hca_cap, capability);
103 memcpy(cap, MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability),
104 MLX5_UN_SZ_BYTES(hca_cap_union));
105 MLX5_SET(cmd_hca_cap, cap, ipsec_offload, ipsec_ofld);
106
107 MLX5_SET(set_hca_cap_in, hca_cap, opcode, MLX5_CMD_OP_SET_HCA_CAP);
108 MLX5_SET(set_hca_cap_in, hca_cap, other_function, 1);
109 MLX5_SET(set_hca_cap_in, hca_cap, function_id, vport_num);
110
111 MLX5_SET(set_hca_cap_in, hca_cap, op_mod,
112 MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1);
113 ret = mlx5_cmd_exec_in(dev, set_hca_cap, hca_cap);
114 free:
115 kvfree(hca_cap);
116 kvfree(query_cap);
117 return ret;
118 }
119
esw_ipsec_vf_set_bytype(struct mlx5_core_dev * dev,struct mlx5_vport * vport,bool enable,enum esw_vport_ipsec_offload type)120 static int esw_ipsec_vf_set_bytype(struct mlx5_core_dev *dev, struct mlx5_vport *vport,
121 bool enable, enum esw_vport_ipsec_offload type)
122 {
123 int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
124 int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in);
125 void *hca_cap, *query_cap, *cap;
126 int ret;
127
128 if (!MLX5_CAP_GEN(dev, vhca_resource_manager))
129 return -EOPNOTSUPP;
130
131 query_cap = kvzalloc(query_sz, GFP_KERNEL);
132 hca_cap = kvzalloc(set_sz, GFP_KERNEL);
133 if (!hca_cap || !query_cap) {
134 ret = -ENOMEM;
135 goto free;
136 }
137
138 ret = mlx5_vport_get_other_func_cap(dev, vport->vport, query_cap, MLX5_CAP_IPSEC);
139 if (ret)
140 goto free;
141
142 cap = MLX5_ADDR_OF(set_hca_cap_in, hca_cap, capability);
143 memcpy(cap, MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability),
144 MLX5_UN_SZ_BYTES(hca_cap_union));
145
146 switch (type) {
147 case MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD:
148 MLX5_SET(ipsec_cap, cap, ipsec_crypto_offload, enable);
149 break;
150 case MLX5_ESW_VPORT_IPSEC_PACKET_OFFLOAD:
151 MLX5_SET(ipsec_cap, cap, ipsec_full_offload, enable);
152 break;
153 default:
154 ret = -EOPNOTSUPP;
155 goto free;
156 }
157
158 MLX5_SET(set_hca_cap_in, hca_cap, opcode, MLX5_CMD_OP_SET_HCA_CAP);
159 MLX5_SET(set_hca_cap_in, hca_cap, other_function, 1);
160 MLX5_SET(set_hca_cap_in, hca_cap, function_id, vport->vport);
161
162 MLX5_SET(set_hca_cap_in, hca_cap, op_mod,
163 MLX5_SET_HCA_CAP_OP_MOD_IPSEC << 1);
164 ret = mlx5_cmd_exec_in(dev, set_hca_cap, hca_cap);
165 free:
166 kvfree(hca_cap);
167 kvfree(query_cap);
168 return ret;
169 }
170
esw_ipsec_vf_crypto_aux_caps_set(struct mlx5_core_dev * dev,u16 vport_num,bool enable)171 static int esw_ipsec_vf_crypto_aux_caps_set(struct mlx5_core_dev *dev, u16 vport_num, bool enable)
172 {
173 int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
174 int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in);
175 struct mlx5_eswitch *esw = dev->priv.eswitch;
176 void *hca_cap, *query_cap, *cap;
177 int ret;
178
179 query_cap = kvzalloc(query_sz, GFP_KERNEL);
180 hca_cap = kvzalloc(set_sz, GFP_KERNEL);
181 if (!hca_cap || !query_cap) {
182 ret = -ENOMEM;
183 goto free;
184 }
185
186 ret = mlx5_vport_get_other_func_cap(dev, vport_num, query_cap, MLX5_CAP_ETHERNET_OFFLOADS);
187 if (ret)
188 goto free;
189
190 cap = MLX5_ADDR_OF(set_hca_cap_in, hca_cap, capability);
191 memcpy(cap, MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability),
192 MLX5_UN_SZ_BYTES(hca_cap_union));
193 MLX5_SET(per_protocol_networking_offload_caps, cap, insert_trailer, enable);
194 MLX5_SET(set_hca_cap_in, hca_cap, opcode, MLX5_CMD_OP_SET_HCA_CAP);
195 MLX5_SET(set_hca_cap_in, hca_cap, other_function, 1);
196 MLX5_SET(set_hca_cap_in, hca_cap, function_id, vport_num);
197 MLX5_SET(set_hca_cap_in, hca_cap, op_mod,
198 MLX5_SET_HCA_CAP_OP_MOD_ETHERNET_OFFLOADS << 1);
199 ret = mlx5_cmd_exec_in(esw->dev, set_hca_cap, hca_cap);
200 free:
201 kvfree(hca_cap);
202 kvfree(query_cap);
203 return ret;
204 }
205
esw_ipsec_vf_offload_set_bytype(struct mlx5_eswitch * esw,struct mlx5_vport * vport,bool enable,enum esw_vport_ipsec_offload type)206 static int esw_ipsec_vf_offload_set_bytype(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
207 bool enable, enum esw_vport_ipsec_offload type)
208 {
209 struct mlx5_core_dev *dev = esw->dev;
210 int err;
211
212 if (vport->vport == MLX5_VPORT_PF)
213 return -EOPNOTSUPP;
214
215 if (type == MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD) {
216 err = esw_ipsec_vf_crypto_aux_caps_set(dev, vport->vport, enable);
217 if (err)
218 return err;
219 }
220
221 if (enable) {
222 err = esw_ipsec_vf_set_generic(dev, vport->vport, enable);
223 if (err)
224 return err;
225 err = esw_ipsec_vf_set_bytype(dev, vport, enable, type);
226 if (err)
227 return err;
228 } else {
229 err = esw_ipsec_vf_set_bytype(dev, vport, enable, type);
230 if (err)
231 return err;
232 err = mlx5_esw_ipsec_vf_offload_get(dev, vport);
233 if (err)
234 return err;
235
236 /* The generic ipsec_offload cap can be disabled only if both
237 * ipsec_crypto_offload and ipsec_full_offload aren't enabled.
238 */
239 if (!vport->info.ipsec_crypto_enabled &&
240 !vport->info.ipsec_packet_enabled) {
241 err = esw_ipsec_vf_set_generic(dev, vport->vport, enable);
242 if (err)
243 return err;
244 }
245 }
246
247 switch (type) {
248 case MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD:
249 vport->info.ipsec_crypto_enabled = enable;
250 break;
251 case MLX5_ESW_VPORT_IPSEC_PACKET_OFFLOAD:
252 vport->info.ipsec_packet_enabled = enable;
253 break;
254 default:
255 return -EINVAL;
256 }
257
258 return 0;
259 }
260
esw_ipsec_offload_supported(struct mlx5_core_dev * dev,u16 vport_num)261 static int esw_ipsec_offload_supported(struct mlx5_core_dev *dev, u16 vport_num)
262 {
263 int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
264 void *hca_cap, *query_cap;
265 int ret;
266
267 query_cap = kvzalloc(query_sz, GFP_KERNEL);
268 if (!query_cap)
269 return -ENOMEM;
270
271 ret = mlx5_vport_get_other_func_cap(dev, vport_num, query_cap, MLX5_CAP_GENERAL);
272 if (ret)
273 goto free;
274
275 hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
276 if (!MLX5_GET(cmd_hca_cap, hca_cap, log_max_dek))
277 ret = -EOPNOTSUPP;
278 free:
279 kvfree(query_cap);
280 return ret;
281 }
282
mlx5_esw_ipsec_vf_offload_supported(struct mlx5_core_dev * dev)283 bool mlx5_esw_ipsec_vf_offload_supported(struct mlx5_core_dev *dev)
284 {
285 /* Old firmware doesn't support ipsec_offload capability for VFs. This
286 * can be detected by checking reformat_add_esp_trasport capability -
287 * when this cap isn't supported it means firmware cannot be trusted
288 * about what it reports for ipsec_offload cap.
289 */
290 return MLX5_CAP_FLOWTABLE_NIC_TX(dev, reformat_add_esp_trasport);
291 }
292
mlx5_esw_ipsec_vf_crypto_offload_supported(struct mlx5_core_dev * dev,u16 vport_num)293 int mlx5_esw_ipsec_vf_crypto_offload_supported(struct mlx5_core_dev *dev,
294 u16 vport_num)
295 {
296 int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
297 void *hca_cap, *query_cap;
298 int err;
299
300 if (!mlx5_esw_ipsec_vf_offload_supported(dev))
301 return -EOPNOTSUPP;
302
303 err = esw_ipsec_offload_supported(dev, vport_num);
304 if (err)
305 return err;
306
307 query_cap = kvzalloc(query_sz, GFP_KERNEL);
308 if (!query_cap)
309 return -ENOMEM;
310
311 err = mlx5_vport_get_other_func_cap(dev, vport_num, query_cap, MLX5_CAP_ETHERNET_OFFLOADS);
312 if (err)
313 goto free;
314
315 hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
316 if (!MLX5_GET(per_protocol_networking_offload_caps, hca_cap, swp))
317 goto free;
318
319 free:
320 kvfree(query_cap);
321 return err;
322 }
323
mlx5_esw_ipsec_vf_packet_offload_supported(struct mlx5_core_dev * dev,u16 vport_num)324 int mlx5_esw_ipsec_vf_packet_offload_supported(struct mlx5_core_dev *dev,
325 u16 vport_num)
326 {
327 int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
328 void *hca_cap, *query_cap;
329 int ret;
330
331 if (!mlx5_esw_ipsec_vf_offload_supported(dev))
332 return -EOPNOTSUPP;
333
334 ret = esw_ipsec_offload_supported(dev, vport_num);
335 if (ret)
336 return ret;
337
338 query_cap = kvzalloc(query_sz, GFP_KERNEL);
339 if (!query_cap)
340 return -ENOMEM;
341
342 ret = mlx5_vport_get_other_func_cap(dev, vport_num, query_cap, MLX5_CAP_FLOW_TABLE);
343 if (ret)
344 goto out;
345
346 hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
347 if (!MLX5_GET(flow_table_nic_cap, hca_cap, flow_table_properties_nic_receive.decap)) {
348 ret = -EOPNOTSUPP;
349 goto out;
350 }
351
352 out:
353 kvfree(query_cap);
354 return ret;
355 }
356
mlx5_esw_ipsec_vf_crypto_offload_set(struct mlx5_eswitch * esw,struct mlx5_vport * vport,bool enable)357 int mlx5_esw_ipsec_vf_crypto_offload_set(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
358 bool enable)
359 {
360 return esw_ipsec_vf_offload_set_bytype(esw, vport, enable,
361 MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD);
362 }
363
mlx5_esw_ipsec_vf_packet_offload_set(struct mlx5_eswitch * esw,struct mlx5_vport * vport,bool enable)364 int mlx5_esw_ipsec_vf_packet_offload_set(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
365 bool enable)
366 {
367 return esw_ipsec_vf_offload_set_bytype(esw, vport, enable,
368 MLX5_ESW_VPORT_IPSEC_PACKET_OFFLOAD);
369 }
370