|  | // 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 |