blob: 99c6f76a2a3a729e3c6601543ab75c2563ec3eae [file] [log] [blame] [edit]
// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
/*
* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved
*/
#ifndef MLX5_VFIO_H
#define MLX5_VFIO_H
#include <stddef.h>
#include <stdio.h>
#include "mlx5.h"
#include "mlx5_ifc.h"
#include <infiniband/driver.h>
#include <util/interval_set.h>
#include "mlx5_ifc.h"
#define FW_INIT_WAIT_MS 2
#define FW_PRE_INIT_TIMEOUT_MILI 120000
enum {
MLX5_MAX_COMMANDS = 32,
MLX5_CMD_DATA_BLOCK_SIZE = 512,
MLX5_PCI_CMD_XPORT = 7,
};
enum mlx5_ib_mtt_access_flags {
MLX5_MTT_READ = (1 << 0),
MLX5_MTT_WRITE = (1 << 1),
};
enum {
MLX5_MAX_PAGE_SHIFT = 31,
};
#define MLX5_MTT_PRESENT (MLX5_MTT_READ | MLX5_MTT_WRITE)
enum {
MLX5_VFIO_BLOCK_SIZE = 2 * 1024 * 1024,
MLX5_VFIO_BLOCK_NUM_PAGES = MLX5_VFIO_BLOCK_SIZE / MLX5_ADAPTER_PAGE_SIZE,
};
struct mlx5_vfio_mr {
struct verbs_mr vmr;
uint64_t iova;
uint64_t iova_page_size;
uint64_t iova_aligned_offset;
uint64_t iova_reg_size;
};
struct mlx5_vfio_devx_umem {
struct mlx5dv_devx_umem dv_devx_umem;
struct ibv_context *context;
void *addr;
size_t size;
uint64_t iova;
uint64_t iova_size;
uint64_t iova_reg_size;
};
struct mlx5_vfio_device {
struct verbs_device vdev;
char *pci_name;
char vfio_path[IBV_SYSFS_PATH_MAX];
int page_size;
uint32_t flags;
atomic_int mkey_var;
};
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define MLX5_SET_HOST_ENDIANNESS 0
#elif __BYTE_ORDER == __BIG_ENDIAN
#define MLX5_SET_HOST_ENDIANNESS 0x80
#else
#error Host endianness not defined
#endif
/* GET Dev Caps macros */
#define MLX5_VFIO_CAP_GEN(ctx, cap) \
DEVX_GET(cmd_hca_cap, ctx->caps.hca_cur[MLX5_CAP_GENERAL], cap)
#define MLX5_VFIO_CAP_GEN_64(mdev, cap) \
DEVX_GET64(cmd_hca_cap, mdev->caps.hca_cur[MLX5_CAP_GENERAL], cap)
#define MLX5_VFIO_CAP_GEN_MAX(ctx, cap) \
DEVX_GET(cmd_hca_cap, ctx->caps.hca_max[MLX5_CAP_GENERAL], cap)
#define MLX5_VFIO_CAP_ROCE(ctx, cap) \
DEVX_GET(roce_cap, ctx->caps.hca_cur[MLX5_CAP_ROCE], cap)
#define MLX5_VFIO_CAP_ROCE_MAX(ctx, cap) \
DEVX_GET(roce_cap, ctx->caps.hca_max[MLX5_CAP_ROCE], cap)
struct mlx5_vfio_context;
struct mlx5_reg_host_endianness {
uint8_t he;
uint8_t rsvd[15];
};
struct health_buffer {
__be32 assert_var[5];
__be32 rsvd0[3];
__be32 assert_exit_ptr;
__be32 assert_callra;
__be32 rsvd1[2];
__be32 fw_ver;
__be32 hw_id;
__be32 rfr;
uint8_t irisc_index;
uint8_t synd;
__be16 ext_synd;
};
struct mlx5_init_seg {
__be32 fw_rev;
__be32 cmdif_rev_fw_sub;
__be32 rsvd0[2];
__be32 cmdq_addr_h;
__be32 cmdq_addr_l_sz;
__be32 cmd_dbell;
__be32 rsvd1[120];
__be32 initializing;
struct health_buffer health;
__be32 rsvd2[880];
__be32 internal_timer_h;
__be32 internal_timer_l;
__be32 rsvd3[2];
__be32 health_counter;
__be32 rsvd4[1019];
__be64 ieee1588_clk;
__be32 ieee1588_clk_type;
__be32 clr_intx;
};
struct mlx5_cmd_layout {
uint8_t type;
uint8_t rsvd0[3];
__be32 ilen;
__be64 iptr;
__be32 in[4];
__be32 out[4];
__be64 optr;
__be32 olen;
uint8_t token;
uint8_t sig;
uint8_t rsvd1;
uint8_t status_own;
};
struct mlx5_cmd_block {
uint8_t data[MLX5_CMD_DATA_BLOCK_SIZE];
uint8_t rsvd0[48];
__be64 next;
__be32 block_num;
uint8_t rsvd1;
uint8_t token;
uint8_t ctrl_sig;
uint8_t sig;
};
struct page_block {
void *page_ptr;
uint64_t iova;
struct list_node next_block;
BMP_DECLARE(free_pages, MLX5_VFIO_BLOCK_NUM_PAGES);
};
struct vfio_mem_allocator {
struct list_head block_list;
pthread_mutex_t block_list_mutex;
};
struct mlx5_cmd_mailbox {
void *buf;
uint64_t iova;
struct mlx5_cmd_mailbox *next;
};
struct mlx5_cmd_msg {
uint32_t len;
struct mlx5_cmd_mailbox *next;
};
typedef int (*vfio_cmd_slot_comp)(struct mlx5_vfio_context *ctx,
unsigned long slot);
struct cmd_async_data {
void *buff_in;
int ilen;
void *buff_out;
int olen;
};
struct mlx5_vfio_cmd_slot {
struct mlx5_cmd_layout *lay;
struct mlx5_cmd_msg in;
struct mlx5_cmd_msg out;
pthread_mutex_t lock;
int completion_event_fd;
vfio_cmd_slot_comp comp_func;
/* async cmd caller data */
bool in_use;
struct cmd_async_data curr;
bool is_pending;
struct cmd_async_data pending;
};
struct mlx5_vfio_cmd {
void *vaddr; /* cmd page address */
uint64_t iova;
uint8_t log_sz;
uint8_t log_stride;
struct mlx5_vfio_cmd_slot cmds[MLX5_MAX_COMMANDS];
};
struct mlx5_eq_param {
uint8_t irq_index;
int nent;
uint64_t mask[4];
};
struct mlx5_eq {
__be32 *doorbell;
uint32_t cons_index;
unsigned int vecidx;
uint8_t eqn;
int nent;
void *vaddr;
uint64_t iova;
uint64_t iova_size;
};
struct mlx5_eqe_cmd {
__be32 vector;
__be32 rsvd[6];
};
struct mlx5_eqe_page_req {
__be16 ec_function;
__be16 func_id;
__be32 num_pages;
__be32 rsvd1[5];
};
union ev_data {
__be32 raw[7];
struct mlx5_eqe_cmd cmd;
struct mlx5_eqe_page_req req_pages;
};
struct mlx5_eqe {
uint8_t rsvd0;
uint8_t type;
uint8_t rsvd1;
uint8_t sub_type;
__be32 rsvd2[7];
union ev_data data;
__be16 rsvd3;
uint8_t signature;
uint8_t owner;
};
#define MLX5_EQE_SIZE (sizeof(struct mlx5_eqe))
#define MLX5_NUM_CMD_EQE (32)
#define MLX5_NUM_SPARE_EQE (0x80)
struct mlx5_vfio_eqs_uar {
uint32_t uarn;
uint64_t iova;
};
#define POLL_HEALTH_INTERVAL 1000 /* ms */
#define MAX_MISSES 3
struct mlx5_vfio_health_state {
uint64_t prev_time; /* ms */
uint32_t prev_count;
uint32_t miss_counter;
};
struct mlx5_vfio_context {
struct verbs_context vctx;
int container_fd;
int group_fd;
int device_fd;
int cmd_comp_fd; /* command completion FD */
struct iset *iova_alloc;
uint64_t iova_min_page_size;
FILE *dbg_fp;
struct vfio_mem_allocator mem_alloc;
struct mlx5_init_seg *bar_map;
size_t bar_map_size;
struct mlx5_vfio_cmd cmd;
bool have_eq;
struct {
uint32_t hca_cur[MLX5_CAP_NUM][DEVX_UN_SZ_DW(hca_cap_union)];
uint32_t hca_max[MLX5_CAP_NUM][DEVX_UN_SZ_DW(hca_cap_union)];
} caps;
struct mlx5_vfio_health_state health_state;
struct mlx5_eq async_eq;
struct mlx5_vfio_eqs_uar eqs_uar;
pthread_mutex_t eq_lock;
struct mlx5_dv_context_ops *dv_ctx_ops;
int *msix_fds;
pthread_mutex_t msix_fds_lock;
};
#define MLX5_MAX_DESTROY_INBOX_SIZE_DW DEVX_ST_SZ_DW(delete_fte_in)
struct mlx5_devx_obj {
struct mlx5dv_devx_obj dv_obj;
uint32_t dinbox[MLX5_MAX_DESTROY_INBOX_SIZE_DW];
uint32_t dinlen;
};
static inline struct mlx5_vfio_device *to_mvfio_dev(struct ibv_device *ibdev)
{
return container_of(ibdev, struct mlx5_vfio_device, vdev.device);
}
static inline struct mlx5_vfio_context *to_mvfio_ctx(struct ibv_context *ibctx)
{
return container_of(ibctx, struct mlx5_vfio_context, vctx.context);
}
static inline struct mlx5_vfio_mr *to_mvfio_mr(struct ibv_mr *ibmr)
{
return container_of(ibmr, struct mlx5_vfio_mr, vmr.ibv_mr);
}
#endif