aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cmd.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c29
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h11
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c21
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_common.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fw.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c755
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.h34
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h12
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c1
-rw-r--r--include/linux/mlx5/device.h4
-rw-r--r--include/linux/mlx5/driver.h2
-rw-r--r--include/linux/mlx5/mlx5_ifc.h163
17 files changed, 992 insertions, 86 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index 382d02f6619c..b00e33ed05e9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -104,6 +104,7 @@ static bool mlx5_cmd_is_throttle_opcode(u16 op)
case MLX5_CMD_OP_DESTROY_GENERAL_OBJECT:
case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT:
case MLX5_CMD_OP_QUERY_GENERAL_OBJECT:
+ case MLX5_CMD_OP_SYNC_CRYPTO:
return true;
}
return false;
@@ -523,6 +524,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
case MLX5_CMD_OP_QUERY_VHCA_MIGRATION_STATE:
case MLX5_CMD_OP_SAVE_VHCA_STATE:
case MLX5_CMD_OP_LOAD_VHCA_STATE:
+ case MLX5_CMD_OP_SYNC_CRYPTO:
*status = MLX5_DRIVER_STATUS_ABORTED;
*synd = MLX5_DRIVER_SYND;
return -ENOLINK;
@@ -725,6 +727,7 @@ const char *mlx5_command_str(int command)
MLX5_COMMAND_STR_CASE(QUERY_VHCA_MIGRATION_STATE);
MLX5_COMMAND_STR_CASE(SAVE_VHCA_STATE);
MLX5_COMMAND_STR_CASE(LOAD_VHCA_STATE);
+ MLX5_COMMAND_STR_CASE(SYNC_CRYPTO);
default: return "unknown command opcode";
}
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c
index 7758a425bfa8..8218c892b161 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c
@@ -204,13 +204,15 @@ mlx5e_flow_meter_create_aso_obj(struct mlx5e_flow_meters *flow_meters, int *obj_
u32 in[MLX5_ST_SZ_DW(create_flow_meter_aso_obj_in)] = {};
u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
struct mlx5_core_dev *mdev = flow_meters->mdev;
- void *obj;
+ void *obj, *param;
int err;
MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
MLX5_SET(general_obj_in_cmd_hdr, in, obj_type,
MLX5_GENERAL_OBJECT_TYPES_FLOW_METER_ASO);
- MLX5_SET(general_obj_in_cmd_hdr, in, log_obj_range, flow_meters->log_granularity);
+ param = MLX5_ADDR_OF(general_obj_in_cmd_hdr, in, op_param);
+ MLX5_SET(general_obj_create_param, param, log_obj_range,
+ flow_meters->log_granularity);
obj = MLX5_ADDR_OF(create_flow_meter_aso_obj_in, in, flow_meter_aso_obj);
MLX5_SET(flow_meter_aso_obj, obj, meter_aso_access_pd, flow_meters->pdn);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
index 2461462b7b99..57ac0f663fcd 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
@@ -4,7 +4,7 @@
#include "mlx5_core.h"
#include "en.h"
#include "ipsec.h"
-#include "lib/mlx5.h"
+#include "lib/crypto.h"
enum {
MLX5_IPSEC_ASO_REMOVE_FLOW_PKT_CNT_OFFSET,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c
index eb5b09f81dec..cf704f106b7c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c
@@ -4,16 +4,16 @@
#include <linux/debugfs.h>
#include "en.h"
#include "lib/mlx5.h"
+#include "lib/crypto.h"
#include "en_accel/ktls.h"
#include "en_accel/ktls_utils.h"
#include "en_accel/fs_tcp.h"
-int mlx5_ktls_create_key(struct mlx5_core_dev *mdev,
- struct tls_crypto_info *crypto_info,
- u32 *p_key_id)
+struct mlx5_crypto_dek *mlx5_ktls_create_key(struct mlx5_crypto_dek_pool *dek_pool,
+ struct tls_crypto_info *crypto_info)
{
+ const void *key;
u32 sz_bytes;
- void *key;
switch (crypto_info->cipher_type) {
case TLS_CIPHER_AES_GCM_128: {
@@ -33,17 +33,16 @@ int mlx5_ktls_create_key(struct mlx5_core_dev *mdev,
break;
}
default:
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
}
- return mlx5_create_encryption_key(mdev, key, sz_bytes,
- MLX5_ACCEL_OBJ_TLS_KEY,
- p_key_id);
+ return mlx5_crypto_dek_create(dek_pool, key, sz_bytes);
}
-void mlx5_ktls_destroy_key(struct mlx5_core_dev *mdev, u32 key_id)
+void mlx5_ktls_destroy_key(struct mlx5_crypto_dek_pool *dek_pool,
+ struct mlx5_crypto_dek *dek)
{
- mlx5_destroy_encryption_key(mdev, key_id);
+ mlx5_crypto_dek_destroy(dek_pool, dek);
}
static int mlx5e_ktls_add(struct net_device *netdev, struct sock *sk,
@@ -189,6 +188,7 @@ static void mlx5e_tls_debugfs_init(struct mlx5e_tls *tls,
int mlx5e_ktls_init(struct mlx5e_priv *priv)
{
+ struct mlx5_crypto_dek_pool *dek_pool;
struct mlx5e_tls *tls;
if (!mlx5e_is_ktls_device(priv->mdev))
@@ -197,9 +197,15 @@ int mlx5e_ktls_init(struct mlx5e_priv *priv)
tls = kzalloc(sizeof(*tls), GFP_KERNEL);
if (!tls)
return -ENOMEM;
+ tls->mdev = priv->mdev;
+ dek_pool = mlx5_crypto_dek_pool_create(priv->mdev, MLX5_ACCEL_OBJ_TLS_KEY);
+ if (IS_ERR(dek_pool)) {
+ kfree(tls);
+ return PTR_ERR(dek_pool);
+ }
+ tls->dek_pool = dek_pool;
priv->tls = tls;
- priv->tls->mdev = priv->mdev;
mlx5e_tls_debugfs_init(tls, priv->dfs_root);
@@ -216,6 +222,7 @@ void mlx5e_ktls_cleanup(struct mlx5e_priv *priv)
debugfs_remove_recursive(tls->debugfs.dfs);
tls->debugfs.dfs = NULL;
+ mlx5_crypto_dek_pool_destroy(tls->dek_pool);
kfree(priv->tls);
priv->tls = NULL;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h
index fccf995ee16d..f11075e67658 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h
@@ -10,10 +10,12 @@
#include "en.h"
#ifdef CONFIG_MLX5_EN_TLS
-int mlx5_ktls_create_key(struct mlx5_core_dev *mdev,
- struct tls_crypto_info *crypto_info,
- u32 *p_key_id);
-void mlx5_ktls_destroy_key(struct mlx5_core_dev *mdev, u32 key_id);
+#include "lib/crypto.h"
+
+struct mlx5_crypto_dek *mlx5_ktls_create_key(struct mlx5_crypto_dek_pool *dek_pool,
+ struct tls_crypto_info *crypto_info);
+void mlx5_ktls_destroy_key(struct mlx5_crypto_dek_pool *dek_pool,
+ struct mlx5_crypto_dek *dek);
static inline bool mlx5e_is_ktls_device(struct mlx5_core_dev *mdev)
{
@@ -83,6 +85,7 @@ struct mlx5e_tls {
struct mlx5e_tls_sw_stats sw_stats;
struct workqueue_struct *rx_wq;
struct mlx5e_tls_tx_pool *tx_pool;
+ struct mlx5_crypto_dek_pool *dek_pool;
struct mlx5e_tls_debugfs debugfs;
};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c
index 3e54834747ce..4be770443b0c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c
@@ -50,7 +50,7 @@ struct mlx5e_ktls_offload_context_rx {
struct mlx5e_tls_sw_stats *sw_stats;
struct completion add_ctx;
struct mlx5e_tir tir;
- u32 key_id;
+ struct mlx5_crypto_dek *dek;
u32 rxq;
DECLARE_BITMAP(flags, MLX5E_NUM_PRIV_RX_FLAGS);
@@ -148,7 +148,8 @@ post_static_params(struct mlx5e_icosq *sq,
wqe = MLX5E_TLS_FETCH_SET_STATIC_PARAMS_WQE(sq, pi);
mlx5e_ktls_build_static_params(wqe, sq->pc, sq->sqn, &priv_rx->crypto_info,
mlx5e_tir_get_tirn(&priv_rx->tir),
- priv_rx->key_id, priv_rx->resync.seq, false,
+ mlx5_crypto_dek_get_id(priv_rx->dek),
+ priv_rx->resync.seq, false,
TLS_OFFLOAD_CTX_DIR_RX);
wi = (struct mlx5e_icosq_wqe_info) {
.wqe_type = MLX5E_ICOSQ_WQE_UMR_TLS,
@@ -610,20 +611,22 @@ int mlx5e_ktls_add_rx(struct net_device *netdev, struct sock *sk,
struct mlx5e_ktls_offload_context_rx *priv_rx;
struct mlx5e_ktls_rx_resync_ctx *resync;
struct tls_context *tls_ctx;
- struct mlx5_core_dev *mdev;
+ struct mlx5_crypto_dek *dek;
struct mlx5e_priv *priv;
int rxq, err;
tls_ctx = tls_get_ctx(sk);
priv = netdev_priv(netdev);
- mdev = priv->mdev;
priv_rx = kzalloc(sizeof(*priv_rx), GFP_KERNEL);
if (unlikely(!priv_rx))
return -ENOMEM;
- err = mlx5_ktls_create_key(mdev, crypto_info, &priv_rx->key_id);
- if (err)
+ dek = mlx5_ktls_create_key(priv->tls->dek_pool, crypto_info);
+ if (IS_ERR(dek)) {
+ err = PTR_ERR(dek);
goto err_create_key;
+ }
+ priv_rx->dek = dek;
INIT_LIST_HEAD(&priv_rx->list);
spin_lock_init(&priv_rx->lock);
@@ -673,7 +676,7 @@ int mlx5e_ktls_add_rx(struct net_device *netdev, struct sock *sk,
err_post_wqes:
mlx5e_tir_destroy(&priv_rx->tir);
err_create_tir:
- mlx5_ktls_destroy_key(mdev, priv_rx->key_id);
+ mlx5_ktls_destroy_key(priv->tls->dek_pool, priv_rx->dek);
err_create_key:
kfree(priv_rx);
return err;
@@ -683,11 +686,9 @@ void mlx5e_ktls_del_rx(struct net_device *netdev, struct tls_context *tls_ctx)
{
struct mlx5e_ktls_offload_context_rx *priv_rx;
struct mlx5e_ktls_rx_resync_ctx *resync;
- struct mlx5_core_dev *mdev;
struct mlx5e_priv *priv;
priv = netdev_priv(netdev);
- mdev = priv->mdev;
priv_rx = mlx5e_get_ktls_rx_priv_ctx(tls_ctx);
set_bit(MLX5E_PRIV_RX_FLAG_DELETING, priv_rx->flags);
@@ -707,7 +708,7 @@ void mlx5e_ktls_del_rx(struct net_device *netdev, struct tls_context *tls_ctx)
mlx5e_accel_fs_del_sk(priv_rx->rule.rule);
mlx5e_tir_destroy(&priv_rx->tir);
- mlx5_ktls_destroy_key(mdev, priv_rx->key_id);
+ mlx5_ktls_destroy_key(priv->tls->dek_pool, priv_rx->dek);
/* priv_rx should normally be freed here, but if there is an outstanding
* GET_PSV, deallocation will be delayed until the CQE for GET_PSV is
* processed.
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
index 6db27062b765..e80b43b7aac9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
@@ -98,7 +98,7 @@ struct mlx5e_ktls_offload_context_tx {
struct tls_offload_context_tx *tx_ctx;
struct mlx5_core_dev *mdev;
struct mlx5e_tls_sw_stats *sw_stats;
- u32 key_id;
+ struct mlx5_crypto_dek *dek;
u8 create_err : 1;
};
@@ -457,6 +457,7 @@ int mlx5e_ktls_add_tx(struct net_device *netdev, struct sock *sk,
struct mlx5e_ktls_offload_context_tx *priv_tx;
struct mlx5e_tls_tx_pool *pool;
struct tls_context *tls_ctx;
+ struct mlx5_crypto_dek *dek;
struct mlx5e_priv *priv;
int err;
@@ -468,9 +469,12 @@ int mlx5e_ktls_add_tx(struct net_device *netdev, struct sock *sk,
if (IS_ERR(priv_tx))
return PTR_ERR(priv_tx);
- err = mlx5_ktls_create_key(pool->mdev, crypto_info, &priv_tx->key_id);
- if (err)
+ dek = mlx5_ktls_create_key(priv->tls->dek_pool, crypto_info);
+ if (IS_ERR(dek)) {
+ err = PTR_ERR(dek);
goto err_create_key;
+ }
+ priv_tx->dek = dek;
priv_tx->expected_seq = start_offload_tcp_sn;
switch (crypto_info->cipher_type) {
@@ -512,7 +516,7 @@ void mlx5e_ktls_del_tx(struct net_device *netdev, struct tls_context *tls_ctx)
pool = priv->tls->tx_pool;
atomic64_inc(&priv_tx->sw_stats->tx_tls_del);
- mlx5_ktls_destroy_key(priv_tx->mdev, priv_tx->key_id);
+ mlx5_ktls_destroy_key(priv->tls->dek_pool, priv_tx->dek);
pool_push(pool, priv_tx);
}
@@ -551,8 +555,9 @@ post_static_params(struct mlx5e_txqsq *sq,
pi = mlx5e_txqsq_get_next_pi(sq, num_wqebbs);
wqe = MLX5E_TLS_FETCH_SET_STATIC_PARAMS_WQE(sq, pi);
mlx5e_ktls_build_static_params(wqe, sq->pc, sq->sqn, &priv_tx->crypto_info,
- priv_tx->tisn, priv_tx->key_id, 0, fence,
- TLS_OFFLOAD_CTX_DIR_TX);
+ priv_tx->tisn,
+ mlx5_crypto_dek_get_id(priv_tx->dek),
+ 0, fence, TLS_OFFLOAD_CTX_DIR_TX);
tx_fill_wi(sq, pi, num_wqebbs, 0, NULL);
sq->pc += num_wqebbs;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
index 7f6b940830b3..08d0929e8260 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
@@ -7,7 +7,7 @@
#include "en.h"
#include "lib/aso.h"
-#include "lib/mlx5.h"
+#include "lib/crypto.h"
#include "en_accel/macsec.h"
#include "en_accel/macsec_fs.h"
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
index 68f19324db93..4c9a3210600c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
@@ -31,6 +31,7 @@
*/
#include "en.h"
+#include "lib/crypto.h"
/* mlx5e global resources should be placed in this file.
* Global resources are common to all the netdevices created on the same nic.
@@ -104,6 +105,13 @@ int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev)
INIT_LIST_HEAD(&res->td.tirs_list);
mutex_init(&res->td.list_lock);
+ mdev->mlx5e_res.dek_priv = mlx5_crypto_dek_init(mdev);
+ if (IS_ERR(mdev->mlx5e_res.dek_priv)) {
+ mlx5_core_err(mdev, "crypto dek init failed, %ld\n",
+ PTR_ERR(mdev->mlx5e_res.dek_priv));
+ mdev->mlx5e_res.dek_priv = NULL;
+ }
+
return 0;
err_destroy_mkey:
@@ -119,6 +127,8 @@ void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev)
{
struct mlx5e_hw_objs *res = &mdev->mlx5e_res.hw_objs;
+ mlx5_crypto_dek_cleanup(mdev->mlx5e_res.dek_priv);
+ mdev->mlx5e_res.dek_priv = NULL;
mlx5_free_bfreg(mdev, &res->bfreg);
mlx5_core_destroy_mkey(mdev, res->mkey);
mlx5_core_dealloc_transport_domain(mdev, res->td.tdn);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
index f34e758a2f1f..7bb7be01225a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
@@ -267,6 +267,12 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
return err;
}
+ if (MLX5_CAP_GEN(dev, crypto)) {
+ err = mlx5_core_get_caps(dev, MLX5_CAP_CRYPTO);
+ if (err)
+ return err;
+ }
+
if (MLX5_CAP_GEN(dev, shampo)) {
err = mlx5_core_get_caps(dev, MLX5_CAP_DEV_SHAMPO);
if (err)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c
index e995f8378df7..3a94b8f8031e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c
@@ -2,53 +2,253 @@
// Copyright (c) 2019 Mellanox Technologies.
#include "mlx5_core.h"
-#include "lib/mlx5.h"
+#include "lib/crypto.h"
-int mlx5_create_encryption_key(struct mlx5_core_dev *mdev,
- void *key, u32 sz_bytes,
- u32 key_type, u32 *p_key_id)
-{
- u32 in[MLX5_ST_SZ_DW(create_encryption_key_in)] = {};
- u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
- u32 sz_bits = sz_bytes * BITS_PER_BYTE;
- u8 general_obj_key_size;
- u64 general_obj_types;
- void *obj, *key_p;
- int err;
+#define MLX5_CRYPTO_DEK_POOLS_NUM (MLX5_ACCEL_OBJ_TYPE_KEY_NUM - 1)
+#define type2idx(type) ((type) - 1)
- obj = MLX5_ADDR_OF(create_encryption_key_in, in, encryption_key_object);
- key_p = MLX5_ADDR_OF(encryption_key_obj, obj, key);
+#define MLX5_CRYPTO_DEK_POOL_SYNC_THRESH 128
- general_obj_types = MLX5_CAP_GEN_64(mdev, general_obj_types);
- if (!(general_obj_types &
- MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY))
- return -EINVAL;
+/* calculate the num of DEKs, which are freed by any user
+ * (for example, TLS) after last revalidation in a pool or a bulk.
+ */
+#define MLX5_CRYPTO_DEK_CALC_FREED(a) \
+ ({ typeof(a) _a = (a); \
+ _a->num_deks - _a->avail_deks - _a->in_use_deks; })
+
+#define MLX5_CRYPTO_DEK_POOL_CALC_FREED(pool) MLX5_CRYPTO_DEK_CALC_FREED(pool)
+#define MLX5_CRYPTO_DEK_BULK_CALC_FREED(bulk) MLX5_CRYPTO_DEK_CALC_FREED(bulk)
+
+#define MLX5_CRYPTO_DEK_BULK_IDLE(bulk) \
+ ({ typeof(bulk) _bulk = (bulk); \
+ _bulk->avail_deks == _bulk->num_deks; })
+
+enum {
+ MLX5_CRYPTO_DEK_ALL_TYPE = BIT(0),
+};
+
+struct mlx5_crypto_dek_pool {
+ struct mlx5_core_dev *mdev;
+ u32 key_purpose;
+ int num_deks; /* the total number of keys in this pool */
+ int avail_deks; /* the number of available keys in this pool */
+ int in_use_deks; /* the number of being used keys in this pool */
+ struct mutex lock; /* protect the following lists, and the bulks */
+ struct list_head partial_list; /* some of keys are available */
+ struct list_head full_list; /* no available keys */
+ struct list_head avail_list; /* all keys are available to use */
+
+ /* No in-used keys, and all need to be synced.
+ * These bulks will be put to avail list after sync.
+ */
+ struct list_head sync_list;
+
+ bool syncing;
+ struct list_head wait_for_free;
+ struct work_struct sync_work;
+
+ spinlock_t destroy_lock; /* protect destroy_list */
+ struct list_head destroy_list;
+ struct work_struct destroy_work;
+};
+
+struct mlx5_crypto_dek_bulk {
+ struct mlx5_core_dev *mdev;
+ int base_obj_id;
+ int avail_start; /* the bit to start search */
+ int num_deks; /* the total number of keys in a bulk */
+ int avail_deks; /* the number of keys available, with need_sync bit 0 */
+ int in_use_deks; /* the number of keys being used, with in_use bit 1 */
+ struct list_head entry;
+
+ /* 0: not being used by any user, 1: otherwise */
+ unsigned long *in_use;
+
+ /* The bits are set when they are used, and reset after crypto_sync
+ * is executed. So, the value 0 means the key is newly created, or not
+ * used after sync, and 1 means it is in use, or freed but not synced
+ */
+ unsigned long *need_sync;
+};
+
+struct mlx5_crypto_dek_priv {
+ struct mlx5_core_dev *mdev;
+ int log_dek_obj_range;
+};
+
+struct mlx5_crypto_dek {
+ struct mlx5_crypto_dek_bulk *bulk;
+ struct list_head entry;
+ u32 obj_id;
+};
+
+u32 mlx5_crypto_dek_get_id(struct mlx5_crypto_dek *dek)
+{
+ return dek->obj_id;
+}
+
+static int mlx5_crypto_dek_get_key_sz(struct mlx5_core_dev *mdev,
+ u32 sz_bytes, u8 *key_sz_p)
+{
+ u32 sz_bits = sz_bytes * BITS_PER_BYTE;
switch (sz_bits) {
case 128:
- general_obj_key_size =
- MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_128;
- key_p += sz_bytes;
+ *key_sz_p = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_128;
break;
case 256:
- general_obj_key_size =
- MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_256;
+ *key_sz_p = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_256;
break;
default:
+ mlx5_core_err(mdev, "Crypto offload error, invalid key size (%u bits)\n",
+ sz_bits);
return -EINVAL;
}
- memcpy(key_p, key, sz_bytes);
+ return 0;
+}
+
+static int mlx5_crypto_dek_fill_key(struct mlx5_core_dev *mdev, u8 *key_obj,
+ const void *key, u32 sz_bytes)
+{
+ void *dst;
+ u8 key_sz;
+ int err;
+
+ err = mlx5_crypto_dek_get_key_sz(mdev, sz_bytes, &key_sz);
+ if (err)
+ return err;
+
+ MLX5_SET(encryption_key_obj, key_obj, key_size, key_sz);
+
+ if (sz_bytes == 16)
+ /* For key size of 128b the MSBs are reserved. */
+ dst = MLX5_ADDR_OF(encryption_key_obj, key_obj, key[1]);
+ else
+ dst = MLX5_ADDR_OF(encryption_key_obj, key_obj, key);
+
+ memcpy(dst, key, sz_bytes);
+
+ return 0;
+}
+
+static int mlx5_crypto_cmd_sync_crypto(struct mlx5_core_dev *mdev,
+ int crypto_type)
+{
+ u32 in[MLX5_ST_SZ_DW(sync_crypto_in)] = {};
+ int err;
+
+ mlx5_core_dbg(mdev,
+ "Execute SYNC_CRYPTO command with crypto_type(0x%x)\n",
+ crypto_type);
+
+ MLX5_SET(sync_crypto_in, in, opcode, MLX5_CMD_OP_SYNC_CRYPTO);
+ MLX5_SET(sync_crypto_in, in, crypto_type, crypto_type);
+
+ err = mlx5_cmd_exec_in(mdev, sync_crypto, in);
+ if (err)
+ mlx5_core_err(mdev,
+ "Failed to exec sync crypto, type=%d, err=%d\n",
+ crypto_type, err);
+
+ return err;
+}
+
+static int mlx5_crypto_create_dek_bulk(struct mlx5_core_dev *mdev,
+ u32 key_purpose, int log_obj_range,
+ u32 *obj_id)
+{
+ u32 in[MLX5_ST_SZ_DW(create_encryption_key_in)] = {};
+ u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
+ void *obj, *param;
+ int err;
- MLX5_SET(encryption_key_obj, obj, key_size, general_obj_key_size);
- MLX5_SET(encryption_key_obj, obj, key_type, key_type);
MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
MLX5_SET(general_obj_in_cmd_hdr, in, obj_type,
MLX5_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY);
+ param = MLX5_ADDR_OF(general_obj_in_cmd_hdr, in, op_param);
+ MLX5_SET(general_obj_create_param, param, log_obj_range, log_obj_range);
+
+ obj = MLX5_ADDR_OF(create_encryption_key_in, in, encryption_key_object);
+ MLX5_SET(encryption_key_obj, obj, key_purpose, key_purpose);
MLX5_SET(encryption_key_obj, obj, pd, mdev->mlx5e_res.hw_objs.pdn);
err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
+ if (err)
+ return err;
+
+ *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
+ mlx5_core_dbg(mdev, "DEK objects created, bulk=%d, obj_id=%d\n",
+ 1 << log_obj_range, *obj_id);
+
+ return 0;
+}
+
+static int mlx5_crypto_modify_dek_key(struct mlx5_core_dev *mdev,
+ const void *key, u32 sz_bytes, u32 key_purpose,
+ u32 obj_id, u32 obj_offset)
+{
+ u32 in[MLX5_ST_SZ_DW(modify_encryption_key_in)] = {};
+ u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
+ void *obj, *param;
+ int err;
+
+ MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
+ MLX5_CMD_OP_MODIFY_GENERAL_OBJECT);
+ MLX5_SET(general_obj_in_cmd_hdr, in, obj_type,
+ MLX5_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY);
+ MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id);
+
+ param = MLX5_ADDR_OF(general_obj_in_cmd_hdr, in, op_param);
+ MLX5_SET(general_obj_query_param, param, obj_offset, obj_offset);
+
+ obj = MLX5_ADDR_OF(modify_encryption_key_in, in, encryption_key_object);
+ MLX5_SET64(encryption_key_obj, obj, modify_field_select, 1);
+ MLX5_SET(encryption_key_obj, obj, key_purpose, key_purpose);
+ MLX5_SET(encryption_key_obj, obj, pd, mdev->mlx5e_res.hw_objs.pdn);
+
+ err = mlx5_crypto_dek_fill_key(mdev, obj, key, sz_bytes);
+ if (err)
+ return err;
+
+ err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
+
+ /* avoid leaking key on the stack */
+ memzero_explicit(in, sizeof(in));
+
+ return err;
+}
+
+static int mlx5_crypto_create_dek_key(struct mlx5_core_dev *mdev,
+ const void *key, u32 sz_bytes,
+ u32 key_purpose, u32 *p_key_id)
+{
+ u32 in[MLX5_ST_SZ_DW(create_encryption_key_in)] = {};
+ u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
+ u64 general_obj_types;
+ void *obj;
+ int err;
+
+ general_obj_types = MLX5_CAP_GEN_64(mdev, general_obj_types);
+ if (!(general_obj_types &
+ MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY))
+ return -EINVAL;
+
+ MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
+ MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
+ MLX5_SET(general_obj_in_cmd_hdr, in, obj_type,
+ MLX5_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY);
+
+ obj = MLX5_ADDR_OF(create_encryption_key_in, in, encryption_key_object);
+ MLX5_SET(encryption_key_obj, obj, key_purpose, key_purpose);
+ MLX5_SET(encryption_key_obj, obj, pd, mdev->mlx5e_res.hw_objs.pdn);
+
+ err = mlx5_crypto_dek_fill_key(mdev, obj, key, sz_bytes);
+ if (err)
+ return err;
+
+ err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
if (!err)
*p_key_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
@@ -58,7 +258,7 @@ int mlx5_create_encryption_key(struct mlx5_core_dev *mdev,
return err;
}
-void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id)
+static void mlx5_crypto_destroy_dek_key(struct mlx5_core_dev *mdev, u32 key_id)
{
u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
@@ -71,3 +271,504 @@ void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id)
mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
}
+
+int mlx5_create_encryption_key(struct mlx5_core_dev *mdev,
+ const void *key, u32 sz_bytes,
+ u32 key_type, u32 *p_key_id)
+{
+ return mlx5_crypto_create_dek_key(mdev, key, sz_bytes, key_type, p_key_id);
+}
+
+void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id)
+{
+ mlx5_crypto_destroy_dek_key(mdev, key_id);
+}
+
+static struct mlx5_crypto_dek_bulk *
+mlx5_crypto_dek_bulk_create(struct mlx5_crypto_dek_pool *pool)
+{
+ struct mlx5_crypto_dek_priv *dek_priv = pool->mdev->mlx5e_res.dek_priv;
+ struct mlx5_core_dev *mdev = pool->mdev;
+ struct mlx5_crypto_dek_bulk *bulk;
+ int num_deks, base_obj_id;
+ int err;
+
+ bulk = kzalloc(sizeof(*bulk), GFP_KERNEL);
+ if (!bulk)
+ return ERR_PTR(-ENOMEM);
+
+ num_deks = 1 << dek_priv->log_dek_obj_range;
+ bulk->need_sync = bitmap_zalloc(num_deks, GFP_KERNEL);
+ if (!bulk->need_sync) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ bulk->in_use = bitmap_zalloc(num_deks, GFP_KERNEL);
+ if (!bulk->in_use) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ err = mlx5_crypto_create_dek_bulk(mdev, pool->key_purpose,
+ dek_priv->log_dek_obj_range,
+ &base_obj_id);
+ if (err)
+ goto err_out;
+
+ bulk->base_obj_id = base_obj_id;
+ bulk->num_deks = num_deks;
+ bulk->avail_deks = num_deks;
+ bulk->mdev = mdev;
+
+ return bulk;
+
+err_out:
+ bitmap_free(bulk->in_use);
+ bitmap_free(bulk->need_sync);
+ kfree(bulk);
+ return ERR_PTR(err);
+}
+
+static struct mlx5_crypto_dek_bulk *
+mlx5_crypto_dek_pool_add_bulk(struct mlx5_crypto_dek_pool *pool)
+{
+ struct mlx5_crypto_dek_bulk *bulk;
+
+ bulk = mlx5_crypto_dek_bulk_create(pool);
+ if (IS_ERR(bulk))
+ return bulk;
+
+ pool->avail_deks += bulk->num_deks;
+ pool->num_deks += bulk->num_deks;
+ list_add(&bulk->entry, &pool->partial_list);
+
+ return bulk;
+}
+
+static void mlx5_crypto_dek_bulk_free(struct mlx5_crypto_dek_bulk *bulk)
+{
+ mlx5_crypto_destroy_dek_key(bulk->mdev, bulk->base_obj_id);
+ bitmap_free(bulk->need_sync);
+ bitmap_free(bulk->in_use);
+ kfree(bulk);
+}
+
+static void mlx5_crypto_dek_pool_remove_bulk(struct mlx5_crypto_dek_pool *pool,
+ struct mlx5_crypto_dek_bulk *bulk,
+ bool delay)
+{
+ pool->num_deks -= bulk->num_deks;
+ pool->avail_deks -= bulk->avail_deks;
+ pool->in_use_deks -= bulk->in_use_deks;
+ list_del(&bulk->entry);
+ if (!delay)
+ mlx5_crypto_dek_bulk_free(bulk);
+}
+
+static struct mlx5_crypto_dek_bulk *
+mlx5_crypto_dek_pool_pop(struct mlx5_crypto_dek_pool *pool, u32 *obj_offset)
+{
+ struct mlx5_crypto_dek_bulk *bulk;
+ int pos;
+
+ mutex_lock(&pool->lock);
+ bulk = list_first_entry_or_null(&pool->partial_list,
+ struct mlx5_crypto_dek_bulk, entry);
+
+ if (bulk) {
+ pos = find_next_zero_bit(bulk->need_sync, bulk->num_deks,
+ bulk->avail_start);
+ if (pos == bulk->num_deks) {
+ mlx5_core_err(pool->mdev, "Wrong DEK bulk avail_start.\n");
+ pos = find_first_zero_bit(bulk->need_sync, bulk->num_deks);
+ }
+ WARN_ON(pos == bulk->num_deks);
+ } else {
+ bulk = list_first_entry_or_null(&pool->avail_list,
+ struct mlx5_crypto_dek_bulk,
+ entry);
+ if (bulk) {
+ list_move(&bulk->entry, &pool->partial_list);
+ } else {
+ bulk = mlx5_crypto_dek_pool_add_bulk(pool);
+ if (IS_ERR(bulk))
+ goto out;
+ }
+ pos = 0;
+ }
+
+ *obj_offset = pos;
+ bitmap_set(bulk->need_sync, pos, 1);
+ bitmap_set(bulk->in_use, pos, 1);
+ bulk->in_use_deks++;
+ bulk->avail_deks--;
+ if (!bulk->avail_deks) {
+ list_move(&bulk->entry, &pool->full_list);
+ bulk->avail_start = bulk->num_deks;
+ } else {
+ bulk->avail_start = pos + 1;
+ }
+ pool->avail_deks--;
+ pool->in_use_deks++;
+
+out:
+ mutex_unlock(&pool->lock);
+ return bulk;
+}
+
+static bool mlx5_crypto_dek_need_sync(struct mlx5_crypto_dek_pool *pool)
+{
+ return !pool->syncing &&
+ MLX5_CRYPTO_DEK_POOL_CALC_FREED(pool) > MLX5_CRYPTO_DEK_POOL_SYNC_THRESH;
+}
+
+static int mlx5_crypto_dek_free_locked(struct mlx5_crypto_dek_pool *pool,
+ struct mlx5_crypto_dek *dek)
+{
+ struct mlx5_crypto_dek_bulk *bulk = dek->bulk;
+ int obj_offset;
+ bool old_val;
+ int err = 0;
+
+ obj_offset = dek->obj_id - bulk->base_obj_id;
+ old_val = test_and_clear_bit(obj_offset, bulk->in_use);
+ WARN_ON_ONCE(!old_val);
+ if (!old_val) {
+ err = -ENOENT;
+ goto out_free;
+ }
+ pool->in_use_deks--;
+ bulk->in_use_deks--;
+ if (!bulk->avail_deks && !bulk->in_use_deks)
+ list_move(&bulk->entry, &pool->sync_list);
+
+ if (mlx5_crypto_dek_need_sync(pool) && schedule_work(&pool->sync_work))
+ pool->syncing = true;
+
+out_free:
+ kfree(dek);
+ return err;
+}
+
+static int mlx5_crypto_dek_pool_push(struct mlx5_crypto_dek_pool *pool,
+ struct mlx5_crypto_dek *dek)
+{
+ int err = 0;
+
+ mutex_lock(&pool->lock);
+ if (pool->syncing)
+ list_add(&dek->entry, &pool->wait_for_free);
+ else
+ err = mlx5_crypto_dek_free_locked(pool, dek);
+ mutex_unlock(&pool->lock);
+
+ return err;
+}
+
+/* Update the bits for a bulk while sync, and avail_next for search.
+ * As the combinations of (need_sync, in_use) of one DEK are
+ * - (0,0) means the key is ready for use,
+ * - (1,1) means the key is currently being used by a user,
+ * - (1,0) means the key is freed, and waiting for being synced,
+ * - (0,1) is invalid state.
+ * the number of revalidated DEKs can be calculated by
+ * hweight_long(need_sync XOR in_use), and the need_sync bits can be reset
+ * by simply copying from in_use bits.
+ */
+static void mlx5_crypto_dek_bulk_reset_synced(struct mlx5_crypto_dek_pool *pool,
+ struct mlx5_crypto_dek_bulk *bulk)
+{
+ unsigned long *need_sync = bulk->need_sync;
+ unsigned long *in_use = bulk->in_use;
+ int i, freed, reused, avail_next;
+ bool first = true;
+
+ freed = MLX5_CRYPTO_DEK_BULK_CALC_FREED(bulk);
+
+ for (i = 0; freed && i < BITS_TO_LONGS(bulk->num_deks);
+ i++, need_sync++, in_use++) {
+ reused = hweight_long((*need_sync) ^ (*in_use));
+ if (!reused)
+ continue;
+
+ bulk->avail_deks += reused;
+ pool->avail_deks += reused;
+ *need_sync = *in_use;
+ if (first) {
+ avail_next = i * BITS_PER_TYPE(long);
+ if (bulk->avail_start > avail_next)
+ bulk->avail_start = avail_next;
+ first = false;
+ }
+
+ freed -= reused;
+ }
+}
+
+/* Return true if the bulk is reused, false if destroyed with delay */
+static bool mlx5_crypto_dek_bulk_handle_avail(struct mlx5_crypto_dek_pool *pool,
+ struct mlx5_crypto_dek_bulk *bulk,
+ struct list_head *destroy_list)
+{
+ if (list_empty(&pool->avail_list)) {
+ list_move(&bulk->entry, &pool->avail_list);
+ return true;
+ }
+
+ mlx5_crypto_dek_pool_remove_bulk(pool, bulk, true);
+ list_add(&bulk->entry, destroy_list);
+ return false;
+}
+
+static void mlx5_crypto_dek_pool_splice_destroy_list(struct mlx5_crypto_dek_pool *pool,
+ struct list_head *list,
+ struct list_head *head)
+{
+ spin_lock(&pool->destroy_lock);
+ list_splice_init(list, head);
+ spin_unlock(&pool->destroy_lock);
+}
+
+static void mlx5_crypto_dek_pool_free_wait_keys(struct mlx5_crypto_dek_pool *pool)
+{
+ struct mlx5_crypto_dek *dek, *next;
+
+ list_for_each_entry_safe(dek, next, &pool->wait_for_free, entry) {
+ list_del(&dek->entry);
+ mlx5_crypto_dek_free_locked(pool, dek);
+ }
+}
+
+/* For all the bulks in each list, reset the bits while sync.
+ * Move them to different lists according to the number of available DEKs.
+ * Destrory all the idle bulks, except one for quick service.
+ * And free DEKs in the waiting list at the end of this func.
+ */
+static void mlx5_crypto_dek_pool_reset_synced(struct mlx5_crypto_dek_pool *pool)
+{
+ struct mlx5_crypto_dek_bulk *bulk, *tmp;
+ LIST_HEAD(destroy_list);
+
+ list_for_each_entry_safe(bulk, tmp, &pool->partial_list, entry) {
+ mlx5_crypto_dek_bulk_reset_synced(pool, bulk);
+ if (MLX5_CRYPTO_DEK_BULK_IDLE(bulk))
+ mlx5_crypto_dek_bulk_handle_avail(pool, bulk, &destroy_list);
+ }
+
+ list_for_each_entry_safe(bulk, tmp, &pool->full_list, entry) {
+ mlx5_crypto_dek_bulk_reset_synced(pool, bulk);
+
+ if (!bulk->avail_deks)
+ continue;
+
+ if (MLX5_CRYPTO_DEK_BULK_IDLE(bulk))
+ mlx5_crypto_dek_bulk_handle_avail(pool, bulk, &destroy_list);
+ else
+ list_move(&bulk->entry, &pool->partial_list);
+ }
+
+ list_for_each_entry_safe(bulk, tmp, &pool->sync_list, entry) {
+ bulk->avail_deks = bulk->num_deks;
+ pool->avail_deks += bulk->num_deks;
+ if (mlx5_crypto_dek_bulk_handle_avail(pool, bulk, &destroy_list)) {
+ memset(bulk->need_sync, 0, BITS_TO_BYTES(bulk->num_deks));
+ bulk->avail_start = 0;
+ }
+ }
+
+ mlx5_crypto_dek_pool_free_wait_keys(pool);
+
+ if (!list_empty(&destroy_list)) {
+ mlx5_crypto_dek_pool_splice_destroy_list(pool, &destroy_list,
+ &pool->destroy_list);
+ schedule_work(&pool->destroy_work);
+ }
+}
+
+static void mlx5_crypto_dek_sync_work_fn(struct work_struct *work)
+{
+ struct mlx5_crypto_dek_pool *pool =
+ container_of(work, struct mlx5_crypto_dek_pool, sync_work);
+ int err;
+
+ err = mlx5_crypto_cmd_sync_crypto(pool->mdev, BIT(pool->key_purpose));
+ mutex_lock(&pool->lock);
+ if (!err)
+ mlx5_crypto_dek_pool_reset_synced(pool);
+ pool->syncing = false;
+ mutex_unlock(&pool->lock);
+}
+
+struct mlx5_crypto_dek *mlx5_crypto_dek_create(struct mlx5_crypto_dek_pool *dek_pool,
+ const void *key, u32 sz_bytes)
+{
+ struct mlx5_crypto_dek_priv *dek_priv = dek_pool->mdev->mlx5e_res.dek_priv;
+ struct mlx5_core_dev *mdev = dek_pool->mdev;
+ u32 key_purpose = dek_pool->key_purpose;
+ struct mlx5_crypto_dek_bulk *bulk;
+ struct mlx5_crypto_dek *dek;
+ int obj_offset;
+ int err;
+
+ dek = kzalloc(sizeof(*dek), GFP_KERNEL);
+ if (!dek)
+ return ERR_PTR(-ENOMEM);
+
+ if (!dek_priv) {
+ err = mlx5_crypto_create_dek_key(mdev, key, sz_bytes,
+ key_purpose, &dek->obj_id);
+ goto out;
+ }
+
+ bulk = mlx5_crypto_dek_pool_pop(dek_pool, &obj_offset);
+ if (IS_ERR(bulk)) {
+ err = PTR_ERR(bulk);
+ goto out;
+ }
+
+ dek->bulk = bulk;
+ dek->obj_id = bulk->base_obj_id + obj_offset;
+ err = mlx5_crypto_modify_dek_key(mdev, key, sz_bytes, key_purpose,
+ bulk->base_obj_id, obj_offset);
+ if (err) {
+ mlx5_crypto_dek_pool_push(dek_pool, dek);
+ return ERR_PTR(err);
+ }
+
+out:
+ if (err) {
+ kfree(dek);
+ return ERR_PTR(err);
+ }
+
+ return dek;
+}
+
+void mlx5_crypto_dek_destroy(struct mlx5_crypto_dek_pool *dek_pool,
+ struct mlx5_crypto_dek *dek)
+{
+ struct mlx5_crypto_dek_priv *dek_priv = dek_pool->mdev->mlx5e_res.dek_priv;
+ struct mlx5_core_dev *mdev = dek_pool->mdev;
+
+ if (!dek_priv) {
+ mlx5_crypto_destroy_dek_key(mdev, dek->obj_id);
+ kfree(dek);
+ } else {
+ mlx5_crypto_dek_pool_push(dek_pool, dek);
+ }
+}
+
+static void mlx5_crypto_dek_free_destroy_list(struct list_head *destroy_list)
+{
+ struct mlx5_crypto_dek_bulk *bulk, *tmp;
+
+ list_for_each_entry_safe(bulk, tmp, destroy_list, entry)
+ mlx5_crypto_dek_bulk_free(bulk);
+}
+
+static void mlx5_crypto_dek_destroy_work_fn(struct work_struct *work)
+{
+ struct mlx5_crypto_dek_pool *pool =
+ container_of(work, struct mlx5_crypto_dek_pool, destroy_work);
+ LIST_HEAD(destroy_list);
+
+ mlx5_crypto_dek_pool_splice_destroy_list(pool, &pool->destroy_list,
+ &destroy_list);
+ mlx5_crypto_dek_free_destroy_list(&destroy_list);
+}
+
+struct mlx5_crypto_dek_pool *
+mlx5_crypto_dek_pool_create(struct mlx5_core_dev *mdev, int key_purpose)
+{
+ struct mlx5_crypto_dek_pool *pool;
+
+ pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+ if (!pool)
+ return ERR_PTR(-ENOMEM);
+
+ pool->mdev = mdev;
+ pool->key_purpose = key_purpose;
+
+ mutex_init(&pool->lock);
+ INIT_LIST_HEAD(&pool->avail_list);
+ INIT_LIST_HEAD(&pool->partial_list);
+ INIT_LIST_HEAD(&pool->full_list);
+ INIT_LIST_HEAD(&pool->sync_list);
+ INIT_LIST_HEAD(&pool->wait_for_free);
+ INIT_WORK(&pool->sync_work, mlx5_crypto_dek_sync_work_fn);
+ spin_lock_init(&pool->destroy_lock);
+ INIT_LIST_HEAD(&pool->destroy_list);
+ INIT_WORK(&pool->destroy_work, mlx5_crypto_dek_destroy_work_fn);
+
+ return pool;
+}
+
+void mlx5_crypto_dek_pool_destroy(struct mlx5_crypto_dek_pool *pool)
+{
+ struct mlx5_crypto_dek_bulk *bulk, *tmp;
+
+ cancel_work_sync(&pool->sync_work);
+ cancel_work_sync(&pool->destroy_work);
+
+ mlx5_crypto_dek_pool_free_wait_keys(pool);
+
+ list_for_each_entry_safe(bulk, tmp, &pool->avail_list, entry)
+ mlx5_crypto_dek_pool_remove_bulk(pool, bulk, false);
+
+ list_for_each_entry_safe(bulk, tmp, &pool->full_list, entry)
+ mlx5_crypto_dek_pool_remove_bulk(pool, bulk, false);
+
+ list_for_each_entry_safe(bulk, tmp, &pool->sync_list, entry)
+ mlx5_crypto_dek_pool_remove_bulk(pool, bulk, false);
+
+ list_for_each_entry_safe(bulk, tmp, &pool->partial_list, entry)
+ mlx5_crypto_dek_pool_remove_bulk(pool, bulk, false);
+
+ mlx5_crypto_dek_free_destroy_list(&pool->destroy_list);
+
+ mutex_destroy(&pool->lock);
+
+ kfree(pool);
+}
+
+void mlx5_crypto_dek_cleanup(struct mlx5_crypto_dek_priv *dek_priv)
+{
+ if (!dek_priv)
+ return;
+
+ kfree(dek_priv);
+}
+
+struct mlx5_crypto_dek_priv *mlx5_crypto_dek_init(struct mlx5_core_dev *mdev)
+{
+ struct mlx5_crypto_dek_priv *dek_priv;
+ int err;
+
+ if (!MLX5_CAP_CRYPTO(mdev, log_dek_max_alloc))
+ return NULL;
+
+ dek_priv = kzalloc(sizeof(*dek_priv), GFP_KERNEL);
+ if (!dek_priv)
+ return ERR_PTR(-ENOMEM);
+
+ dek_priv->mdev = mdev;
+ dek_priv->log_dek_obj_range = min_t(int, 12,
+ MLX5_CAP_CRYPTO(mdev, log_dek_max_alloc));
+
+ /* sync all types of objects */
+ err = mlx5_crypto_cmd_sync_crypto(mdev, MLX5_CRYPTO_DEK_ALL_TYPE);
+ if (err)
+ goto err_sync_crypto;
+
+ mlx5_core_dbg(mdev, "Crypto DEK enabled, %d deks per alloc (max %d), total %d\n",
+ 1 << dek_priv->log_dek_obj_range,
+ 1 << MLX5_CAP_CRYPTO(mdev, log_dek_max_alloc),
+ 1 << MLX5_CAP_CRYPTO(mdev, log_max_num_deks));
+
+ return dek_priv;
+
+err_sync_crypto:
+ kfree(dek_priv);
+ return ERR_PTR(err);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.h
new file mode 100644
index 000000000000..c819c047bb9c
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#ifndef __MLX5_LIB_CRYPTO_H__
+#define __MLX5_LIB_CRYPTO_H__
+
+enum {
+ MLX5_ACCEL_OBJ_TLS_KEY = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_PURPOSE_TLS,
+ MLX5_ACCEL_OBJ_IPSEC_KEY = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_PURPOSE_IPSEC,
+ MLX5_ACCEL_OBJ_MACSEC_KEY = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_PURPOSE_MACSEC,
+ MLX5_ACCEL_OBJ_TYPE_KEY_NUM,
+};
+
+int mlx5_create_encryption_key(struct mlx5_core_dev *mdev,
+ const void *key, u32 sz_bytes,
+ u32 key_type, u32 *p_key_id);
+
+void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id);
+
+struct mlx5_crypto_dek_pool;
+struct mlx5_crypto_dek;
+
+struct mlx5_crypto_dek_pool *mlx5_crypto_dek_pool_create(struct mlx5_core_dev *mdev,
+ int key_purpose);
+void mlx5_crypto_dek_pool_destroy(struct mlx5_crypto_dek_pool *pool);
+struct mlx5_crypto_dek *mlx5_crypto_dek_create(struct mlx5_crypto_dek_pool *dek_pool,
+ const void *key, u32 sz_bytes);
+void mlx5_crypto_dek_destroy(struct mlx5_crypto_dek_pool *dek_pool,
+ struct mlx5_crypto_dek *dek);
+u32 mlx5_crypto_dek_get_id(struct mlx5_crypto_dek *dek);
+
+struct mlx5_crypto_dek_priv *mlx5_crypto_dek_init(struct mlx5_core_dev *mdev);
+void mlx5_crypto_dek_cleanup(struct mlx5_crypto_dek_priv *dek_priv);
+#endif /* __MLX5_LIB_CRYPTO_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h
index 032adb21ad4b..55bd7c4c021e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h
@@ -79,18 +79,6 @@ struct mlx5_pme_stats {
void mlx5_get_pme_stats(struct mlx5_core_dev *dev, struct mlx5_pme_stats *stats);
int mlx5_notifier_call_chain(struct mlx5_events *events, unsigned int event, void *data);
-/* Crypto */
-enum {
- MLX5_ACCEL_OBJ_TLS_KEY = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_TLS,
- MLX5_ACCEL_OBJ_IPSEC_KEY = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_IPSEC,
- MLX5_ACCEL_OBJ_MACSEC_KEY = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_MACSEC,
-};
-
-int mlx5_create_encryption_key(struct mlx5_core_dev *mdev,
- void *key, u32 sz_bytes,
- u32 key_type, u32 *p_key_id);
-void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id);
-
static inline struct net *mlx5_core_net(struct mlx5_core_dev *dev)
{
return devlink_net(priv_to_devlink(dev));
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 8823f20d2122..9441588ac524 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -1555,6 +1555,7 @@ static const int types[] = {
MLX5_CAP_DEV_SHAMPO,
MLX5_CAP_MACSEC,
MLX5_CAP_ADV_VIRTUALIZATION,
+ MLX5_CAP_CRYPTO,
};
static void mlx5_hca_caps_free(struct mlx5_core_dev *dev)
diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h
index 29d4b201c7b2..bc531bd9804f 100644
--- a/include/linux/mlx5/device.h
+++ b/include/linux/mlx5/device.h
@@ -1204,6 +1204,7 @@ enum mlx5_cap_type {
MLX5_CAP_VDPA_EMULATION = 0x13,
MLX5_CAP_DEV_EVENT = 0x14,
MLX5_CAP_IPSEC,
+ MLX5_CAP_CRYPTO = 0x1a,
MLX5_CAP_DEV_SHAMPO = 0x1d,
MLX5_CAP_MACSEC = 0x1f,
MLX5_CAP_GENERAL_2 = 0x20,
@@ -1460,6 +1461,9 @@ enum mlx5_qcam_feature_groups {
#define MLX5_CAP_IPSEC(mdev, cap)\
MLX5_GET(ipsec_cap, (mdev)->caps.hca[MLX5_CAP_IPSEC]->cur, cap)
+#define MLX5_CAP_CRYPTO(mdev, cap)\
+ MLX5_GET(crypto_cap, (mdev)->caps.hca[MLX5_CAP_CRYPTO]->cur, cap)
+
#define MLX5_CAP_DEV_SHAMPO(mdev, cap)\
MLX5_GET(shampo_cap, mdev->caps.hca_cur[MLX5_CAP_DEV_SHAMPO], cap)
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index 44167760ff29..cd529e051b4d 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -516,6 +516,7 @@ struct mlx5_vhca_state_notifier;
struct mlx5_sf_dev_table;
struct mlx5_sf_hw_table;
struct mlx5_sf_table;
+struct mlx5_crypto_dek_priv;
struct mlx5_rate_limit {
u32 rate;
@@ -673,6 +674,7 @@ struct mlx5e_resources {
} hw_objs;
struct devlink_port dl_port;
struct net_device *uplink_netdev;
+ struct mlx5_crypto_dek_priv *dek_priv;
};
enum mlx5_sw_icm_type {
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index 0b102c651fe2..1b6201bb04c1 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -306,6 +306,7 @@ enum {
MLX5_CMD_OP_SYNC_STEERING = 0xb00,
MLX5_CMD_OP_QUERY_VHCA_STATE = 0xb0d,
MLX5_CMD_OP_MODIFY_VHCA_STATE = 0xb0e,
+ MLX5_CMD_OP_SYNC_CRYPTO = 0xb12,
MLX5_CMD_OP_MAX
};
@@ -1112,6 +1113,30 @@ struct mlx5_ifc_sync_steering_out_bits {
u8 reserved_at_40[0x40];
};
+struct mlx5_ifc_sync_crypto_in_bits {
+ u8 opcode[0x10];
+ u8 uid[0x10];
+
+ u8 reserved_at_20[0x10];
+ u8 op_mod[0x10];
+
+ u8 reserved_at_40[0x20];
+
+ u8 reserved_at_60[0x10];
+ u8 crypto_type[0x10];
+
+ u8 reserved_at_80[0x80];
+};
+
+struct mlx5_ifc_sync_crypto_out_bits {
+ u8 status[0x8];
+ u8 reserved_at_8[0x18];
+
+ u8 syndrome[0x20];
+
+ u8 reserved_at_40[0x40];
+};
+
struct mlx5_ifc_device_mem_cap_bits {
u8 memic[0x1];
u8 reserved_at_1[0x1f];
@@ -1768,7 +1793,8 @@ struct mlx5_ifc_cmd_hca_cap_bits {
u8 ats[0x1];
u8 reserved_at_462[0x1];
u8 log_max_uctx[0x5];
- u8 reserved_at_468[0x2];
+ u8 reserved_at_468[0x1];
+ u8 crypto[0x1];
u8 ipsec_offload[0x1];
u8 log_max_umem[0x5];
u8 max_num_eqs[0x10];
@@ -3351,6 +3377,30 @@ struct mlx5_ifc_shampo_cap_bits {
u8 reserved_at_40[0x7c0];
};
+struct mlx5_ifc_crypto_cap_bits {
+ u8 reserved_at_0[0x3];
+ u8 synchronize_dek[0x1];
+ u8 int_kek_manual[0x1];
+ u8 int_kek_auto[0x1];
+ u8 reserved_at_6[0x1a];
+
+ u8 reserved_at_20[0x3];
+ u8 log_dek_max_alloc[0x5];
+ u8 reserved_at_28[0x3];
+ u8 log_max_num_deks[0x5];
+ u8 reserved_at_30[0x10];
+
+ u8 reserved_at_40[0x20];
+
+ u8 reserved_at_60[0x3];
+ u8 log_dek_granularity[0x5];
+ u8 reserved_at_68[0x3];
+ u8 log_max_num_int_kek[0x5];
+ u8 sw_wrapped_dek[0x10];
+
+ u8 reserved_at_80[0x780];
+};
+
union mlx5_ifc_hca_cap_union_bits {
struct mlx5_ifc_cmd_hca_cap_bits cmd_hca_cap;
struct mlx5_ifc_cmd_hca_cap_2_bits cmd_hca_cap_2;
@@ -3371,6 +3421,7 @@ union mlx5_ifc_hca_cap_union_bits {
struct mlx5_ifc_virtio_emulation_cap_bits virtio_emulation_cap;
struct mlx5_ifc_shampo_cap_bits shampo_cap;
struct mlx5_ifc_macsec_cap_bits macsec_cap;
+ struct mlx5_ifc_crypto_cap_bits crypto_cap;
u8 reserved_at_0[0x8000];
};
@@ -6196,6 +6247,18 @@ struct mlx5_ifc_match_definer_bits {
};
};
+struct mlx5_ifc_general_obj_create_param_bits {
+ u8 alias_object[0x1];
+ u8 reserved_at_1[0x2];
+ u8 log_obj_range[0x5];
+ u8 reserved_at_8[0x18];
+};
+
+struct mlx5_ifc_general_obj_query_param_bits {
+ u8 alias_object[0x1];
+ u8 obj_offset[0x1f];
+};
+
struct mlx5_ifc_general_obj_in_cmd_hdr_bits {
u8 opcode[0x10];
u8 uid[0x10];
@@ -6205,9 +6268,10 @@ struct mlx5_ifc_general_obj_in_cmd_hdr_bits {
u8 obj_id[0x20];
- u8 reserved_at_60[0x3];
- u8 log_obj_range[0x5];
- u8 reserved_at_68[0x18];
+ union {
+ struct mlx5_ifc_general_obj_create_param_bits create;
+ struct mlx5_ifc_general_obj_query_param_bits query;
+ } op_param;
};
struct mlx5_ifc_general_obj_out_cmd_hdr_bits {
@@ -11702,6 +11766,7 @@ enum {
MLX5_GENERAL_OBJECT_TYPES_SAMPLER = 0x20,
MLX5_GENERAL_OBJECT_TYPES_FLOW_METER_ASO = 0x24,
MLX5_GENERAL_OBJECT_TYPES_MACSEC = 0x27,
+ MLX5_GENERAL_OBJECT_TYPES_INT_KEK = 0x47,
};
enum {
@@ -11881,21 +11946,62 @@ struct mlx5_ifc_query_macsec_obj_out_bits {
struct mlx5_ifc_macsec_offload_obj_bits macsec_object;
};
+struct mlx5_ifc_wrapped_dek_bits {
+ u8 gcm_iv[0x60];
+
+ u8 reserved_at_60[0x20];
+
+ u8 const0[0x1];
+ u8 key_size[0x1];
+ u8 reserved_at_82[0x2];
+ u8 key2_invalid[0x1];
+ u8 reserved_at_85[0x3];
+ u8 pd[0x18];
+
+ u8 key_purpose[0x5];
+ u8 reserved_at_a5[0x13];
+ u8 kek_id[0x8];
+
+ u8 reserved_at_c0[0x40];
+
+ u8 key1[0x8][0x20];
+
+ u8 key2[0x8][0x20];
+
+ u8 reserved_at_300[0x40];
+
+ u8 const1[0x1];
+ u8 reserved_at_341[0x1f];
+
+ u8 reserved_at_360[0x20];
+
+ u8 auth_tag[0x80];
+};
+
struct mlx5_ifc_encryption_key_obj_bits {
u8 modify_field_select[0x40];
- u8 reserved_at_40[0x14];
+ u8 state[0x8];
+ u8 sw_wrapped[0x1];
+ u8 reserved_at_49[0xb];
u8 key_size[0x4];
u8 reserved_at_58[0x4];
- u8 key_type[0x4];
+ u8 key_purpose[0x4];
u8 reserved_at_60[0x8];
u8 pd[0x18];
- u8 reserved_at_80[0x180];
- u8 key[8][0x20];
+ u8 reserved_at_80[0x100];
+
+ u8 opaque[0x40];
+
+ u8 reserved_at_1c0[0x40];
+
+ u8 key[8][0x80];
+
+ u8 sw_wrapped_dek[8][0x80];
- u8 reserved_at_300[0x500];
+ u8 reserved_at_a00[0x600];
};
struct mlx5_ifc_create_encryption_key_in_bits {
@@ -11903,6 +12009,11 @@ struct mlx5_ifc_create_encryption_key_in_bits {
struct mlx5_ifc_encryption_key_obj_bits encryption_key_object;
};
+struct mlx5_ifc_modify_encryption_key_in_bits {
+ struct mlx5_ifc_general_obj_in_cmd_hdr_bits general_obj_in_cmd_hdr;
+ struct mlx5_ifc_encryption_key_obj_bits encryption_key_object;
+};
+
enum {
MLX5_FLOW_METER_MODE_BYTES_IP_LENGTH = 0x0,
MLX5_FLOW_METER_MODE_BYTES_CALC_WITH_L2 = 0x1,
@@ -11958,6 +12069,34 @@ struct mlx5_ifc_create_flow_meter_aso_obj_in_bits {
struct mlx5_ifc_flow_meter_aso_obj_bits flow_meter_aso_obj;
};
+struct mlx5_ifc_int_kek_obj_bits {
+ u8 modify_field_select[0x40];
+
+ u8 state[0x8];
+ u8 auto_gen[0x1];
+ u8 reserved_at_49[0xb];
+ u8 key_size[0x4];
+ u8 reserved_at_58[0x8];
+
+ u8 reserved_at_60[0x8];
+ u8 pd[0x18];
+
+ u8 reserved_at_80[0x180];
+ u8 key[8][0x80];
+
+ u8 reserved_at_600[0x200];
+};
+
+struct mlx5_ifc_create_int_kek_obj_in_bits {
+ struct mlx5_ifc_general_obj_in_cmd_hdr_bits general_obj_in_cmd_hdr;
+ struct mlx5_ifc_int_kek_obj_bits int_kek_object;
+};
+
+struct mlx5_ifc_create_int_kek_obj_out_bits {
+ struct mlx5_ifc_general_obj_out_cmd_hdr_bits general_obj_out_cmd_hdr;
+ struct mlx5_ifc_int_kek_obj_bits int_kek_object;
+};
+
struct mlx5_ifc_sampler_obj_bits {
u8 modify_field_select[0x40];
@@ -11996,9 +12135,9 @@ enum {
};
enum {
- MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_TLS = 0x1,
- MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_IPSEC = 0x2,
- MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_MACSEC = 0x4,
+ MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_PURPOSE_TLS = 0x1,
+ MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_PURPOSE_IPSEC = 0x2,
+ MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_PURPOSE_MACSEC = 0x4,
};
struct mlx5_ifc_tls_static_params_bits {