Contributors: 17
| Author |
Tokens |
Token Proportion |
Commits |
Commit Proportion |
| Dima Chumak |
982 |
67.31% |
2 |
5.88% |
| Parav Pandit |
104 |
7.13% |
6 |
17.65% |
| Vlad Buslov |
83 |
5.69% |
1 |
2.94% |
| Jiri Pirko |
69 |
4.73% |
7 |
20.59% |
| Eli Cohen |
37 |
2.54% |
1 |
2.94% |
| Moshe Shemesh |
34 |
2.33% |
3 |
8.82% |
| Roi Dayan |
34 |
2.33% |
2 |
5.88% |
| Maor Gottlieb |
31 |
2.12% |
1 |
2.94% |
| Saeed Mahameed |
26 |
1.78% |
2 |
5.88% |
| Yishai Hadas |
25 |
1.71% |
1 |
2.94% |
| Dmytro Linkin |
7 |
0.48% |
2 |
5.88% |
| Leon Romanovsky |
7 |
0.48% |
1 |
2.94% |
| Or Gerlitz |
6 |
0.41% |
1 |
2.94% |
| Vu Pham |
5 |
0.34% |
1 |
2.94% |
| Mohamad Haj Yahia |
4 |
0.27% |
1 |
2.94% |
| Mark Bloch |
4 |
0.27% |
1 |
2.94% |
| Jianbo Liu |
1 |
0.07% |
1 |
2.94% |
| Total |
1459 |
|
34 |
|
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <linux/mlx5/device.h>
#include <linux/mlx5/vport.h>
#include "mlx5_core.h"
#include "eswitch.h"
static int esw_ipsec_vf_query_generic(struct mlx5_core_dev *dev, u16 vport_num, bool *result)
{
int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
void *hca_cap, *query_cap;
int err;
if (!MLX5_CAP_GEN(dev, vport_group_manager))
return -EOPNOTSUPP;
if (!mlx5_esw_ipsec_vf_offload_supported(dev)) {
*result = false;
return 0;
}
query_cap = kvzalloc(query_sz, GFP_KERNEL);
if (!query_cap)
return -ENOMEM;
err = mlx5_vport_get_other_func_general_cap(dev, vport_num, query_cap);
if (err)
goto free;
hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
*result = MLX5_GET(cmd_hca_cap, hca_cap, ipsec_offload);
free:
kvfree(query_cap);
return err;
}
enum esw_vport_ipsec_offload {
MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD,
MLX5_ESW_VPORT_IPSEC_PACKET_OFFLOAD,
};
int mlx5_esw_ipsec_vf_offload_get(struct mlx5_core_dev *dev, struct mlx5_vport *vport)
{
int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
void *hca_cap, *query_cap;
bool ipsec_enabled;
int err;
/* Querying IPsec caps only makes sense when generic ipsec_offload
* HCA cap is enabled
*/
err = esw_ipsec_vf_query_generic(dev, vport->vport, &ipsec_enabled);
if (err)
return err;
if (!ipsec_enabled) {
vport->info.ipsec_crypto_enabled = false;
vport->info.ipsec_packet_enabled = false;
return 0;
}
query_cap = kvzalloc(query_sz, GFP_KERNEL);
if (!query_cap)
return -ENOMEM;
err = mlx5_vport_get_other_func_cap(dev, vport->vport, query_cap, MLX5_CAP_IPSEC);
if (err)
goto free;
hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
vport->info.ipsec_crypto_enabled =
MLX5_GET(ipsec_cap, hca_cap, ipsec_crypto_offload);
vport->info.ipsec_packet_enabled =
MLX5_GET(ipsec_cap, hca_cap, ipsec_full_offload);
free:
kvfree(query_cap);
return err;
}
static int esw_ipsec_vf_set_generic(struct mlx5_core_dev *dev, u16 vport_num, bool ipsec_ofld)
{
int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
void *query_cap, *hca_caps;
int ret;
if (!MLX5_CAP_GEN(dev, vhca_resource_manager))
return -EOPNOTSUPP;
query_cap = kvzalloc(query_sz, GFP_KERNEL);
if (!query_cap)
return -ENOMEM;
ret = mlx5_vport_get_other_func_general_cap(dev, vport_num, query_cap);
if (ret)
goto free;
hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
MLX5_SET(cmd_hca_cap, hca_caps, ipsec_offload, ipsec_ofld);
ret = mlx5_vport_set_other_func_general_cap(dev, hca_caps, vport_num);
free:
kvfree(query_cap);
return ret;
}
static int esw_ipsec_vf_set_bytype(struct mlx5_core_dev *dev, struct mlx5_vport *vport,
bool enable, enum esw_vport_ipsec_offload type)
{
int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
void *query_cap, *hca_caps;
int ret;
if (!MLX5_CAP_GEN(dev, vhca_resource_manager))
return -EOPNOTSUPP;
query_cap = kvzalloc(query_sz, GFP_KERNEL);
if (!query_cap)
return -ENOMEM;
ret = mlx5_vport_get_other_func_cap(dev, vport->vport, query_cap, MLX5_CAP_IPSEC);
if (ret)
goto free;
hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
switch (type) {
case MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD:
MLX5_SET(ipsec_cap, hca_caps, ipsec_crypto_offload, enable);
break;
case MLX5_ESW_VPORT_IPSEC_PACKET_OFFLOAD:
MLX5_SET(ipsec_cap, hca_caps, ipsec_full_offload, enable);
break;
default:
ret = -EOPNOTSUPP;
goto free;
}
ret = mlx5_vport_set_other_func_cap(dev, hca_caps, vport->vport,
MLX5_SET_HCA_CAP_OP_MOD_IPSEC);
free:
kvfree(query_cap);
return ret;
}
static int esw_ipsec_vf_crypto_aux_caps_set(struct mlx5_core_dev *dev, u16 vport_num, bool enable)
{
int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
void *query_cap, *hca_caps;
int ret;
query_cap = kvzalloc(query_sz, GFP_KERNEL);
if (!query_cap)
return -ENOMEM;
ret = mlx5_vport_get_other_func_cap(dev, vport_num, query_cap, MLX5_CAP_ETHERNET_OFFLOADS);
if (ret)
goto free;
hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
MLX5_SET(per_protocol_networking_offload_caps, hca_caps,
insert_trailer, enable);
ret = mlx5_vport_set_other_func_cap(dev, hca_caps, vport_num,
MLX5_SET_HCA_CAP_OP_MOD_ETHERNET_OFFLOADS);
free:
kvfree(query_cap);
return ret;
}
static int esw_ipsec_vf_offload_set_bytype(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
bool enable, enum esw_vport_ipsec_offload type)
{
struct mlx5_core_dev *dev = esw->dev;
int err;
if (!mlx5_eswitch_is_vf_vport(esw, vport->vport))
return -EOPNOTSUPP;
if (type == MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD) {
err = esw_ipsec_vf_crypto_aux_caps_set(dev, vport->vport, enable);
if (err)
return err;
}
if (enable) {
err = esw_ipsec_vf_set_generic(dev, vport->vport, enable);
if (err)
return err;
err = esw_ipsec_vf_set_bytype(dev, vport, enable, type);
if (err)
return err;
} else {
err = esw_ipsec_vf_set_bytype(dev, vport, enable, type);
if (err)
return err;
err = mlx5_esw_ipsec_vf_offload_get(dev, vport);
if (err)
return err;
/* The generic ipsec_offload cap can be disabled only if both
* ipsec_crypto_offload and ipsec_full_offload aren't enabled.
*/
if (!vport->info.ipsec_crypto_enabled &&
!vport->info.ipsec_packet_enabled) {
err = esw_ipsec_vf_set_generic(dev, vport->vport, enable);
if (err)
return err;
}
}
switch (type) {
case MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD:
vport->info.ipsec_crypto_enabled = enable;
break;
case MLX5_ESW_VPORT_IPSEC_PACKET_OFFLOAD:
vport->info.ipsec_packet_enabled = enable;
break;
default:
return -EINVAL;
}
return 0;
}
static int esw_ipsec_offload_supported(struct mlx5_core_dev *dev, u16 vport_num)
{
int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
void *hca_cap, *query_cap;
int ret;
query_cap = kvzalloc(query_sz, GFP_KERNEL);
if (!query_cap)
return -ENOMEM;
ret = mlx5_vport_get_other_func_cap(dev, vport_num, query_cap, MLX5_CAP_GENERAL);
if (ret)
goto free;
hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
if (!MLX5_GET(cmd_hca_cap, hca_cap, log_max_dek))
ret = -EOPNOTSUPP;
free:
kvfree(query_cap);
return ret;
}
bool mlx5_esw_ipsec_vf_offload_supported(struct mlx5_core_dev *dev)
{
/* Old firmware doesn't support ipsec_offload capability for VFs. This
* can be detected by checking reformat_add_esp_trasport capability -
* when this cap isn't supported it means firmware cannot be trusted
* about what it reports for ipsec_offload cap.
*/
return MLX5_CAP_FLOWTABLE_NIC_TX(dev, reformat_add_esp_trasport);
}
int mlx5_esw_ipsec_vf_crypto_offload_supported(struct mlx5_core_dev *dev,
u16 vport_num)
{
int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
void *hca_cap, *query_cap;
int err;
if (!mlx5_esw_ipsec_vf_offload_supported(dev))
return -EOPNOTSUPP;
err = esw_ipsec_offload_supported(dev, vport_num);
if (err)
return err;
query_cap = kvzalloc(query_sz, GFP_KERNEL);
if (!query_cap)
return -ENOMEM;
err = mlx5_vport_get_other_func_cap(dev, vport_num, query_cap, MLX5_CAP_ETHERNET_OFFLOADS);
if (err)
goto free;
hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
if (!MLX5_GET(per_protocol_networking_offload_caps, hca_cap, swp))
goto free;
free:
kvfree(query_cap);
return err;
}
int mlx5_esw_ipsec_vf_packet_offload_supported(struct mlx5_core_dev *dev,
u16 vport_num)
{
int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
void *hca_cap, *query_cap;
int ret;
if (!mlx5_esw_ipsec_vf_offload_supported(dev))
return -EOPNOTSUPP;
ret = esw_ipsec_offload_supported(dev, vport_num);
if (ret)
return ret;
query_cap = kvzalloc(query_sz, GFP_KERNEL);
if (!query_cap)
return -ENOMEM;
ret = mlx5_vport_get_other_func_cap(dev, vport_num, query_cap, MLX5_CAP_FLOW_TABLE);
if (ret)
goto out;
hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
if (!MLX5_GET(flow_table_nic_cap, hca_cap, flow_table_properties_nic_receive.decap)) {
ret = -EOPNOTSUPP;
goto out;
}
out:
kvfree(query_cap);
return ret;
}
int mlx5_esw_ipsec_vf_crypto_offload_set(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
bool enable)
{
return esw_ipsec_vf_offload_set_bytype(esw, vport, enable,
MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD);
}
int mlx5_esw_ipsec_vf_packet_offload_set(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
bool enable)
{
return esw_ipsec_vf_offload_set_bytype(esw, vport, enable,
MLX5_ESW_VPORT_IPSEC_PACKET_OFFLOAD);
}