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; 86*bc9a2b3eSEli 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; 122*bc9a2b3eSEli 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 */ 583563476aeSShay Drory err = mlx5_vector2eqn(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 62871ab6a7cSEli Cohen static void set_umem_size(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int num, 6291a86b377SEli Cohen struct mlx5_vdpa_umem **umemp) 6301a86b377SEli Cohen { 6311a86b377SEli Cohen struct mlx5_core_dev *mdev = ndev->mvdev.mdev; 6321a86b377SEli Cohen int p_a; 6331a86b377SEli Cohen int p_b; 6341a86b377SEli Cohen 6351a86b377SEli Cohen switch (num) { 6361a86b377SEli Cohen case 1: 6371a86b377SEli Cohen p_a = MLX5_CAP_DEV_VDPA_EMULATION(mdev, umem_1_buffer_param_a); 6381a86b377SEli Cohen p_b = MLX5_CAP_DEV_VDPA_EMULATION(mdev, umem_1_buffer_param_b); 6391a86b377SEli Cohen *umemp = &mvq->umem1; 6401a86b377SEli Cohen break; 6411a86b377SEli Cohen case 2: 6421a86b377SEli Cohen p_a = MLX5_CAP_DEV_VDPA_EMULATION(mdev, umem_2_buffer_param_a); 6431a86b377SEli Cohen p_b = MLX5_CAP_DEV_VDPA_EMULATION(mdev, umem_2_buffer_param_b); 6441a86b377SEli Cohen *umemp = &mvq->umem2; 6451a86b377SEli Cohen break; 6461a86b377SEli Cohen case 3: 6471a86b377SEli Cohen p_a = MLX5_CAP_DEV_VDPA_EMULATION(mdev, umem_3_buffer_param_a); 6481a86b377SEli Cohen p_b = MLX5_CAP_DEV_VDPA_EMULATION(mdev, umem_3_buffer_param_b); 6491a86b377SEli Cohen *umemp = &mvq->umem3; 6501a86b377SEli Cohen break; 6511a86b377SEli Cohen } 65271ab6a7cSEli Cohen (*umemp)->size = p_a * mvq->num_ent + p_b; 6531a86b377SEli Cohen } 6541a86b377SEli Cohen 6551a86b377SEli Cohen static void umem_frag_buf_free(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_umem *umem) 6561a86b377SEli Cohen { 6571a86b377SEli Cohen mlx5_frag_buf_free(ndev->mvdev.mdev, &umem->frag_buf); 6581a86b377SEli Cohen } 6591a86b377SEli Cohen 6601a86b377SEli Cohen static int create_umem(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int num) 6611a86b377SEli Cohen { 6621a86b377SEli Cohen int inlen; 6631a86b377SEli Cohen u32 out[MLX5_ST_SZ_DW(create_umem_out)] = {}; 6641a86b377SEli Cohen void *um; 6651a86b377SEli Cohen void *in; 6661a86b377SEli Cohen int err; 6671a86b377SEli Cohen __be64 *pas; 6681a86b377SEli Cohen struct mlx5_vdpa_umem *umem; 6691a86b377SEli Cohen 67071ab6a7cSEli Cohen set_umem_size(ndev, mvq, num, &umem); 67171ab6a7cSEli Cohen err = umem_frag_buf_alloc(ndev, umem, umem->size); 6721a86b377SEli Cohen if (err) 6731a86b377SEli Cohen return err; 6741a86b377SEli Cohen 6751a86b377SEli Cohen inlen = MLX5_ST_SZ_BYTES(create_umem_in) + MLX5_ST_SZ_BYTES(mtt) * umem->frag_buf.npages; 6761a86b377SEli Cohen 6771a86b377SEli Cohen in = kzalloc(inlen, GFP_KERNEL); 6781a86b377SEli Cohen if (!in) { 6791a86b377SEli Cohen err = -ENOMEM; 6801a86b377SEli Cohen goto err_in; 6811a86b377SEli Cohen } 6821a86b377SEli Cohen 6831a86b377SEli Cohen MLX5_SET(create_umem_in, in, opcode, MLX5_CMD_OP_CREATE_UMEM); 6841a86b377SEli Cohen MLX5_SET(create_umem_in, in, uid, ndev->mvdev.res.uid); 6851a86b377SEli Cohen um = MLX5_ADDR_OF(create_umem_in, in, umem); 6861a86b377SEli Cohen MLX5_SET(umem, um, log_page_size, umem->frag_buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); 6871a86b377SEli Cohen MLX5_SET64(umem, um, num_of_mtt, umem->frag_buf.npages); 6881a86b377SEli Cohen 6891a86b377SEli Cohen pas = (__be64 *)MLX5_ADDR_OF(umem, um, mtt[0]); 6901a86b377SEli Cohen mlx5_fill_page_frag_array_perm(&umem->frag_buf, pas, MLX5_MTT_PERM_RW); 6911a86b377SEli Cohen 6921a86b377SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, inlen, out, sizeof(out)); 6931a86b377SEli Cohen if (err) { 6941a86b377SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "create umem(%d)\n", err); 6951a86b377SEli Cohen goto err_cmd; 6961a86b377SEli Cohen } 6971a86b377SEli Cohen 6981a86b377SEli Cohen kfree(in); 6991a86b377SEli Cohen umem->id = MLX5_GET(create_umem_out, out, umem_id); 7001a86b377SEli Cohen 7011a86b377SEli Cohen return 0; 7021a86b377SEli Cohen 7031a86b377SEli Cohen err_cmd: 7041a86b377SEli Cohen kfree(in); 7051a86b377SEli Cohen err_in: 7061a86b377SEli Cohen umem_frag_buf_free(ndev, umem); 7071a86b377SEli Cohen return err; 7081a86b377SEli Cohen } 7091a86b377SEli Cohen 7101a86b377SEli Cohen static void umem_destroy(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int num) 7111a86b377SEli Cohen { 7121a86b377SEli Cohen u32 in[MLX5_ST_SZ_DW(destroy_umem_in)] = {}; 7131a86b377SEli Cohen u32 out[MLX5_ST_SZ_DW(destroy_umem_out)] = {}; 7141a86b377SEli Cohen struct mlx5_vdpa_umem *umem; 7151a86b377SEli Cohen 7161a86b377SEli Cohen switch (num) { 7171a86b377SEli Cohen case 1: 7181a86b377SEli Cohen umem = &mvq->umem1; 7191a86b377SEli Cohen break; 7201a86b377SEli Cohen case 2: 7211a86b377SEli Cohen umem = &mvq->umem2; 7221a86b377SEli Cohen break; 7231a86b377SEli Cohen case 3: 7241a86b377SEli Cohen umem = &mvq->umem3; 7251a86b377SEli Cohen break; 7261a86b377SEli Cohen } 7271a86b377SEli Cohen 7281a86b377SEli Cohen MLX5_SET(destroy_umem_in, in, opcode, MLX5_CMD_OP_DESTROY_UMEM); 7291a86b377SEli Cohen MLX5_SET(destroy_umem_in, in, umem_id, umem->id); 7301a86b377SEli Cohen if (mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out))) 7311a86b377SEli Cohen return; 7321a86b377SEli Cohen 7331a86b377SEli Cohen umem_frag_buf_free(ndev, umem); 7341a86b377SEli Cohen } 7351a86b377SEli Cohen 7361a86b377SEli Cohen static int umems_create(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 7371a86b377SEli Cohen { 7381a86b377SEli Cohen int num; 7391a86b377SEli Cohen int err; 7401a86b377SEli Cohen 7411a86b377SEli Cohen for (num = 1; num <= 3; num++) { 7421a86b377SEli Cohen err = create_umem(ndev, mvq, num); 7431a86b377SEli Cohen if (err) 7441a86b377SEli Cohen goto err_umem; 7451a86b377SEli Cohen } 7461a86b377SEli Cohen return 0; 7471a86b377SEli Cohen 7481a86b377SEli Cohen err_umem: 7491a86b377SEli Cohen for (num--; num > 0; num--) 7501a86b377SEli Cohen umem_destroy(ndev, mvq, num); 7511a86b377SEli Cohen 7521a86b377SEli Cohen return err; 7531a86b377SEli Cohen } 7541a86b377SEli Cohen 7551a86b377SEli Cohen static void umems_destroy(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 7561a86b377SEli Cohen { 7571a86b377SEli Cohen int num; 7581a86b377SEli Cohen 7591a86b377SEli Cohen for (num = 3; num > 0; num--) 7601a86b377SEli Cohen umem_destroy(ndev, mvq, num); 7611a86b377SEli Cohen } 7621a86b377SEli Cohen 7631a86b377SEli Cohen static int get_queue_type(struct mlx5_vdpa_net *ndev) 7641a86b377SEli Cohen { 7651a86b377SEli Cohen u32 type_mask; 7661a86b377SEli Cohen 7671a86b377SEli Cohen type_mask = MLX5_CAP_DEV_VDPA_EMULATION(ndev->mvdev.mdev, virtio_queue_type); 7681a86b377SEli Cohen 7691a86b377SEli Cohen /* prefer split queue */ 770879753c8SEli Cohen if (type_mask & MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_SPLIT) 7711a86b377SEli Cohen return MLX5_VIRTIO_EMULATION_VIRTIO_QUEUE_TYPE_SPLIT; 772879753c8SEli Cohen 773879753c8SEli Cohen WARN_ON(!(type_mask & MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_PACKED)); 774879753c8SEli Cohen 775879753c8SEli Cohen return MLX5_VIRTIO_EMULATION_VIRTIO_QUEUE_TYPE_PACKED; 7761a86b377SEli Cohen } 7771a86b377SEli Cohen 7781a86b377SEli Cohen static bool vq_is_tx(u16 idx) 7791a86b377SEli Cohen { 7801a86b377SEli Cohen return idx % 2; 7811a86b377SEli Cohen } 7821a86b377SEli Cohen 783e9d67e59SEli Cohen enum { 784e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_MRG_RXBUF = 2, 785e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_HOST_ECN = 4, 786e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_GUEST_ECN = 6, 787e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_GUEST_TSO6 = 7, 788e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_GUEST_TSO4 = 8, 789e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_GUEST_CSUM = 9, 790e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_CSUM = 10, 791e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_HOST_TSO6 = 11, 792e9d67e59SEli Cohen MLX5_VIRTIO_NET_F_HOST_TSO4 = 12, 793e9d67e59SEli Cohen }; 794e9d67e59SEli Cohen 795e9d67e59SEli Cohen static u16 get_features(u64 features) 7961a86b377SEli Cohen { 797e9d67e59SEli Cohen return (!!(features & BIT_ULL(VIRTIO_NET_F_MRG_RXBUF)) << MLX5_VIRTIO_NET_F_MRG_RXBUF) | 798e9d67e59SEli Cohen (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_ECN)) << MLX5_VIRTIO_NET_F_HOST_ECN) | 799e9d67e59SEli Cohen (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_ECN)) << MLX5_VIRTIO_NET_F_GUEST_ECN) | 800e9d67e59SEli Cohen (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_TSO6)) << MLX5_VIRTIO_NET_F_GUEST_TSO6) | 801e9d67e59SEli Cohen (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_TSO4)) << MLX5_VIRTIO_NET_F_GUEST_TSO4) | 802e9d67e59SEli Cohen (!!(features & BIT_ULL(VIRTIO_NET_F_CSUM)) << MLX5_VIRTIO_NET_F_CSUM) | 803e9d67e59SEli Cohen (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO6)) << MLX5_VIRTIO_NET_F_HOST_TSO6) | 804e9d67e59SEli Cohen (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO4)) << MLX5_VIRTIO_NET_F_HOST_TSO4); 8051a86b377SEli Cohen } 8061a86b377SEli Cohen 8071892a3d4SEli Cohen static bool counters_supported(const struct mlx5_vdpa_dev *mvdev) 8081892a3d4SEli Cohen { 8091892a3d4SEli Cohen return MLX5_CAP_GEN_64(mvdev->mdev, general_obj_types) & 8101892a3d4SEli Cohen BIT_ULL(MLX5_OBJ_TYPE_VIRTIO_Q_COUNTERS); 8111892a3d4SEli Cohen } 8121892a3d4SEli Cohen 813*bc9a2b3eSEli Cohen static bool msix_mode_supported(struct mlx5_vdpa_dev *mvdev) 814*bc9a2b3eSEli Cohen { 815*bc9a2b3eSEli Cohen return MLX5_CAP_DEV_VDPA_EMULATION(mvdev->mdev, event_mode) & 816*bc9a2b3eSEli Cohen (1 << MLX5_VIRTIO_Q_EVENT_MODE_MSIX_MODE) && 817*bc9a2b3eSEli Cohen pci_msix_can_alloc_dyn(mvdev->mdev->pdev); 818*bc9a2b3eSEli Cohen } 819*bc9a2b3eSEli Cohen 8201a86b377SEli Cohen static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 8211a86b377SEli Cohen { 8221a86b377SEli Cohen int inlen = MLX5_ST_SZ_BYTES(create_virtio_net_q_in); 8231a86b377SEli Cohen u32 out[MLX5_ST_SZ_DW(create_virtio_net_q_out)] = {}; 8241a86b377SEli Cohen void *obj_context; 825e9d67e59SEli Cohen u16 mlx_features; 8261a86b377SEli Cohen void *cmd_hdr; 8271a86b377SEli Cohen void *vq_ctx; 8281a86b377SEli Cohen void *in; 8291a86b377SEli Cohen int err; 8301a86b377SEli Cohen 8311a86b377SEli Cohen err = umems_create(ndev, mvq); 8321a86b377SEli Cohen if (err) 8331a86b377SEli Cohen return err; 8341a86b377SEli Cohen 8351a86b377SEli Cohen in = kzalloc(inlen, GFP_KERNEL); 8361a86b377SEli Cohen if (!in) { 8371a86b377SEli Cohen err = -ENOMEM; 8381a86b377SEli Cohen goto err_alloc; 8391a86b377SEli Cohen } 8401a86b377SEli Cohen 841e9d67e59SEli Cohen mlx_features = get_features(ndev->mvdev.actual_features); 8421a86b377SEli Cohen cmd_hdr = MLX5_ADDR_OF(create_virtio_net_q_in, in, general_obj_in_cmd_hdr); 8431a86b377SEli Cohen 8441a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); 8451a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_NET_Q); 8461a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 8471a86b377SEli Cohen 8481a86b377SEli Cohen obj_context = MLX5_ADDR_OF(create_virtio_net_q_in, in, obj_context); 8491a86b377SEli Cohen MLX5_SET(virtio_net_q_object, obj_context, hw_available_index, mvq->avail_idx); 850b35ccebeSEli Cohen MLX5_SET(virtio_net_q_object, obj_context, hw_used_index, mvq->used_idx); 8511a86b377SEli Cohen MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_12_3, 852e9d67e59SEli Cohen mlx_features >> 3); 853e9d67e59SEli Cohen MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_2_0, 854e9d67e59SEli Cohen mlx_features & 7); 8551a86b377SEli Cohen vq_ctx = MLX5_ADDR_OF(virtio_net_q_object, obj_context, virtio_q_context); 8561a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, virtio_q_type, get_queue_type(ndev)); 8571a86b377SEli Cohen 8581a86b377SEli Cohen if (vq_is_tx(mvq->index)) 8591a86b377SEli Cohen MLX5_SET(virtio_net_q_object, obj_context, tisn_or_qpn, ndev->res.tisn); 8601a86b377SEli Cohen 861*bc9a2b3eSEli Cohen if (mvq->map.virq) { 862*bc9a2b3eSEli Cohen MLX5_SET(virtio_q, vq_ctx, event_mode, MLX5_VIRTIO_Q_EVENT_MODE_MSIX_MODE); 863*bc9a2b3eSEli Cohen MLX5_SET(virtio_q, vq_ctx, event_qpn_or_msix, mvq->map.index); 864*bc9a2b3eSEli Cohen } else { 8651a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, event_mode, MLX5_VIRTIO_Q_EVENT_MODE_QP_MODE); 8661a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, event_qpn_or_msix, mvq->fwqp.mqp.qpn); 867*bc9a2b3eSEli Cohen } 868*bc9a2b3eSEli Cohen 869*bc9a2b3eSEli Cohen MLX5_SET(virtio_q, vq_ctx, queue_index, mvq->index); 8701a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, queue_size, mvq->num_ent); 8711a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, virtio_version_1_0, 8724b454a82SEli Cohen !!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_F_VERSION_1))); 8731a86b377SEli Cohen MLX5_SET64(virtio_q, vq_ctx, desc_addr, mvq->desc_addr); 8741a86b377SEli Cohen MLX5_SET64(virtio_q, vq_ctx, used_addr, mvq->device_addr); 8751a86b377SEli Cohen MLX5_SET64(virtio_q, vq_ctx, available_addr, mvq->driver_addr); 87683fec3f1SAharon Landau MLX5_SET(virtio_q, vq_ctx, virtio_q_mkey, ndev->mvdev.mr.mkey); 8771a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, umem_1_id, mvq->umem1.id); 8781a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, umem_1_size, mvq->umem1.size); 8791a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, umem_2_id, mvq->umem2.id); 880e3011776SEli Cohen MLX5_SET(virtio_q, vq_ctx, umem_2_size, mvq->umem2.size); 8811a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, umem_3_id, mvq->umem3.id); 882e3011776SEli Cohen MLX5_SET(virtio_q, vq_ctx, umem_3_size, mvq->umem3.size); 8831a86b377SEli Cohen MLX5_SET(virtio_q, vq_ctx, pd, ndev->mvdev.res.pdn); 8841892a3d4SEli Cohen if (counters_supported(&ndev->mvdev)) 8851892a3d4SEli Cohen MLX5_SET(virtio_q, vq_ctx, counter_set_id, mvq->counter_set_id); 8861a86b377SEli Cohen 8871a86b377SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, inlen, out, sizeof(out)); 8881a86b377SEli Cohen if (err) 8891a86b377SEli Cohen goto err_cmd; 8901a86b377SEli Cohen 891cae15c2eSEli Cohen mvq->fw_state = MLX5_VIRTIO_NET_Q_OBJECT_STATE_INIT; 8921a86b377SEli Cohen kfree(in); 8931a86b377SEli Cohen mvq->virtq_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); 8941a86b377SEli Cohen 8951a86b377SEli Cohen return 0; 8961a86b377SEli Cohen 8971a86b377SEli Cohen err_cmd: 8981a86b377SEli Cohen kfree(in); 8991a86b377SEli Cohen err_alloc: 9001a86b377SEli Cohen umems_destroy(ndev, mvq); 9011a86b377SEli Cohen return err; 9021a86b377SEli Cohen } 9031a86b377SEli Cohen 9041a86b377SEli Cohen static void destroy_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 9051a86b377SEli Cohen { 9061a86b377SEli Cohen u32 in[MLX5_ST_SZ_DW(destroy_virtio_net_q_in)] = {}; 9071a86b377SEli Cohen u32 out[MLX5_ST_SZ_DW(destroy_virtio_net_q_out)] = {}; 9081a86b377SEli Cohen 9091a86b377SEli Cohen MLX5_SET(destroy_virtio_net_q_in, in, general_obj_out_cmd_hdr.opcode, 9101a86b377SEli Cohen MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); 9111a86b377SEli Cohen MLX5_SET(destroy_virtio_net_q_in, in, general_obj_out_cmd_hdr.obj_id, mvq->virtq_id); 9121a86b377SEli Cohen MLX5_SET(destroy_virtio_net_q_in, in, general_obj_out_cmd_hdr.uid, ndev->mvdev.res.uid); 9131a86b377SEli Cohen MLX5_SET(destroy_virtio_net_q_in, in, general_obj_out_cmd_hdr.obj_type, 9141a86b377SEli Cohen MLX5_OBJ_TYPE_VIRTIO_NET_Q); 9151a86b377SEli Cohen if (mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out))) { 9161a86b377SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "destroy virtqueue 0x%x\n", mvq->virtq_id); 9171a86b377SEli Cohen return; 9181a86b377SEli Cohen } 919cae15c2eSEli Cohen mvq->fw_state = MLX5_VIRTIO_NET_Q_OBJECT_NONE; 9201a86b377SEli Cohen umems_destroy(ndev, mvq); 9211a86b377SEli Cohen } 9221a86b377SEli Cohen 9231a86b377SEli Cohen static u32 get_rqpn(struct mlx5_vdpa_virtqueue *mvq, bool fw) 9241a86b377SEli Cohen { 9251a86b377SEli Cohen return fw ? mvq->vqqp.mqp.qpn : mvq->fwqp.mqp.qpn; 9261a86b377SEli Cohen } 9271a86b377SEli Cohen 9281a86b377SEli Cohen static u32 get_qpn(struct mlx5_vdpa_virtqueue *mvq, bool fw) 9291a86b377SEli Cohen { 9301a86b377SEli Cohen return fw ? mvq->fwqp.mqp.qpn : mvq->vqqp.mqp.qpn; 9311a86b377SEli Cohen } 9321a86b377SEli Cohen 9331a86b377SEli Cohen static void alloc_inout(struct mlx5_vdpa_net *ndev, int cmd, void **in, int *inlen, void **out, 9341a86b377SEli Cohen int *outlen, u32 qpn, u32 rqpn) 9351a86b377SEli Cohen { 9361a86b377SEli Cohen void *qpc; 9371a86b377SEli Cohen void *pp; 9381a86b377SEli Cohen 9391a86b377SEli Cohen switch (cmd) { 9401a86b377SEli Cohen case MLX5_CMD_OP_2RST_QP: 9411a86b377SEli Cohen *inlen = MLX5_ST_SZ_BYTES(qp_2rst_in); 9421a86b377SEli Cohen *outlen = MLX5_ST_SZ_BYTES(qp_2rst_out); 9431a86b377SEli Cohen *in = kzalloc(*inlen, GFP_KERNEL); 9441a86b377SEli Cohen *out = kzalloc(*outlen, GFP_KERNEL); 945f31231bfSColin Ian King if (!*in || !*out) 9461a86b377SEli Cohen goto outerr; 9471a86b377SEli Cohen 9481a86b377SEli Cohen MLX5_SET(qp_2rst_in, *in, opcode, cmd); 9491a86b377SEli Cohen MLX5_SET(qp_2rst_in, *in, uid, ndev->mvdev.res.uid); 9501a86b377SEli Cohen MLX5_SET(qp_2rst_in, *in, qpn, qpn); 9511a86b377SEli Cohen break; 9521a86b377SEli Cohen case MLX5_CMD_OP_RST2INIT_QP: 9531a86b377SEli Cohen *inlen = MLX5_ST_SZ_BYTES(rst2init_qp_in); 9541a86b377SEli Cohen *outlen = MLX5_ST_SZ_BYTES(rst2init_qp_out); 9551a86b377SEli Cohen *in = kzalloc(*inlen, GFP_KERNEL); 9561a86b377SEli Cohen *out = kzalloc(MLX5_ST_SZ_BYTES(rst2init_qp_out), GFP_KERNEL); 957f31231bfSColin Ian King if (!*in || !*out) 9581a86b377SEli Cohen goto outerr; 9591a86b377SEli Cohen 9601a86b377SEli Cohen MLX5_SET(rst2init_qp_in, *in, opcode, cmd); 9611a86b377SEli Cohen MLX5_SET(rst2init_qp_in, *in, uid, ndev->mvdev.res.uid); 9621a86b377SEli Cohen MLX5_SET(rst2init_qp_in, *in, qpn, qpn); 9631a86b377SEli Cohen qpc = MLX5_ADDR_OF(rst2init_qp_in, *in, qpc); 9641a86b377SEli Cohen MLX5_SET(qpc, qpc, remote_qpn, rqpn); 9651a86b377SEli Cohen MLX5_SET(qpc, qpc, rwe, 1); 9661a86b377SEli Cohen pp = MLX5_ADDR_OF(qpc, qpc, primary_address_path); 9671a86b377SEli Cohen MLX5_SET(ads, pp, vhca_port_num, 1); 9681a86b377SEli Cohen break; 9691a86b377SEli Cohen case MLX5_CMD_OP_INIT2RTR_QP: 9701a86b377SEli Cohen *inlen = MLX5_ST_SZ_BYTES(init2rtr_qp_in); 9711a86b377SEli Cohen *outlen = MLX5_ST_SZ_BYTES(init2rtr_qp_out); 9721a86b377SEli Cohen *in = kzalloc(*inlen, GFP_KERNEL); 9731a86b377SEli Cohen *out = kzalloc(MLX5_ST_SZ_BYTES(init2rtr_qp_out), GFP_KERNEL); 974f31231bfSColin Ian King if (!*in || !*out) 9751a86b377SEli Cohen goto outerr; 9761a86b377SEli Cohen 9771a86b377SEli Cohen MLX5_SET(init2rtr_qp_in, *in, opcode, cmd); 9781a86b377SEli Cohen MLX5_SET(init2rtr_qp_in, *in, uid, ndev->mvdev.res.uid); 9791a86b377SEli Cohen MLX5_SET(init2rtr_qp_in, *in, qpn, qpn); 9801a86b377SEli Cohen qpc = MLX5_ADDR_OF(rst2init_qp_in, *in, qpc); 9811a86b377SEli Cohen MLX5_SET(qpc, qpc, mtu, MLX5_QPC_MTU_256_BYTES); 9821a86b377SEli Cohen MLX5_SET(qpc, qpc, log_msg_max, 30); 9831a86b377SEli Cohen MLX5_SET(qpc, qpc, remote_qpn, rqpn); 9841a86b377SEli Cohen pp = MLX5_ADDR_OF(qpc, qpc, primary_address_path); 9851a86b377SEli Cohen MLX5_SET(ads, pp, fl, 1); 9861a86b377SEli Cohen break; 9871a86b377SEli Cohen case MLX5_CMD_OP_RTR2RTS_QP: 9881a86b377SEli Cohen *inlen = MLX5_ST_SZ_BYTES(rtr2rts_qp_in); 9891a86b377SEli Cohen *outlen = MLX5_ST_SZ_BYTES(rtr2rts_qp_out); 9901a86b377SEli Cohen *in = kzalloc(*inlen, GFP_KERNEL); 9911a86b377SEli Cohen *out = kzalloc(MLX5_ST_SZ_BYTES(rtr2rts_qp_out), GFP_KERNEL); 992f31231bfSColin Ian King if (!*in || !*out) 9931a86b377SEli Cohen goto outerr; 9941a86b377SEli Cohen 9951a86b377SEli Cohen MLX5_SET(rtr2rts_qp_in, *in, opcode, cmd); 9961a86b377SEli Cohen MLX5_SET(rtr2rts_qp_in, *in, uid, ndev->mvdev.res.uid); 9971a86b377SEli Cohen MLX5_SET(rtr2rts_qp_in, *in, qpn, qpn); 9981a86b377SEli Cohen qpc = MLX5_ADDR_OF(rst2init_qp_in, *in, qpc); 9991a86b377SEli Cohen pp = MLX5_ADDR_OF(qpc, qpc, primary_address_path); 10001a86b377SEli Cohen MLX5_SET(ads, pp, ack_timeout, 14); 10011a86b377SEli Cohen MLX5_SET(qpc, qpc, retry_count, 7); 10021a86b377SEli Cohen MLX5_SET(qpc, qpc, rnr_retry, 7); 10031a86b377SEli Cohen break; 10041a86b377SEli Cohen default: 1005f31231bfSColin Ian King goto outerr_nullify; 10061a86b377SEli Cohen } 10071a86b377SEli Cohen 10081a86b377SEli Cohen return; 10091a86b377SEli Cohen 10101a86b377SEli Cohen outerr: 10111a86b377SEli Cohen kfree(*in); 10121a86b377SEli Cohen kfree(*out); 1013f31231bfSColin Ian King outerr_nullify: 10141a86b377SEli Cohen *in = NULL; 10151a86b377SEli Cohen *out = NULL; 10161a86b377SEli Cohen } 10171a86b377SEli Cohen 10181a86b377SEli Cohen static void free_inout(void *in, void *out) 10191a86b377SEli Cohen { 10201a86b377SEli Cohen kfree(in); 10211a86b377SEli Cohen kfree(out); 10221a86b377SEli Cohen } 10231a86b377SEli Cohen 10241a86b377SEli Cohen /* Two QPs are used by each virtqueue. One is used by the driver and one by 10251a86b377SEli Cohen * firmware. The fw argument indicates whether the subjected QP is the one used 10261a86b377SEli Cohen * by firmware. 10271a86b377SEli Cohen */ 10281a86b377SEli Cohen static int modify_qp(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, bool fw, int cmd) 10291a86b377SEli Cohen { 10301a86b377SEli Cohen int outlen; 10311a86b377SEli Cohen int inlen; 10321a86b377SEli Cohen void *out; 10331a86b377SEli Cohen void *in; 10341a86b377SEli Cohen int err; 10351a86b377SEli Cohen 10361a86b377SEli Cohen alloc_inout(ndev, cmd, &in, &inlen, &out, &outlen, get_qpn(mvq, fw), get_rqpn(mvq, fw)); 10371a86b377SEli Cohen if (!in || !out) 10381a86b377SEli Cohen return -ENOMEM; 10391a86b377SEli Cohen 10401a86b377SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, inlen, out, outlen); 10411a86b377SEli Cohen free_inout(in, out); 10421a86b377SEli Cohen return err; 10431a86b377SEli Cohen } 10441a86b377SEli Cohen 10451a86b377SEli Cohen static int connect_qps(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 10461a86b377SEli Cohen { 10471a86b377SEli Cohen int err; 10481a86b377SEli Cohen 10491a86b377SEli Cohen err = modify_qp(ndev, mvq, true, MLX5_CMD_OP_2RST_QP); 10501a86b377SEli Cohen if (err) 10511a86b377SEli Cohen return err; 10521a86b377SEli Cohen 10531a86b377SEli Cohen err = modify_qp(ndev, mvq, false, MLX5_CMD_OP_2RST_QP); 10541a86b377SEli Cohen if (err) 10551a86b377SEli Cohen return err; 10561a86b377SEli Cohen 10571a86b377SEli Cohen err = modify_qp(ndev, mvq, true, MLX5_CMD_OP_RST2INIT_QP); 10581a86b377SEli Cohen if (err) 10591a86b377SEli Cohen return err; 10601a86b377SEli Cohen 10611a86b377SEli Cohen err = modify_qp(ndev, mvq, false, MLX5_CMD_OP_RST2INIT_QP); 10621a86b377SEli Cohen if (err) 10631a86b377SEli Cohen return err; 10641a86b377SEli Cohen 10651a86b377SEli Cohen err = modify_qp(ndev, mvq, true, MLX5_CMD_OP_INIT2RTR_QP); 10661a86b377SEli Cohen if (err) 10671a86b377SEli Cohen return err; 10681a86b377SEli Cohen 10691a86b377SEli Cohen err = modify_qp(ndev, mvq, false, MLX5_CMD_OP_INIT2RTR_QP); 10701a86b377SEli Cohen if (err) 10711a86b377SEli Cohen return err; 10721a86b377SEli Cohen 10731a86b377SEli Cohen return modify_qp(ndev, mvq, true, MLX5_CMD_OP_RTR2RTS_QP); 10741a86b377SEli Cohen } 10751a86b377SEli Cohen 10761a86b377SEli Cohen struct mlx5_virtq_attr { 10771a86b377SEli Cohen u8 state; 10781a86b377SEli Cohen u16 available_index; 1079b35ccebeSEli Cohen u16 used_index; 10801a86b377SEli Cohen }; 10811a86b377SEli Cohen 10821a86b377SEli Cohen static int query_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, 10831a86b377SEli Cohen struct mlx5_virtq_attr *attr) 10841a86b377SEli Cohen { 10851a86b377SEli Cohen int outlen = MLX5_ST_SZ_BYTES(query_virtio_net_q_out); 10861a86b377SEli Cohen u32 in[MLX5_ST_SZ_DW(query_virtio_net_q_in)] = {}; 10871a86b377SEli Cohen void *out; 10881a86b377SEli Cohen void *obj_context; 10891a86b377SEli Cohen void *cmd_hdr; 10901a86b377SEli Cohen int err; 10911a86b377SEli Cohen 10921a86b377SEli Cohen out = kzalloc(outlen, GFP_KERNEL); 10931a86b377SEli Cohen if (!out) 10941a86b377SEli Cohen return -ENOMEM; 10951a86b377SEli Cohen 10961a86b377SEli Cohen cmd_hdr = MLX5_ADDR_OF(query_virtio_net_q_in, in, general_obj_in_cmd_hdr); 10971a86b377SEli Cohen 10981a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_QUERY_GENERAL_OBJECT); 10991a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_NET_Q); 11001a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_id, mvq->virtq_id); 11011a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 11021a86b377SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, outlen); 11031a86b377SEli Cohen if (err) 11041a86b377SEli Cohen goto err_cmd; 11051a86b377SEli Cohen 11061a86b377SEli Cohen obj_context = MLX5_ADDR_OF(query_virtio_net_q_out, out, obj_context); 11071a86b377SEli Cohen memset(attr, 0, sizeof(*attr)); 11081a86b377SEli Cohen attr->state = MLX5_GET(virtio_net_q_object, obj_context, state); 11091a86b377SEli Cohen attr->available_index = MLX5_GET(virtio_net_q_object, obj_context, hw_available_index); 1110b35ccebeSEli Cohen attr->used_index = MLX5_GET(virtio_net_q_object, obj_context, hw_used_index); 11111a86b377SEli Cohen kfree(out); 11121a86b377SEli Cohen return 0; 11131a86b377SEli Cohen 11141a86b377SEli Cohen err_cmd: 11151a86b377SEli Cohen kfree(out); 11161a86b377SEli Cohen return err; 11171a86b377SEli Cohen } 11181a86b377SEli Cohen 1119cae15c2eSEli Cohen static bool is_valid_state_change(int oldstate, int newstate) 1120cae15c2eSEli Cohen { 1121cae15c2eSEli Cohen switch (oldstate) { 1122cae15c2eSEli Cohen case MLX5_VIRTIO_NET_Q_OBJECT_STATE_INIT: 1123cae15c2eSEli Cohen return newstate == MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY; 1124cae15c2eSEli Cohen case MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY: 1125cae15c2eSEli Cohen return newstate == MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND; 1126cae15c2eSEli Cohen case MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND: 1127cae15c2eSEli Cohen case MLX5_VIRTIO_NET_Q_OBJECT_STATE_ERR: 1128cae15c2eSEli Cohen default: 1129cae15c2eSEli Cohen return false; 1130cae15c2eSEli Cohen } 1131cae15c2eSEli Cohen } 1132cae15c2eSEli Cohen 11331a86b377SEli Cohen static int modify_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int state) 11341a86b377SEli Cohen { 11351a86b377SEli Cohen int inlen = MLX5_ST_SZ_BYTES(modify_virtio_net_q_in); 11361a86b377SEli Cohen u32 out[MLX5_ST_SZ_DW(modify_virtio_net_q_out)] = {}; 11371a86b377SEli Cohen void *obj_context; 11381a86b377SEli Cohen void *cmd_hdr; 11391a86b377SEli Cohen void *in; 11401a86b377SEli Cohen int err; 11411a86b377SEli Cohen 1142cae15c2eSEli Cohen if (mvq->fw_state == MLX5_VIRTIO_NET_Q_OBJECT_NONE) 1143cae15c2eSEli Cohen return 0; 1144cae15c2eSEli Cohen 1145cae15c2eSEli Cohen if (!is_valid_state_change(mvq->fw_state, state)) 1146cae15c2eSEli Cohen return -EINVAL; 1147cae15c2eSEli Cohen 11481a86b377SEli Cohen in = kzalloc(inlen, GFP_KERNEL); 11491a86b377SEli Cohen if (!in) 11501a86b377SEli Cohen return -ENOMEM; 11511a86b377SEli Cohen 11521a86b377SEli Cohen cmd_hdr = MLX5_ADDR_OF(modify_virtio_net_q_in, in, general_obj_in_cmd_hdr); 11531a86b377SEli Cohen 11541a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_MODIFY_GENERAL_OBJECT); 11551a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_NET_Q); 11561a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_id, mvq->virtq_id); 11571a86b377SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 11581a86b377SEli Cohen 11591a86b377SEli Cohen obj_context = MLX5_ADDR_OF(modify_virtio_net_q_in, in, obj_context); 11601a86b377SEli Cohen MLX5_SET64(virtio_net_q_object, obj_context, modify_field_select, 11611a86b377SEli Cohen MLX5_VIRTQ_MODIFY_MASK_STATE); 11621a86b377SEli Cohen MLX5_SET(virtio_net_q_object, obj_context, state, state); 11631a86b377SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, inlen, out, sizeof(out)); 11641a86b377SEli Cohen kfree(in); 11651a86b377SEli Cohen if (!err) 11661a86b377SEli Cohen mvq->fw_state = state; 11671a86b377SEli Cohen 11681a86b377SEli Cohen return err; 11691a86b377SEli Cohen } 11701a86b377SEli Cohen 11711892a3d4SEli Cohen static int counter_set_alloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 11721892a3d4SEli Cohen { 11731892a3d4SEli Cohen u32 in[MLX5_ST_SZ_DW(create_virtio_q_counters_in)] = {}; 11741892a3d4SEli Cohen u32 out[MLX5_ST_SZ_DW(create_virtio_q_counters_out)] = {}; 11751892a3d4SEli Cohen void *cmd_hdr; 11761892a3d4SEli Cohen int err; 11771892a3d4SEli Cohen 11781892a3d4SEli Cohen if (!counters_supported(&ndev->mvdev)) 11791892a3d4SEli Cohen return 0; 11801892a3d4SEli Cohen 11811892a3d4SEli Cohen cmd_hdr = MLX5_ADDR_OF(create_virtio_q_counters_in, in, hdr); 11821892a3d4SEli Cohen 11831892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); 11841892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_Q_COUNTERS); 11851892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 11861892a3d4SEli Cohen 11871892a3d4SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out)); 11881892a3d4SEli Cohen if (err) 11891892a3d4SEli Cohen return err; 11901892a3d4SEli Cohen 11911892a3d4SEli Cohen mvq->counter_set_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); 11921892a3d4SEli Cohen 11931892a3d4SEli Cohen return 0; 11941892a3d4SEli Cohen } 11951892a3d4SEli Cohen 11961892a3d4SEli Cohen static void counter_set_dealloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 11971892a3d4SEli Cohen { 11981892a3d4SEli Cohen u32 in[MLX5_ST_SZ_DW(destroy_virtio_q_counters_in)] = {}; 11991892a3d4SEli Cohen u32 out[MLX5_ST_SZ_DW(destroy_virtio_q_counters_out)] = {}; 12001892a3d4SEli Cohen 12011892a3d4SEli Cohen if (!counters_supported(&ndev->mvdev)) 12021892a3d4SEli Cohen return; 12031892a3d4SEli Cohen 12041892a3d4SEli Cohen MLX5_SET(destroy_virtio_q_counters_in, in, hdr.opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); 12051892a3d4SEli Cohen MLX5_SET(destroy_virtio_q_counters_in, in, hdr.obj_id, mvq->counter_set_id); 12061892a3d4SEli Cohen MLX5_SET(destroy_virtio_q_counters_in, in, hdr.uid, ndev->mvdev.res.uid); 12071892a3d4SEli Cohen MLX5_SET(destroy_virtio_q_counters_in, in, hdr.obj_type, MLX5_OBJ_TYPE_VIRTIO_Q_COUNTERS); 12081892a3d4SEli Cohen if (mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out))) 12091892a3d4SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "dealloc counter set 0x%x\n", mvq->counter_set_id); 12101892a3d4SEli Cohen } 12111892a3d4SEli Cohen 1212*bc9a2b3eSEli Cohen static irqreturn_t mlx5_vdpa_int_handler(int irq, void *priv) 1213*bc9a2b3eSEli Cohen { 1214*bc9a2b3eSEli Cohen struct vdpa_callback *cb = priv; 1215*bc9a2b3eSEli Cohen 1216*bc9a2b3eSEli Cohen if (cb->callback) 1217*bc9a2b3eSEli Cohen return cb->callback(cb->private); 1218*bc9a2b3eSEli Cohen 1219*bc9a2b3eSEli Cohen return IRQ_HANDLED; 1220*bc9a2b3eSEli Cohen } 1221*bc9a2b3eSEli Cohen 1222*bc9a2b3eSEli Cohen static void alloc_vector(struct mlx5_vdpa_net *ndev, 1223*bc9a2b3eSEli Cohen struct mlx5_vdpa_virtqueue *mvq) 1224*bc9a2b3eSEli Cohen { 1225*bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool *irqp = &ndev->irqp; 1226*bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool_entry *ent; 1227*bc9a2b3eSEli Cohen int err; 1228*bc9a2b3eSEli Cohen int i; 1229*bc9a2b3eSEli Cohen 1230*bc9a2b3eSEli Cohen for (i = 0; i < irqp->num_ent; i++) { 1231*bc9a2b3eSEli Cohen ent = &irqp->entries[i]; 1232*bc9a2b3eSEli Cohen if (!ent->used) { 1233*bc9a2b3eSEli Cohen snprintf(ent->name, MLX5_VDPA_IRQ_NAME_LEN, "%s-vq-%d", 1234*bc9a2b3eSEli Cohen dev_name(&ndev->mvdev.vdev.dev), mvq->index); 1235*bc9a2b3eSEli Cohen ent->dev_id = &ndev->event_cbs[mvq->index]; 1236*bc9a2b3eSEli Cohen err = request_irq(ent->map.virq, mlx5_vdpa_int_handler, 0, 1237*bc9a2b3eSEli Cohen ent->name, ent->dev_id); 1238*bc9a2b3eSEli Cohen if (err) 1239*bc9a2b3eSEli Cohen return; 1240*bc9a2b3eSEli Cohen 1241*bc9a2b3eSEli Cohen ent->used = true; 1242*bc9a2b3eSEli Cohen mvq->map = ent->map; 1243*bc9a2b3eSEli Cohen return; 1244*bc9a2b3eSEli Cohen } 1245*bc9a2b3eSEli Cohen } 1246*bc9a2b3eSEli Cohen } 1247*bc9a2b3eSEli Cohen 1248*bc9a2b3eSEli Cohen static void dealloc_vector(struct mlx5_vdpa_net *ndev, 1249*bc9a2b3eSEli Cohen struct mlx5_vdpa_virtqueue *mvq) 1250*bc9a2b3eSEli Cohen { 1251*bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool *irqp = &ndev->irqp; 1252*bc9a2b3eSEli Cohen int i; 1253*bc9a2b3eSEli Cohen 1254*bc9a2b3eSEli Cohen for (i = 0; i < irqp->num_ent; i++) 1255*bc9a2b3eSEli Cohen if (mvq->map.virq == irqp->entries[i].map.virq) { 1256*bc9a2b3eSEli Cohen free_irq(mvq->map.virq, irqp->entries[i].dev_id); 1257*bc9a2b3eSEli Cohen irqp->entries[i].used = false; 1258*bc9a2b3eSEli Cohen return; 1259*bc9a2b3eSEli Cohen } 1260*bc9a2b3eSEli Cohen } 1261*bc9a2b3eSEli Cohen 12621a86b377SEli Cohen static int setup_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 12631a86b377SEli Cohen { 12641a86b377SEli Cohen u16 idx = mvq->index; 12651a86b377SEli Cohen int err; 12661a86b377SEli Cohen 12671a86b377SEli Cohen if (!mvq->num_ent) 12681a86b377SEli Cohen return 0; 12691a86b377SEli Cohen 127052893733SEli Cohen if (mvq->initialized) 127152893733SEli Cohen return 0; 12721a86b377SEli Cohen 12731a86b377SEli Cohen err = cq_create(ndev, idx, mvq->num_ent); 12741a86b377SEli Cohen if (err) 12751a86b377SEli Cohen return err; 12761a86b377SEli Cohen 12771a86b377SEli Cohen err = qp_create(ndev, mvq, &mvq->fwqp); 12781a86b377SEli Cohen if (err) 12791a86b377SEli Cohen goto err_fwqp; 12801a86b377SEli Cohen 12811a86b377SEli Cohen err = qp_create(ndev, mvq, &mvq->vqqp); 12821a86b377SEli Cohen if (err) 12831a86b377SEli Cohen goto err_vqqp; 12841a86b377SEli Cohen 12851a86b377SEli Cohen err = connect_qps(ndev, mvq); 12861a86b377SEli Cohen if (err) 12871a86b377SEli Cohen goto err_connect; 12881a86b377SEli Cohen 12891892a3d4SEli Cohen err = counter_set_alloc(ndev, mvq); 12901892a3d4SEli Cohen if (err) 1291*bc9a2b3eSEli Cohen goto err_connect; 12921892a3d4SEli Cohen 1293*bc9a2b3eSEli Cohen alloc_vector(ndev, mvq); 12941a86b377SEli Cohen err = create_virtqueue(ndev, mvq); 12951a86b377SEli Cohen if (err) 1296*bc9a2b3eSEli Cohen goto err_vq; 12971a86b377SEli Cohen 12981a86b377SEli Cohen if (mvq->ready) { 12991a86b377SEli Cohen err = modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY); 13001a86b377SEli Cohen if (err) { 13011a86b377SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "failed to modify to ready vq idx %d(%d)\n", 13021a86b377SEli Cohen idx, err); 1303*bc9a2b3eSEli Cohen goto err_modify; 13041a86b377SEli Cohen } 13051a86b377SEli Cohen } 13061a86b377SEli Cohen 13071a86b377SEli Cohen mvq->initialized = true; 13081a86b377SEli Cohen return 0; 13091a86b377SEli Cohen 1310*bc9a2b3eSEli Cohen err_modify: 1311*bc9a2b3eSEli Cohen destroy_virtqueue(ndev, mvq); 1312*bc9a2b3eSEli Cohen err_vq: 1313*bc9a2b3eSEli Cohen dealloc_vector(ndev, mvq); 13141892a3d4SEli Cohen counter_set_dealloc(ndev, mvq); 1315*bc9a2b3eSEli Cohen err_connect: 13161a86b377SEli Cohen qp_destroy(ndev, &mvq->vqqp); 13171a86b377SEli Cohen err_vqqp: 13181a86b377SEli Cohen qp_destroy(ndev, &mvq->fwqp); 13191a86b377SEli Cohen err_fwqp: 13201a86b377SEli Cohen cq_destroy(ndev, idx); 13211a86b377SEli Cohen return err; 13221a86b377SEli Cohen } 13231a86b377SEli Cohen 13241a86b377SEli Cohen static void suspend_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 13251a86b377SEli Cohen { 13261a86b377SEli Cohen struct mlx5_virtq_attr attr; 13271a86b377SEli Cohen 13281a86b377SEli Cohen if (!mvq->initialized) 13291a86b377SEli Cohen return; 13301a86b377SEli Cohen 13311a86b377SEli Cohen if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY) 13321a86b377SEli Cohen return; 13331a86b377SEli Cohen 13341a86b377SEli Cohen if (modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND)) 13351a86b377SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "modify to suspend failed\n"); 13363176e974SSi-Wei Liu 13373176e974SSi-Wei Liu if (query_virtqueue(ndev, mvq, &attr)) { 13383176e974SSi-Wei Liu mlx5_vdpa_warn(&ndev->mvdev, "failed to query virtqueue\n"); 13393176e974SSi-Wei Liu return; 13403176e974SSi-Wei Liu } 13413176e974SSi-Wei Liu mvq->avail_idx = attr.available_index; 1342bc04d93eSEli Cohen mvq->used_idx = attr.used_index; 13431a86b377SEli Cohen } 13441a86b377SEli Cohen 13451a86b377SEli Cohen static void suspend_vqs(struct mlx5_vdpa_net *ndev) 13461a86b377SEli Cohen { 13471a86b377SEli Cohen int i; 13481a86b377SEli Cohen 134975560522SEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) 13501a86b377SEli Cohen suspend_vq(ndev, &ndev->vqs[i]); 13511a86b377SEli Cohen } 13521a86b377SEli Cohen 13531a86b377SEli Cohen static void teardown_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 13541a86b377SEli Cohen { 13551a86b377SEli Cohen if (!mvq->initialized) 13561a86b377SEli Cohen return; 13571a86b377SEli Cohen 13581a86b377SEli Cohen suspend_vq(ndev, mvq); 13591a86b377SEli Cohen destroy_virtqueue(ndev, mvq); 1360*bc9a2b3eSEli Cohen dealloc_vector(ndev, mvq); 13611892a3d4SEli Cohen counter_set_dealloc(ndev, mvq); 13621a86b377SEli Cohen qp_destroy(ndev, &mvq->vqqp); 13631a86b377SEli Cohen qp_destroy(ndev, &mvq->fwqp); 13641a86b377SEli Cohen cq_destroy(ndev, mvq->index); 13651a86b377SEli Cohen mvq->initialized = false; 13661a86b377SEli Cohen } 13671a86b377SEli Cohen 13681a86b377SEli Cohen static int create_rqt(struct mlx5_vdpa_net *ndev) 13691a86b377SEli Cohen { 1370a43ae805SEli Cohen int rqt_table_size = roundup_pow_of_two(ndev->rqt_size); 1371a43ae805SEli Cohen int act_sz = roundup_pow_of_two(ndev->cur_num_vqs / 2); 13721a86b377SEli Cohen __be32 *list; 13731a86b377SEli Cohen void *rqtc; 13741a86b377SEli Cohen int inlen; 13751a86b377SEli Cohen void *in; 13761a86b377SEli Cohen int i, j; 13771a86b377SEli Cohen int err; 13781a86b377SEli Cohen 1379a43ae805SEli Cohen inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + rqt_table_size * MLX5_ST_SZ_BYTES(rq_num); 13801a86b377SEli Cohen in = kzalloc(inlen, GFP_KERNEL); 13811a86b377SEli Cohen if (!in) 13821a86b377SEli Cohen return -ENOMEM; 13831a86b377SEli Cohen 13841a86b377SEli Cohen MLX5_SET(create_rqt_in, in, uid, ndev->mvdev.res.uid); 13851a86b377SEli Cohen rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context); 13861a86b377SEli Cohen 13871a86b377SEli Cohen MLX5_SET(rqtc, rqtc, list_q_type, MLX5_RQTC_LIST_Q_TYPE_VIRTIO_NET_Q); 1388a43ae805SEli Cohen MLX5_SET(rqtc, rqtc, rqt_max_size, rqt_table_size); 13891a86b377SEli Cohen list = MLX5_ADDR_OF(rqtc, rqtc, rq_num[0]); 1390a43ae805SEli Cohen for (i = 0, j = 0; i < act_sz; i++, j += 2) 1391acde3929SEli Cohen list[i] = cpu_to_be32(ndev->vqs[j % ndev->cur_num_vqs].virtq_id); 13921a86b377SEli Cohen 1393a43ae805SEli Cohen MLX5_SET(rqtc, rqtc, rqt_actual_size, act_sz); 13941a86b377SEli Cohen err = mlx5_vdpa_create_rqt(&ndev->mvdev, in, inlen, &ndev->res.rqtn); 13951a86b377SEli Cohen kfree(in); 13961a86b377SEli Cohen if (err) 13971a86b377SEli Cohen return err; 13981a86b377SEli Cohen 13991a86b377SEli Cohen return 0; 14001a86b377SEli Cohen } 14011a86b377SEli Cohen 140252893733SEli Cohen #define MLX5_MODIFY_RQT_NUM_RQS ((u64)1) 140352893733SEli Cohen 140452893733SEli Cohen static int modify_rqt(struct mlx5_vdpa_net *ndev, int num) 140552893733SEli Cohen { 1406a43ae805SEli Cohen int act_sz = roundup_pow_of_two(num / 2); 140752893733SEli Cohen __be32 *list; 140852893733SEli Cohen void *rqtc; 140952893733SEli Cohen int inlen; 141052893733SEli Cohen void *in; 141152893733SEli Cohen int i, j; 141252893733SEli Cohen int err; 141352893733SEli Cohen 1414a43ae805SEli Cohen inlen = MLX5_ST_SZ_BYTES(modify_rqt_in) + act_sz * MLX5_ST_SZ_BYTES(rq_num); 141552893733SEli Cohen in = kzalloc(inlen, GFP_KERNEL); 141652893733SEli Cohen if (!in) 141752893733SEli Cohen return -ENOMEM; 141852893733SEli Cohen 141952893733SEli Cohen MLX5_SET(modify_rqt_in, in, uid, ndev->mvdev.res.uid); 142052893733SEli Cohen MLX5_SET64(modify_rqt_in, in, bitmask, MLX5_MODIFY_RQT_NUM_RQS); 142152893733SEli Cohen rqtc = MLX5_ADDR_OF(modify_rqt_in, in, ctx); 142252893733SEli Cohen MLX5_SET(rqtc, rqtc, list_q_type, MLX5_RQTC_LIST_Q_TYPE_VIRTIO_NET_Q); 142352893733SEli Cohen 142452893733SEli Cohen list = MLX5_ADDR_OF(rqtc, rqtc, rq_num[0]); 1425a43ae805SEli Cohen for (i = 0, j = 0; i < act_sz; i++, j = j + 2) 1426a7f46ba4SEli Cohen list[i] = cpu_to_be32(ndev->vqs[j % num].virtq_id); 142752893733SEli Cohen 1428a43ae805SEli Cohen MLX5_SET(rqtc, rqtc, rqt_actual_size, act_sz); 142952893733SEli Cohen err = mlx5_vdpa_modify_rqt(&ndev->mvdev, in, inlen, ndev->res.rqtn); 143052893733SEli Cohen kfree(in); 143152893733SEli Cohen if (err) 143252893733SEli Cohen return err; 143352893733SEli Cohen 143452893733SEli Cohen return 0; 143552893733SEli Cohen } 143652893733SEli Cohen 14371a86b377SEli Cohen static void destroy_rqt(struct mlx5_vdpa_net *ndev) 14381a86b377SEli Cohen { 14391a86b377SEli Cohen mlx5_vdpa_destroy_rqt(&ndev->mvdev, ndev->res.rqtn); 14401a86b377SEli Cohen } 14411a86b377SEli Cohen 14421a86b377SEli Cohen static int create_tir(struct mlx5_vdpa_net *ndev) 14431a86b377SEli Cohen { 14441a86b377SEli Cohen #define HASH_IP_L4PORTS \ 14451a86b377SEli Cohen (MLX5_HASH_FIELD_SEL_SRC_IP | MLX5_HASH_FIELD_SEL_DST_IP | MLX5_HASH_FIELD_SEL_L4_SPORT | \ 14461a86b377SEli Cohen MLX5_HASH_FIELD_SEL_L4_DPORT) 14471a86b377SEli Cohen static const u8 rx_hash_toeplitz_key[] = { 0x2c, 0xc6, 0x81, 0xd1, 0x5b, 0xdb, 0xf4, 0xf7, 14481a86b377SEli Cohen 0xfc, 0xa2, 0x83, 0x19, 0xdb, 0x1a, 0x3e, 0x94, 14491a86b377SEli Cohen 0x6b, 0x9e, 0x38, 0xd9, 0x2c, 0x9c, 0x03, 0xd1, 14501a86b377SEli Cohen 0xad, 0x99, 0x44, 0xa7, 0xd9, 0x56, 0x3d, 0x59, 14511a86b377SEli Cohen 0x06, 0x3c, 0x25, 0xf3, 0xfc, 0x1f, 0xdc, 0x2a }; 14521a86b377SEli Cohen void *rss_key; 14531a86b377SEli Cohen void *outer; 14541a86b377SEli Cohen void *tirc; 14551a86b377SEli Cohen void *in; 14561a86b377SEli Cohen int err; 14571a86b377SEli Cohen 14581a86b377SEli Cohen in = kzalloc(MLX5_ST_SZ_BYTES(create_tir_in), GFP_KERNEL); 14591a86b377SEli Cohen if (!in) 14601a86b377SEli Cohen return -ENOMEM; 14611a86b377SEli Cohen 14621a86b377SEli Cohen MLX5_SET(create_tir_in, in, uid, ndev->mvdev.res.uid); 14631a86b377SEli Cohen tirc = MLX5_ADDR_OF(create_tir_in, in, ctx); 14641a86b377SEli Cohen MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_INDIRECT); 14651a86b377SEli Cohen 14661a86b377SEli Cohen MLX5_SET(tirc, tirc, rx_hash_symmetric, 1); 14671a86b377SEli Cohen MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_TOEPLITZ); 14681a86b377SEli Cohen rss_key = MLX5_ADDR_OF(tirc, tirc, rx_hash_toeplitz_key); 14691a86b377SEli Cohen memcpy(rss_key, rx_hash_toeplitz_key, sizeof(rx_hash_toeplitz_key)); 14701a86b377SEli Cohen 14711a86b377SEli Cohen outer = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer); 14721a86b377SEli Cohen MLX5_SET(rx_hash_field_select, outer, l3_prot_type, MLX5_L3_PROT_TYPE_IPV4); 14731a86b377SEli Cohen MLX5_SET(rx_hash_field_select, outer, l4_prot_type, MLX5_L4_PROT_TYPE_TCP); 14741a86b377SEli Cohen MLX5_SET(rx_hash_field_select, outer, selected_fields, HASH_IP_L4PORTS); 14751a86b377SEli Cohen 14761a86b377SEli Cohen MLX5_SET(tirc, tirc, indirect_table, ndev->res.rqtn); 14771a86b377SEli Cohen MLX5_SET(tirc, tirc, transport_domain, ndev->res.tdn); 14781a86b377SEli Cohen 14791a86b377SEli Cohen err = mlx5_vdpa_create_tir(&ndev->mvdev, in, &ndev->res.tirn); 14801a86b377SEli Cohen kfree(in); 148129422100SEli Cohen if (err) 148229422100SEli Cohen return err; 148329422100SEli Cohen 148429422100SEli Cohen mlx5_vdpa_add_tirn(ndev); 14851a86b377SEli Cohen return err; 14861a86b377SEli Cohen } 14871a86b377SEli Cohen 14881a86b377SEli Cohen static void destroy_tir(struct mlx5_vdpa_net *ndev) 14891a86b377SEli Cohen { 149029422100SEli Cohen mlx5_vdpa_remove_tirn(ndev); 14911a86b377SEli Cohen mlx5_vdpa_destroy_tir(&ndev->mvdev, ndev->res.tirn); 14921a86b377SEli Cohen } 14931a86b377SEli Cohen 1494baf2ad3fSEli Cohen #define MAX_STEERING_ENT 0x8000 1495baf2ad3fSEli Cohen #define MAX_STEERING_GROUPS 2 1496baf2ad3fSEli Cohen 14970a599750SEli Cohen #if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 14980a599750SEli Cohen #define NUM_DESTS 2 14990a599750SEli Cohen #else 15000a599750SEli Cohen #define NUM_DESTS 1 15010a599750SEli Cohen #endif 15020a599750SEli Cohen 15030a599750SEli Cohen static int add_steering_counters(struct mlx5_vdpa_net *ndev, 15040a599750SEli Cohen struct macvlan_node *node, 15050a599750SEli Cohen struct mlx5_flow_act *flow_act, 15060a599750SEli Cohen struct mlx5_flow_destination *dests) 15071a86b377SEli Cohen { 15080a599750SEli Cohen #if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 15090a599750SEli Cohen int err; 15100a599750SEli Cohen 15110a599750SEli Cohen node->ucast_counter.counter = mlx5_fc_create(ndev->mvdev.mdev, false); 15120a599750SEli Cohen if (IS_ERR(node->ucast_counter.counter)) 15130a599750SEli Cohen return PTR_ERR(node->ucast_counter.counter); 15140a599750SEli Cohen 15150a599750SEli Cohen node->mcast_counter.counter = mlx5_fc_create(ndev->mvdev.mdev, false); 15160a599750SEli Cohen if (IS_ERR(node->mcast_counter.counter)) { 15170a599750SEli Cohen err = PTR_ERR(node->mcast_counter.counter); 15180a599750SEli Cohen goto err_mcast_counter; 15190a599750SEli Cohen } 15200a599750SEli Cohen 15210a599750SEli Cohen dests[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 15220a599750SEli Cohen flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; 15230a599750SEli Cohen return 0; 15240a599750SEli Cohen 15250a599750SEli Cohen err_mcast_counter: 15260a599750SEli Cohen mlx5_fc_destroy(ndev->mvdev.mdev, node->ucast_counter.counter); 15270a599750SEli Cohen return err; 15280a599750SEli Cohen #else 15290a599750SEli Cohen return 0; 15300a599750SEli Cohen #endif 15310a599750SEli Cohen } 15320a599750SEli Cohen 15330a599750SEli Cohen static void remove_steering_counters(struct mlx5_vdpa_net *ndev, 15340a599750SEli Cohen struct macvlan_node *node) 15350a599750SEli Cohen { 15360a599750SEli Cohen #if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 15370a599750SEli Cohen mlx5_fc_destroy(ndev->mvdev.mdev, node->mcast_counter.counter); 15380a599750SEli Cohen mlx5_fc_destroy(ndev->mvdev.mdev, node->ucast_counter.counter); 15390a599750SEli Cohen #endif 15400a599750SEli Cohen } 15410a599750SEli Cohen 15420a599750SEli Cohen static int mlx5_vdpa_add_mac_vlan_rules(struct mlx5_vdpa_net *ndev, u8 *mac, 15430a599750SEli Cohen struct macvlan_node *node) 15440a599750SEli Cohen { 15450a599750SEli Cohen struct mlx5_flow_destination dests[NUM_DESTS] = {}; 15461a86b377SEli Cohen struct mlx5_flow_act flow_act = {}; 1547540061acSEli Cohen struct mlx5_flow_spec *spec; 1548540061acSEli Cohen void *headers_c; 1549540061acSEli Cohen void *headers_v; 1550540061acSEli Cohen u8 *dmac_c; 1551540061acSEli Cohen u8 *dmac_v; 15521a86b377SEli Cohen int err; 15530a599750SEli Cohen u16 vid; 15541a86b377SEli Cohen 1555540061acSEli Cohen spec = kvzalloc(sizeof(*spec), GFP_KERNEL); 1556540061acSEli Cohen if (!spec) 1557540061acSEli Cohen return -ENOMEM; 1558540061acSEli Cohen 15590a599750SEli Cohen vid = key2vid(node->macvlan); 1560540061acSEli Cohen spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 1561540061acSEli Cohen headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, outer_headers); 1562540061acSEli Cohen headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers); 1563baf2ad3fSEli Cohen dmac_c = MLX5_ADDR_OF(fte_match_param, headers_c, outer_headers.dmac_47_16); 1564540061acSEli Cohen dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v, outer_headers.dmac_47_16); 156571aa95a6SXu Qiang eth_broadcast_addr(dmac_c); 1566baf2ad3fSEli Cohen ether_addr_copy(dmac_v, mac); 1567a6ce72c0SEli Cohen if (ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VLAN)) { 1568baf2ad3fSEli Cohen MLX5_SET(fte_match_set_lyr_2_4, headers_c, cvlan_tag, 1); 1569a6ce72c0SEli Cohen MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, first_vid); 1570a6ce72c0SEli Cohen } 15710a599750SEli Cohen if (node->tagged) { 1572baf2ad3fSEli Cohen MLX5_SET(fte_match_set_lyr_2_4, headers_v, cvlan_tag, 1); 1573a6ce72c0SEli Cohen MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, vid); 1574baf2ad3fSEli Cohen } 15757becdd13SEli Cohen flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 15760a599750SEli Cohen dests[0].type = MLX5_FLOW_DESTINATION_TYPE_TIR; 15770a599750SEli Cohen dests[0].tir_num = ndev->res.tirn; 15780a599750SEli Cohen err = add_steering_counters(ndev, node, &flow_act, dests); 15790a599750SEli Cohen if (err) 15800a599750SEli Cohen goto out_free; 1581540061acSEli Cohen 15820a599750SEli Cohen #if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 15830a599750SEli Cohen dests[1].counter_id = mlx5_fc_id(node->ucast_counter.counter); 15840a599750SEli Cohen #endif 15850a599750SEli Cohen node->ucast_rule = mlx5_add_flow_rules(ndev->rxft, spec, &flow_act, dests, NUM_DESTS); 15860a599750SEli Cohen if (IS_ERR(node->ucast_rule)) { 15870a599750SEli Cohen err = PTR_ERR(node->ucast_rule); 15880a599750SEli Cohen goto err_ucast; 15890a599750SEli Cohen } 15900a599750SEli Cohen 15910a599750SEli Cohen #if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG) 15920a599750SEli Cohen dests[1].counter_id = mlx5_fc_id(node->mcast_counter.counter); 15930a599750SEli Cohen #endif 15941a86b377SEli Cohen 1595540061acSEli Cohen memset(dmac_c, 0, ETH_ALEN); 1596540061acSEli Cohen memset(dmac_v, 0, ETH_ALEN); 1597540061acSEli Cohen dmac_c[0] = 1; 1598540061acSEli Cohen dmac_v[0] = 1; 15990a599750SEli Cohen node->mcast_rule = mlx5_add_flow_rules(ndev->rxft, spec, &flow_act, dests, NUM_DESTS); 16000a599750SEli Cohen if (IS_ERR(node->mcast_rule)) { 16010a599750SEli Cohen err = PTR_ERR(node->mcast_rule); 1602baf2ad3fSEli Cohen goto err_mcast; 1603540061acSEli Cohen } 16040a599750SEli Cohen kvfree(spec); 16050a599750SEli Cohen mlx5_vdpa_add_rx_counters(ndev, node); 16061a86b377SEli Cohen return 0; 16071a86b377SEli Cohen 1608baf2ad3fSEli Cohen err_mcast: 16090a599750SEli Cohen mlx5_del_flow_rules(node->ucast_rule); 16100a599750SEli Cohen err_ucast: 16110a599750SEli Cohen remove_steering_counters(ndev, node); 16120a599750SEli Cohen out_free: 16130a599750SEli Cohen kvfree(spec); 16141a86b377SEli Cohen return err; 16151a86b377SEli Cohen } 16161a86b377SEli Cohen 1617baf2ad3fSEli Cohen static void mlx5_vdpa_del_mac_vlan_rules(struct mlx5_vdpa_net *ndev, 16180a599750SEli Cohen struct macvlan_node *node) 16191a86b377SEli Cohen { 16200a599750SEli Cohen mlx5_vdpa_remove_rx_counters(ndev, node); 16210a599750SEli Cohen mlx5_del_flow_rules(node->ucast_rule); 16220a599750SEli Cohen mlx5_del_flow_rules(node->mcast_rule); 1623baf2ad3fSEli Cohen } 1624baf2ad3fSEli Cohen 1625baf2ad3fSEli Cohen static u64 search_val(u8 *mac, u16 vlan, bool tagged) 1626baf2ad3fSEli Cohen { 1627baf2ad3fSEli Cohen u64 val; 1628baf2ad3fSEli Cohen 1629baf2ad3fSEli Cohen if (!tagged) 1630baf2ad3fSEli Cohen vlan = MLX5V_UNTAGGED; 1631baf2ad3fSEli Cohen 1632baf2ad3fSEli Cohen val = (u64)vlan << 48 | 1633baf2ad3fSEli Cohen (u64)mac[0] << 40 | 1634baf2ad3fSEli Cohen (u64)mac[1] << 32 | 1635baf2ad3fSEli Cohen (u64)mac[2] << 24 | 1636baf2ad3fSEli Cohen (u64)mac[3] << 16 | 1637baf2ad3fSEli Cohen (u64)mac[4] << 8 | 1638baf2ad3fSEli Cohen (u64)mac[5]; 1639baf2ad3fSEli Cohen 1640baf2ad3fSEli Cohen return val; 1641baf2ad3fSEli Cohen } 1642baf2ad3fSEli Cohen 1643baf2ad3fSEli Cohen static struct macvlan_node *mac_vlan_lookup(struct mlx5_vdpa_net *ndev, u64 value) 1644baf2ad3fSEli Cohen { 1645baf2ad3fSEli Cohen struct macvlan_node *pos; 1646baf2ad3fSEli Cohen u32 idx; 1647baf2ad3fSEli Cohen 1648baf2ad3fSEli Cohen idx = hash_64(value, 8); // tbd 8 1649baf2ad3fSEli Cohen hlist_for_each_entry(pos, &ndev->macvlan_hash[idx], hlist) { 1650baf2ad3fSEli Cohen if (pos->macvlan == value) 1651baf2ad3fSEli Cohen return pos; 1652baf2ad3fSEli Cohen } 1653baf2ad3fSEli Cohen return NULL; 1654baf2ad3fSEli Cohen } 1655baf2ad3fSEli Cohen 16560a599750SEli Cohen static int mac_vlan_add(struct mlx5_vdpa_net *ndev, u8 *mac, u16 vid, bool tagged) 1657baf2ad3fSEli Cohen { 1658baf2ad3fSEli Cohen struct macvlan_node *ptr; 1659baf2ad3fSEli Cohen u64 val; 1660baf2ad3fSEli Cohen u32 idx; 1661baf2ad3fSEli Cohen int err; 1662baf2ad3fSEli Cohen 16630a599750SEli Cohen val = search_val(mac, vid, tagged); 1664baf2ad3fSEli Cohen if (mac_vlan_lookup(ndev, val)) 1665baf2ad3fSEli Cohen return -EEXIST; 1666baf2ad3fSEli Cohen 1667baf2ad3fSEli Cohen ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); 1668baf2ad3fSEli Cohen if (!ptr) 1669baf2ad3fSEli Cohen return -ENOMEM; 1670baf2ad3fSEli Cohen 16710a599750SEli Cohen ptr->tagged = tagged; 16720a599750SEli Cohen ptr->macvlan = val; 16730a599750SEli Cohen ptr->ndev = ndev; 16740a599750SEli Cohen err = mlx5_vdpa_add_mac_vlan_rules(ndev, ndev->config.mac, ptr); 1675baf2ad3fSEli Cohen if (err) 1676baf2ad3fSEli Cohen goto err_add; 1677baf2ad3fSEli Cohen 1678baf2ad3fSEli Cohen idx = hash_64(val, 8); 1679baf2ad3fSEli Cohen hlist_add_head(&ptr->hlist, &ndev->macvlan_hash[idx]); 1680baf2ad3fSEli Cohen return 0; 1681baf2ad3fSEli Cohen 1682baf2ad3fSEli Cohen err_add: 1683baf2ad3fSEli Cohen kfree(ptr); 1684baf2ad3fSEli Cohen return err; 1685baf2ad3fSEli Cohen } 1686baf2ad3fSEli Cohen 1687baf2ad3fSEli Cohen static void mac_vlan_del(struct mlx5_vdpa_net *ndev, u8 *mac, u16 vlan, bool tagged) 1688baf2ad3fSEli Cohen { 1689baf2ad3fSEli Cohen struct macvlan_node *ptr; 1690baf2ad3fSEli Cohen 1691baf2ad3fSEli Cohen ptr = mac_vlan_lookup(ndev, search_val(mac, vlan, tagged)); 1692baf2ad3fSEli Cohen if (!ptr) 16931a86b377SEli Cohen return; 16941a86b377SEli Cohen 1695baf2ad3fSEli Cohen hlist_del(&ptr->hlist); 16960a599750SEli Cohen mlx5_vdpa_del_mac_vlan_rules(ndev, ptr); 16970a599750SEli Cohen remove_steering_counters(ndev, ptr); 1698baf2ad3fSEli Cohen kfree(ptr); 1699baf2ad3fSEli Cohen } 1700baf2ad3fSEli Cohen 1701baf2ad3fSEli Cohen static void clear_mac_vlan_table(struct mlx5_vdpa_net *ndev) 1702baf2ad3fSEli Cohen { 1703baf2ad3fSEli Cohen struct macvlan_node *pos; 1704baf2ad3fSEli Cohen struct hlist_node *n; 1705baf2ad3fSEli Cohen int i; 1706baf2ad3fSEli Cohen 1707baf2ad3fSEli Cohen for (i = 0; i < MLX5V_MACVLAN_SIZE; i++) { 1708baf2ad3fSEli Cohen hlist_for_each_entry_safe(pos, n, &ndev->macvlan_hash[i], hlist) { 1709baf2ad3fSEli Cohen hlist_del(&pos->hlist); 17100a599750SEli Cohen mlx5_vdpa_del_mac_vlan_rules(ndev, pos); 17110a599750SEli Cohen remove_steering_counters(ndev, pos); 1712baf2ad3fSEli Cohen kfree(pos); 1713baf2ad3fSEli Cohen } 1714baf2ad3fSEli Cohen } 1715baf2ad3fSEli Cohen } 1716baf2ad3fSEli Cohen 1717baf2ad3fSEli Cohen static int setup_steering(struct mlx5_vdpa_net *ndev) 1718baf2ad3fSEli Cohen { 1719baf2ad3fSEli Cohen struct mlx5_flow_table_attr ft_attr = {}; 1720baf2ad3fSEli Cohen struct mlx5_flow_namespace *ns; 1721baf2ad3fSEli Cohen int err; 1722baf2ad3fSEli Cohen 1723baf2ad3fSEli Cohen ft_attr.max_fte = MAX_STEERING_ENT; 1724baf2ad3fSEli Cohen ft_attr.autogroup.max_num_groups = MAX_STEERING_GROUPS; 1725baf2ad3fSEli Cohen 1726baf2ad3fSEli Cohen ns = mlx5_get_flow_namespace(ndev->mvdev.mdev, MLX5_FLOW_NAMESPACE_BYPASS); 1727baf2ad3fSEli Cohen if (!ns) { 1728baf2ad3fSEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "failed to get flow namespace\n"); 1729baf2ad3fSEli Cohen return -EOPNOTSUPP; 1730baf2ad3fSEli Cohen } 1731baf2ad3fSEli Cohen 1732baf2ad3fSEli Cohen ndev->rxft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr); 1733baf2ad3fSEli Cohen if (IS_ERR(ndev->rxft)) { 1734baf2ad3fSEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "failed to create flow table\n"); 1735baf2ad3fSEli Cohen return PTR_ERR(ndev->rxft); 1736baf2ad3fSEli Cohen } 173729422100SEli Cohen mlx5_vdpa_add_rx_flow_table(ndev); 1738baf2ad3fSEli Cohen 1739baf2ad3fSEli Cohen err = mac_vlan_add(ndev, ndev->config.mac, 0, false); 1740baf2ad3fSEli Cohen if (err) 1741baf2ad3fSEli Cohen goto err_add; 1742baf2ad3fSEli Cohen 1743baf2ad3fSEli Cohen return 0; 1744baf2ad3fSEli Cohen 1745baf2ad3fSEli Cohen err_add: 174629422100SEli Cohen mlx5_vdpa_remove_rx_flow_table(ndev); 1747baf2ad3fSEli Cohen mlx5_destroy_flow_table(ndev->rxft); 1748baf2ad3fSEli Cohen return err; 1749baf2ad3fSEli Cohen } 1750baf2ad3fSEli Cohen 1751baf2ad3fSEli Cohen static void teardown_steering(struct mlx5_vdpa_net *ndev) 1752baf2ad3fSEli Cohen { 1753baf2ad3fSEli Cohen clear_mac_vlan_table(ndev); 175429422100SEli Cohen mlx5_vdpa_remove_rx_flow_table(ndev); 17551a86b377SEli Cohen mlx5_destroy_flow_table(ndev->rxft); 17561a86b377SEli Cohen } 17571a86b377SEli Cohen 17585262912eSEli Cohen static virtio_net_ctrl_ack handle_ctrl_mac(struct mlx5_vdpa_dev *mvdev, u8 cmd) 17595262912eSEli Cohen { 17605262912eSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 17615262912eSEli Cohen struct mlx5_control_vq *cvq = &mvdev->cvq; 17625262912eSEli Cohen virtio_net_ctrl_ack status = VIRTIO_NET_ERR; 17635262912eSEli Cohen struct mlx5_core_dev *pfmdev; 17645262912eSEli Cohen size_t read; 1765f1781bedSMichael Qiu u8 mac[ETH_ALEN], mac_back[ETH_ALEN]; 17665262912eSEli Cohen 17675262912eSEli Cohen pfmdev = pci_get_drvdata(pci_physfn(mvdev->mdev->pdev)); 17685262912eSEli Cohen switch (cmd) { 17695262912eSEli Cohen case VIRTIO_NET_CTRL_MAC_ADDR_SET: 17705262912eSEli Cohen read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, (void *)mac, ETH_ALEN); 17715262912eSEli Cohen if (read != ETH_ALEN) 17725262912eSEli Cohen break; 17735262912eSEli Cohen 17745262912eSEli Cohen if (!memcmp(ndev->config.mac, mac, 6)) { 17755262912eSEli Cohen status = VIRTIO_NET_OK; 17765262912eSEli Cohen break; 17775262912eSEli Cohen } 17785262912eSEli Cohen 1779f1781bedSMichael Qiu if (is_zero_ether_addr(mac)) 1780f1781bedSMichael Qiu break; 1781f1781bedSMichael Qiu 17825262912eSEli Cohen if (!is_zero_ether_addr(ndev->config.mac)) { 17835262912eSEli Cohen if (mlx5_mpfs_del_mac(pfmdev, ndev->config.mac)) { 17845262912eSEli Cohen mlx5_vdpa_warn(mvdev, "failed to delete old MAC %pM from MPFS table\n", 17855262912eSEli Cohen ndev->config.mac); 17865262912eSEli Cohen break; 17875262912eSEli Cohen } 17885262912eSEli Cohen } 17895262912eSEli Cohen 17905262912eSEli Cohen if (mlx5_mpfs_add_mac(pfmdev, mac)) { 17915262912eSEli Cohen mlx5_vdpa_warn(mvdev, "failed to insert new MAC %pM into MPFS table\n", 17925262912eSEli Cohen mac); 17935262912eSEli Cohen break; 17945262912eSEli Cohen } 17955262912eSEli Cohen 1796f1781bedSMichael Qiu /* backup the original mac address so that if failed to add the forward rules 1797f1781bedSMichael Qiu * we could restore it 1798f1781bedSMichael Qiu */ 1799f1781bedSMichael Qiu memcpy(mac_back, ndev->config.mac, ETH_ALEN); 1800f1781bedSMichael Qiu 18015262912eSEli Cohen memcpy(ndev->config.mac, mac, ETH_ALEN); 1802f1781bedSMichael Qiu 1803f1781bedSMichael Qiu /* Need recreate the flow table entry, so that the packet could forward back 1804f1781bedSMichael Qiu */ 18051ab53760SEli Cohen mac_vlan_del(ndev, mac_back, 0, false); 1806f1781bedSMichael Qiu 1807baf2ad3fSEli Cohen if (mac_vlan_add(ndev, ndev->config.mac, 0, false)) { 1808f1781bedSMichael Qiu mlx5_vdpa_warn(mvdev, "failed to insert forward rules, try to restore\n"); 1809f1781bedSMichael Qiu 1810f1781bedSMichael Qiu /* Although it hardly run here, we still need double check */ 1811f1781bedSMichael Qiu if (is_zero_ether_addr(mac_back)) { 1812f1781bedSMichael Qiu mlx5_vdpa_warn(mvdev, "restore mac failed: Original MAC is zero\n"); 1813f1781bedSMichael Qiu break; 1814f1781bedSMichael Qiu } 1815f1781bedSMichael Qiu 1816f1781bedSMichael Qiu /* Try to restore original mac address to MFPS table, and try to restore 1817f1781bedSMichael Qiu * the forward rule entry. 1818f1781bedSMichael Qiu */ 1819f1781bedSMichael Qiu if (mlx5_mpfs_del_mac(pfmdev, ndev->config.mac)) { 1820f1781bedSMichael Qiu mlx5_vdpa_warn(mvdev, "restore mac failed: delete MAC %pM from MPFS table failed\n", 1821f1781bedSMichael Qiu ndev->config.mac); 1822f1781bedSMichael Qiu } 1823f1781bedSMichael Qiu 1824f1781bedSMichael Qiu if (mlx5_mpfs_add_mac(pfmdev, mac_back)) { 1825f1781bedSMichael Qiu mlx5_vdpa_warn(mvdev, "restore mac failed: insert old MAC %pM into MPFS table failed\n", 1826f1781bedSMichael Qiu mac_back); 1827f1781bedSMichael Qiu } 1828f1781bedSMichael Qiu 1829f1781bedSMichael Qiu memcpy(ndev->config.mac, mac_back, ETH_ALEN); 1830f1781bedSMichael Qiu 1831baf2ad3fSEli Cohen if (mac_vlan_add(ndev, ndev->config.mac, 0, false)) 1832f1781bedSMichael Qiu mlx5_vdpa_warn(mvdev, "restore forward rules failed: insert forward rules failed\n"); 1833f1781bedSMichael Qiu 1834f1781bedSMichael Qiu break; 1835f1781bedSMichael Qiu } 1836f1781bedSMichael Qiu 18375262912eSEli Cohen status = VIRTIO_NET_OK; 18385262912eSEli Cohen break; 18395262912eSEli Cohen 18405262912eSEli Cohen default: 18415262912eSEli Cohen break; 18425262912eSEli Cohen } 18435262912eSEli Cohen 18445262912eSEli Cohen return status; 18455262912eSEli Cohen } 18465262912eSEli Cohen 184752893733SEli Cohen static int change_num_qps(struct mlx5_vdpa_dev *mvdev, int newqps) 184852893733SEli Cohen { 184952893733SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 185052893733SEli Cohen int cur_qps = ndev->cur_num_vqs / 2; 185152893733SEli Cohen int err; 185252893733SEli Cohen int i; 185352893733SEli Cohen 185452893733SEli Cohen if (cur_qps > newqps) { 185552893733SEli Cohen err = modify_rqt(ndev, 2 * newqps); 185652893733SEli Cohen if (err) 185752893733SEli Cohen return err; 185852893733SEli Cohen 185952893733SEli Cohen for (i = ndev->cur_num_vqs - 1; i >= 2 * newqps; i--) 186052893733SEli Cohen teardown_vq(ndev, &ndev->vqs[i]); 186152893733SEli Cohen 186252893733SEli Cohen ndev->cur_num_vqs = 2 * newqps; 186352893733SEli Cohen } else { 186452893733SEli Cohen ndev->cur_num_vqs = 2 * newqps; 186552893733SEli Cohen for (i = cur_qps * 2; i < 2 * newqps; i++) { 186652893733SEli Cohen err = setup_vq(ndev, &ndev->vqs[i]); 186752893733SEli Cohen if (err) 186852893733SEli Cohen goto clean_added; 186952893733SEli Cohen } 187052893733SEli Cohen err = modify_rqt(ndev, 2 * newqps); 187152893733SEli Cohen if (err) 187252893733SEli Cohen goto clean_added; 187352893733SEli Cohen } 187452893733SEli Cohen return 0; 187552893733SEli Cohen 187652893733SEli Cohen clean_added: 187737e07e70SEli Cohen for (--i; i >= 2 * cur_qps; --i) 187852893733SEli Cohen teardown_vq(ndev, &ndev->vqs[i]); 187952893733SEli Cohen 188037e07e70SEli Cohen ndev->cur_num_vqs = 2 * cur_qps; 188137e07e70SEli Cohen 188252893733SEli Cohen return err; 188352893733SEli Cohen } 188452893733SEli Cohen 188552893733SEli Cohen static virtio_net_ctrl_ack handle_ctrl_mq(struct mlx5_vdpa_dev *mvdev, u8 cmd) 188652893733SEli Cohen { 188752893733SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 188852893733SEli Cohen virtio_net_ctrl_ack status = VIRTIO_NET_ERR; 188952893733SEli Cohen struct mlx5_control_vq *cvq = &mvdev->cvq; 189052893733SEli Cohen struct virtio_net_ctrl_mq mq; 189152893733SEli Cohen size_t read; 189252893733SEli Cohen u16 newqps; 189352893733SEli Cohen 189452893733SEli Cohen switch (cmd) { 189552893733SEli Cohen case VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET: 1896ed0f849fSSi-Wei Liu /* This mq feature check aligns with pre-existing userspace 1897ed0f849fSSi-Wei Liu * implementation. 1898ed0f849fSSi-Wei Liu * 1899ed0f849fSSi-Wei Liu * Without it, an untrusted driver could fake a multiqueue config 1900ed0f849fSSi-Wei Liu * request down to a non-mq device that may cause kernel to 1901ed0f849fSSi-Wei Liu * panic due to uninitialized resources for extra vqs. Even with 1902ed0f849fSSi-Wei Liu * a well behaving guest driver, it is not expected to allow 1903ed0f849fSSi-Wei Liu * changing the number of vqs on a non-mq device. 1904ed0f849fSSi-Wei Liu */ 1905ed0f849fSSi-Wei Liu if (!MLX5_FEATURE(mvdev, VIRTIO_NET_F_MQ)) 1906ed0f849fSSi-Wei Liu break; 1907ed0f849fSSi-Wei Liu 190852893733SEli Cohen read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, (void *)&mq, sizeof(mq)); 190952893733SEli Cohen if (read != sizeof(mq)) 191052893733SEli Cohen break; 191152893733SEli Cohen 191252893733SEli Cohen newqps = mlx5vdpa16_to_cpu(mvdev, mq.virtqueue_pairs); 1913ed0f849fSSi-Wei Liu if (newqps < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN || 1914acde3929SEli Cohen newqps > ndev->rqt_size) 1915ed0f849fSSi-Wei Liu break; 1916ed0f849fSSi-Wei Liu 191752893733SEli Cohen if (ndev->cur_num_vqs == 2 * newqps) { 191852893733SEli Cohen status = VIRTIO_NET_OK; 191952893733SEli Cohen break; 192052893733SEli Cohen } 192152893733SEli Cohen 192252893733SEli Cohen if (!change_num_qps(mvdev, newqps)) 192352893733SEli Cohen status = VIRTIO_NET_OK; 192452893733SEli Cohen 192552893733SEli Cohen break; 192652893733SEli Cohen default: 192752893733SEli Cohen break; 192852893733SEli Cohen } 192952893733SEli Cohen 193052893733SEli Cohen return status; 193152893733SEli Cohen } 193252893733SEli Cohen 1933baf2ad3fSEli Cohen static virtio_net_ctrl_ack handle_ctrl_vlan(struct mlx5_vdpa_dev *mvdev, u8 cmd) 1934baf2ad3fSEli Cohen { 1935baf2ad3fSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 1936baf2ad3fSEli Cohen virtio_net_ctrl_ack status = VIRTIO_NET_ERR; 1937baf2ad3fSEli Cohen struct mlx5_control_vq *cvq = &mvdev->cvq; 1938baf2ad3fSEli Cohen __virtio16 vlan; 1939baf2ad3fSEli Cohen size_t read; 1940baf2ad3fSEli Cohen u16 id; 1941baf2ad3fSEli Cohen 19425aec8049SEli Cohen if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VLAN))) 19435aec8049SEli Cohen return status; 19445aec8049SEli Cohen 1945baf2ad3fSEli Cohen switch (cmd) { 1946baf2ad3fSEli Cohen case VIRTIO_NET_CTRL_VLAN_ADD: 1947baf2ad3fSEli Cohen read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, &vlan, sizeof(vlan)); 1948baf2ad3fSEli Cohen if (read != sizeof(vlan)) 1949baf2ad3fSEli Cohen break; 1950baf2ad3fSEli Cohen 1951baf2ad3fSEli Cohen id = mlx5vdpa16_to_cpu(mvdev, vlan); 1952baf2ad3fSEli Cohen if (mac_vlan_add(ndev, ndev->config.mac, id, true)) 1953baf2ad3fSEli Cohen break; 1954baf2ad3fSEli Cohen 1955baf2ad3fSEli Cohen status = VIRTIO_NET_OK; 1956baf2ad3fSEli Cohen break; 1957baf2ad3fSEli Cohen case VIRTIO_NET_CTRL_VLAN_DEL: 1958baf2ad3fSEli Cohen read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, &vlan, sizeof(vlan)); 1959baf2ad3fSEli Cohen if (read != sizeof(vlan)) 1960baf2ad3fSEli Cohen break; 1961baf2ad3fSEli Cohen 1962baf2ad3fSEli Cohen id = mlx5vdpa16_to_cpu(mvdev, vlan); 1963baf2ad3fSEli Cohen mac_vlan_del(ndev, ndev->config.mac, id, true); 1964f766c409SDan Carpenter status = VIRTIO_NET_OK; 1965baf2ad3fSEli Cohen break; 1966baf2ad3fSEli Cohen default: 1967baf2ad3fSEli Cohen break; 1968baf2ad3fSEli Cohen } 1969baf2ad3fSEli Cohen 1970baf2ad3fSEli Cohen return status; 1971baf2ad3fSEli Cohen } 1972baf2ad3fSEli Cohen 19735262912eSEli Cohen static void mlx5_cvq_kick_handler(struct work_struct *work) 19745262912eSEli Cohen { 19755262912eSEli Cohen virtio_net_ctrl_ack status = VIRTIO_NET_ERR; 19765262912eSEli Cohen struct virtio_net_ctrl_hdr ctrl; 1977218bdd20SEli Cohen struct mlx5_vdpa_wq_ent *wqent; 19785262912eSEli Cohen struct mlx5_vdpa_dev *mvdev; 19795262912eSEli Cohen struct mlx5_control_vq *cvq; 19805262912eSEli Cohen struct mlx5_vdpa_net *ndev; 19815262912eSEli Cohen size_t read, write; 19825262912eSEli Cohen int err; 19835262912eSEli Cohen 1984218bdd20SEli Cohen wqent = container_of(work, struct mlx5_vdpa_wq_ent, work); 19855262912eSEli Cohen mvdev = wqent->mvdev; 19865262912eSEli Cohen ndev = to_mlx5_vdpa_ndev(mvdev); 19875262912eSEli Cohen cvq = &mvdev->cvq; 19881c80cf03SJason Wang 1989759ae7f9SEli Cohen down_write(&ndev->reslock); 19901c80cf03SJason Wang 19911c80cf03SJason Wang if (!(mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) 19921c80cf03SJason Wang goto out; 19931c80cf03SJason Wang 19945262912eSEli Cohen if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) 19951c80cf03SJason Wang goto out; 19965262912eSEli Cohen 19975262912eSEli Cohen if (!cvq->ready) 19981c80cf03SJason Wang goto out; 19995262912eSEli Cohen 20005262912eSEli Cohen while (true) { 20015262912eSEli Cohen err = vringh_getdesc_iotlb(&cvq->vring, &cvq->riov, &cvq->wiov, &cvq->head, 20025262912eSEli Cohen GFP_ATOMIC); 20035262912eSEli Cohen if (err <= 0) 20045262912eSEli Cohen break; 20055262912eSEli Cohen 20065262912eSEli Cohen read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, &ctrl, sizeof(ctrl)); 20075262912eSEli Cohen if (read != sizeof(ctrl)) 20085262912eSEli Cohen break; 20095262912eSEli Cohen 20101892a3d4SEli Cohen cvq->received_desc++; 20115262912eSEli Cohen switch (ctrl.class) { 20125262912eSEli Cohen case VIRTIO_NET_CTRL_MAC: 20135262912eSEli Cohen status = handle_ctrl_mac(mvdev, ctrl.cmd); 20145262912eSEli Cohen break; 201552893733SEli Cohen case VIRTIO_NET_CTRL_MQ: 201652893733SEli Cohen status = handle_ctrl_mq(mvdev, ctrl.cmd); 201752893733SEli Cohen break; 2018baf2ad3fSEli Cohen case VIRTIO_NET_CTRL_VLAN: 2019baf2ad3fSEli Cohen status = handle_ctrl_vlan(mvdev, ctrl.cmd); 2020baf2ad3fSEli Cohen break; 20215262912eSEli Cohen default: 20225262912eSEli Cohen break; 20235262912eSEli Cohen } 20245262912eSEli Cohen 20255262912eSEli Cohen /* Make sure data is written before advancing index */ 20265262912eSEli Cohen smp_wmb(); 20275262912eSEli Cohen 20285262912eSEli Cohen write = vringh_iov_push_iotlb(&cvq->vring, &cvq->wiov, &status, sizeof(status)); 20295262912eSEli Cohen vringh_complete_iotlb(&cvq->vring, cvq->head, write); 20305262912eSEli Cohen vringh_kiov_cleanup(&cvq->riov); 20315262912eSEli Cohen vringh_kiov_cleanup(&cvq->wiov); 20325262912eSEli Cohen 20335262912eSEli Cohen if (vringh_need_notify_iotlb(&cvq->vring)) 20345262912eSEli Cohen vringh_notify(&cvq->vring); 203555ebf0d6SJason Wang 20361892a3d4SEli Cohen cvq->completed_desc++; 203755ebf0d6SJason Wang queue_work(mvdev->wq, &wqent->work); 203855ebf0d6SJason Wang break; 20395262912eSEli Cohen } 20401c80cf03SJason Wang 20411c80cf03SJason Wang out: 2042759ae7f9SEli Cohen up_write(&ndev->reslock); 20435262912eSEli Cohen } 20445262912eSEli Cohen 20451a86b377SEli Cohen static void mlx5_vdpa_kick_vq(struct vdpa_device *vdev, u16 idx) 20461a86b377SEli Cohen { 20471a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 20481a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 20495262912eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 20501a86b377SEli Cohen 2051e4fc6650SEli Cohen if (!is_index_valid(mvdev, idx)) 2052e4fc6650SEli Cohen return; 2053e4fc6650SEli Cohen 20545262912eSEli Cohen if (unlikely(is_ctrl_vq_idx(mvdev, idx))) { 2055ad6dc1daSEli Cohen if (!mvdev->wq || !mvdev->cvq.ready) 20565262912eSEli Cohen return; 20575262912eSEli Cohen 205855ebf0d6SJason Wang queue_work(mvdev->wq, &ndev->cvq_ent.work); 20595262912eSEli Cohen return; 20605262912eSEli Cohen } 20615262912eSEli Cohen 20625262912eSEli Cohen mvq = &ndev->vqs[idx]; 20631a86b377SEli Cohen if (unlikely(!mvq->ready)) 20641a86b377SEli Cohen return; 20651a86b377SEli Cohen 20661a86b377SEli Cohen iowrite16(idx, ndev->mvdev.res.kick_addr); 20671a86b377SEli Cohen } 20681a86b377SEli Cohen 20691a86b377SEli Cohen static int mlx5_vdpa_set_vq_address(struct vdpa_device *vdev, u16 idx, u64 desc_area, 20701a86b377SEli Cohen u64 driver_area, u64 device_area) 20711a86b377SEli Cohen { 20721a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 20731a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 20745262912eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 20751a86b377SEli Cohen 2076e4fc6650SEli Cohen if (!is_index_valid(mvdev, idx)) 2077e4fc6650SEli Cohen return -EINVAL; 2078e4fc6650SEli Cohen 20795262912eSEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) { 20805262912eSEli Cohen mvdev->cvq.desc_addr = desc_area; 20815262912eSEli Cohen mvdev->cvq.device_addr = device_area; 20825262912eSEli Cohen mvdev->cvq.driver_addr = driver_area; 20835262912eSEli Cohen return 0; 20845262912eSEli Cohen } 20855262912eSEli Cohen 20865262912eSEli Cohen mvq = &ndev->vqs[idx]; 20871a86b377SEli Cohen mvq->desc_addr = desc_area; 20881a86b377SEli Cohen mvq->device_addr = device_area; 20891a86b377SEli Cohen mvq->driver_addr = driver_area; 20901a86b377SEli Cohen return 0; 20911a86b377SEli Cohen } 20921a86b377SEli Cohen 20931a86b377SEli Cohen static void mlx5_vdpa_set_vq_num(struct vdpa_device *vdev, u16 idx, u32 num) 20941a86b377SEli Cohen { 20951a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 20961a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 20971a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq; 20981a86b377SEli Cohen 20995262912eSEli Cohen if (!is_index_valid(mvdev, idx) || is_ctrl_vq_idx(mvdev, idx)) 2100e4fc6650SEli Cohen return; 2101e4fc6650SEli Cohen 21021a86b377SEli Cohen mvq = &ndev->vqs[idx]; 21031a86b377SEli Cohen mvq->num_ent = num; 21041a86b377SEli Cohen } 21051a86b377SEli Cohen 21061a86b377SEli Cohen static void mlx5_vdpa_set_vq_cb(struct vdpa_device *vdev, u16 idx, struct vdpa_callback *cb) 21071a86b377SEli Cohen { 21081a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 21091a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 21101a86b377SEli Cohen 2111db296d25SEli Cohen ndev->event_cbs[idx] = *cb; 211240f2f3e9SEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) 211340f2f3e9SEli Cohen mvdev->cvq.event_cb = *cb; 21141a86b377SEli Cohen } 21151a86b377SEli Cohen 21165262912eSEli Cohen static void mlx5_cvq_notify(struct vringh *vring) 21175262912eSEli Cohen { 21185262912eSEli Cohen struct mlx5_control_vq *cvq = container_of(vring, struct mlx5_control_vq, vring); 21195262912eSEli Cohen 21205262912eSEli Cohen if (!cvq->event_cb.callback) 21215262912eSEli Cohen return; 21225262912eSEli Cohen 21235262912eSEli Cohen cvq->event_cb.callback(cvq->event_cb.private); 21245262912eSEli Cohen } 21255262912eSEli Cohen 21265262912eSEli Cohen static void set_cvq_ready(struct mlx5_vdpa_dev *mvdev, bool ready) 21275262912eSEli Cohen { 21285262912eSEli Cohen struct mlx5_control_vq *cvq = &mvdev->cvq; 21295262912eSEli Cohen 21305262912eSEli Cohen cvq->ready = ready; 21315262912eSEli Cohen if (!ready) 21325262912eSEli Cohen return; 21335262912eSEli Cohen 21345262912eSEli Cohen cvq->vring.notify = mlx5_cvq_notify; 21351a86b377SEli Cohen } 21361a86b377SEli Cohen 21371a86b377SEli Cohen static void mlx5_vdpa_set_vq_ready(struct vdpa_device *vdev, u16 idx, bool ready) 21381a86b377SEli Cohen { 21391a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 21401a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 21415262912eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 2142cae15c2eSEli Cohen int err; 21431a86b377SEli Cohen 2144759be899SEli Cohen if (!mvdev->actual_features) 2145759be899SEli Cohen return; 2146759be899SEli Cohen 2147e4fc6650SEli Cohen if (!is_index_valid(mvdev, idx)) 2148e4fc6650SEli Cohen return; 2149e4fc6650SEli Cohen 21505262912eSEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) { 21515262912eSEli Cohen set_cvq_ready(mvdev, ready); 21525262912eSEli Cohen return; 21535262912eSEli Cohen } 21545262912eSEli Cohen 21555262912eSEli Cohen mvq = &ndev->vqs[idx]; 2156cae15c2eSEli Cohen if (!ready) { 21571a86b377SEli Cohen suspend_vq(ndev, mvq); 2158cae15c2eSEli Cohen } else { 2159cae15c2eSEli Cohen err = modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY); 2160cae15c2eSEli Cohen if (err) { 2161cae15c2eSEli Cohen mlx5_vdpa_warn(mvdev, "modify VQ %d to ready failed (%d)\n", idx, err); 2162cae15c2eSEli Cohen ready = false; 2163cae15c2eSEli Cohen } 2164cae15c2eSEli Cohen } 2165cae15c2eSEli Cohen 21661a86b377SEli Cohen 21671a86b377SEli Cohen mvq->ready = ready; 21681a86b377SEli Cohen } 21691a86b377SEli Cohen 21701a86b377SEli Cohen static bool mlx5_vdpa_get_vq_ready(struct vdpa_device *vdev, u16 idx) 21711a86b377SEli Cohen { 21721a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 21731a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 21741a86b377SEli Cohen 2175e4fc6650SEli Cohen if (!is_index_valid(mvdev, idx)) 2176e4fc6650SEli Cohen return false; 2177e4fc6650SEli Cohen 21785262912eSEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) 21795262912eSEli Cohen return mvdev->cvq.ready; 21805262912eSEli Cohen 21815262912eSEli Cohen return ndev->vqs[idx].ready; 21821a86b377SEli Cohen } 21831a86b377SEli Cohen 21841a86b377SEli Cohen static int mlx5_vdpa_set_vq_state(struct vdpa_device *vdev, u16 idx, 21851a86b377SEli Cohen const struct vdpa_vq_state *state) 21861a86b377SEli Cohen { 21871a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 21881a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 21895262912eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 21901a86b377SEli Cohen 2191e4fc6650SEli Cohen if (!is_index_valid(mvdev, idx)) 2192e4fc6650SEli Cohen return -EINVAL; 2193e4fc6650SEli Cohen 21945262912eSEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) { 21955262912eSEli Cohen mvdev->cvq.vring.last_avail_idx = state->split.avail_index; 21965262912eSEli Cohen return 0; 21975262912eSEli Cohen } 21985262912eSEli Cohen 21995262912eSEli Cohen mvq = &ndev->vqs[idx]; 22001a86b377SEli Cohen if (mvq->fw_state == MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY) { 22011a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "can't modify available index\n"); 22021a86b377SEli Cohen return -EINVAL; 22031a86b377SEli Cohen } 22041a86b377SEli Cohen 2205530a5678SJason Wang mvq->used_idx = state->split.avail_index; 2206530a5678SJason Wang mvq->avail_idx = state->split.avail_index; 22071a86b377SEli Cohen return 0; 22081a86b377SEli Cohen } 22091a86b377SEli Cohen 22101a86b377SEli Cohen static int mlx5_vdpa_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa_vq_state *state) 22111a86b377SEli Cohen { 22121a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 22131a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 22145262912eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 22151a86b377SEli Cohen struct mlx5_virtq_attr attr; 22161a86b377SEli Cohen int err; 22171a86b377SEli Cohen 2218e4fc6650SEli Cohen if (!is_index_valid(mvdev, idx)) 2219e4fc6650SEli Cohen return -EINVAL; 2220e4fc6650SEli Cohen 22215262912eSEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) { 22225262912eSEli Cohen state->split.avail_index = mvdev->cvq.vring.last_avail_idx; 22235262912eSEli Cohen return 0; 22245262912eSEli Cohen } 22255262912eSEli Cohen 22265262912eSEli Cohen mvq = &ndev->vqs[idx]; 22273176e974SSi-Wei Liu /* If the virtq object was destroyed, use the value saved at 22283176e974SSi-Wei Liu * the last minute of suspend_vq. This caters for userspace 22293176e974SSi-Wei Liu * that cares about emulating the index after vq is stopped. 22303176e974SSi-Wei Liu */ 22313176e974SSi-Wei Liu if (!mvq->initialized) { 2232bc04d93eSEli Cohen /* Firmware returns a wrong value for the available index. 2233bc04d93eSEli Cohen * Since both values should be identical, we take the value of 2234bc04d93eSEli Cohen * used_idx which is reported correctly. 2235bc04d93eSEli Cohen */ 2236530a5678SJason Wang state->split.avail_index = mvq->used_idx; 22373176e974SSi-Wei Liu return 0; 22383176e974SSi-Wei Liu } 22391a86b377SEli Cohen 22401a86b377SEli Cohen err = query_virtqueue(ndev, mvq, &attr); 22411a86b377SEli Cohen if (err) { 22421a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "failed to query virtqueue\n"); 22431a86b377SEli Cohen return err; 22441a86b377SEli Cohen } 2245530a5678SJason Wang state->split.avail_index = attr.used_index; 22461a86b377SEli Cohen return 0; 22471a86b377SEli Cohen } 22481a86b377SEli Cohen 22491a86b377SEli Cohen static u32 mlx5_vdpa_get_vq_align(struct vdpa_device *vdev) 22501a86b377SEli Cohen { 22511a86b377SEli Cohen return PAGE_SIZE; 22521a86b377SEli Cohen } 22531a86b377SEli Cohen 22548fcd20c3SEli Cohen static u32 mlx5_vdpa_get_vq_group(struct vdpa_device *vdev, u16 idx) 2255d4821902SGautam Dawar { 22568fcd20c3SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 22578fcd20c3SEli Cohen 22588fcd20c3SEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) 22598fcd20c3SEli Cohen return MLX5_VDPA_CVQ_GROUP; 22608fcd20c3SEli Cohen 22618fcd20c3SEli Cohen return MLX5_VDPA_DATAVQ_GROUP; 2262d4821902SGautam Dawar } 2263d4821902SGautam Dawar 22641a86b377SEli Cohen static u64 mlx_to_vritio_features(u16 dev_features) 22651a86b377SEli Cohen { 22661a86b377SEli Cohen u64 result = 0; 22671a86b377SEli Cohen 2268e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_MRG_RXBUF)) 2269e9d67e59SEli Cohen result |= BIT_ULL(VIRTIO_NET_F_MRG_RXBUF); 2270e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_ECN)) 2271e9d67e59SEli Cohen result |= BIT_ULL(VIRTIO_NET_F_HOST_ECN); 2272e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_ECN)) 2273e9d67e59SEli Cohen result |= BIT_ULL(VIRTIO_NET_F_GUEST_ECN); 2274e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_TSO6)) 2275e9d67e59SEli Cohen result |= BIT_ULL(VIRTIO_NET_F_GUEST_TSO6); 2276e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_TSO4)) 2277e9d67e59SEli Cohen result |= BIT_ULL(VIRTIO_NET_F_GUEST_TSO4); 2278e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_CSUM)) 2279cbb52359SNathan Chancellor result |= BIT_ULL(VIRTIO_NET_F_GUEST_CSUM); 2280e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_CSUM)) 2281cbb52359SNathan Chancellor result |= BIT_ULL(VIRTIO_NET_F_CSUM); 2282e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_TSO6)) 2283cbb52359SNathan Chancellor result |= BIT_ULL(VIRTIO_NET_F_HOST_TSO6); 2284e9d67e59SEli Cohen if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_TSO4)) 2285cbb52359SNathan Chancellor result |= BIT_ULL(VIRTIO_NET_F_HOST_TSO4); 22861a86b377SEli Cohen 22871a86b377SEli Cohen return result; 22881a86b377SEli Cohen } 22891a86b377SEli Cohen 229079de65edSEli Cohen static u64 get_supported_features(struct mlx5_core_dev *mdev) 229179de65edSEli Cohen { 229279de65edSEli Cohen u64 mlx_vdpa_features = 0; 229379de65edSEli Cohen u16 dev_features; 229479de65edSEli Cohen 229579de65edSEli Cohen dev_features = MLX5_CAP_DEV_VDPA_EMULATION(mdev, device_features_bits_mask); 229679de65edSEli Cohen mlx_vdpa_features |= mlx_to_vritio_features(dev_features); 229779de65edSEli Cohen if (MLX5_CAP_DEV_VDPA_EMULATION(mdev, virtio_version_1_0)) 229879de65edSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_F_VERSION_1); 229979de65edSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_F_ACCESS_PLATFORM); 230079de65edSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_CTRL_VQ); 230179de65edSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR); 230279de65edSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_MQ); 230379de65edSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_STATUS); 230479de65edSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_MTU); 2305baf2ad3fSEli Cohen mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_CTRL_VLAN); 2306deeacf35SSi-Wei Liu mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_MAC); 230779de65edSEli Cohen 230879de65edSEli Cohen return mlx_vdpa_features; 230979de65edSEli Cohen } 231079de65edSEli Cohen 2311a64917bcSEli Cohen static u64 mlx5_vdpa_get_device_features(struct vdpa_device *vdev) 23121a86b377SEli Cohen { 23131a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 23141a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 23155262912eSEli Cohen 23161a86b377SEli Cohen print_features(mvdev, ndev->mvdev.mlx_features, false); 23171a86b377SEli Cohen return ndev->mvdev.mlx_features; 23181a86b377SEli Cohen } 23191a86b377SEli Cohen 232030c22f38SSi-Wei Liu static int verify_driver_features(struct mlx5_vdpa_dev *mvdev, u64 features) 23211a86b377SEli Cohen { 232230c22f38SSi-Wei Liu /* Minimum features to expect */ 2323cbb52359SNathan Chancellor if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM))) 23241a86b377SEli Cohen return -EOPNOTSUPP; 23251a86b377SEli Cohen 232630c22f38SSi-Wei Liu /* Double check features combination sent down by the driver. 232730c22f38SSi-Wei Liu * Fail invalid features due to absence of the depended feature. 232830c22f38SSi-Wei Liu * 232930c22f38SSi-Wei Liu * Per VIRTIO v1.1 specification, section 5.1.3.1 Feature bit 233030c22f38SSi-Wei Liu * requirements: "VIRTIO_NET_F_MQ Requires VIRTIO_NET_F_CTRL_VQ". 233130c22f38SSi-Wei Liu * By failing the invalid features sent down by untrusted drivers, 233230c22f38SSi-Wei Liu * we're assured the assumption made upon is_index_valid() and 233330c22f38SSi-Wei Liu * is_ctrl_vq_idx() will not be compromised. 233430c22f38SSi-Wei Liu */ 233530c22f38SSi-Wei Liu if ((features & (BIT_ULL(VIRTIO_NET_F_MQ) | BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) == 233630c22f38SSi-Wei Liu BIT_ULL(VIRTIO_NET_F_MQ)) 233730c22f38SSi-Wei Liu return -EINVAL; 233830c22f38SSi-Wei Liu 23391a86b377SEli Cohen return 0; 23401a86b377SEli Cohen } 23411a86b377SEli Cohen 2342ae0428deSEli Cohen static int setup_virtqueues(struct mlx5_vdpa_dev *mvdev) 23431a86b377SEli Cohen { 2344ae0428deSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 23451a86b377SEli Cohen int err; 23461a86b377SEli Cohen int i; 23471a86b377SEli Cohen 2348acde3929SEli Cohen for (i = 0; i < mvdev->max_vqs; i++) { 23491a86b377SEli Cohen err = setup_vq(ndev, &ndev->vqs[i]); 23501a86b377SEli Cohen if (err) 23511a86b377SEli Cohen goto err_vq; 23521a86b377SEli Cohen } 23531a86b377SEli Cohen 23541a86b377SEli Cohen return 0; 23551a86b377SEli Cohen 23561a86b377SEli Cohen err_vq: 23571a86b377SEli Cohen for (--i; i >= 0; i--) 23581a86b377SEli Cohen teardown_vq(ndev, &ndev->vqs[i]); 23591a86b377SEli Cohen 23601a86b377SEli Cohen return err; 23611a86b377SEli Cohen } 23621a86b377SEli Cohen 23631a86b377SEli Cohen static void teardown_virtqueues(struct mlx5_vdpa_net *ndev) 23641a86b377SEli Cohen { 23651a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq; 23661a86b377SEli Cohen int i; 23671a86b377SEli Cohen 23681a86b377SEli Cohen for (i = ndev->mvdev.max_vqs - 1; i >= 0; i--) { 23691a86b377SEli Cohen mvq = &ndev->vqs[i]; 23701a86b377SEli Cohen if (!mvq->initialized) 23711a86b377SEli Cohen continue; 23721a86b377SEli Cohen 23731a86b377SEli Cohen teardown_vq(ndev, mvq); 23741a86b377SEli Cohen } 23751a86b377SEli Cohen } 23761a86b377SEli Cohen 2377e4fc6650SEli Cohen static void update_cvq_info(struct mlx5_vdpa_dev *mvdev) 23788a7c3213SMichael S. Tsirkin { 2379e4fc6650SEli Cohen if (MLX5_FEATURE(mvdev, VIRTIO_NET_F_CTRL_VQ)) { 2380e4fc6650SEli Cohen if (MLX5_FEATURE(mvdev, VIRTIO_NET_F_MQ)) { 2381e4fc6650SEli Cohen /* MQ supported. CVQ index is right above the last data virtqueue's */ 2382e4fc6650SEli Cohen mvdev->max_idx = mvdev->max_vqs; 2383e4fc6650SEli Cohen } else { 2384e4fc6650SEli Cohen /* Only CVQ supportted. data virtqueues occupy indices 0 and 1. 2385e4fc6650SEli Cohen * CVQ gets index 2 2386e4fc6650SEli Cohen */ 2387e4fc6650SEli Cohen mvdev->max_idx = 2; 23888a7c3213SMichael S. Tsirkin } 2389e4fc6650SEli Cohen } else { 2390e4fc6650SEli Cohen /* Two data virtqueues only: one for rx and one for tx */ 2391e4fc6650SEli Cohen mvdev->max_idx = 1; 2392e4fc6650SEli Cohen } 239336bdcf31SEli Cohen } 239436bdcf31SEli Cohen 2395c384c240SEli Cohen static u8 query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport) 2396c384c240SEli Cohen { 2397c384c240SEli Cohen u32 out[MLX5_ST_SZ_DW(query_vport_state_out)] = {}; 2398c384c240SEli Cohen u32 in[MLX5_ST_SZ_DW(query_vport_state_in)] = {}; 2399c384c240SEli Cohen int err; 2400c384c240SEli Cohen 2401c384c240SEli Cohen MLX5_SET(query_vport_state_in, in, opcode, MLX5_CMD_OP_QUERY_VPORT_STATE); 2402c384c240SEli Cohen MLX5_SET(query_vport_state_in, in, op_mod, opmod); 2403c384c240SEli Cohen MLX5_SET(query_vport_state_in, in, vport_number, vport); 2404c384c240SEli Cohen if (vport) 2405c384c240SEli Cohen MLX5_SET(query_vport_state_in, in, other_vport, 1); 2406c384c240SEli Cohen 2407c384c240SEli Cohen err = mlx5_cmd_exec_inout(mdev, query_vport_state, in, out); 2408c384c240SEli Cohen if (err) 2409c384c240SEli Cohen return 0; 2410c384c240SEli Cohen 2411c384c240SEli Cohen return MLX5_GET(query_vport_state_out, out, state); 2412c384c240SEli Cohen } 2413c384c240SEli Cohen 2414c384c240SEli Cohen static bool get_link_state(struct mlx5_vdpa_dev *mvdev) 2415c384c240SEli Cohen { 2416c384c240SEli Cohen if (query_vport_state(mvdev->mdev, MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT, 0) == 2417c384c240SEli Cohen VPORT_STATE_UP) 2418c384c240SEli Cohen return true; 2419c384c240SEli Cohen 2420c384c240SEli Cohen return false; 2421c384c240SEli Cohen } 2422c384c240SEli Cohen 2423c384c240SEli Cohen static void update_carrier(struct work_struct *work) 2424c384c240SEli Cohen { 2425c384c240SEli Cohen struct mlx5_vdpa_wq_ent *wqent; 2426c384c240SEli Cohen struct mlx5_vdpa_dev *mvdev; 2427c384c240SEli Cohen struct mlx5_vdpa_net *ndev; 2428c384c240SEli Cohen 2429c384c240SEli Cohen wqent = container_of(work, struct mlx5_vdpa_wq_ent, work); 2430c384c240SEli Cohen mvdev = wqent->mvdev; 2431c384c240SEli Cohen ndev = to_mlx5_vdpa_ndev(mvdev); 2432c384c240SEli Cohen if (get_link_state(mvdev)) 2433c384c240SEli Cohen ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP); 2434c384c240SEli Cohen else 2435c384c240SEli Cohen ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP); 2436c384c240SEli Cohen 2437c384c240SEli Cohen if (ndev->config_cb.callback) 2438c384c240SEli Cohen ndev->config_cb.callback(ndev->config_cb.private); 2439c384c240SEli Cohen 2440c384c240SEli Cohen kfree(wqent); 2441c384c240SEli Cohen } 2442c384c240SEli Cohen 2443c384c240SEli Cohen static int queue_link_work(struct mlx5_vdpa_net *ndev) 2444c384c240SEli Cohen { 2445c384c240SEli Cohen struct mlx5_vdpa_wq_ent *wqent; 2446c384c240SEli Cohen 2447c384c240SEli Cohen wqent = kzalloc(sizeof(*wqent), GFP_ATOMIC); 2448c384c240SEli Cohen if (!wqent) 2449c384c240SEli Cohen return -ENOMEM; 2450c384c240SEli Cohen 2451c384c240SEli Cohen wqent->mvdev = &ndev->mvdev; 2452c384c240SEli Cohen INIT_WORK(&wqent->work, update_carrier); 2453c384c240SEli Cohen queue_work(ndev->mvdev.wq, &wqent->work); 2454c384c240SEli Cohen return 0; 2455c384c240SEli Cohen } 2456c384c240SEli Cohen 2457c384c240SEli Cohen static int event_handler(struct notifier_block *nb, unsigned long event, void *param) 2458c384c240SEli Cohen { 2459c384c240SEli Cohen struct mlx5_vdpa_net *ndev = container_of(nb, struct mlx5_vdpa_net, nb); 2460c384c240SEli Cohen struct mlx5_eqe *eqe = param; 2461c384c240SEli Cohen int ret = NOTIFY_DONE; 2462c384c240SEli Cohen 2463c384c240SEli Cohen if (event == MLX5_EVENT_TYPE_PORT_CHANGE) { 2464c384c240SEli Cohen switch (eqe->sub_type) { 2465c384c240SEli Cohen case MLX5_PORT_CHANGE_SUBTYPE_DOWN: 2466c384c240SEli Cohen case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE: 2467c384c240SEli Cohen if (queue_link_work(ndev)) 2468c384c240SEli Cohen return NOTIFY_DONE; 2469c384c240SEli Cohen 2470c384c240SEli Cohen ret = NOTIFY_OK; 2471c384c240SEli Cohen break; 2472c384c240SEli Cohen default: 2473c384c240SEli Cohen return NOTIFY_DONE; 2474c384c240SEli Cohen } 2475c384c240SEli Cohen return ret; 2476c384c240SEli Cohen } 2477c384c240SEli Cohen return ret; 2478c384c240SEli Cohen } 2479c384c240SEli Cohen 2480c384c240SEli Cohen static void register_link_notifier(struct mlx5_vdpa_net *ndev) 2481c384c240SEli Cohen { 2482c384c240SEli Cohen if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_STATUS))) 2483c384c240SEli Cohen return; 2484c384c240SEli Cohen 2485c384c240SEli Cohen ndev->nb.notifier_call = event_handler; 2486c384c240SEli Cohen mlx5_notifier_register(ndev->mvdev.mdev, &ndev->nb); 2487c384c240SEli Cohen ndev->nb_registered = true; 2488c384c240SEli Cohen queue_link_work(ndev); 2489c384c240SEli Cohen } 2490c384c240SEli Cohen 2491c384c240SEli Cohen static void unregister_link_notifier(struct mlx5_vdpa_net *ndev) 2492c384c240SEli Cohen { 2493c384c240SEli Cohen if (!ndev->nb_registered) 2494c384c240SEli Cohen return; 2495c384c240SEli Cohen 2496c384c240SEli Cohen ndev->nb_registered = false; 2497c384c240SEli Cohen mlx5_notifier_unregister(ndev->mvdev.mdev, &ndev->nb); 2498c384c240SEli Cohen if (ndev->mvdev.wq) 2499c384c240SEli Cohen flush_workqueue(ndev->mvdev.wq); 2500c384c240SEli Cohen } 2501c384c240SEli Cohen 2502a64917bcSEli Cohen static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features) 25031a86b377SEli Cohen { 25041a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 25051a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 25061a86b377SEli Cohen int err; 25071a86b377SEli Cohen 25081a86b377SEli Cohen print_features(mvdev, features, true); 25091a86b377SEli Cohen 251030c22f38SSi-Wei Liu err = verify_driver_features(mvdev, features); 25111a86b377SEli Cohen if (err) 25121a86b377SEli Cohen return err; 25131a86b377SEli Cohen 25141a86b377SEli Cohen ndev->mvdev.actual_features = features & ndev->mvdev.mlx_features; 2515b03fc43eSEli Cohen if (ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_MQ)) 2516acde3929SEli Cohen ndev->rqt_size = mlx5vdpa16_to_cpu(mvdev, ndev->config.max_virtqueue_pairs); 2517b03fc43eSEli Cohen else 2518acde3929SEli Cohen ndev->rqt_size = 1; 2519acde3929SEli Cohen 2520acde3929SEli Cohen ndev->cur_num_vqs = 2 * ndev->rqt_size; 2521b03fc43eSEli Cohen 2522e4fc6650SEli Cohen update_cvq_info(mvdev); 25231a86b377SEli Cohen return err; 25241a86b377SEli Cohen } 25251a86b377SEli Cohen 25261a86b377SEli Cohen static void mlx5_vdpa_set_config_cb(struct vdpa_device *vdev, struct vdpa_callback *cb) 25271a86b377SEli Cohen { 2528edf747afSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 2529edf747afSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 2530edf747afSEli Cohen 2531edf747afSEli Cohen ndev->config_cb = *cb; 25321a86b377SEli Cohen } 25331a86b377SEli Cohen 25341a86b377SEli Cohen #define MLX5_VDPA_MAX_VQ_ENTRIES 256 25351a86b377SEli Cohen static u16 mlx5_vdpa_get_vq_num_max(struct vdpa_device *vdev) 25361a86b377SEli Cohen { 25371a86b377SEli Cohen return MLX5_VDPA_MAX_VQ_ENTRIES; 25381a86b377SEli Cohen } 25391a86b377SEli Cohen 25401a86b377SEli Cohen static u32 mlx5_vdpa_get_device_id(struct vdpa_device *vdev) 25411a86b377SEli Cohen { 25421a86b377SEli Cohen return VIRTIO_ID_NET; 25431a86b377SEli Cohen } 25441a86b377SEli Cohen 25451a86b377SEli Cohen static u32 mlx5_vdpa_get_vendor_id(struct vdpa_device *vdev) 25461a86b377SEli Cohen { 25471a86b377SEli Cohen return PCI_VENDOR_ID_MELLANOX; 25481a86b377SEli Cohen } 25491a86b377SEli Cohen 25501a86b377SEli Cohen static u8 mlx5_vdpa_get_status(struct vdpa_device *vdev) 25511a86b377SEli Cohen { 25521a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 25531a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 25541a86b377SEli Cohen 25551a86b377SEli Cohen print_status(mvdev, ndev->mvdev.status, false); 25561a86b377SEli Cohen return ndev->mvdev.status; 25571a86b377SEli Cohen } 25581a86b377SEli Cohen 25591a86b377SEli Cohen static int save_channel_info(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 25601a86b377SEli Cohen { 25611a86b377SEli Cohen struct mlx5_vq_restore_info *ri = &mvq->ri; 256252893733SEli Cohen struct mlx5_virtq_attr attr = {}; 25631a86b377SEli Cohen int err; 25641a86b377SEli Cohen 256552893733SEli Cohen if (mvq->initialized) { 25661a86b377SEli Cohen err = query_virtqueue(ndev, mvq, &attr); 25671a86b377SEli Cohen if (err) 25681a86b377SEli Cohen return err; 256952893733SEli Cohen } 25701a86b377SEli Cohen 25711a86b377SEli Cohen ri->avail_index = attr.available_index; 2572b35ccebeSEli Cohen ri->used_index = attr.used_index; 25731a86b377SEli Cohen ri->ready = mvq->ready; 25741a86b377SEli Cohen ri->num_ent = mvq->num_ent; 25751a86b377SEli Cohen ri->desc_addr = mvq->desc_addr; 25761a86b377SEli Cohen ri->device_addr = mvq->device_addr; 25771a86b377SEli Cohen ri->driver_addr = mvq->driver_addr; 2578*bc9a2b3eSEli Cohen ri->map = mvq->map; 25791a86b377SEli Cohen ri->restore = true; 25801a86b377SEli Cohen return 0; 25811a86b377SEli Cohen } 25821a86b377SEli Cohen 25831a86b377SEli Cohen static int save_channels_info(struct mlx5_vdpa_net *ndev) 25841a86b377SEli Cohen { 25851a86b377SEli Cohen int i; 25861a86b377SEli Cohen 25871a86b377SEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) { 25881a86b377SEli Cohen memset(&ndev->vqs[i].ri, 0, sizeof(ndev->vqs[i].ri)); 25891a86b377SEli Cohen save_channel_info(ndev, &ndev->vqs[i]); 25901a86b377SEli Cohen } 25911a86b377SEli Cohen return 0; 25921a86b377SEli Cohen } 25931a86b377SEli Cohen 25941a86b377SEli Cohen static void mlx5_clear_vqs(struct mlx5_vdpa_net *ndev) 25951a86b377SEli Cohen { 25961a86b377SEli Cohen int i; 25971a86b377SEli Cohen 25981a86b377SEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) 25991a86b377SEli Cohen memset(&ndev->vqs[i], 0, offsetof(struct mlx5_vdpa_virtqueue, ri)); 26001a86b377SEli Cohen } 26011a86b377SEli Cohen 26021a86b377SEli Cohen static void restore_channels_info(struct mlx5_vdpa_net *ndev) 26031a86b377SEli Cohen { 26041a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq; 26051a86b377SEli Cohen struct mlx5_vq_restore_info *ri; 26061a86b377SEli Cohen int i; 26071a86b377SEli Cohen 26081a86b377SEli Cohen mlx5_clear_vqs(ndev); 26091a86b377SEli Cohen init_mvqs(ndev); 26101a86b377SEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) { 26111a86b377SEli Cohen mvq = &ndev->vqs[i]; 26121a86b377SEli Cohen ri = &mvq->ri; 26131a86b377SEli Cohen if (!ri->restore) 26141a86b377SEli Cohen continue; 26151a86b377SEli Cohen 26161a86b377SEli Cohen mvq->avail_idx = ri->avail_index; 2617b35ccebeSEli Cohen mvq->used_idx = ri->used_index; 26181a86b377SEli Cohen mvq->ready = ri->ready; 26191a86b377SEli Cohen mvq->num_ent = ri->num_ent; 26201a86b377SEli Cohen mvq->desc_addr = ri->desc_addr; 26211a86b377SEli Cohen mvq->device_addr = ri->device_addr; 26221a86b377SEli Cohen mvq->driver_addr = ri->driver_addr; 2623*bc9a2b3eSEli Cohen mvq->map = ri->map; 26241a86b377SEli Cohen } 26251a86b377SEli Cohen } 26261a86b377SEli Cohen 262738fc462fSEli Cohen static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, 262838fc462fSEli Cohen struct vhost_iotlb *iotlb, unsigned int asid) 26291a86b377SEli Cohen { 2630ae0428deSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 26311a86b377SEli Cohen int err; 26321a86b377SEli Cohen 26331a86b377SEli Cohen suspend_vqs(ndev); 26341a86b377SEli Cohen err = save_channels_info(ndev); 26351a86b377SEli Cohen if (err) 26361a86b377SEli Cohen goto err_mr; 26371a86b377SEli Cohen 26381a86b377SEli Cohen teardown_driver(ndev); 2639ae0428deSEli Cohen mlx5_vdpa_destroy_mr(mvdev); 264038fc462fSEli Cohen err = mlx5_vdpa_create_mr(mvdev, iotlb, asid); 26411a86b377SEli Cohen if (err) 26421a86b377SEli Cohen goto err_mr; 26431a86b377SEli Cohen 264409e65ee9SSi-Wei Liu if (!(mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK) || mvdev->suspended) 26451c80cf03SJason Wang goto err_mr; 26461897f0b6SEli Cohen 26471a86b377SEli Cohen restore_channels_info(ndev); 2648ae0428deSEli Cohen err = setup_driver(mvdev); 26491a86b377SEli Cohen if (err) 26501a86b377SEli Cohen goto err_setup; 26511a86b377SEli Cohen 26521a86b377SEli Cohen return 0; 26531a86b377SEli Cohen 26541a86b377SEli Cohen err_setup: 2655ae0428deSEli Cohen mlx5_vdpa_destroy_mr(mvdev); 26561a86b377SEli Cohen err_mr: 26571a86b377SEli Cohen return err; 26581a86b377SEli Cohen } 26591a86b377SEli Cohen 26601c80cf03SJason Wang /* reslock must be held for this function */ 2661ae0428deSEli Cohen static int setup_driver(struct mlx5_vdpa_dev *mvdev) 26621a86b377SEli Cohen { 2663ae0428deSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 26641a86b377SEli Cohen int err; 26651a86b377SEli Cohen 2666759ae7f9SEli Cohen WARN_ON(!rwsem_is_locked(&ndev->reslock)); 26671c80cf03SJason Wang 26681a86b377SEli Cohen if (ndev->setup) { 2669ae0428deSEli Cohen mlx5_vdpa_warn(mvdev, "setup driver called for already setup driver\n"); 26701a86b377SEli Cohen err = 0; 26711a86b377SEli Cohen goto out; 26721a86b377SEli Cohen } 2673f0417e72SEli Cohen mlx5_vdpa_add_debugfs(ndev); 2674ae0428deSEli Cohen err = setup_virtqueues(mvdev); 26751a86b377SEli Cohen if (err) { 2676ae0428deSEli Cohen mlx5_vdpa_warn(mvdev, "setup_virtqueues\n"); 2677f0417e72SEli Cohen goto err_setup; 26781a86b377SEli Cohen } 26791a86b377SEli Cohen 26801a86b377SEli Cohen err = create_rqt(ndev); 26811a86b377SEli Cohen if (err) { 2682ae0428deSEli Cohen mlx5_vdpa_warn(mvdev, "create_rqt\n"); 26831a86b377SEli Cohen goto err_rqt; 26841a86b377SEli Cohen } 26851a86b377SEli Cohen 26861a86b377SEli Cohen err = create_tir(ndev); 26871a86b377SEli Cohen if (err) { 2688ae0428deSEli Cohen mlx5_vdpa_warn(mvdev, "create_tir\n"); 26891a86b377SEli Cohen goto err_tir; 26901a86b377SEli Cohen } 26911a86b377SEli Cohen 2692baf2ad3fSEli Cohen err = setup_steering(ndev); 26931a86b377SEli Cohen if (err) { 2694baf2ad3fSEli Cohen mlx5_vdpa_warn(mvdev, "setup_steering\n"); 26951a86b377SEli Cohen goto err_fwd; 26961a86b377SEli Cohen } 26971a86b377SEli Cohen ndev->setup = true; 26981a86b377SEli Cohen 26991a86b377SEli Cohen return 0; 27001a86b377SEli Cohen 27011a86b377SEli Cohen err_fwd: 27021a86b377SEli Cohen destroy_tir(ndev); 27031a86b377SEli Cohen err_tir: 27041a86b377SEli Cohen destroy_rqt(ndev); 27051a86b377SEli Cohen err_rqt: 27061a86b377SEli Cohen teardown_virtqueues(ndev); 2707f0417e72SEli Cohen err_setup: 2708f0417e72SEli Cohen mlx5_vdpa_remove_debugfs(ndev->debugfs); 27091a86b377SEli Cohen out: 27101a86b377SEli Cohen return err; 27111a86b377SEli Cohen } 27121a86b377SEli Cohen 27131c80cf03SJason Wang /* reslock must be held for this function */ 27141a86b377SEli Cohen static void teardown_driver(struct mlx5_vdpa_net *ndev) 27151a86b377SEli Cohen { 27161c80cf03SJason Wang 2717759ae7f9SEli Cohen WARN_ON(!rwsem_is_locked(&ndev->reslock)); 27181c80cf03SJason Wang 27191a86b377SEli Cohen if (!ndev->setup) 27201c80cf03SJason Wang return; 27211a86b377SEli Cohen 2722f0417e72SEli Cohen mlx5_vdpa_remove_debugfs(ndev->debugfs); 2723f0417e72SEli Cohen ndev->debugfs = NULL; 2724baf2ad3fSEli Cohen teardown_steering(ndev); 27251a86b377SEli Cohen destroy_tir(ndev); 27261a86b377SEli Cohen destroy_rqt(ndev); 27271a86b377SEli Cohen teardown_virtqueues(ndev); 27281a86b377SEli Cohen ndev->setup = false; 27291a86b377SEli Cohen } 27301a86b377SEli Cohen 2731e3aadf2eSEli Cohen static void clear_vqs_ready(struct mlx5_vdpa_net *ndev) 2732e3aadf2eSEli Cohen { 2733e3aadf2eSEli Cohen int i; 2734e3aadf2eSEli Cohen 2735e3aadf2eSEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) 2736e3aadf2eSEli Cohen ndev->vqs[i].ready = false; 2737ef12e4bfSEli Cohen 2738ef12e4bfSEli Cohen ndev->mvdev.cvq.ready = false; 2739e3aadf2eSEli Cohen } 2740e3aadf2eSEli Cohen 2741ace92524SEli Cohen static int setup_cvq_vring(struct mlx5_vdpa_dev *mvdev) 2742ace92524SEli Cohen { 2743ace92524SEli Cohen struct mlx5_control_vq *cvq = &mvdev->cvq; 2744ace92524SEli Cohen int err = 0; 2745ace92524SEli Cohen 2746ace92524SEli Cohen if (mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ)) 2747ace92524SEli Cohen err = vringh_init_iotlb(&cvq->vring, mvdev->actual_features, 2748ace92524SEli Cohen MLX5_CVQ_MAX_ENT, false, 2749ace92524SEli Cohen (struct vring_desc *)(uintptr_t)cvq->desc_addr, 2750ace92524SEli Cohen (struct vring_avail *)(uintptr_t)cvq->driver_addr, 2751ace92524SEli Cohen (struct vring_used *)(uintptr_t)cvq->device_addr); 2752ace92524SEli Cohen 2753ace92524SEli Cohen return err; 2754ace92524SEli Cohen } 2755ace92524SEli Cohen 27561a86b377SEli Cohen static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) 27571a86b377SEli Cohen { 27581a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 27591a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 27601a86b377SEli Cohen int err; 27611a86b377SEli Cohen 27621a86b377SEli Cohen print_status(mvdev, status, true); 27631a86b377SEli Cohen 2764759ae7f9SEli Cohen down_write(&ndev->reslock); 27651c80cf03SJason Wang 27661a86b377SEli Cohen if ((status ^ ndev->mvdev.status) & VIRTIO_CONFIG_S_DRIVER_OK) { 27671a86b377SEli Cohen if (status & VIRTIO_CONFIG_S_DRIVER_OK) { 2768ace92524SEli Cohen err = setup_cvq_vring(mvdev); 2769ace92524SEli Cohen if (err) { 2770ace92524SEli Cohen mlx5_vdpa_warn(mvdev, "failed to setup control VQ vring\n"); 2771ace92524SEli Cohen goto err_setup; 2772ace92524SEli Cohen } 2773c384c240SEli Cohen register_link_notifier(ndev); 2774ae0428deSEli Cohen err = setup_driver(mvdev); 27751a86b377SEli Cohen if (err) { 27761a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "failed to setup driver\n"); 2777c384c240SEli Cohen goto err_driver; 27781a86b377SEli Cohen } 27791a86b377SEli Cohen } else { 27801a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "did not expect DRIVER_OK to be cleared\n"); 27811c80cf03SJason Wang goto err_clear; 27821a86b377SEli Cohen } 27831a86b377SEli Cohen } 27841a86b377SEli Cohen 27851a86b377SEli Cohen ndev->mvdev.status = status; 2786759ae7f9SEli Cohen up_write(&ndev->reslock); 27871a86b377SEli Cohen return; 27881a86b377SEli Cohen 2789c384c240SEli Cohen err_driver: 2790c384c240SEli Cohen unregister_link_notifier(ndev); 27911a86b377SEli Cohen err_setup: 27921a86b377SEli Cohen mlx5_vdpa_destroy_mr(&ndev->mvdev); 27931a86b377SEli Cohen ndev->mvdev.status |= VIRTIO_CONFIG_S_FAILED; 27941c80cf03SJason Wang err_clear: 2795759ae7f9SEli Cohen up_write(&ndev->reslock); 27961a86b377SEli Cohen } 27971a86b377SEli Cohen 27988fcd20c3SEli Cohen static void init_group_to_asid_map(struct mlx5_vdpa_dev *mvdev) 27998fcd20c3SEli Cohen { 28008fcd20c3SEli Cohen int i; 28018fcd20c3SEli Cohen 28028fcd20c3SEli Cohen /* default mapping all groups are mapped to asid 0 */ 28038fcd20c3SEli Cohen for (i = 0; i < MLX5_VDPA_NUMVQ_GROUPS; i++) 28048fcd20c3SEli Cohen mvdev->group2asid[i] = 0; 28058fcd20c3SEli Cohen } 28068fcd20c3SEli Cohen 28070686082dSXie Yongji static int mlx5_vdpa_reset(struct vdpa_device *vdev) 28080686082dSXie Yongji { 28090686082dSXie Yongji struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 28100686082dSXie Yongji struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 28110686082dSXie Yongji 28120686082dSXie Yongji print_status(mvdev, 0, true); 28130686082dSXie Yongji mlx5_vdpa_info(mvdev, "performing device reset\n"); 28141c80cf03SJason Wang 2815759ae7f9SEli Cohen down_write(&ndev->reslock); 2816c384c240SEli Cohen unregister_link_notifier(ndev); 28170686082dSXie Yongji teardown_driver(ndev); 28180686082dSXie Yongji clear_vqs_ready(ndev); 28190686082dSXie Yongji mlx5_vdpa_destroy_mr(&ndev->mvdev); 28200686082dSXie Yongji ndev->mvdev.status = 0; 282109e65ee9SSi-Wei Liu ndev->mvdev.suspended = false; 2822b03fc43eSEli Cohen ndev->cur_num_vqs = 0; 28231892a3d4SEli Cohen ndev->mvdev.cvq.received_desc = 0; 28241892a3d4SEli Cohen ndev->mvdev.cvq.completed_desc = 0; 282575560522SEli Cohen memset(ndev->event_cbs, 0, sizeof(*ndev->event_cbs) * (mvdev->max_vqs + 1)); 28260686082dSXie Yongji ndev->mvdev.actual_features = 0; 28278fcd20c3SEli Cohen init_group_to_asid_map(mvdev); 28280686082dSXie Yongji ++mvdev->generation; 28298fcd20c3SEli Cohen 28300686082dSXie Yongji if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) { 283138fc462fSEli Cohen if (mlx5_vdpa_create_mr(mvdev, NULL, 0)) 28320686082dSXie Yongji mlx5_vdpa_warn(mvdev, "create MR failed\n"); 28330686082dSXie Yongji } 2834759ae7f9SEli Cohen up_write(&ndev->reslock); 28350686082dSXie Yongji 28360686082dSXie Yongji return 0; 28370686082dSXie Yongji } 28380686082dSXie Yongji 2839442706f9SStefano Garzarella static size_t mlx5_vdpa_get_config_size(struct vdpa_device *vdev) 2840442706f9SStefano Garzarella { 2841442706f9SStefano Garzarella return sizeof(struct virtio_net_config); 2842442706f9SStefano Garzarella } 2843442706f9SStefano Garzarella 28441a86b377SEli Cohen static void mlx5_vdpa_get_config(struct vdpa_device *vdev, unsigned int offset, void *buf, 28451a86b377SEli Cohen unsigned int len) 28461a86b377SEli Cohen { 28471a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 28481a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 28491a86b377SEli Cohen 2850dcfde163SStefano Garzarella if (offset + len <= sizeof(struct virtio_net_config)) 28512874211fSDan Carpenter memcpy(buf, (u8 *)&ndev->config + offset, len); 28521a86b377SEli Cohen } 28531a86b377SEli Cohen 28541a86b377SEli Cohen static void mlx5_vdpa_set_config(struct vdpa_device *vdev, unsigned int offset, const void *buf, 28551a86b377SEli Cohen unsigned int len) 28561a86b377SEli Cohen { 28571a86b377SEli Cohen /* not supported */ 28581a86b377SEli Cohen } 28591a86b377SEli Cohen 28601a86b377SEli Cohen static u32 mlx5_vdpa_get_generation(struct vdpa_device *vdev) 28611a86b377SEli Cohen { 28621a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 28631a86b377SEli Cohen 28641a86b377SEli Cohen return mvdev->generation; 28651a86b377SEli Cohen } 28661a86b377SEli Cohen 286738fc462fSEli Cohen static int set_map_data(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb, 286838fc462fSEli Cohen unsigned int asid) 28698fcd20c3SEli Cohen { 28701a86b377SEli Cohen bool change_map; 28711a86b377SEli Cohen int err; 28721a86b377SEli Cohen 287338fc462fSEli Cohen err = mlx5_vdpa_handle_set_map(mvdev, iotlb, &change_map, asid); 28741a86b377SEli Cohen if (err) { 28751a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "set map failed(%d)\n", err); 28768fcd20c3SEli Cohen return err; 28771a86b377SEli Cohen } 28781a86b377SEli Cohen 28791a86b377SEli Cohen if (change_map) 288038fc462fSEli Cohen err = mlx5_vdpa_change_map(mvdev, iotlb, asid); 28811a86b377SEli Cohen 28828fcd20c3SEli Cohen return err; 28838fcd20c3SEli Cohen } 28848fcd20c3SEli Cohen 28858fcd20c3SEli Cohen static int mlx5_vdpa_set_map(struct vdpa_device *vdev, unsigned int asid, 28868fcd20c3SEli Cohen struct vhost_iotlb *iotlb) 28878fcd20c3SEli Cohen { 28888fcd20c3SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 28898fcd20c3SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 289093e530d2SEli Cohen int err = -EINVAL; 28918fcd20c3SEli Cohen 28928fcd20c3SEli Cohen down_write(&ndev->reslock); 289338fc462fSEli Cohen err = set_map_data(mvdev, iotlb, asid); 2894759ae7f9SEli Cohen up_write(&ndev->reslock); 28951c80cf03SJason Wang return err; 28961a86b377SEli Cohen } 28971a86b377SEli Cohen 289836871fb9SJason Wang static struct device *mlx5_get_vq_dma_dev(struct vdpa_device *vdev, u16 idx) 289936871fb9SJason Wang { 290036871fb9SJason Wang struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 290136871fb9SJason Wang 290236871fb9SJason Wang if (is_ctrl_vq_idx(mvdev, idx)) 290336871fb9SJason Wang return &vdev->dev; 290436871fb9SJason Wang 290536871fb9SJason Wang return mvdev->vdev.dma_dev; 290636871fb9SJason Wang } 290736871fb9SJason Wang 2908*bc9a2b3eSEli Cohen static void free_irqs(struct mlx5_vdpa_net *ndev) 2909*bc9a2b3eSEli Cohen { 2910*bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool_entry *ent; 2911*bc9a2b3eSEli Cohen int i; 2912*bc9a2b3eSEli Cohen 2913*bc9a2b3eSEli Cohen if (!msix_mode_supported(&ndev->mvdev)) 2914*bc9a2b3eSEli Cohen return; 2915*bc9a2b3eSEli Cohen 2916*bc9a2b3eSEli Cohen if (!ndev->irqp.entries) 2917*bc9a2b3eSEli Cohen return; 2918*bc9a2b3eSEli Cohen 2919*bc9a2b3eSEli Cohen for (i = ndev->irqp.num_ent - 1; i >= 0; i--) { 2920*bc9a2b3eSEli Cohen ent = ndev->irqp.entries + i; 2921*bc9a2b3eSEli Cohen if (ent->map.virq) 2922*bc9a2b3eSEli Cohen pci_msix_free_irq(ndev->mvdev.mdev->pdev, ent->map); 2923*bc9a2b3eSEli Cohen } 2924*bc9a2b3eSEli Cohen kfree(ndev->irqp.entries); 2925*bc9a2b3eSEli Cohen } 2926*bc9a2b3eSEli Cohen 29271a86b377SEli Cohen static void mlx5_vdpa_free(struct vdpa_device *vdev) 29281a86b377SEli Cohen { 29291a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 29307c9f131fSEli Cohen struct mlx5_core_dev *pfmdev; 29311a86b377SEli Cohen struct mlx5_vdpa_net *ndev; 29321a86b377SEli Cohen 29331a86b377SEli Cohen ndev = to_mlx5_vdpa_ndev(mvdev); 29341a86b377SEli Cohen 29351a86b377SEli Cohen free_resources(ndev); 29366f5312f8SEli Cohen mlx5_vdpa_destroy_mr(mvdev); 29377c9f131fSEli Cohen if (!is_zero_ether_addr(ndev->config.mac)) { 29387c9f131fSEli Cohen pfmdev = pci_get_drvdata(pci_physfn(mvdev->mdev->pdev)); 29397c9f131fSEli Cohen mlx5_mpfs_del_mac(pfmdev, ndev->config.mac); 29407c9f131fSEli Cohen } 29411a86b377SEli Cohen mlx5_vdpa_free_resources(&ndev->mvdev); 2942*bc9a2b3eSEli Cohen free_irqs(ndev); 294375560522SEli Cohen kfree(ndev->event_cbs); 294475560522SEli Cohen kfree(ndev->vqs); 29451a86b377SEli Cohen } 29461a86b377SEli Cohen 29471a86b377SEli Cohen static struct vdpa_notification_area mlx5_get_vq_notification(struct vdpa_device *vdev, u16 idx) 29481a86b377SEli Cohen { 2949b57c46cbSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 29501a86b377SEli Cohen struct vdpa_notification_area ret = {}; 2951b57c46cbSEli Cohen struct mlx5_vdpa_net *ndev; 2952b57c46cbSEli Cohen phys_addr_t addr; 29531a86b377SEli Cohen 29545262912eSEli Cohen if (!is_index_valid(mvdev, idx) || is_ctrl_vq_idx(mvdev, idx)) 2955e4fc6650SEli Cohen return ret; 2956e4fc6650SEli Cohen 2957b57c46cbSEli Cohen /* If SF BAR size is smaller than PAGE_SIZE, do not use direct 2958b57c46cbSEli Cohen * notification to avoid the risk of mapping pages that contain BAR of more 2959b57c46cbSEli Cohen * than one SF 2960b57c46cbSEli Cohen */ 2961b57c46cbSEli Cohen if (MLX5_CAP_GEN(mvdev->mdev, log_min_sf_size) + 12 < PAGE_SHIFT) 2962b57c46cbSEli Cohen return ret; 2963b57c46cbSEli Cohen 2964b57c46cbSEli Cohen ndev = to_mlx5_vdpa_ndev(mvdev); 2965b57c46cbSEli Cohen addr = (phys_addr_t)ndev->mvdev.res.phys_kick_addr; 2966b57c46cbSEli Cohen ret.addr = addr; 2967b57c46cbSEli Cohen ret.size = PAGE_SIZE; 29681a86b377SEli Cohen return ret; 29691a86b377SEli Cohen } 29701a86b377SEli Cohen 2971*bc9a2b3eSEli Cohen static int mlx5_get_vq_irq(struct vdpa_device *vdev, u16 idx) 29721a86b377SEli Cohen { 2973*bc9a2b3eSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 2974*bc9a2b3eSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 2975*bc9a2b3eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 2976*bc9a2b3eSEli Cohen 2977*bc9a2b3eSEli Cohen if (!is_index_valid(mvdev, idx)) 2978*bc9a2b3eSEli Cohen return -EINVAL; 2979*bc9a2b3eSEli Cohen 2980*bc9a2b3eSEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) 29811a86b377SEli Cohen return -EOPNOTSUPP; 2982*bc9a2b3eSEli Cohen 2983*bc9a2b3eSEli Cohen mvq = &ndev->vqs[idx]; 2984*bc9a2b3eSEli Cohen if (!mvq->map.virq) 2985*bc9a2b3eSEli Cohen return -EOPNOTSUPP; 2986*bc9a2b3eSEli Cohen 2987*bc9a2b3eSEli Cohen return mvq->map.virq; 29881a86b377SEli Cohen } 29891a86b377SEli Cohen 2990a64917bcSEli Cohen static u64 mlx5_vdpa_get_driver_features(struct vdpa_device *vdev) 2991a64917bcSEli Cohen { 2992a64917bcSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 2993a64917bcSEli Cohen 2994a64917bcSEli Cohen return mvdev->actual_features; 2995a64917bcSEli Cohen } 2996a64917bcSEli Cohen 29971892a3d4SEli Cohen static int counter_set_query(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, 29981892a3d4SEli Cohen u64 *received_desc, u64 *completed_desc) 29991892a3d4SEli Cohen { 30001892a3d4SEli Cohen u32 in[MLX5_ST_SZ_DW(query_virtio_q_counters_in)] = {}; 30011892a3d4SEli Cohen u32 out[MLX5_ST_SZ_DW(query_virtio_q_counters_out)] = {}; 30021892a3d4SEli Cohen void *cmd_hdr; 30031892a3d4SEli Cohen void *ctx; 30041892a3d4SEli Cohen int err; 30051892a3d4SEli Cohen 30061892a3d4SEli Cohen if (!counters_supported(&ndev->mvdev)) 30071892a3d4SEli Cohen return -EOPNOTSUPP; 30081892a3d4SEli Cohen 30091892a3d4SEli Cohen if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY) 30101892a3d4SEli Cohen return -EAGAIN; 30111892a3d4SEli Cohen 30121892a3d4SEli Cohen cmd_hdr = MLX5_ADDR_OF(query_virtio_q_counters_in, in, hdr); 30131892a3d4SEli Cohen 30141892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_QUERY_GENERAL_OBJECT); 30151892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_Q_COUNTERS); 30161892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 30171892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_id, mvq->counter_set_id); 30181892a3d4SEli Cohen 30191892a3d4SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out)); 30201892a3d4SEli Cohen if (err) 30211892a3d4SEli Cohen return err; 30221892a3d4SEli Cohen 30231892a3d4SEli Cohen ctx = MLX5_ADDR_OF(query_virtio_q_counters_out, out, counters); 30241892a3d4SEli Cohen *received_desc = MLX5_GET64(virtio_q_counters, ctx, received_desc); 30251892a3d4SEli Cohen *completed_desc = MLX5_GET64(virtio_q_counters, ctx, completed_desc); 30261892a3d4SEli Cohen return 0; 30271892a3d4SEli Cohen } 30281892a3d4SEli Cohen 30291892a3d4SEli Cohen static int mlx5_vdpa_get_vendor_vq_stats(struct vdpa_device *vdev, u16 idx, 30301892a3d4SEli Cohen struct sk_buff *msg, 30311892a3d4SEli Cohen struct netlink_ext_ack *extack) 30321892a3d4SEli Cohen { 30331892a3d4SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 30341892a3d4SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 30351892a3d4SEli Cohen struct mlx5_vdpa_virtqueue *mvq; 30361892a3d4SEli Cohen struct mlx5_control_vq *cvq; 30371892a3d4SEli Cohen u64 received_desc; 30381892a3d4SEli Cohen u64 completed_desc; 30391892a3d4SEli Cohen int err = 0; 30401892a3d4SEli Cohen 3041759ae7f9SEli Cohen down_read(&ndev->reslock); 30421892a3d4SEli Cohen if (!is_index_valid(mvdev, idx)) { 30431892a3d4SEli Cohen NL_SET_ERR_MSG_MOD(extack, "virtqueue index is not valid"); 30441892a3d4SEli Cohen err = -EINVAL; 30451892a3d4SEli Cohen goto out_err; 30461892a3d4SEli Cohen } 30471892a3d4SEli Cohen 30481892a3d4SEli Cohen if (idx == ctrl_vq_idx(mvdev)) { 30491892a3d4SEli Cohen cvq = &mvdev->cvq; 30501892a3d4SEli Cohen received_desc = cvq->received_desc; 30511892a3d4SEli Cohen completed_desc = cvq->completed_desc; 30521892a3d4SEli Cohen goto out; 30531892a3d4SEli Cohen } 30541892a3d4SEli Cohen 30551892a3d4SEli Cohen mvq = &ndev->vqs[idx]; 30561892a3d4SEli Cohen err = counter_set_query(ndev, mvq, &received_desc, &completed_desc); 30571892a3d4SEli Cohen if (err) { 30581892a3d4SEli Cohen NL_SET_ERR_MSG_MOD(extack, "failed to query hardware"); 30591892a3d4SEli Cohen goto out_err; 30601892a3d4SEli Cohen } 30611892a3d4SEli Cohen 30621892a3d4SEli Cohen out: 30631892a3d4SEli Cohen err = -EMSGSIZE; 30641892a3d4SEli Cohen if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME, "received_desc")) 30651892a3d4SEli Cohen goto out_err; 30661892a3d4SEli Cohen 30671892a3d4SEli Cohen if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE, received_desc, 30681892a3d4SEli Cohen VDPA_ATTR_PAD)) 30691892a3d4SEli Cohen goto out_err; 30701892a3d4SEli Cohen 30711892a3d4SEli Cohen if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME, "completed_desc")) 30721892a3d4SEli Cohen goto out_err; 30731892a3d4SEli Cohen 30741892a3d4SEli Cohen if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE, completed_desc, 30751892a3d4SEli Cohen VDPA_ATTR_PAD)) 30761892a3d4SEli Cohen goto out_err; 30771892a3d4SEli Cohen 30781892a3d4SEli Cohen err = 0; 30791892a3d4SEli Cohen out_err: 3080759ae7f9SEli Cohen up_read(&ndev->reslock); 30811892a3d4SEli Cohen return err; 30821892a3d4SEli Cohen } 30831892a3d4SEli Cohen 3084cae15c2eSEli Cohen static void mlx5_vdpa_cvq_suspend(struct mlx5_vdpa_dev *mvdev) 3085cae15c2eSEli Cohen { 3086cae15c2eSEli Cohen struct mlx5_control_vq *cvq; 3087cae15c2eSEli Cohen 3088cae15c2eSEli Cohen if (!(mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) 3089cae15c2eSEli Cohen return; 3090cae15c2eSEli Cohen 3091cae15c2eSEli Cohen cvq = &mvdev->cvq; 3092cae15c2eSEli Cohen cvq->ready = false; 3093cae15c2eSEli Cohen } 3094cae15c2eSEli Cohen 3095cae15c2eSEli Cohen static int mlx5_vdpa_suspend(struct vdpa_device *vdev) 3096cae15c2eSEli Cohen { 3097cae15c2eSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 3098cae15c2eSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 3099cae15c2eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 3100cae15c2eSEli Cohen int i; 3101cae15c2eSEli Cohen 310209e65ee9SSi-Wei Liu mlx5_vdpa_info(mvdev, "suspending device\n"); 310309e65ee9SSi-Wei Liu 3104cae15c2eSEli Cohen down_write(&ndev->reslock); 3105c384c240SEli Cohen unregister_link_notifier(ndev); 3106cae15c2eSEli Cohen for (i = 0; i < ndev->cur_num_vqs; i++) { 3107cae15c2eSEli Cohen mvq = &ndev->vqs[i]; 3108cae15c2eSEli Cohen suspend_vq(ndev, mvq); 3109cae15c2eSEli Cohen } 3110cae15c2eSEli Cohen mlx5_vdpa_cvq_suspend(mvdev); 311109e65ee9SSi-Wei Liu mvdev->suspended = true; 3112cae15c2eSEli Cohen up_write(&ndev->reslock); 3113cae15c2eSEli Cohen return 0; 3114cae15c2eSEli Cohen } 3115cae15c2eSEli Cohen 31168fcd20c3SEli Cohen static int mlx5_set_group_asid(struct vdpa_device *vdev, u32 group, 31178fcd20c3SEli Cohen unsigned int asid) 31188fcd20c3SEli Cohen { 31198fcd20c3SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 31208fcd20c3SEli Cohen 31218fcd20c3SEli Cohen if (group >= MLX5_VDPA_NUMVQ_GROUPS) 31228fcd20c3SEli Cohen return -EINVAL; 31238fcd20c3SEli Cohen 31248fcd20c3SEli Cohen mvdev->group2asid[group] = asid; 31258fcd20c3SEli Cohen return 0; 31268fcd20c3SEli Cohen } 31278fcd20c3SEli Cohen 31281a86b377SEli Cohen static const struct vdpa_config_ops mlx5_vdpa_ops = { 31291a86b377SEli Cohen .set_vq_address = mlx5_vdpa_set_vq_address, 31301a86b377SEli Cohen .set_vq_num = mlx5_vdpa_set_vq_num, 31311a86b377SEli Cohen .kick_vq = mlx5_vdpa_kick_vq, 31321a86b377SEli Cohen .set_vq_cb = mlx5_vdpa_set_vq_cb, 31331a86b377SEli Cohen .set_vq_ready = mlx5_vdpa_set_vq_ready, 31341a86b377SEli Cohen .get_vq_ready = mlx5_vdpa_get_vq_ready, 31351a86b377SEli Cohen .set_vq_state = mlx5_vdpa_set_vq_state, 31361a86b377SEli Cohen .get_vq_state = mlx5_vdpa_get_vq_state, 31371892a3d4SEli Cohen .get_vendor_vq_stats = mlx5_vdpa_get_vendor_vq_stats, 31381a86b377SEli Cohen .get_vq_notification = mlx5_get_vq_notification, 31391a86b377SEli Cohen .get_vq_irq = mlx5_get_vq_irq, 31401a86b377SEli Cohen .get_vq_align = mlx5_vdpa_get_vq_align, 3141d4821902SGautam Dawar .get_vq_group = mlx5_vdpa_get_vq_group, 3142a64917bcSEli Cohen .get_device_features = mlx5_vdpa_get_device_features, 3143a64917bcSEli Cohen .set_driver_features = mlx5_vdpa_set_driver_features, 3144a64917bcSEli Cohen .get_driver_features = mlx5_vdpa_get_driver_features, 31451a86b377SEli Cohen .set_config_cb = mlx5_vdpa_set_config_cb, 31461a86b377SEli Cohen .get_vq_num_max = mlx5_vdpa_get_vq_num_max, 31471a86b377SEli Cohen .get_device_id = mlx5_vdpa_get_device_id, 31481a86b377SEli Cohen .get_vendor_id = mlx5_vdpa_get_vendor_id, 31491a86b377SEli Cohen .get_status = mlx5_vdpa_get_status, 31501a86b377SEli Cohen .set_status = mlx5_vdpa_set_status, 31510686082dSXie Yongji .reset = mlx5_vdpa_reset, 3152442706f9SStefano Garzarella .get_config_size = mlx5_vdpa_get_config_size, 31531a86b377SEli Cohen .get_config = mlx5_vdpa_get_config, 31541a86b377SEli Cohen .set_config = mlx5_vdpa_set_config, 31551a86b377SEli Cohen .get_generation = mlx5_vdpa_get_generation, 31561a86b377SEli Cohen .set_map = mlx5_vdpa_set_map, 31578fcd20c3SEli Cohen .set_group_asid = mlx5_set_group_asid, 315836871fb9SJason Wang .get_vq_dma_dev = mlx5_get_vq_dma_dev, 31591a86b377SEli Cohen .free = mlx5_vdpa_free, 3160cae15c2eSEli Cohen .suspend = mlx5_vdpa_suspend, 31611a86b377SEli Cohen }; 31621a86b377SEli Cohen 3163d084d996SSi-Wei Liu static int query_mtu(struct mlx5_core_dev *mdev, u16 *mtu) 3164d084d996SSi-Wei Liu { 3165d084d996SSi-Wei Liu u16 hw_mtu; 3166d084d996SSi-Wei Liu int err; 3167d084d996SSi-Wei Liu 3168d084d996SSi-Wei Liu err = mlx5_query_nic_vport_mtu(mdev, &hw_mtu); 3169d084d996SSi-Wei Liu if (err) 3170d084d996SSi-Wei Liu return err; 3171d084d996SSi-Wei Liu 3172d084d996SSi-Wei Liu *mtu = hw_mtu - MLX5V_ETH_HARD_MTU; 3173d084d996SSi-Wei Liu return 0; 3174d084d996SSi-Wei Liu } 3175d084d996SSi-Wei Liu 31761a86b377SEli Cohen static int alloc_resources(struct mlx5_vdpa_net *ndev) 31771a86b377SEli Cohen { 31781a86b377SEli Cohen struct mlx5_vdpa_net_resources *res = &ndev->res; 31791a86b377SEli Cohen int err; 31801a86b377SEli Cohen 31811a86b377SEli Cohen if (res->valid) { 31821a86b377SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "resources already allocated\n"); 31831a86b377SEli Cohen return -EEXIST; 31841a86b377SEli Cohen } 31851a86b377SEli Cohen 31861a86b377SEli Cohen err = mlx5_vdpa_alloc_transport_domain(&ndev->mvdev, &res->tdn); 31871a86b377SEli Cohen if (err) 31881a86b377SEli Cohen return err; 31891a86b377SEli Cohen 31901a86b377SEli Cohen err = create_tis(ndev); 31911a86b377SEli Cohen if (err) 31921a86b377SEli Cohen goto err_tis; 31931a86b377SEli Cohen 31941a86b377SEli Cohen res->valid = true; 31951a86b377SEli Cohen 31961a86b377SEli Cohen return 0; 31971a86b377SEli Cohen 31981a86b377SEli Cohen err_tis: 31991a86b377SEli Cohen mlx5_vdpa_dealloc_transport_domain(&ndev->mvdev, res->tdn); 32001a86b377SEli Cohen return err; 32011a86b377SEli Cohen } 32021a86b377SEli Cohen 32031a86b377SEli Cohen static void free_resources(struct mlx5_vdpa_net *ndev) 32041a86b377SEli Cohen { 32051a86b377SEli Cohen struct mlx5_vdpa_net_resources *res = &ndev->res; 32061a86b377SEli Cohen 32071a86b377SEli Cohen if (!res->valid) 32081a86b377SEli Cohen return; 32091a86b377SEli Cohen 32101a86b377SEli Cohen destroy_tis(ndev); 32111a86b377SEli Cohen mlx5_vdpa_dealloc_transport_domain(&ndev->mvdev, res->tdn); 32121a86b377SEli Cohen res->valid = false; 32131a86b377SEli Cohen } 32141a86b377SEli Cohen 32151a86b377SEli Cohen static void init_mvqs(struct mlx5_vdpa_net *ndev) 32161a86b377SEli Cohen { 32171a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq; 32181a86b377SEli Cohen int i; 32191a86b377SEli Cohen 3220acde3929SEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; ++i) { 32211a86b377SEli Cohen mvq = &ndev->vqs[i]; 32221a86b377SEli Cohen memset(mvq, 0, offsetof(struct mlx5_vdpa_virtqueue, ri)); 32231a86b377SEli Cohen mvq->index = i; 32241a86b377SEli Cohen mvq->ndev = ndev; 32251a86b377SEli Cohen mvq->fwqp.fw = true; 3226cae15c2eSEli Cohen mvq->fw_state = MLX5_VIRTIO_NET_Q_OBJECT_NONE; 32271a86b377SEli Cohen } 32281a86b377SEli Cohen for (; i < ndev->mvdev.max_vqs; i++) { 32291a86b377SEli Cohen mvq = &ndev->vqs[i]; 32301a86b377SEli Cohen memset(mvq, 0, offsetof(struct mlx5_vdpa_virtqueue, ri)); 32311a86b377SEli Cohen mvq->index = i; 32321a86b377SEli Cohen mvq->ndev = ndev; 32331a86b377SEli Cohen } 32341a86b377SEli Cohen } 32351a86b377SEli Cohen 323658926c8aSEli Cohen struct mlx5_vdpa_mgmtdev { 323758926c8aSEli Cohen struct vdpa_mgmt_dev mgtdev; 323858926c8aSEli Cohen struct mlx5_adev *madev; 323958926c8aSEli Cohen struct mlx5_vdpa_net *ndev; 324058926c8aSEli Cohen }; 324158926c8aSEli Cohen 32421e00e821SEli Cohen static int config_func_mtu(struct mlx5_core_dev *mdev, u16 mtu) 32431e00e821SEli Cohen { 32441e00e821SEli Cohen int inlen = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in); 32451e00e821SEli Cohen void *in; 32461e00e821SEli Cohen int err; 32471e00e821SEli Cohen 32481e00e821SEli Cohen in = kvzalloc(inlen, GFP_KERNEL); 32491e00e821SEli Cohen if (!in) 32501e00e821SEli Cohen return -ENOMEM; 32511e00e821SEli Cohen 32521e00e821SEli Cohen MLX5_SET(modify_nic_vport_context_in, in, field_select.mtu, 1); 32531e00e821SEli Cohen MLX5_SET(modify_nic_vport_context_in, in, nic_vport_context.mtu, 32541e00e821SEli Cohen mtu + MLX5V_ETH_HARD_MTU); 32551e00e821SEli Cohen MLX5_SET(modify_nic_vport_context_in, in, opcode, 32561e00e821SEli Cohen MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT); 32571e00e821SEli Cohen 32581e00e821SEli Cohen err = mlx5_cmd_exec_in(mdev, modify_nic_vport_context, in); 32591e00e821SEli Cohen 32601e00e821SEli Cohen kvfree(in); 32611e00e821SEli Cohen return err; 32621e00e821SEli Cohen } 32631e00e821SEli Cohen 3264*bc9a2b3eSEli Cohen static void allocate_irqs(struct mlx5_vdpa_net *ndev) 3265*bc9a2b3eSEli Cohen { 3266*bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool_entry *ent; 3267*bc9a2b3eSEli Cohen int i; 3268*bc9a2b3eSEli Cohen 3269*bc9a2b3eSEli Cohen if (!msix_mode_supported(&ndev->mvdev)) 3270*bc9a2b3eSEli Cohen return; 3271*bc9a2b3eSEli Cohen 3272*bc9a2b3eSEli Cohen if (!ndev->mvdev.mdev->pdev) 3273*bc9a2b3eSEli Cohen return; 3274*bc9a2b3eSEli Cohen 3275*bc9a2b3eSEli Cohen ndev->irqp.entries = kcalloc(ndev->mvdev.max_vqs, sizeof(*ndev->irqp.entries), GFP_KERNEL); 3276*bc9a2b3eSEli Cohen if (!ndev->irqp.entries) 3277*bc9a2b3eSEli Cohen return; 3278*bc9a2b3eSEli Cohen 3279*bc9a2b3eSEli Cohen 3280*bc9a2b3eSEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) { 3281*bc9a2b3eSEli Cohen ent = ndev->irqp.entries + i; 3282*bc9a2b3eSEli Cohen snprintf(ent->name, MLX5_VDPA_IRQ_NAME_LEN, "%s-vq-%d", 3283*bc9a2b3eSEli Cohen dev_name(&ndev->mvdev.vdev.dev), i); 3284*bc9a2b3eSEli Cohen ent->map = pci_msix_alloc_irq_at(ndev->mvdev.mdev->pdev, MSI_ANY_INDEX, NULL); 3285*bc9a2b3eSEli Cohen if (!ent->map.virq) 3286*bc9a2b3eSEli Cohen return; 3287*bc9a2b3eSEli Cohen 3288*bc9a2b3eSEli Cohen ndev->irqp.num_ent++; 3289*bc9a2b3eSEli Cohen } 3290*bc9a2b3eSEli Cohen } 3291*bc9a2b3eSEli Cohen 3292d8ca2fa5SParav Pandit static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, 3293d8ca2fa5SParav Pandit const struct vdpa_dev_set_config *add_config) 32941a86b377SEli Cohen { 329558926c8aSEli Cohen struct mlx5_vdpa_mgmtdev *mgtdev = container_of(v_mdev, struct mlx5_vdpa_mgmtdev, mgtdev); 32961a86b377SEli Cohen struct virtio_net_config *config; 32977c9f131fSEli Cohen struct mlx5_core_dev *pfmdev; 32981a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev; 32991a86b377SEli Cohen struct mlx5_vdpa_net *ndev; 330058926c8aSEli Cohen struct mlx5_core_dev *mdev; 3301deeacf35SSi-Wei Liu u64 device_features; 33021a86b377SEli Cohen u32 max_vqs; 3303246fd1caSEli Cohen u16 mtu; 33041a86b377SEli Cohen int err; 33051a86b377SEli Cohen 330658926c8aSEli Cohen if (mgtdev->ndev) 330758926c8aSEli Cohen return -ENOSPC; 330858926c8aSEli Cohen 330958926c8aSEli Cohen mdev = mgtdev->madev->mdev; 3310deeacf35SSi-Wei Liu device_features = mgtdev->mgtdev.supported_features; 3311deeacf35SSi-Wei Liu if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) { 3312deeacf35SSi-Wei Liu if (add_config->device_features & ~device_features) { 3313deeacf35SSi-Wei Liu dev_warn(mdev->device, 3314deeacf35SSi-Wei Liu "The provisioned features 0x%llx are not supported by this device with features 0x%llx\n", 3315deeacf35SSi-Wei Liu add_config->device_features, device_features); 3316deeacf35SSi-Wei Liu return -EINVAL; 3317deeacf35SSi-Wei Liu } 3318deeacf35SSi-Wei Liu device_features &= add_config->device_features; 3319791a1cb7SEli Cohen } else { 3320791a1cb7SEli Cohen device_features &= ~BIT_ULL(VIRTIO_NET_F_MRG_RXBUF); 3321deeacf35SSi-Wei Liu } 3322deeacf35SSi-Wei Liu if (!(device_features & BIT_ULL(VIRTIO_F_VERSION_1) && 3323deeacf35SSi-Wei Liu device_features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM))) { 3324deeacf35SSi-Wei Liu dev_warn(mdev->device, 3325deeacf35SSi-Wei Liu "Must provision minimum features 0x%llx for this device", 3326deeacf35SSi-Wei Liu BIT_ULL(VIRTIO_F_VERSION_1) | BIT_ULL(VIRTIO_F_ACCESS_PLATFORM)); 3327deeacf35SSi-Wei Liu return -EOPNOTSUPP; 3328deeacf35SSi-Wei Liu } 3329deeacf35SSi-Wei Liu 3330879753c8SEli Cohen if (!(MLX5_CAP_DEV_VDPA_EMULATION(mdev, virtio_queue_type) & 3331879753c8SEli Cohen MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_SPLIT)) { 3332879753c8SEli Cohen dev_warn(mdev->device, "missing support for split virtqueues\n"); 3333879753c8SEli Cohen return -EOPNOTSUPP; 3334879753c8SEli Cohen } 3335879753c8SEli Cohen 3336acde3929SEli Cohen max_vqs = min_t(int, MLX5_CAP_DEV_VDPA_EMULATION(mdev, max_num_virtio_queues), 3337acde3929SEli Cohen 1 << MLX5_CAP_GEN(mdev, log_max_rqt_size)); 333875560522SEli Cohen if (max_vqs < 2) { 333975560522SEli Cohen dev_warn(mdev->device, 334075560522SEli Cohen "%d virtqueues are supported. At least 2 are required\n", 334175560522SEli Cohen max_vqs); 334275560522SEli Cohen return -EAGAIN; 334375560522SEli Cohen } 334475560522SEli Cohen 334575560522SEli Cohen if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP)) { 334675560522SEli Cohen if (add_config->net.max_vq_pairs > max_vqs / 2) 334775560522SEli Cohen return -EINVAL; 334875560522SEli Cohen max_vqs = min_t(u32, max_vqs, 2 * add_config->net.max_vq_pairs); 334975560522SEli Cohen } else { 335075560522SEli Cohen max_vqs = 2; 335175560522SEli Cohen } 33521a86b377SEli Cohen 33531a86b377SEli Cohen ndev = vdpa_alloc_device(struct mlx5_vdpa_net, mvdev.vdev, mdev->device, &mlx5_vdpa_ops, 33548fcd20c3SEli Cohen MLX5_VDPA_NUMVQ_GROUPS, MLX5_VDPA_NUM_AS, name, false); 33551a86b377SEli Cohen if (IS_ERR(ndev)) 335674c9729dSLeon Romanovsky return PTR_ERR(ndev); 33571a86b377SEli Cohen 33581a86b377SEli Cohen ndev->mvdev.max_vqs = max_vqs; 33591a86b377SEli Cohen mvdev = &ndev->mvdev; 33601a86b377SEli Cohen mvdev->mdev = mdev; 336175560522SEli Cohen 336275560522SEli Cohen ndev->vqs = kcalloc(max_vqs, sizeof(*ndev->vqs), GFP_KERNEL); 336375560522SEli Cohen ndev->event_cbs = kcalloc(max_vqs + 1, sizeof(*ndev->event_cbs), GFP_KERNEL); 336475560522SEli Cohen if (!ndev->vqs || !ndev->event_cbs) { 336575560522SEli Cohen err = -ENOMEM; 336675560522SEli Cohen goto err_alloc; 336775560522SEli Cohen } 336875560522SEli Cohen 33691a86b377SEli Cohen init_mvqs(ndev); 3370*bc9a2b3eSEli Cohen allocate_irqs(ndev); 3371759ae7f9SEli Cohen init_rwsem(&ndev->reslock); 33721a86b377SEli Cohen config = &ndev->config; 33731e00e821SEli Cohen 33741e00e821SEli Cohen if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MTU)) { 33751e00e821SEli Cohen err = config_func_mtu(mdev, add_config->net.mtu); 33761e00e821SEli Cohen if (err) 3377759ae7f9SEli Cohen goto err_alloc; 33781e00e821SEli Cohen } 33791e00e821SEli Cohen 3380deeacf35SSi-Wei Liu if (device_features & BIT_ULL(VIRTIO_NET_F_MTU)) { 3381246fd1caSEli Cohen err = query_mtu(mdev, &mtu); 33821a86b377SEli Cohen if (err) 3383759ae7f9SEli Cohen goto err_alloc; 33841a86b377SEli Cohen 3385246fd1caSEli Cohen ndev->config.mtu = cpu_to_mlx5vdpa16(mvdev, mtu); 3386033779a7SSi-Wei Liu } 33871a86b377SEli Cohen 3388deeacf35SSi-Wei Liu if (device_features & BIT_ULL(VIRTIO_NET_F_STATUS)) { 3389edf747afSEli Cohen if (get_link_state(mvdev)) 3390edf747afSEli Cohen ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP); 3391edf747afSEli Cohen else 3392edf747afSEli Cohen ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP); 3393033779a7SSi-Wei Liu } 3394edf747afSEli Cohen 3395a007d940SEli Cohen if (add_config->mask & (1 << VDPA_ATTR_DEV_NET_CFG_MACADDR)) { 3396a007d940SEli Cohen memcpy(ndev->config.mac, add_config->net.mac, ETH_ALEN); 3397deeacf35SSi-Wei Liu /* No bother setting mac address in config if not going to provision _F_MAC */ 3398deeacf35SSi-Wei Liu } else if ((add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) == 0 || 3399deeacf35SSi-Wei Liu device_features & BIT_ULL(VIRTIO_NET_F_MAC)) { 34001a86b377SEli Cohen err = mlx5_query_nic_vport_mac_address(mdev, 0, 0, config->mac); 34011a86b377SEli Cohen if (err) 3402759ae7f9SEli Cohen goto err_alloc; 3403a007d940SEli Cohen } 34041a86b377SEli Cohen 34057c9f131fSEli Cohen if (!is_zero_ether_addr(config->mac)) { 34067c9f131fSEli Cohen pfmdev = pci_get_drvdata(pci_physfn(mdev->pdev)); 34077c9f131fSEli Cohen err = mlx5_mpfs_add_mac(pfmdev, config->mac); 34087c9f131fSEli Cohen if (err) 3409759ae7f9SEli Cohen goto err_alloc; 3410deeacf35SSi-Wei Liu } else if ((add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) == 0) { 3411deeacf35SSi-Wei Liu /* 3412deeacf35SSi-Wei Liu * We used to clear _F_MAC feature bit if seeing 3413deeacf35SSi-Wei Liu * zero mac address when device features are not 3414deeacf35SSi-Wei Liu * specifically provisioned. Keep the behaviour 3415deeacf35SSi-Wei Liu * so old scripts do not break. 3416deeacf35SSi-Wei Liu */ 3417deeacf35SSi-Wei Liu device_features &= ~BIT_ULL(VIRTIO_NET_F_MAC); 3418deeacf35SSi-Wei Liu } else if (device_features & BIT_ULL(VIRTIO_NET_F_MAC)) { 3419deeacf35SSi-Wei Liu /* Don't provision zero mac address for _F_MAC */ 3420deeacf35SSi-Wei Liu mlx5_vdpa_warn(&ndev->mvdev, 3421deeacf35SSi-Wei Liu "No mac address provisioned?\n"); 3422deeacf35SSi-Wei Liu err = -EINVAL; 3423deeacf35SSi-Wei Liu goto err_alloc; 34247c9f131fSEli Cohen } 34257c9f131fSEli Cohen 3426deeacf35SSi-Wei Liu if (device_features & BIT_ULL(VIRTIO_NET_F_MQ)) 3427acde3929SEli Cohen config->max_virtqueue_pairs = cpu_to_mlx5vdpa16(mvdev, max_vqs / 2); 3428deeacf35SSi-Wei Liu 3429deeacf35SSi-Wei Liu ndev->mvdev.mlx_features = device_features; 34307d23dcdfSEli Cohen mvdev->vdev.dma_dev = &mdev->pdev->dev; 34311a86b377SEli Cohen err = mlx5_vdpa_alloc_resources(&ndev->mvdev); 34321a86b377SEli Cohen if (err) 34337c9f131fSEli Cohen goto err_mpfs; 34341a86b377SEli Cohen 34356f5312f8SEli Cohen if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) { 343638fc462fSEli Cohen err = mlx5_vdpa_create_mr(mvdev, NULL, 0); 34371a86b377SEli Cohen if (err) 34381a86b377SEli Cohen goto err_res; 34396f5312f8SEli Cohen } 34406f5312f8SEli Cohen 34416f5312f8SEli Cohen err = alloc_resources(ndev); 34426f5312f8SEli Cohen if (err) 34436f5312f8SEli Cohen goto err_mr; 34441a86b377SEli Cohen 344555ebf0d6SJason Wang ndev->cvq_ent.mvdev = mvdev; 344655ebf0d6SJason Wang INIT_WORK(&ndev->cvq_ent.work, mlx5_cvq_kick_handler); 3447218bdd20SEli Cohen mvdev->wq = create_singlethread_workqueue("mlx5_vdpa_wq"); 34485262912eSEli Cohen if (!mvdev->wq) { 34495262912eSEli Cohen err = -ENOMEM; 34505262912eSEli Cohen goto err_res2; 34515262912eSEli Cohen } 34525262912eSEli Cohen 345358926c8aSEli Cohen mvdev->vdev.mdev = &mgtdev->mgtdev; 3454acde3929SEli Cohen err = _vdpa_register_device(&mvdev->vdev, max_vqs + 1); 34551a86b377SEli Cohen if (err) 34561a86b377SEli Cohen goto err_reg; 34571a86b377SEli Cohen 345858926c8aSEli Cohen mgtdev->ndev = ndev; 345974c9729dSLeon Romanovsky return 0; 34601a86b377SEli Cohen 34611a86b377SEli Cohen err_reg: 34625262912eSEli Cohen destroy_workqueue(mvdev->wq); 34635262912eSEli Cohen err_res2: 34641a86b377SEli Cohen free_resources(ndev); 34656f5312f8SEli Cohen err_mr: 34666f5312f8SEli Cohen mlx5_vdpa_destroy_mr(mvdev); 34671a86b377SEli Cohen err_res: 34681a86b377SEli Cohen mlx5_vdpa_free_resources(&ndev->mvdev); 34697c9f131fSEli Cohen err_mpfs: 34707c9f131fSEli Cohen if (!is_zero_ether_addr(config->mac)) 34717c9f131fSEli Cohen mlx5_mpfs_del_mac(pfmdev, config->mac); 347275560522SEli Cohen err_alloc: 34731a86b377SEli Cohen put_device(&mvdev->vdev.dev); 347474c9729dSLeon Romanovsky return err; 34751a86b377SEli Cohen } 34761a86b377SEli Cohen 347758926c8aSEli Cohen static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device *dev) 347858926c8aSEli Cohen { 347958926c8aSEli Cohen struct mlx5_vdpa_mgmtdev *mgtdev = container_of(v_mdev, struct mlx5_vdpa_mgmtdev, mgtdev); 34805262912eSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(dev); 3481edf747afSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 3482ad6dc1daSEli Cohen struct workqueue_struct *wq; 348358926c8aSEli Cohen 348429422100SEli Cohen mlx5_vdpa_remove_debugfs(ndev->debugfs); 348529422100SEli Cohen ndev->debugfs = NULL; 3486c384c240SEli Cohen unregister_link_notifier(ndev); 348773790bdfSDragos Tatulea _vdpa_unregister_device(dev); 3488ad6dc1daSEli Cohen wq = mvdev->wq; 3489ad6dc1daSEli Cohen mvdev->wq = NULL; 3490ad6dc1daSEli Cohen destroy_workqueue(wq); 349158926c8aSEli Cohen mgtdev->ndev = NULL; 349258926c8aSEli Cohen } 349358926c8aSEli Cohen 349458926c8aSEli Cohen static const struct vdpa_mgmtdev_ops mdev_ops = { 349558926c8aSEli Cohen .dev_add = mlx5_vdpa_dev_add, 349658926c8aSEli Cohen .dev_del = mlx5_vdpa_dev_del, 349758926c8aSEli Cohen }; 349858926c8aSEli Cohen 349958926c8aSEli Cohen static struct virtio_device_id id_table[] = { 350058926c8aSEli Cohen { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID }, 350158926c8aSEli Cohen { 0 }, 350258926c8aSEli Cohen }; 350358926c8aSEli Cohen 350458926c8aSEli Cohen static int mlx5v_probe(struct auxiliary_device *adev, 350558926c8aSEli Cohen const struct auxiliary_device_id *id) 350658926c8aSEli Cohen 350758926c8aSEli Cohen { 350858926c8aSEli Cohen struct mlx5_adev *madev = container_of(adev, struct mlx5_adev, adev); 350958926c8aSEli Cohen struct mlx5_core_dev *mdev = madev->mdev; 351058926c8aSEli Cohen struct mlx5_vdpa_mgmtdev *mgtdev; 351158926c8aSEli Cohen int err; 351258926c8aSEli Cohen 351358926c8aSEli Cohen mgtdev = kzalloc(sizeof(*mgtdev), GFP_KERNEL); 351458926c8aSEli Cohen if (!mgtdev) 351558926c8aSEli Cohen return -ENOMEM; 351658926c8aSEli Cohen 351758926c8aSEli Cohen mgtdev->mgtdev.ops = &mdev_ops; 351858926c8aSEli Cohen mgtdev->mgtdev.device = mdev->device; 351958926c8aSEli Cohen mgtdev->mgtdev.id_table = id_table; 352075560522SEli Cohen mgtdev->mgtdev.config_attr_mask = BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR) | 35211e00e821SEli Cohen BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP) | 3522deeacf35SSi-Wei Liu BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MTU) | 3523deeacf35SSi-Wei Liu BIT_ULL(VDPA_ATTR_DEV_FEATURES); 352479de65edSEli Cohen mgtdev->mgtdev.max_supported_vqs = 352579de65edSEli Cohen MLX5_CAP_DEV_VDPA_EMULATION(mdev, max_num_virtio_queues) + 1; 352679de65edSEli Cohen mgtdev->mgtdev.supported_features = get_supported_features(mdev); 352758926c8aSEli Cohen mgtdev->madev = madev; 352858926c8aSEli Cohen 352958926c8aSEli Cohen err = vdpa_mgmtdev_register(&mgtdev->mgtdev); 353058926c8aSEli Cohen if (err) 353158926c8aSEli Cohen goto reg_err; 353258926c8aSEli Cohen 353345e3a279SDavid E. Box auxiliary_set_drvdata(adev, mgtdev); 353458926c8aSEli Cohen 353558926c8aSEli Cohen return 0; 353658926c8aSEli Cohen 353758926c8aSEli Cohen reg_err: 353858926c8aSEli Cohen kfree(mgtdev); 353958926c8aSEli Cohen return err; 354058926c8aSEli Cohen } 354158926c8aSEli Cohen 354274c9729dSLeon Romanovsky static void mlx5v_remove(struct auxiliary_device *adev) 35431a86b377SEli Cohen { 354458926c8aSEli Cohen struct mlx5_vdpa_mgmtdev *mgtdev; 354574c9729dSLeon Romanovsky 354645e3a279SDavid E. Box mgtdev = auxiliary_get_drvdata(adev); 354758926c8aSEli Cohen vdpa_mgmtdev_unregister(&mgtdev->mgtdev); 354858926c8aSEli Cohen kfree(mgtdev); 35491a86b377SEli Cohen } 355074c9729dSLeon Romanovsky 3551*bc9a2b3eSEli Cohen static void mlx5v_shutdown(struct auxiliary_device *auxdev) 3552*bc9a2b3eSEli Cohen { 3553*bc9a2b3eSEli Cohen struct mlx5_vdpa_mgmtdev *mgtdev; 3554*bc9a2b3eSEli Cohen struct mlx5_vdpa_net *ndev; 3555*bc9a2b3eSEli Cohen 3556*bc9a2b3eSEli Cohen mgtdev = auxiliary_get_drvdata(auxdev); 3557*bc9a2b3eSEli Cohen ndev = mgtdev->ndev; 3558*bc9a2b3eSEli Cohen 3559*bc9a2b3eSEli Cohen free_irqs(ndev); 3560*bc9a2b3eSEli Cohen } 3561*bc9a2b3eSEli Cohen 356274c9729dSLeon Romanovsky static const struct auxiliary_device_id mlx5v_id_table[] = { 356374c9729dSLeon Romanovsky { .name = MLX5_ADEV_NAME ".vnet", }, 356474c9729dSLeon Romanovsky {}, 356574c9729dSLeon Romanovsky }; 356674c9729dSLeon Romanovsky 356774c9729dSLeon Romanovsky MODULE_DEVICE_TABLE(auxiliary, mlx5v_id_table); 356874c9729dSLeon Romanovsky 356974c9729dSLeon Romanovsky static struct auxiliary_driver mlx5v_driver = { 357074c9729dSLeon Romanovsky .name = "vnet", 357174c9729dSLeon Romanovsky .probe = mlx5v_probe, 357274c9729dSLeon Romanovsky .remove = mlx5v_remove, 3573*bc9a2b3eSEli Cohen .shutdown = mlx5v_shutdown, 357474c9729dSLeon Romanovsky .id_table = mlx5v_id_table, 357574c9729dSLeon Romanovsky }; 357674c9729dSLeon Romanovsky 357774c9729dSLeon Romanovsky module_auxiliary_driver(mlx5v_driver); 3578