162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 262306a36Sopenharmony_ci/* Copyright (c) 2020 Mellanox Technologies Ltd. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/module.h> 562306a36Sopenharmony_ci#include <linux/vdpa.h> 662306a36Sopenharmony_ci#include <linux/vringh.h> 762306a36Sopenharmony_ci#include <uapi/linux/virtio_net.h> 862306a36Sopenharmony_ci#include <uapi/linux/virtio_ids.h> 962306a36Sopenharmony_ci#include <uapi/linux/vdpa.h> 1062306a36Sopenharmony_ci#include <linux/virtio_config.h> 1162306a36Sopenharmony_ci#include <linux/auxiliary_bus.h> 1262306a36Sopenharmony_ci#include <linux/mlx5/cq.h> 1362306a36Sopenharmony_ci#include <linux/mlx5/qp.h> 1462306a36Sopenharmony_ci#include <linux/mlx5/device.h> 1562306a36Sopenharmony_ci#include <linux/mlx5/driver.h> 1662306a36Sopenharmony_ci#include <linux/mlx5/vport.h> 1762306a36Sopenharmony_ci#include <linux/mlx5/fs.h> 1862306a36Sopenharmony_ci#include <linux/mlx5/mlx5_ifc_vdpa.h> 1962306a36Sopenharmony_ci#include <linux/mlx5/mpfs.h> 2062306a36Sopenharmony_ci#include "mlx5_vdpa.h" 2162306a36Sopenharmony_ci#include "mlx5_vnet.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ciMODULE_AUTHOR("Eli Cohen <eli@mellanox.com>"); 2462306a36Sopenharmony_ciMODULE_DESCRIPTION("Mellanox VDPA driver"); 2562306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define VALID_FEATURES_MASK \ 2862306a36Sopenharmony_ci (BIT_ULL(VIRTIO_NET_F_CSUM) | BIT_ULL(VIRTIO_NET_F_GUEST_CSUM) | \ 2962306a36Sopenharmony_ci BIT_ULL(VIRTIO_NET_F_CTRL_GUEST_OFFLOADS) | BIT_ULL(VIRTIO_NET_F_MTU) | BIT_ULL(VIRTIO_NET_F_MAC) | \ 3062306a36Sopenharmony_ci BIT_ULL(VIRTIO_NET_F_GUEST_TSO4) | BIT_ULL(VIRTIO_NET_F_GUEST_TSO6) | \ 3162306a36Sopenharmony_ci BIT_ULL(VIRTIO_NET_F_GUEST_ECN) | BIT_ULL(VIRTIO_NET_F_GUEST_UFO) | BIT_ULL(VIRTIO_NET_F_HOST_TSO4) | \ 3262306a36Sopenharmony_ci BIT_ULL(VIRTIO_NET_F_HOST_TSO6) | BIT_ULL(VIRTIO_NET_F_HOST_ECN) | BIT_ULL(VIRTIO_NET_F_HOST_UFO) | \ 3362306a36Sopenharmony_ci BIT_ULL(VIRTIO_NET_F_MRG_RXBUF) | BIT_ULL(VIRTIO_NET_F_STATUS) | BIT_ULL(VIRTIO_NET_F_CTRL_VQ) | \ 3462306a36Sopenharmony_ci BIT_ULL(VIRTIO_NET_F_CTRL_RX) | BIT_ULL(VIRTIO_NET_F_CTRL_VLAN) | \ 3562306a36Sopenharmony_ci BIT_ULL(VIRTIO_NET_F_CTRL_RX_EXTRA) | BIT_ULL(VIRTIO_NET_F_GUEST_ANNOUNCE) | \ 3662306a36Sopenharmony_ci BIT_ULL(VIRTIO_NET_F_MQ) | BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR) | BIT_ULL(VIRTIO_NET_F_HASH_REPORT) | \ 3762306a36Sopenharmony_ci BIT_ULL(VIRTIO_NET_F_RSS) | BIT_ULL(VIRTIO_NET_F_RSC_EXT) | BIT_ULL(VIRTIO_NET_F_STANDBY) | \ 3862306a36Sopenharmony_ci BIT_ULL(VIRTIO_NET_F_SPEED_DUPLEX) | BIT_ULL(VIRTIO_F_NOTIFY_ON_EMPTY) | \ 3962306a36Sopenharmony_ci BIT_ULL(VIRTIO_F_ANY_LAYOUT) | BIT_ULL(VIRTIO_F_VERSION_1) | BIT_ULL(VIRTIO_F_ACCESS_PLATFORM) | \ 4062306a36Sopenharmony_ci BIT_ULL(VIRTIO_F_RING_PACKED) | BIT_ULL(VIRTIO_F_ORDER_PLATFORM) | BIT_ULL(VIRTIO_F_SR_IOV)) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define VALID_STATUS_MASK \ 4362306a36Sopenharmony_ci (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK | \ 4462306a36Sopenharmony_ci VIRTIO_CONFIG_S_FEATURES_OK | VIRTIO_CONFIG_S_NEEDS_RESET | VIRTIO_CONFIG_S_FAILED) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define MLX5_FEATURE(_mvdev, _feature) (!!((_mvdev)->actual_features & BIT_ULL(_feature))) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define MLX5V_UNTAGGED 0x1000 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistruct mlx5_vdpa_cq_buf { 5162306a36Sopenharmony_ci struct mlx5_frag_buf_ctrl fbc; 5262306a36Sopenharmony_ci struct mlx5_frag_buf frag_buf; 5362306a36Sopenharmony_ci int cqe_size; 5462306a36Sopenharmony_ci int nent; 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistruct mlx5_vdpa_cq { 5862306a36Sopenharmony_ci struct mlx5_core_cq mcq; 5962306a36Sopenharmony_ci struct mlx5_vdpa_cq_buf buf; 6062306a36Sopenharmony_ci struct mlx5_db db; 6162306a36Sopenharmony_ci int cqe; 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistruct mlx5_vdpa_umem { 6562306a36Sopenharmony_ci struct mlx5_frag_buf_ctrl fbc; 6662306a36Sopenharmony_ci struct mlx5_frag_buf frag_buf; 6762306a36Sopenharmony_ci int size; 6862306a36Sopenharmony_ci u32 id; 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistruct mlx5_vdpa_qp { 7262306a36Sopenharmony_ci struct mlx5_core_qp mqp; 7362306a36Sopenharmony_ci struct mlx5_frag_buf frag_buf; 7462306a36Sopenharmony_ci struct mlx5_db db; 7562306a36Sopenharmony_ci u16 head; 7662306a36Sopenharmony_ci bool fw; 7762306a36Sopenharmony_ci}; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistruct mlx5_vq_restore_info { 8062306a36Sopenharmony_ci u32 num_ent; 8162306a36Sopenharmony_ci u64 desc_addr; 8262306a36Sopenharmony_ci u64 device_addr; 8362306a36Sopenharmony_ci u64 driver_addr; 8462306a36Sopenharmony_ci u16 avail_index; 8562306a36Sopenharmony_ci u16 used_index; 8662306a36Sopenharmony_ci struct msi_map map; 8762306a36Sopenharmony_ci bool ready; 8862306a36Sopenharmony_ci bool restore; 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistruct mlx5_vdpa_virtqueue { 9262306a36Sopenharmony_ci bool ready; 9362306a36Sopenharmony_ci u64 desc_addr; 9462306a36Sopenharmony_ci u64 device_addr; 9562306a36Sopenharmony_ci u64 driver_addr; 9662306a36Sopenharmony_ci u32 num_ent; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* Resources for implementing the notification channel from the device 9962306a36Sopenharmony_ci * to the driver. fwqp is the firmware end of an RC connection; the 10062306a36Sopenharmony_ci * other end is vqqp used by the driver. cq is where completions are 10162306a36Sopenharmony_ci * reported. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci struct mlx5_vdpa_cq cq; 10462306a36Sopenharmony_ci struct mlx5_vdpa_qp fwqp; 10562306a36Sopenharmony_ci struct mlx5_vdpa_qp vqqp; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* umem resources are required for the virtqueue operation. They're use 10862306a36Sopenharmony_ci * is internal and they must be provided by the driver. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_ci struct mlx5_vdpa_umem umem1; 11162306a36Sopenharmony_ci struct mlx5_vdpa_umem umem2; 11262306a36Sopenharmony_ci struct mlx5_vdpa_umem umem3; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci u32 counter_set_id; 11562306a36Sopenharmony_ci bool initialized; 11662306a36Sopenharmony_ci int index; 11762306a36Sopenharmony_ci u32 virtq_id; 11862306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev; 11962306a36Sopenharmony_ci u16 avail_idx; 12062306a36Sopenharmony_ci u16 used_idx; 12162306a36Sopenharmony_ci int fw_state; 12262306a36Sopenharmony_ci struct msi_map map; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* keep last in the struct */ 12562306a36Sopenharmony_ci struct mlx5_vq_restore_info ri; 12662306a36Sopenharmony_ci}; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic bool is_index_valid(struct mlx5_vdpa_dev *mvdev, u16 idx) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci if (!(mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_MQ))) { 13162306a36Sopenharmony_ci if (!(mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) 13262306a36Sopenharmony_ci return idx < 2; 13362306a36Sopenharmony_ci else 13462306a36Sopenharmony_ci return idx < 3; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return idx <= mvdev->max_idx; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic void free_resources(struct mlx5_vdpa_net *ndev); 14162306a36Sopenharmony_cistatic void init_mvqs(struct mlx5_vdpa_net *ndev); 14262306a36Sopenharmony_cistatic int setup_driver(struct mlx5_vdpa_dev *mvdev); 14362306a36Sopenharmony_cistatic void teardown_driver(struct mlx5_vdpa_net *ndev); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic bool mlx5_vdpa_debug; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#define MLX5_LOG_VIO_FLAG(_feature) \ 14862306a36Sopenharmony_ci do { \ 14962306a36Sopenharmony_ci if (features & BIT_ULL(_feature)) \ 15062306a36Sopenharmony_ci mlx5_vdpa_info(mvdev, "%s\n", #_feature); \ 15162306a36Sopenharmony_ci } while (0) 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci#define MLX5_LOG_VIO_STAT(_status) \ 15462306a36Sopenharmony_ci do { \ 15562306a36Sopenharmony_ci if (status & (_status)) \ 15662306a36Sopenharmony_ci mlx5_vdpa_info(mvdev, "%s\n", #_status); \ 15762306a36Sopenharmony_ci } while (0) 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* TODO: cross-endian support */ 16062306a36Sopenharmony_cistatic inline bool mlx5_vdpa_is_little_endian(struct mlx5_vdpa_dev *mvdev) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci return virtio_legacy_is_little_endian() || 16362306a36Sopenharmony_ci (mvdev->actual_features & BIT_ULL(VIRTIO_F_VERSION_1)); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic u16 mlx5vdpa16_to_cpu(struct mlx5_vdpa_dev *mvdev, __virtio16 val) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci return __virtio16_to_cpu(mlx5_vdpa_is_little_endian(mvdev), val); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic __virtio16 cpu_to_mlx5vdpa16(struct mlx5_vdpa_dev *mvdev, u16 val) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci return __cpu_to_virtio16(mlx5_vdpa_is_little_endian(mvdev), val); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic u16 ctrl_vq_idx(struct mlx5_vdpa_dev *mvdev) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci if (!(mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_MQ))) 17962306a36Sopenharmony_ci return 2; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return mvdev->max_vqs; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic bool is_ctrl_vq_idx(struct mlx5_vdpa_dev *mvdev, u16 idx) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci return idx == ctrl_vq_idx(mvdev); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic void print_status(struct mlx5_vdpa_dev *mvdev, u8 status, bool set) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci if (status & ~VALID_STATUS_MASK) 19262306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "Warning: there are invalid status bits 0x%x\n", 19362306a36Sopenharmony_ci status & ~VALID_STATUS_MASK); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (!mlx5_vdpa_debug) 19662306a36Sopenharmony_ci return; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci mlx5_vdpa_info(mvdev, "driver status %s", set ? "set" : "get"); 19962306a36Sopenharmony_ci if (set && !status) { 20062306a36Sopenharmony_ci mlx5_vdpa_info(mvdev, "driver resets the device\n"); 20162306a36Sopenharmony_ci return; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_ACKNOWLEDGE); 20562306a36Sopenharmony_ci MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_DRIVER); 20662306a36Sopenharmony_ci MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_DRIVER_OK); 20762306a36Sopenharmony_ci MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_FEATURES_OK); 20862306a36Sopenharmony_ci MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_NEEDS_RESET); 20962306a36Sopenharmony_ci MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_FAILED); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic void print_features(struct mlx5_vdpa_dev *mvdev, u64 features, bool set) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci if (features & ~VALID_FEATURES_MASK) 21562306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "There are invalid feature bits 0x%llx\n", 21662306a36Sopenharmony_ci features & ~VALID_FEATURES_MASK); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (!mlx5_vdpa_debug) 21962306a36Sopenharmony_ci return; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci mlx5_vdpa_info(mvdev, "driver %s feature bits:\n", set ? "sets" : "reads"); 22262306a36Sopenharmony_ci if (!features) 22362306a36Sopenharmony_ci mlx5_vdpa_info(mvdev, "all feature bits are cleared\n"); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CSUM); 22662306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_CSUM); 22762306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_GUEST_OFFLOADS); 22862306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_MTU); 22962306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_MAC); 23062306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_TSO4); 23162306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_TSO6); 23262306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_ECN); 23362306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_UFO); 23462306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HOST_TSO4); 23562306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HOST_TSO6); 23662306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HOST_ECN); 23762306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HOST_UFO); 23862306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_MRG_RXBUF); 23962306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_STATUS); 24062306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_VQ); 24162306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_RX); 24262306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_VLAN); 24362306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_RX_EXTRA); 24462306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_ANNOUNCE); 24562306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_MQ); 24662306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_MAC_ADDR); 24762306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HASH_REPORT); 24862306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_RSS); 24962306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_RSC_EXT); 25062306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_STANDBY); 25162306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_SPEED_DUPLEX); 25262306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_F_NOTIFY_ON_EMPTY); 25362306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_F_ANY_LAYOUT); 25462306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_F_VERSION_1); 25562306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_F_ACCESS_PLATFORM); 25662306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_F_RING_PACKED); 25762306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_F_ORDER_PLATFORM); 25862306a36Sopenharmony_ci MLX5_LOG_VIO_FLAG(VIRTIO_F_SR_IOV); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic int create_tis(struct mlx5_vdpa_net *ndev) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = &ndev->mvdev; 26462306a36Sopenharmony_ci u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {}; 26562306a36Sopenharmony_ci void *tisc; 26662306a36Sopenharmony_ci int err; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci tisc = MLX5_ADDR_OF(create_tis_in, in, ctx); 26962306a36Sopenharmony_ci MLX5_SET(tisc, tisc, transport_domain, ndev->res.tdn); 27062306a36Sopenharmony_ci err = mlx5_vdpa_create_tis(mvdev, in, &ndev->res.tisn); 27162306a36Sopenharmony_ci if (err) 27262306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "create TIS (%d)\n", err); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci return err; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic void destroy_tis(struct mlx5_vdpa_net *ndev) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci mlx5_vdpa_destroy_tis(&ndev->mvdev, ndev->res.tisn); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci#define MLX5_VDPA_CQE_SIZE 64 28362306a36Sopenharmony_ci#define MLX5_VDPA_LOG_CQE_SIZE ilog2(MLX5_VDPA_CQE_SIZE) 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int cq_frag_buf_alloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_cq_buf *buf, int nent) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct mlx5_frag_buf *frag_buf = &buf->frag_buf; 28862306a36Sopenharmony_ci u8 log_wq_stride = MLX5_VDPA_LOG_CQE_SIZE; 28962306a36Sopenharmony_ci u8 log_wq_sz = MLX5_VDPA_LOG_CQE_SIZE; 29062306a36Sopenharmony_ci int err; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci err = mlx5_frag_buf_alloc_node(ndev->mvdev.mdev, nent * MLX5_VDPA_CQE_SIZE, frag_buf, 29362306a36Sopenharmony_ci ndev->mvdev.mdev->priv.numa_node); 29462306a36Sopenharmony_ci if (err) 29562306a36Sopenharmony_ci return err; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci mlx5_init_fbc(frag_buf->frags, log_wq_stride, log_wq_sz, &buf->fbc); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci buf->cqe_size = MLX5_VDPA_CQE_SIZE; 30062306a36Sopenharmony_ci buf->nent = nent; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return 0; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic int umem_frag_buf_alloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_umem *umem, int size) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct mlx5_frag_buf *frag_buf = &umem->frag_buf; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci return mlx5_frag_buf_alloc_node(ndev->mvdev.mdev, size, frag_buf, 31062306a36Sopenharmony_ci ndev->mvdev.mdev->priv.numa_node); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic void cq_frag_buf_free(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_cq_buf *buf) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci mlx5_frag_buf_free(ndev->mvdev.mdev, &buf->frag_buf); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic void *get_cqe(struct mlx5_vdpa_cq *vcq, int n) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci return mlx5_frag_buf_get_wqe(&vcq->buf.fbc, n); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic void cq_frag_buf_init(struct mlx5_vdpa_cq *vcq, struct mlx5_vdpa_cq_buf *buf) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct mlx5_cqe64 *cqe64; 32662306a36Sopenharmony_ci void *cqe; 32762306a36Sopenharmony_ci int i; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci for (i = 0; i < buf->nent; i++) { 33062306a36Sopenharmony_ci cqe = get_cqe(vcq, i); 33162306a36Sopenharmony_ci cqe64 = cqe; 33262306a36Sopenharmony_ci cqe64->op_own = MLX5_CQE_INVALID << 4; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic void *get_sw_cqe(struct mlx5_vdpa_cq *cq, int n) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct mlx5_cqe64 *cqe64 = get_cqe(cq, n & (cq->cqe - 1)); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (likely(get_cqe_opcode(cqe64) != MLX5_CQE_INVALID) && 34162306a36Sopenharmony_ci !((cqe64->op_own & MLX5_CQE_OWNER_MASK) ^ !!(n & cq->cqe))) 34262306a36Sopenharmony_ci return cqe64; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return NULL; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic void rx_post(struct mlx5_vdpa_qp *vqp, int n) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci vqp->head += n; 35062306a36Sopenharmony_ci vqp->db.db[0] = cpu_to_be32(vqp->head); 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic void qp_prepare(struct mlx5_vdpa_net *ndev, bool fw, void *in, 35462306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq, u32 num_ent) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct mlx5_vdpa_qp *vqp; 35762306a36Sopenharmony_ci __be64 *pas; 35862306a36Sopenharmony_ci void *qpc; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci vqp = fw ? &mvq->fwqp : &mvq->vqqp; 36162306a36Sopenharmony_ci MLX5_SET(create_qp_in, in, uid, ndev->mvdev.res.uid); 36262306a36Sopenharmony_ci qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); 36362306a36Sopenharmony_ci if (vqp->fw) { 36462306a36Sopenharmony_ci /* Firmware QP is allocated by the driver for the firmware's 36562306a36Sopenharmony_ci * use so we can skip part of the params as they will be chosen by firmware 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_ci qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); 36862306a36Sopenharmony_ci MLX5_SET(qpc, qpc, rq_type, MLX5_ZERO_LEN_RQ); 36962306a36Sopenharmony_ci MLX5_SET(qpc, qpc, no_sq, 1); 37062306a36Sopenharmony_ci return; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci MLX5_SET(qpc, qpc, st, MLX5_QP_ST_RC); 37462306a36Sopenharmony_ci MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); 37562306a36Sopenharmony_ci MLX5_SET(qpc, qpc, pd, ndev->mvdev.res.pdn); 37662306a36Sopenharmony_ci MLX5_SET(qpc, qpc, mtu, MLX5_QPC_MTU_256_BYTES); 37762306a36Sopenharmony_ci MLX5_SET(qpc, qpc, uar_page, ndev->mvdev.res.uar->index); 37862306a36Sopenharmony_ci MLX5_SET(qpc, qpc, log_page_size, vqp->frag_buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); 37962306a36Sopenharmony_ci MLX5_SET(qpc, qpc, no_sq, 1); 38062306a36Sopenharmony_ci MLX5_SET(qpc, qpc, cqn_rcv, mvq->cq.mcq.cqn); 38162306a36Sopenharmony_ci MLX5_SET(qpc, qpc, log_rq_size, ilog2(num_ent)); 38262306a36Sopenharmony_ci MLX5_SET(qpc, qpc, rq_type, MLX5_NON_ZERO_RQ); 38362306a36Sopenharmony_ci pas = (__be64 *)MLX5_ADDR_OF(create_qp_in, in, pas); 38462306a36Sopenharmony_ci mlx5_fill_page_frag_array(&vqp->frag_buf, pas); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int rq_buf_alloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_qp *vqp, u32 num_ent) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci return mlx5_frag_buf_alloc_node(ndev->mvdev.mdev, 39062306a36Sopenharmony_ci num_ent * sizeof(struct mlx5_wqe_data_seg), &vqp->frag_buf, 39162306a36Sopenharmony_ci ndev->mvdev.mdev->priv.numa_node); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic void rq_buf_free(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_qp *vqp) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci mlx5_frag_buf_free(ndev->mvdev.mdev, &vqp->frag_buf); 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic int qp_create(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, 40062306a36Sopenharmony_ci struct mlx5_vdpa_qp *vqp) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci struct mlx5_core_dev *mdev = ndev->mvdev.mdev; 40362306a36Sopenharmony_ci int inlen = MLX5_ST_SZ_BYTES(create_qp_in); 40462306a36Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(create_qp_out)] = {}; 40562306a36Sopenharmony_ci void *qpc; 40662306a36Sopenharmony_ci void *in; 40762306a36Sopenharmony_ci int err; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (!vqp->fw) { 41062306a36Sopenharmony_ci vqp = &mvq->vqqp; 41162306a36Sopenharmony_ci err = rq_buf_alloc(ndev, vqp, mvq->num_ent); 41262306a36Sopenharmony_ci if (err) 41362306a36Sopenharmony_ci return err; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci err = mlx5_db_alloc(ndev->mvdev.mdev, &vqp->db); 41662306a36Sopenharmony_ci if (err) 41762306a36Sopenharmony_ci goto err_db; 41862306a36Sopenharmony_ci inlen += vqp->frag_buf.npages * sizeof(__be64); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci in = kzalloc(inlen, GFP_KERNEL); 42262306a36Sopenharmony_ci if (!in) { 42362306a36Sopenharmony_ci err = -ENOMEM; 42462306a36Sopenharmony_ci goto err_kzalloc; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci qp_prepare(ndev, vqp->fw, in, mvq, mvq->num_ent); 42862306a36Sopenharmony_ci qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); 42962306a36Sopenharmony_ci MLX5_SET(qpc, qpc, st, MLX5_QP_ST_RC); 43062306a36Sopenharmony_ci MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); 43162306a36Sopenharmony_ci MLX5_SET(qpc, qpc, pd, ndev->mvdev.res.pdn); 43262306a36Sopenharmony_ci MLX5_SET(qpc, qpc, mtu, MLX5_QPC_MTU_256_BYTES); 43362306a36Sopenharmony_ci if (!vqp->fw) 43462306a36Sopenharmony_ci MLX5_SET64(qpc, qpc, dbr_addr, vqp->db.dma); 43562306a36Sopenharmony_ci MLX5_SET(create_qp_in, in, opcode, MLX5_CMD_OP_CREATE_QP); 43662306a36Sopenharmony_ci err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); 43762306a36Sopenharmony_ci kfree(in); 43862306a36Sopenharmony_ci if (err) 43962306a36Sopenharmony_ci goto err_kzalloc; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci vqp->mqp.uid = ndev->mvdev.res.uid; 44262306a36Sopenharmony_ci vqp->mqp.qpn = MLX5_GET(create_qp_out, out, qpn); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (!vqp->fw) 44562306a36Sopenharmony_ci rx_post(vqp, mvq->num_ent); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci return 0; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cierr_kzalloc: 45062306a36Sopenharmony_ci if (!vqp->fw) 45162306a36Sopenharmony_ci mlx5_db_free(ndev->mvdev.mdev, &vqp->db); 45262306a36Sopenharmony_cierr_db: 45362306a36Sopenharmony_ci if (!vqp->fw) 45462306a36Sopenharmony_ci rq_buf_free(ndev, vqp); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci return err; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic void qp_destroy(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_qp *vqp) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci u32 in[MLX5_ST_SZ_DW(destroy_qp_in)] = {}; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci MLX5_SET(destroy_qp_in, in, opcode, MLX5_CMD_OP_DESTROY_QP); 46462306a36Sopenharmony_ci MLX5_SET(destroy_qp_in, in, qpn, vqp->mqp.qpn); 46562306a36Sopenharmony_ci MLX5_SET(destroy_qp_in, in, uid, ndev->mvdev.res.uid); 46662306a36Sopenharmony_ci if (mlx5_cmd_exec_in(ndev->mvdev.mdev, destroy_qp, in)) 46762306a36Sopenharmony_ci mlx5_vdpa_warn(&ndev->mvdev, "destroy qp 0x%x\n", vqp->mqp.qpn); 46862306a36Sopenharmony_ci if (!vqp->fw) { 46962306a36Sopenharmony_ci mlx5_db_free(ndev->mvdev.mdev, &vqp->db); 47062306a36Sopenharmony_ci rq_buf_free(ndev, vqp); 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic void *next_cqe_sw(struct mlx5_vdpa_cq *cq) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci return get_sw_cqe(cq, cq->mcq.cons_index); 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic int mlx5_vdpa_poll_one(struct mlx5_vdpa_cq *vcq) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct mlx5_cqe64 *cqe64; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci cqe64 = next_cqe_sw(vcq); 48462306a36Sopenharmony_ci if (!cqe64) 48562306a36Sopenharmony_ci return -EAGAIN; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci vcq->mcq.cons_index++; 48862306a36Sopenharmony_ci return 0; 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic void mlx5_vdpa_handle_completions(struct mlx5_vdpa_virtqueue *mvq, int num) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = mvq->ndev; 49462306a36Sopenharmony_ci struct vdpa_callback *event_cb; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci event_cb = &ndev->event_cbs[mvq->index]; 49762306a36Sopenharmony_ci mlx5_cq_set_ci(&mvq->cq.mcq); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* make sure CQ cosumer update is visible to the hardware before updating 50062306a36Sopenharmony_ci * RX doorbell record. 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_ci dma_wmb(); 50362306a36Sopenharmony_ci rx_post(&mvq->vqqp, num); 50462306a36Sopenharmony_ci if (event_cb->callback) 50562306a36Sopenharmony_ci event_cb->callback(event_cb->private); 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic void mlx5_vdpa_cq_comp(struct mlx5_core_cq *mcq, struct mlx5_eqe *eqe) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq = container_of(mcq, struct mlx5_vdpa_virtqueue, cq.mcq); 51162306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = mvq->ndev; 51262306a36Sopenharmony_ci void __iomem *uar_page = ndev->mvdev.res.uar->map; 51362306a36Sopenharmony_ci int num = 0; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci while (!mlx5_vdpa_poll_one(&mvq->cq)) { 51662306a36Sopenharmony_ci num++; 51762306a36Sopenharmony_ci if (num > mvq->num_ent / 2) { 51862306a36Sopenharmony_ci /* If completions keep coming while we poll, we want to 51962306a36Sopenharmony_ci * let the hardware know that we consumed them by 52062306a36Sopenharmony_ci * updating the doorbell record. We also let vdpa core 52162306a36Sopenharmony_ci * know about this so it passes it on the virtio driver 52262306a36Sopenharmony_ci * on the guest. 52362306a36Sopenharmony_ci */ 52462306a36Sopenharmony_ci mlx5_vdpa_handle_completions(mvq, num); 52562306a36Sopenharmony_ci num = 0; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (num) 53062306a36Sopenharmony_ci mlx5_vdpa_handle_completions(mvq, num); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci mlx5_cq_arm(&mvq->cq.mcq, MLX5_CQ_DB_REQ_NOT, uar_page, mvq->cq.mcq.cons_index); 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic int cq_create(struct mlx5_vdpa_net *ndev, u16 idx, u32 num_ent) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq = &ndev->vqs[idx]; 53862306a36Sopenharmony_ci struct mlx5_core_dev *mdev = ndev->mvdev.mdev; 53962306a36Sopenharmony_ci void __iomem *uar_page = ndev->mvdev.res.uar->map; 54062306a36Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(create_cq_out)]; 54162306a36Sopenharmony_ci struct mlx5_vdpa_cq *vcq = &mvq->cq; 54262306a36Sopenharmony_ci __be64 *pas; 54362306a36Sopenharmony_ci int inlen; 54462306a36Sopenharmony_ci void *cqc; 54562306a36Sopenharmony_ci void *in; 54662306a36Sopenharmony_ci int err; 54762306a36Sopenharmony_ci int eqn; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci err = mlx5_db_alloc(mdev, &vcq->db); 55062306a36Sopenharmony_ci if (err) 55162306a36Sopenharmony_ci return err; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci vcq->mcq.set_ci_db = vcq->db.db; 55462306a36Sopenharmony_ci vcq->mcq.arm_db = vcq->db.db + 1; 55562306a36Sopenharmony_ci vcq->mcq.cqe_sz = 64; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci err = cq_frag_buf_alloc(ndev, &vcq->buf, num_ent); 55862306a36Sopenharmony_ci if (err) 55962306a36Sopenharmony_ci goto err_db; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci cq_frag_buf_init(vcq, &vcq->buf); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(create_cq_in) + 56462306a36Sopenharmony_ci MLX5_FLD_SZ_BYTES(create_cq_in, pas[0]) * vcq->buf.frag_buf.npages; 56562306a36Sopenharmony_ci in = kzalloc(inlen, GFP_KERNEL); 56662306a36Sopenharmony_ci if (!in) { 56762306a36Sopenharmony_ci err = -ENOMEM; 56862306a36Sopenharmony_ci goto err_vzalloc; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci MLX5_SET(create_cq_in, in, uid, ndev->mvdev.res.uid); 57262306a36Sopenharmony_ci pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas); 57362306a36Sopenharmony_ci mlx5_fill_page_frag_array(&vcq->buf.frag_buf, pas); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context); 57662306a36Sopenharmony_ci MLX5_SET(cqc, cqc, log_page_size, vcq->buf.frag_buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* Use vector 0 by default. Consider adding code to choose least used 57962306a36Sopenharmony_ci * vector. 58062306a36Sopenharmony_ci */ 58162306a36Sopenharmony_ci err = mlx5_comp_eqn_get(mdev, 0, &eqn); 58262306a36Sopenharmony_ci if (err) 58362306a36Sopenharmony_ci goto err_vec; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context); 58662306a36Sopenharmony_ci MLX5_SET(cqc, cqc, log_cq_size, ilog2(num_ent)); 58762306a36Sopenharmony_ci MLX5_SET(cqc, cqc, uar_page, ndev->mvdev.res.uar->index); 58862306a36Sopenharmony_ci MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn); 58962306a36Sopenharmony_ci MLX5_SET64(cqc, cqc, dbr_addr, vcq->db.dma); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci err = mlx5_core_create_cq(mdev, &vcq->mcq, in, inlen, out, sizeof(out)); 59262306a36Sopenharmony_ci if (err) 59362306a36Sopenharmony_ci goto err_vec; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci vcq->mcq.comp = mlx5_vdpa_cq_comp; 59662306a36Sopenharmony_ci vcq->cqe = num_ent; 59762306a36Sopenharmony_ci vcq->mcq.set_ci_db = vcq->db.db; 59862306a36Sopenharmony_ci vcq->mcq.arm_db = vcq->db.db + 1; 59962306a36Sopenharmony_ci mlx5_cq_arm(&mvq->cq.mcq, MLX5_CQ_DB_REQ_NOT, uar_page, mvq->cq.mcq.cons_index); 60062306a36Sopenharmony_ci kfree(in); 60162306a36Sopenharmony_ci return 0; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cierr_vec: 60462306a36Sopenharmony_ci kfree(in); 60562306a36Sopenharmony_cierr_vzalloc: 60662306a36Sopenharmony_ci cq_frag_buf_free(ndev, &vcq->buf); 60762306a36Sopenharmony_cierr_db: 60862306a36Sopenharmony_ci mlx5_db_free(ndev->mvdev.mdev, &vcq->db); 60962306a36Sopenharmony_ci return err; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic void cq_destroy(struct mlx5_vdpa_net *ndev, u16 idx) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq = &ndev->vqs[idx]; 61562306a36Sopenharmony_ci struct mlx5_core_dev *mdev = ndev->mvdev.mdev; 61662306a36Sopenharmony_ci struct mlx5_vdpa_cq *vcq = &mvq->cq; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci if (mlx5_core_destroy_cq(mdev, &vcq->mcq)) { 61962306a36Sopenharmony_ci mlx5_vdpa_warn(&ndev->mvdev, "destroy CQ 0x%x\n", vcq->mcq.cqn); 62062306a36Sopenharmony_ci return; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci cq_frag_buf_free(ndev, &vcq->buf); 62362306a36Sopenharmony_ci mlx5_db_free(ndev->mvdev.mdev, &vcq->db); 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic int read_umem_params(struct mlx5_vdpa_net *ndev) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; 62962306a36Sopenharmony_ci u16 opmod = (MLX5_CAP_VDPA_EMULATION << 1) | (HCA_CAP_OPMOD_GET_CUR & 0x01); 63062306a36Sopenharmony_ci struct mlx5_core_dev *mdev = ndev->mvdev.mdev; 63162306a36Sopenharmony_ci int out_size; 63262306a36Sopenharmony_ci void *caps; 63362306a36Sopenharmony_ci void *out; 63462306a36Sopenharmony_ci int err; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out); 63762306a36Sopenharmony_ci out = kzalloc(out_size, GFP_KERNEL); 63862306a36Sopenharmony_ci if (!out) 63962306a36Sopenharmony_ci return -ENOMEM; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); 64262306a36Sopenharmony_ci MLX5_SET(query_hca_cap_in, in, op_mod, opmod); 64362306a36Sopenharmony_ci err = mlx5_cmd_exec_inout(mdev, query_hca_cap, in, out); 64462306a36Sopenharmony_ci if (err) { 64562306a36Sopenharmony_ci mlx5_vdpa_warn(&ndev->mvdev, 64662306a36Sopenharmony_ci "Failed reading vdpa umem capabilities with err %d\n", err); 64762306a36Sopenharmony_ci goto out; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci caps = MLX5_ADDR_OF(query_hca_cap_out, out, capability); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci ndev->umem_1_buffer_param_a = MLX5_GET(virtio_emulation_cap, caps, umem_1_buffer_param_a); 65362306a36Sopenharmony_ci ndev->umem_1_buffer_param_b = MLX5_GET(virtio_emulation_cap, caps, umem_1_buffer_param_b); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci ndev->umem_2_buffer_param_a = MLX5_GET(virtio_emulation_cap, caps, umem_2_buffer_param_a); 65662306a36Sopenharmony_ci ndev->umem_2_buffer_param_b = MLX5_GET(virtio_emulation_cap, caps, umem_2_buffer_param_b); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci ndev->umem_3_buffer_param_a = MLX5_GET(virtio_emulation_cap, caps, umem_3_buffer_param_a); 65962306a36Sopenharmony_ci ndev->umem_3_buffer_param_b = MLX5_GET(virtio_emulation_cap, caps, umem_3_buffer_param_b); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ciout: 66262306a36Sopenharmony_ci kfree(out); 66362306a36Sopenharmony_ci return 0; 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic void set_umem_size(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int num, 66762306a36Sopenharmony_ci struct mlx5_vdpa_umem **umemp) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci u32 p_a; 67062306a36Sopenharmony_ci u32 p_b; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci switch (num) { 67362306a36Sopenharmony_ci case 1: 67462306a36Sopenharmony_ci p_a = ndev->umem_1_buffer_param_a; 67562306a36Sopenharmony_ci p_b = ndev->umem_1_buffer_param_b; 67662306a36Sopenharmony_ci *umemp = &mvq->umem1; 67762306a36Sopenharmony_ci break; 67862306a36Sopenharmony_ci case 2: 67962306a36Sopenharmony_ci p_a = ndev->umem_2_buffer_param_a; 68062306a36Sopenharmony_ci p_b = ndev->umem_2_buffer_param_b; 68162306a36Sopenharmony_ci *umemp = &mvq->umem2; 68262306a36Sopenharmony_ci break; 68362306a36Sopenharmony_ci case 3: 68462306a36Sopenharmony_ci p_a = ndev->umem_3_buffer_param_a; 68562306a36Sopenharmony_ci p_b = ndev->umem_3_buffer_param_b; 68662306a36Sopenharmony_ci *umemp = &mvq->umem3; 68762306a36Sopenharmony_ci break; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci (*umemp)->size = p_a * mvq->num_ent + p_b; 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic void umem_frag_buf_free(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_umem *umem) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci mlx5_frag_buf_free(ndev->mvdev.mdev, &umem->frag_buf); 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic int create_umem(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int num) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci int inlen; 70162306a36Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(create_umem_out)] = {}; 70262306a36Sopenharmony_ci void *um; 70362306a36Sopenharmony_ci void *in; 70462306a36Sopenharmony_ci int err; 70562306a36Sopenharmony_ci __be64 *pas; 70662306a36Sopenharmony_ci struct mlx5_vdpa_umem *umem; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci set_umem_size(ndev, mvq, num, &umem); 70962306a36Sopenharmony_ci err = umem_frag_buf_alloc(ndev, umem, umem->size); 71062306a36Sopenharmony_ci if (err) 71162306a36Sopenharmony_ci return err; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(create_umem_in) + MLX5_ST_SZ_BYTES(mtt) * umem->frag_buf.npages; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci in = kzalloc(inlen, GFP_KERNEL); 71662306a36Sopenharmony_ci if (!in) { 71762306a36Sopenharmony_ci err = -ENOMEM; 71862306a36Sopenharmony_ci goto err_in; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci MLX5_SET(create_umem_in, in, opcode, MLX5_CMD_OP_CREATE_UMEM); 72262306a36Sopenharmony_ci MLX5_SET(create_umem_in, in, uid, ndev->mvdev.res.uid); 72362306a36Sopenharmony_ci um = MLX5_ADDR_OF(create_umem_in, in, umem); 72462306a36Sopenharmony_ci MLX5_SET(umem, um, log_page_size, umem->frag_buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); 72562306a36Sopenharmony_ci MLX5_SET64(umem, um, num_of_mtt, umem->frag_buf.npages); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci pas = (__be64 *)MLX5_ADDR_OF(umem, um, mtt[0]); 72862306a36Sopenharmony_ci mlx5_fill_page_frag_array_perm(&umem->frag_buf, pas, MLX5_MTT_PERM_RW); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci err = mlx5_cmd_exec(ndev->mvdev.mdev, in, inlen, out, sizeof(out)); 73162306a36Sopenharmony_ci if (err) { 73262306a36Sopenharmony_ci mlx5_vdpa_warn(&ndev->mvdev, "create umem(%d)\n", err); 73362306a36Sopenharmony_ci goto err_cmd; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci kfree(in); 73762306a36Sopenharmony_ci umem->id = MLX5_GET(create_umem_out, out, umem_id); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci return 0; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cierr_cmd: 74262306a36Sopenharmony_ci kfree(in); 74362306a36Sopenharmony_cierr_in: 74462306a36Sopenharmony_ci umem_frag_buf_free(ndev, umem); 74562306a36Sopenharmony_ci return err; 74662306a36Sopenharmony_ci} 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cistatic void umem_destroy(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int num) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci u32 in[MLX5_ST_SZ_DW(destroy_umem_in)] = {}; 75162306a36Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(destroy_umem_out)] = {}; 75262306a36Sopenharmony_ci struct mlx5_vdpa_umem *umem; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci switch (num) { 75562306a36Sopenharmony_ci case 1: 75662306a36Sopenharmony_ci umem = &mvq->umem1; 75762306a36Sopenharmony_ci break; 75862306a36Sopenharmony_ci case 2: 75962306a36Sopenharmony_ci umem = &mvq->umem2; 76062306a36Sopenharmony_ci break; 76162306a36Sopenharmony_ci case 3: 76262306a36Sopenharmony_ci umem = &mvq->umem3; 76362306a36Sopenharmony_ci break; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci MLX5_SET(destroy_umem_in, in, opcode, MLX5_CMD_OP_DESTROY_UMEM); 76762306a36Sopenharmony_ci MLX5_SET(destroy_umem_in, in, umem_id, umem->id); 76862306a36Sopenharmony_ci if (mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out))) 76962306a36Sopenharmony_ci return; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci umem_frag_buf_free(ndev, umem); 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic int umems_create(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci int num; 77762306a36Sopenharmony_ci int err; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci for (num = 1; num <= 3; num++) { 78062306a36Sopenharmony_ci err = create_umem(ndev, mvq, num); 78162306a36Sopenharmony_ci if (err) 78262306a36Sopenharmony_ci goto err_umem; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci return 0; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cierr_umem: 78762306a36Sopenharmony_ci for (num--; num > 0; num--) 78862306a36Sopenharmony_ci umem_destroy(ndev, mvq, num); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci return err; 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic void umems_destroy(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci int num; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci for (num = 3; num > 0; num--) 79862306a36Sopenharmony_ci umem_destroy(ndev, mvq, num); 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic int get_queue_type(struct mlx5_vdpa_net *ndev) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci u32 type_mask; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci type_mask = MLX5_CAP_DEV_VDPA_EMULATION(ndev->mvdev.mdev, virtio_queue_type); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci /* prefer split queue */ 80862306a36Sopenharmony_ci if (type_mask & MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_SPLIT) 80962306a36Sopenharmony_ci return MLX5_VIRTIO_EMULATION_VIRTIO_QUEUE_TYPE_SPLIT; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci WARN_ON(!(type_mask & MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_PACKED)); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci return MLX5_VIRTIO_EMULATION_VIRTIO_QUEUE_TYPE_PACKED; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cistatic bool vq_is_tx(u16 idx) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci return idx % 2; 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cienum { 82262306a36Sopenharmony_ci MLX5_VIRTIO_NET_F_MRG_RXBUF = 2, 82362306a36Sopenharmony_ci MLX5_VIRTIO_NET_F_HOST_ECN = 4, 82462306a36Sopenharmony_ci MLX5_VIRTIO_NET_F_GUEST_ECN = 6, 82562306a36Sopenharmony_ci MLX5_VIRTIO_NET_F_GUEST_TSO6 = 7, 82662306a36Sopenharmony_ci MLX5_VIRTIO_NET_F_GUEST_TSO4 = 8, 82762306a36Sopenharmony_ci MLX5_VIRTIO_NET_F_GUEST_CSUM = 9, 82862306a36Sopenharmony_ci MLX5_VIRTIO_NET_F_CSUM = 10, 82962306a36Sopenharmony_ci MLX5_VIRTIO_NET_F_HOST_TSO6 = 11, 83062306a36Sopenharmony_ci MLX5_VIRTIO_NET_F_HOST_TSO4 = 12, 83162306a36Sopenharmony_ci}; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cistatic u16 get_features(u64 features) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci return (!!(features & BIT_ULL(VIRTIO_NET_F_MRG_RXBUF)) << MLX5_VIRTIO_NET_F_MRG_RXBUF) | 83662306a36Sopenharmony_ci (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_ECN)) << MLX5_VIRTIO_NET_F_HOST_ECN) | 83762306a36Sopenharmony_ci (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_ECN)) << MLX5_VIRTIO_NET_F_GUEST_ECN) | 83862306a36Sopenharmony_ci (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_TSO6)) << MLX5_VIRTIO_NET_F_GUEST_TSO6) | 83962306a36Sopenharmony_ci (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_TSO4)) << MLX5_VIRTIO_NET_F_GUEST_TSO4) | 84062306a36Sopenharmony_ci (!!(features & BIT_ULL(VIRTIO_NET_F_CSUM)) << MLX5_VIRTIO_NET_F_CSUM) | 84162306a36Sopenharmony_ci (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO6)) << MLX5_VIRTIO_NET_F_HOST_TSO6) | 84262306a36Sopenharmony_ci (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO4)) << MLX5_VIRTIO_NET_F_HOST_TSO4); 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic bool counters_supported(const struct mlx5_vdpa_dev *mvdev) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci return MLX5_CAP_GEN_64(mvdev->mdev, general_obj_types) & 84862306a36Sopenharmony_ci BIT_ULL(MLX5_OBJ_TYPE_VIRTIO_Q_COUNTERS); 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_cistatic bool msix_mode_supported(struct mlx5_vdpa_dev *mvdev) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci return MLX5_CAP_DEV_VDPA_EMULATION(mvdev->mdev, event_mode) & 85462306a36Sopenharmony_ci (1 << MLX5_VIRTIO_Q_EVENT_MODE_MSIX_MODE) && 85562306a36Sopenharmony_ci pci_msix_can_alloc_dyn(mvdev->mdev->pdev); 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci int inlen = MLX5_ST_SZ_BYTES(create_virtio_net_q_in); 86162306a36Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(create_virtio_net_q_out)] = {}; 86262306a36Sopenharmony_ci void *obj_context; 86362306a36Sopenharmony_ci u16 mlx_features; 86462306a36Sopenharmony_ci void *cmd_hdr; 86562306a36Sopenharmony_ci void *vq_ctx; 86662306a36Sopenharmony_ci void *in; 86762306a36Sopenharmony_ci int err; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci err = umems_create(ndev, mvq); 87062306a36Sopenharmony_ci if (err) 87162306a36Sopenharmony_ci return err; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci in = kzalloc(inlen, GFP_KERNEL); 87462306a36Sopenharmony_ci if (!in) { 87562306a36Sopenharmony_ci err = -ENOMEM; 87662306a36Sopenharmony_ci goto err_alloc; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci mlx_features = get_features(ndev->mvdev.actual_features); 88062306a36Sopenharmony_ci cmd_hdr = MLX5_ADDR_OF(create_virtio_net_q_in, in, general_obj_in_cmd_hdr); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); 88362306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_NET_Q); 88462306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci obj_context = MLX5_ADDR_OF(create_virtio_net_q_in, in, obj_context); 88762306a36Sopenharmony_ci MLX5_SET(virtio_net_q_object, obj_context, hw_available_index, mvq->avail_idx); 88862306a36Sopenharmony_ci MLX5_SET(virtio_net_q_object, obj_context, hw_used_index, mvq->used_idx); 88962306a36Sopenharmony_ci MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_12_3, 89062306a36Sopenharmony_ci mlx_features >> 3); 89162306a36Sopenharmony_ci MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_2_0, 89262306a36Sopenharmony_ci mlx_features & 7); 89362306a36Sopenharmony_ci vq_ctx = MLX5_ADDR_OF(virtio_net_q_object, obj_context, virtio_q_context); 89462306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, virtio_q_type, get_queue_type(ndev)); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci if (vq_is_tx(mvq->index)) 89762306a36Sopenharmony_ci MLX5_SET(virtio_net_q_object, obj_context, tisn_or_qpn, ndev->res.tisn); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci if (mvq->map.virq) { 90062306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, event_mode, MLX5_VIRTIO_Q_EVENT_MODE_MSIX_MODE); 90162306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, event_qpn_or_msix, mvq->map.index); 90262306a36Sopenharmony_ci } else { 90362306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, event_mode, MLX5_VIRTIO_Q_EVENT_MODE_QP_MODE); 90462306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, event_qpn_or_msix, mvq->fwqp.mqp.qpn); 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, queue_index, mvq->index); 90862306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, queue_size, mvq->num_ent); 90962306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, virtio_version_1_0, 91062306a36Sopenharmony_ci !!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_F_VERSION_1))); 91162306a36Sopenharmony_ci MLX5_SET64(virtio_q, vq_ctx, desc_addr, mvq->desc_addr); 91262306a36Sopenharmony_ci MLX5_SET64(virtio_q, vq_ctx, used_addr, mvq->device_addr); 91362306a36Sopenharmony_ci MLX5_SET64(virtio_q, vq_ctx, available_addr, mvq->driver_addr); 91462306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, virtio_q_mkey, ndev->mvdev.mr.mkey); 91562306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, umem_1_id, mvq->umem1.id); 91662306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, umem_1_size, mvq->umem1.size); 91762306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, umem_2_id, mvq->umem2.id); 91862306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, umem_2_size, mvq->umem2.size); 91962306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, umem_3_id, mvq->umem3.id); 92062306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, umem_3_size, mvq->umem3.size); 92162306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, pd, ndev->mvdev.res.pdn); 92262306a36Sopenharmony_ci if (counters_supported(&ndev->mvdev)) 92362306a36Sopenharmony_ci MLX5_SET(virtio_q, vq_ctx, counter_set_id, mvq->counter_set_id); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci err = mlx5_cmd_exec(ndev->mvdev.mdev, in, inlen, out, sizeof(out)); 92662306a36Sopenharmony_ci if (err) 92762306a36Sopenharmony_ci goto err_cmd; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci mvq->fw_state = MLX5_VIRTIO_NET_Q_OBJECT_STATE_INIT; 93062306a36Sopenharmony_ci kfree(in); 93162306a36Sopenharmony_ci mvq->virtq_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci return 0; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_cierr_cmd: 93662306a36Sopenharmony_ci kfree(in); 93762306a36Sopenharmony_cierr_alloc: 93862306a36Sopenharmony_ci umems_destroy(ndev, mvq); 93962306a36Sopenharmony_ci return err; 94062306a36Sopenharmony_ci} 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_cistatic void destroy_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci u32 in[MLX5_ST_SZ_DW(destroy_virtio_net_q_in)] = {}; 94562306a36Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(destroy_virtio_net_q_out)] = {}; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci MLX5_SET(destroy_virtio_net_q_in, in, general_obj_out_cmd_hdr.opcode, 94862306a36Sopenharmony_ci MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); 94962306a36Sopenharmony_ci MLX5_SET(destroy_virtio_net_q_in, in, general_obj_out_cmd_hdr.obj_id, mvq->virtq_id); 95062306a36Sopenharmony_ci MLX5_SET(destroy_virtio_net_q_in, in, general_obj_out_cmd_hdr.uid, ndev->mvdev.res.uid); 95162306a36Sopenharmony_ci MLX5_SET(destroy_virtio_net_q_in, in, general_obj_out_cmd_hdr.obj_type, 95262306a36Sopenharmony_ci MLX5_OBJ_TYPE_VIRTIO_NET_Q); 95362306a36Sopenharmony_ci if (mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out))) { 95462306a36Sopenharmony_ci mlx5_vdpa_warn(&ndev->mvdev, "destroy virtqueue 0x%x\n", mvq->virtq_id); 95562306a36Sopenharmony_ci return; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci mvq->fw_state = MLX5_VIRTIO_NET_Q_OBJECT_NONE; 95862306a36Sopenharmony_ci umems_destroy(ndev, mvq); 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic u32 get_rqpn(struct mlx5_vdpa_virtqueue *mvq, bool fw) 96262306a36Sopenharmony_ci{ 96362306a36Sopenharmony_ci return fw ? mvq->vqqp.mqp.qpn : mvq->fwqp.mqp.qpn; 96462306a36Sopenharmony_ci} 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic u32 get_qpn(struct mlx5_vdpa_virtqueue *mvq, bool fw) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci return fw ? mvq->fwqp.mqp.qpn : mvq->vqqp.mqp.qpn; 96962306a36Sopenharmony_ci} 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_cistatic void alloc_inout(struct mlx5_vdpa_net *ndev, int cmd, void **in, int *inlen, void **out, 97262306a36Sopenharmony_ci int *outlen, u32 qpn, u32 rqpn) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci void *qpc; 97562306a36Sopenharmony_ci void *pp; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci switch (cmd) { 97862306a36Sopenharmony_ci case MLX5_CMD_OP_2RST_QP: 97962306a36Sopenharmony_ci *inlen = MLX5_ST_SZ_BYTES(qp_2rst_in); 98062306a36Sopenharmony_ci *outlen = MLX5_ST_SZ_BYTES(qp_2rst_out); 98162306a36Sopenharmony_ci *in = kzalloc(*inlen, GFP_KERNEL); 98262306a36Sopenharmony_ci *out = kzalloc(*outlen, GFP_KERNEL); 98362306a36Sopenharmony_ci if (!*in || !*out) 98462306a36Sopenharmony_ci goto outerr; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci MLX5_SET(qp_2rst_in, *in, opcode, cmd); 98762306a36Sopenharmony_ci MLX5_SET(qp_2rst_in, *in, uid, ndev->mvdev.res.uid); 98862306a36Sopenharmony_ci MLX5_SET(qp_2rst_in, *in, qpn, qpn); 98962306a36Sopenharmony_ci break; 99062306a36Sopenharmony_ci case MLX5_CMD_OP_RST2INIT_QP: 99162306a36Sopenharmony_ci *inlen = MLX5_ST_SZ_BYTES(rst2init_qp_in); 99262306a36Sopenharmony_ci *outlen = MLX5_ST_SZ_BYTES(rst2init_qp_out); 99362306a36Sopenharmony_ci *in = kzalloc(*inlen, GFP_KERNEL); 99462306a36Sopenharmony_ci *out = kzalloc(MLX5_ST_SZ_BYTES(rst2init_qp_out), GFP_KERNEL); 99562306a36Sopenharmony_ci if (!*in || !*out) 99662306a36Sopenharmony_ci goto outerr; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci MLX5_SET(rst2init_qp_in, *in, opcode, cmd); 99962306a36Sopenharmony_ci MLX5_SET(rst2init_qp_in, *in, uid, ndev->mvdev.res.uid); 100062306a36Sopenharmony_ci MLX5_SET(rst2init_qp_in, *in, qpn, qpn); 100162306a36Sopenharmony_ci qpc = MLX5_ADDR_OF(rst2init_qp_in, *in, qpc); 100262306a36Sopenharmony_ci MLX5_SET(qpc, qpc, remote_qpn, rqpn); 100362306a36Sopenharmony_ci MLX5_SET(qpc, qpc, rwe, 1); 100462306a36Sopenharmony_ci pp = MLX5_ADDR_OF(qpc, qpc, primary_address_path); 100562306a36Sopenharmony_ci MLX5_SET(ads, pp, vhca_port_num, 1); 100662306a36Sopenharmony_ci break; 100762306a36Sopenharmony_ci case MLX5_CMD_OP_INIT2RTR_QP: 100862306a36Sopenharmony_ci *inlen = MLX5_ST_SZ_BYTES(init2rtr_qp_in); 100962306a36Sopenharmony_ci *outlen = MLX5_ST_SZ_BYTES(init2rtr_qp_out); 101062306a36Sopenharmony_ci *in = kzalloc(*inlen, GFP_KERNEL); 101162306a36Sopenharmony_ci *out = kzalloc(MLX5_ST_SZ_BYTES(init2rtr_qp_out), GFP_KERNEL); 101262306a36Sopenharmony_ci if (!*in || !*out) 101362306a36Sopenharmony_ci goto outerr; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci MLX5_SET(init2rtr_qp_in, *in, opcode, cmd); 101662306a36Sopenharmony_ci MLX5_SET(init2rtr_qp_in, *in, uid, ndev->mvdev.res.uid); 101762306a36Sopenharmony_ci MLX5_SET(init2rtr_qp_in, *in, qpn, qpn); 101862306a36Sopenharmony_ci qpc = MLX5_ADDR_OF(rst2init_qp_in, *in, qpc); 101962306a36Sopenharmony_ci MLX5_SET(qpc, qpc, mtu, MLX5_QPC_MTU_256_BYTES); 102062306a36Sopenharmony_ci MLX5_SET(qpc, qpc, log_msg_max, 30); 102162306a36Sopenharmony_ci MLX5_SET(qpc, qpc, remote_qpn, rqpn); 102262306a36Sopenharmony_ci pp = MLX5_ADDR_OF(qpc, qpc, primary_address_path); 102362306a36Sopenharmony_ci MLX5_SET(ads, pp, fl, 1); 102462306a36Sopenharmony_ci break; 102562306a36Sopenharmony_ci case MLX5_CMD_OP_RTR2RTS_QP: 102662306a36Sopenharmony_ci *inlen = MLX5_ST_SZ_BYTES(rtr2rts_qp_in); 102762306a36Sopenharmony_ci *outlen = MLX5_ST_SZ_BYTES(rtr2rts_qp_out); 102862306a36Sopenharmony_ci *in = kzalloc(*inlen, GFP_KERNEL); 102962306a36Sopenharmony_ci *out = kzalloc(MLX5_ST_SZ_BYTES(rtr2rts_qp_out), GFP_KERNEL); 103062306a36Sopenharmony_ci if (!*in || !*out) 103162306a36Sopenharmony_ci goto outerr; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci MLX5_SET(rtr2rts_qp_in, *in, opcode, cmd); 103462306a36Sopenharmony_ci MLX5_SET(rtr2rts_qp_in, *in, uid, ndev->mvdev.res.uid); 103562306a36Sopenharmony_ci MLX5_SET(rtr2rts_qp_in, *in, qpn, qpn); 103662306a36Sopenharmony_ci qpc = MLX5_ADDR_OF(rst2init_qp_in, *in, qpc); 103762306a36Sopenharmony_ci pp = MLX5_ADDR_OF(qpc, qpc, primary_address_path); 103862306a36Sopenharmony_ci MLX5_SET(ads, pp, ack_timeout, 14); 103962306a36Sopenharmony_ci MLX5_SET(qpc, qpc, retry_count, 7); 104062306a36Sopenharmony_ci MLX5_SET(qpc, qpc, rnr_retry, 7); 104162306a36Sopenharmony_ci break; 104262306a36Sopenharmony_ci default: 104362306a36Sopenharmony_ci goto outerr_nullify; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci return; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ciouterr: 104962306a36Sopenharmony_ci kfree(*in); 105062306a36Sopenharmony_ci kfree(*out); 105162306a36Sopenharmony_ciouterr_nullify: 105262306a36Sopenharmony_ci *in = NULL; 105362306a36Sopenharmony_ci *out = NULL; 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_cistatic void free_inout(void *in, void *out) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci kfree(in); 105962306a36Sopenharmony_ci kfree(out); 106062306a36Sopenharmony_ci} 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci/* Two QPs are used by each virtqueue. One is used by the driver and one by 106362306a36Sopenharmony_ci * firmware. The fw argument indicates whether the subjected QP is the one used 106462306a36Sopenharmony_ci * by firmware. 106562306a36Sopenharmony_ci */ 106662306a36Sopenharmony_cistatic int modify_qp(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, bool fw, int cmd) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci int outlen; 106962306a36Sopenharmony_ci int inlen; 107062306a36Sopenharmony_ci void *out; 107162306a36Sopenharmony_ci void *in; 107262306a36Sopenharmony_ci int err; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci alloc_inout(ndev, cmd, &in, &inlen, &out, &outlen, get_qpn(mvq, fw), get_rqpn(mvq, fw)); 107562306a36Sopenharmony_ci if (!in || !out) 107662306a36Sopenharmony_ci return -ENOMEM; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci err = mlx5_cmd_exec(ndev->mvdev.mdev, in, inlen, out, outlen); 107962306a36Sopenharmony_ci free_inout(in, out); 108062306a36Sopenharmony_ci return err; 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_cistatic int connect_qps(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 108462306a36Sopenharmony_ci{ 108562306a36Sopenharmony_ci int err; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci err = modify_qp(ndev, mvq, true, MLX5_CMD_OP_2RST_QP); 108862306a36Sopenharmony_ci if (err) 108962306a36Sopenharmony_ci return err; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci err = modify_qp(ndev, mvq, false, MLX5_CMD_OP_2RST_QP); 109262306a36Sopenharmony_ci if (err) 109362306a36Sopenharmony_ci return err; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci err = modify_qp(ndev, mvq, true, MLX5_CMD_OP_RST2INIT_QP); 109662306a36Sopenharmony_ci if (err) 109762306a36Sopenharmony_ci return err; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci err = modify_qp(ndev, mvq, false, MLX5_CMD_OP_RST2INIT_QP); 110062306a36Sopenharmony_ci if (err) 110162306a36Sopenharmony_ci return err; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci err = modify_qp(ndev, mvq, true, MLX5_CMD_OP_INIT2RTR_QP); 110462306a36Sopenharmony_ci if (err) 110562306a36Sopenharmony_ci return err; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci err = modify_qp(ndev, mvq, false, MLX5_CMD_OP_INIT2RTR_QP); 110862306a36Sopenharmony_ci if (err) 110962306a36Sopenharmony_ci return err; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci return modify_qp(ndev, mvq, true, MLX5_CMD_OP_RTR2RTS_QP); 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cistruct mlx5_virtq_attr { 111562306a36Sopenharmony_ci u8 state; 111662306a36Sopenharmony_ci u16 available_index; 111762306a36Sopenharmony_ci u16 used_index; 111862306a36Sopenharmony_ci}; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cistatic int query_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, 112162306a36Sopenharmony_ci struct mlx5_virtq_attr *attr) 112262306a36Sopenharmony_ci{ 112362306a36Sopenharmony_ci int outlen = MLX5_ST_SZ_BYTES(query_virtio_net_q_out); 112462306a36Sopenharmony_ci u32 in[MLX5_ST_SZ_DW(query_virtio_net_q_in)] = {}; 112562306a36Sopenharmony_ci void *out; 112662306a36Sopenharmony_ci void *obj_context; 112762306a36Sopenharmony_ci void *cmd_hdr; 112862306a36Sopenharmony_ci int err; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci out = kzalloc(outlen, GFP_KERNEL); 113162306a36Sopenharmony_ci if (!out) 113262306a36Sopenharmony_ci return -ENOMEM; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci cmd_hdr = MLX5_ADDR_OF(query_virtio_net_q_in, in, general_obj_in_cmd_hdr); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_QUERY_GENERAL_OBJECT); 113762306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_NET_Q); 113862306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_id, mvq->virtq_id); 113962306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 114062306a36Sopenharmony_ci err = mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, outlen); 114162306a36Sopenharmony_ci if (err) 114262306a36Sopenharmony_ci goto err_cmd; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci obj_context = MLX5_ADDR_OF(query_virtio_net_q_out, out, obj_context); 114562306a36Sopenharmony_ci memset(attr, 0, sizeof(*attr)); 114662306a36Sopenharmony_ci attr->state = MLX5_GET(virtio_net_q_object, obj_context, state); 114762306a36Sopenharmony_ci attr->available_index = MLX5_GET(virtio_net_q_object, obj_context, hw_available_index); 114862306a36Sopenharmony_ci attr->used_index = MLX5_GET(virtio_net_q_object, obj_context, hw_used_index); 114962306a36Sopenharmony_ci kfree(out); 115062306a36Sopenharmony_ci return 0; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_cierr_cmd: 115362306a36Sopenharmony_ci kfree(out); 115462306a36Sopenharmony_ci return err; 115562306a36Sopenharmony_ci} 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_cistatic bool is_valid_state_change(int oldstate, int newstate) 115862306a36Sopenharmony_ci{ 115962306a36Sopenharmony_ci switch (oldstate) { 116062306a36Sopenharmony_ci case MLX5_VIRTIO_NET_Q_OBJECT_STATE_INIT: 116162306a36Sopenharmony_ci return newstate == MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY; 116262306a36Sopenharmony_ci case MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY: 116362306a36Sopenharmony_ci return newstate == MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND; 116462306a36Sopenharmony_ci case MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND: 116562306a36Sopenharmony_ci case MLX5_VIRTIO_NET_Q_OBJECT_STATE_ERR: 116662306a36Sopenharmony_ci default: 116762306a36Sopenharmony_ci return false; 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_cistatic int modify_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int state) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci int inlen = MLX5_ST_SZ_BYTES(modify_virtio_net_q_in); 117462306a36Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(modify_virtio_net_q_out)] = {}; 117562306a36Sopenharmony_ci void *obj_context; 117662306a36Sopenharmony_ci void *cmd_hdr; 117762306a36Sopenharmony_ci void *in; 117862306a36Sopenharmony_ci int err; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci if (mvq->fw_state == MLX5_VIRTIO_NET_Q_OBJECT_NONE) 118162306a36Sopenharmony_ci return 0; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci if (!is_valid_state_change(mvq->fw_state, state)) 118462306a36Sopenharmony_ci return -EINVAL; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci in = kzalloc(inlen, GFP_KERNEL); 118762306a36Sopenharmony_ci if (!in) 118862306a36Sopenharmony_ci return -ENOMEM; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci cmd_hdr = MLX5_ADDR_OF(modify_virtio_net_q_in, in, general_obj_in_cmd_hdr); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_MODIFY_GENERAL_OBJECT); 119362306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_NET_Q); 119462306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_id, mvq->virtq_id); 119562306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci obj_context = MLX5_ADDR_OF(modify_virtio_net_q_in, in, obj_context); 119862306a36Sopenharmony_ci MLX5_SET64(virtio_net_q_object, obj_context, modify_field_select, 119962306a36Sopenharmony_ci MLX5_VIRTQ_MODIFY_MASK_STATE); 120062306a36Sopenharmony_ci MLX5_SET(virtio_net_q_object, obj_context, state, state); 120162306a36Sopenharmony_ci err = mlx5_cmd_exec(ndev->mvdev.mdev, in, inlen, out, sizeof(out)); 120262306a36Sopenharmony_ci kfree(in); 120362306a36Sopenharmony_ci if (!err) 120462306a36Sopenharmony_ci mvq->fw_state = state; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci return err; 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_cistatic int counter_set_alloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 121062306a36Sopenharmony_ci{ 121162306a36Sopenharmony_ci u32 in[MLX5_ST_SZ_DW(create_virtio_q_counters_in)] = {}; 121262306a36Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(create_virtio_q_counters_out)] = {}; 121362306a36Sopenharmony_ci void *cmd_hdr; 121462306a36Sopenharmony_ci int err; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci if (!counters_supported(&ndev->mvdev)) 121762306a36Sopenharmony_ci return 0; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci cmd_hdr = MLX5_ADDR_OF(create_virtio_q_counters_in, in, hdr); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); 122262306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_Q_COUNTERS); 122362306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci err = mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out)); 122662306a36Sopenharmony_ci if (err) 122762306a36Sopenharmony_ci return err; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci mvq->counter_set_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci return 0; 123262306a36Sopenharmony_ci} 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_cistatic void counter_set_dealloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 123562306a36Sopenharmony_ci{ 123662306a36Sopenharmony_ci u32 in[MLX5_ST_SZ_DW(destroy_virtio_q_counters_in)] = {}; 123762306a36Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(destroy_virtio_q_counters_out)] = {}; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci if (!counters_supported(&ndev->mvdev)) 124062306a36Sopenharmony_ci return; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci MLX5_SET(destroy_virtio_q_counters_in, in, hdr.opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); 124362306a36Sopenharmony_ci MLX5_SET(destroy_virtio_q_counters_in, in, hdr.obj_id, mvq->counter_set_id); 124462306a36Sopenharmony_ci MLX5_SET(destroy_virtio_q_counters_in, in, hdr.uid, ndev->mvdev.res.uid); 124562306a36Sopenharmony_ci MLX5_SET(destroy_virtio_q_counters_in, in, hdr.obj_type, MLX5_OBJ_TYPE_VIRTIO_Q_COUNTERS); 124662306a36Sopenharmony_ci if (mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out))) 124762306a36Sopenharmony_ci mlx5_vdpa_warn(&ndev->mvdev, "dealloc counter set 0x%x\n", mvq->counter_set_id); 124862306a36Sopenharmony_ci} 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_cistatic irqreturn_t mlx5_vdpa_int_handler(int irq, void *priv) 125162306a36Sopenharmony_ci{ 125262306a36Sopenharmony_ci struct vdpa_callback *cb = priv; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci if (cb->callback) 125562306a36Sopenharmony_ci return cb->callback(cb->private); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci return IRQ_HANDLED; 125862306a36Sopenharmony_ci} 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_cistatic void alloc_vector(struct mlx5_vdpa_net *ndev, 126162306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq) 126262306a36Sopenharmony_ci{ 126362306a36Sopenharmony_ci struct mlx5_vdpa_irq_pool *irqp = &ndev->irqp; 126462306a36Sopenharmony_ci struct mlx5_vdpa_irq_pool_entry *ent; 126562306a36Sopenharmony_ci int err; 126662306a36Sopenharmony_ci int i; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci for (i = 0; i < irqp->num_ent; i++) { 126962306a36Sopenharmony_ci ent = &irqp->entries[i]; 127062306a36Sopenharmony_ci if (!ent->used) { 127162306a36Sopenharmony_ci snprintf(ent->name, MLX5_VDPA_IRQ_NAME_LEN, "%s-vq-%d", 127262306a36Sopenharmony_ci dev_name(&ndev->mvdev.vdev.dev), mvq->index); 127362306a36Sopenharmony_ci ent->dev_id = &ndev->event_cbs[mvq->index]; 127462306a36Sopenharmony_ci err = request_irq(ent->map.virq, mlx5_vdpa_int_handler, 0, 127562306a36Sopenharmony_ci ent->name, ent->dev_id); 127662306a36Sopenharmony_ci if (err) 127762306a36Sopenharmony_ci return; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci ent->used = true; 128062306a36Sopenharmony_ci mvq->map = ent->map; 128162306a36Sopenharmony_ci return; 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci} 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_cistatic void dealloc_vector(struct mlx5_vdpa_net *ndev, 128762306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq) 128862306a36Sopenharmony_ci{ 128962306a36Sopenharmony_ci struct mlx5_vdpa_irq_pool *irqp = &ndev->irqp; 129062306a36Sopenharmony_ci int i; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci for (i = 0; i < irqp->num_ent; i++) 129362306a36Sopenharmony_ci if (mvq->map.virq == irqp->entries[i].map.virq) { 129462306a36Sopenharmony_ci free_irq(mvq->map.virq, irqp->entries[i].dev_id); 129562306a36Sopenharmony_ci irqp->entries[i].used = false; 129662306a36Sopenharmony_ci return; 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic int setup_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci u16 idx = mvq->index; 130362306a36Sopenharmony_ci int err; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci if (!mvq->num_ent) 130662306a36Sopenharmony_ci return 0; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci if (mvq->initialized) 130962306a36Sopenharmony_ci return 0; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci err = cq_create(ndev, idx, mvq->num_ent); 131262306a36Sopenharmony_ci if (err) 131362306a36Sopenharmony_ci return err; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci err = qp_create(ndev, mvq, &mvq->fwqp); 131662306a36Sopenharmony_ci if (err) 131762306a36Sopenharmony_ci goto err_fwqp; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci err = qp_create(ndev, mvq, &mvq->vqqp); 132062306a36Sopenharmony_ci if (err) 132162306a36Sopenharmony_ci goto err_vqqp; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci err = connect_qps(ndev, mvq); 132462306a36Sopenharmony_ci if (err) 132562306a36Sopenharmony_ci goto err_connect; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci err = counter_set_alloc(ndev, mvq); 132862306a36Sopenharmony_ci if (err) 132962306a36Sopenharmony_ci goto err_connect; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci alloc_vector(ndev, mvq); 133262306a36Sopenharmony_ci err = create_virtqueue(ndev, mvq); 133362306a36Sopenharmony_ci if (err) 133462306a36Sopenharmony_ci goto err_vq; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci if (mvq->ready) { 133762306a36Sopenharmony_ci err = modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY); 133862306a36Sopenharmony_ci if (err) { 133962306a36Sopenharmony_ci mlx5_vdpa_warn(&ndev->mvdev, "failed to modify to ready vq idx %d(%d)\n", 134062306a36Sopenharmony_ci idx, err); 134162306a36Sopenharmony_ci goto err_modify; 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci mvq->initialized = true; 134662306a36Sopenharmony_ci return 0; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_cierr_modify: 134962306a36Sopenharmony_ci destroy_virtqueue(ndev, mvq); 135062306a36Sopenharmony_cierr_vq: 135162306a36Sopenharmony_ci dealloc_vector(ndev, mvq); 135262306a36Sopenharmony_ci counter_set_dealloc(ndev, mvq); 135362306a36Sopenharmony_cierr_connect: 135462306a36Sopenharmony_ci qp_destroy(ndev, &mvq->vqqp); 135562306a36Sopenharmony_cierr_vqqp: 135662306a36Sopenharmony_ci qp_destroy(ndev, &mvq->fwqp); 135762306a36Sopenharmony_cierr_fwqp: 135862306a36Sopenharmony_ci cq_destroy(ndev, idx); 135962306a36Sopenharmony_ci return err; 136062306a36Sopenharmony_ci} 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_cistatic void suspend_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 136362306a36Sopenharmony_ci{ 136462306a36Sopenharmony_ci struct mlx5_virtq_attr attr; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci if (!mvq->initialized) 136762306a36Sopenharmony_ci return; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY) 137062306a36Sopenharmony_ci return; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci if (modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND)) 137362306a36Sopenharmony_ci mlx5_vdpa_warn(&ndev->mvdev, "modify to suspend failed\n"); 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci if (query_virtqueue(ndev, mvq, &attr)) { 137662306a36Sopenharmony_ci mlx5_vdpa_warn(&ndev->mvdev, "failed to query virtqueue\n"); 137762306a36Sopenharmony_ci return; 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci mvq->avail_idx = attr.available_index; 138062306a36Sopenharmony_ci mvq->used_idx = attr.used_index; 138162306a36Sopenharmony_ci} 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_cistatic void suspend_vqs(struct mlx5_vdpa_net *ndev) 138462306a36Sopenharmony_ci{ 138562306a36Sopenharmony_ci int i; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci for (i = 0; i < ndev->mvdev.max_vqs; i++) 138862306a36Sopenharmony_ci suspend_vq(ndev, &ndev->vqs[i]); 138962306a36Sopenharmony_ci} 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_cistatic void teardown_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 139262306a36Sopenharmony_ci{ 139362306a36Sopenharmony_ci if (!mvq->initialized) 139462306a36Sopenharmony_ci return; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci suspend_vq(ndev, mvq); 139762306a36Sopenharmony_ci destroy_virtqueue(ndev, mvq); 139862306a36Sopenharmony_ci dealloc_vector(ndev, mvq); 139962306a36Sopenharmony_ci counter_set_dealloc(ndev, mvq); 140062306a36Sopenharmony_ci qp_destroy(ndev, &mvq->vqqp); 140162306a36Sopenharmony_ci qp_destroy(ndev, &mvq->fwqp); 140262306a36Sopenharmony_ci cq_destroy(ndev, mvq->index); 140362306a36Sopenharmony_ci mvq->initialized = false; 140462306a36Sopenharmony_ci} 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_cistatic int create_rqt(struct mlx5_vdpa_net *ndev) 140762306a36Sopenharmony_ci{ 140862306a36Sopenharmony_ci int rqt_table_size = roundup_pow_of_two(ndev->rqt_size); 140962306a36Sopenharmony_ci int act_sz = roundup_pow_of_two(ndev->cur_num_vqs / 2); 141062306a36Sopenharmony_ci __be32 *list; 141162306a36Sopenharmony_ci void *rqtc; 141262306a36Sopenharmony_ci int inlen; 141362306a36Sopenharmony_ci void *in; 141462306a36Sopenharmony_ci int i, j; 141562306a36Sopenharmony_ci int err; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + rqt_table_size * MLX5_ST_SZ_BYTES(rq_num); 141862306a36Sopenharmony_ci in = kzalloc(inlen, GFP_KERNEL); 141962306a36Sopenharmony_ci if (!in) 142062306a36Sopenharmony_ci return -ENOMEM; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci MLX5_SET(create_rqt_in, in, uid, ndev->mvdev.res.uid); 142362306a36Sopenharmony_ci rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci MLX5_SET(rqtc, rqtc, list_q_type, MLX5_RQTC_LIST_Q_TYPE_VIRTIO_NET_Q); 142662306a36Sopenharmony_ci MLX5_SET(rqtc, rqtc, rqt_max_size, rqt_table_size); 142762306a36Sopenharmony_ci list = MLX5_ADDR_OF(rqtc, rqtc, rq_num[0]); 142862306a36Sopenharmony_ci for (i = 0, j = 0; i < act_sz; i++, j += 2) 142962306a36Sopenharmony_ci list[i] = cpu_to_be32(ndev->vqs[j % ndev->cur_num_vqs].virtq_id); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci MLX5_SET(rqtc, rqtc, rqt_actual_size, act_sz); 143262306a36Sopenharmony_ci err = mlx5_vdpa_create_rqt(&ndev->mvdev, in, inlen, &ndev->res.rqtn); 143362306a36Sopenharmony_ci kfree(in); 143462306a36Sopenharmony_ci if (err) 143562306a36Sopenharmony_ci return err; 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci return 0; 143862306a36Sopenharmony_ci} 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci#define MLX5_MODIFY_RQT_NUM_RQS ((u64)1) 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_cistatic int modify_rqt(struct mlx5_vdpa_net *ndev, int num) 144362306a36Sopenharmony_ci{ 144462306a36Sopenharmony_ci int act_sz = roundup_pow_of_two(num / 2); 144562306a36Sopenharmony_ci __be32 *list; 144662306a36Sopenharmony_ci void *rqtc; 144762306a36Sopenharmony_ci int inlen; 144862306a36Sopenharmony_ci void *in; 144962306a36Sopenharmony_ci int i, j; 145062306a36Sopenharmony_ci int err; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(modify_rqt_in) + act_sz * MLX5_ST_SZ_BYTES(rq_num); 145362306a36Sopenharmony_ci in = kzalloc(inlen, GFP_KERNEL); 145462306a36Sopenharmony_ci if (!in) 145562306a36Sopenharmony_ci return -ENOMEM; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci MLX5_SET(modify_rqt_in, in, uid, ndev->mvdev.res.uid); 145862306a36Sopenharmony_ci MLX5_SET64(modify_rqt_in, in, bitmask, MLX5_MODIFY_RQT_NUM_RQS); 145962306a36Sopenharmony_ci rqtc = MLX5_ADDR_OF(modify_rqt_in, in, ctx); 146062306a36Sopenharmony_ci MLX5_SET(rqtc, rqtc, list_q_type, MLX5_RQTC_LIST_Q_TYPE_VIRTIO_NET_Q); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci list = MLX5_ADDR_OF(rqtc, rqtc, rq_num[0]); 146362306a36Sopenharmony_ci for (i = 0, j = 0; i < act_sz; i++, j = j + 2) 146462306a36Sopenharmony_ci list[i] = cpu_to_be32(ndev->vqs[j % num].virtq_id); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci MLX5_SET(rqtc, rqtc, rqt_actual_size, act_sz); 146762306a36Sopenharmony_ci err = mlx5_vdpa_modify_rqt(&ndev->mvdev, in, inlen, ndev->res.rqtn); 146862306a36Sopenharmony_ci kfree(in); 146962306a36Sopenharmony_ci if (err) 147062306a36Sopenharmony_ci return err; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci return 0; 147362306a36Sopenharmony_ci} 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_cistatic void destroy_rqt(struct mlx5_vdpa_net *ndev) 147662306a36Sopenharmony_ci{ 147762306a36Sopenharmony_ci mlx5_vdpa_destroy_rqt(&ndev->mvdev, ndev->res.rqtn); 147862306a36Sopenharmony_ci} 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_cistatic int create_tir(struct mlx5_vdpa_net *ndev) 148162306a36Sopenharmony_ci{ 148262306a36Sopenharmony_ci#define HASH_IP_L4PORTS \ 148362306a36Sopenharmony_ci (MLX5_HASH_FIELD_SEL_SRC_IP | MLX5_HASH_FIELD_SEL_DST_IP | MLX5_HASH_FIELD_SEL_L4_SPORT | \ 148462306a36Sopenharmony_ci MLX5_HASH_FIELD_SEL_L4_DPORT) 148562306a36Sopenharmony_ci static const u8 rx_hash_toeplitz_key[] = { 0x2c, 0xc6, 0x81, 0xd1, 0x5b, 0xdb, 0xf4, 0xf7, 148662306a36Sopenharmony_ci 0xfc, 0xa2, 0x83, 0x19, 0xdb, 0x1a, 0x3e, 0x94, 148762306a36Sopenharmony_ci 0x6b, 0x9e, 0x38, 0xd9, 0x2c, 0x9c, 0x03, 0xd1, 148862306a36Sopenharmony_ci 0xad, 0x99, 0x44, 0xa7, 0xd9, 0x56, 0x3d, 0x59, 148962306a36Sopenharmony_ci 0x06, 0x3c, 0x25, 0xf3, 0xfc, 0x1f, 0xdc, 0x2a }; 149062306a36Sopenharmony_ci void *rss_key; 149162306a36Sopenharmony_ci void *outer; 149262306a36Sopenharmony_ci void *tirc; 149362306a36Sopenharmony_ci void *in; 149462306a36Sopenharmony_ci int err; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci in = kzalloc(MLX5_ST_SZ_BYTES(create_tir_in), GFP_KERNEL); 149762306a36Sopenharmony_ci if (!in) 149862306a36Sopenharmony_ci return -ENOMEM; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci MLX5_SET(create_tir_in, in, uid, ndev->mvdev.res.uid); 150162306a36Sopenharmony_ci tirc = MLX5_ADDR_OF(create_tir_in, in, ctx); 150262306a36Sopenharmony_ci MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_INDIRECT); 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci MLX5_SET(tirc, tirc, rx_hash_symmetric, 1); 150562306a36Sopenharmony_ci MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_TOEPLITZ); 150662306a36Sopenharmony_ci rss_key = MLX5_ADDR_OF(tirc, tirc, rx_hash_toeplitz_key); 150762306a36Sopenharmony_ci memcpy(rss_key, rx_hash_toeplitz_key, sizeof(rx_hash_toeplitz_key)); 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci outer = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer); 151062306a36Sopenharmony_ci MLX5_SET(rx_hash_field_select, outer, l3_prot_type, MLX5_L3_PROT_TYPE_IPV4); 151162306a36Sopenharmony_ci MLX5_SET(rx_hash_field_select, outer, l4_prot_type, MLX5_L4_PROT_TYPE_TCP); 151262306a36Sopenharmony_ci MLX5_SET(rx_hash_field_select, outer, selected_fields, HASH_IP_L4PORTS); 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci MLX5_SET(tirc, tirc, indirect_table, ndev->res.rqtn); 151562306a36Sopenharmony_ci MLX5_SET(tirc, tirc, transport_domain, ndev->res.tdn); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci err = mlx5_vdpa_create_tir(&ndev->mvdev, in, &ndev->res.tirn); 151862306a36Sopenharmony_ci kfree(in); 151962306a36Sopenharmony_ci if (err) 152062306a36Sopenharmony_ci return err; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci mlx5_vdpa_add_tirn(ndev); 152362306a36Sopenharmony_ci return err; 152462306a36Sopenharmony_ci} 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_cistatic void destroy_tir(struct mlx5_vdpa_net *ndev) 152762306a36Sopenharmony_ci{ 152862306a36Sopenharmony_ci mlx5_vdpa_remove_tirn(ndev); 152962306a36Sopenharmony_ci mlx5_vdpa_destroy_tir(&ndev->mvdev, ndev->res.tirn); 153062306a36Sopenharmony_ci} 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci#define MAX_STEERING_ENT 0x8000 153362306a36Sopenharmony_ci#define MAX_STEERING_GROUPS 2 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci#if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 153662306a36Sopenharmony_ci #define NUM_DESTS 2 153762306a36Sopenharmony_ci#else 153862306a36Sopenharmony_ci #define NUM_DESTS 1 153962306a36Sopenharmony_ci#endif 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_cistatic int add_steering_counters(struct mlx5_vdpa_net *ndev, 154262306a36Sopenharmony_ci struct macvlan_node *node, 154362306a36Sopenharmony_ci struct mlx5_flow_act *flow_act, 154462306a36Sopenharmony_ci struct mlx5_flow_destination *dests) 154562306a36Sopenharmony_ci{ 154662306a36Sopenharmony_ci#if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 154762306a36Sopenharmony_ci int err; 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci node->ucast_counter.counter = mlx5_fc_create(ndev->mvdev.mdev, false); 155062306a36Sopenharmony_ci if (IS_ERR(node->ucast_counter.counter)) 155162306a36Sopenharmony_ci return PTR_ERR(node->ucast_counter.counter); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci node->mcast_counter.counter = mlx5_fc_create(ndev->mvdev.mdev, false); 155462306a36Sopenharmony_ci if (IS_ERR(node->mcast_counter.counter)) { 155562306a36Sopenharmony_ci err = PTR_ERR(node->mcast_counter.counter); 155662306a36Sopenharmony_ci goto err_mcast_counter; 155762306a36Sopenharmony_ci } 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci dests[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 156062306a36Sopenharmony_ci flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; 156162306a36Sopenharmony_ci return 0; 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_cierr_mcast_counter: 156462306a36Sopenharmony_ci mlx5_fc_destroy(ndev->mvdev.mdev, node->ucast_counter.counter); 156562306a36Sopenharmony_ci return err; 156662306a36Sopenharmony_ci#else 156762306a36Sopenharmony_ci return 0; 156862306a36Sopenharmony_ci#endif 156962306a36Sopenharmony_ci} 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_cistatic void remove_steering_counters(struct mlx5_vdpa_net *ndev, 157262306a36Sopenharmony_ci struct macvlan_node *node) 157362306a36Sopenharmony_ci{ 157462306a36Sopenharmony_ci#if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 157562306a36Sopenharmony_ci mlx5_fc_destroy(ndev->mvdev.mdev, node->mcast_counter.counter); 157662306a36Sopenharmony_ci mlx5_fc_destroy(ndev->mvdev.mdev, node->ucast_counter.counter); 157762306a36Sopenharmony_ci#endif 157862306a36Sopenharmony_ci} 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_cistatic int mlx5_vdpa_add_mac_vlan_rules(struct mlx5_vdpa_net *ndev, u8 *mac, 158162306a36Sopenharmony_ci struct macvlan_node *node) 158262306a36Sopenharmony_ci{ 158362306a36Sopenharmony_ci struct mlx5_flow_destination dests[NUM_DESTS] = {}; 158462306a36Sopenharmony_ci struct mlx5_flow_act flow_act = {}; 158562306a36Sopenharmony_ci struct mlx5_flow_spec *spec; 158662306a36Sopenharmony_ci void *headers_c; 158762306a36Sopenharmony_ci void *headers_v; 158862306a36Sopenharmony_ci u8 *dmac_c; 158962306a36Sopenharmony_ci u8 *dmac_v; 159062306a36Sopenharmony_ci int err; 159162306a36Sopenharmony_ci u16 vid; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci spec = kvzalloc(sizeof(*spec), GFP_KERNEL); 159462306a36Sopenharmony_ci if (!spec) 159562306a36Sopenharmony_ci return -ENOMEM; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci vid = key2vid(node->macvlan); 159862306a36Sopenharmony_ci spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 159962306a36Sopenharmony_ci headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, outer_headers); 160062306a36Sopenharmony_ci headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers); 160162306a36Sopenharmony_ci dmac_c = MLX5_ADDR_OF(fte_match_param, headers_c, outer_headers.dmac_47_16); 160262306a36Sopenharmony_ci dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v, outer_headers.dmac_47_16); 160362306a36Sopenharmony_ci eth_broadcast_addr(dmac_c); 160462306a36Sopenharmony_ci ether_addr_copy(dmac_v, mac); 160562306a36Sopenharmony_ci if (ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VLAN)) { 160662306a36Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_c, cvlan_tag, 1); 160762306a36Sopenharmony_ci MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, first_vid); 160862306a36Sopenharmony_ci } 160962306a36Sopenharmony_ci if (node->tagged) { 161062306a36Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, cvlan_tag, 1); 161162306a36Sopenharmony_ci MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, vid); 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 161462306a36Sopenharmony_ci dests[0].type = MLX5_FLOW_DESTINATION_TYPE_TIR; 161562306a36Sopenharmony_ci dests[0].tir_num = ndev->res.tirn; 161662306a36Sopenharmony_ci err = add_steering_counters(ndev, node, &flow_act, dests); 161762306a36Sopenharmony_ci if (err) 161862306a36Sopenharmony_ci goto out_free; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci#if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 162162306a36Sopenharmony_ci dests[1].counter_id = mlx5_fc_id(node->ucast_counter.counter); 162262306a36Sopenharmony_ci#endif 162362306a36Sopenharmony_ci node->ucast_rule = mlx5_add_flow_rules(ndev->rxft, spec, &flow_act, dests, NUM_DESTS); 162462306a36Sopenharmony_ci if (IS_ERR(node->ucast_rule)) { 162562306a36Sopenharmony_ci err = PTR_ERR(node->ucast_rule); 162662306a36Sopenharmony_ci goto err_ucast; 162762306a36Sopenharmony_ci } 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci#if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 163062306a36Sopenharmony_ci dests[1].counter_id = mlx5_fc_id(node->mcast_counter.counter); 163162306a36Sopenharmony_ci#endif 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci memset(dmac_c, 0, ETH_ALEN); 163462306a36Sopenharmony_ci memset(dmac_v, 0, ETH_ALEN); 163562306a36Sopenharmony_ci dmac_c[0] = 1; 163662306a36Sopenharmony_ci dmac_v[0] = 1; 163762306a36Sopenharmony_ci node->mcast_rule = mlx5_add_flow_rules(ndev->rxft, spec, &flow_act, dests, NUM_DESTS); 163862306a36Sopenharmony_ci if (IS_ERR(node->mcast_rule)) { 163962306a36Sopenharmony_ci err = PTR_ERR(node->mcast_rule); 164062306a36Sopenharmony_ci goto err_mcast; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci kvfree(spec); 164362306a36Sopenharmony_ci mlx5_vdpa_add_rx_counters(ndev, node); 164462306a36Sopenharmony_ci return 0; 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_cierr_mcast: 164762306a36Sopenharmony_ci mlx5_del_flow_rules(node->ucast_rule); 164862306a36Sopenharmony_cierr_ucast: 164962306a36Sopenharmony_ci remove_steering_counters(ndev, node); 165062306a36Sopenharmony_ciout_free: 165162306a36Sopenharmony_ci kvfree(spec); 165262306a36Sopenharmony_ci return err; 165362306a36Sopenharmony_ci} 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_cistatic void mlx5_vdpa_del_mac_vlan_rules(struct mlx5_vdpa_net *ndev, 165662306a36Sopenharmony_ci struct macvlan_node *node) 165762306a36Sopenharmony_ci{ 165862306a36Sopenharmony_ci mlx5_vdpa_remove_rx_counters(ndev, node); 165962306a36Sopenharmony_ci mlx5_del_flow_rules(node->ucast_rule); 166062306a36Sopenharmony_ci mlx5_del_flow_rules(node->mcast_rule); 166162306a36Sopenharmony_ci} 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_cistatic u64 search_val(u8 *mac, u16 vlan, bool tagged) 166462306a36Sopenharmony_ci{ 166562306a36Sopenharmony_ci u64 val; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci if (!tagged) 166862306a36Sopenharmony_ci vlan = MLX5V_UNTAGGED; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci val = (u64)vlan << 48 | 167162306a36Sopenharmony_ci (u64)mac[0] << 40 | 167262306a36Sopenharmony_ci (u64)mac[1] << 32 | 167362306a36Sopenharmony_ci (u64)mac[2] << 24 | 167462306a36Sopenharmony_ci (u64)mac[3] << 16 | 167562306a36Sopenharmony_ci (u64)mac[4] << 8 | 167662306a36Sopenharmony_ci (u64)mac[5]; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci return val; 167962306a36Sopenharmony_ci} 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_cistatic struct macvlan_node *mac_vlan_lookup(struct mlx5_vdpa_net *ndev, u64 value) 168262306a36Sopenharmony_ci{ 168362306a36Sopenharmony_ci struct macvlan_node *pos; 168462306a36Sopenharmony_ci u32 idx; 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci idx = hash_64(value, 8); // tbd 8 168762306a36Sopenharmony_ci hlist_for_each_entry(pos, &ndev->macvlan_hash[idx], hlist) { 168862306a36Sopenharmony_ci if (pos->macvlan == value) 168962306a36Sopenharmony_ci return pos; 169062306a36Sopenharmony_ci } 169162306a36Sopenharmony_ci return NULL; 169262306a36Sopenharmony_ci} 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_cistatic int mac_vlan_add(struct mlx5_vdpa_net *ndev, u8 *mac, u16 vid, bool tagged) 169562306a36Sopenharmony_ci{ 169662306a36Sopenharmony_ci struct macvlan_node *ptr; 169762306a36Sopenharmony_ci u64 val; 169862306a36Sopenharmony_ci u32 idx; 169962306a36Sopenharmony_ci int err; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci val = search_val(mac, vid, tagged); 170262306a36Sopenharmony_ci if (mac_vlan_lookup(ndev, val)) 170362306a36Sopenharmony_ci return -EEXIST; 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); 170662306a36Sopenharmony_ci if (!ptr) 170762306a36Sopenharmony_ci return -ENOMEM; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci ptr->tagged = tagged; 171062306a36Sopenharmony_ci ptr->macvlan = val; 171162306a36Sopenharmony_ci ptr->ndev = ndev; 171262306a36Sopenharmony_ci err = mlx5_vdpa_add_mac_vlan_rules(ndev, ndev->config.mac, ptr); 171362306a36Sopenharmony_ci if (err) 171462306a36Sopenharmony_ci goto err_add; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci idx = hash_64(val, 8); 171762306a36Sopenharmony_ci hlist_add_head(&ptr->hlist, &ndev->macvlan_hash[idx]); 171862306a36Sopenharmony_ci return 0; 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_cierr_add: 172162306a36Sopenharmony_ci kfree(ptr); 172262306a36Sopenharmony_ci return err; 172362306a36Sopenharmony_ci} 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_cistatic void mac_vlan_del(struct mlx5_vdpa_net *ndev, u8 *mac, u16 vlan, bool tagged) 172662306a36Sopenharmony_ci{ 172762306a36Sopenharmony_ci struct macvlan_node *ptr; 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci ptr = mac_vlan_lookup(ndev, search_val(mac, vlan, tagged)); 173062306a36Sopenharmony_ci if (!ptr) 173162306a36Sopenharmony_ci return; 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci hlist_del(&ptr->hlist); 173462306a36Sopenharmony_ci mlx5_vdpa_del_mac_vlan_rules(ndev, ptr); 173562306a36Sopenharmony_ci remove_steering_counters(ndev, ptr); 173662306a36Sopenharmony_ci kfree(ptr); 173762306a36Sopenharmony_ci} 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_cistatic void clear_mac_vlan_table(struct mlx5_vdpa_net *ndev) 174062306a36Sopenharmony_ci{ 174162306a36Sopenharmony_ci struct macvlan_node *pos; 174262306a36Sopenharmony_ci struct hlist_node *n; 174362306a36Sopenharmony_ci int i; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci for (i = 0; i < MLX5V_MACVLAN_SIZE; i++) { 174662306a36Sopenharmony_ci hlist_for_each_entry_safe(pos, n, &ndev->macvlan_hash[i], hlist) { 174762306a36Sopenharmony_ci hlist_del(&pos->hlist); 174862306a36Sopenharmony_ci mlx5_vdpa_del_mac_vlan_rules(ndev, pos); 174962306a36Sopenharmony_ci remove_steering_counters(ndev, pos); 175062306a36Sopenharmony_ci kfree(pos); 175162306a36Sopenharmony_ci } 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci} 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_cistatic int setup_steering(struct mlx5_vdpa_net *ndev) 175662306a36Sopenharmony_ci{ 175762306a36Sopenharmony_ci struct mlx5_flow_table_attr ft_attr = {}; 175862306a36Sopenharmony_ci struct mlx5_flow_namespace *ns; 175962306a36Sopenharmony_ci int err; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci ft_attr.max_fte = MAX_STEERING_ENT; 176262306a36Sopenharmony_ci ft_attr.autogroup.max_num_groups = MAX_STEERING_GROUPS; 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci ns = mlx5_get_flow_namespace(ndev->mvdev.mdev, MLX5_FLOW_NAMESPACE_BYPASS); 176562306a36Sopenharmony_ci if (!ns) { 176662306a36Sopenharmony_ci mlx5_vdpa_warn(&ndev->mvdev, "failed to get flow namespace\n"); 176762306a36Sopenharmony_ci return -EOPNOTSUPP; 176862306a36Sopenharmony_ci } 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci ndev->rxft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr); 177162306a36Sopenharmony_ci if (IS_ERR(ndev->rxft)) { 177262306a36Sopenharmony_ci mlx5_vdpa_warn(&ndev->mvdev, "failed to create flow table\n"); 177362306a36Sopenharmony_ci return PTR_ERR(ndev->rxft); 177462306a36Sopenharmony_ci } 177562306a36Sopenharmony_ci mlx5_vdpa_add_rx_flow_table(ndev); 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci err = mac_vlan_add(ndev, ndev->config.mac, 0, false); 177862306a36Sopenharmony_ci if (err) 177962306a36Sopenharmony_ci goto err_add; 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci return 0; 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_cierr_add: 178462306a36Sopenharmony_ci mlx5_vdpa_remove_rx_flow_table(ndev); 178562306a36Sopenharmony_ci mlx5_destroy_flow_table(ndev->rxft); 178662306a36Sopenharmony_ci return err; 178762306a36Sopenharmony_ci} 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_cistatic void teardown_steering(struct mlx5_vdpa_net *ndev) 179062306a36Sopenharmony_ci{ 179162306a36Sopenharmony_ci clear_mac_vlan_table(ndev); 179262306a36Sopenharmony_ci mlx5_vdpa_remove_rx_flow_table(ndev); 179362306a36Sopenharmony_ci mlx5_destroy_flow_table(ndev->rxft); 179462306a36Sopenharmony_ci} 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_cistatic virtio_net_ctrl_ack handle_ctrl_mac(struct mlx5_vdpa_dev *mvdev, u8 cmd) 179762306a36Sopenharmony_ci{ 179862306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 179962306a36Sopenharmony_ci struct mlx5_control_vq *cvq = &mvdev->cvq; 180062306a36Sopenharmony_ci virtio_net_ctrl_ack status = VIRTIO_NET_ERR; 180162306a36Sopenharmony_ci struct mlx5_core_dev *pfmdev; 180262306a36Sopenharmony_ci size_t read; 180362306a36Sopenharmony_ci u8 mac[ETH_ALEN], mac_back[ETH_ALEN]; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci pfmdev = pci_get_drvdata(pci_physfn(mvdev->mdev->pdev)); 180662306a36Sopenharmony_ci switch (cmd) { 180762306a36Sopenharmony_ci case VIRTIO_NET_CTRL_MAC_ADDR_SET: 180862306a36Sopenharmony_ci read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, (void *)mac, ETH_ALEN); 180962306a36Sopenharmony_ci if (read != ETH_ALEN) 181062306a36Sopenharmony_ci break; 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci if (!memcmp(ndev->config.mac, mac, 6)) { 181362306a36Sopenharmony_ci status = VIRTIO_NET_OK; 181462306a36Sopenharmony_ci break; 181562306a36Sopenharmony_ci } 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci if (is_zero_ether_addr(mac)) 181862306a36Sopenharmony_ci break; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci if (!is_zero_ether_addr(ndev->config.mac)) { 182162306a36Sopenharmony_ci if (mlx5_mpfs_del_mac(pfmdev, ndev->config.mac)) { 182262306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "failed to delete old MAC %pM from MPFS table\n", 182362306a36Sopenharmony_ci ndev->config.mac); 182462306a36Sopenharmony_ci break; 182562306a36Sopenharmony_ci } 182662306a36Sopenharmony_ci } 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci if (mlx5_mpfs_add_mac(pfmdev, mac)) { 182962306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "failed to insert new MAC %pM into MPFS table\n", 183062306a36Sopenharmony_ci mac); 183162306a36Sopenharmony_ci break; 183262306a36Sopenharmony_ci } 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci /* backup the original mac address so that if failed to add the forward rules 183562306a36Sopenharmony_ci * we could restore it 183662306a36Sopenharmony_ci */ 183762306a36Sopenharmony_ci memcpy(mac_back, ndev->config.mac, ETH_ALEN); 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci memcpy(ndev->config.mac, mac, ETH_ALEN); 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci /* Need recreate the flow table entry, so that the packet could forward back 184262306a36Sopenharmony_ci */ 184362306a36Sopenharmony_ci mac_vlan_del(ndev, mac_back, 0, false); 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci if (mac_vlan_add(ndev, ndev->config.mac, 0, false)) { 184662306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "failed to insert forward rules, try to restore\n"); 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci /* Although it hardly run here, we still need double check */ 184962306a36Sopenharmony_ci if (is_zero_ether_addr(mac_back)) { 185062306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "restore mac failed: Original MAC is zero\n"); 185162306a36Sopenharmony_ci break; 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci /* Try to restore original mac address to MFPS table, and try to restore 185562306a36Sopenharmony_ci * the forward rule entry. 185662306a36Sopenharmony_ci */ 185762306a36Sopenharmony_ci if (mlx5_mpfs_del_mac(pfmdev, ndev->config.mac)) { 185862306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "restore mac failed: delete MAC %pM from MPFS table failed\n", 185962306a36Sopenharmony_ci ndev->config.mac); 186062306a36Sopenharmony_ci } 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci if (mlx5_mpfs_add_mac(pfmdev, mac_back)) { 186362306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "restore mac failed: insert old MAC %pM into MPFS table failed\n", 186462306a36Sopenharmony_ci mac_back); 186562306a36Sopenharmony_ci } 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci memcpy(ndev->config.mac, mac_back, ETH_ALEN); 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci if (mac_vlan_add(ndev, ndev->config.mac, 0, false)) 187062306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "restore forward rules failed: insert forward rules failed\n"); 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci break; 187362306a36Sopenharmony_ci } 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci status = VIRTIO_NET_OK; 187662306a36Sopenharmony_ci break; 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci default: 187962306a36Sopenharmony_ci break; 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci return status; 188362306a36Sopenharmony_ci} 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_cistatic int change_num_qps(struct mlx5_vdpa_dev *mvdev, int newqps) 188662306a36Sopenharmony_ci{ 188762306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 188862306a36Sopenharmony_ci int cur_qps = ndev->cur_num_vqs / 2; 188962306a36Sopenharmony_ci int err; 189062306a36Sopenharmony_ci int i; 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci if (cur_qps > newqps) { 189362306a36Sopenharmony_ci err = modify_rqt(ndev, 2 * newqps); 189462306a36Sopenharmony_ci if (err) 189562306a36Sopenharmony_ci return err; 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci for (i = ndev->cur_num_vqs - 1; i >= 2 * newqps; i--) 189862306a36Sopenharmony_ci teardown_vq(ndev, &ndev->vqs[i]); 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci ndev->cur_num_vqs = 2 * newqps; 190162306a36Sopenharmony_ci } else { 190262306a36Sopenharmony_ci ndev->cur_num_vqs = 2 * newqps; 190362306a36Sopenharmony_ci for (i = cur_qps * 2; i < 2 * newqps; i++) { 190462306a36Sopenharmony_ci err = setup_vq(ndev, &ndev->vqs[i]); 190562306a36Sopenharmony_ci if (err) 190662306a36Sopenharmony_ci goto clean_added; 190762306a36Sopenharmony_ci } 190862306a36Sopenharmony_ci err = modify_rqt(ndev, 2 * newqps); 190962306a36Sopenharmony_ci if (err) 191062306a36Sopenharmony_ci goto clean_added; 191162306a36Sopenharmony_ci } 191262306a36Sopenharmony_ci return 0; 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ciclean_added: 191562306a36Sopenharmony_ci for (--i; i >= 2 * cur_qps; --i) 191662306a36Sopenharmony_ci teardown_vq(ndev, &ndev->vqs[i]); 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci ndev->cur_num_vqs = 2 * cur_qps; 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci return err; 192162306a36Sopenharmony_ci} 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_cistatic virtio_net_ctrl_ack handle_ctrl_mq(struct mlx5_vdpa_dev *mvdev, u8 cmd) 192462306a36Sopenharmony_ci{ 192562306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 192662306a36Sopenharmony_ci virtio_net_ctrl_ack status = VIRTIO_NET_ERR; 192762306a36Sopenharmony_ci struct mlx5_control_vq *cvq = &mvdev->cvq; 192862306a36Sopenharmony_ci struct virtio_net_ctrl_mq mq; 192962306a36Sopenharmony_ci size_t read; 193062306a36Sopenharmony_ci u16 newqps; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci switch (cmd) { 193362306a36Sopenharmony_ci case VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET: 193462306a36Sopenharmony_ci /* This mq feature check aligns with pre-existing userspace 193562306a36Sopenharmony_ci * implementation. 193662306a36Sopenharmony_ci * 193762306a36Sopenharmony_ci * Without it, an untrusted driver could fake a multiqueue config 193862306a36Sopenharmony_ci * request down to a non-mq device that may cause kernel to 193962306a36Sopenharmony_ci * panic due to uninitialized resources for extra vqs. Even with 194062306a36Sopenharmony_ci * a well behaving guest driver, it is not expected to allow 194162306a36Sopenharmony_ci * changing the number of vqs on a non-mq device. 194262306a36Sopenharmony_ci */ 194362306a36Sopenharmony_ci if (!MLX5_FEATURE(mvdev, VIRTIO_NET_F_MQ)) 194462306a36Sopenharmony_ci break; 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, (void *)&mq, sizeof(mq)); 194762306a36Sopenharmony_ci if (read != sizeof(mq)) 194862306a36Sopenharmony_ci break; 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci newqps = mlx5vdpa16_to_cpu(mvdev, mq.virtqueue_pairs); 195162306a36Sopenharmony_ci if (newqps < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN || 195262306a36Sopenharmony_ci newqps > ndev->rqt_size) 195362306a36Sopenharmony_ci break; 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci if (ndev->cur_num_vqs == 2 * newqps) { 195662306a36Sopenharmony_ci status = VIRTIO_NET_OK; 195762306a36Sopenharmony_ci break; 195862306a36Sopenharmony_ci } 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci if (!change_num_qps(mvdev, newqps)) 196162306a36Sopenharmony_ci status = VIRTIO_NET_OK; 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci break; 196462306a36Sopenharmony_ci default: 196562306a36Sopenharmony_ci break; 196662306a36Sopenharmony_ci } 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci return status; 196962306a36Sopenharmony_ci} 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_cistatic virtio_net_ctrl_ack handle_ctrl_vlan(struct mlx5_vdpa_dev *mvdev, u8 cmd) 197262306a36Sopenharmony_ci{ 197362306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 197462306a36Sopenharmony_ci virtio_net_ctrl_ack status = VIRTIO_NET_ERR; 197562306a36Sopenharmony_ci struct mlx5_control_vq *cvq = &mvdev->cvq; 197662306a36Sopenharmony_ci __virtio16 vlan; 197762306a36Sopenharmony_ci size_t read; 197862306a36Sopenharmony_ci u16 id; 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VLAN))) 198162306a36Sopenharmony_ci return status; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci switch (cmd) { 198462306a36Sopenharmony_ci case VIRTIO_NET_CTRL_VLAN_ADD: 198562306a36Sopenharmony_ci read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, &vlan, sizeof(vlan)); 198662306a36Sopenharmony_ci if (read != sizeof(vlan)) 198762306a36Sopenharmony_ci break; 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci id = mlx5vdpa16_to_cpu(mvdev, vlan); 199062306a36Sopenharmony_ci if (mac_vlan_add(ndev, ndev->config.mac, id, true)) 199162306a36Sopenharmony_ci break; 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci status = VIRTIO_NET_OK; 199462306a36Sopenharmony_ci break; 199562306a36Sopenharmony_ci case VIRTIO_NET_CTRL_VLAN_DEL: 199662306a36Sopenharmony_ci read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, &vlan, sizeof(vlan)); 199762306a36Sopenharmony_ci if (read != sizeof(vlan)) 199862306a36Sopenharmony_ci break; 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci id = mlx5vdpa16_to_cpu(mvdev, vlan); 200162306a36Sopenharmony_ci mac_vlan_del(ndev, ndev->config.mac, id, true); 200262306a36Sopenharmony_ci status = VIRTIO_NET_OK; 200362306a36Sopenharmony_ci break; 200462306a36Sopenharmony_ci default: 200562306a36Sopenharmony_ci break; 200662306a36Sopenharmony_ci } 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci return status; 200962306a36Sopenharmony_ci} 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_cistatic void mlx5_cvq_kick_handler(struct work_struct *work) 201262306a36Sopenharmony_ci{ 201362306a36Sopenharmony_ci virtio_net_ctrl_ack status = VIRTIO_NET_ERR; 201462306a36Sopenharmony_ci struct virtio_net_ctrl_hdr ctrl; 201562306a36Sopenharmony_ci struct mlx5_vdpa_wq_ent *wqent; 201662306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev; 201762306a36Sopenharmony_ci struct mlx5_control_vq *cvq; 201862306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev; 201962306a36Sopenharmony_ci size_t read, write; 202062306a36Sopenharmony_ci int err; 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci wqent = container_of(work, struct mlx5_vdpa_wq_ent, work); 202362306a36Sopenharmony_ci mvdev = wqent->mvdev; 202462306a36Sopenharmony_ci ndev = to_mlx5_vdpa_ndev(mvdev); 202562306a36Sopenharmony_ci cvq = &mvdev->cvq; 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci down_write(&ndev->reslock); 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci if (!(mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) 203062306a36Sopenharmony_ci goto out; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) 203362306a36Sopenharmony_ci goto out; 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci if (!cvq->ready) 203662306a36Sopenharmony_ci goto out; 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci while (true) { 203962306a36Sopenharmony_ci err = vringh_getdesc_iotlb(&cvq->vring, &cvq->riov, &cvq->wiov, &cvq->head, 204062306a36Sopenharmony_ci GFP_ATOMIC); 204162306a36Sopenharmony_ci if (err <= 0) 204262306a36Sopenharmony_ci break; 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_ci read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, &ctrl, sizeof(ctrl)); 204562306a36Sopenharmony_ci if (read != sizeof(ctrl)) 204662306a36Sopenharmony_ci break; 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci cvq->received_desc++; 204962306a36Sopenharmony_ci switch (ctrl.class) { 205062306a36Sopenharmony_ci case VIRTIO_NET_CTRL_MAC: 205162306a36Sopenharmony_ci status = handle_ctrl_mac(mvdev, ctrl.cmd); 205262306a36Sopenharmony_ci break; 205362306a36Sopenharmony_ci case VIRTIO_NET_CTRL_MQ: 205462306a36Sopenharmony_ci status = handle_ctrl_mq(mvdev, ctrl.cmd); 205562306a36Sopenharmony_ci break; 205662306a36Sopenharmony_ci case VIRTIO_NET_CTRL_VLAN: 205762306a36Sopenharmony_ci status = handle_ctrl_vlan(mvdev, ctrl.cmd); 205862306a36Sopenharmony_ci break; 205962306a36Sopenharmony_ci default: 206062306a36Sopenharmony_ci break; 206162306a36Sopenharmony_ci } 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci /* Make sure data is written before advancing index */ 206462306a36Sopenharmony_ci smp_wmb(); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci write = vringh_iov_push_iotlb(&cvq->vring, &cvq->wiov, &status, sizeof(status)); 206762306a36Sopenharmony_ci vringh_complete_iotlb(&cvq->vring, cvq->head, write); 206862306a36Sopenharmony_ci vringh_kiov_cleanup(&cvq->riov); 206962306a36Sopenharmony_ci vringh_kiov_cleanup(&cvq->wiov); 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci if (vringh_need_notify_iotlb(&cvq->vring)) 207262306a36Sopenharmony_ci vringh_notify(&cvq->vring); 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci cvq->completed_desc++; 207562306a36Sopenharmony_ci queue_work(mvdev->wq, &wqent->work); 207662306a36Sopenharmony_ci break; 207762306a36Sopenharmony_ci } 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ciout: 208062306a36Sopenharmony_ci up_write(&ndev->reslock); 208162306a36Sopenharmony_ci} 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_cistatic void mlx5_vdpa_kick_vq(struct vdpa_device *vdev, u16 idx) 208462306a36Sopenharmony_ci{ 208562306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 208662306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 208762306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq; 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci if (!is_index_valid(mvdev, idx)) 209062306a36Sopenharmony_ci return; 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci if (unlikely(is_ctrl_vq_idx(mvdev, idx))) { 209362306a36Sopenharmony_ci if (!mvdev->wq || !mvdev->cvq.ready) 209462306a36Sopenharmony_ci return; 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci queue_work(mvdev->wq, &ndev->cvq_ent.work); 209762306a36Sopenharmony_ci return; 209862306a36Sopenharmony_ci } 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci mvq = &ndev->vqs[idx]; 210162306a36Sopenharmony_ci if (unlikely(!mvq->ready)) 210262306a36Sopenharmony_ci return; 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci iowrite16(idx, ndev->mvdev.res.kick_addr); 210562306a36Sopenharmony_ci} 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_cistatic int mlx5_vdpa_set_vq_address(struct vdpa_device *vdev, u16 idx, u64 desc_area, 210862306a36Sopenharmony_ci u64 driver_area, u64 device_area) 210962306a36Sopenharmony_ci{ 211062306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 211162306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 211262306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq; 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci if (!is_index_valid(mvdev, idx)) 211562306a36Sopenharmony_ci return -EINVAL; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci if (is_ctrl_vq_idx(mvdev, idx)) { 211862306a36Sopenharmony_ci mvdev->cvq.desc_addr = desc_area; 211962306a36Sopenharmony_ci mvdev->cvq.device_addr = device_area; 212062306a36Sopenharmony_ci mvdev->cvq.driver_addr = driver_area; 212162306a36Sopenharmony_ci return 0; 212262306a36Sopenharmony_ci } 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci mvq = &ndev->vqs[idx]; 212562306a36Sopenharmony_ci mvq->desc_addr = desc_area; 212662306a36Sopenharmony_ci mvq->device_addr = device_area; 212762306a36Sopenharmony_ci mvq->driver_addr = driver_area; 212862306a36Sopenharmony_ci return 0; 212962306a36Sopenharmony_ci} 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_cistatic void mlx5_vdpa_set_vq_num(struct vdpa_device *vdev, u16 idx, u32 num) 213262306a36Sopenharmony_ci{ 213362306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 213462306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 213562306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq; 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci if (!is_index_valid(mvdev, idx)) 213862306a36Sopenharmony_ci return; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci if (is_ctrl_vq_idx(mvdev, idx)) { 214162306a36Sopenharmony_ci struct mlx5_control_vq *cvq = &mvdev->cvq; 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci cvq->vring.vring.num = num; 214462306a36Sopenharmony_ci return; 214562306a36Sopenharmony_ci } 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci mvq = &ndev->vqs[idx]; 214862306a36Sopenharmony_ci mvq->num_ent = num; 214962306a36Sopenharmony_ci} 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_cistatic void mlx5_vdpa_set_vq_cb(struct vdpa_device *vdev, u16 idx, struct vdpa_callback *cb) 215262306a36Sopenharmony_ci{ 215362306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 215462306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci ndev->event_cbs[idx] = *cb; 215762306a36Sopenharmony_ci if (is_ctrl_vq_idx(mvdev, idx)) 215862306a36Sopenharmony_ci mvdev->cvq.event_cb = *cb; 215962306a36Sopenharmony_ci} 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_cistatic void mlx5_cvq_notify(struct vringh *vring) 216262306a36Sopenharmony_ci{ 216362306a36Sopenharmony_ci struct mlx5_control_vq *cvq = container_of(vring, struct mlx5_control_vq, vring); 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci if (!cvq->event_cb.callback) 216662306a36Sopenharmony_ci return; 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci cvq->event_cb.callback(cvq->event_cb.private); 216962306a36Sopenharmony_ci} 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_cistatic void set_cvq_ready(struct mlx5_vdpa_dev *mvdev, bool ready) 217262306a36Sopenharmony_ci{ 217362306a36Sopenharmony_ci struct mlx5_control_vq *cvq = &mvdev->cvq; 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci cvq->ready = ready; 217662306a36Sopenharmony_ci if (!ready) 217762306a36Sopenharmony_ci return; 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci cvq->vring.notify = mlx5_cvq_notify; 218062306a36Sopenharmony_ci} 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_cistatic void mlx5_vdpa_set_vq_ready(struct vdpa_device *vdev, u16 idx, bool ready) 218362306a36Sopenharmony_ci{ 218462306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 218562306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 218662306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq; 218762306a36Sopenharmony_ci int err; 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci if (!mvdev->actual_features) 219062306a36Sopenharmony_ci return; 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci if (!is_index_valid(mvdev, idx)) 219362306a36Sopenharmony_ci return; 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci if (is_ctrl_vq_idx(mvdev, idx)) { 219662306a36Sopenharmony_ci set_cvq_ready(mvdev, ready); 219762306a36Sopenharmony_ci return; 219862306a36Sopenharmony_ci } 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci mvq = &ndev->vqs[idx]; 220162306a36Sopenharmony_ci if (!ready) { 220262306a36Sopenharmony_ci suspend_vq(ndev, mvq); 220362306a36Sopenharmony_ci } else { 220462306a36Sopenharmony_ci err = modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY); 220562306a36Sopenharmony_ci if (err) { 220662306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "modify VQ %d to ready failed (%d)\n", idx, err); 220762306a36Sopenharmony_ci ready = false; 220862306a36Sopenharmony_ci } 220962306a36Sopenharmony_ci } 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci mvq->ready = ready; 221362306a36Sopenharmony_ci} 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_cistatic bool mlx5_vdpa_get_vq_ready(struct vdpa_device *vdev, u16 idx) 221662306a36Sopenharmony_ci{ 221762306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 221862306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci if (!is_index_valid(mvdev, idx)) 222162306a36Sopenharmony_ci return false; 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci if (is_ctrl_vq_idx(mvdev, idx)) 222462306a36Sopenharmony_ci return mvdev->cvq.ready; 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci return ndev->vqs[idx].ready; 222762306a36Sopenharmony_ci} 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_cistatic int mlx5_vdpa_set_vq_state(struct vdpa_device *vdev, u16 idx, 223062306a36Sopenharmony_ci const struct vdpa_vq_state *state) 223162306a36Sopenharmony_ci{ 223262306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 223362306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 223462306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq; 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci if (!is_index_valid(mvdev, idx)) 223762306a36Sopenharmony_ci return -EINVAL; 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci if (is_ctrl_vq_idx(mvdev, idx)) { 224062306a36Sopenharmony_ci mvdev->cvq.vring.last_avail_idx = state->split.avail_index; 224162306a36Sopenharmony_ci return 0; 224262306a36Sopenharmony_ci } 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci mvq = &ndev->vqs[idx]; 224562306a36Sopenharmony_ci if (mvq->fw_state == MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY) { 224662306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "can't modify available index\n"); 224762306a36Sopenharmony_ci return -EINVAL; 224862306a36Sopenharmony_ci } 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci mvq->used_idx = state->split.avail_index; 225162306a36Sopenharmony_ci mvq->avail_idx = state->split.avail_index; 225262306a36Sopenharmony_ci return 0; 225362306a36Sopenharmony_ci} 225462306a36Sopenharmony_ci 225562306a36Sopenharmony_cistatic int mlx5_vdpa_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa_vq_state *state) 225662306a36Sopenharmony_ci{ 225762306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 225862306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 225962306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq; 226062306a36Sopenharmony_ci struct mlx5_virtq_attr attr; 226162306a36Sopenharmony_ci int err; 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci if (!is_index_valid(mvdev, idx)) 226462306a36Sopenharmony_ci return -EINVAL; 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci if (is_ctrl_vq_idx(mvdev, idx)) { 226762306a36Sopenharmony_ci state->split.avail_index = mvdev->cvq.vring.last_avail_idx; 226862306a36Sopenharmony_ci return 0; 226962306a36Sopenharmony_ci } 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci mvq = &ndev->vqs[idx]; 227262306a36Sopenharmony_ci /* If the virtq object was destroyed, use the value saved at 227362306a36Sopenharmony_ci * the last minute of suspend_vq. This caters for userspace 227462306a36Sopenharmony_ci * that cares about emulating the index after vq is stopped. 227562306a36Sopenharmony_ci */ 227662306a36Sopenharmony_ci if (!mvq->initialized) { 227762306a36Sopenharmony_ci /* Firmware returns a wrong value for the available index. 227862306a36Sopenharmony_ci * Since both values should be identical, we take the value of 227962306a36Sopenharmony_ci * used_idx which is reported correctly. 228062306a36Sopenharmony_ci */ 228162306a36Sopenharmony_ci state->split.avail_index = mvq->used_idx; 228262306a36Sopenharmony_ci return 0; 228362306a36Sopenharmony_ci } 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci err = query_virtqueue(ndev, mvq, &attr); 228662306a36Sopenharmony_ci if (err) { 228762306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "failed to query virtqueue\n"); 228862306a36Sopenharmony_ci return err; 228962306a36Sopenharmony_ci } 229062306a36Sopenharmony_ci state->split.avail_index = attr.used_index; 229162306a36Sopenharmony_ci return 0; 229262306a36Sopenharmony_ci} 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_cistatic u32 mlx5_vdpa_get_vq_align(struct vdpa_device *vdev) 229562306a36Sopenharmony_ci{ 229662306a36Sopenharmony_ci return PAGE_SIZE; 229762306a36Sopenharmony_ci} 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_cistatic u32 mlx5_vdpa_get_vq_group(struct vdpa_device *vdev, u16 idx) 230062306a36Sopenharmony_ci{ 230162306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci if (is_ctrl_vq_idx(mvdev, idx)) 230462306a36Sopenharmony_ci return MLX5_VDPA_CVQ_GROUP; 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_ci return MLX5_VDPA_DATAVQ_GROUP; 230762306a36Sopenharmony_ci} 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_cistatic u64 mlx_to_vritio_features(u16 dev_features) 231062306a36Sopenharmony_ci{ 231162306a36Sopenharmony_ci u64 result = 0; 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_MRG_RXBUF)) 231462306a36Sopenharmony_ci result |= BIT_ULL(VIRTIO_NET_F_MRG_RXBUF); 231562306a36Sopenharmony_ci if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_ECN)) 231662306a36Sopenharmony_ci result |= BIT_ULL(VIRTIO_NET_F_HOST_ECN); 231762306a36Sopenharmony_ci if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_ECN)) 231862306a36Sopenharmony_ci result |= BIT_ULL(VIRTIO_NET_F_GUEST_ECN); 231962306a36Sopenharmony_ci if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_TSO6)) 232062306a36Sopenharmony_ci result |= BIT_ULL(VIRTIO_NET_F_GUEST_TSO6); 232162306a36Sopenharmony_ci if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_TSO4)) 232262306a36Sopenharmony_ci result |= BIT_ULL(VIRTIO_NET_F_GUEST_TSO4); 232362306a36Sopenharmony_ci if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_CSUM)) 232462306a36Sopenharmony_ci result |= BIT_ULL(VIRTIO_NET_F_GUEST_CSUM); 232562306a36Sopenharmony_ci if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_CSUM)) 232662306a36Sopenharmony_ci result |= BIT_ULL(VIRTIO_NET_F_CSUM); 232762306a36Sopenharmony_ci if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_TSO6)) 232862306a36Sopenharmony_ci result |= BIT_ULL(VIRTIO_NET_F_HOST_TSO6); 232962306a36Sopenharmony_ci if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_TSO4)) 233062306a36Sopenharmony_ci result |= BIT_ULL(VIRTIO_NET_F_HOST_TSO4); 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci return result; 233362306a36Sopenharmony_ci} 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_cistatic u64 get_supported_features(struct mlx5_core_dev *mdev) 233662306a36Sopenharmony_ci{ 233762306a36Sopenharmony_ci u64 mlx_vdpa_features = 0; 233862306a36Sopenharmony_ci u16 dev_features; 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_ci dev_features = MLX5_CAP_DEV_VDPA_EMULATION(mdev, device_features_bits_mask); 234162306a36Sopenharmony_ci mlx_vdpa_features |= mlx_to_vritio_features(dev_features); 234262306a36Sopenharmony_ci if (MLX5_CAP_DEV_VDPA_EMULATION(mdev, virtio_version_1_0)) 234362306a36Sopenharmony_ci mlx_vdpa_features |= BIT_ULL(VIRTIO_F_VERSION_1); 234462306a36Sopenharmony_ci mlx_vdpa_features |= BIT_ULL(VIRTIO_F_ACCESS_PLATFORM); 234562306a36Sopenharmony_ci mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_CTRL_VQ); 234662306a36Sopenharmony_ci mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR); 234762306a36Sopenharmony_ci mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_MQ); 234862306a36Sopenharmony_ci mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_STATUS); 234962306a36Sopenharmony_ci mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_MTU); 235062306a36Sopenharmony_ci mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_CTRL_VLAN); 235162306a36Sopenharmony_ci mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_MAC); 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci return mlx_vdpa_features; 235462306a36Sopenharmony_ci} 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_cistatic u64 mlx5_vdpa_get_device_features(struct vdpa_device *vdev) 235762306a36Sopenharmony_ci{ 235862306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 235962306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci print_features(mvdev, ndev->mvdev.mlx_features, false); 236262306a36Sopenharmony_ci return ndev->mvdev.mlx_features; 236362306a36Sopenharmony_ci} 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_cistatic int verify_driver_features(struct mlx5_vdpa_dev *mvdev, u64 features) 236662306a36Sopenharmony_ci{ 236762306a36Sopenharmony_ci /* Minimum features to expect */ 236862306a36Sopenharmony_ci if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM))) 236962306a36Sopenharmony_ci return -EOPNOTSUPP; 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci /* Double check features combination sent down by the driver. 237262306a36Sopenharmony_ci * Fail invalid features due to absence of the depended feature. 237362306a36Sopenharmony_ci * 237462306a36Sopenharmony_ci * Per VIRTIO v1.1 specification, section 5.1.3.1 Feature bit 237562306a36Sopenharmony_ci * requirements: "VIRTIO_NET_F_MQ Requires VIRTIO_NET_F_CTRL_VQ". 237662306a36Sopenharmony_ci * By failing the invalid features sent down by untrusted drivers, 237762306a36Sopenharmony_ci * we're assured the assumption made upon is_index_valid() and 237862306a36Sopenharmony_ci * is_ctrl_vq_idx() will not be compromised. 237962306a36Sopenharmony_ci */ 238062306a36Sopenharmony_ci if ((features & (BIT_ULL(VIRTIO_NET_F_MQ) | BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) == 238162306a36Sopenharmony_ci BIT_ULL(VIRTIO_NET_F_MQ)) 238262306a36Sopenharmony_ci return -EINVAL; 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci return 0; 238562306a36Sopenharmony_ci} 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_cistatic int setup_virtqueues(struct mlx5_vdpa_dev *mvdev) 238862306a36Sopenharmony_ci{ 238962306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 239062306a36Sopenharmony_ci int err; 239162306a36Sopenharmony_ci int i; 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci for (i = 0; i < mvdev->max_vqs; i++) { 239462306a36Sopenharmony_ci err = setup_vq(ndev, &ndev->vqs[i]); 239562306a36Sopenharmony_ci if (err) 239662306a36Sopenharmony_ci goto err_vq; 239762306a36Sopenharmony_ci } 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci return 0; 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_cierr_vq: 240262306a36Sopenharmony_ci for (--i; i >= 0; i--) 240362306a36Sopenharmony_ci teardown_vq(ndev, &ndev->vqs[i]); 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci return err; 240662306a36Sopenharmony_ci} 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_cistatic void teardown_virtqueues(struct mlx5_vdpa_net *ndev) 240962306a36Sopenharmony_ci{ 241062306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq; 241162306a36Sopenharmony_ci int i; 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci for (i = ndev->mvdev.max_vqs - 1; i >= 0; i--) { 241462306a36Sopenharmony_ci mvq = &ndev->vqs[i]; 241562306a36Sopenharmony_ci if (!mvq->initialized) 241662306a36Sopenharmony_ci continue; 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci teardown_vq(ndev, mvq); 241962306a36Sopenharmony_ci } 242062306a36Sopenharmony_ci} 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_cistatic void update_cvq_info(struct mlx5_vdpa_dev *mvdev) 242362306a36Sopenharmony_ci{ 242462306a36Sopenharmony_ci if (MLX5_FEATURE(mvdev, VIRTIO_NET_F_CTRL_VQ)) { 242562306a36Sopenharmony_ci if (MLX5_FEATURE(mvdev, VIRTIO_NET_F_MQ)) { 242662306a36Sopenharmony_ci /* MQ supported. CVQ index is right above the last data virtqueue's */ 242762306a36Sopenharmony_ci mvdev->max_idx = mvdev->max_vqs; 242862306a36Sopenharmony_ci } else { 242962306a36Sopenharmony_ci /* Only CVQ supportted. data virtqueues occupy indices 0 and 1. 243062306a36Sopenharmony_ci * CVQ gets index 2 243162306a36Sopenharmony_ci */ 243262306a36Sopenharmony_ci mvdev->max_idx = 2; 243362306a36Sopenharmony_ci } 243462306a36Sopenharmony_ci } else { 243562306a36Sopenharmony_ci /* Two data virtqueues only: one for rx and one for tx */ 243662306a36Sopenharmony_ci mvdev->max_idx = 1; 243762306a36Sopenharmony_ci } 243862306a36Sopenharmony_ci} 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_cistatic u8 query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport) 244162306a36Sopenharmony_ci{ 244262306a36Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(query_vport_state_out)] = {}; 244362306a36Sopenharmony_ci u32 in[MLX5_ST_SZ_DW(query_vport_state_in)] = {}; 244462306a36Sopenharmony_ci int err; 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci MLX5_SET(query_vport_state_in, in, opcode, MLX5_CMD_OP_QUERY_VPORT_STATE); 244762306a36Sopenharmony_ci MLX5_SET(query_vport_state_in, in, op_mod, opmod); 244862306a36Sopenharmony_ci MLX5_SET(query_vport_state_in, in, vport_number, vport); 244962306a36Sopenharmony_ci if (vport) 245062306a36Sopenharmony_ci MLX5_SET(query_vport_state_in, in, other_vport, 1); 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci err = mlx5_cmd_exec_inout(mdev, query_vport_state, in, out); 245362306a36Sopenharmony_ci if (err) 245462306a36Sopenharmony_ci return 0; 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci return MLX5_GET(query_vport_state_out, out, state); 245762306a36Sopenharmony_ci} 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_cistatic bool get_link_state(struct mlx5_vdpa_dev *mvdev) 246062306a36Sopenharmony_ci{ 246162306a36Sopenharmony_ci if (query_vport_state(mvdev->mdev, MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT, 0) == 246262306a36Sopenharmony_ci VPORT_STATE_UP) 246362306a36Sopenharmony_ci return true; 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci return false; 246662306a36Sopenharmony_ci} 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_cistatic void update_carrier(struct work_struct *work) 246962306a36Sopenharmony_ci{ 247062306a36Sopenharmony_ci struct mlx5_vdpa_wq_ent *wqent; 247162306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev; 247262306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev; 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci wqent = container_of(work, struct mlx5_vdpa_wq_ent, work); 247562306a36Sopenharmony_ci mvdev = wqent->mvdev; 247662306a36Sopenharmony_ci ndev = to_mlx5_vdpa_ndev(mvdev); 247762306a36Sopenharmony_ci if (get_link_state(mvdev)) 247862306a36Sopenharmony_ci ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP); 247962306a36Sopenharmony_ci else 248062306a36Sopenharmony_ci ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP); 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci if (ndev->config_cb.callback) 248362306a36Sopenharmony_ci ndev->config_cb.callback(ndev->config_cb.private); 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci kfree(wqent); 248662306a36Sopenharmony_ci} 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_cistatic int queue_link_work(struct mlx5_vdpa_net *ndev) 248962306a36Sopenharmony_ci{ 249062306a36Sopenharmony_ci struct mlx5_vdpa_wq_ent *wqent; 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci wqent = kzalloc(sizeof(*wqent), GFP_ATOMIC); 249362306a36Sopenharmony_ci if (!wqent) 249462306a36Sopenharmony_ci return -ENOMEM; 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci wqent->mvdev = &ndev->mvdev; 249762306a36Sopenharmony_ci INIT_WORK(&wqent->work, update_carrier); 249862306a36Sopenharmony_ci queue_work(ndev->mvdev.wq, &wqent->work); 249962306a36Sopenharmony_ci return 0; 250062306a36Sopenharmony_ci} 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_cistatic int event_handler(struct notifier_block *nb, unsigned long event, void *param) 250362306a36Sopenharmony_ci{ 250462306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = container_of(nb, struct mlx5_vdpa_net, nb); 250562306a36Sopenharmony_ci struct mlx5_eqe *eqe = param; 250662306a36Sopenharmony_ci int ret = NOTIFY_DONE; 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci if (event == MLX5_EVENT_TYPE_PORT_CHANGE) { 250962306a36Sopenharmony_ci switch (eqe->sub_type) { 251062306a36Sopenharmony_ci case MLX5_PORT_CHANGE_SUBTYPE_DOWN: 251162306a36Sopenharmony_ci case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE: 251262306a36Sopenharmony_ci if (queue_link_work(ndev)) 251362306a36Sopenharmony_ci return NOTIFY_DONE; 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci ret = NOTIFY_OK; 251662306a36Sopenharmony_ci break; 251762306a36Sopenharmony_ci default: 251862306a36Sopenharmony_ci return NOTIFY_DONE; 251962306a36Sopenharmony_ci } 252062306a36Sopenharmony_ci return ret; 252162306a36Sopenharmony_ci } 252262306a36Sopenharmony_ci return ret; 252362306a36Sopenharmony_ci} 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_cistatic void register_link_notifier(struct mlx5_vdpa_net *ndev) 252662306a36Sopenharmony_ci{ 252762306a36Sopenharmony_ci if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_STATUS))) 252862306a36Sopenharmony_ci return; 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci ndev->nb.notifier_call = event_handler; 253162306a36Sopenharmony_ci mlx5_notifier_register(ndev->mvdev.mdev, &ndev->nb); 253262306a36Sopenharmony_ci ndev->nb_registered = true; 253362306a36Sopenharmony_ci queue_link_work(ndev); 253462306a36Sopenharmony_ci} 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_cistatic void unregister_link_notifier(struct mlx5_vdpa_net *ndev) 253762306a36Sopenharmony_ci{ 253862306a36Sopenharmony_ci if (!ndev->nb_registered) 253962306a36Sopenharmony_ci return; 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ci ndev->nb_registered = false; 254262306a36Sopenharmony_ci mlx5_notifier_unregister(ndev->mvdev.mdev, &ndev->nb); 254362306a36Sopenharmony_ci if (ndev->mvdev.wq) 254462306a36Sopenharmony_ci flush_workqueue(ndev->mvdev.wq); 254562306a36Sopenharmony_ci} 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_cistatic int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features) 254862306a36Sopenharmony_ci{ 254962306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 255062306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 255162306a36Sopenharmony_ci int err; 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci print_features(mvdev, features, true); 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_ci err = verify_driver_features(mvdev, features); 255662306a36Sopenharmony_ci if (err) 255762306a36Sopenharmony_ci return err; 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_ci ndev->mvdev.actual_features = features & ndev->mvdev.mlx_features; 256062306a36Sopenharmony_ci if (ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_MQ)) 256162306a36Sopenharmony_ci ndev->rqt_size = mlx5vdpa16_to_cpu(mvdev, ndev->config.max_virtqueue_pairs); 256262306a36Sopenharmony_ci else 256362306a36Sopenharmony_ci ndev->rqt_size = 1; 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci /* Device must start with 1 queue pair, as per VIRTIO v1.2 spec, section 256662306a36Sopenharmony_ci * 5.1.6.5.5 "Device operation in multiqueue mode": 256762306a36Sopenharmony_ci * 256862306a36Sopenharmony_ci * Multiqueue is disabled by default. 256962306a36Sopenharmony_ci * The driver enables multiqueue by sending a command using class 257062306a36Sopenharmony_ci * VIRTIO_NET_CTRL_MQ. The command selects the mode of multiqueue 257162306a36Sopenharmony_ci * operation, as follows: ... 257262306a36Sopenharmony_ci */ 257362306a36Sopenharmony_ci ndev->cur_num_vqs = 2; 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci update_cvq_info(mvdev); 257662306a36Sopenharmony_ci return err; 257762306a36Sopenharmony_ci} 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_cistatic void mlx5_vdpa_set_config_cb(struct vdpa_device *vdev, struct vdpa_callback *cb) 258062306a36Sopenharmony_ci{ 258162306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 258262306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci ndev->config_cb = *cb; 258562306a36Sopenharmony_ci} 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci#define MLX5_VDPA_MAX_VQ_ENTRIES 256 258862306a36Sopenharmony_cistatic u16 mlx5_vdpa_get_vq_num_max(struct vdpa_device *vdev) 258962306a36Sopenharmony_ci{ 259062306a36Sopenharmony_ci return MLX5_VDPA_MAX_VQ_ENTRIES; 259162306a36Sopenharmony_ci} 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_cistatic u32 mlx5_vdpa_get_device_id(struct vdpa_device *vdev) 259462306a36Sopenharmony_ci{ 259562306a36Sopenharmony_ci return VIRTIO_ID_NET; 259662306a36Sopenharmony_ci} 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_cistatic u32 mlx5_vdpa_get_vendor_id(struct vdpa_device *vdev) 259962306a36Sopenharmony_ci{ 260062306a36Sopenharmony_ci return PCI_VENDOR_ID_MELLANOX; 260162306a36Sopenharmony_ci} 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_cistatic u8 mlx5_vdpa_get_status(struct vdpa_device *vdev) 260462306a36Sopenharmony_ci{ 260562306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 260662306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 260762306a36Sopenharmony_ci 260862306a36Sopenharmony_ci print_status(mvdev, ndev->mvdev.status, false); 260962306a36Sopenharmony_ci return ndev->mvdev.status; 261062306a36Sopenharmony_ci} 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_cistatic int save_channel_info(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 261362306a36Sopenharmony_ci{ 261462306a36Sopenharmony_ci struct mlx5_vq_restore_info *ri = &mvq->ri; 261562306a36Sopenharmony_ci struct mlx5_virtq_attr attr = {}; 261662306a36Sopenharmony_ci int err; 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci if (mvq->initialized) { 261962306a36Sopenharmony_ci err = query_virtqueue(ndev, mvq, &attr); 262062306a36Sopenharmony_ci if (err) 262162306a36Sopenharmony_ci return err; 262262306a36Sopenharmony_ci } 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci ri->avail_index = attr.available_index; 262562306a36Sopenharmony_ci ri->used_index = attr.used_index; 262662306a36Sopenharmony_ci ri->ready = mvq->ready; 262762306a36Sopenharmony_ci ri->num_ent = mvq->num_ent; 262862306a36Sopenharmony_ci ri->desc_addr = mvq->desc_addr; 262962306a36Sopenharmony_ci ri->device_addr = mvq->device_addr; 263062306a36Sopenharmony_ci ri->driver_addr = mvq->driver_addr; 263162306a36Sopenharmony_ci ri->map = mvq->map; 263262306a36Sopenharmony_ci ri->restore = true; 263362306a36Sopenharmony_ci return 0; 263462306a36Sopenharmony_ci} 263562306a36Sopenharmony_ci 263662306a36Sopenharmony_cistatic int save_channels_info(struct mlx5_vdpa_net *ndev) 263762306a36Sopenharmony_ci{ 263862306a36Sopenharmony_ci int i; 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci for (i = 0; i < ndev->mvdev.max_vqs; i++) { 264162306a36Sopenharmony_ci memset(&ndev->vqs[i].ri, 0, sizeof(ndev->vqs[i].ri)); 264262306a36Sopenharmony_ci save_channel_info(ndev, &ndev->vqs[i]); 264362306a36Sopenharmony_ci } 264462306a36Sopenharmony_ci return 0; 264562306a36Sopenharmony_ci} 264662306a36Sopenharmony_ci 264762306a36Sopenharmony_cistatic void mlx5_clear_vqs(struct mlx5_vdpa_net *ndev) 264862306a36Sopenharmony_ci{ 264962306a36Sopenharmony_ci int i; 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci for (i = 0; i < ndev->mvdev.max_vqs; i++) 265262306a36Sopenharmony_ci memset(&ndev->vqs[i], 0, offsetof(struct mlx5_vdpa_virtqueue, ri)); 265362306a36Sopenharmony_ci} 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_cistatic void restore_channels_info(struct mlx5_vdpa_net *ndev) 265662306a36Sopenharmony_ci{ 265762306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq; 265862306a36Sopenharmony_ci struct mlx5_vq_restore_info *ri; 265962306a36Sopenharmony_ci int i; 266062306a36Sopenharmony_ci 266162306a36Sopenharmony_ci mlx5_clear_vqs(ndev); 266262306a36Sopenharmony_ci init_mvqs(ndev); 266362306a36Sopenharmony_ci for (i = 0; i < ndev->mvdev.max_vqs; i++) { 266462306a36Sopenharmony_ci mvq = &ndev->vqs[i]; 266562306a36Sopenharmony_ci ri = &mvq->ri; 266662306a36Sopenharmony_ci if (!ri->restore) 266762306a36Sopenharmony_ci continue; 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci mvq->avail_idx = ri->avail_index; 267062306a36Sopenharmony_ci mvq->used_idx = ri->used_index; 267162306a36Sopenharmony_ci mvq->ready = ri->ready; 267262306a36Sopenharmony_ci mvq->num_ent = ri->num_ent; 267362306a36Sopenharmony_ci mvq->desc_addr = ri->desc_addr; 267462306a36Sopenharmony_ci mvq->device_addr = ri->device_addr; 267562306a36Sopenharmony_ci mvq->driver_addr = ri->driver_addr; 267662306a36Sopenharmony_ci mvq->map = ri->map; 267762306a36Sopenharmony_ci } 267862306a36Sopenharmony_ci} 267962306a36Sopenharmony_ci 268062306a36Sopenharmony_cistatic int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, 268162306a36Sopenharmony_ci struct vhost_iotlb *iotlb, unsigned int asid) 268262306a36Sopenharmony_ci{ 268362306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 268462306a36Sopenharmony_ci int err; 268562306a36Sopenharmony_ci 268662306a36Sopenharmony_ci suspend_vqs(ndev); 268762306a36Sopenharmony_ci err = save_channels_info(ndev); 268862306a36Sopenharmony_ci if (err) 268962306a36Sopenharmony_ci goto err_mr; 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_ci teardown_driver(ndev); 269262306a36Sopenharmony_ci mlx5_vdpa_destroy_mr_asid(mvdev, asid); 269362306a36Sopenharmony_ci err = mlx5_vdpa_create_mr(mvdev, iotlb, asid); 269462306a36Sopenharmony_ci if (err) 269562306a36Sopenharmony_ci goto err_mr; 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci if (!(mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK) || mvdev->suspended) 269862306a36Sopenharmony_ci goto err_mr; 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ci restore_channels_info(ndev); 270162306a36Sopenharmony_ci err = setup_driver(mvdev); 270262306a36Sopenharmony_ci if (err) 270362306a36Sopenharmony_ci goto err_setup; 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci return 0; 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_cierr_setup: 270862306a36Sopenharmony_ci mlx5_vdpa_destroy_mr_asid(mvdev, asid); 270962306a36Sopenharmony_cierr_mr: 271062306a36Sopenharmony_ci return err; 271162306a36Sopenharmony_ci} 271262306a36Sopenharmony_ci 271362306a36Sopenharmony_ci/* reslock must be held for this function */ 271462306a36Sopenharmony_cistatic int setup_driver(struct mlx5_vdpa_dev *mvdev) 271562306a36Sopenharmony_ci{ 271662306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 271762306a36Sopenharmony_ci int err; 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci WARN_ON(!rwsem_is_locked(&ndev->reslock)); 272062306a36Sopenharmony_ci 272162306a36Sopenharmony_ci if (ndev->setup) { 272262306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "setup driver called for already setup driver\n"); 272362306a36Sopenharmony_ci err = 0; 272462306a36Sopenharmony_ci goto out; 272562306a36Sopenharmony_ci } 272662306a36Sopenharmony_ci mlx5_vdpa_add_debugfs(ndev); 272762306a36Sopenharmony_ci 272862306a36Sopenharmony_ci err = read_umem_params(ndev); 272962306a36Sopenharmony_ci if (err) 273062306a36Sopenharmony_ci goto err_setup; 273162306a36Sopenharmony_ci 273262306a36Sopenharmony_ci err = setup_virtqueues(mvdev); 273362306a36Sopenharmony_ci if (err) { 273462306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "setup_virtqueues\n"); 273562306a36Sopenharmony_ci goto err_setup; 273662306a36Sopenharmony_ci } 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci err = create_rqt(ndev); 273962306a36Sopenharmony_ci if (err) { 274062306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "create_rqt\n"); 274162306a36Sopenharmony_ci goto err_rqt; 274262306a36Sopenharmony_ci } 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci err = create_tir(ndev); 274562306a36Sopenharmony_ci if (err) { 274662306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "create_tir\n"); 274762306a36Sopenharmony_ci goto err_tir; 274862306a36Sopenharmony_ci } 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci err = setup_steering(ndev); 275162306a36Sopenharmony_ci if (err) { 275262306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "setup_steering\n"); 275362306a36Sopenharmony_ci goto err_fwd; 275462306a36Sopenharmony_ci } 275562306a36Sopenharmony_ci ndev->setup = true; 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci return 0; 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_cierr_fwd: 276062306a36Sopenharmony_ci destroy_tir(ndev); 276162306a36Sopenharmony_cierr_tir: 276262306a36Sopenharmony_ci destroy_rqt(ndev); 276362306a36Sopenharmony_cierr_rqt: 276462306a36Sopenharmony_ci teardown_virtqueues(ndev); 276562306a36Sopenharmony_cierr_setup: 276662306a36Sopenharmony_ci mlx5_vdpa_remove_debugfs(ndev); 276762306a36Sopenharmony_ciout: 276862306a36Sopenharmony_ci return err; 276962306a36Sopenharmony_ci} 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_ci/* reslock must be held for this function */ 277262306a36Sopenharmony_cistatic void teardown_driver(struct mlx5_vdpa_net *ndev) 277362306a36Sopenharmony_ci{ 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci WARN_ON(!rwsem_is_locked(&ndev->reslock)); 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci if (!ndev->setup) 277862306a36Sopenharmony_ci return; 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci mlx5_vdpa_remove_debugfs(ndev); 278162306a36Sopenharmony_ci teardown_steering(ndev); 278262306a36Sopenharmony_ci destroy_tir(ndev); 278362306a36Sopenharmony_ci destroy_rqt(ndev); 278462306a36Sopenharmony_ci teardown_virtqueues(ndev); 278562306a36Sopenharmony_ci ndev->setup = false; 278662306a36Sopenharmony_ci} 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_cistatic void clear_vqs_ready(struct mlx5_vdpa_net *ndev) 278962306a36Sopenharmony_ci{ 279062306a36Sopenharmony_ci int i; 279162306a36Sopenharmony_ci 279262306a36Sopenharmony_ci for (i = 0; i < ndev->mvdev.max_vqs; i++) 279362306a36Sopenharmony_ci ndev->vqs[i].ready = false; 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ci ndev->mvdev.cvq.ready = false; 279662306a36Sopenharmony_ci} 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_cistatic int setup_cvq_vring(struct mlx5_vdpa_dev *mvdev) 279962306a36Sopenharmony_ci{ 280062306a36Sopenharmony_ci struct mlx5_control_vq *cvq = &mvdev->cvq; 280162306a36Sopenharmony_ci int err = 0; 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_ci if (mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ)) { 280462306a36Sopenharmony_ci u16 idx = cvq->vring.last_avail_idx; 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_ci err = vringh_init_iotlb(&cvq->vring, mvdev->actual_features, 280762306a36Sopenharmony_ci cvq->vring.vring.num, false, 280862306a36Sopenharmony_ci (struct vring_desc *)(uintptr_t)cvq->desc_addr, 280962306a36Sopenharmony_ci (struct vring_avail *)(uintptr_t)cvq->driver_addr, 281062306a36Sopenharmony_ci (struct vring_used *)(uintptr_t)cvq->device_addr); 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci if (!err) 281362306a36Sopenharmony_ci cvq->vring.last_avail_idx = cvq->vring.last_used_idx = idx; 281462306a36Sopenharmony_ci } 281562306a36Sopenharmony_ci return err; 281662306a36Sopenharmony_ci} 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_cistatic void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) 281962306a36Sopenharmony_ci{ 282062306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 282162306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 282262306a36Sopenharmony_ci int err; 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci print_status(mvdev, status, true); 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_ci down_write(&ndev->reslock); 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_ci if ((status ^ ndev->mvdev.status) & VIRTIO_CONFIG_S_DRIVER_OK) { 282962306a36Sopenharmony_ci if (status & VIRTIO_CONFIG_S_DRIVER_OK) { 283062306a36Sopenharmony_ci err = setup_cvq_vring(mvdev); 283162306a36Sopenharmony_ci if (err) { 283262306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "failed to setup control VQ vring\n"); 283362306a36Sopenharmony_ci goto err_setup; 283462306a36Sopenharmony_ci } 283562306a36Sopenharmony_ci register_link_notifier(ndev); 283662306a36Sopenharmony_ci err = setup_driver(mvdev); 283762306a36Sopenharmony_ci if (err) { 283862306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "failed to setup driver\n"); 283962306a36Sopenharmony_ci goto err_driver; 284062306a36Sopenharmony_ci } 284162306a36Sopenharmony_ci } else { 284262306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "did not expect DRIVER_OK to be cleared\n"); 284362306a36Sopenharmony_ci goto err_clear; 284462306a36Sopenharmony_ci } 284562306a36Sopenharmony_ci } 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_ci ndev->mvdev.status = status; 284862306a36Sopenharmony_ci up_write(&ndev->reslock); 284962306a36Sopenharmony_ci return; 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_cierr_driver: 285262306a36Sopenharmony_ci unregister_link_notifier(ndev); 285362306a36Sopenharmony_cierr_setup: 285462306a36Sopenharmony_ci mlx5_vdpa_destroy_mr(&ndev->mvdev); 285562306a36Sopenharmony_ci ndev->mvdev.status |= VIRTIO_CONFIG_S_FAILED; 285662306a36Sopenharmony_cierr_clear: 285762306a36Sopenharmony_ci up_write(&ndev->reslock); 285862306a36Sopenharmony_ci} 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_cistatic void init_group_to_asid_map(struct mlx5_vdpa_dev *mvdev) 286162306a36Sopenharmony_ci{ 286262306a36Sopenharmony_ci int i; 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_ci /* default mapping all groups are mapped to asid 0 */ 286562306a36Sopenharmony_ci for (i = 0; i < MLX5_VDPA_NUMVQ_GROUPS; i++) 286662306a36Sopenharmony_ci mvdev->group2asid[i] = 0; 286762306a36Sopenharmony_ci} 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_cistatic int mlx5_vdpa_reset(struct vdpa_device *vdev) 287062306a36Sopenharmony_ci{ 287162306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 287262306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ci print_status(mvdev, 0, true); 287562306a36Sopenharmony_ci mlx5_vdpa_info(mvdev, "performing device reset\n"); 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_ci down_write(&ndev->reslock); 287862306a36Sopenharmony_ci unregister_link_notifier(ndev); 287962306a36Sopenharmony_ci teardown_driver(ndev); 288062306a36Sopenharmony_ci clear_vqs_ready(ndev); 288162306a36Sopenharmony_ci mlx5_vdpa_destroy_mr(&ndev->mvdev); 288262306a36Sopenharmony_ci ndev->mvdev.status = 0; 288362306a36Sopenharmony_ci ndev->mvdev.suspended = false; 288462306a36Sopenharmony_ci ndev->cur_num_vqs = 0; 288562306a36Sopenharmony_ci ndev->mvdev.cvq.received_desc = 0; 288662306a36Sopenharmony_ci ndev->mvdev.cvq.completed_desc = 0; 288762306a36Sopenharmony_ci memset(ndev->event_cbs, 0, sizeof(*ndev->event_cbs) * (mvdev->max_vqs + 1)); 288862306a36Sopenharmony_ci ndev->mvdev.actual_features = 0; 288962306a36Sopenharmony_ci init_group_to_asid_map(mvdev); 289062306a36Sopenharmony_ci ++mvdev->generation; 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) { 289362306a36Sopenharmony_ci if (mlx5_vdpa_create_mr(mvdev, NULL, 0)) 289462306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "create MR failed\n"); 289562306a36Sopenharmony_ci } 289662306a36Sopenharmony_ci up_write(&ndev->reslock); 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci return 0; 289962306a36Sopenharmony_ci} 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_cistatic size_t mlx5_vdpa_get_config_size(struct vdpa_device *vdev) 290262306a36Sopenharmony_ci{ 290362306a36Sopenharmony_ci return sizeof(struct virtio_net_config); 290462306a36Sopenharmony_ci} 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_cistatic void mlx5_vdpa_get_config(struct vdpa_device *vdev, unsigned int offset, void *buf, 290762306a36Sopenharmony_ci unsigned int len) 290862306a36Sopenharmony_ci{ 290962306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 291062306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 291162306a36Sopenharmony_ci 291262306a36Sopenharmony_ci if (offset + len <= sizeof(struct virtio_net_config)) 291362306a36Sopenharmony_ci memcpy(buf, (u8 *)&ndev->config + offset, len); 291462306a36Sopenharmony_ci} 291562306a36Sopenharmony_ci 291662306a36Sopenharmony_cistatic void mlx5_vdpa_set_config(struct vdpa_device *vdev, unsigned int offset, const void *buf, 291762306a36Sopenharmony_ci unsigned int len) 291862306a36Sopenharmony_ci{ 291962306a36Sopenharmony_ci /* not supported */ 292062306a36Sopenharmony_ci} 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_cistatic u32 mlx5_vdpa_get_generation(struct vdpa_device *vdev) 292362306a36Sopenharmony_ci{ 292462306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci return mvdev->generation; 292762306a36Sopenharmony_ci} 292862306a36Sopenharmony_ci 292962306a36Sopenharmony_cistatic int set_map_data(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb, 293062306a36Sopenharmony_ci unsigned int asid) 293162306a36Sopenharmony_ci{ 293262306a36Sopenharmony_ci bool change_map; 293362306a36Sopenharmony_ci int err; 293462306a36Sopenharmony_ci 293562306a36Sopenharmony_ci err = mlx5_vdpa_handle_set_map(mvdev, iotlb, &change_map, asid); 293662306a36Sopenharmony_ci if (err) { 293762306a36Sopenharmony_ci mlx5_vdpa_warn(mvdev, "set map failed(%d)\n", err); 293862306a36Sopenharmony_ci return err; 293962306a36Sopenharmony_ci } 294062306a36Sopenharmony_ci 294162306a36Sopenharmony_ci if (change_map) 294262306a36Sopenharmony_ci err = mlx5_vdpa_change_map(mvdev, iotlb, asid); 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_ci return err; 294562306a36Sopenharmony_ci} 294662306a36Sopenharmony_ci 294762306a36Sopenharmony_cistatic int mlx5_vdpa_set_map(struct vdpa_device *vdev, unsigned int asid, 294862306a36Sopenharmony_ci struct vhost_iotlb *iotlb) 294962306a36Sopenharmony_ci{ 295062306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 295162306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 295262306a36Sopenharmony_ci int err = -EINVAL; 295362306a36Sopenharmony_ci 295462306a36Sopenharmony_ci down_write(&ndev->reslock); 295562306a36Sopenharmony_ci err = set_map_data(mvdev, iotlb, asid); 295662306a36Sopenharmony_ci up_write(&ndev->reslock); 295762306a36Sopenharmony_ci return err; 295862306a36Sopenharmony_ci} 295962306a36Sopenharmony_ci 296062306a36Sopenharmony_cistatic struct device *mlx5_get_vq_dma_dev(struct vdpa_device *vdev, u16 idx) 296162306a36Sopenharmony_ci{ 296262306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci if (is_ctrl_vq_idx(mvdev, idx)) 296562306a36Sopenharmony_ci return &vdev->dev; 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci return mvdev->vdev.dma_dev; 296862306a36Sopenharmony_ci} 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_cistatic void free_irqs(struct mlx5_vdpa_net *ndev) 297162306a36Sopenharmony_ci{ 297262306a36Sopenharmony_ci struct mlx5_vdpa_irq_pool_entry *ent; 297362306a36Sopenharmony_ci int i; 297462306a36Sopenharmony_ci 297562306a36Sopenharmony_ci if (!msix_mode_supported(&ndev->mvdev)) 297662306a36Sopenharmony_ci return; 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_ci if (!ndev->irqp.entries) 297962306a36Sopenharmony_ci return; 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci for (i = ndev->irqp.num_ent - 1; i >= 0; i--) { 298262306a36Sopenharmony_ci ent = ndev->irqp.entries + i; 298362306a36Sopenharmony_ci if (ent->map.virq) 298462306a36Sopenharmony_ci pci_msix_free_irq(ndev->mvdev.mdev->pdev, ent->map); 298562306a36Sopenharmony_ci } 298662306a36Sopenharmony_ci kfree(ndev->irqp.entries); 298762306a36Sopenharmony_ci} 298862306a36Sopenharmony_ci 298962306a36Sopenharmony_cistatic void mlx5_vdpa_free(struct vdpa_device *vdev) 299062306a36Sopenharmony_ci{ 299162306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 299262306a36Sopenharmony_ci struct mlx5_core_dev *pfmdev; 299362306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev; 299462306a36Sopenharmony_ci 299562306a36Sopenharmony_ci ndev = to_mlx5_vdpa_ndev(mvdev); 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci free_resources(ndev); 299862306a36Sopenharmony_ci mlx5_vdpa_destroy_mr(mvdev); 299962306a36Sopenharmony_ci if (!is_zero_ether_addr(ndev->config.mac)) { 300062306a36Sopenharmony_ci pfmdev = pci_get_drvdata(pci_physfn(mvdev->mdev->pdev)); 300162306a36Sopenharmony_ci mlx5_mpfs_del_mac(pfmdev, ndev->config.mac); 300262306a36Sopenharmony_ci } 300362306a36Sopenharmony_ci mlx5_vdpa_free_resources(&ndev->mvdev); 300462306a36Sopenharmony_ci free_irqs(ndev); 300562306a36Sopenharmony_ci kfree(ndev->event_cbs); 300662306a36Sopenharmony_ci kfree(ndev->vqs); 300762306a36Sopenharmony_ci} 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_cistatic struct vdpa_notification_area mlx5_get_vq_notification(struct vdpa_device *vdev, u16 idx) 301062306a36Sopenharmony_ci{ 301162306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 301262306a36Sopenharmony_ci struct vdpa_notification_area ret = {}; 301362306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev; 301462306a36Sopenharmony_ci phys_addr_t addr; 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_ci if (!is_index_valid(mvdev, idx) || is_ctrl_vq_idx(mvdev, idx)) 301762306a36Sopenharmony_ci return ret; 301862306a36Sopenharmony_ci 301962306a36Sopenharmony_ci /* If SF BAR size is smaller than PAGE_SIZE, do not use direct 302062306a36Sopenharmony_ci * notification to avoid the risk of mapping pages that contain BAR of more 302162306a36Sopenharmony_ci * than one SF 302262306a36Sopenharmony_ci */ 302362306a36Sopenharmony_ci if (MLX5_CAP_GEN(mvdev->mdev, log_min_sf_size) + 12 < PAGE_SHIFT) 302462306a36Sopenharmony_ci return ret; 302562306a36Sopenharmony_ci 302662306a36Sopenharmony_ci ndev = to_mlx5_vdpa_ndev(mvdev); 302762306a36Sopenharmony_ci addr = (phys_addr_t)ndev->mvdev.res.phys_kick_addr; 302862306a36Sopenharmony_ci ret.addr = addr; 302962306a36Sopenharmony_ci ret.size = PAGE_SIZE; 303062306a36Sopenharmony_ci return ret; 303162306a36Sopenharmony_ci} 303262306a36Sopenharmony_ci 303362306a36Sopenharmony_cistatic int mlx5_get_vq_irq(struct vdpa_device *vdev, u16 idx) 303462306a36Sopenharmony_ci{ 303562306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 303662306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 303762306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq; 303862306a36Sopenharmony_ci 303962306a36Sopenharmony_ci if (!is_index_valid(mvdev, idx)) 304062306a36Sopenharmony_ci return -EINVAL; 304162306a36Sopenharmony_ci 304262306a36Sopenharmony_ci if (is_ctrl_vq_idx(mvdev, idx)) 304362306a36Sopenharmony_ci return -EOPNOTSUPP; 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ci mvq = &ndev->vqs[idx]; 304662306a36Sopenharmony_ci if (!mvq->map.virq) 304762306a36Sopenharmony_ci return -EOPNOTSUPP; 304862306a36Sopenharmony_ci 304962306a36Sopenharmony_ci return mvq->map.virq; 305062306a36Sopenharmony_ci} 305162306a36Sopenharmony_ci 305262306a36Sopenharmony_cistatic u64 mlx5_vdpa_get_driver_features(struct vdpa_device *vdev) 305362306a36Sopenharmony_ci{ 305462306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_ci return mvdev->actual_features; 305762306a36Sopenharmony_ci} 305862306a36Sopenharmony_ci 305962306a36Sopenharmony_cistatic int counter_set_query(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, 306062306a36Sopenharmony_ci u64 *received_desc, u64 *completed_desc) 306162306a36Sopenharmony_ci{ 306262306a36Sopenharmony_ci u32 in[MLX5_ST_SZ_DW(query_virtio_q_counters_in)] = {}; 306362306a36Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(query_virtio_q_counters_out)] = {}; 306462306a36Sopenharmony_ci void *cmd_hdr; 306562306a36Sopenharmony_ci void *ctx; 306662306a36Sopenharmony_ci int err; 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci if (!counters_supported(&ndev->mvdev)) 306962306a36Sopenharmony_ci return -EOPNOTSUPP; 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY) 307262306a36Sopenharmony_ci return -EAGAIN; 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ci cmd_hdr = MLX5_ADDR_OF(query_virtio_q_counters_in, in, hdr); 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_QUERY_GENERAL_OBJECT); 307762306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_Q_COUNTERS); 307862306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 307962306a36Sopenharmony_ci MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_id, mvq->counter_set_id); 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_ci err = mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out)); 308262306a36Sopenharmony_ci if (err) 308362306a36Sopenharmony_ci return err; 308462306a36Sopenharmony_ci 308562306a36Sopenharmony_ci ctx = MLX5_ADDR_OF(query_virtio_q_counters_out, out, counters); 308662306a36Sopenharmony_ci *received_desc = MLX5_GET64(virtio_q_counters, ctx, received_desc); 308762306a36Sopenharmony_ci *completed_desc = MLX5_GET64(virtio_q_counters, ctx, completed_desc); 308862306a36Sopenharmony_ci return 0; 308962306a36Sopenharmony_ci} 309062306a36Sopenharmony_ci 309162306a36Sopenharmony_cistatic int mlx5_vdpa_get_vendor_vq_stats(struct vdpa_device *vdev, u16 idx, 309262306a36Sopenharmony_ci struct sk_buff *msg, 309362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 309462306a36Sopenharmony_ci{ 309562306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 309662306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 309762306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq; 309862306a36Sopenharmony_ci struct mlx5_control_vq *cvq; 309962306a36Sopenharmony_ci u64 received_desc; 310062306a36Sopenharmony_ci u64 completed_desc; 310162306a36Sopenharmony_ci int err = 0; 310262306a36Sopenharmony_ci 310362306a36Sopenharmony_ci down_read(&ndev->reslock); 310462306a36Sopenharmony_ci if (!is_index_valid(mvdev, idx)) { 310562306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "virtqueue index is not valid"); 310662306a36Sopenharmony_ci err = -EINVAL; 310762306a36Sopenharmony_ci goto out_err; 310862306a36Sopenharmony_ci } 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci if (idx == ctrl_vq_idx(mvdev)) { 311162306a36Sopenharmony_ci cvq = &mvdev->cvq; 311262306a36Sopenharmony_ci received_desc = cvq->received_desc; 311362306a36Sopenharmony_ci completed_desc = cvq->completed_desc; 311462306a36Sopenharmony_ci goto out; 311562306a36Sopenharmony_ci } 311662306a36Sopenharmony_ci 311762306a36Sopenharmony_ci mvq = &ndev->vqs[idx]; 311862306a36Sopenharmony_ci err = counter_set_query(ndev, mvq, &received_desc, &completed_desc); 311962306a36Sopenharmony_ci if (err) { 312062306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "failed to query hardware"); 312162306a36Sopenharmony_ci goto out_err; 312262306a36Sopenharmony_ci } 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_ciout: 312562306a36Sopenharmony_ci err = -EMSGSIZE; 312662306a36Sopenharmony_ci if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME, "received_desc")) 312762306a36Sopenharmony_ci goto out_err; 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE, received_desc, 313062306a36Sopenharmony_ci VDPA_ATTR_PAD)) 313162306a36Sopenharmony_ci goto out_err; 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_ci if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME, "completed_desc")) 313462306a36Sopenharmony_ci goto out_err; 313562306a36Sopenharmony_ci 313662306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE, completed_desc, 313762306a36Sopenharmony_ci VDPA_ATTR_PAD)) 313862306a36Sopenharmony_ci goto out_err; 313962306a36Sopenharmony_ci 314062306a36Sopenharmony_ci err = 0; 314162306a36Sopenharmony_ciout_err: 314262306a36Sopenharmony_ci up_read(&ndev->reslock); 314362306a36Sopenharmony_ci return err; 314462306a36Sopenharmony_ci} 314562306a36Sopenharmony_ci 314662306a36Sopenharmony_cistatic void mlx5_vdpa_cvq_suspend(struct mlx5_vdpa_dev *mvdev) 314762306a36Sopenharmony_ci{ 314862306a36Sopenharmony_ci struct mlx5_control_vq *cvq; 314962306a36Sopenharmony_ci 315062306a36Sopenharmony_ci if (!(mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) 315162306a36Sopenharmony_ci return; 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci cvq = &mvdev->cvq; 315462306a36Sopenharmony_ci cvq->ready = false; 315562306a36Sopenharmony_ci} 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_cistatic int mlx5_vdpa_suspend(struct vdpa_device *vdev) 315862306a36Sopenharmony_ci{ 315962306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 316062306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 316162306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq; 316262306a36Sopenharmony_ci int i; 316362306a36Sopenharmony_ci 316462306a36Sopenharmony_ci mlx5_vdpa_info(mvdev, "suspending device\n"); 316562306a36Sopenharmony_ci 316662306a36Sopenharmony_ci down_write(&ndev->reslock); 316762306a36Sopenharmony_ci unregister_link_notifier(ndev); 316862306a36Sopenharmony_ci for (i = 0; i < ndev->cur_num_vqs; i++) { 316962306a36Sopenharmony_ci mvq = &ndev->vqs[i]; 317062306a36Sopenharmony_ci suspend_vq(ndev, mvq); 317162306a36Sopenharmony_ci } 317262306a36Sopenharmony_ci mlx5_vdpa_cvq_suspend(mvdev); 317362306a36Sopenharmony_ci mvdev->suspended = true; 317462306a36Sopenharmony_ci up_write(&ndev->reslock); 317562306a36Sopenharmony_ci return 0; 317662306a36Sopenharmony_ci} 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_cistatic int mlx5_set_group_asid(struct vdpa_device *vdev, u32 group, 317962306a36Sopenharmony_ci unsigned int asid) 318062306a36Sopenharmony_ci{ 318162306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 318262306a36Sopenharmony_ci 318362306a36Sopenharmony_ci if (group >= MLX5_VDPA_NUMVQ_GROUPS) 318462306a36Sopenharmony_ci return -EINVAL; 318562306a36Sopenharmony_ci 318662306a36Sopenharmony_ci mvdev->group2asid[group] = asid; 318762306a36Sopenharmony_ci return 0; 318862306a36Sopenharmony_ci} 318962306a36Sopenharmony_ci 319062306a36Sopenharmony_cistatic const struct vdpa_config_ops mlx5_vdpa_ops = { 319162306a36Sopenharmony_ci .set_vq_address = mlx5_vdpa_set_vq_address, 319262306a36Sopenharmony_ci .set_vq_num = mlx5_vdpa_set_vq_num, 319362306a36Sopenharmony_ci .kick_vq = mlx5_vdpa_kick_vq, 319462306a36Sopenharmony_ci .set_vq_cb = mlx5_vdpa_set_vq_cb, 319562306a36Sopenharmony_ci .set_vq_ready = mlx5_vdpa_set_vq_ready, 319662306a36Sopenharmony_ci .get_vq_ready = mlx5_vdpa_get_vq_ready, 319762306a36Sopenharmony_ci .set_vq_state = mlx5_vdpa_set_vq_state, 319862306a36Sopenharmony_ci .get_vq_state = mlx5_vdpa_get_vq_state, 319962306a36Sopenharmony_ci .get_vendor_vq_stats = mlx5_vdpa_get_vendor_vq_stats, 320062306a36Sopenharmony_ci .get_vq_notification = mlx5_get_vq_notification, 320162306a36Sopenharmony_ci .get_vq_irq = mlx5_get_vq_irq, 320262306a36Sopenharmony_ci .get_vq_align = mlx5_vdpa_get_vq_align, 320362306a36Sopenharmony_ci .get_vq_group = mlx5_vdpa_get_vq_group, 320462306a36Sopenharmony_ci .get_device_features = mlx5_vdpa_get_device_features, 320562306a36Sopenharmony_ci .set_driver_features = mlx5_vdpa_set_driver_features, 320662306a36Sopenharmony_ci .get_driver_features = mlx5_vdpa_get_driver_features, 320762306a36Sopenharmony_ci .set_config_cb = mlx5_vdpa_set_config_cb, 320862306a36Sopenharmony_ci .get_vq_num_max = mlx5_vdpa_get_vq_num_max, 320962306a36Sopenharmony_ci .get_device_id = mlx5_vdpa_get_device_id, 321062306a36Sopenharmony_ci .get_vendor_id = mlx5_vdpa_get_vendor_id, 321162306a36Sopenharmony_ci .get_status = mlx5_vdpa_get_status, 321262306a36Sopenharmony_ci .set_status = mlx5_vdpa_set_status, 321362306a36Sopenharmony_ci .reset = mlx5_vdpa_reset, 321462306a36Sopenharmony_ci .get_config_size = mlx5_vdpa_get_config_size, 321562306a36Sopenharmony_ci .get_config = mlx5_vdpa_get_config, 321662306a36Sopenharmony_ci .set_config = mlx5_vdpa_set_config, 321762306a36Sopenharmony_ci .get_generation = mlx5_vdpa_get_generation, 321862306a36Sopenharmony_ci .set_map = mlx5_vdpa_set_map, 321962306a36Sopenharmony_ci .set_group_asid = mlx5_set_group_asid, 322062306a36Sopenharmony_ci .get_vq_dma_dev = mlx5_get_vq_dma_dev, 322162306a36Sopenharmony_ci .free = mlx5_vdpa_free, 322262306a36Sopenharmony_ci .suspend = mlx5_vdpa_suspend, 322362306a36Sopenharmony_ci}; 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_cistatic int query_mtu(struct mlx5_core_dev *mdev, u16 *mtu) 322662306a36Sopenharmony_ci{ 322762306a36Sopenharmony_ci u16 hw_mtu; 322862306a36Sopenharmony_ci int err; 322962306a36Sopenharmony_ci 323062306a36Sopenharmony_ci err = mlx5_query_nic_vport_mtu(mdev, &hw_mtu); 323162306a36Sopenharmony_ci if (err) 323262306a36Sopenharmony_ci return err; 323362306a36Sopenharmony_ci 323462306a36Sopenharmony_ci *mtu = hw_mtu - MLX5V_ETH_HARD_MTU; 323562306a36Sopenharmony_ci return 0; 323662306a36Sopenharmony_ci} 323762306a36Sopenharmony_ci 323862306a36Sopenharmony_cistatic int alloc_resources(struct mlx5_vdpa_net *ndev) 323962306a36Sopenharmony_ci{ 324062306a36Sopenharmony_ci struct mlx5_vdpa_net_resources *res = &ndev->res; 324162306a36Sopenharmony_ci int err; 324262306a36Sopenharmony_ci 324362306a36Sopenharmony_ci if (res->valid) { 324462306a36Sopenharmony_ci mlx5_vdpa_warn(&ndev->mvdev, "resources already allocated\n"); 324562306a36Sopenharmony_ci return -EEXIST; 324662306a36Sopenharmony_ci } 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci err = mlx5_vdpa_alloc_transport_domain(&ndev->mvdev, &res->tdn); 324962306a36Sopenharmony_ci if (err) 325062306a36Sopenharmony_ci return err; 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_ci err = create_tis(ndev); 325362306a36Sopenharmony_ci if (err) 325462306a36Sopenharmony_ci goto err_tis; 325562306a36Sopenharmony_ci 325662306a36Sopenharmony_ci res->valid = true; 325762306a36Sopenharmony_ci 325862306a36Sopenharmony_ci return 0; 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_cierr_tis: 326162306a36Sopenharmony_ci mlx5_vdpa_dealloc_transport_domain(&ndev->mvdev, res->tdn); 326262306a36Sopenharmony_ci return err; 326362306a36Sopenharmony_ci} 326462306a36Sopenharmony_ci 326562306a36Sopenharmony_cistatic void free_resources(struct mlx5_vdpa_net *ndev) 326662306a36Sopenharmony_ci{ 326762306a36Sopenharmony_ci struct mlx5_vdpa_net_resources *res = &ndev->res; 326862306a36Sopenharmony_ci 326962306a36Sopenharmony_ci if (!res->valid) 327062306a36Sopenharmony_ci return; 327162306a36Sopenharmony_ci 327262306a36Sopenharmony_ci destroy_tis(ndev); 327362306a36Sopenharmony_ci mlx5_vdpa_dealloc_transport_domain(&ndev->mvdev, res->tdn); 327462306a36Sopenharmony_ci res->valid = false; 327562306a36Sopenharmony_ci} 327662306a36Sopenharmony_ci 327762306a36Sopenharmony_cistatic void init_mvqs(struct mlx5_vdpa_net *ndev) 327862306a36Sopenharmony_ci{ 327962306a36Sopenharmony_ci struct mlx5_vdpa_virtqueue *mvq; 328062306a36Sopenharmony_ci int i; 328162306a36Sopenharmony_ci 328262306a36Sopenharmony_ci for (i = 0; i < ndev->mvdev.max_vqs; ++i) { 328362306a36Sopenharmony_ci mvq = &ndev->vqs[i]; 328462306a36Sopenharmony_ci memset(mvq, 0, offsetof(struct mlx5_vdpa_virtqueue, ri)); 328562306a36Sopenharmony_ci mvq->index = i; 328662306a36Sopenharmony_ci mvq->ndev = ndev; 328762306a36Sopenharmony_ci mvq->fwqp.fw = true; 328862306a36Sopenharmony_ci mvq->fw_state = MLX5_VIRTIO_NET_Q_OBJECT_NONE; 328962306a36Sopenharmony_ci } 329062306a36Sopenharmony_ci for (; i < ndev->mvdev.max_vqs; i++) { 329162306a36Sopenharmony_ci mvq = &ndev->vqs[i]; 329262306a36Sopenharmony_ci memset(mvq, 0, offsetof(struct mlx5_vdpa_virtqueue, ri)); 329362306a36Sopenharmony_ci mvq->index = i; 329462306a36Sopenharmony_ci mvq->ndev = ndev; 329562306a36Sopenharmony_ci } 329662306a36Sopenharmony_ci} 329762306a36Sopenharmony_ci 329862306a36Sopenharmony_cistruct mlx5_vdpa_mgmtdev { 329962306a36Sopenharmony_ci struct vdpa_mgmt_dev mgtdev; 330062306a36Sopenharmony_ci struct mlx5_adev *madev; 330162306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev; 330262306a36Sopenharmony_ci}; 330362306a36Sopenharmony_ci 330462306a36Sopenharmony_cistatic int config_func_mtu(struct mlx5_core_dev *mdev, u16 mtu) 330562306a36Sopenharmony_ci{ 330662306a36Sopenharmony_ci int inlen = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in); 330762306a36Sopenharmony_ci void *in; 330862306a36Sopenharmony_ci int err; 330962306a36Sopenharmony_ci 331062306a36Sopenharmony_ci in = kvzalloc(inlen, GFP_KERNEL); 331162306a36Sopenharmony_ci if (!in) 331262306a36Sopenharmony_ci return -ENOMEM; 331362306a36Sopenharmony_ci 331462306a36Sopenharmony_ci MLX5_SET(modify_nic_vport_context_in, in, field_select.mtu, 1); 331562306a36Sopenharmony_ci MLX5_SET(modify_nic_vport_context_in, in, nic_vport_context.mtu, 331662306a36Sopenharmony_ci mtu + MLX5V_ETH_HARD_MTU); 331762306a36Sopenharmony_ci MLX5_SET(modify_nic_vport_context_in, in, opcode, 331862306a36Sopenharmony_ci MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT); 331962306a36Sopenharmony_ci 332062306a36Sopenharmony_ci err = mlx5_cmd_exec_in(mdev, modify_nic_vport_context, in); 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_ci kvfree(in); 332362306a36Sopenharmony_ci return err; 332462306a36Sopenharmony_ci} 332562306a36Sopenharmony_ci 332662306a36Sopenharmony_cistatic void allocate_irqs(struct mlx5_vdpa_net *ndev) 332762306a36Sopenharmony_ci{ 332862306a36Sopenharmony_ci struct mlx5_vdpa_irq_pool_entry *ent; 332962306a36Sopenharmony_ci int i; 333062306a36Sopenharmony_ci 333162306a36Sopenharmony_ci if (!msix_mode_supported(&ndev->mvdev)) 333262306a36Sopenharmony_ci return; 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci if (!ndev->mvdev.mdev->pdev) 333562306a36Sopenharmony_ci return; 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci ndev->irqp.entries = kcalloc(ndev->mvdev.max_vqs, sizeof(*ndev->irqp.entries), GFP_KERNEL); 333862306a36Sopenharmony_ci if (!ndev->irqp.entries) 333962306a36Sopenharmony_ci return; 334062306a36Sopenharmony_ci 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ci for (i = 0; i < ndev->mvdev.max_vqs; i++) { 334362306a36Sopenharmony_ci ent = ndev->irqp.entries + i; 334462306a36Sopenharmony_ci snprintf(ent->name, MLX5_VDPA_IRQ_NAME_LEN, "%s-vq-%d", 334562306a36Sopenharmony_ci dev_name(&ndev->mvdev.vdev.dev), i); 334662306a36Sopenharmony_ci ent->map = pci_msix_alloc_irq_at(ndev->mvdev.mdev->pdev, MSI_ANY_INDEX, NULL); 334762306a36Sopenharmony_ci if (!ent->map.virq) 334862306a36Sopenharmony_ci return; 334962306a36Sopenharmony_ci 335062306a36Sopenharmony_ci ndev->irqp.num_ent++; 335162306a36Sopenharmony_ci } 335262306a36Sopenharmony_ci} 335362306a36Sopenharmony_ci 335462306a36Sopenharmony_cistatic int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, 335562306a36Sopenharmony_ci const struct vdpa_dev_set_config *add_config) 335662306a36Sopenharmony_ci{ 335762306a36Sopenharmony_ci struct mlx5_vdpa_mgmtdev *mgtdev = container_of(v_mdev, struct mlx5_vdpa_mgmtdev, mgtdev); 335862306a36Sopenharmony_ci struct virtio_net_config *config; 335962306a36Sopenharmony_ci struct mlx5_core_dev *pfmdev; 336062306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev; 336162306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev; 336262306a36Sopenharmony_ci struct mlx5_core_dev *mdev; 336362306a36Sopenharmony_ci u64 device_features; 336462306a36Sopenharmony_ci u32 max_vqs; 336562306a36Sopenharmony_ci u16 mtu; 336662306a36Sopenharmony_ci int err; 336762306a36Sopenharmony_ci 336862306a36Sopenharmony_ci if (mgtdev->ndev) 336962306a36Sopenharmony_ci return -ENOSPC; 337062306a36Sopenharmony_ci 337162306a36Sopenharmony_ci mdev = mgtdev->madev->mdev; 337262306a36Sopenharmony_ci device_features = mgtdev->mgtdev.supported_features; 337362306a36Sopenharmony_ci if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) { 337462306a36Sopenharmony_ci if (add_config->device_features & ~device_features) { 337562306a36Sopenharmony_ci dev_warn(mdev->device, 337662306a36Sopenharmony_ci "The provisioned features 0x%llx are not supported by this device with features 0x%llx\n", 337762306a36Sopenharmony_ci add_config->device_features, device_features); 337862306a36Sopenharmony_ci return -EINVAL; 337962306a36Sopenharmony_ci } 338062306a36Sopenharmony_ci device_features &= add_config->device_features; 338162306a36Sopenharmony_ci } else { 338262306a36Sopenharmony_ci device_features &= ~BIT_ULL(VIRTIO_NET_F_MRG_RXBUF); 338362306a36Sopenharmony_ci } 338462306a36Sopenharmony_ci if (!(device_features & BIT_ULL(VIRTIO_F_VERSION_1) && 338562306a36Sopenharmony_ci device_features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM))) { 338662306a36Sopenharmony_ci dev_warn(mdev->device, 338762306a36Sopenharmony_ci "Must provision minimum features 0x%llx for this device", 338862306a36Sopenharmony_ci BIT_ULL(VIRTIO_F_VERSION_1) | BIT_ULL(VIRTIO_F_ACCESS_PLATFORM)); 338962306a36Sopenharmony_ci return -EOPNOTSUPP; 339062306a36Sopenharmony_ci } 339162306a36Sopenharmony_ci 339262306a36Sopenharmony_ci if (!(MLX5_CAP_DEV_VDPA_EMULATION(mdev, virtio_queue_type) & 339362306a36Sopenharmony_ci MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_SPLIT)) { 339462306a36Sopenharmony_ci dev_warn(mdev->device, "missing support for split virtqueues\n"); 339562306a36Sopenharmony_ci return -EOPNOTSUPP; 339662306a36Sopenharmony_ci } 339762306a36Sopenharmony_ci 339862306a36Sopenharmony_ci max_vqs = min_t(int, MLX5_CAP_DEV_VDPA_EMULATION(mdev, max_num_virtio_queues), 339962306a36Sopenharmony_ci 1 << MLX5_CAP_GEN(mdev, log_max_rqt_size)); 340062306a36Sopenharmony_ci if (max_vqs < 2) { 340162306a36Sopenharmony_ci dev_warn(mdev->device, 340262306a36Sopenharmony_ci "%d virtqueues are supported. At least 2 are required\n", 340362306a36Sopenharmony_ci max_vqs); 340462306a36Sopenharmony_ci return -EAGAIN; 340562306a36Sopenharmony_ci } 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP)) { 340862306a36Sopenharmony_ci if (add_config->net.max_vq_pairs > max_vqs / 2) 340962306a36Sopenharmony_ci return -EINVAL; 341062306a36Sopenharmony_ci max_vqs = min_t(u32, max_vqs, 2 * add_config->net.max_vq_pairs); 341162306a36Sopenharmony_ci } else { 341262306a36Sopenharmony_ci max_vqs = 2; 341362306a36Sopenharmony_ci } 341462306a36Sopenharmony_ci 341562306a36Sopenharmony_ci ndev = vdpa_alloc_device(struct mlx5_vdpa_net, mvdev.vdev, mdev->device, &mlx5_vdpa_ops, 341662306a36Sopenharmony_ci MLX5_VDPA_NUMVQ_GROUPS, MLX5_VDPA_NUM_AS, name, false); 341762306a36Sopenharmony_ci if (IS_ERR(ndev)) 341862306a36Sopenharmony_ci return PTR_ERR(ndev); 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci ndev->mvdev.max_vqs = max_vqs; 342162306a36Sopenharmony_ci mvdev = &ndev->mvdev; 342262306a36Sopenharmony_ci mvdev->mdev = mdev; 342362306a36Sopenharmony_ci 342462306a36Sopenharmony_ci ndev->vqs = kcalloc(max_vqs, sizeof(*ndev->vqs), GFP_KERNEL); 342562306a36Sopenharmony_ci ndev->event_cbs = kcalloc(max_vqs + 1, sizeof(*ndev->event_cbs), GFP_KERNEL); 342662306a36Sopenharmony_ci if (!ndev->vqs || !ndev->event_cbs) { 342762306a36Sopenharmony_ci err = -ENOMEM; 342862306a36Sopenharmony_ci goto err_alloc; 342962306a36Sopenharmony_ci } 343062306a36Sopenharmony_ci 343162306a36Sopenharmony_ci init_mvqs(ndev); 343262306a36Sopenharmony_ci allocate_irqs(ndev); 343362306a36Sopenharmony_ci init_rwsem(&ndev->reslock); 343462306a36Sopenharmony_ci config = &ndev->config; 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MTU)) { 343762306a36Sopenharmony_ci err = config_func_mtu(mdev, add_config->net.mtu); 343862306a36Sopenharmony_ci if (err) 343962306a36Sopenharmony_ci goto err_alloc; 344062306a36Sopenharmony_ci } 344162306a36Sopenharmony_ci 344262306a36Sopenharmony_ci if (device_features & BIT_ULL(VIRTIO_NET_F_MTU)) { 344362306a36Sopenharmony_ci err = query_mtu(mdev, &mtu); 344462306a36Sopenharmony_ci if (err) 344562306a36Sopenharmony_ci goto err_alloc; 344662306a36Sopenharmony_ci 344762306a36Sopenharmony_ci ndev->config.mtu = cpu_to_mlx5vdpa16(mvdev, mtu); 344862306a36Sopenharmony_ci } 344962306a36Sopenharmony_ci 345062306a36Sopenharmony_ci if (device_features & BIT_ULL(VIRTIO_NET_F_STATUS)) { 345162306a36Sopenharmony_ci if (get_link_state(mvdev)) 345262306a36Sopenharmony_ci ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP); 345362306a36Sopenharmony_ci else 345462306a36Sopenharmony_ci ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP); 345562306a36Sopenharmony_ci } 345662306a36Sopenharmony_ci 345762306a36Sopenharmony_ci if (add_config->mask & (1 << VDPA_ATTR_DEV_NET_CFG_MACADDR)) { 345862306a36Sopenharmony_ci memcpy(ndev->config.mac, add_config->net.mac, ETH_ALEN); 345962306a36Sopenharmony_ci /* No bother setting mac address in config if not going to provision _F_MAC */ 346062306a36Sopenharmony_ci } else if ((add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) == 0 || 346162306a36Sopenharmony_ci device_features & BIT_ULL(VIRTIO_NET_F_MAC)) { 346262306a36Sopenharmony_ci err = mlx5_query_nic_vport_mac_address(mdev, 0, 0, config->mac); 346362306a36Sopenharmony_ci if (err) 346462306a36Sopenharmony_ci goto err_alloc; 346562306a36Sopenharmony_ci } 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ci if (!is_zero_ether_addr(config->mac)) { 346862306a36Sopenharmony_ci pfmdev = pci_get_drvdata(pci_physfn(mdev->pdev)); 346962306a36Sopenharmony_ci err = mlx5_mpfs_add_mac(pfmdev, config->mac); 347062306a36Sopenharmony_ci if (err) 347162306a36Sopenharmony_ci goto err_alloc; 347262306a36Sopenharmony_ci } else if ((add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) == 0) { 347362306a36Sopenharmony_ci /* 347462306a36Sopenharmony_ci * We used to clear _F_MAC feature bit if seeing 347562306a36Sopenharmony_ci * zero mac address when device features are not 347662306a36Sopenharmony_ci * specifically provisioned. Keep the behaviour 347762306a36Sopenharmony_ci * so old scripts do not break. 347862306a36Sopenharmony_ci */ 347962306a36Sopenharmony_ci device_features &= ~BIT_ULL(VIRTIO_NET_F_MAC); 348062306a36Sopenharmony_ci } else if (device_features & BIT_ULL(VIRTIO_NET_F_MAC)) { 348162306a36Sopenharmony_ci /* Don't provision zero mac address for _F_MAC */ 348262306a36Sopenharmony_ci mlx5_vdpa_warn(&ndev->mvdev, 348362306a36Sopenharmony_ci "No mac address provisioned?\n"); 348462306a36Sopenharmony_ci err = -EINVAL; 348562306a36Sopenharmony_ci goto err_alloc; 348662306a36Sopenharmony_ci } 348762306a36Sopenharmony_ci 348862306a36Sopenharmony_ci if (device_features & BIT_ULL(VIRTIO_NET_F_MQ)) 348962306a36Sopenharmony_ci config->max_virtqueue_pairs = cpu_to_mlx5vdpa16(mvdev, max_vqs / 2); 349062306a36Sopenharmony_ci 349162306a36Sopenharmony_ci ndev->mvdev.mlx_features = device_features; 349262306a36Sopenharmony_ci mvdev->vdev.dma_dev = &mdev->pdev->dev; 349362306a36Sopenharmony_ci err = mlx5_vdpa_alloc_resources(&ndev->mvdev); 349462306a36Sopenharmony_ci if (err) 349562306a36Sopenharmony_ci goto err_mpfs; 349662306a36Sopenharmony_ci 349762306a36Sopenharmony_ci if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) { 349862306a36Sopenharmony_ci err = mlx5_vdpa_create_mr(mvdev, NULL, 0); 349962306a36Sopenharmony_ci if (err) 350062306a36Sopenharmony_ci goto err_res; 350162306a36Sopenharmony_ci } 350262306a36Sopenharmony_ci 350362306a36Sopenharmony_ci err = alloc_resources(ndev); 350462306a36Sopenharmony_ci if (err) 350562306a36Sopenharmony_ci goto err_mr; 350662306a36Sopenharmony_ci 350762306a36Sopenharmony_ci ndev->cvq_ent.mvdev = mvdev; 350862306a36Sopenharmony_ci INIT_WORK(&ndev->cvq_ent.work, mlx5_cvq_kick_handler); 350962306a36Sopenharmony_ci mvdev->wq = create_singlethread_workqueue("mlx5_vdpa_wq"); 351062306a36Sopenharmony_ci if (!mvdev->wq) { 351162306a36Sopenharmony_ci err = -ENOMEM; 351262306a36Sopenharmony_ci goto err_res2; 351362306a36Sopenharmony_ci } 351462306a36Sopenharmony_ci 351562306a36Sopenharmony_ci mvdev->vdev.mdev = &mgtdev->mgtdev; 351662306a36Sopenharmony_ci err = _vdpa_register_device(&mvdev->vdev, max_vqs + 1); 351762306a36Sopenharmony_ci if (err) 351862306a36Sopenharmony_ci goto err_reg; 351962306a36Sopenharmony_ci 352062306a36Sopenharmony_ci mgtdev->ndev = ndev; 352162306a36Sopenharmony_ci return 0; 352262306a36Sopenharmony_ci 352362306a36Sopenharmony_cierr_reg: 352462306a36Sopenharmony_ci destroy_workqueue(mvdev->wq); 352562306a36Sopenharmony_cierr_res2: 352662306a36Sopenharmony_ci free_resources(ndev); 352762306a36Sopenharmony_cierr_mr: 352862306a36Sopenharmony_ci mlx5_vdpa_destroy_mr(mvdev); 352962306a36Sopenharmony_cierr_res: 353062306a36Sopenharmony_ci mlx5_vdpa_free_resources(&ndev->mvdev); 353162306a36Sopenharmony_cierr_mpfs: 353262306a36Sopenharmony_ci if (!is_zero_ether_addr(config->mac)) 353362306a36Sopenharmony_ci mlx5_mpfs_del_mac(pfmdev, config->mac); 353462306a36Sopenharmony_cierr_alloc: 353562306a36Sopenharmony_ci put_device(&mvdev->vdev.dev); 353662306a36Sopenharmony_ci return err; 353762306a36Sopenharmony_ci} 353862306a36Sopenharmony_ci 353962306a36Sopenharmony_cistatic void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device *dev) 354062306a36Sopenharmony_ci{ 354162306a36Sopenharmony_ci struct mlx5_vdpa_mgmtdev *mgtdev = container_of(v_mdev, struct mlx5_vdpa_mgmtdev, mgtdev); 354262306a36Sopenharmony_ci struct mlx5_vdpa_dev *mvdev = to_mvdev(dev); 354362306a36Sopenharmony_ci struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 354462306a36Sopenharmony_ci struct workqueue_struct *wq; 354562306a36Sopenharmony_ci 354662306a36Sopenharmony_ci unregister_link_notifier(ndev); 354762306a36Sopenharmony_ci _vdpa_unregister_device(dev); 354862306a36Sopenharmony_ci wq = mvdev->wq; 354962306a36Sopenharmony_ci mvdev->wq = NULL; 355062306a36Sopenharmony_ci destroy_workqueue(wq); 355162306a36Sopenharmony_ci mgtdev->ndev = NULL; 355262306a36Sopenharmony_ci} 355362306a36Sopenharmony_ci 355462306a36Sopenharmony_cistatic const struct vdpa_mgmtdev_ops mdev_ops = { 355562306a36Sopenharmony_ci .dev_add = mlx5_vdpa_dev_add, 355662306a36Sopenharmony_ci .dev_del = mlx5_vdpa_dev_del, 355762306a36Sopenharmony_ci}; 355862306a36Sopenharmony_ci 355962306a36Sopenharmony_cistatic struct virtio_device_id id_table[] = { 356062306a36Sopenharmony_ci { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID }, 356162306a36Sopenharmony_ci { 0 }, 356262306a36Sopenharmony_ci}; 356362306a36Sopenharmony_ci 356462306a36Sopenharmony_cistatic int mlx5v_probe(struct auxiliary_device *adev, 356562306a36Sopenharmony_ci const struct auxiliary_device_id *id) 356662306a36Sopenharmony_ci 356762306a36Sopenharmony_ci{ 356862306a36Sopenharmony_ci struct mlx5_adev *madev = container_of(adev, struct mlx5_adev, adev); 356962306a36Sopenharmony_ci struct mlx5_core_dev *mdev = madev->mdev; 357062306a36Sopenharmony_ci struct mlx5_vdpa_mgmtdev *mgtdev; 357162306a36Sopenharmony_ci int err; 357262306a36Sopenharmony_ci 357362306a36Sopenharmony_ci mgtdev = kzalloc(sizeof(*mgtdev), GFP_KERNEL); 357462306a36Sopenharmony_ci if (!mgtdev) 357562306a36Sopenharmony_ci return -ENOMEM; 357662306a36Sopenharmony_ci 357762306a36Sopenharmony_ci mgtdev->mgtdev.ops = &mdev_ops; 357862306a36Sopenharmony_ci mgtdev->mgtdev.device = mdev->device; 357962306a36Sopenharmony_ci mgtdev->mgtdev.id_table = id_table; 358062306a36Sopenharmony_ci mgtdev->mgtdev.config_attr_mask = BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR) | 358162306a36Sopenharmony_ci BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP) | 358262306a36Sopenharmony_ci BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MTU) | 358362306a36Sopenharmony_ci BIT_ULL(VDPA_ATTR_DEV_FEATURES); 358462306a36Sopenharmony_ci mgtdev->mgtdev.max_supported_vqs = 358562306a36Sopenharmony_ci MLX5_CAP_DEV_VDPA_EMULATION(mdev, max_num_virtio_queues) + 1; 358662306a36Sopenharmony_ci mgtdev->mgtdev.supported_features = get_supported_features(mdev); 358762306a36Sopenharmony_ci mgtdev->madev = madev; 358862306a36Sopenharmony_ci 358962306a36Sopenharmony_ci err = vdpa_mgmtdev_register(&mgtdev->mgtdev); 359062306a36Sopenharmony_ci if (err) 359162306a36Sopenharmony_ci goto reg_err; 359262306a36Sopenharmony_ci 359362306a36Sopenharmony_ci auxiliary_set_drvdata(adev, mgtdev); 359462306a36Sopenharmony_ci 359562306a36Sopenharmony_ci return 0; 359662306a36Sopenharmony_ci 359762306a36Sopenharmony_cireg_err: 359862306a36Sopenharmony_ci kfree(mgtdev); 359962306a36Sopenharmony_ci return err; 360062306a36Sopenharmony_ci} 360162306a36Sopenharmony_ci 360262306a36Sopenharmony_cistatic void mlx5v_remove(struct auxiliary_device *adev) 360362306a36Sopenharmony_ci{ 360462306a36Sopenharmony_ci struct mlx5_vdpa_mgmtdev *mgtdev; 360562306a36Sopenharmony_ci 360662306a36Sopenharmony_ci mgtdev = auxiliary_get_drvdata(adev); 360762306a36Sopenharmony_ci vdpa_mgmtdev_unregister(&mgtdev->mgtdev); 360862306a36Sopenharmony_ci kfree(mgtdev); 360962306a36Sopenharmony_ci} 361062306a36Sopenharmony_ci 361162306a36Sopenharmony_cistatic const struct auxiliary_device_id mlx5v_id_table[] = { 361262306a36Sopenharmony_ci { .name = MLX5_ADEV_NAME ".vnet", }, 361362306a36Sopenharmony_ci {}, 361462306a36Sopenharmony_ci}; 361562306a36Sopenharmony_ci 361662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(auxiliary, mlx5v_id_table); 361762306a36Sopenharmony_ci 361862306a36Sopenharmony_cistatic struct auxiliary_driver mlx5v_driver = { 361962306a36Sopenharmony_ci .name = "vnet", 362062306a36Sopenharmony_ci .probe = mlx5v_probe, 362162306a36Sopenharmony_ci .remove = mlx5v_remove, 362262306a36Sopenharmony_ci .id_table = mlx5v_id_table, 362362306a36Sopenharmony_ci}; 362462306a36Sopenharmony_ci 362562306a36Sopenharmony_cimodule_auxiliary_driver(mlx5v_driver); 3626