11a86b377SEli Cohen // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 21a86b377SEli Cohen /* Copyright (c) 2020 Mellanox Technologies Ltd. */ 31a86b377SEli Cohen 474c9729dSLeon Romanovsky #include <linux/module.h> 51a86b377SEli Cohen #include <linux/vdpa.h> 674c9729dSLeon Romanovsky #include <linux/vringh.h> 774c9729dSLeon Romanovsky #include <uapi/linux/virtio_net.h> 81a86b377SEli Cohen #include <uapi/linux/virtio_ids.h> 9a007d940SEli Cohen #include <uapi/linux/vdpa.h> 101a86b377SEli Cohen #include <linux/virtio_config.h> 1174c9729dSLeon Romanovsky #include <linux/auxiliary_bus.h> 1274c9729dSLeon Romanovsky #include <linux/mlx5/cq.h> 131a86b377SEli Cohen #include <linux/mlx5/qp.h> 141a86b377SEli Cohen #include <linux/mlx5/device.h> 1574c9729dSLeon Romanovsky #include <linux/mlx5/driver.h> 161a86b377SEli Cohen #include <linux/mlx5/vport.h> 171a86b377SEli Cohen #include <linux/mlx5/fs.h> 180aae392bSLeon Romanovsky #include <linux/mlx5/mlx5_ifc_vdpa.h> 197c9f131fSEli Cohen #include <linux/mlx5/mpfs.h> 201a86b377SEli Cohen #include "mlx5_vdpa.h" 2172c67e9bSEli Cohen #include "mlx5_vnet.h" 221a86b377SEli Cohen 2374c9729dSLeon Romanovsky MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>"); 2474c9729dSLeon Romanovsky MODULE_DESCRIPTION("Mellanox VDPA driver"); 2574c9729dSLeon Romanovsky MODULE_LICENSE("Dual BSD/GPL"); 2674c9729dSLeon Romanovsky 271a86b377SEli Cohen #define VALID_FEATURES_MASK \ 28cbb52359SNathan Chancellor (BIT_ULL(VIRTIO_NET_F_CSUM) | BIT_ULL(VIRTIO_NET_F_GUEST_CSUM) | \ 29cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_CTRL_GUEST_OFFLOADS) | BIT_ULL(VIRTIO_NET_F_MTU) | BIT_ULL(VIRTIO_NET_F_MAC) | \ 30cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_GUEST_TSO4) | BIT_ULL(VIRTIO_NET_F_GUEST_TSO6) | \ 31cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_GUEST_ECN) | BIT_ULL(VIRTIO_NET_F_GUEST_UFO) | BIT_ULL(VIRTIO_NET_F_HOST_TSO4) | \ 32cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_HOST_TSO6) | BIT_ULL(VIRTIO_NET_F_HOST_ECN) | BIT_ULL(VIRTIO_NET_F_HOST_UFO) | \ 33cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_MRG_RXBUF) | BIT_ULL(VIRTIO_NET_F_STATUS) | BIT_ULL(VIRTIO_NET_F_CTRL_VQ) | \ 34cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_CTRL_RX) | BIT_ULL(VIRTIO_NET_F_CTRL_VLAN) | \ 35cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_CTRL_RX_EXTRA) | BIT_ULL(VIRTIO_NET_F_GUEST_ANNOUNCE) | \ 36cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_MQ) | BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR) | BIT_ULL(VIRTIO_NET_F_HASH_REPORT) | \ 37cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_RSS) | BIT_ULL(VIRTIO_NET_F_RSC_EXT) | BIT_ULL(VIRTIO_NET_F_STANDBY) | \ 38cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_SPEED_DUPLEX) | BIT_ULL(VIRTIO_F_NOTIFY_ON_EMPTY) | \ 39cbb52359SNathan Chancellor BIT_ULL(VIRTIO_F_ANY_LAYOUT) | BIT_ULL(VIRTIO_F_VERSION_1) | BIT_ULL(VIRTIO_F_ACCESS_PLATFORM) | \ 40cbb52359SNathan Chancellor BIT_ULL(VIRTIO_F_RING_PACKED) | BIT_ULL(VIRTIO_F_ORDER_PLATFORM) | BIT_ULL(VIRTIO_F_SR_IOV)) 411a86b377SEli Cohen 421a86b377SEli Cohen #define VALID_STATUS_MASK \ 431a86b377SEli Cohen (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK | \ 441a86b377SEli Cohen VIRTIO_CONFIG_S_FEATURES_OK | VIRTIO_CONFIG_S_NEEDS_RESET | VIRTIO_CONFIG_S_FAILED) 451a86b377SEli Cohen 46e4fc6650SEli Cohen #define MLX5_FEATURE(_mvdev, _feature) (!!((_mvdev)->actual_features & BIT_ULL(_feature))) 47e4fc6650SEli Cohen 48baf2ad3fSEli Cohen #define MLX5V_UNTAGGED 0x1000 49baf2ad3fSEli Cohen 501a86b377SEli Cohen struct mlx5_vdpa_cq_buf { 511a86b377SEli Cohen struct mlx5_frag_buf_ctrl fbc; 521a86b377SEli Cohen struct mlx5_frag_buf frag_buf; 531a86b377SEli Cohen int cqe_size; 541a86b377SEli Cohen int nent; 551a86b377SEli Cohen }; 561a86b377SEli Cohen 571a86b377SEli Cohen struct mlx5_vdpa_cq { 581a86b377SEli Cohen struct mlx5_core_cq mcq; 591a86b377SEli Cohen struct mlx5_vdpa_cq_buf buf; 601a86b377SEli Cohen struct mlx5_db db; 611a86b377SEli Cohen int cqe; 621a86b377SEli Cohen }; 631a86b377SEli Cohen 641a86b377SEli Cohen struct mlx5_vdpa_umem { 651a86b377SEli Cohen struct mlx5_frag_buf_ctrl fbc; 661a86b377SEli Cohen struct mlx5_frag_buf frag_buf; 671a86b377SEli Cohen int size; 681a86b377SEli Cohen u32 id; 691a86b377SEli Cohen }; 701a86b377SEli Cohen 711a86b377SEli Cohen struct mlx5_vdpa_qp { 721a86b377SEli Cohen struct mlx5_core_qp mqp; 731a86b377SEli Cohen struct mlx5_frag_buf frag_buf; 741a86b377SEli Cohen struct mlx5_db db; 751a86b377SEli Cohen u16 head; 761a86b377SEli Cohen bool fw; 771a86b377SEli Cohen }; 781a86b377SEli Cohen 791a86b377SEli Cohen struct mlx5_vq_restore_info { 801a86b377SEli Cohen u32 num_ent; 811a86b377SEli Cohen u64 desc_addr; 821a86b377SEli Cohen u64 device_addr; 831a86b377SEli Cohen u64 driver_addr; 841a86b377SEli Cohen u16 avail_index; 85b35ccebeSEli Cohen u16 used_index; 86bc9a2b3eSEli Cohen struct msi_map map; 871a86b377SEli Cohen bool ready; 881a86b377SEli Cohen bool restore; 891a86b377SEli Cohen }; 901a86b377SEli Cohen 911a86b377SEli Cohen struct mlx5_vdpa_virtqueue { 921a86b377SEli Cohen bool ready; 931a86b377SEli Cohen u64 desc_addr; 941a86b377SEli Cohen u64 device_addr; 951a86b377SEli Cohen u64 driver_addr; 961a86b377SEli Cohen u32 num_ent; 971a86b377SEli Cohen 981a86b377SEli Cohen /* Resources for implementing the notification channel from the device 991a86b377SEli Cohen * to the driver. fwqp is the firmware end of an RC connection; the 1002f72b226SXiang wangx * other end is vqqp used by the driver. cq is where completions are 1011a86b377SEli Cohen * reported. 1021a86b377SEli Cohen */ 1031a86b377SEli Cohen struct mlx5_vdpa_cq cq; 1041a86b377SEli Cohen struct mlx5_vdpa_qp fwqp; 1051a86b377SEli Cohen struct mlx5_vdpa_qp vqqp; 1061a86b377SEli Cohen 1071a86b377SEli Cohen /* umem resources are required for the virtqueue operation. They're use 1081a86b377SEli Cohen * is internal and they must be provided by the driver. 1091a86b377SEli Cohen */ 1101a86b377SEli Cohen struct mlx5_vdpa_umem umem1; 1111a86b377SEli Cohen struct mlx5_vdpa_umem umem2; 1121a86b377SEli Cohen struct mlx5_vdpa_umem umem3; 1131a86b377SEli Cohen 1141892a3d4SEli Cohen u32 counter_set_id; 1151a86b377SEli Cohen bool initialized; 1161a86b377SEli Cohen int index; 1171a86b377SEli Cohen u32 virtq_id; 1181a86b377SEli Cohen struct mlx5_vdpa_net *ndev; 1191a86b377SEli Cohen u16 avail_idx; 120b35ccebeSEli Cohen u16 used_idx; 1211a86b377SEli Cohen int fw_state; 122bc9a2b3eSEli Cohen struct msi_map map; 1231a86b377SEli Cohen 1241a86b377SEli Cohen /* keep last in the struct */ 1251a86b377SEli Cohen struct mlx5_vq_restore_info ri; 1261a86b377SEli Cohen }; 1271a86b377SEli Cohen 128e4fc6650SEli Cohen static bool is_index_valid(struct mlx5_vdpa_dev *mvdev, u16 idx) 129e4fc6650SEli Cohen { 130f8ae3a48SEli Cohen if (!(mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_MQ))) { 131f8ae3a48SEli Cohen if (!(mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) 132f8ae3a48SEli Cohen return idx < 2; 133f8ae3a48SEli Cohen else 134f8ae3a48SEli Cohen return idx < 3; 135f8ae3a48SEli Cohen } 136e4fc6650SEli Cohen 137f8ae3a48SEli Cohen return idx <= mvdev->max_idx; 138e4fc6650SEli Cohen } 139e4fc6650SEli Cohen 1401a86b377SEli Cohen static void free_resources(struct mlx5_vdpa_net *ndev); 1411a86b377SEli Cohen static void init_mvqs(struct mlx5_vdpa_net *ndev); 142ae0428deSEli Cohen static int setup_driver(struct mlx5_vdpa_dev *mvdev); 1431a86b377SEli Cohen static void teardown_driver(struct mlx5_vdpa_net *ndev); 1441a86b377SEli Cohen 1451a86b377SEli Cohen static bool mlx5_vdpa_debug; 1461a86b377SEli Cohen 1475262912eSEli Cohen #define MLX5_CVQ_MAX_ENT 16 1485262912eSEli Cohen 1491a86b377SEli Cohen #define MLX5_LOG_VIO_FLAG(_feature) \ 1501a86b377SEli Cohen do { \ 151cbb52359SNathan Chancellor if (features & BIT_ULL(_feature)) \ 1521a86b377SEli Cohen mlx5_vdpa_info(mvdev, "%s\n", #_feature); \ 1531a86b377SEli Cohen } while (0) 1541a86b377SEli Cohen 1551a86b377SEli Cohen #define MLX5_LOG_VIO_STAT(_status) \ 1561a86b377SEli Cohen do { \ 1571a86b377SEli Cohen if (status & (_status)) \ 1581a86b377SEli Cohen mlx5_vdpa_info(mvdev, "%s\n", #_status); \ 1591a86b377SEli Cohen } while (0) 1601a86b377SEli Cohen 16152893733SEli Cohen /* TODO: cross-endian support */ 16252893733SEli Cohen static inline bool mlx5_vdpa_is_little_endian(struct mlx5_vdpa_dev *mvdev) 16352893733SEli Cohen { 16452893733SEli Cohen return virtio_legacy_is_little_endian() || 16552893733SEli Cohen (mvdev->actual_features & BIT_ULL(VIRTIO_F_VERSION_1)); 16652893733SEli Cohen } 16752893733SEli Cohen 16852893733SEli Cohen static u16 mlx5vdpa16_to_cpu(struct mlx5_vdpa_dev *mvdev, __virtio16 val) 16952893733SEli Cohen { 17052893733SEli Cohen return __virtio16_to_cpu(mlx5_vdpa_is_little_endian(mvdev), val); 17152893733SEli Cohen } 17252893733SEli Cohen 17352893733SEli Cohen static __virtio16 cpu_to_mlx5vdpa16(struct mlx5_vdpa_dev *mvdev, u16 val) 17452893733SEli Cohen { 17552893733SEli Cohen return __cpu_to_virtio16(mlx5_vdpa_is_little_endian(mvdev), val); 17652893733SEli Cohen } 17752893733SEli Cohen 1785262912eSEli Cohen static u16 ctrl_vq_idx(struct mlx5_vdpa_dev *mvdev) 1795262912eSEli Cohen { 18052893733SEli Cohen if (!(mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_MQ))) 18152893733SEli Cohen return 2; 18252893733SEli Cohen 183acde3929SEli Cohen return mvdev->max_vqs; 1845262912eSEli Cohen } 1855262912eSEli Cohen 1865262912eSEli Cohen static bool is_ctrl_vq_idx(struct mlx5_vdpa_dev *mvdev, u16 idx) 1875262912eSEli Cohen { 1885262912eSEli Cohen return idx == ctrl_vq_idx(mvdev); 1895262912eSEli Cohen } 1905262912eSEli Cohen 1911a86b377SEli Cohen static void print_status(struct mlx5_vdpa_dev *mvdev, u8 status, bool set) 1921a86b377SEli Cohen { 1931a86b377SEli Cohen if (status & ~VALID_STATUS_MASK) 1941a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "Warning: there are invalid status bits 0x%x\n", 1951a86b377SEli Cohen status & ~VALID_STATUS_MASK); 1961a86b377SEli Cohen 1971a86b377SEli Cohen if (!mlx5_vdpa_debug) 1981a86b377SEli Cohen return; 1991a86b377SEli Cohen 2001a86b377SEli Cohen mlx5_vdpa_info(mvdev, "driver status %s", set ? "set" : "get"); 2011a86b377SEli Cohen if (set && !status) { 2021a86b377SEli Cohen mlx5_vdpa_info(mvdev, "driver resets the device\n"); 2031a86b377SEli Cohen return; 2041a86b377SEli Cohen } 2051a86b377SEli Cohen 2061a86b377SEli Cohen MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_ACKNOWLEDGE); 2071a86b377SEli Cohen MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_DRIVER); 2081a86b377SEli Cohen MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_DRIVER_OK); 2091a86b377SEli Cohen MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_FEATURES_OK); 2101a86b377SEli Cohen MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_NEEDS_RESET); 2111a86b377SEli Cohen MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_FAILED); 2121a86b377SEli Cohen } 2131a86b377SEli Cohen 2141a86b377SEli Cohen static void print_features(struct mlx5_vdpa_dev *mvdev, u64 features, bool set) 2151a86b377SEli Cohen { 2161a86b377SEli Cohen if (features & ~VALID_FEATURES_MASK) 2171a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "There are invalid feature bits 0x%llx\n", 2181a86b377SEli Cohen features & ~VALID_FEATURES_MASK); 2191a86b377SEli Cohen 2201a86b377SEli Cohen if (!mlx5_vdpa_debug) 2211a86b377SEli Cohen return; 2221a86b377SEli Cohen 2231a86b377SEli Cohen mlx5_vdpa_info(mvdev, "driver %s feature bits:\n", set ? "sets" : "reads"); 2241a86b377SEli Cohen if (!features) 2251a86b377SEli Cohen mlx5_vdpa_info(mvdev, "all feature bits are cleared\n"); 2261a86b377SEli Cohen 2271a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CSUM); 2281a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_CSUM); 2291a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_GUEST_OFFLOADS); 2301a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_MTU); 2311a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_MAC); 2321a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_TSO4); 2331a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_TSO6); 2341a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_ECN); 2351a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_UFO); 2361a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HOST_TSO4); 2371a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HOST_TSO6); 2381a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HOST_ECN); 2391a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HOST_UFO); 2401a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_MRG_RXBUF); 2411a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_STATUS); 2421a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_VQ); 2431a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_RX); 2441a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_VLAN); 2451a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_RX_EXTRA); 2461a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_ANNOUNCE); 2471a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_MQ); 2481a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_MAC_ADDR); 2491a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HASH_REPORT); 2501a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_RSS); 2511a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_RSC_EXT); 2521a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_STANDBY); 2531a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_SPEED_DUPLEX); 2541a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_F_NOTIFY_ON_EMPTY); 2551a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_F_ANY_LAYOUT); 2561a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_F_VERSION_1); 2571a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_F_ACCESS_PLATFORM); 2581a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_F_RING_PACKED); 2591a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_F_ORDER_PLATFORM); 2601a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_F_SR_IOV); 2611a86b377SEli Cohen } 2621a86b377SEli Cohen 2631a86b377SEli Cohen static int create_tis(struct mlx5_vdpa_net *ndev) 2641a86b377SEli Cohen { 2651a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = &ndev->mvdev; 2661a86b377SEli Cohen u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {}; 2671a86b377SEli Cohen void *tisc; 2681a86b377SEli Cohen int err; 2691a86b377SEli Cohen 2701a86b377SEli Cohen tisc = MLX5_ADDR_OF(create_tis_in, in, ctx); 2711a86b377SEli Cohen MLX5_SET(tisc, tisc, transport_domain, ndev->res.tdn); 2721a86b377SEli Cohen err = mlx5_vdpa_create_tis(mvdev, in, &ndev->res.tisn); 2731a86b377SEli Cohen if (err) 2741a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "create TIS (%d)\n", err); 2751a86b377SEli Cohen 2761a86b377SEli Cohen return err; 2771a86b377SEli Cohen } 2781a86b377SEli Cohen 2791a86b377SEli Cohen static void destroy_tis(struct mlx5_vdpa_net *ndev) 2801a86b377SEli Cohen { 2811a86b377SEli Cohen mlx5_vdpa_destroy_tis(&ndev->mvdev, ndev->res.tisn); 2821a86b377SEli Cohen } 2831a86b377SEli Cohen 2841a86b377SEli Cohen #define MLX5_VDPA_CQE_SIZE 64 2851a86b377SEli Cohen #define MLX5_VDPA_LOG_CQE_SIZE ilog2(MLX5_VDPA_CQE_SIZE) 2861a86b377SEli Cohen 2871a86b377SEli Cohen static int cq_frag_buf_alloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_cq_buf *buf, int nent) 2881a86b377SEli Cohen { 2891a86b377SEli Cohen struct mlx5_frag_buf *frag_buf = &buf->frag_buf; 2901a86b377SEli Cohen u8 log_wq_stride = MLX5_VDPA_LOG_CQE_SIZE; 2911a86b377SEli Cohen u8 log_wq_sz = MLX5_VDPA_LOG_CQE_SIZE; 2921a86b377SEli Cohen int err; 2931a86b377SEli Cohen 2941a86b377SEli Cohen err = mlx5_frag_buf_alloc_node(ndev->mvdev.mdev, nent * MLX5_VDPA_CQE_SIZE, frag_buf, 2951a86b377SEli Cohen ndev->mvdev.mdev->priv.numa_node); 2961a86b377SEli Cohen if (err) 2971a86b377SEli Cohen return err; 2981a86b377SEli Cohen 2991a86b377SEli Cohen mlx5_init_fbc(frag_buf->frags, log_wq_stride, log_wq_sz, &buf->fbc); 3001a86b377SEli Cohen 3011a86b377SEli Cohen buf->cqe_size = MLX5_VDPA_CQE_SIZE; 3021a86b377SEli Cohen buf->nent = nent; 3031a86b377SEli Cohen 3041a86b377SEli Cohen return 0; 3051a86b377SEli Cohen } 3061a86b377SEli Cohen 3071a86b377SEli Cohen static int umem_frag_buf_alloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_umem *umem, int size) 3081a86b377SEli Cohen { 3091a86b377SEli Cohen struct mlx5_frag_buf *frag_buf = &umem->frag_buf; 3101a86b377SEli Cohen 3111a86b377SEli Cohen return mlx5_frag_buf_alloc_node(ndev->mvdev.mdev, size, frag_buf, 3121a86b377SEli Cohen ndev->mvdev.mdev->priv.numa_node); 3131a86b377SEli Cohen } 3141a86b377SEli Cohen 3151a86b377SEli Cohen static void cq_frag_buf_free(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_cq_buf *buf) 3161a86b377SEli Cohen { 3171a86b377SEli Cohen mlx5_frag_buf_free(ndev->mvdev.mdev, &buf->frag_buf); 3181a86b377SEli Cohen } 3191a86b377SEli Cohen 3201a86b377SEli Cohen static void *get_cqe(struct mlx5_vdpa_cq *vcq, int n) 3211a86b377SEli Cohen { 3221a86b377SEli Cohen return mlx5_frag_buf_get_wqe(&vcq->buf.fbc, n); 3231a86b377SEli Cohen } 3241a86b377SEli Cohen 3251a86b377SEli Cohen static void cq_frag_buf_init(struct mlx5_vdpa_cq *vcq, struct mlx5_vdpa_cq_buf *buf) 3261a86b377SEli Cohen { 3271a86b377SEli Cohen struct mlx5_cqe64 *cqe64; 3281a86b377SEli Cohen void *cqe; 3291a86b377SEli Cohen int i; 3301a86b377SEli Cohen 3311a86b377SEli Cohen for (i = 0; i < buf->nent; i++) { 3321a86b377SEli Cohen cqe = get_cqe(vcq, i); 3331a86b377SEli Cohen cqe64 = cqe; 3341a86b377SEli Cohen cqe64->op_own = MLX5_CQE_INVALID << 4; 3351a86b377SEli Cohen } 3361a86b377SEli Cohen } 3371a86b377SEli Cohen 3381a86b377SEli Cohen static void *get_sw_cqe(struct mlx5_vdpa_cq *cq, int n) 3391a86b377SEli Cohen { 3401a86b377SEli Cohen struct mlx5_cqe64 *cqe64 = get_cqe(cq, n & (cq->cqe - 1)); 3411a86b377SEli Cohen 3421a86b377SEli Cohen if (likely(get_cqe_opcode(cqe64) != MLX5_CQE_INVALID) && 3431a86b377SEli Cohen !((cqe64->op_own & MLX5_CQE_OWNER_MASK) ^ !!(n & cq->cqe))) 3441a86b377SEli Cohen return cqe64; 3451a86b377SEli Cohen 3461a86b377SEli Cohen return NULL; 3471a86b377SEli Cohen } 3481a86b377SEli Cohen 3491a86b377SEli Cohen static void rx_post(struct mlx5_vdpa_qp *vqp, int n) 3501a86b377SEli Cohen { 3511a86b377SEli Cohen vqp->head += n; 3521a86b377SEli Cohen vqp->db.db[0] = cpu_to_be32(vqp->head); 3531a86b377SEli Cohen } 3541a86b377SEli Cohen 3551a86b377SEli Cohen static void qp_prepare(struct mlx5_vdpa_net *ndev, bool fw, void *in, 3561a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq, u32 num_ent) 3571a86b377SEli Cohen { 3581a86b377SEli Cohen struct mlx5_vdpa_qp *vqp; 3591a86b377SEli Cohen __be64 *pas; 3601a86b377SEli Cohen void *qpc; 3611a86b377SEli Cohen 3621a86b377SEli Cohen vqp = fw ? &mvq->fwqp : &mvq->vqqp; 3631a86b377SEli Cohen MLX5_SET(create_qp_in, in, uid, ndev->mvdev.res.uid); 3641a86b377SEli Cohen qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); 3651a86b377SEli Cohen if (vqp->fw) { 3661a86b377SEli Cohen /* Firmware QP is allocated by the driver for the firmware's 3671a86b377SEli Cohen * use so we can skip part of the params as they will be chosen by firmware 3681a86b377SEli Cohen */ 3691a86b377SEli Cohen qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); 3701a86b377SEli Cohen MLX5_SET(qpc, qpc, rq_type, MLX5_ZERO_LEN_RQ); 3711a86b377SEli Cohen MLX5_SET(qpc, qpc, no_sq, 1); 3721a86b377SEli Cohen return; 3731a86b377SEli Cohen } 3741a86b377SEli Cohen 3751a86b377SEli Cohen MLX5_SET(qpc, qpc, st, MLX5_QP_ST_RC); 3761a86b377SEli Cohen MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); 3771a86b377SEli Cohen MLX5_SET(qpc, qpc, pd, ndev->mvdev.res.pdn); 3781a86b377SEli Cohen MLX5_SET(qpc, qpc, mtu, MLX5_QPC_MTU_256_BYTES); 3791a86b377SEli Cohen MLX5_SET(qpc, qpc, uar_page, ndev->mvdev.res.uar->index); 3801a86b377SEli Cohen MLX5_SET(qpc, qpc, log_page_size, vqp->frag_buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); 3811a86b377SEli Cohen MLX5_SET(qpc, qpc, no_sq, 1); 3821a86b377SEli Cohen MLX5_SET(qpc, qpc, cqn_rcv, mvq->cq.mcq.cqn); 3831a86b377SEli Cohen MLX5_SET(qpc, qpc, log_rq_size, ilog2(num_ent)); 3841a86b377SEli Cohen MLX5_SET(qpc, qpc, rq_type, MLX5_NON_ZERO_RQ); 3851a86b377SEli Cohen pas = (__be64 *)MLX5_ADDR_OF(create_qp_in, in, pas); 3861a86b377SEli Cohen mlx5_fill_page_frag_array(&vqp->frag_buf, pas); 3871a86b377SEli Cohen } 3881a86b377SEli Cohen 3891a86b377SEli Cohen static int rq_buf_alloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_qp *vqp, u32 num_ent) 3901a86b377SEli Cohen { 3911a86b377SEli Cohen return mlx5_frag_buf_alloc_node(ndev->mvdev.mdev, 3921a86b377SEli Cohen num_ent * sizeof(struct mlx5_wqe_data_seg), &vqp->frag_buf, 3931a86b377SEli Cohen ndev->mvdev.mdev->priv.numa_node); 3941a86b377SEli Cohen } 3951a86b377SEli Cohen 3961a86b377SEli Cohen static void rq_buf_free(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_qp *vqp) 3971a86b377SEli Cohen { 3981a86b377SEli Cohen mlx5_frag_buf_free(ndev->mvdev.mdev, &vqp->frag_buf); 3991a86b377SEli Cohen } 4001a86b377SEli Cohen 4011a86b377SEli Cohen static int qp_create(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, 4021a86b377SEli Cohen struct mlx5_vdpa_qp *vqp) 4031a86b377SEli Cohen { 4041a86b377SEli Cohen struct mlx5_core_dev *mdev = ndev->mvdev.mdev; 4051a86b377SEli Cohen int inlen = MLX5_ST_SZ_BYTES(create_qp_in); 4061a86b377SEli Cohen u32 out[MLX5_ST_SZ_DW(create_qp_out)] = {}; 4071a86b377SEli Cohen void *qpc; 4081a86b377SEli Cohen void *in; 4091a86b377SEli Cohen int err; 4101a86b377SEli Cohen 4111a86b377SEli Cohen if (!vqp->fw) { 4121a86b377SEli Cohen vqp = &mvq->vqqp; 4131a86b377SEli Cohen err = rq_buf_alloc(ndev, vqp, mvq->num_ent); 4141a86b377SEli Cohen if (err) 4151a86b377SEli Cohen return err; 4161a86b377SEli Cohen 4171a86b377SEli Cohen err = mlx5_db_alloc(ndev->mvdev.mdev, &vqp->db); 4181a86b377SEli Cohen if (err) 4191a86b377SEli Cohen goto err_db; 4201a86b377SEli Cohen inlen += vqp->frag_buf.npages * sizeof(__be64); 4211a86b377SEli Cohen } 4221a86b377SEli Cohen 4231a86b377SEli Cohen in = kzalloc(inlen, GFP_KERNEL); 4241a86b377SEli Cohen if (!in) { 4251a86b377SEli Cohen err = -ENOMEM; 4261a86b377SEli Cohen goto err_kzalloc; 4271a86b377SEli Cohen } 4281a86b377SEli Cohen 4291a86b377SEli Cohen qp_prepare(ndev, vqp->fw, in, mvq, mvq->num_ent); 4301a86b377SEli Cohen qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); 4311a86b377SEli Cohen MLX5_SET(qpc, qpc, st, MLX5_QP_ST_RC); 4321a86b377SEli Cohen MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); 4331a86b377SEli Cohen MLX5_SET(qpc, qpc, pd, ndev->mvdev.res.pdn); 4341a86b377SEli Cohen MLX5_SET(qpc, qpc, mtu, MLX5_QPC_MTU_256_BYTES); 4351a86b377SEli Cohen if (!vqp->fw) 4361a86b377SEli Cohen MLX5_SET64(qpc, qpc, dbr_addr, vqp->db.dma); 4371a86b377SEli Cohen MLX5_SET(create_qp_in, in, opcode, MLX5_CMD_OP_CREATE_QP); 4381a86b377SEli Cohen err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); 4391a86b377SEli Cohen kfree(in); 4401a86b377SEli Cohen if (err) 4411a86b377SEli Cohen goto err_kzalloc; 4421a86b377SEli Cohen 4431a86b377SEli Cohen vqp->mqp.uid = ndev->mvdev.res.uid; 4441a86b377SEli Cohen vqp->mqp.qpn = MLX5_GET(create_qp_out, out, qpn); 4451a86b377SEli Cohen 4461a86b377SEli Cohen if (!vqp->fw) 4471a86b377SEli Cohen rx_post(vqp, mvq->num_ent); 4481a86b377SEli Cohen 4491a86b377SEli Cohen return 0; 4501a86b377SEli Cohen 4511a86b377SEli Cohen err_kzalloc: 4521a86b377SEli Cohen if (!vqp->fw) 4531a86b377SEli Cohen mlx5_db_free(ndev->mvdev.mdev, &vqp->db); 4541a86b377SEli Cohen err_db: 4551a86b377SEli Cohen if (!vqp->fw) 4561a86b377SEli Cohen rq_buf_free(ndev, vqp); 4571a86b377SEli Cohen 4581a86b377SEli Cohen return err; 4591a86b377SEli Cohen } 4601a86b377SEli Cohen 4611a86b377SEli Cohen static void qp_destroy(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_qp *vqp) 4621a86b377SEli Cohen { 4631a86b377SEli Cohen u32 in[MLX5_ST_SZ_DW(destroy_qp_in)] = {}; 4641a86b377SEli Cohen 4651a86b377SEli Cohen MLX5_SET(destroy_qp_in, in, opcode, MLX5_CMD_OP_DESTROY_QP); 4661a86b377SEli Cohen MLX5_SET(destroy_qp_in, in, qpn, vqp->mqp.qpn); 4671a86b377SEli Cohen MLX5_SET(destroy_qp_in, in, uid, ndev->mvdev.res.uid); 4681a86b377SEli Cohen if (mlx5_cmd_exec_in(ndev->mvdev.mdev, destroy_qp, in)) 4691a86b377SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "destroy qp 0x%x\n", vqp->mqp.qpn); 4701a86b377SEli Cohen if (!vqp->fw) { 4711a86b377SEli Cohen mlx5_db_free(ndev->mvdev.mdev, &vqp->db); 4721a86b377SEli Cohen rq_buf_free(ndev, vqp); 4731a86b377SEli Cohen } 4741a86b377SEli Cohen } 4751a86b377SEli Cohen 4761a86b377SEli Cohen static void *next_cqe_sw(struct mlx5_vdpa_cq *cq) 4771a86b377SEli Cohen { 4781a86b377SEli Cohen return get_sw_cqe(cq, cq->mcq.cons_index); 4791a86b377SEli Cohen } 4801a86b377SEli Cohen 4811a86b377SEli Cohen static int mlx5_vdpa_poll_one(struct mlx5_vdpa_cq *vcq) 4821a86b377SEli Cohen { 4831a86b377SEli Cohen struct mlx5_cqe64 *cqe64; 4841a86b377SEli Cohen 4851a86b377SEli Cohen cqe64 = next_cqe_sw(vcq); 4861a86b377SEli Cohen if (!cqe64) 4871a86b377SEli Cohen return -EAGAIN; 4881a86b377SEli Cohen 4891a86b377SEli Cohen vcq->mcq.cons_index++; 4901a86b377SEli Cohen return 0; 4911a86b377SEli Cohen } 4921a86b377SEli Cohen 4931a86b377SEli Cohen static void mlx5_vdpa_handle_completions(struct mlx5_vdpa_virtqueue *mvq, int num) 4941a86b377SEli Cohen { 495db296d25SEli Cohen struct mlx5_vdpa_net *ndev = mvq->ndev; 496db296d25SEli Cohen struct vdpa_callback *event_cb; 497db296d25SEli Cohen 498db296d25SEli Cohen event_cb = &ndev->event_cbs[mvq->index]; 4991a86b377SEli Cohen mlx5_cq_set_ci(&mvq->cq.mcq); 50083ef73b2SEli Cohen 50183ef73b2SEli Cohen /* make sure CQ cosumer update is visible to the hardware before updating 50283ef73b2SEli Cohen * RX doorbell record. 50383ef73b2SEli Cohen */ 50483ef73b2SEli Cohen dma_wmb(); 5051a86b377SEli Cohen rx_post(&mvq->vqqp, num); 506db296d25SEli Cohen if (event_cb->callback) 507db296d25SEli Cohen event_cb->callback(event_cb->private); 5081a86b377SEli Cohen } 5091a86b377SEli Cohen 5101a86b377SEli Cohen static void mlx5_vdpa_cq_comp(struct mlx5_core_cq *mcq, struct mlx5_eqe *eqe) 5111a86b377SEli Cohen { 5121a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq = container_of(mcq, struct mlx5_vdpa_virtqueue, cq.mcq); 5131a86b377SEli Cohen struct mlx5_vdpa_net *ndev = mvq->ndev; 5141a86b377SEli Cohen void __iomem *uar_page = ndev->mvdev.res.uar->map; 5151a86b377SEli Cohen int num = 0; 5161a86b377SEli Cohen 5171a86b377SEli Cohen while (!mlx5_vdpa_poll_one(&mvq->cq)) { 5181a86b377SEli Cohen num++; 5191a86b377SEli Cohen if (num > mvq->num_ent / 2) { 5201a86b377SEli Cohen /* If completions keep coming while we poll, we want to 5211a86b377SEli Cohen * let the hardware know that we consumed them by 5221a86b377SEli Cohen * updating the doorbell record. We also let vdpa core 5231a86b377SEli Cohen * know about this so it passes it on the virtio driver 5241a86b377SEli Cohen * on the guest. 5251a86b377SEli Cohen */ 5261a86b377SEli Cohen mlx5_vdpa_handle_completions(mvq, num); 5271a86b377SEli Cohen num = 0; 5281a86b377SEli Cohen } 5291a86b377SEli Cohen } 5301a86b377SEli Cohen 5311a86b377SEli Cohen if (num) 5321a86b377SEli Cohen mlx5_vdpa_handle_completions(mvq, num); 5331a86b377SEli Cohen 5341a86b377SEli Cohen mlx5_cq_arm(&mvq->cq.mcq, MLX5_CQ_DB_REQ_NOT, uar_page, mvq->cq.mcq.cons_index); 5351a86b377SEli Cohen } 5361a86b377SEli Cohen 5371a86b377SEli Cohen static int cq_create(struct mlx5_vdpa_net *ndev, u16 idx, u32 num_ent) 5381a86b377SEli Cohen { 5391a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq = &ndev->vqs[idx]; 5401a86b377SEli Cohen struct mlx5_core_dev *mdev = ndev->mvdev.mdev; 5411a86b377SEli Cohen void __iomem *uar_page = ndev->mvdev.res.uar->map; 5421a86b377SEli Cohen u32 out[MLX5_ST_SZ_DW(create_cq_out)]; 5431a86b377SEli Cohen struct mlx5_vdpa_cq *vcq = &mvq->cq; 5441a86b377SEli Cohen __be64 *pas; 5451a86b377SEli Cohen int inlen; 5461a86b377SEli Cohen void *cqc; 5471a86b377SEli Cohen void *in; 5481a86b377SEli Cohen int err; 5491a86b377SEli Cohen int eqn; 5501a86b377SEli Cohen 5511a86b377SEli Cohen err = mlx5_db_alloc(mdev, &vcq->db); 5521a86b377SEli Cohen if (err) 5531a86b377SEli Cohen return err; 5541a86b377SEli Cohen 5551a86b377SEli Cohen vcq->mcq.set_ci_db = vcq->db.db; 5561a86b377SEli Cohen vcq->mcq.arm_db = vcq->db.db + 1; 5571a86b377SEli Cohen vcq->mcq.cqe_sz = 64; 5581a86b377SEli Cohen 5591a86b377SEli Cohen err = cq_frag_buf_alloc(ndev, &vcq->buf, num_ent); 5601a86b377SEli Cohen if (err) 5611a86b377SEli Cohen goto err_db; 5621a86b377SEli Cohen 5631a86b377SEli Cohen cq_frag_buf_init(vcq, &vcq->buf); 5641a86b377SEli Cohen 5651a86b377SEli Cohen inlen = MLX5_ST_SZ_BYTES(create_cq_in) + 5661a86b377SEli Cohen MLX5_FLD_SZ_BYTES(create_cq_in, pas[0]) * vcq->buf.frag_buf.npages; 5671a86b377SEli Cohen in = kzalloc(inlen, GFP_KERNEL); 5681a86b377SEli Cohen if (!in) { 5691a86b377SEli Cohen err = -ENOMEM; 5701a86b377SEli Cohen goto err_vzalloc; 5711a86b377SEli Cohen } 5721a86b377SEli Cohen 5731a86b377SEli Cohen MLX5_SET(create_cq_in, in, uid, ndev->mvdev.res.uid); 5741a86b377SEli Cohen pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas); 5751a86b377SEli Cohen mlx5_fill_page_frag_array(&vcq->buf.frag_buf, pas); 5761a86b377SEli Cohen 5771a86b377SEli Cohen cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context); 5781a86b377SEli Cohen MLX5_SET(cqc, cqc, log_page_size, vcq->buf.frag_buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); 5791a86b377SEli Cohen 5801a86b377SEli Cohen /* Use vector 0 by default. Consider adding code to choose least used 5811a86b377SEli Cohen * vector. 5821a86b377SEli Cohen */ 583f14c1a14SMaher Sanalla err = mlx5_comp_eqn_get(mdev, 0, &eqn); 5841a86b377SEli Cohen if (err) 5851a86b377SEli Cohen goto err_vec; 5861a86b377SEli Cohen 5871a86b377SEli Cohen cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context); 5881a86b377SEli Cohen MLX5_SET(cqc, cqc, log_cq_size, ilog2(num_ent)); 5891a86b377SEli Cohen MLX5_SET(cqc, cqc, uar_page, ndev->mvdev.res.uar->index); 590616d5769STal Gilboa MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn); 5911a86b377SEli Cohen MLX5_SET64(cqc, cqc, dbr_addr, vcq->db.dma); 5921a86b377SEli Cohen 5931a86b377SEli Cohen err = mlx5_core_create_cq(mdev, &vcq->mcq, in, inlen, out, sizeof(out)); 5941a86b377SEli Cohen if (err) 5951a86b377SEli Cohen goto err_vec; 5961a86b377SEli Cohen 5971a86b377SEli Cohen vcq->mcq.comp = mlx5_vdpa_cq_comp; 5981a86b377SEli Cohen vcq->cqe = num_ent; 5991a86b377SEli Cohen vcq->mcq.set_ci_db = vcq->db.db; 6001a86b377SEli Cohen vcq->mcq.arm_db = vcq->db.db + 1; 6011a86b377SEli Cohen mlx5_cq_arm(&mvq->cq.mcq, MLX5_CQ_DB_REQ_NOT, uar_page, mvq->cq.mcq.cons_index); 6021a86b377SEli Cohen kfree(in); 6031a86b377SEli Cohen return 0; 6041a86b377SEli Cohen 6051a86b377SEli Cohen err_vec: 6061a86b377SEli Cohen kfree(in); 6071a86b377SEli Cohen err_vzalloc: 6081a86b377SEli Cohen cq_frag_buf_free(ndev, &vcq->buf); 6091a86b377SEli Cohen err_db: 6101a86b377SEli Cohen mlx5_db_free(ndev->mvdev.mdev, &vcq->db); 6111a86b377SEli Cohen return err; 6121a86b377SEli Cohen } 6131a86b377SEli Cohen 6141a86b377SEli Cohen static void cq_destroy(struct mlx5_vdpa_net *ndev, u16 idx) 6151a86b377SEli Cohen { 6161a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq = &ndev->vqs[idx]; 6171a86b377SEli Cohen struct mlx5_core_dev *mdev = ndev->mvdev.mdev; 6181a86b377SEli Cohen struct mlx5_vdpa_cq *vcq = &mvq->cq; 6191a86b377SEli Cohen 6201a86b377SEli Cohen if (mlx5_core_destroy_cq(mdev, &vcq->mcq)) { 6211a86b377SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "destroy CQ 0x%x\n", vcq->mcq.cqn); 6221a86b377SEli Cohen return; 6231a86b377SEli Cohen } 6241a86b377SEli Cohen cq_frag_buf_free(ndev, &vcq->buf); 6251a86b377SEli Cohen mlx5_db_free(ndev->mvdev.mdev, &vcq->db); 6261a86b377SEli Cohen } 6271a86b377SEli Cohen 628abb0dcf9SDragos Tatulea static int read_umem_params(struct mlx5_vdpa_net *ndev) 629abb0dcf9SDragos Tatulea { 630abb0dcf9SDragos Tatulea u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; 631abb0dcf9SDragos Tatulea u16 opmod = (MLX5_CAP_VDPA_EMULATION << 1) | (HCA_CAP_OPMOD_GET_CUR & 0x01); 632abb0dcf9SDragos Tatulea struct mlx5_core_dev *mdev = ndev->mvdev.mdev; 633abb0dcf9SDragos Tatulea int out_size; 634abb0dcf9SDragos Tatulea void *caps; 635abb0dcf9SDragos Tatulea void *out; 636abb0dcf9SDragos Tatulea int err; 637abb0dcf9SDragos Tatulea 638abb0dcf9SDragos Tatulea out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out); 639abb0dcf9SDragos Tatulea out = kzalloc(out_size, GFP_KERNEL); 640abb0dcf9SDragos Tatulea if (!out) 641abb0dcf9SDragos Tatulea return -ENOMEM; 642abb0dcf9SDragos Tatulea 643abb0dcf9SDragos Tatulea MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); 644abb0dcf9SDragos Tatulea MLX5_SET(query_hca_cap_in, in, op_mod, opmod); 645abb0dcf9SDragos Tatulea err = mlx5_cmd_exec_inout(mdev, query_hca_cap, in, out); 646abb0dcf9SDragos Tatulea if (err) { 647abb0dcf9SDragos Tatulea mlx5_vdpa_warn(&ndev->mvdev, 648abb0dcf9SDragos Tatulea "Failed reading vdpa umem capabilities with err %d\n", err); 649abb0dcf9SDragos Tatulea goto out; 650abb0dcf9SDragos Tatulea } 651abb0dcf9SDragos Tatulea 652abb0dcf9SDragos Tatulea caps = MLX5_ADDR_OF(query_hca_cap_out, out, capability); 653abb0dcf9SDragos Tatulea 654abb0dcf9SDragos Tatulea ndev->umem_1_buffer_param_a = MLX5_GET(virtio_emulation_cap, caps, umem_1_buffer_param_a); 655abb0dcf9SDragos Tatulea ndev->umem_1_buffer_param_b = MLX5_GET(virtio_emulation_cap, caps, umem_1_buffer_param_b); 656abb0dcf9SDragos Tatulea 657abb0dcf9SDragos Tatulea ndev->umem_2_buffer_param_a = MLX5_GET(virtio_emulation_cap, caps, umem_2_buffer_param_a); 658abb0dcf9SDragos Tatulea ndev->umem_2_buffer_param_b = MLX5_GET(virtio_emulation_cap, caps, umem_2_buffer_param_b); 659abb0dcf9SDragos Tatulea 660abb0dcf9SDragos Tatulea ndev->umem_3_buffer_param_a = MLX5_GET(virtio_emulation_cap, caps, umem_3_buffer_param_a); 661abb0dcf9SDragos Tatulea ndev->umem_3_buffer_param_b = MLX5_GET(virtio_emulation_cap, caps, umem_3_buffer_param_b); 662abb0dcf9SDragos Tatulea 663abb0dcf9SDragos Tatulea out: 664abb0dcf9SDragos Tatulea kfree(out); 665abb0dcf9SDragos Tatulea return 0; 666abb0dcf9SDragos Tatulea } 667abb0dcf9SDragos Tatulea 66871ab6a7cSEli Cohen static void set_umem_size(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int num, 6691a86b377SEli Cohen struct mlx5_vdpa_umem **umemp) 6701a86b377SEli Cohen { 671abb0dcf9SDragos Tatulea u32 p_a; 672abb0dcf9SDragos Tatulea u32 p_b; 6731a86b377SEli Cohen 6741a86b377SEli Cohen switch (num) { 6751a86b377SEli Cohen case 1: 676abb0dcf9SDragos Tatulea p_a = ndev->umem_1_buffer_param_a; 677abb0dcf9SDragos Tatulea p_b = ndev->umem_1_buffer_param_b; 6781a86b377SEli Cohen *umemp = &mvq->umem1; 6791a86b377SEli Cohen break; 6801a86b377SEli Cohen case 2: 681abb0dcf9SDragos Tatulea p_a = ndev->umem_2_buffer_param_a; 682abb0dcf9SDragos Tatulea p_b = ndev->umem_2_buffer_param_b; 6831a86b377SEli Cohen *umemp = &mvq->umem2; 6841a86b377SEli Cohen break; 6851a86b377SEli Cohen case 3: 686abb0dcf9SDragos Tatulea p_a = ndev->umem_3_buffer_param_a; 687abb0dcf9SDragos Tatulea p_b = ndev->umem_3_buffer_param_b; 6881a86b377SEli Cohen *umemp = &mvq->umem3; 6891a86b377SEli Cohen break; 6901a86b377SEli Cohen } 691abb0dcf9SDragos Tatulea 69271ab6a7cSEli Cohen (*umemp)->size = p_a * mvq->num_ent + p_b; 6931a86b377SEli Cohen } 6941a86b377SEli Cohen 6951a86b377SEli Cohen static void umem_frag_buf_free(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_umem *umem) 6961a86b377SEli Cohen { 6971a86b377SEli Cohen mlx5_frag_buf_free(ndev->mvdev.mdev, &umem->frag_buf); 6981a86b377SEli Cohen } 6991a86b377SEli Cohen 7001a86b377SEli Cohen static int create_umem(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int num) 7011a86b377SEli Cohen { 7021a86b377SEli Cohen int inlen; 7031a86b377SEli Cohen u32 out[MLX5_ST_SZ_DW(create_umem_out)] = {}; 7041a86b377SEli Cohen void *um; 7051a86b377SEli Cohen void *in; 7061a86b377SEli Cohen int err; 7071a86b377SEli Cohen __be64 *pas; 7081a86b377SEli Cohen struct mlx5_vdpa_umem *umem; 7091a86b377SEli Cohen 71071ab6a7cSEli Cohen set_umem_size(ndev, mvq, num, &umem); 71171ab6a7cSEli Cohen err = umem_frag_buf_alloc(ndev, umem, umem->size); 7121a86b377SEli Cohen if (err) 7131a86b377SEli Cohen return err; 7141a86b377SEli Cohen 7151a86b377SEli Cohen inlen = MLX5_ST_SZ_BYTES(create_umem_in) + MLX5_ST_SZ_BYTES(mtt) * umem->frag_buf.npages; 7161a86b377SEli Cohen 7171a86b377SEli Cohen in = kzalloc(inlen, GFP_KERNEL); 7181a86b377SEli Cohen if (!in) { 7191a86b377SEli Cohen err = -ENOMEM; 7201a86b377SEli Cohen goto err_in; 7211a86b377SEli Cohen } 7221a86b377SEli Cohen 7231a86b377SEli Cohen MLX5_SET(create_umem_in, in, opcode, MLX5_CMD_OP_CREATE_UMEM); 7241a86b377SEli Cohen MLX5_SET(create_umem_in, in, uid, ndev->mvdev.res.uid); 7251a86b377SEli Cohen um = MLX5_ADDR_OF(create_umem_in, in, umem); 7261a86b377SEli Cohen MLX5_SET(umem, um, log_page_size, umem->frag_buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); 7271a86b377SEli Cohen MLX5_SET64(umem, um, num_of_mtt, umem->frag_buf.npages); 7281a86b377SEli Cohen 7291a86b377SEli Cohen pas = (__be64 *)MLX5_ADDR_OF(umem, um, mtt[0]); 7301a86b377SEli Cohen mlx5_fill_page_frag_array_perm(&umem->frag_buf, pas, MLX5_MTT_PERM_RW); 7311a86b377SEli Cohen 7321a86b377SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, inlen, out, sizeof(out)); 7331a86b377SEli Cohen if (err) { 7341a86b377SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "create umem(%d)\n", err); 7351a86b377SEli Cohen goto err_cmd; 7361a86b377SEli Cohen } 7371a86b377SEli Cohen 7381a86b377SEli Cohen kfree(in); 7391a86b377SEli Cohen umem->id = MLX5_GET(create_umem_out, out, umem_id); 7401a86b377SEli Cohen 7411a86b377SEli Cohen return 0; 7421a86b377SEli Cohen 7431a86b377SEli Cohen err_cmd: 7441a86b377SEli Cohen kfree(in); 7451a86b377SEli Cohen err_in: 7461a86b377SEli Cohen umem_frag_buf_free(ndev, umem); 7471a86b377SEli Cohen return err; 7481a86b377SEli Cohen } 7491a86b377SEli Cohen 7501a86b377SEli Cohen static void umem_destroy(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int num) 7511a86b377SEli Cohen { 7521a86b377SEli Cohen u32 in[MLX5_ST_SZ_DW(destroy_umem_in)] = {}; 7531a86b377SEli Cohen u32 out[MLX5_ST_SZ_DW(destroy_umem_out)] = {}; 7541a86b377SEli Cohen struct mlx5_vdpa_umem *umem; 7551a86b377SEli Cohen 7561a86b377SEli Cohen switch (num) { 7571a86b377SEli Cohen case 1: 7581a86b377SEli Cohen umem = &mvq->umem1; 7591a86b377SEli Cohen break; 7601a86b377SEli Cohen case 2: 7611a86b377SEli Cohen umem = &mvq->umem2; 7621a86b377SEli Cohen break; 7631a86b377SEli Cohen case 3: 7641a86b377SEli Cohen umem = &mvq->umem3; 7651a86b377SEli Cohen break; 7661a86b377SEli Cohen } 7671a86b377SEli Cohen 7681a86b377SEli Cohen MLX5_SET(destroy_umem_in, in, opcode, MLX5_CMD_OP_DESTROY_UMEM); 7691a86b377SEli Cohen MLX5_SET(destroy_umem_in, in, umem_id, umem->id); 7701a86b377SEli Cohen if (mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out))) 7711a86b377SEli Cohen return; 7721a86b377SEli Cohen 7731a86b377SEli Cohen umem_frag_buf_free(ndev, umem); 7741a86b377SEli Cohen } 7751a86b377SEli Cohen 7761a86b377SEli Cohen static int umems_create(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 7771a86b377SEli Cohen { 7781a86b377SEli Cohen int num; 7791a86b377SEli Cohen int err; 7801a86b377SEli Cohen 7811a86b377SEli Cohen for (num = 1; num <= 3; num++) { 7821a86b377SEli Cohen err = create_umem(ndev, mvq, num); 7831a86b377SEli Cohen if (err) 7841a86b377SEli Cohen goto err_umem; 7851a86b377SEli Cohen } 7861a86b377SEli Cohen return 0; 7871a86b377SEli Cohen 7881a86b377SEli Cohen err_umem: 7891a86b377SEli Cohen for (num--; num > 0; num--) 7901a86b377SEli Cohen umem_destroy(ndev, mvq, num); 7911a86b377SEli Cohen 7921a86b377SEli Cohen return err; 7931a86b377SEli Cohen } 7941a86b377SEli Cohen 7951a86b377SEli Cohen static void umems_destroy(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 7961a86b377SEli Cohen { 7971a86b377SEli Cohen int num; 7981a86b377SEli Cohen 7991a86b377SEli Cohen for (num = 3; num > 0; num--) 8001a86b377SEli Cohen umem_destroy(ndev, mvq, num); 8011a86b377SEli Cohen } 8021a86b377SEli Cohen 8031a86b377SEli Cohen static int get_queue_type(struct mlx5_vdpa_net *ndev) 8041a86b377SEli Cohen { 8051a86b377SEli Cohen u32 type_mask; 8061a86b377SEli Cohen 8071a86b377SEli Cohen type_mask = MLX5_CAP_DEV_VDPA_EMULATION(ndev->mvdev.mdev, virtio_queue_type); 8081a86b377SEli Cohen 8091a86b377SEli Cohen /* prefer split queue */ 810879753c8SEli Cohen if (type_mask & MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_SPLIT) 8111a86b377SEli Cohen return MLX5_VIRTIO_EMULATION_VIRTIO_QUEUE_TYPE_SPLIT; 812879753c8SEli Cohen 813879753c8SEli Cohen WARN_ON(!(type_mask & MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_PACKED)); 814879753c8SEli Cohen 815879753c8SEli Cohen return MLX5_VIRTIO_EMULATION_VIRTIO_QUEUE_TYPE_PACKED; 8161a86b377SEli Cohen } 8171a86b377SEli Cohen 8181a86b377SEli Cohen static bool vq_is_tx(u16 idx) 8191a86b377SEli Cohen { 8201a86b377SEli Cohen return idx % 2; 8211a86b377SEli Cohen } 8221a86b377SEli Cohen 823e9d67e59SEli Cohen enum { 824e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_MRG_RXBUF = 2, 825e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_HOST_ECN = 4, 826e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_GUEST_ECN = 6, 827e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_GUEST_TSO6 = 7, 828e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_GUEST_TSO4 = 8, 829e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_GUEST_CSUM = 9, 830e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_CSUM = 10, 831e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_HOST_TSO6 = 11, 832e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_HOST_TSO4 = 12, 833e9d67e59SEli Cohen }; 834e9d67e59SEli Cohen 835e9d67e59SEli Cohen static u16 get_features(u64 features) 8361a86b377SEli Cohen { 837e9d67e59SEli Cohen return (!!(features & BIT_ULL(VIRTIO_NET_F_MRG_RXBUF)) << MLX5_VIRTIO_NET_F_MRG_RXBUF) | 838e9d67e59SEli Cohen (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_ECN)) << MLX5_VIRTIO_NET_F_HOST_ECN) | 839e9d67e59SEli Cohen (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_ECN)) << MLX5_VIRTIO_NET_F_GUEST_ECN) | 840e9d67e59SEli Cohen (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_TSO6)) << MLX5_VIRTIO_NET_F_GUEST_TSO6) | 841e9d67e59SEli Cohen (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_TSO4)) << MLX5_VIRTIO_NET_F_GUEST_TSO4) | 842e9d67e59SEli Cohen (!!(features & BIT_ULL(VIRTIO_NET_F_CSUM)) << MLX5_VIRTIO_NET_F_CSUM) | 843e9d67e59SEli Cohen (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO6)) << MLX5_VIRTIO_NET_F_HOST_TSO6) | 844e9d67e59SEli Cohen (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO4)) << MLX5_VIRTIO_NET_F_HOST_TSO4); 8451a86b377SEli Cohen } 8461a86b377SEli Cohen 8471892a3d4SEli Cohen static bool counters_supported(const struct mlx5_vdpa_dev *mvdev) 8481892a3d4SEli Cohen { 8491892a3d4SEli Cohen return MLX5_CAP_GEN_64(mvdev->mdev, general_obj_types) & 8501892a3d4SEli Cohen BIT_ULL(MLX5_OBJ_TYPE_VIRTIO_Q_COUNTERS); 8511892a3d4SEli Cohen } 8521892a3d4SEli Cohen 853bc9a2b3eSEli Cohen static bool msix_mode_supported(struct mlx5_vdpa_dev *mvdev) 854bc9a2b3eSEli Cohen { 855bc9a2b3eSEli Cohen return MLX5_CAP_DEV_VDPA_EMULATION(mvdev->mdev, event_mode) & 856bc9a2b3eSEli Cohen (1 << MLX5_VIRTIO_Q_EVENT_MODE_MSIX_MODE) && 857bc9a2b3eSEli Cohen pci_msix_can_alloc_dyn(mvdev->mdev->pdev); 858bc9a2b3eSEli Cohen } 859bc9a2b3eSEli Cohen 8601a86b377SEli Cohen static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 8611a86b377SEli Cohen { 8621a86b377SEli Cohen int inlen = MLX5_ST_SZ_BYTES(create_virtio_net_q_in); 8631a86b377SEli Cohen u32 out[MLX5_ST_SZ_DW(create_virtio_net_q_out)] = {}; 8641a86b377SEli Cohen void *obj_context; 865e9d67e59SEli Cohen u16 mlx_features; 8661a86b377SEli Cohen void *cmd_hdr; 8671a86b377SEli Cohen void *vq_ctx; 8681a86b377SEli Cohen void *in; 8691a86b377SEli Cohen int err; 8701a86b377SEli Cohen 8711a86b377SEli Cohen err = umems_create(ndev, mvq); 8721a86b377SEli Cohen if (err) 8731a86b377SEli Cohen return err; 8741a86b377SEli Cohen 8751a86b377SEli Cohen in = kzalloc(inlen, GFP_KERNEL); 8761a86b377SEli Cohen if (!in) { 8771a86b377SEli Cohen err = -ENOMEM; 8781a86b377SEli Cohen goto err_alloc; 8791a86b377SEli Cohen } 8801a86b377SEli Cohen 881e9d67e59SEli Cohen mlx_features = get_features(ndev->mvdev.actual_features); 8821a86b377SEli Cohen cmd_hdr = MLX5_ADDR_OF(create_virtio_net_q_in, in, general_obj_in_cmd_hdr); 8831a86b377SEli Cohen 8841a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); 8851a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_NET_Q); 8861a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 8871a86b377SEli Cohen 8881a86b377SEli Cohen obj_context = MLX5_ADDR_OF(create_virtio_net_q_in, in, obj_context); 8891a86b377SEli Cohen MLX5_SET(virtio_net_q_object, obj_context, hw_available_index, mvq->avail_idx); 890b35ccebeSEli Cohen MLX5_SET(virtio_net_q_object, obj_context, hw_used_index, mvq->used_idx); 8911a86b377SEli Cohen MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_12_3, 892e9d67e59SEli Cohen mlx_features >> 3); 893e9d67e59SEli Cohen MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_2_0, 894e9d67e59SEli Cohen mlx_features & 7); 8951a86b377SEli Cohen vq_ctx = MLX5_ADDR_OF(virtio_net_q_object, obj_context, virtio_q_context); 8961a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, virtio_q_type, get_queue_type(ndev)); 8971a86b377SEli Cohen 8981a86b377SEli Cohen if (vq_is_tx(mvq->index)) 8991a86b377SEli Cohen MLX5_SET(virtio_net_q_object, obj_context, tisn_or_qpn, ndev->res.tisn); 9001a86b377SEli Cohen 901bc9a2b3eSEli Cohen if (mvq->map.virq) { 902bc9a2b3eSEli Cohen MLX5_SET(virtio_q, vq_ctx, event_mode, MLX5_VIRTIO_Q_EVENT_MODE_MSIX_MODE); 903bc9a2b3eSEli Cohen MLX5_SET(virtio_q, vq_ctx, event_qpn_or_msix, mvq->map.index); 904bc9a2b3eSEli Cohen } else { 9051a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, event_mode, MLX5_VIRTIO_Q_EVENT_MODE_QP_MODE); 9061a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, event_qpn_or_msix, mvq->fwqp.mqp.qpn); 907bc9a2b3eSEli Cohen } 908bc9a2b3eSEli Cohen 909bc9a2b3eSEli Cohen MLX5_SET(virtio_q, vq_ctx, queue_index, mvq->index); 9101a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, queue_size, mvq->num_ent); 9111a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, virtio_version_1_0, 9124b454a82SEli Cohen !!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_F_VERSION_1))); 9131a86b377SEli Cohen MLX5_SET64(virtio_q, vq_ctx, desc_addr, mvq->desc_addr); 9141a86b377SEli Cohen MLX5_SET64(virtio_q, vq_ctx, used_addr, mvq->device_addr); 9151a86b377SEli Cohen MLX5_SET64(virtio_q, vq_ctx, available_addr, mvq->driver_addr); 91683fec3f1SAharon Landau MLX5_SET(virtio_q, vq_ctx, virtio_q_mkey, ndev->mvdev.mr.mkey); 9171a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, umem_1_id, mvq->umem1.id); 9181a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, umem_1_size, mvq->umem1.size); 9191a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, umem_2_id, mvq->umem2.id); 920e3011776SEli Cohen MLX5_SET(virtio_q, vq_ctx, umem_2_size, mvq->umem2.size); 9211a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, umem_3_id, mvq->umem3.id); 922e3011776SEli Cohen MLX5_SET(virtio_q, vq_ctx, umem_3_size, mvq->umem3.size); 9231a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, pd, ndev->mvdev.res.pdn); 9241892a3d4SEli Cohen if (counters_supported(&ndev->mvdev)) 9251892a3d4SEli Cohen MLX5_SET(virtio_q, vq_ctx, counter_set_id, mvq->counter_set_id); 9261a86b377SEli Cohen 9271a86b377SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, inlen, out, sizeof(out)); 9281a86b377SEli Cohen if (err) 9291a86b377SEli Cohen goto err_cmd; 9301a86b377SEli Cohen 931cae15c2eSEli Cohen mvq->fw_state = MLX5_VIRTIO_NET_Q_OBJECT_STATE_INIT; 9321a86b377SEli Cohen kfree(in); 9331a86b377SEli Cohen mvq->virtq_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); 9341a86b377SEli Cohen 9351a86b377SEli Cohen return 0; 9361a86b377SEli Cohen 9371a86b377SEli Cohen err_cmd: 9381a86b377SEli Cohen kfree(in); 9391a86b377SEli Cohen err_alloc: 9401a86b377SEli Cohen umems_destroy(ndev, mvq); 9411a86b377SEli Cohen return err; 9421a86b377SEli Cohen } 9431a86b377SEli Cohen 9441a86b377SEli Cohen static void destroy_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 9451a86b377SEli Cohen { 9461a86b377SEli Cohen u32 in[MLX5_ST_SZ_DW(destroy_virtio_net_q_in)] = {}; 9471a86b377SEli Cohen u32 out[MLX5_ST_SZ_DW(destroy_virtio_net_q_out)] = {}; 9481a86b377SEli Cohen 9491a86b377SEli Cohen MLX5_SET(destroy_virtio_net_q_in, in, general_obj_out_cmd_hdr.opcode, 9501a86b377SEli Cohen MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); 9511a86b377SEli Cohen MLX5_SET(destroy_virtio_net_q_in, in, general_obj_out_cmd_hdr.obj_id, mvq->virtq_id); 9521a86b377SEli Cohen MLX5_SET(destroy_virtio_net_q_in, in, general_obj_out_cmd_hdr.uid, ndev->mvdev.res.uid); 9531a86b377SEli Cohen MLX5_SET(destroy_virtio_net_q_in, in, general_obj_out_cmd_hdr.obj_type, 9541a86b377SEli Cohen MLX5_OBJ_TYPE_VIRTIO_NET_Q); 9551a86b377SEli Cohen if (mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out))) { 9561a86b377SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "destroy virtqueue 0x%x\n", mvq->virtq_id); 9571a86b377SEli Cohen return; 9581a86b377SEli Cohen } 959cae15c2eSEli Cohen mvq->fw_state = MLX5_VIRTIO_NET_Q_OBJECT_NONE; 9601a86b377SEli Cohen umems_destroy(ndev, mvq); 9611a86b377SEli Cohen } 9621a86b377SEli Cohen 9631a86b377SEli Cohen static u32 get_rqpn(struct mlx5_vdpa_virtqueue *mvq, bool fw) 9641a86b377SEli Cohen { 9651a86b377SEli Cohen return fw ? mvq->vqqp.mqp.qpn : mvq->fwqp.mqp.qpn; 9661a86b377SEli Cohen } 9671a86b377SEli Cohen 9681a86b377SEli Cohen static u32 get_qpn(struct mlx5_vdpa_virtqueue *mvq, bool fw) 9691a86b377SEli Cohen { 9701a86b377SEli Cohen return fw ? mvq->fwqp.mqp.qpn : mvq->vqqp.mqp.qpn; 9711a86b377SEli Cohen } 9721a86b377SEli Cohen 9731a86b377SEli Cohen static void alloc_inout(struct mlx5_vdpa_net *ndev, int cmd, void **in, int *inlen, void **out, 9741a86b377SEli Cohen int *outlen, u32 qpn, u32 rqpn) 9751a86b377SEli Cohen { 9761a86b377SEli Cohen void *qpc; 9771a86b377SEli Cohen void *pp; 9781a86b377SEli Cohen 9791a86b377SEli Cohen switch (cmd) { 9801a86b377SEli Cohen case MLX5_CMD_OP_2RST_QP: 9811a86b377SEli Cohen *inlen = MLX5_ST_SZ_BYTES(qp_2rst_in); 9821a86b377SEli Cohen *outlen = MLX5_ST_SZ_BYTES(qp_2rst_out); 9831a86b377SEli Cohen *in = kzalloc(*inlen, GFP_KERNEL); 9841a86b377SEli Cohen *out = kzalloc(*outlen, GFP_KERNEL); 985f31231bfSColin Ian King if (!*in || !*out) 9861a86b377SEli Cohen goto outerr; 9871a86b377SEli Cohen 9881a86b377SEli Cohen MLX5_SET(qp_2rst_in, *in, opcode, cmd); 9891a86b377SEli Cohen MLX5_SET(qp_2rst_in, *in, uid, ndev->mvdev.res.uid); 9901a86b377SEli Cohen MLX5_SET(qp_2rst_in, *in, qpn, qpn); 9911a86b377SEli Cohen break; 9921a86b377SEli Cohen case MLX5_CMD_OP_RST2INIT_QP: 9931a86b377SEli Cohen *inlen = MLX5_ST_SZ_BYTES(rst2init_qp_in); 9941a86b377SEli Cohen *outlen = MLX5_ST_SZ_BYTES(rst2init_qp_out); 9951a86b377SEli Cohen *in = kzalloc(*inlen, GFP_KERNEL); 9961a86b377SEli Cohen *out = kzalloc(MLX5_ST_SZ_BYTES(rst2init_qp_out), GFP_KERNEL); 997f31231bfSColin Ian King if (!*in || !*out) 9981a86b377SEli Cohen goto outerr; 9991a86b377SEli Cohen 10001a86b377SEli Cohen MLX5_SET(rst2init_qp_in, *in, opcode, cmd); 10011a86b377SEli Cohen MLX5_SET(rst2init_qp_in, *in, uid, ndev->mvdev.res.uid); 10021a86b377SEli Cohen MLX5_SET(rst2init_qp_in, *in, qpn, qpn); 10031a86b377SEli Cohen qpc = MLX5_ADDR_OF(rst2init_qp_in, *in, qpc); 10041a86b377SEli Cohen MLX5_SET(qpc, qpc, remote_qpn, rqpn); 10051a86b377SEli Cohen MLX5_SET(qpc, qpc, rwe, 1); 10061a86b377SEli Cohen pp = MLX5_ADDR_OF(qpc, qpc, primary_address_path); 10071a86b377SEli Cohen MLX5_SET(ads, pp, vhca_port_num, 1); 10081a86b377SEli Cohen break; 10091a86b377SEli Cohen case MLX5_CMD_OP_INIT2RTR_QP: 10101a86b377SEli Cohen *inlen = MLX5_ST_SZ_BYTES(init2rtr_qp_in); 10111a86b377SEli Cohen *outlen = MLX5_ST_SZ_BYTES(init2rtr_qp_out); 10121a86b377SEli Cohen *in = kzalloc(*inlen, GFP_KERNEL); 10131a86b377SEli Cohen *out = kzalloc(MLX5_ST_SZ_BYTES(init2rtr_qp_out), GFP_KERNEL); 1014f31231bfSColin Ian King if (!*in || !*out) 10151a86b377SEli Cohen goto outerr; 10161a86b377SEli Cohen 10171a86b377SEli Cohen MLX5_SET(init2rtr_qp_in, *in, opcode, cmd); 10181a86b377SEli Cohen MLX5_SET(init2rtr_qp_in, *in, uid, ndev->mvdev.res.uid); 10191a86b377SEli Cohen MLX5_SET(init2rtr_qp_in, *in, qpn, qpn); 10201a86b377SEli Cohen qpc = MLX5_ADDR_OF(rst2init_qp_in, *in, qpc); 10211a86b377SEli Cohen MLX5_SET(qpc, qpc, mtu, MLX5_QPC_MTU_256_BYTES); 10221a86b377SEli Cohen MLX5_SET(qpc, qpc, log_msg_max, 30); 10231a86b377SEli Cohen MLX5_SET(qpc, qpc, remote_qpn, rqpn); 10241a86b377SEli Cohen pp = MLX5_ADDR_OF(qpc, qpc, primary_address_path); 10251a86b377SEli Cohen MLX5_SET(ads, pp, fl, 1); 10261a86b377SEli Cohen break; 10271a86b377SEli Cohen case MLX5_CMD_OP_RTR2RTS_QP: 10281a86b377SEli Cohen *inlen = MLX5_ST_SZ_BYTES(rtr2rts_qp_in); 10291a86b377SEli Cohen *outlen = MLX5_ST_SZ_BYTES(rtr2rts_qp_out); 10301a86b377SEli Cohen *in = kzalloc(*inlen, GFP_KERNEL); 10311a86b377SEli Cohen *out = kzalloc(MLX5_ST_SZ_BYTES(rtr2rts_qp_out), GFP_KERNEL); 1032f31231bfSColin Ian King if (!*in || !*out) 10331a86b377SEli Cohen goto outerr; 10341a86b377SEli Cohen 10351a86b377SEli Cohen MLX5_SET(rtr2rts_qp_in, *in, opcode, cmd); 10361a86b377SEli Cohen MLX5_SET(rtr2rts_qp_in, *in, uid, ndev->mvdev.res.uid); 10371a86b377SEli Cohen MLX5_SET(rtr2rts_qp_in, *in, qpn, qpn); 10381a86b377SEli Cohen qpc = MLX5_ADDR_OF(rst2init_qp_in, *in, qpc); 10391a86b377SEli Cohen pp = MLX5_ADDR_OF(qpc, qpc, primary_address_path); 10401a86b377SEli Cohen MLX5_SET(ads, pp, ack_timeout, 14); 10411a86b377SEli Cohen MLX5_SET(qpc, qpc, retry_count, 7); 10421a86b377SEli Cohen MLX5_SET(qpc, qpc, rnr_retry, 7); 10431a86b377SEli Cohen break; 10441a86b377SEli Cohen default: 1045f31231bfSColin Ian King goto outerr_nullify; 10461a86b377SEli Cohen } 10471a86b377SEli Cohen 10481a86b377SEli Cohen return; 10491a86b377SEli Cohen 10501a86b377SEli Cohen outerr: 10511a86b377SEli Cohen kfree(*in); 10521a86b377SEli Cohen kfree(*out); 1053f31231bfSColin Ian King outerr_nullify: 10541a86b377SEli Cohen *in = NULL; 10551a86b377SEli Cohen *out = NULL; 10561a86b377SEli Cohen } 10571a86b377SEli Cohen 10581a86b377SEli Cohen static void free_inout(void *in, void *out) 10591a86b377SEli Cohen { 10601a86b377SEli Cohen kfree(in); 10611a86b377SEli Cohen kfree(out); 10621a86b377SEli Cohen } 10631a86b377SEli Cohen 10641a86b377SEli Cohen /* Two QPs are used by each virtqueue. One is used by the driver and one by 10651a86b377SEli Cohen * firmware. The fw argument indicates whether the subjected QP is the one used 10661a86b377SEli Cohen * by firmware. 10671a86b377SEli Cohen */ 10681a86b377SEli Cohen static int modify_qp(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, bool fw, int cmd) 10691a86b377SEli Cohen { 10701a86b377SEli Cohen int outlen; 10711a86b377SEli Cohen int inlen; 10721a86b377SEli Cohen void *out; 10731a86b377SEli Cohen void *in; 10741a86b377SEli Cohen int err; 10751a86b377SEli Cohen 10761a86b377SEli Cohen alloc_inout(ndev, cmd, &in, &inlen, &out, &outlen, get_qpn(mvq, fw), get_rqpn(mvq, fw)); 10771a86b377SEli Cohen if (!in || !out) 10781a86b377SEli Cohen return -ENOMEM; 10791a86b377SEli Cohen 10801a86b377SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, inlen, out, outlen); 10811a86b377SEli Cohen free_inout(in, out); 10821a86b377SEli Cohen return err; 10831a86b377SEli Cohen } 10841a86b377SEli Cohen 10851a86b377SEli Cohen static int connect_qps(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 10861a86b377SEli Cohen { 10871a86b377SEli Cohen int err; 10881a86b377SEli Cohen 10891a86b377SEli Cohen err = modify_qp(ndev, mvq, true, MLX5_CMD_OP_2RST_QP); 10901a86b377SEli Cohen if (err) 10911a86b377SEli Cohen return err; 10921a86b377SEli Cohen 10931a86b377SEli Cohen err = modify_qp(ndev, mvq, false, MLX5_CMD_OP_2RST_QP); 10941a86b377SEli Cohen if (err) 10951a86b377SEli Cohen return err; 10961a86b377SEli Cohen 10971a86b377SEli Cohen err = modify_qp(ndev, mvq, true, MLX5_CMD_OP_RST2INIT_QP); 10981a86b377SEli Cohen if (err) 10991a86b377SEli Cohen return err; 11001a86b377SEli Cohen 11011a86b377SEli Cohen err = modify_qp(ndev, mvq, false, MLX5_CMD_OP_RST2INIT_QP); 11021a86b377SEli Cohen if (err) 11031a86b377SEli Cohen return err; 11041a86b377SEli Cohen 11051a86b377SEli Cohen err = modify_qp(ndev, mvq, true, MLX5_CMD_OP_INIT2RTR_QP); 11061a86b377SEli Cohen if (err) 11071a86b377SEli Cohen return err; 11081a86b377SEli Cohen 11091a86b377SEli Cohen err = modify_qp(ndev, mvq, false, MLX5_CMD_OP_INIT2RTR_QP); 11101a86b377SEli Cohen if (err) 11111a86b377SEli Cohen return err; 11121a86b377SEli Cohen 11131a86b377SEli Cohen return modify_qp(ndev, mvq, true, MLX5_CMD_OP_RTR2RTS_QP); 11141a86b377SEli Cohen } 11151a86b377SEli Cohen 11161a86b377SEli Cohen struct mlx5_virtq_attr { 11171a86b377SEli Cohen u8 state; 11181a86b377SEli Cohen u16 available_index; 1119b35ccebeSEli Cohen u16 used_index; 11201a86b377SEli Cohen }; 11211a86b377SEli Cohen 11221a86b377SEli Cohen static int query_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, 11231a86b377SEli Cohen struct mlx5_virtq_attr *attr) 11241a86b377SEli Cohen { 11251a86b377SEli Cohen int outlen = MLX5_ST_SZ_BYTES(query_virtio_net_q_out); 11261a86b377SEli Cohen u32 in[MLX5_ST_SZ_DW(query_virtio_net_q_in)] = {}; 11271a86b377SEli Cohen void *out; 11281a86b377SEli Cohen void *obj_context; 11291a86b377SEli Cohen void *cmd_hdr; 11301a86b377SEli Cohen int err; 11311a86b377SEli Cohen 11321a86b377SEli Cohen out = kzalloc(outlen, GFP_KERNEL); 11331a86b377SEli Cohen if (!out) 11341a86b377SEli Cohen return -ENOMEM; 11351a86b377SEli Cohen 11361a86b377SEli Cohen cmd_hdr = MLX5_ADDR_OF(query_virtio_net_q_in, in, general_obj_in_cmd_hdr); 11371a86b377SEli Cohen 11381a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_QUERY_GENERAL_OBJECT); 11391a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_NET_Q); 11401a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_id, mvq->virtq_id); 11411a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 11421a86b377SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, outlen); 11431a86b377SEli Cohen if (err) 11441a86b377SEli Cohen goto err_cmd; 11451a86b377SEli Cohen 11461a86b377SEli Cohen obj_context = MLX5_ADDR_OF(query_virtio_net_q_out, out, obj_context); 11471a86b377SEli Cohen memset(attr, 0, sizeof(*attr)); 11481a86b377SEli Cohen attr->state = MLX5_GET(virtio_net_q_object, obj_context, state); 11491a86b377SEli Cohen attr->available_index = MLX5_GET(virtio_net_q_object, obj_context, hw_available_index); 1150b35ccebeSEli Cohen attr->used_index = MLX5_GET(virtio_net_q_object, obj_context, hw_used_index); 11511a86b377SEli Cohen kfree(out); 11521a86b377SEli Cohen return 0; 11531a86b377SEli Cohen 11541a86b377SEli Cohen err_cmd: 11551a86b377SEli Cohen kfree(out); 11561a86b377SEli Cohen return err; 11571a86b377SEli Cohen } 11581a86b377SEli Cohen 1159cae15c2eSEli Cohen static bool is_valid_state_change(int oldstate, int newstate) 1160cae15c2eSEli Cohen { 1161cae15c2eSEli Cohen switch (oldstate) { 1162cae15c2eSEli Cohen case MLX5_VIRTIO_NET_Q_OBJECT_STATE_INIT: 1163cae15c2eSEli Cohen return newstate == MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY; 1164cae15c2eSEli Cohen case MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY: 1165cae15c2eSEli Cohen return newstate == MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND; 1166cae15c2eSEli Cohen case MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND: 1167cae15c2eSEli Cohen case MLX5_VIRTIO_NET_Q_OBJECT_STATE_ERR: 1168cae15c2eSEli Cohen default: 1169cae15c2eSEli Cohen return false; 1170cae15c2eSEli Cohen } 1171cae15c2eSEli Cohen } 1172cae15c2eSEli Cohen 11731a86b377SEli Cohen static int modify_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int state) 11741a86b377SEli Cohen { 11751a86b377SEli Cohen int inlen = MLX5_ST_SZ_BYTES(modify_virtio_net_q_in); 11761a86b377SEli Cohen u32 out[MLX5_ST_SZ_DW(modify_virtio_net_q_out)] = {}; 11771a86b377SEli Cohen void *obj_context; 11781a86b377SEli Cohen void *cmd_hdr; 11791a86b377SEli Cohen void *in; 11801a86b377SEli Cohen int err; 11811a86b377SEli Cohen 1182cae15c2eSEli Cohen if (mvq->fw_state == MLX5_VIRTIO_NET_Q_OBJECT_NONE) 1183cae15c2eSEli Cohen return 0; 1184cae15c2eSEli Cohen 1185cae15c2eSEli Cohen if (!is_valid_state_change(mvq->fw_state, state)) 1186cae15c2eSEli Cohen return -EINVAL; 1187cae15c2eSEli Cohen 11881a86b377SEli Cohen in = kzalloc(inlen, GFP_KERNEL); 11891a86b377SEli Cohen if (!in) 11901a86b377SEli Cohen return -ENOMEM; 11911a86b377SEli Cohen 11921a86b377SEli Cohen cmd_hdr = MLX5_ADDR_OF(modify_virtio_net_q_in, in, general_obj_in_cmd_hdr); 11931a86b377SEli Cohen 11941a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_MODIFY_GENERAL_OBJECT); 11951a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_NET_Q); 11961a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_id, mvq->virtq_id); 11971a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 11981a86b377SEli Cohen 11991a86b377SEli Cohen obj_context = MLX5_ADDR_OF(modify_virtio_net_q_in, in, obj_context); 12001a86b377SEli Cohen MLX5_SET64(virtio_net_q_object, obj_context, modify_field_select, 12011a86b377SEli Cohen MLX5_VIRTQ_MODIFY_MASK_STATE); 12021a86b377SEli Cohen MLX5_SET(virtio_net_q_object, obj_context, state, state); 12031a86b377SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, inlen, out, sizeof(out)); 12041a86b377SEli Cohen kfree(in); 12051a86b377SEli Cohen if (!err) 12061a86b377SEli Cohen mvq->fw_state = state; 12071a86b377SEli Cohen 12081a86b377SEli Cohen return err; 12091a86b377SEli Cohen } 12101a86b377SEli Cohen 12111892a3d4SEli Cohen static int counter_set_alloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 12121892a3d4SEli Cohen { 12131892a3d4SEli Cohen u32 in[MLX5_ST_SZ_DW(create_virtio_q_counters_in)] = {}; 12141892a3d4SEli Cohen u32 out[MLX5_ST_SZ_DW(create_virtio_q_counters_out)] = {}; 12151892a3d4SEli Cohen void *cmd_hdr; 12161892a3d4SEli Cohen int err; 12171892a3d4SEli Cohen 12181892a3d4SEli Cohen if (!counters_supported(&ndev->mvdev)) 12191892a3d4SEli Cohen return 0; 12201892a3d4SEli Cohen 12211892a3d4SEli Cohen cmd_hdr = MLX5_ADDR_OF(create_virtio_q_counters_in, in, hdr); 12221892a3d4SEli Cohen 12231892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); 12241892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_Q_COUNTERS); 12251892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 12261892a3d4SEli Cohen 12271892a3d4SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out)); 12281892a3d4SEli Cohen if (err) 12291892a3d4SEli Cohen return err; 12301892a3d4SEli Cohen 12311892a3d4SEli Cohen mvq->counter_set_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); 12321892a3d4SEli Cohen 12331892a3d4SEli Cohen return 0; 12341892a3d4SEli Cohen } 12351892a3d4SEli Cohen 12361892a3d4SEli Cohen static void counter_set_dealloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 12371892a3d4SEli Cohen { 12381892a3d4SEli Cohen u32 in[MLX5_ST_SZ_DW(destroy_virtio_q_counters_in)] = {}; 12391892a3d4SEli Cohen u32 out[MLX5_ST_SZ_DW(destroy_virtio_q_counters_out)] = {}; 12401892a3d4SEli Cohen 12411892a3d4SEli Cohen if (!counters_supported(&ndev->mvdev)) 12421892a3d4SEli Cohen return; 12431892a3d4SEli Cohen 12441892a3d4SEli Cohen MLX5_SET(destroy_virtio_q_counters_in, in, hdr.opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); 12451892a3d4SEli Cohen MLX5_SET(destroy_virtio_q_counters_in, in, hdr.obj_id, mvq->counter_set_id); 12461892a3d4SEli Cohen MLX5_SET(destroy_virtio_q_counters_in, in, hdr.uid, ndev->mvdev.res.uid); 12471892a3d4SEli Cohen MLX5_SET(destroy_virtio_q_counters_in, in, hdr.obj_type, MLX5_OBJ_TYPE_VIRTIO_Q_COUNTERS); 12481892a3d4SEli Cohen if (mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out))) 12491892a3d4SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "dealloc counter set 0x%x\n", mvq->counter_set_id); 12501892a3d4SEli Cohen } 12511892a3d4SEli Cohen 1252bc9a2b3eSEli Cohen static irqreturn_t mlx5_vdpa_int_handler(int irq, void *priv) 1253bc9a2b3eSEli Cohen { 1254bc9a2b3eSEli Cohen struct vdpa_callback *cb = priv; 1255bc9a2b3eSEli Cohen 1256bc9a2b3eSEli Cohen if (cb->callback) 1257bc9a2b3eSEli Cohen return cb->callback(cb->private); 1258bc9a2b3eSEli Cohen 1259bc9a2b3eSEli Cohen return IRQ_HANDLED; 1260bc9a2b3eSEli Cohen } 1261bc9a2b3eSEli Cohen 1262bc9a2b3eSEli Cohen static void alloc_vector(struct mlx5_vdpa_net *ndev, 1263bc9a2b3eSEli Cohen struct mlx5_vdpa_virtqueue *mvq) 1264bc9a2b3eSEli Cohen { 1265bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool *irqp = &ndev->irqp; 1266bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool_entry *ent; 1267bc9a2b3eSEli Cohen int err; 1268bc9a2b3eSEli Cohen int i; 1269bc9a2b3eSEli Cohen 1270bc9a2b3eSEli Cohen for (i = 0; i < irqp->num_ent; i++) { 1271bc9a2b3eSEli Cohen ent = &irqp->entries[i]; 1272bc9a2b3eSEli Cohen if (!ent->used) { 1273bc9a2b3eSEli Cohen snprintf(ent->name, MLX5_VDPA_IRQ_NAME_LEN, "%s-vq-%d", 1274bc9a2b3eSEli Cohen dev_name(&ndev->mvdev.vdev.dev), mvq->index); 1275bc9a2b3eSEli Cohen ent->dev_id = &ndev->event_cbs[mvq->index]; 1276bc9a2b3eSEli Cohen err = request_irq(ent->map.virq, mlx5_vdpa_int_handler, 0, 1277bc9a2b3eSEli Cohen ent->name, ent->dev_id); 1278bc9a2b3eSEli Cohen if (err) 1279bc9a2b3eSEli Cohen return; 1280bc9a2b3eSEli Cohen 1281bc9a2b3eSEli Cohen ent->used = true; 1282bc9a2b3eSEli Cohen mvq->map = ent->map; 1283bc9a2b3eSEli Cohen return; 1284bc9a2b3eSEli Cohen } 1285bc9a2b3eSEli Cohen } 1286bc9a2b3eSEli Cohen } 1287bc9a2b3eSEli Cohen 1288bc9a2b3eSEli Cohen static void dealloc_vector(struct mlx5_vdpa_net *ndev, 1289bc9a2b3eSEli Cohen struct mlx5_vdpa_virtqueue *mvq) 1290bc9a2b3eSEli Cohen { 1291bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool *irqp = &ndev->irqp; 1292bc9a2b3eSEli Cohen int i; 1293bc9a2b3eSEli Cohen 1294bc9a2b3eSEli Cohen for (i = 0; i < irqp->num_ent; i++) 1295bc9a2b3eSEli Cohen if (mvq->map.virq == irqp->entries[i].map.virq) { 1296bc9a2b3eSEli Cohen free_irq(mvq->map.virq, irqp->entries[i].dev_id); 1297bc9a2b3eSEli Cohen irqp->entries[i].used = false; 1298bc9a2b3eSEli Cohen return; 1299bc9a2b3eSEli Cohen } 1300bc9a2b3eSEli Cohen } 1301bc9a2b3eSEli Cohen 13021a86b377SEli Cohen static int setup_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 13031a86b377SEli Cohen { 13041a86b377SEli Cohen u16 idx = mvq->index; 13051a86b377SEli Cohen int err; 13061a86b377SEli Cohen 13071a86b377SEli Cohen if (!mvq->num_ent) 13081a86b377SEli Cohen return 0; 13091a86b377SEli Cohen 131052893733SEli Cohen if (mvq->initialized) 131152893733SEli Cohen return 0; 13121a86b377SEli Cohen 13131a86b377SEli Cohen err = cq_create(ndev, idx, mvq->num_ent); 13141a86b377SEli Cohen if (err) 13151a86b377SEli Cohen return err; 13161a86b377SEli Cohen 13171a86b377SEli Cohen err = qp_create(ndev, mvq, &mvq->fwqp); 13181a86b377SEli Cohen if (err) 13191a86b377SEli Cohen goto err_fwqp; 13201a86b377SEli Cohen 13211a86b377SEli Cohen err = qp_create(ndev, mvq, &mvq->vqqp); 13221a86b377SEli Cohen if (err) 13231a86b377SEli Cohen goto err_vqqp; 13241a86b377SEli Cohen 13251a86b377SEli Cohen err = connect_qps(ndev, mvq); 13261a86b377SEli Cohen if (err) 13271a86b377SEli Cohen goto err_connect; 13281a86b377SEli Cohen 13291892a3d4SEli Cohen err = counter_set_alloc(ndev, mvq); 13301892a3d4SEli Cohen if (err) 1331bc9a2b3eSEli Cohen goto err_connect; 13321892a3d4SEli Cohen 1333bc9a2b3eSEli Cohen alloc_vector(ndev, mvq); 13341a86b377SEli Cohen err = create_virtqueue(ndev, mvq); 13351a86b377SEli Cohen if (err) 1336bc9a2b3eSEli Cohen goto err_vq; 13371a86b377SEli Cohen 13381a86b377SEli Cohen if (mvq->ready) { 13391a86b377SEli Cohen err = modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY); 13401a86b377SEli Cohen if (err) { 13411a86b377SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "failed to modify to ready vq idx %d(%d)\n", 13421a86b377SEli Cohen idx, err); 1343bc9a2b3eSEli Cohen goto err_modify; 13441a86b377SEli Cohen } 13451a86b377SEli Cohen } 13461a86b377SEli Cohen 13471a86b377SEli Cohen mvq->initialized = true; 13481a86b377SEli Cohen return 0; 13491a86b377SEli Cohen 1350bc9a2b3eSEli Cohen err_modify: 1351bc9a2b3eSEli Cohen destroy_virtqueue(ndev, mvq); 1352bc9a2b3eSEli Cohen err_vq: 1353bc9a2b3eSEli Cohen dealloc_vector(ndev, mvq); 13541892a3d4SEli Cohen counter_set_dealloc(ndev, mvq); 1355bc9a2b3eSEli Cohen err_connect: 13561a86b377SEli Cohen qp_destroy(ndev, &mvq->vqqp); 13571a86b377SEli Cohen err_vqqp: 13581a86b377SEli Cohen qp_destroy(ndev, &mvq->fwqp); 13591a86b377SEli Cohen err_fwqp: 13601a86b377SEli Cohen cq_destroy(ndev, idx); 13611a86b377SEli Cohen return err; 13621a86b377SEli Cohen } 13631a86b377SEli Cohen 13641a86b377SEli Cohen static void suspend_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 13651a86b377SEli Cohen { 13661a86b377SEli Cohen struct mlx5_virtq_attr attr; 13671a86b377SEli Cohen 13681a86b377SEli Cohen if (!mvq->initialized) 13691a86b377SEli Cohen return; 13701a86b377SEli Cohen 13711a86b377SEli Cohen if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY) 13721a86b377SEli Cohen return; 13731a86b377SEli Cohen 13741a86b377SEli Cohen if (modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND)) 13751a86b377SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "modify to suspend failed\n"); 13763176e974SSi-Wei Liu 13773176e974SSi-Wei Liu if (query_virtqueue(ndev, mvq, &attr)) { 13783176e974SSi-Wei Liu mlx5_vdpa_warn(&ndev->mvdev, "failed to query virtqueue\n"); 13793176e974SSi-Wei Liu return; 13803176e974SSi-Wei Liu } 13813176e974SSi-Wei Liu mvq->avail_idx = attr.available_index; 1382bc04d93eSEli Cohen mvq->used_idx = attr.used_index; 13831a86b377SEli Cohen } 13841a86b377SEli Cohen 13851a86b377SEli Cohen static void suspend_vqs(struct mlx5_vdpa_net *ndev) 13861a86b377SEli Cohen { 13871a86b377SEli Cohen int i; 13881a86b377SEli Cohen 138975560522SEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) 13901a86b377SEli Cohen suspend_vq(ndev, &ndev->vqs[i]); 13911a86b377SEli Cohen } 13921a86b377SEli Cohen 13931a86b377SEli Cohen static void teardown_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 13941a86b377SEli Cohen { 13951a86b377SEli Cohen if (!mvq->initialized) 13961a86b377SEli Cohen return; 13971a86b377SEli Cohen 13981a86b377SEli Cohen suspend_vq(ndev, mvq); 13991a86b377SEli Cohen destroy_virtqueue(ndev, mvq); 1400bc9a2b3eSEli Cohen dealloc_vector(ndev, mvq); 14011892a3d4SEli Cohen counter_set_dealloc(ndev, mvq); 14021a86b377SEli Cohen qp_destroy(ndev, &mvq->vqqp); 14031a86b377SEli Cohen qp_destroy(ndev, &mvq->fwqp); 14041a86b377SEli Cohen cq_destroy(ndev, mvq->index); 14051a86b377SEli Cohen mvq->initialized = false; 14061a86b377SEli Cohen } 14071a86b377SEli Cohen 14081a86b377SEli Cohen static int create_rqt(struct mlx5_vdpa_net *ndev) 14091a86b377SEli Cohen { 1410a43ae805SEli Cohen int rqt_table_size = roundup_pow_of_two(ndev->rqt_size); 1411a43ae805SEli Cohen int act_sz = roundup_pow_of_two(ndev->cur_num_vqs / 2); 14121a86b377SEli Cohen __be32 *list; 14131a86b377SEli Cohen void *rqtc; 14141a86b377SEli Cohen int inlen; 14151a86b377SEli Cohen void *in; 14161a86b377SEli Cohen int i, j; 14171a86b377SEli Cohen int err; 14181a86b377SEli Cohen 1419a43ae805SEli Cohen inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + rqt_table_size * MLX5_ST_SZ_BYTES(rq_num); 14201a86b377SEli Cohen in = kzalloc(inlen, GFP_KERNEL); 14211a86b377SEli Cohen if (!in) 14221a86b377SEli Cohen return -ENOMEM; 14231a86b377SEli Cohen 14241a86b377SEli Cohen MLX5_SET(create_rqt_in, in, uid, ndev->mvdev.res.uid); 14251a86b377SEli Cohen rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context); 14261a86b377SEli Cohen 14271a86b377SEli Cohen MLX5_SET(rqtc, rqtc, list_q_type, MLX5_RQTC_LIST_Q_TYPE_VIRTIO_NET_Q); 1428a43ae805SEli Cohen MLX5_SET(rqtc, rqtc, rqt_max_size, rqt_table_size); 14291a86b377SEli Cohen list = MLX5_ADDR_OF(rqtc, rqtc, rq_num[0]); 1430a43ae805SEli Cohen for (i = 0, j = 0; i < act_sz; i++, j += 2) 1431acde3929SEli Cohen list[i] = cpu_to_be32(ndev->vqs[j % ndev->cur_num_vqs].virtq_id); 14321a86b377SEli Cohen 1433a43ae805SEli Cohen MLX5_SET(rqtc, rqtc, rqt_actual_size, act_sz); 14341a86b377SEli Cohen err = mlx5_vdpa_create_rqt(&ndev->mvdev, in, inlen, &ndev->res.rqtn); 14351a86b377SEli Cohen kfree(in); 14361a86b377SEli Cohen if (err) 14371a86b377SEli Cohen return err; 14381a86b377SEli Cohen 14391a86b377SEli Cohen return 0; 14401a86b377SEli Cohen } 14411a86b377SEli Cohen 144252893733SEli Cohen #define MLX5_MODIFY_RQT_NUM_RQS ((u64)1) 144352893733SEli Cohen 144452893733SEli Cohen static int modify_rqt(struct mlx5_vdpa_net *ndev, int num) 144552893733SEli Cohen { 1446a43ae805SEli Cohen int act_sz = roundup_pow_of_two(num / 2); 144752893733SEli Cohen __be32 *list; 144852893733SEli Cohen void *rqtc; 144952893733SEli Cohen int inlen; 145052893733SEli Cohen void *in; 145152893733SEli Cohen int i, j; 145252893733SEli Cohen int err; 145352893733SEli Cohen 1454a43ae805SEli Cohen inlen = MLX5_ST_SZ_BYTES(modify_rqt_in) + act_sz * MLX5_ST_SZ_BYTES(rq_num); 145552893733SEli Cohen in = kzalloc(inlen, GFP_KERNEL); 145652893733SEli Cohen if (!in) 145752893733SEli Cohen return -ENOMEM; 145852893733SEli Cohen 145952893733SEli Cohen MLX5_SET(modify_rqt_in, in, uid, ndev->mvdev.res.uid); 146052893733SEli Cohen MLX5_SET64(modify_rqt_in, in, bitmask, MLX5_MODIFY_RQT_NUM_RQS); 146152893733SEli Cohen rqtc = MLX5_ADDR_OF(modify_rqt_in, in, ctx); 146252893733SEli Cohen MLX5_SET(rqtc, rqtc, list_q_type, MLX5_RQTC_LIST_Q_TYPE_VIRTIO_NET_Q); 146352893733SEli Cohen 146452893733SEli Cohen list = MLX5_ADDR_OF(rqtc, rqtc, rq_num[0]); 1465a43ae805SEli Cohen for (i = 0, j = 0; i < act_sz; i++, j = j + 2) 1466a7f46ba4SEli Cohen list[i] = cpu_to_be32(ndev->vqs[j % num].virtq_id); 146752893733SEli Cohen 1468a43ae805SEli Cohen MLX5_SET(rqtc, rqtc, rqt_actual_size, act_sz); 146952893733SEli Cohen err = mlx5_vdpa_modify_rqt(&ndev->mvdev, in, inlen, ndev->res.rqtn); 147052893733SEli Cohen kfree(in); 147152893733SEli Cohen if (err) 147252893733SEli Cohen return err; 147352893733SEli Cohen 147452893733SEli Cohen return 0; 147552893733SEli Cohen } 147652893733SEli Cohen 14771a86b377SEli Cohen static void destroy_rqt(struct mlx5_vdpa_net *ndev) 14781a86b377SEli Cohen { 14791a86b377SEli Cohen mlx5_vdpa_destroy_rqt(&ndev->mvdev, ndev->res.rqtn); 14801a86b377SEli Cohen } 14811a86b377SEli Cohen 14821a86b377SEli Cohen static int create_tir(struct mlx5_vdpa_net *ndev) 14831a86b377SEli Cohen { 14841a86b377SEli Cohen #define HASH_IP_L4PORTS \ 14851a86b377SEli Cohen (MLX5_HASH_FIELD_SEL_SRC_IP | MLX5_HASH_FIELD_SEL_DST_IP | MLX5_HASH_FIELD_SEL_L4_SPORT | \ 14861a86b377SEli Cohen MLX5_HASH_FIELD_SEL_L4_DPORT) 14871a86b377SEli Cohen static const u8 rx_hash_toeplitz_key[] = { 0x2c, 0xc6, 0x81, 0xd1, 0x5b, 0xdb, 0xf4, 0xf7, 14881a86b377SEli Cohen 0xfc, 0xa2, 0x83, 0x19, 0xdb, 0x1a, 0x3e, 0x94, 14891a86b377SEli Cohen 0x6b, 0x9e, 0x38, 0xd9, 0x2c, 0x9c, 0x03, 0xd1, 14901a86b377SEli Cohen 0xad, 0x99, 0x44, 0xa7, 0xd9, 0x56, 0x3d, 0x59, 14911a86b377SEli Cohen 0x06, 0x3c, 0x25, 0xf3, 0xfc, 0x1f, 0xdc, 0x2a }; 14921a86b377SEli Cohen void *rss_key; 14931a86b377SEli Cohen void *outer; 14941a86b377SEli Cohen void *tirc; 14951a86b377SEli Cohen void *in; 14961a86b377SEli Cohen int err; 14971a86b377SEli Cohen 14981a86b377SEli Cohen in = kzalloc(MLX5_ST_SZ_BYTES(create_tir_in), GFP_KERNEL); 14991a86b377SEli Cohen if (!in) 15001a86b377SEli Cohen return -ENOMEM; 15011a86b377SEli Cohen 15021a86b377SEli Cohen MLX5_SET(create_tir_in, in, uid, ndev->mvdev.res.uid); 15031a86b377SEli Cohen tirc = MLX5_ADDR_OF(create_tir_in, in, ctx); 15041a86b377SEli Cohen MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_INDIRECT); 15051a86b377SEli Cohen 15061a86b377SEli Cohen MLX5_SET(tirc, tirc, rx_hash_symmetric, 1); 15071a86b377SEli Cohen MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_TOEPLITZ); 15081a86b377SEli Cohen rss_key = MLX5_ADDR_OF(tirc, tirc, rx_hash_toeplitz_key); 15091a86b377SEli Cohen memcpy(rss_key, rx_hash_toeplitz_key, sizeof(rx_hash_toeplitz_key)); 15101a86b377SEli Cohen 15111a86b377SEli Cohen outer = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer); 15121a86b377SEli Cohen MLX5_SET(rx_hash_field_select, outer, l3_prot_type, MLX5_L3_PROT_TYPE_IPV4); 15131a86b377SEli Cohen MLX5_SET(rx_hash_field_select, outer, l4_prot_type, MLX5_L4_PROT_TYPE_TCP); 15141a86b377SEli Cohen MLX5_SET(rx_hash_field_select, outer, selected_fields, HASH_IP_L4PORTS); 15151a86b377SEli Cohen 15161a86b377SEli Cohen MLX5_SET(tirc, tirc, indirect_table, ndev->res.rqtn); 15171a86b377SEli Cohen MLX5_SET(tirc, tirc, transport_domain, ndev->res.tdn); 15181a86b377SEli Cohen 15191a86b377SEli Cohen err = mlx5_vdpa_create_tir(&ndev->mvdev, in, &ndev->res.tirn); 15201a86b377SEli Cohen kfree(in); 152129422100SEli Cohen if (err) 152229422100SEli Cohen return err; 152329422100SEli Cohen 152429422100SEli Cohen mlx5_vdpa_add_tirn(ndev); 15251a86b377SEli Cohen return err; 15261a86b377SEli Cohen } 15271a86b377SEli Cohen 15281a86b377SEli Cohen static void destroy_tir(struct mlx5_vdpa_net *ndev) 15291a86b377SEli Cohen { 153029422100SEli Cohen mlx5_vdpa_remove_tirn(ndev); 15311a86b377SEli Cohen mlx5_vdpa_destroy_tir(&ndev->mvdev, ndev->res.tirn); 15321a86b377SEli Cohen } 15331a86b377SEli Cohen 1534baf2ad3fSEli Cohen #define MAX_STEERING_ENT 0x8000 1535baf2ad3fSEli Cohen #define MAX_STEERING_GROUPS 2 1536baf2ad3fSEli Cohen 15370a599750SEli Cohen #if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 15380a599750SEli Cohen #define NUM_DESTS 2 15390a599750SEli Cohen #else 15400a599750SEli Cohen #define NUM_DESTS 1 15410a599750SEli Cohen #endif 15420a599750SEli Cohen 15430a599750SEli Cohen static int add_steering_counters(struct mlx5_vdpa_net *ndev, 15440a599750SEli Cohen struct macvlan_node *node, 15450a599750SEli Cohen struct mlx5_flow_act *flow_act, 15460a599750SEli Cohen struct mlx5_flow_destination *dests) 15471a86b377SEli Cohen { 15480a599750SEli Cohen #if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 15490a599750SEli Cohen int err; 15500a599750SEli Cohen 15510a599750SEli Cohen node->ucast_counter.counter = mlx5_fc_create(ndev->mvdev.mdev, false); 15520a599750SEli Cohen if (IS_ERR(node->ucast_counter.counter)) 15530a599750SEli Cohen return PTR_ERR(node->ucast_counter.counter); 15540a599750SEli Cohen 15550a599750SEli Cohen node->mcast_counter.counter = mlx5_fc_create(ndev->mvdev.mdev, false); 15560a599750SEli Cohen if (IS_ERR(node->mcast_counter.counter)) { 15570a599750SEli Cohen err = PTR_ERR(node->mcast_counter.counter); 15580a599750SEli Cohen goto err_mcast_counter; 15590a599750SEli Cohen } 15600a599750SEli Cohen 15610a599750SEli Cohen dests[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 15620a599750SEli Cohen flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; 15630a599750SEli Cohen return 0; 15640a599750SEli Cohen 15650a599750SEli Cohen err_mcast_counter: 15660a599750SEli Cohen mlx5_fc_destroy(ndev->mvdev.mdev, node->ucast_counter.counter); 15670a599750SEli Cohen return err; 15680a599750SEli Cohen #else 15690a599750SEli Cohen return 0; 15700a599750SEli Cohen #endif 15710a599750SEli Cohen } 15720a599750SEli Cohen 15730a599750SEli Cohen static void remove_steering_counters(struct mlx5_vdpa_net *ndev, 15740a599750SEli Cohen struct macvlan_node *node) 15750a599750SEli Cohen { 15760a599750SEli Cohen #if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 15770a599750SEli Cohen mlx5_fc_destroy(ndev->mvdev.mdev, node->mcast_counter.counter); 15780a599750SEli Cohen mlx5_fc_destroy(ndev->mvdev.mdev, node->ucast_counter.counter); 15790a599750SEli Cohen #endif 15800a599750SEli Cohen } 15810a599750SEli Cohen 15820a599750SEli Cohen static int mlx5_vdpa_add_mac_vlan_rules(struct mlx5_vdpa_net *ndev, u8 *mac, 15830a599750SEli Cohen struct macvlan_node *node) 15840a599750SEli Cohen { 15850a599750SEli Cohen struct mlx5_flow_destination dests[NUM_DESTS] = {}; 15861a86b377SEli Cohen struct mlx5_flow_act flow_act = {}; 1587540061acSEli Cohen struct mlx5_flow_spec *spec; 1588540061acSEli Cohen void *headers_c; 1589540061acSEli Cohen void *headers_v; 1590540061acSEli Cohen u8 *dmac_c; 1591540061acSEli Cohen u8 *dmac_v; 15921a86b377SEli Cohen int err; 15930a599750SEli Cohen u16 vid; 15941a86b377SEli Cohen 1595540061acSEli Cohen spec = kvzalloc(sizeof(*spec), GFP_KERNEL); 1596540061acSEli Cohen if (!spec) 1597540061acSEli Cohen return -ENOMEM; 1598540061acSEli Cohen 15990a599750SEli Cohen vid = key2vid(node->macvlan); 1600540061acSEli Cohen spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 1601540061acSEli Cohen headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, outer_headers); 1602540061acSEli Cohen headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers); 1603baf2ad3fSEli Cohen dmac_c = MLX5_ADDR_OF(fte_match_param, headers_c, outer_headers.dmac_47_16); 1604540061acSEli Cohen dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v, outer_headers.dmac_47_16); 160571aa95a6SXu Qiang eth_broadcast_addr(dmac_c); 1606baf2ad3fSEli Cohen ether_addr_copy(dmac_v, mac); 1607a6ce72c0SEli Cohen if (ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VLAN)) { 1608baf2ad3fSEli Cohen MLX5_SET(fte_match_set_lyr_2_4, headers_c, cvlan_tag, 1); 1609a6ce72c0SEli Cohen MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, first_vid); 1610a6ce72c0SEli Cohen } 16110a599750SEli Cohen if (node->tagged) { 1612baf2ad3fSEli Cohen MLX5_SET(fte_match_set_lyr_2_4, headers_v, cvlan_tag, 1); 1613a6ce72c0SEli Cohen MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, vid); 1614baf2ad3fSEli Cohen } 16157becdd13SEli Cohen flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 16160a599750SEli Cohen dests[0].type = MLX5_FLOW_DESTINATION_TYPE_TIR; 16170a599750SEli Cohen dests[0].tir_num = ndev->res.tirn; 16180a599750SEli Cohen err = add_steering_counters(ndev, node, &flow_act, dests); 16190a599750SEli Cohen if (err) 16200a599750SEli Cohen goto out_free; 1621540061acSEli Cohen 16220a599750SEli Cohen #if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 16230a599750SEli Cohen dests[1].counter_id = mlx5_fc_id(node->ucast_counter.counter); 16240a599750SEli Cohen #endif 16250a599750SEli Cohen node->ucast_rule = mlx5_add_flow_rules(ndev->rxft, spec, &flow_act, dests, NUM_DESTS); 16260a599750SEli Cohen if (IS_ERR(node->ucast_rule)) { 16270a599750SEli Cohen err = PTR_ERR(node->ucast_rule); 16280a599750SEli Cohen goto err_ucast; 16290a599750SEli Cohen } 16300a599750SEli Cohen 16310a599750SEli Cohen #if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 16320a599750SEli Cohen dests[1].counter_id = mlx5_fc_id(node->mcast_counter.counter); 16330a599750SEli Cohen #endif 16341a86b377SEli Cohen 1635540061acSEli Cohen memset(dmac_c, 0, ETH_ALEN); 1636540061acSEli Cohen memset(dmac_v, 0, ETH_ALEN); 1637540061acSEli Cohen dmac_c[0] = 1; 1638540061acSEli Cohen dmac_v[0] = 1; 16390a599750SEli Cohen node->mcast_rule = mlx5_add_flow_rules(ndev->rxft, spec, &flow_act, dests, NUM_DESTS); 16400a599750SEli Cohen if (IS_ERR(node->mcast_rule)) { 16410a599750SEli Cohen err = PTR_ERR(node->mcast_rule); 1642baf2ad3fSEli Cohen goto err_mcast; 1643540061acSEli Cohen } 16440a599750SEli Cohen kvfree(spec); 16450a599750SEli Cohen mlx5_vdpa_add_rx_counters(ndev, node); 16461a86b377SEli Cohen return 0; 16471a86b377SEli Cohen 1648baf2ad3fSEli Cohen err_mcast: 16490a599750SEli Cohen mlx5_del_flow_rules(node->ucast_rule); 16500a599750SEli Cohen err_ucast: 16510a599750SEli Cohen remove_steering_counters(ndev, node); 16520a599750SEli Cohen out_free: 16530a599750SEli Cohen kvfree(spec); 16541a86b377SEli Cohen return err; 16551a86b377SEli Cohen } 16561a86b377SEli Cohen 1657baf2ad3fSEli Cohen static void mlx5_vdpa_del_mac_vlan_rules(struct mlx5_vdpa_net *ndev, 16580a599750SEli Cohen struct macvlan_node *node) 16591a86b377SEli Cohen { 16600a599750SEli Cohen mlx5_vdpa_remove_rx_counters(ndev, node); 16610a599750SEli Cohen mlx5_del_flow_rules(node->ucast_rule); 16620a599750SEli Cohen mlx5_del_flow_rules(node->mcast_rule); 1663baf2ad3fSEli Cohen } 1664baf2ad3fSEli Cohen 1665baf2ad3fSEli Cohen static u64 search_val(u8 *mac, u16 vlan, bool tagged) 1666baf2ad3fSEli Cohen { 1667baf2ad3fSEli Cohen u64 val; 1668baf2ad3fSEli Cohen 1669baf2ad3fSEli Cohen if (!tagged) 1670baf2ad3fSEli Cohen vlan = MLX5V_UNTAGGED; 1671baf2ad3fSEli Cohen 1672baf2ad3fSEli Cohen val = (u64)vlan << 48 | 1673baf2ad3fSEli Cohen (u64)mac[0] << 40 | 1674baf2ad3fSEli Cohen (u64)mac[1] << 32 | 1675baf2ad3fSEli Cohen (u64)mac[2] << 24 | 1676baf2ad3fSEli Cohen (u64)mac[3] << 16 | 1677baf2ad3fSEli Cohen (u64)mac[4] << 8 | 1678baf2ad3fSEli Cohen (u64)mac[5]; 1679baf2ad3fSEli Cohen 1680baf2ad3fSEli Cohen return val; 1681baf2ad3fSEli Cohen } 1682baf2ad3fSEli Cohen 1683baf2ad3fSEli Cohen static struct macvlan_node *mac_vlan_lookup(struct mlx5_vdpa_net *ndev, u64 value) 1684baf2ad3fSEli Cohen { 1685baf2ad3fSEli Cohen struct macvlan_node *pos; 1686baf2ad3fSEli Cohen u32 idx; 1687baf2ad3fSEli Cohen 1688baf2ad3fSEli Cohen idx = hash_64(value, 8); // tbd 8 1689baf2ad3fSEli Cohen hlist_for_each_entry(pos, &ndev->macvlan_hash[idx], hlist) { 1690baf2ad3fSEli Cohen if (pos->macvlan == value) 1691baf2ad3fSEli Cohen return pos; 1692baf2ad3fSEli Cohen } 1693baf2ad3fSEli Cohen return NULL; 1694baf2ad3fSEli Cohen } 1695baf2ad3fSEli Cohen 16960a599750SEli Cohen static int mac_vlan_add(struct mlx5_vdpa_net *ndev, u8 *mac, u16 vid, bool tagged) 1697baf2ad3fSEli Cohen { 1698baf2ad3fSEli Cohen struct macvlan_node *ptr; 1699baf2ad3fSEli Cohen u64 val; 1700baf2ad3fSEli Cohen u32 idx; 1701baf2ad3fSEli Cohen int err; 1702baf2ad3fSEli Cohen 17030a599750SEli Cohen val = search_val(mac, vid, tagged); 1704baf2ad3fSEli Cohen if (mac_vlan_lookup(ndev, val)) 1705baf2ad3fSEli Cohen return -EEXIST; 1706baf2ad3fSEli Cohen 1707baf2ad3fSEli Cohen ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); 1708baf2ad3fSEli Cohen if (!ptr) 1709baf2ad3fSEli Cohen return -ENOMEM; 1710baf2ad3fSEli Cohen 17110a599750SEli Cohen ptr->tagged = tagged; 17120a599750SEli Cohen ptr->macvlan = val; 17130a599750SEli Cohen ptr->ndev = ndev; 17140a599750SEli Cohen err = mlx5_vdpa_add_mac_vlan_rules(ndev, ndev->config.mac, ptr); 1715baf2ad3fSEli Cohen if (err) 1716baf2ad3fSEli Cohen goto err_add; 1717baf2ad3fSEli Cohen 1718baf2ad3fSEli Cohen idx = hash_64(val, 8); 1719baf2ad3fSEli Cohen hlist_add_head(&ptr->hlist, &ndev->macvlan_hash[idx]); 1720baf2ad3fSEli Cohen return 0; 1721baf2ad3fSEli Cohen 1722baf2ad3fSEli Cohen err_add: 1723baf2ad3fSEli Cohen kfree(ptr); 1724baf2ad3fSEli Cohen return err; 1725baf2ad3fSEli Cohen } 1726baf2ad3fSEli Cohen 1727baf2ad3fSEli Cohen static void mac_vlan_del(struct mlx5_vdpa_net *ndev, u8 *mac, u16 vlan, bool tagged) 1728baf2ad3fSEli Cohen { 1729baf2ad3fSEli Cohen struct macvlan_node *ptr; 1730baf2ad3fSEli Cohen 1731baf2ad3fSEli Cohen ptr = mac_vlan_lookup(ndev, search_val(mac, vlan, tagged)); 1732baf2ad3fSEli Cohen if (!ptr) 17331a86b377SEli Cohen return; 17341a86b377SEli Cohen 1735baf2ad3fSEli Cohen hlist_del(&ptr->hlist); 17360a599750SEli Cohen mlx5_vdpa_del_mac_vlan_rules(ndev, ptr); 17370a599750SEli Cohen remove_steering_counters(ndev, ptr); 1738baf2ad3fSEli Cohen kfree(ptr); 1739baf2ad3fSEli Cohen } 1740baf2ad3fSEli Cohen 1741baf2ad3fSEli Cohen static void clear_mac_vlan_table(struct mlx5_vdpa_net *ndev) 1742baf2ad3fSEli Cohen { 1743baf2ad3fSEli Cohen struct macvlan_node *pos; 1744baf2ad3fSEli Cohen struct hlist_node *n; 1745baf2ad3fSEli Cohen int i; 1746baf2ad3fSEli Cohen 1747baf2ad3fSEli Cohen for (i = 0; i < MLX5V_MACVLAN_SIZE; i++) { 1748baf2ad3fSEli Cohen hlist_for_each_entry_safe(pos, n, &ndev->macvlan_hash[i], hlist) { 1749baf2ad3fSEli Cohen hlist_del(&pos->hlist); 17500a599750SEli Cohen mlx5_vdpa_del_mac_vlan_rules(ndev, pos); 17510a599750SEli Cohen remove_steering_counters(ndev, pos); 1752baf2ad3fSEli Cohen kfree(pos); 1753baf2ad3fSEli Cohen } 1754baf2ad3fSEli Cohen } 1755baf2ad3fSEli Cohen } 1756baf2ad3fSEli Cohen 1757baf2ad3fSEli Cohen static int setup_steering(struct mlx5_vdpa_net *ndev) 1758baf2ad3fSEli Cohen { 1759baf2ad3fSEli Cohen struct mlx5_flow_table_attr ft_attr = {}; 1760baf2ad3fSEli Cohen struct mlx5_flow_namespace *ns; 1761baf2ad3fSEli Cohen int err; 1762baf2ad3fSEli Cohen 1763baf2ad3fSEli Cohen ft_attr.max_fte = MAX_STEERING_ENT; 1764baf2ad3fSEli Cohen ft_attr.autogroup.max_num_groups = MAX_STEERING_GROUPS; 1765baf2ad3fSEli Cohen 1766baf2ad3fSEli Cohen ns = mlx5_get_flow_namespace(ndev->mvdev.mdev, MLX5_FLOW_NAMESPACE_BYPASS); 1767baf2ad3fSEli Cohen if (!ns) { 1768baf2ad3fSEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "failed to get flow namespace\n"); 1769baf2ad3fSEli Cohen return -EOPNOTSUPP; 1770baf2ad3fSEli Cohen } 1771baf2ad3fSEli Cohen 1772baf2ad3fSEli Cohen ndev->rxft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr); 1773baf2ad3fSEli Cohen if (IS_ERR(ndev->rxft)) { 1774baf2ad3fSEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "failed to create flow table\n"); 1775baf2ad3fSEli Cohen return PTR_ERR(ndev->rxft); 1776baf2ad3fSEli Cohen } 177729422100SEli Cohen mlx5_vdpa_add_rx_flow_table(ndev); 1778baf2ad3fSEli Cohen 1779baf2ad3fSEli Cohen err = mac_vlan_add(ndev, ndev->config.mac, 0, false); 1780baf2ad3fSEli Cohen if (err) 1781baf2ad3fSEli Cohen goto err_add; 1782baf2ad3fSEli Cohen 1783baf2ad3fSEli Cohen return 0; 1784baf2ad3fSEli Cohen 1785baf2ad3fSEli Cohen err_add: 178629422100SEli Cohen mlx5_vdpa_remove_rx_flow_table(ndev); 1787baf2ad3fSEli Cohen mlx5_destroy_flow_table(ndev->rxft); 1788baf2ad3fSEli Cohen return err; 1789baf2ad3fSEli Cohen } 1790baf2ad3fSEli Cohen 1791baf2ad3fSEli Cohen static void teardown_steering(struct mlx5_vdpa_net *ndev) 1792baf2ad3fSEli Cohen { 1793baf2ad3fSEli Cohen clear_mac_vlan_table(ndev); 179429422100SEli Cohen mlx5_vdpa_remove_rx_flow_table(ndev); 17951a86b377SEli Cohen mlx5_destroy_flow_table(ndev->rxft); 17961a86b377SEli Cohen } 17971a86b377SEli Cohen 17985262912eSEli Cohen static virtio_net_ctrl_ack handle_ctrl_mac(struct mlx5_vdpa_dev *mvdev, u8 cmd) 17995262912eSEli Cohen { 18005262912eSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 18015262912eSEli Cohen struct mlx5_control_vq *cvq = &mvdev->cvq; 18025262912eSEli Cohen virtio_net_ctrl_ack status = VIRTIO_NET_ERR; 18035262912eSEli Cohen struct mlx5_core_dev *pfmdev; 18045262912eSEli Cohen size_t read; 1805f1781bedSMichael Qiu u8 mac[ETH_ALEN], mac_back[ETH_ALEN]; 18065262912eSEli Cohen 18075262912eSEli Cohen pfmdev = pci_get_drvdata(pci_physfn(mvdev->mdev->pdev)); 18085262912eSEli Cohen switch (cmd) { 18095262912eSEli Cohen case VIRTIO_NET_CTRL_MAC_ADDR_SET: 18105262912eSEli Cohen read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, (void *)mac, ETH_ALEN); 18115262912eSEli Cohen if (read != ETH_ALEN) 18125262912eSEli Cohen break; 18135262912eSEli Cohen 18145262912eSEli Cohen if (!memcmp(ndev->config.mac, mac, 6)) { 18155262912eSEli Cohen status = VIRTIO_NET_OK; 18165262912eSEli Cohen break; 18175262912eSEli Cohen } 18185262912eSEli Cohen 1819f1781bedSMichael Qiu if (is_zero_ether_addr(mac)) 1820f1781bedSMichael Qiu break; 1821f1781bedSMichael Qiu 18225262912eSEli Cohen if (!is_zero_ether_addr(ndev->config.mac)) { 18235262912eSEli Cohen if (mlx5_mpfs_del_mac(pfmdev, ndev->config.mac)) { 18245262912eSEli Cohen mlx5_vdpa_warn(mvdev, "failed to delete old MAC %pM from MPFS table\n", 18255262912eSEli Cohen ndev->config.mac); 18265262912eSEli Cohen break; 18275262912eSEli Cohen } 18285262912eSEli Cohen } 18295262912eSEli Cohen 18305262912eSEli Cohen if (mlx5_mpfs_add_mac(pfmdev, mac)) { 18315262912eSEli Cohen mlx5_vdpa_warn(mvdev, "failed to insert new MAC %pM into MPFS table\n", 18325262912eSEli Cohen mac); 18335262912eSEli Cohen break; 18345262912eSEli Cohen } 18355262912eSEli Cohen 1836f1781bedSMichael Qiu /* backup the original mac address so that if failed to add the forward rules 1837f1781bedSMichael Qiu * we could restore it 1838f1781bedSMichael Qiu */ 1839f1781bedSMichael Qiu memcpy(mac_back, ndev->config.mac, ETH_ALEN); 1840f1781bedSMichael Qiu 18415262912eSEli Cohen memcpy(ndev->config.mac, mac, ETH_ALEN); 1842f1781bedSMichael Qiu 1843f1781bedSMichael Qiu /* Need recreate the flow table entry, so that the packet could forward back 1844f1781bedSMichael Qiu */ 18451ab53760SEli Cohen mac_vlan_del(ndev, mac_back, 0, false); 1846f1781bedSMichael Qiu 1847baf2ad3fSEli Cohen if (mac_vlan_add(ndev, ndev->config.mac, 0, false)) { 1848f1781bedSMichael Qiu mlx5_vdpa_warn(mvdev, "failed to insert forward rules, try to restore\n"); 1849f1781bedSMichael Qiu 1850f1781bedSMichael Qiu /* Although it hardly run here, we still need double check */ 1851f1781bedSMichael Qiu if (is_zero_ether_addr(mac_back)) { 1852f1781bedSMichael Qiu mlx5_vdpa_warn(mvdev, "restore mac failed: Original MAC is zero\n"); 1853f1781bedSMichael Qiu break; 1854f1781bedSMichael Qiu } 1855f1781bedSMichael Qiu 1856f1781bedSMichael Qiu /* Try to restore original mac address to MFPS table, and try to restore 1857f1781bedSMichael Qiu * the forward rule entry. 1858f1781bedSMichael Qiu */ 1859f1781bedSMichael Qiu if (mlx5_mpfs_del_mac(pfmdev, ndev->config.mac)) { 1860f1781bedSMichael Qiu mlx5_vdpa_warn(mvdev, "restore mac failed: delete MAC %pM from MPFS table failed\n", 1861f1781bedSMichael Qiu ndev->config.mac); 1862f1781bedSMichael Qiu } 1863f1781bedSMichael Qiu 1864f1781bedSMichael Qiu if (mlx5_mpfs_add_mac(pfmdev, mac_back)) { 1865f1781bedSMichael Qiu mlx5_vdpa_warn(mvdev, "restore mac failed: insert old MAC %pM into MPFS table failed\n", 1866f1781bedSMichael Qiu mac_back); 1867f1781bedSMichael Qiu } 1868f1781bedSMichael Qiu 1869f1781bedSMichael Qiu memcpy(ndev->config.mac, mac_back, ETH_ALEN); 1870f1781bedSMichael Qiu 1871baf2ad3fSEli Cohen if (mac_vlan_add(ndev, ndev->config.mac, 0, false)) 1872f1781bedSMichael Qiu mlx5_vdpa_warn(mvdev, "restore forward rules failed: insert forward rules failed\n"); 1873f1781bedSMichael Qiu 1874f1781bedSMichael Qiu break; 1875f1781bedSMichael Qiu } 1876f1781bedSMichael Qiu 18775262912eSEli Cohen status = VIRTIO_NET_OK; 18785262912eSEli Cohen break; 18795262912eSEli Cohen 18805262912eSEli Cohen default: 18815262912eSEli Cohen break; 18825262912eSEli Cohen } 18835262912eSEli Cohen 18845262912eSEli Cohen return status; 18855262912eSEli Cohen } 18865262912eSEli Cohen 188752893733SEli Cohen static int change_num_qps(struct mlx5_vdpa_dev *mvdev, int newqps) 188852893733SEli Cohen { 188952893733SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 189052893733SEli Cohen int cur_qps = ndev->cur_num_vqs / 2; 189152893733SEli Cohen int err; 189252893733SEli Cohen int i; 189352893733SEli Cohen 189452893733SEli Cohen if (cur_qps > newqps) { 189552893733SEli Cohen err = modify_rqt(ndev, 2 * newqps); 189652893733SEli Cohen if (err) 189752893733SEli Cohen return err; 189852893733SEli Cohen 189952893733SEli Cohen for (i = ndev->cur_num_vqs - 1; i >= 2 * newqps; i--) 190052893733SEli Cohen teardown_vq(ndev, &ndev->vqs[i]); 190152893733SEli Cohen 190252893733SEli Cohen ndev->cur_num_vqs = 2 * newqps; 190352893733SEli Cohen } else { 190452893733SEli Cohen ndev->cur_num_vqs = 2 * newqps; 190552893733SEli Cohen for (i = cur_qps * 2; i < 2 * newqps; i++) { 190652893733SEli Cohen err = setup_vq(ndev, &ndev->vqs[i]); 190752893733SEli Cohen if (err) 190852893733SEli Cohen goto clean_added; 190952893733SEli Cohen } 191052893733SEli Cohen err = modify_rqt(ndev, 2 * newqps); 191152893733SEli Cohen if (err) 191252893733SEli Cohen goto clean_added; 191352893733SEli Cohen } 191452893733SEli Cohen return 0; 191552893733SEli Cohen 191652893733SEli Cohen clean_added: 191737e07e70SEli Cohen for (--i; i >= 2 * cur_qps; --i) 191852893733SEli Cohen teardown_vq(ndev, &ndev->vqs[i]); 191952893733SEli Cohen 192037e07e70SEli Cohen ndev->cur_num_vqs = 2 * cur_qps; 192137e07e70SEli Cohen 192252893733SEli Cohen return err; 192352893733SEli Cohen } 192452893733SEli Cohen 192552893733SEli Cohen static virtio_net_ctrl_ack handle_ctrl_mq(struct mlx5_vdpa_dev *mvdev, u8 cmd) 192652893733SEli Cohen { 192752893733SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 192852893733SEli Cohen virtio_net_ctrl_ack status = VIRTIO_NET_ERR; 192952893733SEli Cohen struct mlx5_control_vq *cvq = &mvdev->cvq; 193052893733SEli Cohen struct virtio_net_ctrl_mq mq; 193152893733SEli Cohen size_t read; 193252893733SEli Cohen u16 newqps; 193352893733SEli Cohen 193452893733SEli Cohen switch (cmd) { 193552893733SEli Cohen case VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET: 1936ed0f849fSSi-Wei Liu /* This mq feature check aligns with pre-existing userspace 1937ed0f849fSSi-Wei Liu * implementation. 1938ed0f849fSSi-Wei Liu * 1939ed0f849fSSi-Wei Liu * Without it, an untrusted driver could fake a multiqueue config 1940ed0f849fSSi-Wei Liu * request down to a non-mq device that may cause kernel to 1941ed0f849fSSi-Wei Liu * panic due to uninitialized resources for extra vqs. Even with 1942ed0f849fSSi-Wei Liu * a well behaving guest driver, it is not expected to allow 1943ed0f849fSSi-Wei Liu * changing the number of vqs on a non-mq device. 1944ed0f849fSSi-Wei Liu */ 1945ed0f849fSSi-Wei Liu if (!MLX5_FEATURE(mvdev, VIRTIO_NET_F_MQ)) 1946ed0f849fSSi-Wei Liu break; 1947ed0f849fSSi-Wei Liu 194852893733SEli Cohen read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, (void *)&mq, sizeof(mq)); 194952893733SEli Cohen if (read != sizeof(mq)) 195052893733SEli Cohen break; 195152893733SEli Cohen 195252893733SEli Cohen newqps = mlx5vdpa16_to_cpu(mvdev, mq.virtqueue_pairs); 1953ed0f849fSSi-Wei Liu if (newqps < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN || 1954acde3929SEli Cohen newqps > ndev->rqt_size) 1955ed0f849fSSi-Wei Liu break; 1956ed0f849fSSi-Wei Liu 195752893733SEli Cohen if (ndev->cur_num_vqs == 2 * newqps) { 195852893733SEli Cohen status = VIRTIO_NET_OK; 195952893733SEli Cohen break; 196052893733SEli Cohen } 196152893733SEli Cohen 196252893733SEli Cohen if (!change_num_qps(mvdev, newqps)) 196352893733SEli Cohen status = VIRTIO_NET_OK; 196452893733SEli Cohen 196552893733SEli Cohen break; 196652893733SEli Cohen default: 196752893733SEli Cohen break; 196852893733SEli Cohen } 196952893733SEli Cohen 197052893733SEli Cohen return status; 197152893733SEli Cohen } 197252893733SEli Cohen 1973baf2ad3fSEli Cohen static virtio_net_ctrl_ack handle_ctrl_vlan(struct mlx5_vdpa_dev *mvdev, u8 cmd) 1974baf2ad3fSEli Cohen { 1975baf2ad3fSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 1976baf2ad3fSEli Cohen virtio_net_ctrl_ack status = VIRTIO_NET_ERR; 1977baf2ad3fSEli Cohen struct mlx5_control_vq *cvq = &mvdev->cvq; 1978baf2ad3fSEli Cohen __virtio16 vlan; 1979baf2ad3fSEli Cohen size_t read; 1980baf2ad3fSEli Cohen u16 id; 1981baf2ad3fSEli Cohen 19825aec8049SEli Cohen if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VLAN))) 19835aec8049SEli Cohen return status; 19845aec8049SEli Cohen 1985baf2ad3fSEli Cohen switch (cmd) { 1986baf2ad3fSEli Cohen case VIRTIO_NET_CTRL_VLAN_ADD: 1987baf2ad3fSEli Cohen read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, &vlan, sizeof(vlan)); 1988baf2ad3fSEli Cohen if (read != sizeof(vlan)) 1989baf2ad3fSEli Cohen break; 1990baf2ad3fSEli Cohen 1991baf2ad3fSEli Cohen id = mlx5vdpa16_to_cpu(mvdev, vlan); 1992baf2ad3fSEli Cohen if (mac_vlan_add(ndev, ndev->config.mac, id, true)) 1993baf2ad3fSEli Cohen break; 1994baf2ad3fSEli Cohen 1995baf2ad3fSEli Cohen status = VIRTIO_NET_OK; 1996baf2ad3fSEli Cohen break; 1997baf2ad3fSEli Cohen case VIRTIO_NET_CTRL_VLAN_DEL: 1998baf2ad3fSEli Cohen read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, &vlan, sizeof(vlan)); 1999baf2ad3fSEli Cohen if (read != sizeof(vlan)) 2000baf2ad3fSEli Cohen break; 2001baf2ad3fSEli Cohen 2002baf2ad3fSEli Cohen id = mlx5vdpa16_to_cpu(mvdev, vlan); 2003baf2ad3fSEli Cohen mac_vlan_del(ndev, ndev->config.mac, id, true); 2004f766c409SDan Carpenter status = VIRTIO_NET_OK; 2005baf2ad3fSEli Cohen break; 2006baf2ad3fSEli Cohen default: 2007baf2ad3fSEli Cohen break; 2008baf2ad3fSEli Cohen } 2009baf2ad3fSEli Cohen 2010baf2ad3fSEli Cohen return status; 2011baf2ad3fSEli Cohen } 2012baf2ad3fSEli Cohen 20135262912eSEli Cohen static void mlx5_cvq_kick_handler(struct work_struct *work) 20145262912eSEli Cohen { 20155262912eSEli Cohen virtio_net_ctrl_ack status = VIRTIO_NET_ERR; 20165262912eSEli Cohen struct virtio_net_ctrl_hdr ctrl; 2017218bdd20SEli Cohen struct mlx5_vdpa_wq_ent *wqent; 20185262912eSEli Cohen struct mlx5_vdpa_dev *mvdev; 20195262912eSEli Cohen struct mlx5_control_vq *cvq; 20205262912eSEli Cohen struct mlx5_vdpa_net *ndev; 20215262912eSEli Cohen size_t read, write; 20225262912eSEli Cohen int err; 20235262912eSEli Cohen 2024218bdd20SEli Cohen wqent = container_of(work, struct mlx5_vdpa_wq_ent, work); 20255262912eSEli Cohen mvdev = wqent->mvdev; 20265262912eSEli Cohen ndev = to_mlx5_vdpa_ndev(mvdev); 20275262912eSEli Cohen cvq = &mvdev->cvq; 20281c80cf03SJason Wang 2029759ae7f9SEli Cohen down_write(&ndev->reslock); 20301c80cf03SJason Wang 20311c80cf03SJason Wang if (!(mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) 20321c80cf03SJason Wang goto out; 20331c80cf03SJason Wang 20345262912eSEli Cohen if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) 20351c80cf03SJason Wang goto out; 20365262912eSEli Cohen 20375262912eSEli Cohen if (!cvq->ready) 20381c80cf03SJason Wang goto out; 20395262912eSEli Cohen 20405262912eSEli Cohen while (true) { 20415262912eSEli Cohen err = vringh_getdesc_iotlb(&cvq->vring, &cvq->riov, &cvq->wiov, &cvq->head, 20425262912eSEli Cohen GFP_ATOMIC); 20435262912eSEli Cohen if (err <= 0) 20445262912eSEli Cohen break; 20455262912eSEli Cohen 20465262912eSEli Cohen read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, &ctrl, sizeof(ctrl)); 20475262912eSEli Cohen if (read != sizeof(ctrl)) 20485262912eSEli Cohen break; 20495262912eSEli Cohen 20501892a3d4SEli Cohen cvq->received_desc++; 20515262912eSEli Cohen switch (ctrl.class) { 20525262912eSEli Cohen case VIRTIO_NET_CTRL_MAC: 20535262912eSEli Cohen status = handle_ctrl_mac(mvdev, ctrl.cmd); 20545262912eSEli Cohen break; 205552893733SEli Cohen case VIRTIO_NET_CTRL_MQ: 205652893733SEli Cohen status = handle_ctrl_mq(mvdev, ctrl.cmd); 205752893733SEli Cohen break; 2058baf2ad3fSEli Cohen case VIRTIO_NET_CTRL_VLAN: 2059baf2ad3fSEli Cohen status = handle_ctrl_vlan(mvdev, ctrl.cmd); 2060baf2ad3fSEli Cohen break; 20615262912eSEli Cohen default: 20625262912eSEli Cohen break; 20635262912eSEli Cohen } 20645262912eSEli Cohen 20655262912eSEli Cohen /* Make sure data is written before advancing index */ 20665262912eSEli Cohen smp_wmb(); 20675262912eSEli Cohen 20685262912eSEli Cohen write = vringh_iov_push_iotlb(&cvq->vring, &cvq->wiov, &status, sizeof(status)); 20695262912eSEli Cohen vringh_complete_iotlb(&cvq->vring, cvq->head, write); 20705262912eSEli Cohen vringh_kiov_cleanup(&cvq->riov); 20715262912eSEli Cohen vringh_kiov_cleanup(&cvq->wiov); 20725262912eSEli Cohen 20735262912eSEli Cohen if (vringh_need_notify_iotlb(&cvq->vring)) 20745262912eSEli Cohen vringh_notify(&cvq->vring); 207555ebf0d6SJason Wang 20761892a3d4SEli Cohen cvq->completed_desc++; 207755ebf0d6SJason Wang queue_work(mvdev->wq, &wqent->work); 207855ebf0d6SJason Wang break; 20795262912eSEli Cohen } 20801c80cf03SJason Wang 20811c80cf03SJason Wang out: 2082759ae7f9SEli Cohen up_write(&ndev->reslock); 20835262912eSEli Cohen } 20845262912eSEli Cohen 20851a86b377SEli Cohen static void mlx5_vdpa_kick_vq(struct vdpa_device *vdev, u16 idx) 20861a86b377SEli Cohen { 20871a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 20881a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 20895262912eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 20901a86b377SEli Cohen 2091e4fc6650SEli Cohen if (!is_index_valid(mvdev, idx)) 2092e4fc6650SEli Cohen return; 2093e4fc6650SEli Cohen 20945262912eSEli Cohen if (unlikely(is_ctrl_vq_idx(mvdev, idx))) { 2095ad6dc1daSEli Cohen if (!mvdev->wq || !mvdev->cvq.ready) 20965262912eSEli Cohen return; 20975262912eSEli Cohen 209855ebf0d6SJason Wang queue_work(mvdev->wq, &ndev->cvq_ent.work); 20995262912eSEli Cohen return; 21005262912eSEli Cohen } 21015262912eSEli Cohen 21025262912eSEli Cohen mvq = &ndev->vqs[idx]; 21031a86b377SEli Cohen if (unlikely(!mvq->ready)) 21041a86b377SEli Cohen return; 21051a86b377SEli Cohen 21061a86b377SEli Cohen iowrite16(idx, ndev->mvdev.res.kick_addr); 21071a86b377SEli Cohen } 21081a86b377SEli Cohen 21091a86b377SEli Cohen static int mlx5_vdpa_set_vq_address(struct vdpa_device *vdev, u16 idx, u64 desc_area, 21101a86b377SEli Cohen u64 driver_area, u64 device_area) 21111a86b377SEli Cohen { 21121a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 21131a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 21145262912eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 21151a86b377SEli Cohen 2116e4fc6650SEli Cohen if (!is_index_valid(mvdev, idx)) 2117e4fc6650SEli Cohen return -EINVAL; 2118e4fc6650SEli Cohen 21195262912eSEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) { 21205262912eSEli Cohen mvdev->cvq.desc_addr = desc_area; 21215262912eSEli Cohen mvdev->cvq.device_addr = device_area; 21225262912eSEli Cohen mvdev->cvq.driver_addr = driver_area; 21235262912eSEli Cohen return 0; 21245262912eSEli Cohen } 21255262912eSEli Cohen 21265262912eSEli Cohen mvq = &ndev->vqs[idx]; 21271a86b377SEli Cohen mvq->desc_addr = desc_area; 21281a86b377SEli Cohen mvq->device_addr = device_area; 21291a86b377SEli Cohen mvq->driver_addr = driver_area; 21301a86b377SEli Cohen return 0; 21311a86b377SEli Cohen } 21321a86b377SEli Cohen 21331a86b377SEli Cohen static void mlx5_vdpa_set_vq_num(struct vdpa_device *vdev, u16 idx, u32 num) 21341a86b377SEli Cohen { 21351a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 21361a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 21371a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq; 21381a86b377SEli Cohen 21395262912eSEli Cohen if (!is_index_valid(mvdev, idx) || is_ctrl_vq_idx(mvdev, idx)) 2140e4fc6650SEli Cohen return; 2141e4fc6650SEli Cohen 21421a86b377SEli Cohen mvq = &ndev->vqs[idx]; 21431a86b377SEli Cohen mvq->num_ent = num; 21441a86b377SEli Cohen } 21451a86b377SEli Cohen 21461a86b377SEli Cohen static void mlx5_vdpa_set_vq_cb(struct vdpa_device *vdev, u16 idx, struct vdpa_callback *cb) 21471a86b377SEli Cohen { 21481a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 21491a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 21501a86b377SEli Cohen 2151db296d25SEli Cohen ndev->event_cbs[idx] = *cb; 215240f2f3e9SEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) 215340f2f3e9SEli Cohen mvdev->cvq.event_cb = *cb; 21541a86b377SEli Cohen } 21551a86b377SEli Cohen 21565262912eSEli Cohen static void mlx5_cvq_notify(struct vringh *vring) 21575262912eSEli Cohen { 21585262912eSEli Cohen struct mlx5_control_vq *cvq = container_of(vring, struct mlx5_control_vq, vring); 21595262912eSEli Cohen 21605262912eSEli Cohen if (!cvq->event_cb.callback) 21615262912eSEli Cohen return; 21625262912eSEli Cohen 21635262912eSEli Cohen cvq->event_cb.callback(cvq->event_cb.private); 21645262912eSEli Cohen } 21655262912eSEli Cohen 21665262912eSEli Cohen static void set_cvq_ready(struct mlx5_vdpa_dev *mvdev, bool ready) 21675262912eSEli Cohen { 21685262912eSEli Cohen struct mlx5_control_vq *cvq = &mvdev->cvq; 21695262912eSEli Cohen 21705262912eSEli Cohen cvq->ready = ready; 21715262912eSEli Cohen if (!ready) 21725262912eSEli Cohen return; 21735262912eSEli Cohen 21745262912eSEli Cohen cvq->vring.notify = mlx5_cvq_notify; 21751a86b377SEli Cohen } 21761a86b377SEli Cohen 21771a86b377SEli Cohen static void mlx5_vdpa_set_vq_ready(struct vdpa_device *vdev, u16 idx, bool ready) 21781a86b377SEli Cohen { 21791a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 21801a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 21815262912eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 2182cae15c2eSEli Cohen int err; 21831a86b377SEli Cohen 2184759be899SEli Cohen if (!mvdev->actual_features) 2185759be899SEli Cohen return; 2186759be899SEli Cohen 2187e4fc6650SEli Cohen if (!is_index_valid(mvdev, idx)) 2188e4fc6650SEli Cohen return; 2189e4fc6650SEli Cohen 21905262912eSEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) { 21915262912eSEli Cohen set_cvq_ready(mvdev, ready); 21925262912eSEli Cohen return; 21935262912eSEli Cohen } 21945262912eSEli Cohen 21955262912eSEli Cohen mvq = &ndev->vqs[idx]; 2196cae15c2eSEli Cohen if (!ready) { 21971a86b377SEli Cohen suspend_vq(ndev, mvq); 2198cae15c2eSEli Cohen } else { 2199cae15c2eSEli Cohen err = modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY); 2200cae15c2eSEli Cohen if (err) { 2201cae15c2eSEli Cohen mlx5_vdpa_warn(mvdev, "modify VQ %d to ready failed (%d)\n", idx, err); 2202cae15c2eSEli Cohen ready = false; 2203cae15c2eSEli Cohen } 2204cae15c2eSEli Cohen } 2205cae15c2eSEli Cohen 22061a86b377SEli Cohen 22071a86b377SEli Cohen mvq->ready = ready; 22081a86b377SEli Cohen } 22091a86b377SEli Cohen 22101a86b377SEli Cohen static bool mlx5_vdpa_get_vq_ready(struct vdpa_device *vdev, u16 idx) 22111a86b377SEli Cohen { 22121a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 22131a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 22141a86b377SEli Cohen 2215e4fc6650SEli Cohen if (!is_index_valid(mvdev, idx)) 2216e4fc6650SEli Cohen return false; 2217e4fc6650SEli Cohen 22185262912eSEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) 22195262912eSEli Cohen return mvdev->cvq.ready; 22205262912eSEli Cohen 22215262912eSEli Cohen return ndev->vqs[idx].ready; 22221a86b377SEli Cohen } 22231a86b377SEli Cohen 22241a86b377SEli Cohen static int mlx5_vdpa_set_vq_state(struct vdpa_device *vdev, u16 idx, 22251a86b377SEli Cohen const struct vdpa_vq_state *state) 22261a86b377SEli Cohen { 22271a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 22281a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 22295262912eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 22301a86b377SEli Cohen 2231e4fc6650SEli Cohen if (!is_index_valid(mvdev, idx)) 2232e4fc6650SEli Cohen return -EINVAL; 2233e4fc6650SEli Cohen 22345262912eSEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) { 22355262912eSEli Cohen mvdev->cvq.vring.last_avail_idx = state->split.avail_index; 22365262912eSEli Cohen return 0; 22375262912eSEli Cohen } 22385262912eSEli Cohen 22395262912eSEli Cohen mvq = &ndev->vqs[idx]; 22401a86b377SEli Cohen if (mvq->fw_state == MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY) { 22411a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "can't modify available index\n"); 22421a86b377SEli Cohen return -EINVAL; 22431a86b377SEli Cohen } 22441a86b377SEli Cohen 2245530a5678SJason Wang mvq->used_idx = state->split.avail_index; 2246530a5678SJason Wang mvq->avail_idx = state->split.avail_index; 22471a86b377SEli Cohen return 0; 22481a86b377SEli Cohen } 22491a86b377SEli Cohen 22501a86b377SEli Cohen static int mlx5_vdpa_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa_vq_state *state) 22511a86b377SEli Cohen { 22521a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 22531a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 22545262912eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 22551a86b377SEli Cohen struct mlx5_virtq_attr attr; 22561a86b377SEli Cohen int err; 22571a86b377SEli Cohen 2258e4fc6650SEli Cohen if (!is_index_valid(mvdev, idx)) 2259e4fc6650SEli Cohen return -EINVAL; 2260e4fc6650SEli Cohen 22615262912eSEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) { 22625262912eSEli Cohen state->split.avail_index = mvdev->cvq.vring.last_avail_idx; 22635262912eSEli Cohen return 0; 22645262912eSEli Cohen } 22655262912eSEli Cohen 22665262912eSEli Cohen mvq = &ndev->vqs[idx]; 22673176e974SSi-Wei Liu /* If the virtq object was destroyed, use the value saved at 22683176e974SSi-Wei Liu * the last minute of suspend_vq. This caters for userspace 22693176e974SSi-Wei Liu * that cares about emulating the index after vq is stopped. 22703176e974SSi-Wei Liu */ 22713176e974SSi-Wei Liu if (!mvq->initialized) { 2272bc04d93eSEli Cohen /* Firmware returns a wrong value for the available index. 2273bc04d93eSEli Cohen * Since both values should be identical, we take the value of 2274bc04d93eSEli Cohen * used_idx which is reported correctly. 2275bc04d93eSEli Cohen */ 2276530a5678SJason Wang state->split.avail_index = mvq->used_idx; 22773176e974SSi-Wei Liu return 0; 22783176e974SSi-Wei Liu } 22791a86b377SEli Cohen 22801a86b377SEli Cohen err = query_virtqueue(ndev, mvq, &attr); 22811a86b377SEli Cohen if (err) { 22821a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "failed to query virtqueue\n"); 22831a86b377SEli Cohen return err; 22841a86b377SEli Cohen } 2285530a5678SJason Wang state->split.avail_index = attr.used_index; 22861a86b377SEli Cohen return 0; 22871a86b377SEli Cohen } 22881a86b377SEli Cohen 22891a86b377SEli Cohen static u32 mlx5_vdpa_get_vq_align(struct vdpa_device *vdev) 22901a86b377SEli Cohen { 22911a86b377SEli Cohen return PAGE_SIZE; 22921a86b377SEli Cohen } 22931a86b377SEli Cohen 22948fcd20c3SEli Cohen static u32 mlx5_vdpa_get_vq_group(struct vdpa_device *vdev, u16 idx) 2295d4821902SGautam Dawar { 22968fcd20c3SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 22978fcd20c3SEli Cohen 22988fcd20c3SEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) 22998fcd20c3SEli Cohen return MLX5_VDPA_CVQ_GROUP; 23008fcd20c3SEli Cohen 23018fcd20c3SEli Cohen return MLX5_VDPA_DATAVQ_GROUP; 2302d4821902SGautam Dawar } 2303d4821902SGautam Dawar 23041a86b377SEli Cohen static u64 mlx_to_vritio_features(u16 dev_features) 23051a86b377SEli Cohen { 23061a86b377SEli Cohen u64 result = 0; 23071a86b377SEli Cohen 2308e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_MRG_RXBUF)) 2309e9d67e59SEli Cohen result |= BIT_ULL(VIRTIO_NET_F_MRG_RXBUF); 2310e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_ECN)) 2311e9d67e59SEli Cohen result |= BIT_ULL(VIRTIO_NET_F_HOST_ECN); 2312e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_ECN)) 2313e9d67e59SEli Cohen result |= BIT_ULL(VIRTIO_NET_F_GUEST_ECN); 2314e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_TSO6)) 2315e9d67e59SEli Cohen result |= BIT_ULL(VIRTIO_NET_F_GUEST_TSO6); 2316e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_TSO4)) 2317e9d67e59SEli Cohen result |= BIT_ULL(VIRTIO_NET_F_GUEST_TSO4); 2318e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_CSUM)) 2319cbb52359SNathan Chancellor result |= BIT_ULL(VIRTIO_NET_F_GUEST_CSUM); 2320e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_CSUM)) 2321cbb52359SNathan Chancellor result |= BIT_ULL(VIRTIO_NET_F_CSUM); 2322e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_TSO6)) 2323cbb52359SNathan Chancellor result |= BIT_ULL(VIRTIO_NET_F_HOST_TSO6); 2324e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_TSO4)) 2325cbb52359SNathan Chancellor result |= BIT_ULL(VIRTIO_NET_F_HOST_TSO4); 23261a86b377SEli Cohen 23271a86b377SEli Cohen return result; 23281a86b377SEli Cohen } 23291a86b377SEli Cohen 233079de65edSEli Cohen static u64 get_supported_features(struct mlx5_core_dev *mdev) 233179de65edSEli Cohen { 233279de65edSEli Cohen u64 mlx_vdpa_features = 0; 233379de65edSEli Cohen u16 dev_features; 233479de65edSEli Cohen 233579de65edSEli Cohen dev_features = MLX5_CAP_DEV_VDPA_EMULATION(mdev, device_features_bits_mask); 233679de65edSEli Cohen mlx_vdpa_features |= mlx_to_vritio_features(dev_features); 233779de65edSEli Cohen if (MLX5_CAP_DEV_VDPA_EMULATION(mdev, virtio_version_1_0)) 233879de65edSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_F_VERSION_1); 233979de65edSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_F_ACCESS_PLATFORM); 234079de65edSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_CTRL_VQ); 234179de65edSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR); 234279de65edSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_MQ); 234379de65edSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_STATUS); 234479de65edSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_MTU); 2345baf2ad3fSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_CTRL_VLAN); 2346deeacf35SSi-Wei Liu mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_MAC); 234779de65edSEli Cohen 234879de65edSEli Cohen return mlx_vdpa_features; 234979de65edSEli Cohen } 235079de65edSEli Cohen 2351a64917bcSEli Cohen static u64 mlx5_vdpa_get_device_features(struct vdpa_device *vdev) 23521a86b377SEli Cohen { 23531a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 23541a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 23555262912eSEli Cohen 23561a86b377SEli Cohen print_features(mvdev, ndev->mvdev.mlx_features, false); 23571a86b377SEli Cohen return ndev->mvdev.mlx_features; 23581a86b377SEli Cohen } 23591a86b377SEli Cohen 236030c22f38SSi-Wei Liu static int verify_driver_features(struct mlx5_vdpa_dev *mvdev, u64 features) 23611a86b377SEli Cohen { 236230c22f38SSi-Wei Liu /* Minimum features to expect */ 2363cbb52359SNathan Chancellor if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM))) 23641a86b377SEli Cohen return -EOPNOTSUPP; 23651a86b377SEli Cohen 236630c22f38SSi-Wei Liu /* Double check features combination sent down by the driver. 236730c22f38SSi-Wei Liu * Fail invalid features due to absence of the depended feature. 236830c22f38SSi-Wei Liu * 236930c22f38SSi-Wei Liu * Per VIRTIO v1.1 specification, section 5.1.3.1 Feature bit 237030c22f38SSi-Wei Liu * requirements: "VIRTIO_NET_F_MQ Requires VIRTIO_NET_F_CTRL_VQ". 237130c22f38SSi-Wei Liu * By failing the invalid features sent down by untrusted drivers, 237230c22f38SSi-Wei Liu * we're assured the assumption made upon is_index_valid() and 237330c22f38SSi-Wei Liu * is_ctrl_vq_idx() will not be compromised. 237430c22f38SSi-Wei Liu */ 237530c22f38SSi-Wei Liu if ((features & (BIT_ULL(VIRTIO_NET_F_MQ) | BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) == 237630c22f38SSi-Wei Liu BIT_ULL(VIRTIO_NET_F_MQ)) 237730c22f38SSi-Wei Liu return -EINVAL; 237830c22f38SSi-Wei Liu 23791a86b377SEli Cohen return 0; 23801a86b377SEli Cohen } 23811a86b377SEli Cohen 2382ae0428deSEli Cohen static int setup_virtqueues(struct mlx5_vdpa_dev *mvdev) 23831a86b377SEli Cohen { 2384ae0428deSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 23851a86b377SEli Cohen int err; 23861a86b377SEli Cohen int i; 23871a86b377SEli Cohen 2388acde3929SEli Cohen for (i = 0; i < mvdev->max_vqs; i++) { 23891a86b377SEli Cohen err = setup_vq(ndev, &ndev->vqs[i]); 23901a86b377SEli Cohen if (err) 23911a86b377SEli Cohen goto err_vq; 23921a86b377SEli Cohen } 23931a86b377SEli Cohen 23941a86b377SEli Cohen return 0; 23951a86b377SEli Cohen 23961a86b377SEli Cohen err_vq: 23971a86b377SEli Cohen for (--i; i >= 0; i--) 23981a86b377SEli Cohen teardown_vq(ndev, &ndev->vqs[i]); 23991a86b377SEli Cohen 24001a86b377SEli Cohen return err; 24011a86b377SEli Cohen } 24021a86b377SEli Cohen 24031a86b377SEli Cohen static void teardown_virtqueues(struct mlx5_vdpa_net *ndev) 24041a86b377SEli Cohen { 24051a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq; 24061a86b377SEli Cohen int i; 24071a86b377SEli Cohen 24081a86b377SEli Cohen for (i = ndev->mvdev.max_vqs - 1; i >= 0; i--) { 24091a86b377SEli Cohen mvq = &ndev->vqs[i]; 24101a86b377SEli Cohen if (!mvq->initialized) 24111a86b377SEli Cohen continue; 24121a86b377SEli Cohen 24131a86b377SEli Cohen teardown_vq(ndev, mvq); 24141a86b377SEli Cohen } 24151a86b377SEli Cohen } 24161a86b377SEli Cohen 2417e4fc6650SEli Cohen static void update_cvq_info(struct mlx5_vdpa_dev *mvdev) 24188a7c3213SMichael S. Tsirkin { 2419e4fc6650SEli Cohen if (MLX5_FEATURE(mvdev, VIRTIO_NET_F_CTRL_VQ)) { 2420e4fc6650SEli Cohen if (MLX5_FEATURE(mvdev, VIRTIO_NET_F_MQ)) { 2421e4fc6650SEli Cohen /* MQ supported. CVQ index is right above the last data virtqueue's */ 2422e4fc6650SEli Cohen mvdev->max_idx = mvdev->max_vqs; 2423e4fc6650SEli Cohen } else { 2424e4fc6650SEli Cohen /* Only CVQ supportted. data virtqueues occupy indices 0 and 1. 2425e4fc6650SEli Cohen * CVQ gets index 2 2426e4fc6650SEli Cohen */ 2427e4fc6650SEli Cohen mvdev->max_idx = 2; 24288a7c3213SMichael S. Tsirkin } 2429e4fc6650SEli Cohen } else { 2430e4fc6650SEli Cohen /* Two data virtqueues only: one for rx and one for tx */ 2431e4fc6650SEli Cohen mvdev->max_idx = 1; 2432e4fc6650SEli Cohen } 243336bdcf31SEli Cohen } 243436bdcf31SEli Cohen 2435c384c240SEli Cohen static u8 query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport) 2436c384c240SEli Cohen { 2437c384c240SEli Cohen u32 out[MLX5_ST_SZ_DW(query_vport_state_out)] = {}; 2438c384c240SEli Cohen u32 in[MLX5_ST_SZ_DW(query_vport_state_in)] = {}; 2439c384c240SEli Cohen int err; 2440c384c240SEli Cohen 2441c384c240SEli Cohen MLX5_SET(query_vport_state_in, in, opcode, MLX5_CMD_OP_QUERY_VPORT_STATE); 2442c384c240SEli Cohen MLX5_SET(query_vport_state_in, in, op_mod, opmod); 2443c384c240SEli Cohen MLX5_SET(query_vport_state_in, in, vport_number, vport); 2444c384c240SEli Cohen if (vport) 2445c384c240SEli Cohen MLX5_SET(query_vport_state_in, in, other_vport, 1); 2446c384c240SEli Cohen 2447c384c240SEli Cohen err = mlx5_cmd_exec_inout(mdev, query_vport_state, in, out); 2448c384c240SEli Cohen if (err) 2449c384c240SEli Cohen return 0; 2450c384c240SEli Cohen 2451c384c240SEli Cohen return MLX5_GET(query_vport_state_out, out, state); 2452c384c240SEli Cohen } 2453c384c240SEli Cohen 2454c384c240SEli Cohen static bool get_link_state(struct mlx5_vdpa_dev *mvdev) 2455c384c240SEli Cohen { 2456c384c240SEli Cohen if (query_vport_state(mvdev->mdev, MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT, 0) == 2457c384c240SEli Cohen VPORT_STATE_UP) 2458c384c240SEli Cohen return true; 2459c384c240SEli Cohen 2460c384c240SEli Cohen return false; 2461c384c240SEli Cohen } 2462c384c240SEli Cohen 2463c384c240SEli Cohen static void update_carrier(struct work_struct *work) 2464c384c240SEli Cohen { 2465c384c240SEli Cohen struct mlx5_vdpa_wq_ent *wqent; 2466c384c240SEli Cohen struct mlx5_vdpa_dev *mvdev; 2467c384c240SEli Cohen struct mlx5_vdpa_net *ndev; 2468c384c240SEli Cohen 2469c384c240SEli Cohen wqent = container_of(work, struct mlx5_vdpa_wq_ent, work); 2470c384c240SEli Cohen mvdev = wqent->mvdev; 2471c384c240SEli Cohen ndev = to_mlx5_vdpa_ndev(mvdev); 2472c384c240SEli Cohen if (get_link_state(mvdev)) 2473c384c240SEli Cohen ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP); 2474c384c240SEli Cohen else 2475c384c240SEli Cohen ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP); 2476c384c240SEli Cohen 2477c384c240SEli Cohen if (ndev->config_cb.callback) 2478c384c240SEli Cohen ndev->config_cb.callback(ndev->config_cb.private); 2479c384c240SEli Cohen 2480c384c240SEli Cohen kfree(wqent); 2481c384c240SEli Cohen } 2482c384c240SEli Cohen 2483c384c240SEli Cohen static int queue_link_work(struct mlx5_vdpa_net *ndev) 2484c384c240SEli Cohen { 2485c384c240SEli Cohen struct mlx5_vdpa_wq_ent *wqent; 2486c384c240SEli Cohen 2487c384c240SEli Cohen wqent = kzalloc(sizeof(*wqent), GFP_ATOMIC); 2488c384c240SEli Cohen if (!wqent) 2489c384c240SEli Cohen return -ENOMEM; 2490c384c240SEli Cohen 2491c384c240SEli Cohen wqent->mvdev = &ndev->mvdev; 2492c384c240SEli Cohen INIT_WORK(&wqent->work, update_carrier); 2493c384c240SEli Cohen queue_work(ndev->mvdev.wq, &wqent->work); 2494c384c240SEli Cohen return 0; 2495c384c240SEli Cohen } 2496c384c240SEli Cohen 2497c384c240SEli Cohen static int event_handler(struct notifier_block *nb, unsigned long event, void *param) 2498c384c240SEli Cohen { 2499c384c240SEli Cohen struct mlx5_vdpa_net *ndev = container_of(nb, struct mlx5_vdpa_net, nb); 2500c384c240SEli Cohen struct mlx5_eqe *eqe = param; 2501c384c240SEli Cohen int ret = NOTIFY_DONE; 2502c384c240SEli Cohen 2503c384c240SEli Cohen if (event == MLX5_EVENT_TYPE_PORT_CHANGE) { 2504c384c240SEli Cohen switch (eqe->sub_type) { 2505c384c240SEli Cohen case MLX5_PORT_CHANGE_SUBTYPE_DOWN: 2506c384c240SEli Cohen case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE: 2507c384c240SEli Cohen if (queue_link_work(ndev)) 2508c384c240SEli Cohen return NOTIFY_DONE; 2509c384c240SEli Cohen 2510c384c240SEli Cohen ret = NOTIFY_OK; 2511c384c240SEli Cohen break; 2512c384c240SEli Cohen default: 2513c384c240SEli Cohen return NOTIFY_DONE; 2514c384c240SEli Cohen } 2515c384c240SEli Cohen return ret; 2516c384c240SEli Cohen } 2517c384c240SEli Cohen return ret; 2518c384c240SEli Cohen } 2519c384c240SEli Cohen 2520c384c240SEli Cohen static void register_link_notifier(struct mlx5_vdpa_net *ndev) 2521c384c240SEli Cohen { 2522c384c240SEli Cohen if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_STATUS))) 2523c384c240SEli Cohen return; 2524c384c240SEli Cohen 2525c384c240SEli Cohen ndev->nb.notifier_call = event_handler; 2526c384c240SEli Cohen mlx5_notifier_register(ndev->mvdev.mdev, &ndev->nb); 2527c384c240SEli Cohen ndev->nb_registered = true; 2528c384c240SEli Cohen queue_link_work(ndev); 2529c384c240SEli Cohen } 2530c384c240SEli Cohen 2531c384c240SEli Cohen static void unregister_link_notifier(struct mlx5_vdpa_net *ndev) 2532c384c240SEli Cohen { 2533c384c240SEli Cohen if (!ndev->nb_registered) 2534c384c240SEli Cohen return; 2535c384c240SEli Cohen 2536c384c240SEli Cohen ndev->nb_registered = false; 2537c384c240SEli Cohen mlx5_notifier_unregister(ndev->mvdev.mdev, &ndev->nb); 2538c384c240SEli Cohen if (ndev->mvdev.wq) 2539c384c240SEli Cohen flush_workqueue(ndev->mvdev.wq); 2540c384c240SEli Cohen } 2541c384c240SEli Cohen 2542a64917bcSEli Cohen static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features) 25431a86b377SEli Cohen { 25441a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 25451a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 25461a86b377SEli Cohen int err; 25471a86b377SEli Cohen 25481a86b377SEli Cohen print_features(mvdev, features, true); 25491a86b377SEli Cohen 255030c22f38SSi-Wei Liu err = verify_driver_features(mvdev, features); 25511a86b377SEli Cohen if (err) 25521a86b377SEli Cohen return err; 25531a86b377SEli Cohen 25541a86b377SEli Cohen ndev->mvdev.actual_features = features & ndev->mvdev.mlx_features; 2555b03fc43eSEli Cohen if (ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_MQ)) 2556acde3929SEli Cohen ndev->rqt_size = mlx5vdpa16_to_cpu(mvdev, ndev->config.max_virtqueue_pairs); 2557b03fc43eSEli Cohen else 2558acde3929SEli Cohen ndev->rqt_size = 1; 2559acde3929SEli Cohen 25603fe02419SDragos Tatulea /* Device must start with 1 queue pair, as per VIRTIO v1.2 spec, section 25613fe02419SDragos Tatulea * 5.1.6.5.5 "Device operation in multiqueue mode": 25623fe02419SDragos Tatulea * 25633fe02419SDragos Tatulea * Multiqueue is disabled by default. 25643fe02419SDragos Tatulea * The driver enables multiqueue by sending a command using class 25653fe02419SDragos Tatulea * VIRTIO_NET_CTRL_MQ. The command selects the mode of multiqueue 25663fe02419SDragos Tatulea * operation, as follows: ... 25673fe02419SDragos Tatulea */ 25683fe02419SDragos Tatulea ndev->cur_num_vqs = 2; 2569b03fc43eSEli Cohen 2570e4fc6650SEli Cohen update_cvq_info(mvdev); 25711a86b377SEli Cohen return err; 25721a86b377SEli Cohen } 25731a86b377SEli Cohen 25741a86b377SEli Cohen static void mlx5_vdpa_set_config_cb(struct vdpa_device *vdev, struct vdpa_callback *cb) 25751a86b377SEli Cohen { 2576edf747afSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 2577edf747afSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 2578edf747afSEli Cohen 2579edf747afSEli Cohen ndev->config_cb = *cb; 25801a86b377SEli Cohen } 25811a86b377SEli Cohen 25821a86b377SEli Cohen #define MLX5_VDPA_MAX_VQ_ENTRIES 256 25831a86b377SEli Cohen static u16 mlx5_vdpa_get_vq_num_max(struct vdpa_device *vdev) 25841a86b377SEli Cohen { 25851a86b377SEli Cohen return MLX5_VDPA_MAX_VQ_ENTRIES; 25861a86b377SEli Cohen } 25871a86b377SEli Cohen 25881a86b377SEli Cohen static u32 mlx5_vdpa_get_device_id(struct vdpa_device *vdev) 25891a86b377SEli Cohen { 25901a86b377SEli Cohen return VIRTIO_ID_NET; 25911a86b377SEli Cohen } 25921a86b377SEli Cohen 25931a86b377SEli Cohen static u32 mlx5_vdpa_get_vendor_id(struct vdpa_device *vdev) 25941a86b377SEli Cohen { 25951a86b377SEli Cohen return PCI_VENDOR_ID_MELLANOX; 25961a86b377SEli Cohen } 25971a86b377SEli Cohen 25981a86b377SEli Cohen static u8 mlx5_vdpa_get_status(struct vdpa_device *vdev) 25991a86b377SEli Cohen { 26001a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 26011a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 26021a86b377SEli Cohen 26031a86b377SEli Cohen print_status(mvdev, ndev->mvdev.status, false); 26041a86b377SEli Cohen return ndev->mvdev.status; 26051a86b377SEli Cohen } 26061a86b377SEli Cohen 26071a86b377SEli Cohen static int save_channel_info(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 26081a86b377SEli Cohen { 26091a86b377SEli Cohen struct mlx5_vq_restore_info *ri = &mvq->ri; 261052893733SEli Cohen struct mlx5_virtq_attr attr = {}; 26111a86b377SEli Cohen int err; 26121a86b377SEli Cohen 261352893733SEli Cohen if (mvq->initialized) { 26141a86b377SEli Cohen err = query_virtqueue(ndev, mvq, &attr); 26151a86b377SEli Cohen if (err) 26161a86b377SEli Cohen return err; 261752893733SEli Cohen } 26181a86b377SEli Cohen 26191a86b377SEli Cohen ri->avail_index = attr.available_index; 2620b35ccebeSEli Cohen ri->used_index = attr.used_index; 26211a86b377SEli Cohen ri->ready = mvq->ready; 26221a86b377SEli Cohen ri->num_ent = mvq->num_ent; 26231a86b377SEli Cohen ri->desc_addr = mvq->desc_addr; 26241a86b377SEli Cohen ri->device_addr = mvq->device_addr; 26251a86b377SEli Cohen ri->driver_addr = mvq->driver_addr; 2626bc9a2b3eSEli Cohen ri->map = mvq->map; 26271a86b377SEli Cohen ri->restore = true; 26281a86b377SEli Cohen return 0; 26291a86b377SEli Cohen } 26301a86b377SEli Cohen 26311a86b377SEli Cohen static int save_channels_info(struct mlx5_vdpa_net *ndev) 26321a86b377SEli Cohen { 26331a86b377SEli Cohen int i; 26341a86b377SEli Cohen 26351a86b377SEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) { 26361a86b377SEli Cohen memset(&ndev->vqs[i].ri, 0, sizeof(ndev->vqs[i].ri)); 26371a86b377SEli Cohen save_channel_info(ndev, &ndev->vqs[i]); 26381a86b377SEli Cohen } 26391a86b377SEli Cohen return 0; 26401a86b377SEli Cohen } 26411a86b377SEli Cohen 26421a86b377SEli Cohen static void mlx5_clear_vqs(struct mlx5_vdpa_net *ndev) 26431a86b377SEli Cohen { 26441a86b377SEli Cohen int i; 26451a86b377SEli Cohen 26461a86b377SEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) 26471a86b377SEli Cohen memset(&ndev->vqs[i], 0, offsetof(struct mlx5_vdpa_virtqueue, ri)); 26481a86b377SEli Cohen } 26491a86b377SEli Cohen 26501a86b377SEli Cohen static void restore_channels_info(struct mlx5_vdpa_net *ndev) 26511a86b377SEli Cohen { 26521a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq; 26531a86b377SEli Cohen struct mlx5_vq_restore_info *ri; 26541a86b377SEli Cohen int i; 26551a86b377SEli Cohen 26561a86b377SEli Cohen mlx5_clear_vqs(ndev); 26571a86b377SEli Cohen init_mvqs(ndev); 26581a86b377SEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) { 26591a86b377SEli Cohen mvq = &ndev->vqs[i]; 26601a86b377SEli Cohen ri = &mvq->ri; 26611a86b377SEli Cohen if (!ri->restore) 26621a86b377SEli Cohen continue; 26631a86b377SEli Cohen 26641a86b377SEli Cohen mvq->avail_idx = ri->avail_index; 2665b35ccebeSEli Cohen mvq->used_idx = ri->used_index; 26661a86b377SEli Cohen mvq->ready = ri->ready; 26671a86b377SEli Cohen mvq->num_ent = ri->num_ent; 26681a86b377SEli Cohen mvq->desc_addr = ri->desc_addr; 26691a86b377SEli Cohen mvq->device_addr = ri->device_addr; 26701a86b377SEli Cohen mvq->driver_addr = ri->driver_addr; 2671bc9a2b3eSEli Cohen mvq->map = ri->map; 26721a86b377SEli Cohen } 26731a86b377SEli Cohen } 26741a86b377SEli Cohen 267538fc462fSEli Cohen static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, 267638fc462fSEli Cohen struct vhost_iotlb *iotlb, unsigned int asid) 26771a86b377SEli Cohen { 2678ae0428deSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 26791a86b377SEli Cohen int err; 26801a86b377SEli Cohen 26811a86b377SEli Cohen suspend_vqs(ndev); 26821a86b377SEli Cohen err = save_channels_info(ndev); 26831a86b377SEli Cohen if (err) 26841a86b377SEli Cohen goto err_mr; 26851a86b377SEli Cohen 26861a86b377SEli Cohen teardown_driver(ndev); 2687ad03a0f4SEugenio Pérez mlx5_vdpa_destroy_mr_asid(mvdev, asid); 268838fc462fSEli Cohen err = mlx5_vdpa_create_mr(mvdev, iotlb, asid); 26891a86b377SEli Cohen if (err) 26901a86b377SEli Cohen goto err_mr; 26911a86b377SEli Cohen 269209e65ee9SSi-Wei Liu if (!(mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK) || mvdev->suspended) 26931c80cf03SJason Wang goto err_mr; 26941897f0b6SEli Cohen 26951a86b377SEli Cohen restore_channels_info(ndev); 2696ae0428deSEli Cohen err = setup_driver(mvdev); 26971a86b377SEli Cohen if (err) 26981a86b377SEli Cohen goto err_setup; 26991a86b377SEli Cohen 27001a86b377SEli Cohen return 0; 27011a86b377SEli Cohen 27021a86b377SEli Cohen err_setup: 2703ad03a0f4SEugenio Pérez mlx5_vdpa_destroy_mr_asid(mvdev, asid); 27041a86b377SEli Cohen err_mr: 27051a86b377SEli Cohen return err; 27061a86b377SEli Cohen } 27071a86b377SEli Cohen 27081c80cf03SJason Wang /* reslock must be held for this function */ 2709ae0428deSEli Cohen static int setup_driver(struct mlx5_vdpa_dev *mvdev) 27101a86b377SEli Cohen { 2711ae0428deSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 27121a86b377SEli Cohen int err; 27131a86b377SEli Cohen 2714759ae7f9SEli Cohen WARN_ON(!rwsem_is_locked(&ndev->reslock)); 27151c80cf03SJason Wang 27161a86b377SEli Cohen if (ndev->setup) { 2717ae0428deSEli Cohen mlx5_vdpa_warn(mvdev, "setup driver called for already setup driver\n"); 27181a86b377SEli Cohen err = 0; 27191a86b377SEli Cohen goto out; 27201a86b377SEli Cohen } 2721f0417e72SEli Cohen mlx5_vdpa_add_debugfs(ndev); 2722abb0dcf9SDragos Tatulea 2723abb0dcf9SDragos Tatulea err = read_umem_params(ndev); 2724abb0dcf9SDragos Tatulea if (err) 2725abb0dcf9SDragos Tatulea goto err_setup; 2726abb0dcf9SDragos Tatulea 2727ae0428deSEli Cohen err = setup_virtqueues(mvdev); 27281a86b377SEli Cohen if (err) { 2729ae0428deSEli Cohen mlx5_vdpa_warn(mvdev, "setup_virtqueues\n"); 2730f0417e72SEli Cohen goto err_setup; 27311a86b377SEli Cohen } 27321a86b377SEli Cohen 27331a86b377SEli Cohen err = create_rqt(ndev); 27341a86b377SEli Cohen if (err) { 2735ae0428deSEli Cohen mlx5_vdpa_warn(mvdev, "create_rqt\n"); 27361a86b377SEli Cohen goto err_rqt; 27371a86b377SEli Cohen } 27381a86b377SEli Cohen 27391a86b377SEli Cohen err = create_tir(ndev); 27401a86b377SEli Cohen if (err) { 2741ae0428deSEli Cohen mlx5_vdpa_warn(mvdev, "create_tir\n"); 27421a86b377SEli Cohen goto err_tir; 27431a86b377SEli Cohen } 27441a86b377SEli Cohen 2745baf2ad3fSEli Cohen err = setup_steering(ndev); 27461a86b377SEli Cohen if (err) { 2747baf2ad3fSEli Cohen mlx5_vdpa_warn(mvdev, "setup_steering\n"); 27481a86b377SEli Cohen goto err_fwd; 27491a86b377SEli Cohen } 27501a86b377SEli Cohen ndev->setup = true; 27511a86b377SEli Cohen 27521a86b377SEli Cohen return 0; 27531a86b377SEli Cohen 27541a86b377SEli Cohen err_fwd: 27551a86b377SEli Cohen destroy_tir(ndev); 27561a86b377SEli Cohen err_tir: 27571a86b377SEli Cohen destroy_rqt(ndev); 27581a86b377SEli Cohen err_rqt: 27591a86b377SEli Cohen teardown_virtqueues(ndev); 2760f0417e72SEli Cohen err_setup: 2761f8a3db47SDragos Tatulea mlx5_vdpa_remove_debugfs(ndev); 27621a86b377SEli Cohen out: 27631a86b377SEli Cohen return err; 27641a86b377SEli Cohen } 27651a86b377SEli Cohen 27661c80cf03SJason Wang /* reslock must be held for this function */ 27671a86b377SEli Cohen static void teardown_driver(struct mlx5_vdpa_net *ndev) 27681a86b377SEli Cohen { 27691c80cf03SJason Wang 2770759ae7f9SEli Cohen WARN_ON(!rwsem_is_locked(&ndev->reslock)); 27711c80cf03SJason Wang 27721a86b377SEli Cohen if (!ndev->setup) 27731c80cf03SJason Wang return; 27741a86b377SEli Cohen 2775f8a3db47SDragos Tatulea mlx5_vdpa_remove_debugfs(ndev); 2776baf2ad3fSEli Cohen teardown_steering(ndev); 27771a86b377SEli Cohen destroy_tir(ndev); 27781a86b377SEli Cohen destroy_rqt(ndev); 27791a86b377SEli Cohen teardown_virtqueues(ndev); 27801a86b377SEli Cohen ndev->setup = false; 27811a86b377SEli Cohen } 27821a86b377SEli Cohen 2783e3aadf2eSEli Cohen static void clear_vqs_ready(struct mlx5_vdpa_net *ndev) 2784e3aadf2eSEli Cohen { 2785e3aadf2eSEli Cohen int i; 2786e3aadf2eSEli Cohen 2787e3aadf2eSEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) 2788e3aadf2eSEli Cohen ndev->vqs[i].ready = false; 2789ef12e4bfSEli Cohen 2790ef12e4bfSEli Cohen ndev->mvdev.cvq.ready = false; 2791e3aadf2eSEli Cohen } 2792e3aadf2eSEli Cohen 2793ace92524SEli Cohen static int setup_cvq_vring(struct mlx5_vdpa_dev *mvdev) 2794ace92524SEli Cohen { 2795ace92524SEli Cohen struct mlx5_control_vq *cvq = &mvdev->cvq; 2796ace92524SEli Cohen int err = 0; 2797ace92524SEli Cohen 2798*dd3438abSSteve Sistare if (mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ)) { 2799*dd3438abSSteve Sistare u16 idx = cvq->vring.last_avail_idx; 2800*dd3438abSSteve Sistare 2801ace92524SEli Cohen err = vringh_init_iotlb(&cvq->vring, mvdev->actual_features, 2802ace92524SEli Cohen MLX5_CVQ_MAX_ENT, false, 2803ace92524SEli Cohen (struct vring_desc *)(uintptr_t)cvq->desc_addr, 2804ace92524SEli Cohen (struct vring_avail *)(uintptr_t)cvq->driver_addr, 2805ace92524SEli Cohen (struct vring_used *)(uintptr_t)cvq->device_addr); 2806ace92524SEli Cohen 2807*dd3438abSSteve Sistare if (!err) 2808*dd3438abSSteve Sistare cvq->vring.last_avail_idx = cvq->vring.last_used_idx = idx; 2809*dd3438abSSteve Sistare } 2810ace92524SEli Cohen return err; 2811ace92524SEli Cohen } 2812ace92524SEli Cohen 28131a86b377SEli Cohen static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) 28141a86b377SEli Cohen { 28151a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 28161a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 28171a86b377SEli Cohen int err; 28181a86b377SEli Cohen 28191a86b377SEli Cohen print_status(mvdev, status, true); 28201a86b377SEli Cohen 2821759ae7f9SEli Cohen down_write(&ndev->reslock); 28221c80cf03SJason Wang 28231a86b377SEli Cohen if ((status ^ ndev->mvdev.status) & VIRTIO_CONFIG_S_DRIVER_OK) { 28241a86b377SEli Cohen if (status & VIRTIO_CONFIG_S_DRIVER_OK) { 2825ace92524SEli Cohen err = setup_cvq_vring(mvdev); 2826ace92524SEli Cohen if (err) { 2827ace92524SEli Cohen mlx5_vdpa_warn(mvdev, "failed to setup control VQ vring\n"); 2828ace92524SEli Cohen goto err_setup; 2829ace92524SEli Cohen } 2830c384c240SEli Cohen register_link_notifier(ndev); 2831ae0428deSEli Cohen err = setup_driver(mvdev); 28321a86b377SEli Cohen if (err) { 28331a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "failed to setup driver\n"); 2834c384c240SEli Cohen goto err_driver; 28351a86b377SEli Cohen } 28361a86b377SEli Cohen } else { 28371a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "did not expect DRIVER_OK to be cleared\n"); 28381c80cf03SJason Wang goto err_clear; 28391a86b377SEli Cohen } 28401a86b377SEli Cohen } 28411a86b377SEli Cohen 28421a86b377SEli Cohen ndev->mvdev.status = status; 2843759ae7f9SEli Cohen up_write(&ndev->reslock); 28441a86b377SEli Cohen return; 28451a86b377SEli Cohen 2846c384c240SEli Cohen err_driver: 2847c384c240SEli Cohen unregister_link_notifier(ndev); 28481a86b377SEli Cohen err_setup: 28491a86b377SEli Cohen mlx5_vdpa_destroy_mr(&ndev->mvdev); 28501a86b377SEli Cohen ndev->mvdev.status |= VIRTIO_CONFIG_S_FAILED; 28511c80cf03SJason Wang err_clear: 2852759ae7f9SEli Cohen up_write(&ndev->reslock); 28531a86b377SEli Cohen } 28541a86b377SEli Cohen 28558fcd20c3SEli Cohen static void init_group_to_asid_map(struct mlx5_vdpa_dev *mvdev) 28568fcd20c3SEli Cohen { 28578fcd20c3SEli Cohen int i; 28588fcd20c3SEli Cohen 28598fcd20c3SEli Cohen /* default mapping all groups are mapped to asid 0 */ 28608fcd20c3SEli Cohen for (i = 0; i < MLX5_VDPA_NUMVQ_GROUPS; i++) 28618fcd20c3SEli Cohen mvdev->group2asid[i] = 0; 28628fcd20c3SEli Cohen } 28638fcd20c3SEli Cohen 28640686082dSXie Yongji static int mlx5_vdpa_reset(struct vdpa_device *vdev) 28650686082dSXie Yongji { 28660686082dSXie Yongji struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 28670686082dSXie Yongji struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 28680686082dSXie Yongji 28690686082dSXie Yongji print_status(mvdev, 0, true); 28700686082dSXie Yongji mlx5_vdpa_info(mvdev, "performing device reset\n"); 28711c80cf03SJason Wang 2872759ae7f9SEli Cohen down_write(&ndev->reslock); 2873c384c240SEli Cohen unregister_link_notifier(ndev); 28740686082dSXie Yongji teardown_driver(ndev); 28750686082dSXie Yongji clear_vqs_ready(ndev); 28760686082dSXie Yongji mlx5_vdpa_destroy_mr(&ndev->mvdev); 28770686082dSXie Yongji ndev->mvdev.status = 0; 287809e65ee9SSi-Wei Liu ndev->mvdev.suspended = false; 2879b03fc43eSEli Cohen ndev->cur_num_vqs = 0; 28801892a3d4SEli Cohen ndev->mvdev.cvq.received_desc = 0; 28811892a3d4SEli Cohen ndev->mvdev.cvq.completed_desc = 0; 288275560522SEli Cohen memset(ndev->event_cbs, 0, sizeof(*ndev->event_cbs) * (mvdev->max_vqs + 1)); 28830686082dSXie Yongji ndev->mvdev.actual_features = 0; 28848fcd20c3SEli Cohen init_group_to_asid_map(mvdev); 28850686082dSXie Yongji ++mvdev->generation; 28868fcd20c3SEli Cohen 28870686082dSXie Yongji if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) { 288838fc462fSEli Cohen if (mlx5_vdpa_create_mr(mvdev, NULL, 0)) 28890686082dSXie Yongji mlx5_vdpa_warn(mvdev, "create MR failed\n"); 28900686082dSXie Yongji } 2891759ae7f9SEli Cohen up_write(&ndev->reslock); 28920686082dSXie Yongji 28930686082dSXie Yongji return 0; 28940686082dSXie Yongji } 28950686082dSXie Yongji 2896442706f9SStefano Garzarella static size_t mlx5_vdpa_get_config_size(struct vdpa_device *vdev) 2897442706f9SStefano Garzarella { 2898442706f9SStefano Garzarella return sizeof(struct virtio_net_config); 2899442706f9SStefano Garzarella } 2900442706f9SStefano Garzarella 29011a86b377SEli Cohen static void mlx5_vdpa_get_config(struct vdpa_device *vdev, unsigned int offset, void *buf, 29021a86b377SEli Cohen unsigned int len) 29031a86b377SEli Cohen { 29041a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 29051a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 29061a86b377SEli Cohen 2907dcfde163SStefano Garzarella if (offset + len <= sizeof(struct virtio_net_config)) 29082874211fSDan Carpenter memcpy(buf, (u8 *)&ndev->config + offset, len); 29091a86b377SEli Cohen } 29101a86b377SEli Cohen 29111a86b377SEli Cohen static void mlx5_vdpa_set_config(struct vdpa_device *vdev, unsigned int offset, const void *buf, 29121a86b377SEli Cohen unsigned int len) 29131a86b377SEli Cohen { 29141a86b377SEli Cohen /* not supported */ 29151a86b377SEli Cohen } 29161a86b377SEli Cohen 29171a86b377SEli Cohen static u32 mlx5_vdpa_get_generation(struct vdpa_device *vdev) 29181a86b377SEli Cohen { 29191a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 29201a86b377SEli Cohen 29211a86b377SEli Cohen return mvdev->generation; 29221a86b377SEli Cohen } 29231a86b377SEli Cohen 292438fc462fSEli Cohen static int set_map_data(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb, 292538fc462fSEli Cohen unsigned int asid) 29268fcd20c3SEli Cohen { 29271a86b377SEli Cohen bool change_map; 29281a86b377SEli Cohen int err; 29291a86b377SEli Cohen 293038fc462fSEli Cohen err = mlx5_vdpa_handle_set_map(mvdev, iotlb, &change_map, asid); 29311a86b377SEli Cohen if (err) { 29321a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "set map failed(%d)\n", err); 29338fcd20c3SEli Cohen return err; 29341a86b377SEli Cohen } 29351a86b377SEli Cohen 29361a86b377SEli Cohen if (change_map) 293738fc462fSEli Cohen err = mlx5_vdpa_change_map(mvdev, iotlb, asid); 29381a86b377SEli Cohen 29398fcd20c3SEli Cohen return err; 29408fcd20c3SEli Cohen } 29418fcd20c3SEli Cohen 29428fcd20c3SEli Cohen static int mlx5_vdpa_set_map(struct vdpa_device *vdev, unsigned int asid, 29438fcd20c3SEli Cohen struct vhost_iotlb *iotlb) 29448fcd20c3SEli Cohen { 29458fcd20c3SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 29468fcd20c3SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 294793e530d2SEli Cohen int err = -EINVAL; 29488fcd20c3SEli Cohen 29498fcd20c3SEli Cohen down_write(&ndev->reslock); 295038fc462fSEli Cohen err = set_map_data(mvdev, iotlb, asid); 2951759ae7f9SEli Cohen up_write(&ndev->reslock); 29521c80cf03SJason Wang return err; 29531a86b377SEli Cohen } 29541a86b377SEli Cohen 295536871fb9SJason Wang static struct device *mlx5_get_vq_dma_dev(struct vdpa_device *vdev, u16 idx) 295636871fb9SJason Wang { 295736871fb9SJason Wang struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 295836871fb9SJason Wang 295936871fb9SJason Wang if (is_ctrl_vq_idx(mvdev, idx)) 296036871fb9SJason Wang return &vdev->dev; 296136871fb9SJason Wang 296236871fb9SJason Wang return mvdev->vdev.dma_dev; 296336871fb9SJason Wang } 296436871fb9SJason Wang 2965bc9a2b3eSEli Cohen static void free_irqs(struct mlx5_vdpa_net *ndev) 2966bc9a2b3eSEli Cohen { 2967bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool_entry *ent; 2968bc9a2b3eSEli Cohen int i; 2969bc9a2b3eSEli Cohen 2970bc9a2b3eSEli Cohen if (!msix_mode_supported(&ndev->mvdev)) 2971bc9a2b3eSEli Cohen return; 2972bc9a2b3eSEli Cohen 2973bc9a2b3eSEli Cohen if (!ndev->irqp.entries) 2974bc9a2b3eSEli Cohen return; 2975bc9a2b3eSEli Cohen 2976bc9a2b3eSEli Cohen for (i = ndev->irqp.num_ent - 1; i >= 0; i--) { 2977bc9a2b3eSEli Cohen ent = ndev->irqp.entries + i; 2978bc9a2b3eSEli Cohen if (ent->map.virq) 2979bc9a2b3eSEli Cohen pci_msix_free_irq(ndev->mvdev.mdev->pdev, ent->map); 2980bc9a2b3eSEli Cohen } 2981bc9a2b3eSEli Cohen kfree(ndev->irqp.entries); 2982bc9a2b3eSEli Cohen } 2983bc9a2b3eSEli Cohen 29841a86b377SEli Cohen static void mlx5_vdpa_free(struct vdpa_device *vdev) 29851a86b377SEli Cohen { 29861a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 29877c9f131fSEli Cohen struct mlx5_core_dev *pfmdev; 29881a86b377SEli Cohen struct mlx5_vdpa_net *ndev; 29891a86b377SEli Cohen 29901a86b377SEli Cohen ndev = to_mlx5_vdpa_ndev(mvdev); 29911a86b377SEli Cohen 29921a86b377SEli Cohen free_resources(ndev); 29936f5312f8SEli Cohen mlx5_vdpa_destroy_mr(mvdev); 29947c9f131fSEli Cohen if (!is_zero_ether_addr(ndev->config.mac)) { 29957c9f131fSEli Cohen pfmdev = pci_get_drvdata(pci_physfn(mvdev->mdev->pdev)); 29967c9f131fSEli Cohen mlx5_mpfs_del_mac(pfmdev, ndev->config.mac); 29977c9f131fSEli Cohen } 29981a86b377SEli Cohen mlx5_vdpa_free_resources(&ndev->mvdev); 2999bc9a2b3eSEli Cohen free_irqs(ndev); 300075560522SEli Cohen kfree(ndev->event_cbs); 300175560522SEli Cohen kfree(ndev->vqs); 30021a86b377SEli Cohen } 30031a86b377SEli Cohen 30041a86b377SEli Cohen static struct vdpa_notification_area mlx5_get_vq_notification(struct vdpa_device *vdev, u16 idx) 30051a86b377SEli Cohen { 3006b57c46cbSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 30071a86b377SEli Cohen struct vdpa_notification_area ret = {}; 3008b57c46cbSEli Cohen struct mlx5_vdpa_net *ndev; 3009b57c46cbSEli Cohen phys_addr_t addr; 30101a86b377SEli Cohen 30115262912eSEli Cohen if (!is_index_valid(mvdev, idx) || is_ctrl_vq_idx(mvdev, idx)) 3012e4fc6650SEli Cohen return ret; 3013e4fc6650SEli Cohen 3014b57c46cbSEli Cohen /* If SF BAR size is smaller than PAGE_SIZE, do not use direct 3015b57c46cbSEli Cohen * notification to avoid the risk of mapping pages that contain BAR of more 3016b57c46cbSEli Cohen * than one SF 3017b57c46cbSEli Cohen */ 3018b57c46cbSEli Cohen if (MLX5_CAP_GEN(mvdev->mdev, log_min_sf_size) + 12 < PAGE_SHIFT) 3019b57c46cbSEli Cohen return ret; 3020b57c46cbSEli Cohen 3021b57c46cbSEli Cohen ndev = to_mlx5_vdpa_ndev(mvdev); 3022b57c46cbSEli Cohen addr = (phys_addr_t)ndev->mvdev.res.phys_kick_addr; 3023b57c46cbSEli Cohen ret.addr = addr; 3024b57c46cbSEli Cohen ret.size = PAGE_SIZE; 30251a86b377SEli Cohen return ret; 30261a86b377SEli Cohen } 30271a86b377SEli Cohen 3028bc9a2b3eSEli Cohen static int mlx5_get_vq_irq(struct vdpa_device *vdev, u16 idx) 30291a86b377SEli Cohen { 3030bc9a2b3eSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 3031bc9a2b3eSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 3032bc9a2b3eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 3033bc9a2b3eSEli Cohen 3034bc9a2b3eSEli Cohen if (!is_index_valid(mvdev, idx)) 3035bc9a2b3eSEli Cohen return -EINVAL; 3036bc9a2b3eSEli Cohen 3037bc9a2b3eSEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) 30381a86b377SEli Cohen return -EOPNOTSUPP; 3039bc9a2b3eSEli Cohen 3040bc9a2b3eSEli Cohen mvq = &ndev->vqs[idx]; 3041bc9a2b3eSEli Cohen if (!mvq->map.virq) 3042bc9a2b3eSEli Cohen return -EOPNOTSUPP; 3043bc9a2b3eSEli Cohen 3044bc9a2b3eSEli Cohen return mvq->map.virq; 30451a86b377SEli Cohen } 30461a86b377SEli Cohen 3047a64917bcSEli Cohen static u64 mlx5_vdpa_get_driver_features(struct vdpa_device *vdev) 3048a64917bcSEli Cohen { 3049a64917bcSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 3050a64917bcSEli Cohen 3051a64917bcSEli Cohen return mvdev->actual_features; 3052a64917bcSEli Cohen } 3053a64917bcSEli Cohen 30541892a3d4SEli Cohen static int counter_set_query(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, 30551892a3d4SEli Cohen u64 *received_desc, u64 *completed_desc) 30561892a3d4SEli Cohen { 30571892a3d4SEli Cohen u32 in[MLX5_ST_SZ_DW(query_virtio_q_counters_in)] = {}; 30581892a3d4SEli Cohen u32 out[MLX5_ST_SZ_DW(query_virtio_q_counters_out)] = {}; 30591892a3d4SEli Cohen void *cmd_hdr; 30601892a3d4SEli Cohen void *ctx; 30611892a3d4SEli Cohen int err; 30621892a3d4SEli Cohen 30631892a3d4SEli Cohen if (!counters_supported(&ndev->mvdev)) 30641892a3d4SEli Cohen return -EOPNOTSUPP; 30651892a3d4SEli Cohen 30661892a3d4SEli Cohen if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY) 30671892a3d4SEli Cohen return -EAGAIN; 30681892a3d4SEli Cohen 30691892a3d4SEli Cohen cmd_hdr = MLX5_ADDR_OF(query_virtio_q_counters_in, in, hdr); 30701892a3d4SEli Cohen 30711892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_QUERY_GENERAL_OBJECT); 30721892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_Q_COUNTERS); 30731892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 30741892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_id, mvq->counter_set_id); 30751892a3d4SEli Cohen 30761892a3d4SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out)); 30771892a3d4SEli Cohen if (err) 30781892a3d4SEli Cohen return err; 30791892a3d4SEli Cohen 30801892a3d4SEli Cohen ctx = MLX5_ADDR_OF(query_virtio_q_counters_out, out, counters); 30811892a3d4SEli Cohen *received_desc = MLX5_GET64(virtio_q_counters, ctx, received_desc); 30821892a3d4SEli Cohen *completed_desc = MLX5_GET64(virtio_q_counters, ctx, completed_desc); 30831892a3d4SEli Cohen return 0; 30841892a3d4SEli Cohen } 30851892a3d4SEli Cohen 30861892a3d4SEli Cohen static int mlx5_vdpa_get_vendor_vq_stats(struct vdpa_device *vdev, u16 idx, 30871892a3d4SEli Cohen struct sk_buff *msg, 30881892a3d4SEli Cohen struct netlink_ext_ack *extack) 30891892a3d4SEli Cohen { 30901892a3d4SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 30911892a3d4SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 30921892a3d4SEli Cohen struct mlx5_vdpa_virtqueue *mvq; 30931892a3d4SEli Cohen struct mlx5_control_vq *cvq; 30941892a3d4SEli Cohen u64 received_desc; 30951892a3d4SEli Cohen u64 completed_desc; 30961892a3d4SEli Cohen int err = 0; 30971892a3d4SEli Cohen 3098759ae7f9SEli Cohen down_read(&ndev->reslock); 30991892a3d4SEli Cohen if (!is_index_valid(mvdev, idx)) { 31001892a3d4SEli Cohen NL_SET_ERR_MSG_MOD(extack, "virtqueue index is not valid"); 31011892a3d4SEli Cohen err = -EINVAL; 31021892a3d4SEli Cohen goto out_err; 31031892a3d4SEli Cohen } 31041892a3d4SEli Cohen 31051892a3d4SEli Cohen if (idx == ctrl_vq_idx(mvdev)) { 31061892a3d4SEli Cohen cvq = &mvdev->cvq; 31071892a3d4SEli Cohen received_desc = cvq->received_desc; 31081892a3d4SEli Cohen completed_desc = cvq->completed_desc; 31091892a3d4SEli Cohen goto out; 31101892a3d4SEli Cohen } 31111892a3d4SEli Cohen 31121892a3d4SEli Cohen mvq = &ndev->vqs[idx]; 31131892a3d4SEli Cohen err = counter_set_query(ndev, mvq, &received_desc, &completed_desc); 31141892a3d4SEli Cohen if (err) { 31151892a3d4SEli Cohen NL_SET_ERR_MSG_MOD(extack, "failed to query hardware"); 31161892a3d4SEli Cohen goto out_err; 31171892a3d4SEli Cohen } 31181892a3d4SEli Cohen 31191892a3d4SEli Cohen out: 31201892a3d4SEli Cohen err = -EMSGSIZE; 31211892a3d4SEli Cohen if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME, "received_desc")) 31221892a3d4SEli Cohen goto out_err; 31231892a3d4SEli Cohen 31241892a3d4SEli Cohen if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE, received_desc, 31251892a3d4SEli Cohen VDPA_ATTR_PAD)) 31261892a3d4SEli Cohen goto out_err; 31271892a3d4SEli Cohen 31281892a3d4SEli Cohen if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME, "completed_desc")) 31291892a3d4SEli Cohen goto out_err; 31301892a3d4SEli Cohen 31311892a3d4SEli Cohen if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE, completed_desc, 31321892a3d4SEli Cohen VDPA_ATTR_PAD)) 31331892a3d4SEli Cohen goto out_err; 31341892a3d4SEli Cohen 31351892a3d4SEli Cohen err = 0; 31361892a3d4SEli Cohen out_err: 3137759ae7f9SEli Cohen up_read(&ndev->reslock); 31381892a3d4SEli Cohen return err; 31391892a3d4SEli Cohen } 31401892a3d4SEli Cohen 3141cae15c2eSEli Cohen static void mlx5_vdpa_cvq_suspend(struct mlx5_vdpa_dev *mvdev) 3142cae15c2eSEli Cohen { 3143cae15c2eSEli Cohen struct mlx5_control_vq *cvq; 3144cae15c2eSEli Cohen 3145cae15c2eSEli Cohen if (!(mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) 3146cae15c2eSEli Cohen return; 3147cae15c2eSEli Cohen 3148cae15c2eSEli Cohen cvq = &mvdev->cvq; 3149cae15c2eSEli Cohen cvq->ready = false; 3150cae15c2eSEli Cohen } 3151cae15c2eSEli Cohen 3152cae15c2eSEli Cohen static int mlx5_vdpa_suspend(struct vdpa_device *vdev) 3153cae15c2eSEli Cohen { 3154cae15c2eSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 3155cae15c2eSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 3156cae15c2eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 3157cae15c2eSEli Cohen int i; 3158cae15c2eSEli Cohen 315909e65ee9SSi-Wei Liu mlx5_vdpa_info(mvdev, "suspending device\n"); 316009e65ee9SSi-Wei Liu 3161cae15c2eSEli Cohen down_write(&ndev->reslock); 3162c384c240SEli Cohen unregister_link_notifier(ndev); 3163cae15c2eSEli Cohen for (i = 0; i < ndev->cur_num_vqs; i++) { 3164cae15c2eSEli Cohen mvq = &ndev->vqs[i]; 3165cae15c2eSEli Cohen suspend_vq(ndev, mvq); 3166cae15c2eSEli Cohen } 3167cae15c2eSEli Cohen mlx5_vdpa_cvq_suspend(mvdev); 316809e65ee9SSi-Wei Liu mvdev->suspended = true; 3169cae15c2eSEli Cohen up_write(&ndev->reslock); 3170cae15c2eSEli Cohen return 0; 3171cae15c2eSEli Cohen } 3172cae15c2eSEli Cohen 31738fcd20c3SEli Cohen static int mlx5_set_group_asid(struct vdpa_device *vdev, u32 group, 31748fcd20c3SEli Cohen unsigned int asid) 31758fcd20c3SEli Cohen { 31768fcd20c3SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 31778fcd20c3SEli Cohen 31788fcd20c3SEli Cohen if (group >= MLX5_VDPA_NUMVQ_GROUPS) 31798fcd20c3SEli Cohen return -EINVAL; 31808fcd20c3SEli Cohen 31818fcd20c3SEli Cohen mvdev->group2asid[group] = asid; 31828fcd20c3SEli Cohen return 0; 31838fcd20c3SEli Cohen } 31848fcd20c3SEli Cohen 31851a86b377SEli Cohen static const struct vdpa_config_ops mlx5_vdpa_ops = { 31861a86b377SEli Cohen .set_vq_address = mlx5_vdpa_set_vq_address, 31871a86b377SEli Cohen .set_vq_num = mlx5_vdpa_set_vq_num, 31881a86b377SEli Cohen .kick_vq = mlx5_vdpa_kick_vq, 31891a86b377SEli Cohen .set_vq_cb = mlx5_vdpa_set_vq_cb, 31901a86b377SEli Cohen .set_vq_ready = mlx5_vdpa_set_vq_ready, 31911a86b377SEli Cohen .get_vq_ready = mlx5_vdpa_get_vq_ready, 31921a86b377SEli Cohen .set_vq_state = mlx5_vdpa_set_vq_state, 31931a86b377SEli Cohen .get_vq_state = mlx5_vdpa_get_vq_state, 31941892a3d4SEli Cohen .get_vendor_vq_stats = mlx5_vdpa_get_vendor_vq_stats, 31951a86b377SEli Cohen .get_vq_notification = mlx5_get_vq_notification, 31961a86b377SEli Cohen .get_vq_irq = mlx5_get_vq_irq, 31971a86b377SEli Cohen .get_vq_align = mlx5_vdpa_get_vq_align, 3198d4821902SGautam Dawar .get_vq_group = mlx5_vdpa_get_vq_group, 3199a64917bcSEli Cohen .get_device_features = mlx5_vdpa_get_device_features, 3200a64917bcSEli Cohen .set_driver_features = mlx5_vdpa_set_driver_features, 3201a64917bcSEli Cohen .get_driver_features = mlx5_vdpa_get_driver_features, 32021a86b377SEli Cohen .set_config_cb = mlx5_vdpa_set_config_cb, 32031a86b377SEli Cohen .get_vq_num_max = mlx5_vdpa_get_vq_num_max, 32041a86b377SEli Cohen .get_device_id = mlx5_vdpa_get_device_id, 32051a86b377SEli Cohen .get_vendor_id = mlx5_vdpa_get_vendor_id, 32061a86b377SEli Cohen .get_status = mlx5_vdpa_get_status, 32071a86b377SEli Cohen .set_status = mlx5_vdpa_set_status, 32080686082dSXie Yongji .reset = mlx5_vdpa_reset, 3209442706f9SStefano Garzarella .get_config_size = mlx5_vdpa_get_config_size, 32101a86b377SEli Cohen .get_config = mlx5_vdpa_get_config, 32111a86b377SEli Cohen .set_config = mlx5_vdpa_set_config, 32121a86b377SEli Cohen .get_generation = mlx5_vdpa_get_generation, 32131a86b377SEli Cohen .set_map = mlx5_vdpa_set_map, 32148fcd20c3SEli Cohen .set_group_asid = mlx5_set_group_asid, 321536871fb9SJason Wang .get_vq_dma_dev = mlx5_get_vq_dma_dev, 32161a86b377SEli Cohen .free = mlx5_vdpa_free, 3217cae15c2eSEli Cohen .suspend = mlx5_vdpa_suspend, 32181a86b377SEli Cohen }; 32191a86b377SEli Cohen 3220d084d996SSi-Wei Liu static int query_mtu(struct mlx5_core_dev *mdev, u16 *mtu) 3221d084d996SSi-Wei Liu { 3222d084d996SSi-Wei Liu u16 hw_mtu; 3223d084d996SSi-Wei Liu int err; 3224d084d996SSi-Wei Liu 3225d084d996SSi-Wei Liu err = mlx5_query_nic_vport_mtu(mdev, &hw_mtu); 3226d084d996SSi-Wei Liu if (err) 3227d084d996SSi-Wei Liu return err; 3228d084d996SSi-Wei Liu 3229d084d996SSi-Wei Liu *mtu = hw_mtu - MLX5V_ETH_HARD_MTU; 3230d084d996SSi-Wei Liu return 0; 3231d084d996SSi-Wei Liu } 3232d084d996SSi-Wei Liu 32331a86b377SEli Cohen static int alloc_resources(struct mlx5_vdpa_net *ndev) 32341a86b377SEli Cohen { 32351a86b377SEli Cohen struct mlx5_vdpa_net_resources *res = &ndev->res; 32361a86b377SEli Cohen int err; 32371a86b377SEli Cohen 32381a86b377SEli Cohen if (res->valid) { 32391a86b377SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "resources already allocated\n"); 32401a86b377SEli Cohen return -EEXIST; 32411a86b377SEli Cohen } 32421a86b377SEli Cohen 32431a86b377SEli Cohen err = mlx5_vdpa_alloc_transport_domain(&ndev->mvdev, &res->tdn); 32441a86b377SEli Cohen if (err) 32451a86b377SEli Cohen return err; 32461a86b377SEli Cohen 32471a86b377SEli Cohen err = create_tis(ndev); 32481a86b377SEli Cohen if (err) 32491a86b377SEli Cohen goto err_tis; 32501a86b377SEli Cohen 32511a86b377SEli Cohen res->valid = true; 32521a86b377SEli Cohen 32531a86b377SEli Cohen return 0; 32541a86b377SEli Cohen 32551a86b377SEli Cohen err_tis: 32561a86b377SEli Cohen mlx5_vdpa_dealloc_transport_domain(&ndev->mvdev, res->tdn); 32571a86b377SEli Cohen return err; 32581a86b377SEli Cohen } 32591a86b377SEli Cohen 32601a86b377SEli Cohen static void free_resources(struct mlx5_vdpa_net *ndev) 32611a86b377SEli Cohen { 32621a86b377SEli Cohen struct mlx5_vdpa_net_resources *res = &ndev->res; 32631a86b377SEli Cohen 32641a86b377SEli Cohen if (!res->valid) 32651a86b377SEli Cohen return; 32661a86b377SEli Cohen 32671a86b377SEli Cohen destroy_tis(ndev); 32681a86b377SEli Cohen mlx5_vdpa_dealloc_transport_domain(&ndev->mvdev, res->tdn); 32691a86b377SEli Cohen res->valid = false; 32701a86b377SEli Cohen } 32711a86b377SEli Cohen 32721a86b377SEli Cohen static void init_mvqs(struct mlx5_vdpa_net *ndev) 32731a86b377SEli Cohen { 32741a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq; 32751a86b377SEli Cohen int i; 32761a86b377SEli Cohen 3277acde3929SEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; ++i) { 32781a86b377SEli Cohen mvq = &ndev->vqs[i]; 32791a86b377SEli Cohen memset(mvq, 0, offsetof(struct mlx5_vdpa_virtqueue, ri)); 32801a86b377SEli Cohen mvq->index = i; 32811a86b377SEli Cohen mvq->ndev = ndev; 32821a86b377SEli Cohen mvq->fwqp.fw = true; 3283cae15c2eSEli Cohen mvq->fw_state = MLX5_VIRTIO_NET_Q_OBJECT_NONE; 32841a86b377SEli Cohen } 32851a86b377SEli Cohen for (; i < ndev->mvdev.max_vqs; i++) { 32861a86b377SEli Cohen mvq = &ndev->vqs[i]; 32871a86b377SEli Cohen memset(mvq, 0, offsetof(struct mlx5_vdpa_virtqueue, ri)); 32881a86b377SEli Cohen mvq->index = i; 32891a86b377SEli Cohen mvq->ndev = ndev; 32901a86b377SEli Cohen } 32911a86b377SEli Cohen } 32921a86b377SEli Cohen 329358926c8aSEli Cohen struct mlx5_vdpa_mgmtdev { 329458926c8aSEli Cohen struct vdpa_mgmt_dev mgtdev; 329558926c8aSEli Cohen struct mlx5_adev *madev; 329658926c8aSEli Cohen struct mlx5_vdpa_net *ndev; 329758926c8aSEli Cohen }; 329858926c8aSEli Cohen 32991e00e821SEli Cohen static int config_func_mtu(struct mlx5_core_dev *mdev, u16 mtu) 33001e00e821SEli Cohen { 33011e00e821SEli Cohen int inlen = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in); 33021e00e821SEli Cohen void *in; 33031e00e821SEli Cohen int err; 33041e00e821SEli Cohen 33051e00e821SEli Cohen in = kvzalloc(inlen, GFP_KERNEL); 33061e00e821SEli Cohen if (!in) 33071e00e821SEli Cohen return -ENOMEM; 33081e00e821SEli Cohen 33091e00e821SEli Cohen MLX5_SET(modify_nic_vport_context_in, in, field_select.mtu, 1); 33101e00e821SEli Cohen MLX5_SET(modify_nic_vport_context_in, in, nic_vport_context.mtu, 33111e00e821SEli Cohen mtu + MLX5V_ETH_HARD_MTU); 33121e00e821SEli Cohen MLX5_SET(modify_nic_vport_context_in, in, opcode, 33131e00e821SEli Cohen MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT); 33141e00e821SEli Cohen 33151e00e821SEli Cohen err = mlx5_cmd_exec_in(mdev, modify_nic_vport_context, in); 33161e00e821SEli Cohen 33171e00e821SEli Cohen kvfree(in); 33181e00e821SEli Cohen return err; 33191e00e821SEli Cohen } 33201e00e821SEli Cohen 3321bc9a2b3eSEli Cohen static void allocate_irqs(struct mlx5_vdpa_net *ndev) 3322bc9a2b3eSEli Cohen { 3323bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool_entry *ent; 3324bc9a2b3eSEli Cohen int i; 3325bc9a2b3eSEli Cohen 3326bc9a2b3eSEli Cohen if (!msix_mode_supported(&ndev->mvdev)) 3327bc9a2b3eSEli Cohen return; 3328bc9a2b3eSEli Cohen 3329bc9a2b3eSEli Cohen if (!ndev->mvdev.mdev->pdev) 3330bc9a2b3eSEli Cohen return; 3331bc9a2b3eSEli Cohen 3332bc9a2b3eSEli Cohen ndev->irqp.entries = kcalloc(ndev->mvdev.max_vqs, sizeof(*ndev->irqp.entries), GFP_KERNEL); 3333bc9a2b3eSEli Cohen if (!ndev->irqp.entries) 3334bc9a2b3eSEli Cohen return; 3335bc9a2b3eSEli Cohen 3336bc9a2b3eSEli Cohen 3337bc9a2b3eSEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) { 3338bc9a2b3eSEli Cohen ent = ndev->irqp.entries + i; 3339bc9a2b3eSEli Cohen snprintf(ent->name, MLX5_VDPA_IRQ_NAME_LEN, "%s-vq-%d", 3340bc9a2b3eSEli Cohen dev_name(&ndev->mvdev.vdev.dev), i); 3341bc9a2b3eSEli Cohen ent->map = pci_msix_alloc_irq_at(ndev->mvdev.mdev->pdev, MSI_ANY_INDEX, NULL); 3342bc9a2b3eSEli Cohen if (!ent->map.virq) 3343bc9a2b3eSEli Cohen return; 3344bc9a2b3eSEli Cohen 3345bc9a2b3eSEli Cohen ndev->irqp.num_ent++; 3346bc9a2b3eSEli Cohen } 3347bc9a2b3eSEli Cohen } 3348bc9a2b3eSEli Cohen 3349d8ca2fa5SParav Pandit static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, 3350d8ca2fa5SParav Pandit const struct vdpa_dev_set_config *add_config) 33511a86b377SEli Cohen { 335258926c8aSEli Cohen struct mlx5_vdpa_mgmtdev *mgtdev = container_of(v_mdev, struct mlx5_vdpa_mgmtdev, mgtdev); 33531a86b377SEli Cohen struct virtio_net_config *config; 33547c9f131fSEli Cohen struct mlx5_core_dev *pfmdev; 33551a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev; 33561a86b377SEli Cohen struct mlx5_vdpa_net *ndev; 335758926c8aSEli Cohen struct mlx5_core_dev *mdev; 3358deeacf35SSi-Wei Liu u64 device_features; 33591a86b377SEli Cohen u32 max_vqs; 3360246fd1caSEli Cohen u16 mtu; 33611a86b377SEli Cohen int err; 33621a86b377SEli Cohen 336358926c8aSEli Cohen if (mgtdev->ndev) 336458926c8aSEli Cohen return -ENOSPC; 336558926c8aSEli Cohen 336658926c8aSEli Cohen mdev = mgtdev->madev->mdev; 3367deeacf35SSi-Wei Liu device_features = mgtdev->mgtdev.supported_features; 3368deeacf35SSi-Wei Liu if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) { 3369deeacf35SSi-Wei Liu if (add_config->device_features & ~device_features) { 3370deeacf35SSi-Wei Liu dev_warn(mdev->device, 3371deeacf35SSi-Wei Liu "The provisioned features 0x%llx are not supported by this device with features 0x%llx\n", 3372deeacf35SSi-Wei Liu add_config->device_features, device_features); 3373deeacf35SSi-Wei Liu return -EINVAL; 3374deeacf35SSi-Wei Liu } 3375deeacf35SSi-Wei Liu device_features &= add_config->device_features; 3376791a1cb7SEli Cohen } else { 3377791a1cb7SEli Cohen device_features &= ~BIT_ULL(VIRTIO_NET_F_MRG_RXBUF); 3378deeacf35SSi-Wei Liu } 3379deeacf35SSi-Wei Liu if (!(device_features & BIT_ULL(VIRTIO_F_VERSION_1) && 3380deeacf35SSi-Wei Liu device_features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM))) { 3381deeacf35SSi-Wei Liu dev_warn(mdev->device, 3382deeacf35SSi-Wei Liu "Must provision minimum features 0x%llx for this device", 3383deeacf35SSi-Wei Liu BIT_ULL(VIRTIO_F_VERSION_1) | BIT_ULL(VIRTIO_F_ACCESS_PLATFORM)); 3384deeacf35SSi-Wei Liu return -EOPNOTSUPP; 3385deeacf35SSi-Wei Liu } 3386deeacf35SSi-Wei Liu 3387879753c8SEli Cohen if (!(MLX5_CAP_DEV_VDPA_EMULATION(mdev, virtio_queue_type) & 3388879753c8SEli Cohen MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_SPLIT)) { 3389879753c8SEli Cohen dev_warn(mdev->device, "missing support for split virtqueues\n"); 3390879753c8SEli Cohen return -EOPNOTSUPP; 3391879753c8SEli Cohen } 3392879753c8SEli Cohen 3393acde3929SEli Cohen max_vqs = min_t(int, MLX5_CAP_DEV_VDPA_EMULATION(mdev, max_num_virtio_queues), 3394acde3929SEli Cohen 1 << MLX5_CAP_GEN(mdev, log_max_rqt_size)); 339575560522SEli Cohen if (max_vqs < 2) { 339675560522SEli Cohen dev_warn(mdev->device, 339775560522SEli Cohen "%d virtqueues are supported. At least 2 are required\n", 339875560522SEli Cohen max_vqs); 339975560522SEli Cohen return -EAGAIN; 340075560522SEli Cohen } 340175560522SEli Cohen 340275560522SEli Cohen if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP)) { 340375560522SEli Cohen if (add_config->net.max_vq_pairs > max_vqs / 2) 340475560522SEli Cohen return -EINVAL; 340575560522SEli Cohen max_vqs = min_t(u32, max_vqs, 2 * add_config->net.max_vq_pairs); 340675560522SEli Cohen } else { 340775560522SEli Cohen max_vqs = 2; 340875560522SEli Cohen } 34091a86b377SEli Cohen 34101a86b377SEli Cohen ndev = vdpa_alloc_device(struct mlx5_vdpa_net, mvdev.vdev, mdev->device, &mlx5_vdpa_ops, 34118fcd20c3SEli Cohen MLX5_VDPA_NUMVQ_GROUPS, MLX5_VDPA_NUM_AS, name, false); 34121a86b377SEli Cohen if (IS_ERR(ndev)) 341374c9729dSLeon Romanovsky return PTR_ERR(ndev); 34141a86b377SEli Cohen 34151a86b377SEli Cohen ndev->mvdev.max_vqs = max_vqs; 34161a86b377SEli Cohen mvdev = &ndev->mvdev; 34171a86b377SEli Cohen mvdev->mdev = mdev; 341875560522SEli Cohen 341975560522SEli Cohen ndev->vqs = kcalloc(max_vqs, sizeof(*ndev->vqs), GFP_KERNEL); 342075560522SEli Cohen ndev->event_cbs = kcalloc(max_vqs + 1, sizeof(*ndev->event_cbs), GFP_KERNEL); 342175560522SEli Cohen if (!ndev->vqs || !ndev->event_cbs) { 342275560522SEli Cohen err = -ENOMEM; 342375560522SEli Cohen goto err_alloc; 342475560522SEli Cohen } 342575560522SEli Cohen 34261a86b377SEli Cohen init_mvqs(ndev); 3427bc9a2b3eSEli Cohen allocate_irqs(ndev); 3428759ae7f9SEli Cohen init_rwsem(&ndev->reslock); 34291a86b377SEli Cohen config = &ndev->config; 34301e00e821SEli Cohen 34311e00e821SEli Cohen if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MTU)) { 34321e00e821SEli Cohen err = config_func_mtu(mdev, add_config->net.mtu); 34331e00e821SEli Cohen if (err) 3434759ae7f9SEli Cohen goto err_alloc; 34351e00e821SEli Cohen } 34361e00e821SEli Cohen 3437deeacf35SSi-Wei Liu if (device_features & BIT_ULL(VIRTIO_NET_F_MTU)) { 3438246fd1caSEli Cohen err = query_mtu(mdev, &mtu); 34391a86b377SEli Cohen if (err) 3440759ae7f9SEli Cohen goto err_alloc; 34411a86b377SEli Cohen 3442246fd1caSEli Cohen ndev->config.mtu = cpu_to_mlx5vdpa16(mvdev, mtu); 3443033779a7SSi-Wei Liu } 34441a86b377SEli Cohen 3445deeacf35SSi-Wei Liu if (device_features & BIT_ULL(VIRTIO_NET_F_STATUS)) { 3446edf747afSEli Cohen if (get_link_state(mvdev)) 3447edf747afSEli Cohen ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP); 3448edf747afSEli Cohen else 3449edf747afSEli Cohen ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP); 3450033779a7SSi-Wei Liu } 3451edf747afSEli Cohen 3452a007d940SEli Cohen if (add_config->mask & (1 << VDPA_ATTR_DEV_NET_CFG_MACADDR)) { 3453a007d940SEli Cohen memcpy(ndev->config.mac, add_config->net.mac, ETH_ALEN); 3454deeacf35SSi-Wei Liu /* No bother setting mac address in config if not going to provision _F_MAC */ 3455deeacf35SSi-Wei Liu } else if ((add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) == 0 || 3456deeacf35SSi-Wei Liu device_features & BIT_ULL(VIRTIO_NET_F_MAC)) { 34571a86b377SEli Cohen err = mlx5_query_nic_vport_mac_address(mdev, 0, 0, config->mac); 34581a86b377SEli Cohen if (err) 3459759ae7f9SEli Cohen goto err_alloc; 3460a007d940SEli Cohen } 34611a86b377SEli Cohen 34627c9f131fSEli Cohen if (!is_zero_ether_addr(config->mac)) { 34637c9f131fSEli Cohen pfmdev = pci_get_drvdata(pci_physfn(mdev->pdev)); 34647c9f131fSEli Cohen err = mlx5_mpfs_add_mac(pfmdev, config->mac); 34657c9f131fSEli Cohen if (err) 3466759ae7f9SEli Cohen goto err_alloc; 3467deeacf35SSi-Wei Liu } else if ((add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) == 0) { 3468deeacf35SSi-Wei Liu /* 3469deeacf35SSi-Wei Liu * We used to clear _F_MAC feature bit if seeing 3470deeacf35SSi-Wei Liu * zero mac address when device features are not 3471deeacf35SSi-Wei Liu * specifically provisioned. Keep the behaviour 3472deeacf35SSi-Wei Liu * so old scripts do not break. 3473deeacf35SSi-Wei Liu */ 3474deeacf35SSi-Wei Liu device_features &= ~BIT_ULL(VIRTIO_NET_F_MAC); 3475deeacf35SSi-Wei Liu } else if (device_features & BIT_ULL(VIRTIO_NET_F_MAC)) { 3476deeacf35SSi-Wei Liu /* Don't provision zero mac address for _F_MAC */ 3477deeacf35SSi-Wei Liu mlx5_vdpa_warn(&ndev->mvdev, 3478deeacf35SSi-Wei Liu "No mac address provisioned?\n"); 3479deeacf35SSi-Wei Liu err = -EINVAL; 3480deeacf35SSi-Wei Liu goto err_alloc; 34817c9f131fSEli Cohen } 34827c9f131fSEli Cohen 3483deeacf35SSi-Wei Liu if (device_features & BIT_ULL(VIRTIO_NET_F_MQ)) 3484acde3929SEli Cohen config->max_virtqueue_pairs = cpu_to_mlx5vdpa16(mvdev, max_vqs / 2); 3485deeacf35SSi-Wei Liu 3486deeacf35SSi-Wei Liu ndev->mvdev.mlx_features = device_features; 34877d23dcdfSEli Cohen mvdev->vdev.dma_dev = &mdev->pdev->dev; 34881a86b377SEli Cohen err = mlx5_vdpa_alloc_resources(&ndev->mvdev); 34891a86b377SEli Cohen if (err) 34907c9f131fSEli Cohen goto err_mpfs; 34911a86b377SEli Cohen 34926f5312f8SEli Cohen if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) { 349338fc462fSEli Cohen err = mlx5_vdpa_create_mr(mvdev, NULL, 0); 34941a86b377SEli Cohen if (err) 34951a86b377SEli Cohen goto err_res; 34966f5312f8SEli Cohen } 34976f5312f8SEli Cohen 34986f5312f8SEli Cohen err = alloc_resources(ndev); 34996f5312f8SEli Cohen if (err) 35006f5312f8SEli Cohen goto err_mr; 35011a86b377SEli Cohen 350255ebf0d6SJason Wang ndev->cvq_ent.mvdev = mvdev; 350355ebf0d6SJason Wang INIT_WORK(&ndev->cvq_ent.work, mlx5_cvq_kick_handler); 3504218bdd20SEli Cohen mvdev->wq = create_singlethread_workqueue("mlx5_vdpa_wq"); 35055262912eSEli Cohen if (!mvdev->wq) { 35065262912eSEli Cohen err = -ENOMEM; 35075262912eSEli Cohen goto err_res2; 35085262912eSEli Cohen } 35095262912eSEli Cohen 351058926c8aSEli Cohen mvdev->vdev.mdev = &mgtdev->mgtdev; 3511acde3929SEli Cohen err = _vdpa_register_device(&mvdev->vdev, max_vqs + 1); 35121a86b377SEli Cohen if (err) 35131a86b377SEli Cohen goto err_reg; 35141a86b377SEli Cohen 351558926c8aSEli Cohen mgtdev->ndev = ndev; 351674c9729dSLeon Romanovsky return 0; 35171a86b377SEli Cohen 35181a86b377SEli Cohen err_reg: 35195262912eSEli Cohen destroy_workqueue(mvdev->wq); 35205262912eSEli Cohen err_res2: 35211a86b377SEli Cohen free_resources(ndev); 35226f5312f8SEli Cohen err_mr: 35236f5312f8SEli Cohen mlx5_vdpa_destroy_mr(mvdev); 35241a86b377SEli Cohen err_res: 35251a86b377SEli Cohen mlx5_vdpa_free_resources(&ndev->mvdev); 35267c9f131fSEli Cohen err_mpfs: 35277c9f131fSEli Cohen if (!is_zero_ether_addr(config->mac)) 35287c9f131fSEli Cohen mlx5_mpfs_del_mac(pfmdev, config->mac); 352975560522SEli Cohen err_alloc: 35301a86b377SEli Cohen put_device(&mvdev->vdev.dev); 353174c9729dSLeon Romanovsky return err; 35321a86b377SEli Cohen } 35331a86b377SEli Cohen 353458926c8aSEli Cohen static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device *dev) 353558926c8aSEli Cohen { 353658926c8aSEli Cohen struct mlx5_vdpa_mgmtdev *mgtdev = container_of(v_mdev, struct mlx5_vdpa_mgmtdev, mgtdev); 35375262912eSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(dev); 3538edf747afSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 3539ad6dc1daSEli Cohen struct workqueue_struct *wq; 354058926c8aSEli Cohen 3541c384c240SEli Cohen unregister_link_notifier(ndev); 354273790bdfSDragos Tatulea _vdpa_unregister_device(dev); 3543ad6dc1daSEli Cohen wq = mvdev->wq; 3544ad6dc1daSEli Cohen mvdev->wq = NULL; 3545ad6dc1daSEli Cohen destroy_workqueue(wq); 354658926c8aSEli Cohen mgtdev->ndev = NULL; 354758926c8aSEli Cohen } 354858926c8aSEli Cohen 354958926c8aSEli Cohen static const struct vdpa_mgmtdev_ops mdev_ops = { 355058926c8aSEli Cohen .dev_add = mlx5_vdpa_dev_add, 355158926c8aSEli Cohen .dev_del = mlx5_vdpa_dev_del, 355258926c8aSEli Cohen }; 355358926c8aSEli Cohen 355458926c8aSEli Cohen static struct virtio_device_id id_table[] = { 355558926c8aSEli Cohen { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID }, 355658926c8aSEli Cohen { 0 }, 355758926c8aSEli Cohen }; 355858926c8aSEli Cohen 355958926c8aSEli Cohen static int mlx5v_probe(struct auxiliary_device *adev, 356058926c8aSEli Cohen const struct auxiliary_device_id *id) 356158926c8aSEli Cohen 356258926c8aSEli Cohen { 356358926c8aSEli Cohen struct mlx5_adev *madev = container_of(adev, struct mlx5_adev, adev); 356458926c8aSEli Cohen struct mlx5_core_dev *mdev = madev->mdev; 356558926c8aSEli Cohen struct mlx5_vdpa_mgmtdev *mgtdev; 356658926c8aSEli Cohen int err; 356758926c8aSEli Cohen 356858926c8aSEli Cohen mgtdev = kzalloc(sizeof(*mgtdev), GFP_KERNEL); 356958926c8aSEli Cohen if (!mgtdev) 357058926c8aSEli Cohen return -ENOMEM; 357158926c8aSEli Cohen 357258926c8aSEli Cohen mgtdev->mgtdev.ops = &mdev_ops; 357358926c8aSEli Cohen mgtdev->mgtdev.device = mdev->device; 357458926c8aSEli Cohen mgtdev->mgtdev.id_table = id_table; 357575560522SEli Cohen mgtdev->mgtdev.config_attr_mask = BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR) | 35761e00e821SEli Cohen BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP) | 3577deeacf35SSi-Wei Liu BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MTU) | 3578deeacf35SSi-Wei Liu BIT_ULL(VDPA_ATTR_DEV_FEATURES); 357979de65edSEli Cohen mgtdev->mgtdev.max_supported_vqs = 358079de65edSEli Cohen MLX5_CAP_DEV_VDPA_EMULATION(mdev, max_num_virtio_queues) + 1; 358179de65edSEli Cohen mgtdev->mgtdev.supported_features = get_supported_features(mdev); 358258926c8aSEli Cohen mgtdev->madev = madev; 358358926c8aSEli Cohen 358458926c8aSEli Cohen err = vdpa_mgmtdev_register(&mgtdev->mgtdev); 358558926c8aSEli Cohen if (err) 358658926c8aSEli Cohen goto reg_err; 358758926c8aSEli Cohen 358845e3a279SDavid E. Box auxiliary_set_drvdata(adev, mgtdev); 358958926c8aSEli Cohen 359058926c8aSEli Cohen return 0; 359158926c8aSEli Cohen 359258926c8aSEli Cohen reg_err: 359358926c8aSEli Cohen kfree(mgtdev); 359458926c8aSEli Cohen return err; 359558926c8aSEli Cohen } 359658926c8aSEli Cohen 359774c9729dSLeon Romanovsky static void mlx5v_remove(struct auxiliary_device *adev) 35981a86b377SEli Cohen { 359958926c8aSEli Cohen struct mlx5_vdpa_mgmtdev *mgtdev; 360074c9729dSLeon Romanovsky 360145e3a279SDavid E. Box mgtdev = auxiliary_get_drvdata(adev); 360258926c8aSEli Cohen vdpa_mgmtdev_unregister(&mgtdev->mgtdev); 360358926c8aSEli Cohen kfree(mgtdev); 36041a86b377SEli Cohen } 360574c9729dSLeon Romanovsky 360674c9729dSLeon Romanovsky static const struct auxiliary_device_id mlx5v_id_table[] = { 360774c9729dSLeon Romanovsky { .name = MLX5_ADEV_NAME ".vnet", }, 360874c9729dSLeon Romanovsky {}, 360974c9729dSLeon Romanovsky }; 361074c9729dSLeon Romanovsky 361174c9729dSLeon Romanovsky MODULE_DEVICE_TABLE(auxiliary, mlx5v_id_table); 361274c9729dSLeon Romanovsky 361374c9729dSLeon Romanovsky static struct auxiliary_driver mlx5v_driver = { 361474c9729dSLeon Romanovsky .name = "vnet", 361574c9729dSLeon Romanovsky .probe = mlx5v_probe, 361674c9729dSLeon Romanovsky .remove = mlx5v_remove, 361774c9729dSLeon Romanovsky .id_table = mlx5v_id_table, 361874c9729dSLeon Romanovsky }; 361974c9729dSLeon Romanovsky 362074c9729dSLeon Romanovsky module_auxiliary_driver(mlx5v_driver); 3621