cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dm.c (6316B)


      1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
      2// Copyright (c) 2019 Mellanox Technologies
      3
      4#include <linux/mlx5/driver.h>
      5#include <linux/mlx5/device.h>
      6
      7#include "mlx5_core.h"
      8#include "lib/mlx5.h"
      9
     10struct mlx5_dm {
     11	/* protect access to icm bitmask */
     12	spinlock_t lock;
     13	unsigned long *steering_sw_icm_alloc_blocks;
     14	unsigned long *header_modify_sw_icm_alloc_blocks;
     15};
     16
     17struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
     18{
     19	u64 header_modify_icm_blocks = 0;
     20	u64 steering_icm_blocks = 0;
     21	struct mlx5_dm *dm;
     22
     23	if (!(MLX5_CAP_GEN_64(dev, general_obj_types) & MLX5_GENERAL_OBJ_TYPES_CAP_SW_ICM))
     24		return NULL;
     25
     26	dm = kzalloc(sizeof(*dm), GFP_KERNEL);
     27	if (!dm)
     28		return ERR_PTR(-ENOMEM);
     29
     30	spin_lock_init(&dm->lock);
     31
     32	if (MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address)) {
     33		steering_icm_blocks =
     34			BIT(MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size) -
     35			    MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
     36
     37		dm->steering_sw_icm_alloc_blocks =
     38			kcalloc(BITS_TO_LONGS(steering_icm_blocks),
     39				sizeof(unsigned long), GFP_KERNEL);
     40		if (!dm->steering_sw_icm_alloc_blocks)
     41			goto err_steering;
     42	}
     43
     44	if (MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address)) {
     45		header_modify_icm_blocks =
     46			BIT(MLX5_CAP_DEV_MEM(dev, log_header_modify_sw_icm_size) -
     47			    MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
     48
     49		dm->header_modify_sw_icm_alloc_blocks =
     50			kcalloc(BITS_TO_LONGS(header_modify_icm_blocks),
     51				sizeof(unsigned long), GFP_KERNEL);
     52		if (!dm->header_modify_sw_icm_alloc_blocks)
     53			goto err_modify_hdr;
     54	}
     55
     56	return dm;
     57
     58err_modify_hdr:
     59	kfree(dm->steering_sw_icm_alloc_blocks);
     60
     61err_steering:
     62	kfree(dm);
     63
     64	return ERR_PTR(-ENOMEM);
     65}
     66
     67void mlx5_dm_cleanup(struct mlx5_core_dev *dev)
     68{
     69	struct mlx5_dm *dm = dev->dm;
     70
     71	if (!dev->dm)
     72		return;
     73
     74	if (dm->steering_sw_icm_alloc_blocks) {
     75		WARN_ON(!bitmap_empty(dm->steering_sw_icm_alloc_blocks,
     76				      BIT(MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size) -
     77					  MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
     78		kfree(dm->steering_sw_icm_alloc_blocks);
     79	}
     80
     81	if (dm->header_modify_sw_icm_alloc_blocks) {
     82		WARN_ON(!bitmap_empty(dm->header_modify_sw_icm_alloc_blocks,
     83				      BIT(MLX5_CAP_DEV_MEM(dev,
     84							   log_header_modify_sw_icm_size) -
     85				      MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
     86		kfree(dm->header_modify_sw_icm_alloc_blocks);
     87	}
     88
     89	kfree(dm);
     90}
     91
     92int mlx5_dm_sw_icm_alloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type,
     93			 u64 length, u32 log_alignment, u16 uid,
     94			 phys_addr_t *addr, u32 *obj_id)
     95{
     96	u32 num_blocks = DIV_ROUND_UP_ULL(length, MLX5_SW_ICM_BLOCK_SIZE(dev));
     97	u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
     98	u32 in[MLX5_ST_SZ_DW(create_sw_icm_in)] = {};
     99	struct mlx5_dm *dm = dev->dm;
    100	unsigned long *block_map;
    101	u64 icm_start_addr;
    102	u32 log_icm_size;
    103	u64 align_mask;
    104	u32 max_blocks;
    105	u64 block_idx;
    106	void *sw_icm;
    107	int ret;
    108
    109	if (!dev->dm)
    110		return -EOPNOTSUPP;
    111
    112	if (!length || (length & (length - 1)) ||
    113	    length & (MLX5_SW_ICM_BLOCK_SIZE(dev) - 1))
    114		return -EINVAL;
    115
    116	MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
    117		 MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
    118	MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_SW_ICM);
    119	MLX5_SET(general_obj_in_cmd_hdr, in, uid, uid);
    120
    121	switch (type) {
    122	case MLX5_SW_ICM_TYPE_STEERING:
    123		icm_start_addr = MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address);
    124		log_icm_size = MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size);
    125		block_map = dm->steering_sw_icm_alloc_blocks;
    126		break;
    127	case MLX5_SW_ICM_TYPE_HEADER_MODIFY:
    128		icm_start_addr = MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address);
    129		log_icm_size = MLX5_CAP_DEV_MEM(dev,
    130						log_header_modify_sw_icm_size);
    131		block_map = dm->header_modify_sw_icm_alloc_blocks;
    132		break;
    133	default:
    134		return -EINVAL;
    135	}
    136
    137	if (!block_map)
    138		return -EOPNOTSUPP;
    139
    140	max_blocks = BIT(log_icm_size - MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
    141
    142	if (log_alignment < MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))
    143		log_alignment = MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
    144	align_mask = BIT(log_alignment - MLX5_LOG_SW_ICM_BLOCK_SIZE(dev)) - 1;
    145
    146	spin_lock(&dm->lock);
    147	block_idx = bitmap_find_next_zero_area(block_map, max_blocks, 0,
    148					       num_blocks, align_mask);
    149
    150	if (block_idx < max_blocks)
    151		bitmap_set(block_map,
    152			   block_idx, num_blocks);
    153
    154	spin_unlock(&dm->lock);
    155
    156	if (block_idx >= max_blocks)
    157		return -ENOMEM;
    158
    159	sw_icm = MLX5_ADDR_OF(create_sw_icm_in, in, sw_icm);
    160	icm_start_addr += block_idx << MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
    161	MLX5_SET64(sw_icm, sw_icm, sw_icm_start_addr,
    162		   icm_start_addr);
    163	MLX5_SET(sw_icm, sw_icm, log_sw_icm_size, ilog2(length));
    164
    165	ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
    166	if (ret) {
    167		spin_lock(&dm->lock);
    168		bitmap_clear(block_map,
    169			     block_idx, num_blocks);
    170		spin_unlock(&dm->lock);
    171
    172		return ret;
    173	}
    174
    175	*addr = icm_start_addr;
    176	*obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
    177
    178	return 0;
    179}
    180EXPORT_SYMBOL_GPL(mlx5_dm_sw_icm_alloc);
    181
    182int mlx5_dm_sw_icm_dealloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type,
    183			   u64 length, u16 uid, phys_addr_t addr, u32 obj_id)
    184{
    185	u32 num_blocks = DIV_ROUND_UP_ULL(length, MLX5_SW_ICM_BLOCK_SIZE(dev));
    186	u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
    187	u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
    188	struct mlx5_dm *dm = dev->dm;
    189	unsigned long *block_map;
    190	u64 icm_start_addr;
    191	u64 start_idx;
    192	int err;
    193
    194	if (!dev->dm)
    195		return -EOPNOTSUPP;
    196
    197	switch (type) {
    198	case MLX5_SW_ICM_TYPE_STEERING:
    199		icm_start_addr = MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address);
    200		block_map = dm->steering_sw_icm_alloc_blocks;
    201		break;
    202	case MLX5_SW_ICM_TYPE_HEADER_MODIFY:
    203		icm_start_addr = MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address);
    204		block_map = dm->header_modify_sw_icm_alloc_blocks;
    205		break;
    206	default:
    207		return -EINVAL;
    208	}
    209
    210	MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
    211		 MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
    212	MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_SW_ICM);
    213	MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id);
    214	MLX5_SET(general_obj_in_cmd_hdr, in, uid, uid);
    215
    216	err =  mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
    217	if (err)
    218		return err;
    219
    220	start_idx = (addr - icm_start_addr) >> MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
    221	spin_lock(&dm->lock);
    222	bitmap_clear(block_map,
    223		     start_idx, num_blocks);
    224	spin_unlock(&dm->lock);
    225
    226	return 0;
    227}
    228EXPORT_SYMBOL_GPL(mlx5_dm_sw_icm_dealloc);