11a86b377SEli Cohen // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 21a86b377SEli Cohen /* Copyright (c) 2020 Mellanox Technologies Ltd. */ 31a86b377SEli Cohen 474c9729dSLeon Romanovsky #include <linux/module.h> 51a86b377SEli Cohen #include <linux/vdpa.h> 674c9729dSLeon Romanovsky #include <linux/vringh.h> 774c9729dSLeon Romanovsky #include <uapi/linux/virtio_net.h> 81a86b377SEli Cohen #include <uapi/linux/virtio_ids.h> 9a007d940SEli Cohen #include <uapi/linux/vdpa.h> 101a86b377SEli Cohen #include <linux/virtio_config.h> 1174c9729dSLeon Romanovsky #include <linux/auxiliary_bus.h> 1274c9729dSLeon Romanovsky #include <linux/mlx5/cq.h> 131a86b377SEli Cohen #include <linux/mlx5/qp.h> 141a86b377SEli Cohen #include <linux/mlx5/device.h> 1574c9729dSLeon Romanovsky #include <linux/mlx5/driver.h> 161a86b377SEli Cohen #include <linux/mlx5/vport.h> 171a86b377SEli Cohen #include <linux/mlx5/fs.h> 180aae392bSLeon Romanovsky #include <linux/mlx5/mlx5_ifc_vdpa.h> 197c9f131fSEli Cohen #include <linux/mlx5/mpfs.h> 201a86b377SEli Cohen #include "mlx5_vdpa.h" 2172c67e9bSEli Cohen #include "mlx5_vnet.h" 221a86b377SEli Cohen 2374c9729dSLeon Romanovsky MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>"); 2474c9729dSLeon Romanovsky MODULE_DESCRIPTION("Mellanox VDPA driver"); 2574c9729dSLeon Romanovsky MODULE_LICENSE("Dual BSD/GPL"); 2674c9729dSLeon Romanovsky 271a86b377SEli Cohen #define VALID_FEATURES_MASK \ 28cbb52359SNathan Chancellor (BIT_ULL(VIRTIO_NET_F_CSUM) | BIT_ULL(VIRTIO_NET_F_GUEST_CSUM) | \ 29cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_CTRL_GUEST_OFFLOADS) | BIT_ULL(VIRTIO_NET_F_MTU) | BIT_ULL(VIRTIO_NET_F_MAC) | \ 30cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_GUEST_TSO4) | BIT_ULL(VIRTIO_NET_F_GUEST_TSO6) | \ 31cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_GUEST_ECN) | BIT_ULL(VIRTIO_NET_F_GUEST_UFO) | BIT_ULL(VIRTIO_NET_F_HOST_TSO4) | \ 32cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_HOST_TSO6) | BIT_ULL(VIRTIO_NET_F_HOST_ECN) | BIT_ULL(VIRTIO_NET_F_HOST_UFO) | \ 33cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_MRG_RXBUF) | BIT_ULL(VIRTIO_NET_F_STATUS) | BIT_ULL(VIRTIO_NET_F_CTRL_VQ) | \ 34cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_CTRL_RX) | BIT_ULL(VIRTIO_NET_F_CTRL_VLAN) | \ 35cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_CTRL_RX_EXTRA) | BIT_ULL(VIRTIO_NET_F_GUEST_ANNOUNCE) | \ 36cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_MQ) | BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR) | BIT_ULL(VIRTIO_NET_F_HASH_REPORT) | \ 37cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_RSS) | BIT_ULL(VIRTIO_NET_F_RSC_EXT) | BIT_ULL(VIRTIO_NET_F_STANDBY) | \ 38cbb52359SNathan Chancellor BIT_ULL(VIRTIO_NET_F_SPEED_DUPLEX) | BIT_ULL(VIRTIO_F_NOTIFY_ON_EMPTY) | \ 39cbb52359SNathan Chancellor BIT_ULL(VIRTIO_F_ANY_LAYOUT) | BIT_ULL(VIRTIO_F_VERSION_1) | BIT_ULL(VIRTIO_F_ACCESS_PLATFORM) | \ 40cbb52359SNathan Chancellor BIT_ULL(VIRTIO_F_RING_PACKED) | BIT_ULL(VIRTIO_F_ORDER_PLATFORM) | BIT_ULL(VIRTIO_F_SR_IOV)) 411a86b377SEli Cohen 421a86b377SEli Cohen #define VALID_STATUS_MASK \ 431a86b377SEli Cohen (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK | \ 441a86b377SEli Cohen VIRTIO_CONFIG_S_FEATURES_OK | VIRTIO_CONFIG_S_NEEDS_RESET | VIRTIO_CONFIG_S_FAILED) 451a86b377SEli Cohen 46e4fc6650SEli Cohen #define MLX5_FEATURE(_mvdev, _feature) (!!((_mvdev)->actual_features & BIT_ULL(_feature))) 47e4fc6650SEli Cohen 48baf2ad3fSEli Cohen #define MLX5V_UNTAGGED 0x1000 49baf2ad3fSEli Cohen 501a86b377SEli Cohen struct mlx5_vdpa_cq_buf { 511a86b377SEli Cohen struct mlx5_frag_buf_ctrl fbc; 521a86b377SEli Cohen struct mlx5_frag_buf frag_buf; 531a86b377SEli Cohen int cqe_size; 541a86b377SEli Cohen int nent; 551a86b377SEli Cohen }; 561a86b377SEli Cohen 571a86b377SEli Cohen struct mlx5_vdpa_cq { 581a86b377SEli Cohen struct mlx5_core_cq mcq; 591a86b377SEli Cohen struct mlx5_vdpa_cq_buf buf; 601a86b377SEli Cohen struct mlx5_db db; 611a86b377SEli Cohen int cqe; 621a86b377SEli Cohen }; 631a86b377SEli Cohen 641a86b377SEli Cohen struct mlx5_vdpa_umem { 651a86b377SEli Cohen struct mlx5_frag_buf_ctrl fbc; 661a86b377SEli Cohen struct mlx5_frag_buf frag_buf; 671a86b377SEli Cohen int size; 681a86b377SEli Cohen u32 id; 691a86b377SEli Cohen }; 701a86b377SEli Cohen 711a86b377SEli Cohen struct mlx5_vdpa_qp { 721a86b377SEli Cohen struct mlx5_core_qp mqp; 731a86b377SEli Cohen struct mlx5_frag_buf frag_buf; 741a86b377SEli Cohen struct mlx5_db db; 751a86b377SEli Cohen u16 head; 761a86b377SEli Cohen bool fw; 771a86b377SEli Cohen }; 781a86b377SEli Cohen 791a86b377SEli Cohen struct mlx5_vq_restore_info { 801a86b377SEli Cohen u32 num_ent; 811a86b377SEli Cohen u64 desc_addr; 821a86b377SEli Cohen u64 device_addr; 831a86b377SEli Cohen u64 driver_addr; 841a86b377SEli Cohen u16 avail_index; 85b35ccebeSEli Cohen u16 used_index; 86bc9a2b3eSEli Cohen struct msi_map map; 871a86b377SEli Cohen bool ready; 881a86b377SEli Cohen bool restore; 891a86b377SEli Cohen }; 901a86b377SEli Cohen 911a86b377SEli Cohen struct mlx5_vdpa_virtqueue { 921a86b377SEli Cohen bool ready; 931a86b377SEli Cohen u64 desc_addr; 941a86b377SEli Cohen u64 device_addr; 951a86b377SEli Cohen u64 driver_addr; 961a86b377SEli Cohen u32 num_ent; 971a86b377SEli Cohen 981a86b377SEli Cohen /* Resources for implementing the notification channel from the device 991a86b377SEli Cohen * to the driver. fwqp is the firmware end of an RC connection; the 1002f72b226SXiang wangx * other end is vqqp used by the driver. cq is where completions are 1011a86b377SEli Cohen * reported. 1021a86b377SEli Cohen */ 1031a86b377SEli Cohen struct mlx5_vdpa_cq cq; 1041a86b377SEli Cohen struct mlx5_vdpa_qp fwqp; 1051a86b377SEli Cohen struct mlx5_vdpa_qp vqqp; 1061a86b377SEli Cohen 1071a86b377SEli Cohen /* umem resources are required for the virtqueue operation. They're use 1081a86b377SEli Cohen * is internal and they must be provided by the driver. 1091a86b377SEli Cohen */ 1101a86b377SEli Cohen struct mlx5_vdpa_umem umem1; 1111a86b377SEli Cohen struct mlx5_vdpa_umem umem2; 1121a86b377SEli Cohen struct mlx5_vdpa_umem umem3; 1131a86b377SEli Cohen 1141892a3d4SEli Cohen u32 counter_set_id; 1151a86b377SEli Cohen bool initialized; 1161a86b377SEli Cohen int index; 1171a86b377SEli Cohen u32 virtq_id; 1181a86b377SEli Cohen struct mlx5_vdpa_net *ndev; 1191a86b377SEli Cohen u16 avail_idx; 120b35ccebeSEli Cohen u16 used_idx; 1211a86b377SEli Cohen int fw_state; 122bc9a2b3eSEli Cohen struct msi_map map; 1231a86b377SEli Cohen 1241a86b377SEli Cohen /* keep last in the struct */ 1251a86b377SEli Cohen struct mlx5_vq_restore_info ri; 1261a86b377SEli Cohen }; 1271a86b377SEli Cohen 128e4fc6650SEli Cohen static bool is_index_valid(struct mlx5_vdpa_dev *mvdev, u16 idx) 129e4fc6650SEli Cohen { 130f8ae3a48SEli Cohen if (!(mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_MQ))) { 131f8ae3a48SEli Cohen if (!(mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) 132f8ae3a48SEli Cohen return idx < 2; 133f8ae3a48SEli Cohen else 134f8ae3a48SEli Cohen return idx < 3; 135f8ae3a48SEli Cohen } 136e4fc6650SEli Cohen 137f8ae3a48SEli Cohen return idx <= mvdev->max_idx; 138e4fc6650SEli Cohen } 139e4fc6650SEli Cohen 1401a86b377SEli Cohen static void free_resources(struct mlx5_vdpa_net *ndev); 1411a86b377SEli Cohen static void init_mvqs(struct mlx5_vdpa_net *ndev); 142ae0428deSEli Cohen static int setup_driver(struct mlx5_vdpa_dev *mvdev); 1431a86b377SEli Cohen static void teardown_driver(struct mlx5_vdpa_net *ndev); 1441a86b377SEli Cohen 1451a86b377SEli Cohen static bool mlx5_vdpa_debug; 1461a86b377SEli Cohen 1475262912eSEli Cohen #define MLX5_CVQ_MAX_ENT 16 1485262912eSEli Cohen 1491a86b377SEli Cohen #define MLX5_LOG_VIO_FLAG(_feature) \ 1501a86b377SEli Cohen do { \ 151cbb52359SNathan Chancellor if (features & BIT_ULL(_feature)) \ 1521a86b377SEli Cohen mlx5_vdpa_info(mvdev, "%s\n", #_feature); \ 1531a86b377SEli Cohen } while (0) 1541a86b377SEli Cohen 1551a86b377SEli Cohen #define MLX5_LOG_VIO_STAT(_status) \ 1561a86b377SEli Cohen do { \ 1571a86b377SEli Cohen if (status & (_status)) \ 1581a86b377SEli Cohen mlx5_vdpa_info(mvdev, "%s\n", #_status); \ 1591a86b377SEli Cohen } while (0) 1601a86b377SEli Cohen 16152893733SEli Cohen /* TODO: cross-endian support */ 16252893733SEli Cohen static inline bool mlx5_vdpa_is_little_endian(struct mlx5_vdpa_dev *mvdev) 16352893733SEli Cohen { 16452893733SEli Cohen return virtio_legacy_is_little_endian() || 16552893733SEli Cohen (mvdev->actual_features & BIT_ULL(VIRTIO_F_VERSION_1)); 16652893733SEli Cohen } 16752893733SEli Cohen 16852893733SEli Cohen static u16 mlx5vdpa16_to_cpu(struct mlx5_vdpa_dev *mvdev, __virtio16 val) 16952893733SEli Cohen { 17052893733SEli Cohen return __virtio16_to_cpu(mlx5_vdpa_is_little_endian(mvdev), val); 17152893733SEli Cohen } 17252893733SEli Cohen 17352893733SEli Cohen static __virtio16 cpu_to_mlx5vdpa16(struct mlx5_vdpa_dev *mvdev, u16 val) 17452893733SEli Cohen { 17552893733SEli Cohen return __cpu_to_virtio16(mlx5_vdpa_is_little_endian(mvdev), val); 17652893733SEli Cohen } 17752893733SEli Cohen 1785262912eSEli Cohen static u16 ctrl_vq_idx(struct mlx5_vdpa_dev *mvdev) 1795262912eSEli Cohen { 18052893733SEli Cohen if (!(mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_MQ))) 18152893733SEli Cohen return 2; 18252893733SEli Cohen 183acde3929SEli Cohen return mvdev->max_vqs; 1845262912eSEli Cohen } 1855262912eSEli Cohen 1865262912eSEli Cohen static bool is_ctrl_vq_idx(struct mlx5_vdpa_dev *mvdev, u16 idx) 1875262912eSEli Cohen { 1885262912eSEli Cohen return idx == ctrl_vq_idx(mvdev); 1895262912eSEli Cohen } 1905262912eSEli Cohen 1911a86b377SEli Cohen static void print_status(struct mlx5_vdpa_dev *mvdev, u8 status, bool set) 1921a86b377SEli Cohen { 1931a86b377SEli Cohen if (status & ~VALID_STATUS_MASK) 1941a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "Warning: there are invalid status bits 0x%x\n", 1951a86b377SEli Cohen status & ~VALID_STATUS_MASK); 1961a86b377SEli Cohen 1971a86b377SEli Cohen if (!mlx5_vdpa_debug) 1981a86b377SEli Cohen return; 1991a86b377SEli Cohen 2001a86b377SEli Cohen mlx5_vdpa_info(mvdev, "driver status %s", set ? "set" : "get"); 2011a86b377SEli Cohen if (set && !status) { 2021a86b377SEli Cohen mlx5_vdpa_info(mvdev, "driver resets the device\n"); 2031a86b377SEli Cohen return; 2041a86b377SEli Cohen } 2051a86b377SEli Cohen 2061a86b377SEli Cohen MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_ACKNOWLEDGE); 2071a86b377SEli Cohen MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_DRIVER); 2081a86b377SEli Cohen MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_DRIVER_OK); 2091a86b377SEli Cohen MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_FEATURES_OK); 2101a86b377SEli Cohen MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_NEEDS_RESET); 2111a86b377SEli Cohen MLX5_LOG_VIO_STAT(VIRTIO_CONFIG_S_FAILED); 2121a86b377SEli Cohen } 2131a86b377SEli Cohen 2141a86b377SEli Cohen static void print_features(struct mlx5_vdpa_dev *mvdev, u64 features, bool set) 2151a86b377SEli Cohen { 2161a86b377SEli Cohen if (features & ~VALID_FEATURES_MASK) 2171a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "There are invalid feature bits 0x%llx\n", 2181a86b377SEli Cohen features & ~VALID_FEATURES_MASK); 2191a86b377SEli Cohen 2201a86b377SEli Cohen if (!mlx5_vdpa_debug) 2211a86b377SEli Cohen return; 2221a86b377SEli Cohen 2231a86b377SEli Cohen mlx5_vdpa_info(mvdev, "driver %s feature bits:\n", set ? "sets" : "reads"); 2241a86b377SEli Cohen if (!features) 2251a86b377SEli Cohen mlx5_vdpa_info(mvdev, "all feature bits are cleared\n"); 2261a86b377SEli Cohen 2271a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CSUM); 2281a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_CSUM); 2291a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_GUEST_OFFLOADS); 2301a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_MTU); 2311a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_MAC); 2321a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_TSO4); 2331a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_TSO6); 2341a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_ECN); 2351a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_UFO); 2361a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HOST_TSO4); 2371a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HOST_TSO6); 2381a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HOST_ECN); 2391a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HOST_UFO); 2401a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_MRG_RXBUF); 2411a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_STATUS); 2421a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_VQ); 2431a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_RX); 2441a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_VLAN); 2451a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_RX_EXTRA); 2461a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_GUEST_ANNOUNCE); 2471a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_MQ); 2481a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_CTRL_MAC_ADDR); 2491a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_HASH_REPORT); 2501a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_RSS); 2511a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_RSC_EXT); 2521a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_STANDBY); 2531a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_NET_F_SPEED_DUPLEX); 2541a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_F_NOTIFY_ON_EMPTY); 2551a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_F_ANY_LAYOUT); 2561a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_F_VERSION_1); 2571a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_F_ACCESS_PLATFORM); 2581a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_F_RING_PACKED); 2591a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_F_ORDER_PLATFORM); 2601a86b377SEli Cohen MLX5_LOG_VIO_FLAG(VIRTIO_F_SR_IOV); 2611a86b377SEli Cohen } 2621a86b377SEli Cohen 2631a86b377SEli Cohen static int create_tis(struct mlx5_vdpa_net *ndev) 2641a86b377SEli Cohen { 2651a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = &ndev->mvdev; 2661a86b377SEli Cohen u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {}; 2671a86b377SEli Cohen void *tisc; 2681a86b377SEli Cohen int err; 2691a86b377SEli Cohen 2701a86b377SEli Cohen tisc = MLX5_ADDR_OF(create_tis_in, in, ctx); 2711a86b377SEli Cohen MLX5_SET(tisc, tisc, transport_domain, ndev->res.tdn); 2721a86b377SEli Cohen err = mlx5_vdpa_create_tis(mvdev, in, &ndev->res.tisn); 2731a86b377SEli Cohen if (err) 2741a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "create TIS (%d)\n", err); 2751a86b377SEli Cohen 2761a86b377SEli Cohen return err; 2771a86b377SEli Cohen } 2781a86b377SEli Cohen 2791a86b377SEli Cohen static void destroy_tis(struct mlx5_vdpa_net *ndev) 2801a86b377SEli Cohen { 2811a86b377SEli Cohen mlx5_vdpa_destroy_tis(&ndev->mvdev, ndev->res.tisn); 2821a86b377SEli Cohen } 2831a86b377SEli Cohen 2841a86b377SEli Cohen #define MLX5_VDPA_CQE_SIZE 64 2851a86b377SEli Cohen #define MLX5_VDPA_LOG_CQE_SIZE ilog2(MLX5_VDPA_CQE_SIZE) 2861a86b377SEli Cohen 2871a86b377SEli Cohen static int cq_frag_buf_alloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_cq_buf *buf, int nent) 2881a86b377SEli Cohen { 2891a86b377SEli Cohen struct mlx5_frag_buf *frag_buf = &buf->frag_buf; 2901a86b377SEli Cohen u8 log_wq_stride = MLX5_VDPA_LOG_CQE_SIZE; 2911a86b377SEli Cohen u8 log_wq_sz = MLX5_VDPA_LOG_CQE_SIZE; 2921a86b377SEli Cohen int err; 2931a86b377SEli Cohen 2941a86b377SEli Cohen err = mlx5_frag_buf_alloc_node(ndev->mvdev.mdev, nent * MLX5_VDPA_CQE_SIZE, frag_buf, 2951a86b377SEli Cohen ndev->mvdev.mdev->priv.numa_node); 2961a86b377SEli Cohen if (err) 2971a86b377SEli Cohen return err; 2981a86b377SEli Cohen 2991a86b377SEli Cohen mlx5_init_fbc(frag_buf->frags, log_wq_stride, log_wq_sz, &buf->fbc); 3001a86b377SEli Cohen 3011a86b377SEli Cohen buf->cqe_size = MLX5_VDPA_CQE_SIZE; 3021a86b377SEli Cohen buf->nent = nent; 3031a86b377SEli Cohen 3041a86b377SEli Cohen return 0; 3051a86b377SEli Cohen } 3061a86b377SEli Cohen 3071a86b377SEli Cohen static int umem_frag_buf_alloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_umem *umem, int size) 3081a86b377SEli Cohen { 3091a86b377SEli Cohen struct mlx5_frag_buf *frag_buf = &umem->frag_buf; 3101a86b377SEli Cohen 3111a86b377SEli Cohen return mlx5_frag_buf_alloc_node(ndev->mvdev.mdev, size, frag_buf, 3121a86b377SEli Cohen ndev->mvdev.mdev->priv.numa_node); 3131a86b377SEli Cohen } 3141a86b377SEli Cohen 3151a86b377SEli Cohen static void cq_frag_buf_free(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_cq_buf *buf) 3161a86b377SEli Cohen { 3171a86b377SEli Cohen mlx5_frag_buf_free(ndev->mvdev.mdev, &buf->frag_buf); 3181a86b377SEli Cohen } 3191a86b377SEli Cohen 3201a86b377SEli Cohen static void *get_cqe(struct mlx5_vdpa_cq *vcq, int n) 3211a86b377SEli Cohen { 3221a86b377SEli Cohen return mlx5_frag_buf_get_wqe(&vcq->buf.fbc, n); 3231a86b377SEli Cohen } 3241a86b377SEli Cohen 3251a86b377SEli Cohen static void cq_frag_buf_init(struct mlx5_vdpa_cq *vcq, struct mlx5_vdpa_cq_buf *buf) 3261a86b377SEli Cohen { 3271a86b377SEli Cohen struct mlx5_cqe64 *cqe64; 3281a86b377SEli Cohen void *cqe; 3291a86b377SEli Cohen int i; 3301a86b377SEli Cohen 3311a86b377SEli Cohen for (i = 0; i < buf->nent; i++) { 3321a86b377SEli Cohen cqe = get_cqe(vcq, i); 3331a86b377SEli Cohen cqe64 = cqe; 3341a86b377SEli Cohen cqe64->op_own = MLX5_CQE_INVALID << 4; 3351a86b377SEli Cohen } 3361a86b377SEli Cohen } 3371a86b377SEli Cohen 3381a86b377SEli Cohen static void *get_sw_cqe(struct mlx5_vdpa_cq *cq, int n) 3391a86b377SEli Cohen { 3401a86b377SEli Cohen struct mlx5_cqe64 *cqe64 = get_cqe(cq, n & (cq->cqe - 1)); 3411a86b377SEli Cohen 3421a86b377SEli Cohen if (likely(get_cqe_opcode(cqe64) != MLX5_CQE_INVALID) && 3431a86b377SEli Cohen !((cqe64->op_own & MLX5_CQE_OWNER_MASK) ^ !!(n & cq->cqe))) 3441a86b377SEli Cohen return cqe64; 3451a86b377SEli Cohen 3461a86b377SEli Cohen return NULL; 3471a86b377SEli Cohen } 3481a86b377SEli Cohen 3491a86b377SEli Cohen static void rx_post(struct mlx5_vdpa_qp *vqp, int n) 3501a86b377SEli Cohen { 3511a86b377SEli Cohen vqp->head += n; 3521a86b377SEli Cohen vqp->db.db[0] = cpu_to_be32(vqp->head); 3531a86b377SEli Cohen } 3541a86b377SEli Cohen 3551a86b377SEli Cohen static void qp_prepare(struct mlx5_vdpa_net *ndev, bool fw, void *in, 3561a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq, u32 num_ent) 3571a86b377SEli Cohen { 3581a86b377SEli Cohen struct mlx5_vdpa_qp *vqp; 3591a86b377SEli Cohen __be64 *pas; 3601a86b377SEli Cohen void *qpc; 3611a86b377SEli Cohen 3621a86b377SEli Cohen vqp = fw ? &mvq->fwqp : &mvq->vqqp; 3631a86b377SEli Cohen MLX5_SET(create_qp_in, in, uid, ndev->mvdev.res.uid); 3641a86b377SEli Cohen qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); 3651a86b377SEli Cohen if (vqp->fw) { 3661a86b377SEli Cohen /* Firmware QP is allocated by the driver for the firmware's 3671a86b377SEli Cohen * use so we can skip part of the params as they will be chosen by firmware 3681a86b377SEli Cohen */ 3691a86b377SEli Cohen qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); 3701a86b377SEli Cohen MLX5_SET(qpc, qpc, rq_type, MLX5_ZERO_LEN_RQ); 3711a86b377SEli Cohen MLX5_SET(qpc, qpc, no_sq, 1); 3721a86b377SEli Cohen return; 3731a86b377SEli Cohen } 3741a86b377SEli Cohen 3751a86b377SEli Cohen MLX5_SET(qpc, qpc, st, MLX5_QP_ST_RC); 3761a86b377SEli Cohen MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); 3771a86b377SEli Cohen MLX5_SET(qpc, qpc, pd, ndev->mvdev.res.pdn); 3781a86b377SEli Cohen MLX5_SET(qpc, qpc, mtu, MLX5_QPC_MTU_256_BYTES); 3791a86b377SEli Cohen MLX5_SET(qpc, qpc, uar_page, ndev->mvdev.res.uar->index); 3801a86b377SEli Cohen MLX5_SET(qpc, qpc, log_page_size, vqp->frag_buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); 3811a86b377SEli Cohen MLX5_SET(qpc, qpc, no_sq, 1); 3821a86b377SEli Cohen MLX5_SET(qpc, qpc, cqn_rcv, mvq->cq.mcq.cqn); 3831a86b377SEli Cohen MLX5_SET(qpc, qpc, log_rq_size, ilog2(num_ent)); 3841a86b377SEli Cohen MLX5_SET(qpc, qpc, rq_type, MLX5_NON_ZERO_RQ); 3851a86b377SEli Cohen pas = (__be64 *)MLX5_ADDR_OF(create_qp_in, in, pas); 3861a86b377SEli Cohen mlx5_fill_page_frag_array(&vqp->frag_buf, pas); 3871a86b377SEli Cohen } 3881a86b377SEli Cohen 3891a86b377SEli Cohen static int rq_buf_alloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_qp *vqp, u32 num_ent) 3901a86b377SEli Cohen { 3911a86b377SEli Cohen return mlx5_frag_buf_alloc_node(ndev->mvdev.mdev, 3921a86b377SEli Cohen num_ent * sizeof(struct mlx5_wqe_data_seg), &vqp->frag_buf, 3931a86b377SEli Cohen ndev->mvdev.mdev->priv.numa_node); 3941a86b377SEli Cohen } 3951a86b377SEli Cohen 3961a86b377SEli Cohen static void rq_buf_free(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_qp *vqp) 3971a86b377SEli Cohen { 3981a86b377SEli Cohen mlx5_frag_buf_free(ndev->mvdev.mdev, &vqp->frag_buf); 3991a86b377SEli Cohen } 4001a86b377SEli Cohen 4011a86b377SEli Cohen static int qp_create(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, 4021a86b377SEli Cohen struct mlx5_vdpa_qp *vqp) 4031a86b377SEli Cohen { 4041a86b377SEli Cohen struct mlx5_core_dev *mdev = ndev->mvdev.mdev; 4051a86b377SEli Cohen int inlen = MLX5_ST_SZ_BYTES(create_qp_in); 4061a86b377SEli Cohen u32 out[MLX5_ST_SZ_DW(create_qp_out)] = {}; 4071a86b377SEli Cohen void *qpc; 4081a86b377SEli Cohen void *in; 4091a86b377SEli Cohen int err; 4101a86b377SEli Cohen 4111a86b377SEli Cohen if (!vqp->fw) { 4121a86b377SEli Cohen vqp = &mvq->vqqp; 4131a86b377SEli Cohen err = rq_buf_alloc(ndev, vqp, mvq->num_ent); 4141a86b377SEli Cohen if (err) 4151a86b377SEli Cohen return err; 4161a86b377SEli Cohen 4171a86b377SEli Cohen err = mlx5_db_alloc(ndev->mvdev.mdev, &vqp->db); 4181a86b377SEli Cohen if (err) 4191a86b377SEli Cohen goto err_db; 4201a86b377SEli Cohen inlen += vqp->frag_buf.npages * sizeof(__be64); 4211a86b377SEli Cohen } 4221a86b377SEli Cohen 4231a86b377SEli Cohen in = kzalloc(inlen, GFP_KERNEL); 4241a86b377SEli Cohen if (!in) { 4251a86b377SEli Cohen err = -ENOMEM; 4261a86b377SEli Cohen goto err_kzalloc; 4271a86b377SEli Cohen } 4281a86b377SEli Cohen 4291a86b377SEli Cohen qp_prepare(ndev, vqp->fw, in, mvq, mvq->num_ent); 4301a86b377SEli Cohen qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); 4311a86b377SEli Cohen MLX5_SET(qpc, qpc, st, MLX5_QP_ST_RC); 4321a86b377SEli Cohen MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); 4331a86b377SEli Cohen MLX5_SET(qpc, qpc, pd, ndev->mvdev.res.pdn); 4341a86b377SEli Cohen MLX5_SET(qpc, qpc, mtu, MLX5_QPC_MTU_256_BYTES); 4351a86b377SEli Cohen if (!vqp->fw) 4361a86b377SEli Cohen MLX5_SET64(qpc, qpc, dbr_addr, vqp->db.dma); 4371a86b377SEli Cohen MLX5_SET(create_qp_in, in, opcode, MLX5_CMD_OP_CREATE_QP); 4381a86b377SEli Cohen err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); 4391a86b377SEli Cohen kfree(in); 4401a86b377SEli Cohen if (err) 4411a86b377SEli Cohen goto err_kzalloc; 4421a86b377SEli Cohen 4431a86b377SEli Cohen vqp->mqp.uid = ndev->mvdev.res.uid; 4441a86b377SEli Cohen vqp->mqp.qpn = MLX5_GET(create_qp_out, out, qpn); 4451a86b377SEli Cohen 4461a86b377SEli Cohen if (!vqp->fw) 4471a86b377SEli Cohen rx_post(vqp, mvq->num_ent); 4481a86b377SEli Cohen 4491a86b377SEli Cohen return 0; 4501a86b377SEli Cohen 4511a86b377SEli Cohen err_kzalloc: 4521a86b377SEli Cohen if (!vqp->fw) 4531a86b377SEli Cohen mlx5_db_free(ndev->mvdev.mdev, &vqp->db); 4541a86b377SEli Cohen err_db: 4551a86b377SEli Cohen if (!vqp->fw) 4561a86b377SEli Cohen rq_buf_free(ndev, vqp); 4571a86b377SEli Cohen 4581a86b377SEli Cohen return err; 4591a86b377SEli Cohen } 4601a86b377SEli Cohen 4611a86b377SEli Cohen static void qp_destroy(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_qp *vqp) 4621a86b377SEli Cohen { 4631a86b377SEli Cohen u32 in[MLX5_ST_SZ_DW(destroy_qp_in)] = {}; 4641a86b377SEli Cohen 4651a86b377SEli Cohen MLX5_SET(destroy_qp_in, in, opcode, MLX5_CMD_OP_DESTROY_QP); 4661a86b377SEli Cohen MLX5_SET(destroy_qp_in, in, qpn, vqp->mqp.qpn); 4671a86b377SEli Cohen MLX5_SET(destroy_qp_in, in, uid, ndev->mvdev.res.uid); 4681a86b377SEli Cohen if (mlx5_cmd_exec_in(ndev->mvdev.mdev, destroy_qp, in)) 4691a86b377SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "destroy qp 0x%x\n", vqp->mqp.qpn); 4701a86b377SEli Cohen if (!vqp->fw) { 4711a86b377SEli Cohen mlx5_db_free(ndev->mvdev.mdev, &vqp->db); 4721a86b377SEli Cohen rq_buf_free(ndev, vqp); 4731a86b377SEli Cohen } 4741a86b377SEli Cohen } 4751a86b377SEli Cohen 4761a86b377SEli Cohen static void *next_cqe_sw(struct mlx5_vdpa_cq *cq) 4771a86b377SEli Cohen { 4781a86b377SEli Cohen return get_sw_cqe(cq, cq->mcq.cons_index); 4791a86b377SEli Cohen } 4801a86b377SEli Cohen 4811a86b377SEli Cohen static int mlx5_vdpa_poll_one(struct mlx5_vdpa_cq *vcq) 4821a86b377SEli Cohen { 4831a86b377SEli Cohen struct mlx5_cqe64 *cqe64; 4841a86b377SEli Cohen 4851a86b377SEli Cohen cqe64 = next_cqe_sw(vcq); 4861a86b377SEli Cohen if (!cqe64) 4871a86b377SEli Cohen return -EAGAIN; 4881a86b377SEli Cohen 4891a86b377SEli Cohen vcq->mcq.cons_index++; 4901a86b377SEli Cohen return 0; 4911a86b377SEli Cohen } 4921a86b377SEli Cohen 4931a86b377SEli Cohen static void mlx5_vdpa_handle_completions(struct mlx5_vdpa_virtqueue *mvq, int num) 4941a86b377SEli Cohen { 495db296d25SEli Cohen struct mlx5_vdpa_net *ndev = mvq->ndev; 496db296d25SEli Cohen struct vdpa_callback *event_cb; 497db296d25SEli Cohen 498db296d25SEli Cohen event_cb = &ndev->event_cbs[mvq->index]; 4991a86b377SEli Cohen mlx5_cq_set_ci(&mvq->cq.mcq); 50083ef73b2SEli Cohen 50183ef73b2SEli Cohen /* make sure CQ cosumer update is visible to the hardware before updating 50283ef73b2SEli Cohen * RX doorbell record. 50383ef73b2SEli Cohen */ 50483ef73b2SEli Cohen dma_wmb(); 5051a86b377SEli Cohen rx_post(&mvq->vqqp, num); 506db296d25SEli Cohen if (event_cb->callback) 507db296d25SEli Cohen event_cb->callback(event_cb->private); 5081a86b377SEli Cohen } 5091a86b377SEli Cohen 5101a86b377SEli Cohen static void mlx5_vdpa_cq_comp(struct mlx5_core_cq *mcq, struct mlx5_eqe *eqe) 5111a86b377SEli Cohen { 5121a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq = container_of(mcq, struct mlx5_vdpa_virtqueue, cq.mcq); 5131a86b377SEli Cohen struct mlx5_vdpa_net *ndev = mvq->ndev; 5141a86b377SEli Cohen void __iomem *uar_page = ndev->mvdev.res.uar->map; 5151a86b377SEli Cohen int num = 0; 5161a86b377SEli Cohen 5171a86b377SEli Cohen while (!mlx5_vdpa_poll_one(&mvq->cq)) { 5181a86b377SEli Cohen num++; 5191a86b377SEli Cohen if (num > mvq->num_ent / 2) { 5201a86b377SEli Cohen /* If completions keep coming while we poll, we want to 5211a86b377SEli Cohen * let the hardware know that we consumed them by 5221a86b377SEli Cohen * updating the doorbell record. We also let vdpa core 5231a86b377SEli Cohen * know about this so it passes it on the virtio driver 5241a86b377SEli Cohen * on the guest. 5251a86b377SEli Cohen */ 5261a86b377SEli Cohen mlx5_vdpa_handle_completions(mvq, num); 5271a86b377SEli Cohen num = 0; 5281a86b377SEli Cohen } 5291a86b377SEli Cohen } 5301a86b377SEli Cohen 5311a86b377SEli Cohen if (num) 5321a86b377SEli Cohen mlx5_vdpa_handle_completions(mvq, num); 5331a86b377SEli Cohen 5341a86b377SEli Cohen mlx5_cq_arm(&mvq->cq.mcq, MLX5_CQ_DB_REQ_NOT, uar_page, mvq->cq.mcq.cons_index); 5351a86b377SEli Cohen } 5361a86b377SEli Cohen 5371a86b377SEli Cohen static int cq_create(struct mlx5_vdpa_net *ndev, u16 idx, u32 num_ent) 5381a86b377SEli Cohen { 5391a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq = &ndev->vqs[idx]; 5401a86b377SEli Cohen struct mlx5_core_dev *mdev = ndev->mvdev.mdev; 5411a86b377SEli Cohen void __iomem *uar_page = ndev->mvdev.res.uar->map; 5421a86b377SEli Cohen u32 out[MLX5_ST_SZ_DW(create_cq_out)]; 5431a86b377SEli Cohen struct mlx5_vdpa_cq *vcq = &mvq->cq; 5441a86b377SEli Cohen __be64 *pas; 5451a86b377SEli Cohen int inlen; 5461a86b377SEli Cohen void *cqc; 5471a86b377SEli Cohen void *in; 5481a86b377SEli Cohen int err; 5491a86b377SEli Cohen int eqn; 5501a86b377SEli Cohen 5511a86b377SEli Cohen err = mlx5_db_alloc(mdev, &vcq->db); 5521a86b377SEli Cohen if (err) 5531a86b377SEli Cohen return err; 5541a86b377SEli Cohen 5551a86b377SEli Cohen vcq->mcq.set_ci_db = vcq->db.db; 5561a86b377SEli Cohen vcq->mcq.arm_db = vcq->db.db + 1; 5571a86b377SEli Cohen vcq->mcq.cqe_sz = 64; 5581a86b377SEli Cohen 5591a86b377SEli Cohen err = cq_frag_buf_alloc(ndev, &vcq->buf, num_ent); 5601a86b377SEli Cohen if (err) 5611a86b377SEli Cohen goto err_db; 5621a86b377SEli Cohen 5631a86b377SEli Cohen cq_frag_buf_init(vcq, &vcq->buf); 5641a86b377SEli Cohen 5651a86b377SEli Cohen inlen = MLX5_ST_SZ_BYTES(create_cq_in) + 5661a86b377SEli Cohen MLX5_FLD_SZ_BYTES(create_cq_in, pas[0]) * vcq->buf.frag_buf.npages; 5671a86b377SEli Cohen in = kzalloc(inlen, GFP_KERNEL); 5681a86b377SEli Cohen if (!in) { 5691a86b377SEli Cohen err = -ENOMEM; 5701a86b377SEli Cohen goto err_vzalloc; 5711a86b377SEli Cohen } 5721a86b377SEli Cohen 5731a86b377SEli Cohen MLX5_SET(create_cq_in, in, uid, ndev->mvdev.res.uid); 5741a86b377SEli Cohen pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas); 5751a86b377SEli Cohen mlx5_fill_page_frag_array(&vcq->buf.frag_buf, pas); 5761a86b377SEli Cohen 5771a86b377SEli Cohen cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context); 5781a86b377SEli Cohen MLX5_SET(cqc, cqc, log_page_size, vcq->buf.frag_buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); 5791a86b377SEli Cohen 5801a86b377SEli Cohen /* Use vector 0 by default. Consider adding code to choose least used 5811a86b377SEli Cohen * vector. 5821a86b377SEli Cohen */ 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 813bc9a2b3eSEli Cohen static bool msix_mode_supported(struct mlx5_vdpa_dev *mvdev) 814bc9a2b3eSEli Cohen { 815bc9a2b3eSEli Cohen return MLX5_CAP_DEV_VDPA_EMULATION(mvdev->mdev, event_mode) & 816bc9a2b3eSEli Cohen (1 << MLX5_VIRTIO_Q_EVENT_MODE_MSIX_MODE) && 817bc9a2b3eSEli Cohen pci_msix_can_alloc_dyn(mvdev->mdev->pdev); 818bc9a2b3eSEli Cohen } 819bc9a2b3eSEli 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 861bc9a2b3eSEli Cohen if (mvq->map.virq) { 862bc9a2b3eSEli Cohen MLX5_SET(virtio_q, vq_ctx, event_mode, MLX5_VIRTIO_Q_EVENT_MODE_MSIX_MODE); 863bc9a2b3eSEli Cohen MLX5_SET(virtio_q, vq_ctx, event_qpn_or_msix, mvq->map.index); 864bc9a2b3eSEli 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); 867bc9a2b3eSEli Cohen } 868bc9a2b3eSEli Cohen 869bc9a2b3eSEli 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 1212bc9a2b3eSEli Cohen static irqreturn_t mlx5_vdpa_int_handler(int irq, void *priv) 1213bc9a2b3eSEli Cohen { 1214bc9a2b3eSEli Cohen struct vdpa_callback *cb = priv; 1215bc9a2b3eSEli Cohen 1216bc9a2b3eSEli Cohen if (cb->callback) 1217bc9a2b3eSEli Cohen return cb->callback(cb->private); 1218bc9a2b3eSEli Cohen 1219bc9a2b3eSEli Cohen return IRQ_HANDLED; 1220bc9a2b3eSEli Cohen } 1221bc9a2b3eSEli Cohen 1222bc9a2b3eSEli Cohen static void alloc_vector(struct mlx5_vdpa_net *ndev, 1223bc9a2b3eSEli Cohen struct mlx5_vdpa_virtqueue *mvq) 1224bc9a2b3eSEli Cohen { 1225bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool *irqp = &ndev->irqp; 1226bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool_entry *ent; 1227bc9a2b3eSEli Cohen int err; 1228bc9a2b3eSEli Cohen int i; 1229bc9a2b3eSEli Cohen 1230bc9a2b3eSEli Cohen for (i = 0; i < irqp->num_ent; i++) { 1231bc9a2b3eSEli Cohen ent = &irqp->entries[i]; 1232bc9a2b3eSEli Cohen if (!ent->used) { 1233bc9a2b3eSEli Cohen snprintf(ent->name, MLX5_VDPA_IRQ_NAME_LEN, "%s-vq-%d", 1234bc9a2b3eSEli Cohen dev_name(&ndev->mvdev.vdev.dev), mvq->index); 1235bc9a2b3eSEli Cohen ent->dev_id = &ndev->event_cbs[mvq->index]; 1236bc9a2b3eSEli Cohen err = request_irq(ent->map.virq, mlx5_vdpa_int_handler, 0, 1237bc9a2b3eSEli Cohen ent->name, ent->dev_id); 1238bc9a2b3eSEli Cohen if (err) 1239bc9a2b3eSEli Cohen return; 1240bc9a2b3eSEli Cohen 1241bc9a2b3eSEli Cohen ent->used = true; 1242bc9a2b3eSEli Cohen mvq->map = ent->map; 1243bc9a2b3eSEli Cohen return; 1244bc9a2b3eSEli Cohen } 1245bc9a2b3eSEli Cohen } 1246bc9a2b3eSEli Cohen } 1247bc9a2b3eSEli Cohen 1248bc9a2b3eSEli Cohen static void dealloc_vector(struct mlx5_vdpa_net *ndev, 1249bc9a2b3eSEli Cohen struct mlx5_vdpa_virtqueue *mvq) 1250bc9a2b3eSEli Cohen { 1251bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool *irqp = &ndev->irqp; 1252bc9a2b3eSEli Cohen int i; 1253bc9a2b3eSEli Cohen 1254bc9a2b3eSEli Cohen for (i = 0; i < irqp->num_ent; i++) 1255bc9a2b3eSEli Cohen if (mvq->map.virq == irqp->entries[i].map.virq) { 1256bc9a2b3eSEli Cohen free_irq(mvq->map.virq, irqp->entries[i].dev_id); 1257bc9a2b3eSEli Cohen irqp->entries[i].used = false; 1258bc9a2b3eSEli Cohen return; 1259bc9a2b3eSEli Cohen } 1260bc9a2b3eSEli Cohen } 1261bc9a2b3eSEli 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) 1291bc9a2b3eSEli Cohen goto err_connect; 12921892a3d4SEli Cohen 1293bc9a2b3eSEli Cohen alloc_vector(ndev, mvq); 12941a86b377SEli Cohen err = create_virtqueue(ndev, mvq); 12951a86b377SEli Cohen if (err) 1296bc9a2b3eSEli 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); 1303bc9a2b3eSEli Cohen goto err_modify; 13041a86b377SEli Cohen } 13051a86b377SEli Cohen } 13061a86b377SEli Cohen 13071a86b377SEli Cohen mvq->initialized = true; 13081a86b377SEli Cohen return 0; 13091a86b377SEli Cohen 1310bc9a2b3eSEli Cohen err_modify: 1311bc9a2b3eSEli Cohen destroy_virtqueue(ndev, mvq); 1312bc9a2b3eSEli Cohen err_vq: 1313bc9a2b3eSEli Cohen dealloc_vector(ndev, mvq); 13141892a3d4SEli Cohen counter_set_dealloc(ndev, mvq); 1315bc9a2b3eSEli 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); 1360bc9a2b3eSEli 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 2520*3fe02419SDragos Tatulea /* Device must start with 1 queue pair, as per VIRTIO v1.2 spec, section 2521*3fe02419SDragos Tatulea * 5.1.6.5.5 "Device operation in multiqueue mode": 2522*3fe02419SDragos Tatulea * 2523*3fe02419SDragos Tatulea * Multiqueue is disabled by default. 2524*3fe02419SDragos Tatulea * The driver enables multiqueue by sending a command using class 2525*3fe02419SDragos Tatulea * VIRTIO_NET_CTRL_MQ. The command selects the mode of multiqueue 2526*3fe02419SDragos Tatulea * operation, as follows: ... 2527*3fe02419SDragos Tatulea */ 2528*3fe02419SDragos Tatulea ndev->cur_num_vqs = 2; 2529b03fc43eSEli Cohen 2530e4fc6650SEli Cohen update_cvq_info(mvdev); 25311a86b377SEli Cohen return err; 25321a86b377SEli Cohen } 25331a86b377SEli Cohen 25341a86b377SEli Cohen static void mlx5_vdpa_set_config_cb(struct vdpa_device *vdev, struct vdpa_callback *cb) 25351a86b377SEli Cohen { 2536edf747afSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 2537edf747afSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 2538edf747afSEli Cohen 2539edf747afSEli Cohen ndev->config_cb = *cb; 25401a86b377SEli Cohen } 25411a86b377SEli Cohen 25421a86b377SEli Cohen #define MLX5_VDPA_MAX_VQ_ENTRIES 256 25431a86b377SEli Cohen static u16 mlx5_vdpa_get_vq_num_max(struct vdpa_device *vdev) 25441a86b377SEli Cohen { 25451a86b377SEli Cohen return MLX5_VDPA_MAX_VQ_ENTRIES; 25461a86b377SEli Cohen } 25471a86b377SEli Cohen 25481a86b377SEli Cohen static u32 mlx5_vdpa_get_device_id(struct vdpa_device *vdev) 25491a86b377SEli Cohen { 25501a86b377SEli Cohen return VIRTIO_ID_NET; 25511a86b377SEli Cohen } 25521a86b377SEli Cohen 25531a86b377SEli Cohen static u32 mlx5_vdpa_get_vendor_id(struct vdpa_device *vdev) 25541a86b377SEli Cohen { 25551a86b377SEli Cohen return PCI_VENDOR_ID_MELLANOX; 25561a86b377SEli Cohen } 25571a86b377SEli Cohen 25581a86b377SEli Cohen static u8 mlx5_vdpa_get_status(struct vdpa_device *vdev) 25591a86b377SEli Cohen { 25601a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 25611a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 25621a86b377SEli Cohen 25631a86b377SEli Cohen print_status(mvdev, ndev->mvdev.status, false); 25641a86b377SEli Cohen return ndev->mvdev.status; 25651a86b377SEli Cohen } 25661a86b377SEli Cohen 25671a86b377SEli Cohen static int save_channel_info(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) 25681a86b377SEli Cohen { 25691a86b377SEli Cohen struct mlx5_vq_restore_info *ri = &mvq->ri; 257052893733SEli Cohen struct mlx5_virtq_attr attr = {}; 25711a86b377SEli Cohen int err; 25721a86b377SEli Cohen 257352893733SEli Cohen if (mvq->initialized) { 25741a86b377SEli Cohen err = query_virtqueue(ndev, mvq, &attr); 25751a86b377SEli Cohen if (err) 25761a86b377SEli Cohen return err; 257752893733SEli Cohen } 25781a86b377SEli Cohen 25791a86b377SEli Cohen ri->avail_index = attr.available_index; 2580b35ccebeSEli Cohen ri->used_index = attr.used_index; 25811a86b377SEli Cohen ri->ready = mvq->ready; 25821a86b377SEli Cohen ri->num_ent = mvq->num_ent; 25831a86b377SEli Cohen ri->desc_addr = mvq->desc_addr; 25841a86b377SEli Cohen ri->device_addr = mvq->device_addr; 25851a86b377SEli Cohen ri->driver_addr = mvq->driver_addr; 2586bc9a2b3eSEli Cohen ri->map = mvq->map; 25871a86b377SEli Cohen ri->restore = true; 25881a86b377SEli Cohen return 0; 25891a86b377SEli Cohen } 25901a86b377SEli Cohen 25911a86b377SEli Cohen static int save_channels_info(struct mlx5_vdpa_net *ndev) 25921a86b377SEli Cohen { 25931a86b377SEli Cohen int i; 25941a86b377SEli Cohen 25951a86b377SEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) { 25961a86b377SEli Cohen memset(&ndev->vqs[i].ri, 0, sizeof(ndev->vqs[i].ri)); 25971a86b377SEli Cohen save_channel_info(ndev, &ndev->vqs[i]); 25981a86b377SEli Cohen } 25991a86b377SEli Cohen return 0; 26001a86b377SEli Cohen } 26011a86b377SEli Cohen 26021a86b377SEli Cohen static void mlx5_clear_vqs(struct mlx5_vdpa_net *ndev) 26031a86b377SEli Cohen { 26041a86b377SEli Cohen int i; 26051a86b377SEli Cohen 26061a86b377SEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) 26071a86b377SEli Cohen memset(&ndev->vqs[i], 0, offsetof(struct mlx5_vdpa_virtqueue, ri)); 26081a86b377SEli Cohen } 26091a86b377SEli Cohen 26101a86b377SEli Cohen static void restore_channels_info(struct mlx5_vdpa_net *ndev) 26111a86b377SEli Cohen { 26121a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq; 26131a86b377SEli Cohen struct mlx5_vq_restore_info *ri; 26141a86b377SEli Cohen int i; 26151a86b377SEli Cohen 26161a86b377SEli Cohen mlx5_clear_vqs(ndev); 26171a86b377SEli Cohen init_mvqs(ndev); 26181a86b377SEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) { 26191a86b377SEli Cohen mvq = &ndev->vqs[i]; 26201a86b377SEli Cohen ri = &mvq->ri; 26211a86b377SEli Cohen if (!ri->restore) 26221a86b377SEli Cohen continue; 26231a86b377SEli Cohen 26241a86b377SEli Cohen mvq->avail_idx = ri->avail_index; 2625b35ccebeSEli Cohen mvq->used_idx = ri->used_index; 26261a86b377SEli Cohen mvq->ready = ri->ready; 26271a86b377SEli Cohen mvq->num_ent = ri->num_ent; 26281a86b377SEli Cohen mvq->desc_addr = ri->desc_addr; 26291a86b377SEli Cohen mvq->device_addr = ri->device_addr; 26301a86b377SEli Cohen mvq->driver_addr = ri->driver_addr; 2631bc9a2b3eSEli Cohen mvq->map = ri->map; 26321a86b377SEli Cohen } 26331a86b377SEli Cohen } 26341a86b377SEli Cohen 263538fc462fSEli Cohen static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, 263638fc462fSEli Cohen struct vhost_iotlb *iotlb, unsigned int asid) 26371a86b377SEli Cohen { 2638ae0428deSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 26391a86b377SEli Cohen int err; 26401a86b377SEli Cohen 26411a86b377SEli Cohen suspend_vqs(ndev); 26421a86b377SEli Cohen err = save_channels_info(ndev); 26431a86b377SEli Cohen if (err) 26441a86b377SEli Cohen goto err_mr; 26451a86b377SEli Cohen 26461a86b377SEli Cohen teardown_driver(ndev); 2647ae0428deSEli Cohen mlx5_vdpa_destroy_mr(mvdev); 264838fc462fSEli Cohen err = mlx5_vdpa_create_mr(mvdev, iotlb, asid); 26491a86b377SEli Cohen if (err) 26501a86b377SEli Cohen goto err_mr; 26511a86b377SEli Cohen 265209e65ee9SSi-Wei Liu if (!(mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK) || mvdev->suspended) 26531c80cf03SJason Wang goto err_mr; 26541897f0b6SEli Cohen 26551a86b377SEli Cohen restore_channels_info(ndev); 2656ae0428deSEli Cohen err = setup_driver(mvdev); 26571a86b377SEli Cohen if (err) 26581a86b377SEli Cohen goto err_setup; 26591a86b377SEli Cohen 26601a86b377SEli Cohen return 0; 26611a86b377SEli Cohen 26621a86b377SEli Cohen err_setup: 2663ae0428deSEli Cohen mlx5_vdpa_destroy_mr(mvdev); 26641a86b377SEli Cohen err_mr: 26651a86b377SEli Cohen return err; 26661a86b377SEli Cohen } 26671a86b377SEli Cohen 26681c80cf03SJason Wang /* reslock must be held for this function */ 2669ae0428deSEli Cohen static int setup_driver(struct mlx5_vdpa_dev *mvdev) 26701a86b377SEli Cohen { 2671ae0428deSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 26721a86b377SEli Cohen int err; 26731a86b377SEli Cohen 2674759ae7f9SEli Cohen WARN_ON(!rwsem_is_locked(&ndev->reslock)); 26751c80cf03SJason Wang 26761a86b377SEli Cohen if (ndev->setup) { 2677ae0428deSEli Cohen mlx5_vdpa_warn(mvdev, "setup driver called for already setup driver\n"); 26781a86b377SEli Cohen err = 0; 26791a86b377SEli Cohen goto out; 26801a86b377SEli Cohen } 2681f0417e72SEli Cohen mlx5_vdpa_add_debugfs(ndev); 2682ae0428deSEli Cohen err = setup_virtqueues(mvdev); 26831a86b377SEli Cohen if (err) { 2684ae0428deSEli Cohen mlx5_vdpa_warn(mvdev, "setup_virtqueues\n"); 2685f0417e72SEli Cohen goto err_setup; 26861a86b377SEli Cohen } 26871a86b377SEli Cohen 26881a86b377SEli Cohen err = create_rqt(ndev); 26891a86b377SEli Cohen if (err) { 2690ae0428deSEli Cohen mlx5_vdpa_warn(mvdev, "create_rqt\n"); 26911a86b377SEli Cohen goto err_rqt; 26921a86b377SEli Cohen } 26931a86b377SEli Cohen 26941a86b377SEli Cohen err = create_tir(ndev); 26951a86b377SEli Cohen if (err) { 2696ae0428deSEli Cohen mlx5_vdpa_warn(mvdev, "create_tir\n"); 26971a86b377SEli Cohen goto err_tir; 26981a86b377SEli Cohen } 26991a86b377SEli Cohen 2700baf2ad3fSEli Cohen err = setup_steering(ndev); 27011a86b377SEli Cohen if (err) { 2702baf2ad3fSEli Cohen mlx5_vdpa_warn(mvdev, "setup_steering\n"); 27031a86b377SEli Cohen goto err_fwd; 27041a86b377SEli Cohen } 27051a86b377SEli Cohen ndev->setup = true; 27061a86b377SEli Cohen 27071a86b377SEli Cohen return 0; 27081a86b377SEli Cohen 27091a86b377SEli Cohen err_fwd: 27101a86b377SEli Cohen destroy_tir(ndev); 27111a86b377SEli Cohen err_tir: 27121a86b377SEli Cohen destroy_rqt(ndev); 27131a86b377SEli Cohen err_rqt: 27141a86b377SEli Cohen teardown_virtqueues(ndev); 2715f0417e72SEli Cohen err_setup: 2716f0417e72SEli Cohen mlx5_vdpa_remove_debugfs(ndev->debugfs); 27171a86b377SEli Cohen out: 27181a86b377SEli Cohen return err; 27191a86b377SEli Cohen } 27201a86b377SEli Cohen 27211c80cf03SJason Wang /* reslock must be held for this function */ 27221a86b377SEli Cohen static void teardown_driver(struct mlx5_vdpa_net *ndev) 27231a86b377SEli Cohen { 27241c80cf03SJason Wang 2725759ae7f9SEli Cohen WARN_ON(!rwsem_is_locked(&ndev->reslock)); 27261c80cf03SJason Wang 27271a86b377SEli Cohen if (!ndev->setup) 27281c80cf03SJason Wang return; 27291a86b377SEli Cohen 2730f0417e72SEli Cohen mlx5_vdpa_remove_debugfs(ndev->debugfs); 2731f0417e72SEli Cohen ndev->debugfs = NULL; 2732baf2ad3fSEli Cohen teardown_steering(ndev); 27331a86b377SEli Cohen destroy_tir(ndev); 27341a86b377SEli Cohen destroy_rqt(ndev); 27351a86b377SEli Cohen teardown_virtqueues(ndev); 27361a86b377SEli Cohen ndev->setup = false; 27371a86b377SEli Cohen } 27381a86b377SEli Cohen 2739e3aadf2eSEli Cohen static void clear_vqs_ready(struct mlx5_vdpa_net *ndev) 2740e3aadf2eSEli Cohen { 2741e3aadf2eSEli Cohen int i; 2742e3aadf2eSEli Cohen 2743e3aadf2eSEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) 2744e3aadf2eSEli Cohen ndev->vqs[i].ready = false; 2745ef12e4bfSEli Cohen 2746ef12e4bfSEli Cohen ndev->mvdev.cvq.ready = false; 2747e3aadf2eSEli Cohen } 2748e3aadf2eSEli Cohen 2749ace92524SEli Cohen static int setup_cvq_vring(struct mlx5_vdpa_dev *mvdev) 2750ace92524SEli Cohen { 2751ace92524SEli Cohen struct mlx5_control_vq *cvq = &mvdev->cvq; 2752ace92524SEli Cohen int err = 0; 2753ace92524SEli Cohen 2754ace92524SEli Cohen if (mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ)) 2755ace92524SEli Cohen err = vringh_init_iotlb(&cvq->vring, mvdev->actual_features, 2756ace92524SEli Cohen MLX5_CVQ_MAX_ENT, false, 2757ace92524SEli Cohen (struct vring_desc *)(uintptr_t)cvq->desc_addr, 2758ace92524SEli Cohen (struct vring_avail *)(uintptr_t)cvq->driver_addr, 2759ace92524SEli Cohen (struct vring_used *)(uintptr_t)cvq->device_addr); 2760ace92524SEli Cohen 2761ace92524SEli Cohen return err; 2762ace92524SEli Cohen } 2763ace92524SEli Cohen 27641a86b377SEli Cohen static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) 27651a86b377SEli Cohen { 27661a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 27671a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 27681a86b377SEli Cohen int err; 27691a86b377SEli Cohen 27701a86b377SEli Cohen print_status(mvdev, status, true); 27711a86b377SEli Cohen 2772759ae7f9SEli Cohen down_write(&ndev->reslock); 27731c80cf03SJason Wang 27741a86b377SEli Cohen if ((status ^ ndev->mvdev.status) & VIRTIO_CONFIG_S_DRIVER_OK) { 27751a86b377SEli Cohen if (status & VIRTIO_CONFIG_S_DRIVER_OK) { 2776ace92524SEli Cohen err = setup_cvq_vring(mvdev); 2777ace92524SEli Cohen if (err) { 2778ace92524SEli Cohen mlx5_vdpa_warn(mvdev, "failed to setup control VQ vring\n"); 2779ace92524SEli Cohen goto err_setup; 2780ace92524SEli Cohen } 2781c384c240SEli Cohen register_link_notifier(ndev); 2782ae0428deSEli Cohen err = setup_driver(mvdev); 27831a86b377SEli Cohen if (err) { 27841a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "failed to setup driver\n"); 2785c384c240SEli Cohen goto err_driver; 27861a86b377SEli Cohen } 27871a86b377SEli Cohen } else { 27881a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "did not expect DRIVER_OK to be cleared\n"); 27891c80cf03SJason Wang goto err_clear; 27901a86b377SEli Cohen } 27911a86b377SEli Cohen } 27921a86b377SEli Cohen 27931a86b377SEli Cohen ndev->mvdev.status = status; 2794759ae7f9SEli Cohen up_write(&ndev->reslock); 27951a86b377SEli Cohen return; 27961a86b377SEli Cohen 2797c384c240SEli Cohen err_driver: 2798c384c240SEli Cohen unregister_link_notifier(ndev); 27991a86b377SEli Cohen err_setup: 28001a86b377SEli Cohen mlx5_vdpa_destroy_mr(&ndev->mvdev); 28011a86b377SEli Cohen ndev->mvdev.status |= VIRTIO_CONFIG_S_FAILED; 28021c80cf03SJason Wang err_clear: 2803759ae7f9SEli Cohen up_write(&ndev->reslock); 28041a86b377SEli Cohen } 28051a86b377SEli Cohen 28068fcd20c3SEli Cohen static void init_group_to_asid_map(struct mlx5_vdpa_dev *mvdev) 28078fcd20c3SEli Cohen { 28088fcd20c3SEli Cohen int i; 28098fcd20c3SEli Cohen 28108fcd20c3SEli Cohen /* default mapping all groups are mapped to asid 0 */ 28118fcd20c3SEli Cohen for (i = 0; i < MLX5_VDPA_NUMVQ_GROUPS; i++) 28128fcd20c3SEli Cohen mvdev->group2asid[i] = 0; 28138fcd20c3SEli Cohen } 28148fcd20c3SEli Cohen 28150686082dSXie Yongji static int mlx5_vdpa_reset(struct vdpa_device *vdev) 28160686082dSXie Yongji { 28170686082dSXie Yongji struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 28180686082dSXie Yongji struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 28190686082dSXie Yongji 28200686082dSXie Yongji print_status(mvdev, 0, true); 28210686082dSXie Yongji mlx5_vdpa_info(mvdev, "performing device reset\n"); 28221c80cf03SJason Wang 2823759ae7f9SEli Cohen down_write(&ndev->reslock); 2824c384c240SEli Cohen unregister_link_notifier(ndev); 28250686082dSXie Yongji teardown_driver(ndev); 28260686082dSXie Yongji clear_vqs_ready(ndev); 28270686082dSXie Yongji mlx5_vdpa_destroy_mr(&ndev->mvdev); 28280686082dSXie Yongji ndev->mvdev.status = 0; 282909e65ee9SSi-Wei Liu ndev->mvdev.suspended = false; 2830b03fc43eSEli Cohen ndev->cur_num_vqs = 0; 28311892a3d4SEli Cohen ndev->mvdev.cvq.received_desc = 0; 28321892a3d4SEli Cohen ndev->mvdev.cvq.completed_desc = 0; 283375560522SEli Cohen memset(ndev->event_cbs, 0, sizeof(*ndev->event_cbs) * (mvdev->max_vqs + 1)); 28340686082dSXie Yongji ndev->mvdev.actual_features = 0; 28358fcd20c3SEli Cohen init_group_to_asid_map(mvdev); 28360686082dSXie Yongji ++mvdev->generation; 28378fcd20c3SEli Cohen 28380686082dSXie Yongji if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) { 283938fc462fSEli Cohen if (mlx5_vdpa_create_mr(mvdev, NULL, 0)) 28400686082dSXie Yongji mlx5_vdpa_warn(mvdev, "create MR failed\n"); 28410686082dSXie Yongji } 2842759ae7f9SEli Cohen up_write(&ndev->reslock); 28430686082dSXie Yongji 28440686082dSXie Yongji return 0; 28450686082dSXie Yongji } 28460686082dSXie Yongji 2847442706f9SStefano Garzarella static size_t mlx5_vdpa_get_config_size(struct vdpa_device *vdev) 2848442706f9SStefano Garzarella { 2849442706f9SStefano Garzarella return sizeof(struct virtio_net_config); 2850442706f9SStefano Garzarella } 2851442706f9SStefano Garzarella 28521a86b377SEli Cohen static void mlx5_vdpa_get_config(struct vdpa_device *vdev, unsigned int offset, void *buf, 28531a86b377SEli Cohen unsigned int len) 28541a86b377SEli Cohen { 28551a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 28561a86b377SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 28571a86b377SEli Cohen 2858dcfde163SStefano Garzarella if (offset + len <= sizeof(struct virtio_net_config)) 28592874211fSDan Carpenter memcpy(buf, (u8 *)&ndev->config + offset, len); 28601a86b377SEli Cohen } 28611a86b377SEli Cohen 28621a86b377SEli Cohen static void mlx5_vdpa_set_config(struct vdpa_device *vdev, unsigned int offset, const void *buf, 28631a86b377SEli Cohen unsigned int len) 28641a86b377SEli Cohen { 28651a86b377SEli Cohen /* not supported */ 28661a86b377SEli Cohen } 28671a86b377SEli Cohen 28681a86b377SEli Cohen static u32 mlx5_vdpa_get_generation(struct vdpa_device *vdev) 28691a86b377SEli Cohen { 28701a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 28711a86b377SEli Cohen 28721a86b377SEli Cohen return mvdev->generation; 28731a86b377SEli Cohen } 28741a86b377SEli Cohen 287538fc462fSEli Cohen static int set_map_data(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb, 287638fc462fSEli Cohen unsigned int asid) 28778fcd20c3SEli Cohen { 28781a86b377SEli Cohen bool change_map; 28791a86b377SEli Cohen int err; 28801a86b377SEli Cohen 288138fc462fSEli Cohen err = mlx5_vdpa_handle_set_map(mvdev, iotlb, &change_map, asid); 28821a86b377SEli Cohen if (err) { 28831a86b377SEli Cohen mlx5_vdpa_warn(mvdev, "set map failed(%d)\n", err); 28848fcd20c3SEli Cohen return err; 28851a86b377SEli Cohen } 28861a86b377SEli Cohen 28871a86b377SEli Cohen if (change_map) 288838fc462fSEli Cohen err = mlx5_vdpa_change_map(mvdev, iotlb, asid); 28891a86b377SEli Cohen 28908fcd20c3SEli Cohen return err; 28918fcd20c3SEli Cohen } 28928fcd20c3SEli Cohen 28938fcd20c3SEli Cohen static int mlx5_vdpa_set_map(struct vdpa_device *vdev, unsigned int asid, 28948fcd20c3SEli Cohen struct vhost_iotlb *iotlb) 28958fcd20c3SEli Cohen { 28968fcd20c3SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 28978fcd20c3SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 289893e530d2SEli Cohen int err = -EINVAL; 28998fcd20c3SEli Cohen 29008fcd20c3SEli Cohen down_write(&ndev->reslock); 290138fc462fSEli Cohen err = set_map_data(mvdev, iotlb, asid); 2902759ae7f9SEli Cohen up_write(&ndev->reslock); 29031c80cf03SJason Wang return err; 29041a86b377SEli Cohen } 29051a86b377SEli Cohen 290636871fb9SJason Wang static struct device *mlx5_get_vq_dma_dev(struct vdpa_device *vdev, u16 idx) 290736871fb9SJason Wang { 290836871fb9SJason Wang struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 290936871fb9SJason Wang 291036871fb9SJason Wang if (is_ctrl_vq_idx(mvdev, idx)) 291136871fb9SJason Wang return &vdev->dev; 291236871fb9SJason Wang 291336871fb9SJason Wang return mvdev->vdev.dma_dev; 291436871fb9SJason Wang } 291536871fb9SJason Wang 2916bc9a2b3eSEli Cohen static void free_irqs(struct mlx5_vdpa_net *ndev) 2917bc9a2b3eSEli Cohen { 2918bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool_entry *ent; 2919bc9a2b3eSEli Cohen int i; 2920bc9a2b3eSEli Cohen 2921bc9a2b3eSEli Cohen if (!msix_mode_supported(&ndev->mvdev)) 2922bc9a2b3eSEli Cohen return; 2923bc9a2b3eSEli Cohen 2924bc9a2b3eSEli Cohen if (!ndev->irqp.entries) 2925bc9a2b3eSEli Cohen return; 2926bc9a2b3eSEli Cohen 2927bc9a2b3eSEli Cohen for (i = ndev->irqp.num_ent - 1; i >= 0; i--) { 2928bc9a2b3eSEli Cohen ent = ndev->irqp.entries + i; 2929bc9a2b3eSEli Cohen if (ent->map.virq) 2930bc9a2b3eSEli Cohen pci_msix_free_irq(ndev->mvdev.mdev->pdev, ent->map); 2931bc9a2b3eSEli Cohen } 2932bc9a2b3eSEli Cohen kfree(ndev->irqp.entries); 2933bc9a2b3eSEli Cohen } 2934bc9a2b3eSEli Cohen 29351a86b377SEli Cohen static void mlx5_vdpa_free(struct vdpa_device *vdev) 29361a86b377SEli Cohen { 29371a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 29387c9f131fSEli Cohen struct mlx5_core_dev *pfmdev; 29391a86b377SEli Cohen struct mlx5_vdpa_net *ndev; 29401a86b377SEli Cohen 29411a86b377SEli Cohen ndev = to_mlx5_vdpa_ndev(mvdev); 29421a86b377SEli Cohen 29431a86b377SEli Cohen free_resources(ndev); 29446f5312f8SEli Cohen mlx5_vdpa_destroy_mr(mvdev); 29457c9f131fSEli Cohen if (!is_zero_ether_addr(ndev->config.mac)) { 29467c9f131fSEli Cohen pfmdev = pci_get_drvdata(pci_physfn(mvdev->mdev->pdev)); 29477c9f131fSEli Cohen mlx5_mpfs_del_mac(pfmdev, ndev->config.mac); 29487c9f131fSEli Cohen } 29491a86b377SEli Cohen mlx5_vdpa_free_resources(&ndev->mvdev); 2950bc9a2b3eSEli Cohen free_irqs(ndev); 295175560522SEli Cohen kfree(ndev->event_cbs); 295275560522SEli Cohen kfree(ndev->vqs); 29531a86b377SEli Cohen } 29541a86b377SEli Cohen 29551a86b377SEli Cohen static struct vdpa_notification_area mlx5_get_vq_notification(struct vdpa_device *vdev, u16 idx) 29561a86b377SEli Cohen { 2957b57c46cbSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 29581a86b377SEli Cohen struct vdpa_notification_area ret = {}; 2959b57c46cbSEli Cohen struct mlx5_vdpa_net *ndev; 2960b57c46cbSEli Cohen phys_addr_t addr; 29611a86b377SEli Cohen 29625262912eSEli Cohen if (!is_index_valid(mvdev, idx) || is_ctrl_vq_idx(mvdev, idx)) 2963e4fc6650SEli Cohen return ret; 2964e4fc6650SEli Cohen 2965b57c46cbSEli Cohen /* If SF BAR size is smaller than PAGE_SIZE, do not use direct 2966b57c46cbSEli Cohen * notification to avoid the risk of mapping pages that contain BAR of more 2967b57c46cbSEli Cohen * than one SF 2968b57c46cbSEli Cohen */ 2969b57c46cbSEli Cohen if (MLX5_CAP_GEN(mvdev->mdev, log_min_sf_size) + 12 < PAGE_SHIFT) 2970b57c46cbSEli Cohen return ret; 2971b57c46cbSEli Cohen 2972b57c46cbSEli Cohen ndev = to_mlx5_vdpa_ndev(mvdev); 2973b57c46cbSEli Cohen addr = (phys_addr_t)ndev->mvdev.res.phys_kick_addr; 2974b57c46cbSEli Cohen ret.addr = addr; 2975b57c46cbSEli Cohen ret.size = PAGE_SIZE; 29761a86b377SEli Cohen return ret; 29771a86b377SEli Cohen } 29781a86b377SEli Cohen 2979bc9a2b3eSEli Cohen static int mlx5_get_vq_irq(struct vdpa_device *vdev, u16 idx) 29801a86b377SEli Cohen { 2981bc9a2b3eSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 2982bc9a2b3eSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 2983bc9a2b3eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 2984bc9a2b3eSEli Cohen 2985bc9a2b3eSEli Cohen if (!is_index_valid(mvdev, idx)) 2986bc9a2b3eSEli Cohen return -EINVAL; 2987bc9a2b3eSEli Cohen 2988bc9a2b3eSEli Cohen if (is_ctrl_vq_idx(mvdev, idx)) 29891a86b377SEli Cohen return -EOPNOTSUPP; 2990bc9a2b3eSEli Cohen 2991bc9a2b3eSEli Cohen mvq = &ndev->vqs[idx]; 2992bc9a2b3eSEli Cohen if (!mvq->map.virq) 2993bc9a2b3eSEli Cohen return -EOPNOTSUPP; 2994bc9a2b3eSEli Cohen 2995bc9a2b3eSEli Cohen return mvq->map.virq; 29961a86b377SEli Cohen } 29971a86b377SEli Cohen 2998a64917bcSEli Cohen static u64 mlx5_vdpa_get_driver_features(struct vdpa_device *vdev) 2999a64917bcSEli Cohen { 3000a64917bcSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 3001a64917bcSEli Cohen 3002a64917bcSEli Cohen return mvdev->actual_features; 3003a64917bcSEli Cohen } 3004a64917bcSEli Cohen 30051892a3d4SEli Cohen static int counter_set_query(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, 30061892a3d4SEli Cohen u64 *received_desc, u64 *completed_desc) 30071892a3d4SEli Cohen { 30081892a3d4SEli Cohen u32 in[MLX5_ST_SZ_DW(query_virtio_q_counters_in)] = {}; 30091892a3d4SEli Cohen u32 out[MLX5_ST_SZ_DW(query_virtio_q_counters_out)] = {}; 30101892a3d4SEli Cohen void *cmd_hdr; 30111892a3d4SEli Cohen void *ctx; 30121892a3d4SEli Cohen int err; 30131892a3d4SEli Cohen 30141892a3d4SEli Cohen if (!counters_supported(&ndev->mvdev)) 30151892a3d4SEli Cohen return -EOPNOTSUPP; 30161892a3d4SEli Cohen 30171892a3d4SEli Cohen if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY) 30181892a3d4SEli Cohen return -EAGAIN; 30191892a3d4SEli Cohen 30201892a3d4SEli Cohen cmd_hdr = MLX5_ADDR_OF(query_virtio_q_counters_in, in, hdr); 30211892a3d4SEli Cohen 30221892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_QUERY_GENERAL_OBJECT); 30231892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_type, MLX5_OBJ_TYPE_VIRTIO_Q_COUNTERS); 30241892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); 30251892a3d4SEli Cohen MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, obj_id, mvq->counter_set_id); 30261892a3d4SEli Cohen 30271892a3d4SEli Cohen err = mlx5_cmd_exec(ndev->mvdev.mdev, in, sizeof(in), out, sizeof(out)); 30281892a3d4SEli Cohen if (err) 30291892a3d4SEli Cohen return err; 30301892a3d4SEli Cohen 30311892a3d4SEli Cohen ctx = MLX5_ADDR_OF(query_virtio_q_counters_out, out, counters); 30321892a3d4SEli Cohen *received_desc = MLX5_GET64(virtio_q_counters, ctx, received_desc); 30331892a3d4SEli Cohen *completed_desc = MLX5_GET64(virtio_q_counters, ctx, completed_desc); 30341892a3d4SEli Cohen return 0; 30351892a3d4SEli Cohen } 30361892a3d4SEli Cohen 30371892a3d4SEli Cohen static int mlx5_vdpa_get_vendor_vq_stats(struct vdpa_device *vdev, u16 idx, 30381892a3d4SEli Cohen struct sk_buff *msg, 30391892a3d4SEli Cohen struct netlink_ext_ack *extack) 30401892a3d4SEli Cohen { 30411892a3d4SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 30421892a3d4SEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 30431892a3d4SEli Cohen struct mlx5_vdpa_virtqueue *mvq; 30441892a3d4SEli Cohen struct mlx5_control_vq *cvq; 30451892a3d4SEli Cohen u64 received_desc; 30461892a3d4SEli Cohen u64 completed_desc; 30471892a3d4SEli Cohen int err = 0; 30481892a3d4SEli Cohen 3049759ae7f9SEli Cohen down_read(&ndev->reslock); 30501892a3d4SEli Cohen if (!is_index_valid(mvdev, idx)) { 30511892a3d4SEli Cohen NL_SET_ERR_MSG_MOD(extack, "virtqueue index is not valid"); 30521892a3d4SEli Cohen err = -EINVAL; 30531892a3d4SEli Cohen goto out_err; 30541892a3d4SEli Cohen } 30551892a3d4SEli Cohen 30561892a3d4SEli Cohen if (idx == ctrl_vq_idx(mvdev)) { 30571892a3d4SEli Cohen cvq = &mvdev->cvq; 30581892a3d4SEli Cohen received_desc = cvq->received_desc; 30591892a3d4SEli Cohen completed_desc = cvq->completed_desc; 30601892a3d4SEli Cohen goto out; 30611892a3d4SEli Cohen } 30621892a3d4SEli Cohen 30631892a3d4SEli Cohen mvq = &ndev->vqs[idx]; 30641892a3d4SEli Cohen err = counter_set_query(ndev, mvq, &received_desc, &completed_desc); 30651892a3d4SEli Cohen if (err) { 30661892a3d4SEli Cohen NL_SET_ERR_MSG_MOD(extack, "failed to query hardware"); 30671892a3d4SEli Cohen goto out_err; 30681892a3d4SEli Cohen } 30691892a3d4SEli Cohen 30701892a3d4SEli Cohen out: 30711892a3d4SEli Cohen err = -EMSGSIZE; 30721892a3d4SEli Cohen if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME, "received_desc")) 30731892a3d4SEli Cohen goto out_err; 30741892a3d4SEli Cohen 30751892a3d4SEli Cohen if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE, received_desc, 30761892a3d4SEli Cohen VDPA_ATTR_PAD)) 30771892a3d4SEli Cohen goto out_err; 30781892a3d4SEli Cohen 30791892a3d4SEli Cohen if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME, "completed_desc")) 30801892a3d4SEli Cohen goto out_err; 30811892a3d4SEli Cohen 30821892a3d4SEli Cohen if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE, completed_desc, 30831892a3d4SEli Cohen VDPA_ATTR_PAD)) 30841892a3d4SEli Cohen goto out_err; 30851892a3d4SEli Cohen 30861892a3d4SEli Cohen err = 0; 30871892a3d4SEli Cohen out_err: 3088759ae7f9SEli Cohen up_read(&ndev->reslock); 30891892a3d4SEli Cohen return err; 30901892a3d4SEli Cohen } 30911892a3d4SEli Cohen 3092cae15c2eSEli Cohen static void mlx5_vdpa_cvq_suspend(struct mlx5_vdpa_dev *mvdev) 3093cae15c2eSEli Cohen { 3094cae15c2eSEli Cohen struct mlx5_control_vq *cvq; 3095cae15c2eSEli Cohen 3096cae15c2eSEli Cohen if (!(mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) 3097cae15c2eSEli Cohen return; 3098cae15c2eSEli Cohen 3099cae15c2eSEli Cohen cvq = &mvdev->cvq; 3100cae15c2eSEli Cohen cvq->ready = false; 3101cae15c2eSEli Cohen } 3102cae15c2eSEli Cohen 3103cae15c2eSEli Cohen static int mlx5_vdpa_suspend(struct vdpa_device *vdev) 3104cae15c2eSEli Cohen { 3105cae15c2eSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 3106cae15c2eSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 3107cae15c2eSEli Cohen struct mlx5_vdpa_virtqueue *mvq; 3108cae15c2eSEli Cohen int i; 3109cae15c2eSEli Cohen 311009e65ee9SSi-Wei Liu mlx5_vdpa_info(mvdev, "suspending device\n"); 311109e65ee9SSi-Wei Liu 3112cae15c2eSEli Cohen down_write(&ndev->reslock); 3113c384c240SEli Cohen unregister_link_notifier(ndev); 3114cae15c2eSEli Cohen for (i = 0; i < ndev->cur_num_vqs; i++) { 3115cae15c2eSEli Cohen mvq = &ndev->vqs[i]; 3116cae15c2eSEli Cohen suspend_vq(ndev, mvq); 3117cae15c2eSEli Cohen } 3118cae15c2eSEli Cohen mlx5_vdpa_cvq_suspend(mvdev); 311909e65ee9SSi-Wei Liu mvdev->suspended = true; 3120cae15c2eSEli Cohen up_write(&ndev->reslock); 3121cae15c2eSEli Cohen return 0; 3122cae15c2eSEli Cohen } 3123cae15c2eSEli Cohen 31248fcd20c3SEli Cohen static int mlx5_set_group_asid(struct vdpa_device *vdev, u32 group, 31258fcd20c3SEli Cohen unsigned int asid) 31268fcd20c3SEli Cohen { 31278fcd20c3SEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); 31288fcd20c3SEli Cohen 31298fcd20c3SEli Cohen if (group >= MLX5_VDPA_NUMVQ_GROUPS) 31308fcd20c3SEli Cohen return -EINVAL; 31318fcd20c3SEli Cohen 31328fcd20c3SEli Cohen mvdev->group2asid[group] = asid; 31338fcd20c3SEli Cohen return 0; 31348fcd20c3SEli Cohen } 31358fcd20c3SEli Cohen 31361a86b377SEli Cohen static const struct vdpa_config_ops mlx5_vdpa_ops = { 31371a86b377SEli Cohen .set_vq_address = mlx5_vdpa_set_vq_address, 31381a86b377SEli Cohen .set_vq_num = mlx5_vdpa_set_vq_num, 31391a86b377SEli Cohen .kick_vq = mlx5_vdpa_kick_vq, 31401a86b377SEli Cohen .set_vq_cb = mlx5_vdpa_set_vq_cb, 31411a86b377SEli Cohen .set_vq_ready = mlx5_vdpa_set_vq_ready, 31421a86b377SEli Cohen .get_vq_ready = mlx5_vdpa_get_vq_ready, 31431a86b377SEli Cohen .set_vq_state = mlx5_vdpa_set_vq_state, 31441a86b377SEli Cohen .get_vq_state = mlx5_vdpa_get_vq_state, 31451892a3d4SEli Cohen .get_vendor_vq_stats = mlx5_vdpa_get_vendor_vq_stats, 31461a86b377SEli Cohen .get_vq_notification = mlx5_get_vq_notification, 31471a86b377SEli Cohen .get_vq_irq = mlx5_get_vq_irq, 31481a86b377SEli Cohen .get_vq_align = mlx5_vdpa_get_vq_align, 3149d4821902SGautam Dawar .get_vq_group = mlx5_vdpa_get_vq_group, 3150a64917bcSEli Cohen .get_device_features = mlx5_vdpa_get_device_features, 3151a64917bcSEli Cohen .set_driver_features = mlx5_vdpa_set_driver_features, 3152a64917bcSEli Cohen .get_driver_features = mlx5_vdpa_get_driver_features, 31531a86b377SEli Cohen .set_config_cb = mlx5_vdpa_set_config_cb, 31541a86b377SEli Cohen .get_vq_num_max = mlx5_vdpa_get_vq_num_max, 31551a86b377SEli Cohen .get_device_id = mlx5_vdpa_get_device_id, 31561a86b377SEli Cohen .get_vendor_id = mlx5_vdpa_get_vendor_id, 31571a86b377SEli Cohen .get_status = mlx5_vdpa_get_status, 31581a86b377SEli Cohen .set_status = mlx5_vdpa_set_status, 31590686082dSXie Yongji .reset = mlx5_vdpa_reset, 3160442706f9SStefano Garzarella .get_config_size = mlx5_vdpa_get_config_size, 31611a86b377SEli Cohen .get_config = mlx5_vdpa_get_config, 31621a86b377SEli Cohen .set_config = mlx5_vdpa_set_config, 31631a86b377SEli Cohen .get_generation = mlx5_vdpa_get_generation, 31641a86b377SEli Cohen .set_map = mlx5_vdpa_set_map, 31658fcd20c3SEli Cohen .set_group_asid = mlx5_set_group_asid, 316636871fb9SJason Wang .get_vq_dma_dev = mlx5_get_vq_dma_dev, 31671a86b377SEli Cohen .free = mlx5_vdpa_free, 3168cae15c2eSEli Cohen .suspend = mlx5_vdpa_suspend, 31691a86b377SEli Cohen }; 31701a86b377SEli Cohen 3171d084d996SSi-Wei Liu static int query_mtu(struct mlx5_core_dev *mdev, u16 *mtu) 3172d084d996SSi-Wei Liu { 3173d084d996SSi-Wei Liu u16 hw_mtu; 3174d084d996SSi-Wei Liu int err; 3175d084d996SSi-Wei Liu 3176d084d996SSi-Wei Liu err = mlx5_query_nic_vport_mtu(mdev, &hw_mtu); 3177d084d996SSi-Wei Liu if (err) 3178d084d996SSi-Wei Liu return err; 3179d084d996SSi-Wei Liu 3180d084d996SSi-Wei Liu *mtu = hw_mtu - MLX5V_ETH_HARD_MTU; 3181d084d996SSi-Wei Liu return 0; 3182d084d996SSi-Wei Liu } 3183d084d996SSi-Wei Liu 31841a86b377SEli Cohen static int alloc_resources(struct mlx5_vdpa_net *ndev) 31851a86b377SEli Cohen { 31861a86b377SEli Cohen struct mlx5_vdpa_net_resources *res = &ndev->res; 31871a86b377SEli Cohen int err; 31881a86b377SEli Cohen 31891a86b377SEli Cohen if (res->valid) { 31901a86b377SEli Cohen mlx5_vdpa_warn(&ndev->mvdev, "resources already allocated\n"); 31911a86b377SEli Cohen return -EEXIST; 31921a86b377SEli Cohen } 31931a86b377SEli Cohen 31941a86b377SEli Cohen err = mlx5_vdpa_alloc_transport_domain(&ndev->mvdev, &res->tdn); 31951a86b377SEli Cohen if (err) 31961a86b377SEli Cohen return err; 31971a86b377SEli Cohen 31981a86b377SEli Cohen err = create_tis(ndev); 31991a86b377SEli Cohen if (err) 32001a86b377SEli Cohen goto err_tis; 32011a86b377SEli Cohen 32021a86b377SEli Cohen res->valid = true; 32031a86b377SEli Cohen 32041a86b377SEli Cohen return 0; 32051a86b377SEli Cohen 32061a86b377SEli Cohen err_tis: 32071a86b377SEli Cohen mlx5_vdpa_dealloc_transport_domain(&ndev->mvdev, res->tdn); 32081a86b377SEli Cohen return err; 32091a86b377SEli Cohen } 32101a86b377SEli Cohen 32111a86b377SEli Cohen static void free_resources(struct mlx5_vdpa_net *ndev) 32121a86b377SEli Cohen { 32131a86b377SEli Cohen struct mlx5_vdpa_net_resources *res = &ndev->res; 32141a86b377SEli Cohen 32151a86b377SEli Cohen if (!res->valid) 32161a86b377SEli Cohen return; 32171a86b377SEli Cohen 32181a86b377SEli Cohen destroy_tis(ndev); 32191a86b377SEli Cohen mlx5_vdpa_dealloc_transport_domain(&ndev->mvdev, res->tdn); 32201a86b377SEli Cohen res->valid = false; 32211a86b377SEli Cohen } 32221a86b377SEli Cohen 32231a86b377SEli Cohen static void init_mvqs(struct mlx5_vdpa_net *ndev) 32241a86b377SEli Cohen { 32251a86b377SEli Cohen struct mlx5_vdpa_virtqueue *mvq; 32261a86b377SEli Cohen int i; 32271a86b377SEli Cohen 3228acde3929SEli Cohen for (i = 0; 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 mvq->fwqp.fw = true; 3234cae15c2eSEli Cohen mvq->fw_state = MLX5_VIRTIO_NET_Q_OBJECT_NONE; 32351a86b377SEli Cohen } 32361a86b377SEli Cohen for (; i < ndev->mvdev.max_vqs; i++) { 32371a86b377SEli Cohen mvq = &ndev->vqs[i]; 32381a86b377SEli Cohen memset(mvq, 0, offsetof(struct mlx5_vdpa_virtqueue, ri)); 32391a86b377SEli Cohen mvq->index = i; 32401a86b377SEli Cohen mvq->ndev = ndev; 32411a86b377SEli Cohen } 32421a86b377SEli Cohen } 32431a86b377SEli Cohen 324458926c8aSEli Cohen struct mlx5_vdpa_mgmtdev { 324558926c8aSEli Cohen struct vdpa_mgmt_dev mgtdev; 324658926c8aSEli Cohen struct mlx5_adev *madev; 324758926c8aSEli Cohen struct mlx5_vdpa_net *ndev; 324858926c8aSEli Cohen }; 324958926c8aSEli Cohen 32501e00e821SEli Cohen static int config_func_mtu(struct mlx5_core_dev *mdev, u16 mtu) 32511e00e821SEli Cohen { 32521e00e821SEli Cohen int inlen = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in); 32531e00e821SEli Cohen void *in; 32541e00e821SEli Cohen int err; 32551e00e821SEli Cohen 32561e00e821SEli Cohen in = kvzalloc(inlen, GFP_KERNEL); 32571e00e821SEli Cohen if (!in) 32581e00e821SEli Cohen return -ENOMEM; 32591e00e821SEli Cohen 32601e00e821SEli Cohen MLX5_SET(modify_nic_vport_context_in, in, field_select.mtu, 1); 32611e00e821SEli Cohen MLX5_SET(modify_nic_vport_context_in, in, nic_vport_context.mtu, 32621e00e821SEli Cohen mtu + MLX5V_ETH_HARD_MTU); 32631e00e821SEli Cohen MLX5_SET(modify_nic_vport_context_in, in, opcode, 32641e00e821SEli Cohen MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT); 32651e00e821SEli Cohen 32661e00e821SEli Cohen err = mlx5_cmd_exec_in(mdev, modify_nic_vport_context, in); 32671e00e821SEli Cohen 32681e00e821SEli Cohen kvfree(in); 32691e00e821SEli Cohen return err; 32701e00e821SEli Cohen } 32711e00e821SEli Cohen 3272bc9a2b3eSEli Cohen static void allocate_irqs(struct mlx5_vdpa_net *ndev) 3273bc9a2b3eSEli Cohen { 3274bc9a2b3eSEli Cohen struct mlx5_vdpa_irq_pool_entry *ent; 3275bc9a2b3eSEli Cohen int i; 3276bc9a2b3eSEli Cohen 3277bc9a2b3eSEli Cohen if (!msix_mode_supported(&ndev->mvdev)) 3278bc9a2b3eSEli Cohen return; 3279bc9a2b3eSEli Cohen 3280bc9a2b3eSEli Cohen if (!ndev->mvdev.mdev->pdev) 3281bc9a2b3eSEli Cohen return; 3282bc9a2b3eSEli Cohen 3283bc9a2b3eSEli Cohen ndev->irqp.entries = kcalloc(ndev->mvdev.max_vqs, sizeof(*ndev->irqp.entries), GFP_KERNEL); 3284bc9a2b3eSEli Cohen if (!ndev->irqp.entries) 3285bc9a2b3eSEli Cohen return; 3286bc9a2b3eSEli Cohen 3287bc9a2b3eSEli Cohen 3288bc9a2b3eSEli Cohen for (i = 0; i < ndev->mvdev.max_vqs; i++) { 3289bc9a2b3eSEli Cohen ent = ndev->irqp.entries + i; 3290bc9a2b3eSEli Cohen snprintf(ent->name, MLX5_VDPA_IRQ_NAME_LEN, "%s-vq-%d", 3291bc9a2b3eSEli Cohen dev_name(&ndev->mvdev.vdev.dev), i); 3292bc9a2b3eSEli Cohen ent->map = pci_msix_alloc_irq_at(ndev->mvdev.mdev->pdev, MSI_ANY_INDEX, NULL); 3293bc9a2b3eSEli Cohen if (!ent->map.virq) 3294bc9a2b3eSEli Cohen return; 3295bc9a2b3eSEli Cohen 3296bc9a2b3eSEli Cohen ndev->irqp.num_ent++; 3297bc9a2b3eSEli Cohen } 3298bc9a2b3eSEli Cohen } 3299bc9a2b3eSEli Cohen 3300d8ca2fa5SParav Pandit static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, 3301d8ca2fa5SParav Pandit const struct vdpa_dev_set_config *add_config) 33021a86b377SEli Cohen { 330358926c8aSEli Cohen struct mlx5_vdpa_mgmtdev *mgtdev = container_of(v_mdev, struct mlx5_vdpa_mgmtdev, mgtdev); 33041a86b377SEli Cohen struct virtio_net_config *config; 33057c9f131fSEli Cohen struct mlx5_core_dev *pfmdev; 33061a86b377SEli Cohen struct mlx5_vdpa_dev *mvdev; 33071a86b377SEli Cohen struct mlx5_vdpa_net *ndev; 330858926c8aSEli Cohen struct mlx5_core_dev *mdev; 3309deeacf35SSi-Wei Liu u64 device_features; 33101a86b377SEli Cohen u32 max_vqs; 3311246fd1caSEli Cohen u16 mtu; 33121a86b377SEli Cohen int err; 33131a86b377SEli Cohen 331458926c8aSEli Cohen if (mgtdev->ndev) 331558926c8aSEli Cohen return -ENOSPC; 331658926c8aSEli Cohen 331758926c8aSEli Cohen mdev = mgtdev->madev->mdev; 3318deeacf35SSi-Wei Liu device_features = mgtdev->mgtdev.supported_features; 3319deeacf35SSi-Wei Liu if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) { 3320deeacf35SSi-Wei Liu if (add_config->device_features & ~device_features) { 3321deeacf35SSi-Wei Liu dev_warn(mdev->device, 3322deeacf35SSi-Wei Liu "The provisioned features 0x%llx are not supported by this device with features 0x%llx\n", 3323deeacf35SSi-Wei Liu add_config->device_features, device_features); 3324deeacf35SSi-Wei Liu return -EINVAL; 3325deeacf35SSi-Wei Liu } 3326deeacf35SSi-Wei Liu device_features &= add_config->device_features; 3327791a1cb7SEli Cohen } else { 3328791a1cb7SEli Cohen device_features &= ~BIT_ULL(VIRTIO_NET_F_MRG_RXBUF); 3329deeacf35SSi-Wei Liu } 3330deeacf35SSi-Wei Liu if (!(device_features & BIT_ULL(VIRTIO_F_VERSION_1) && 3331deeacf35SSi-Wei Liu device_features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM))) { 3332deeacf35SSi-Wei Liu dev_warn(mdev->device, 3333deeacf35SSi-Wei Liu "Must provision minimum features 0x%llx for this device", 3334deeacf35SSi-Wei Liu BIT_ULL(VIRTIO_F_VERSION_1) | BIT_ULL(VIRTIO_F_ACCESS_PLATFORM)); 3335deeacf35SSi-Wei Liu return -EOPNOTSUPP; 3336deeacf35SSi-Wei Liu } 3337deeacf35SSi-Wei Liu 3338879753c8SEli Cohen if (!(MLX5_CAP_DEV_VDPA_EMULATION(mdev, virtio_queue_type) & 3339879753c8SEli Cohen MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_SPLIT)) { 3340879753c8SEli Cohen dev_warn(mdev->device, "missing support for split virtqueues\n"); 3341879753c8SEli Cohen return -EOPNOTSUPP; 3342879753c8SEli Cohen } 3343879753c8SEli Cohen 3344acde3929SEli Cohen max_vqs = min_t(int, MLX5_CAP_DEV_VDPA_EMULATION(mdev, max_num_virtio_queues), 3345acde3929SEli Cohen 1 << MLX5_CAP_GEN(mdev, log_max_rqt_size)); 334675560522SEli Cohen if (max_vqs < 2) { 334775560522SEli Cohen dev_warn(mdev->device, 334875560522SEli Cohen "%d virtqueues are supported. At least 2 are required\n", 334975560522SEli Cohen max_vqs); 335075560522SEli Cohen return -EAGAIN; 335175560522SEli Cohen } 335275560522SEli Cohen 335375560522SEli Cohen if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP)) { 335475560522SEli Cohen if (add_config->net.max_vq_pairs > max_vqs / 2) 335575560522SEli Cohen return -EINVAL; 335675560522SEli Cohen max_vqs = min_t(u32, max_vqs, 2 * add_config->net.max_vq_pairs); 335775560522SEli Cohen } else { 335875560522SEli Cohen max_vqs = 2; 335975560522SEli Cohen } 33601a86b377SEli Cohen 33611a86b377SEli Cohen ndev = vdpa_alloc_device(struct mlx5_vdpa_net, mvdev.vdev, mdev->device, &mlx5_vdpa_ops, 33628fcd20c3SEli Cohen MLX5_VDPA_NUMVQ_GROUPS, MLX5_VDPA_NUM_AS, name, false); 33631a86b377SEli Cohen if (IS_ERR(ndev)) 336474c9729dSLeon Romanovsky return PTR_ERR(ndev); 33651a86b377SEli Cohen 33661a86b377SEli Cohen ndev->mvdev.max_vqs = max_vqs; 33671a86b377SEli Cohen mvdev = &ndev->mvdev; 33681a86b377SEli Cohen mvdev->mdev = mdev; 336975560522SEli Cohen 337075560522SEli Cohen ndev->vqs = kcalloc(max_vqs, sizeof(*ndev->vqs), GFP_KERNEL); 337175560522SEli Cohen ndev->event_cbs = kcalloc(max_vqs + 1, sizeof(*ndev->event_cbs), GFP_KERNEL); 337275560522SEli Cohen if (!ndev->vqs || !ndev->event_cbs) { 337375560522SEli Cohen err = -ENOMEM; 337475560522SEli Cohen goto err_alloc; 337575560522SEli Cohen } 337675560522SEli Cohen 33771a86b377SEli Cohen init_mvqs(ndev); 3378bc9a2b3eSEli Cohen allocate_irqs(ndev); 3379759ae7f9SEli Cohen init_rwsem(&ndev->reslock); 33801a86b377SEli Cohen config = &ndev->config; 33811e00e821SEli Cohen 33821e00e821SEli Cohen if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MTU)) { 33831e00e821SEli Cohen err = config_func_mtu(mdev, add_config->net.mtu); 33841e00e821SEli Cohen if (err) 3385759ae7f9SEli Cohen goto err_alloc; 33861e00e821SEli Cohen } 33871e00e821SEli Cohen 3388deeacf35SSi-Wei Liu if (device_features & BIT_ULL(VIRTIO_NET_F_MTU)) { 3389246fd1caSEli Cohen err = query_mtu(mdev, &mtu); 33901a86b377SEli Cohen if (err) 3391759ae7f9SEli Cohen goto err_alloc; 33921a86b377SEli Cohen 3393246fd1caSEli Cohen ndev->config.mtu = cpu_to_mlx5vdpa16(mvdev, mtu); 3394033779a7SSi-Wei Liu } 33951a86b377SEli Cohen 3396deeacf35SSi-Wei Liu if (device_features & BIT_ULL(VIRTIO_NET_F_STATUS)) { 3397edf747afSEli Cohen if (get_link_state(mvdev)) 3398edf747afSEli Cohen ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP); 3399edf747afSEli Cohen else 3400edf747afSEli Cohen ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP); 3401033779a7SSi-Wei Liu } 3402edf747afSEli Cohen 3403a007d940SEli Cohen if (add_config->mask & (1 << VDPA_ATTR_DEV_NET_CFG_MACADDR)) { 3404a007d940SEli Cohen memcpy(ndev->config.mac, add_config->net.mac, ETH_ALEN); 3405deeacf35SSi-Wei Liu /* No bother setting mac address in config if not going to provision _F_MAC */ 3406deeacf35SSi-Wei Liu } else if ((add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) == 0 || 3407deeacf35SSi-Wei Liu device_features & BIT_ULL(VIRTIO_NET_F_MAC)) { 34081a86b377SEli Cohen err = mlx5_query_nic_vport_mac_address(mdev, 0, 0, config->mac); 34091a86b377SEli Cohen if (err) 3410759ae7f9SEli Cohen goto err_alloc; 3411a007d940SEli Cohen } 34121a86b377SEli Cohen 34137c9f131fSEli Cohen if (!is_zero_ether_addr(config->mac)) { 34147c9f131fSEli Cohen pfmdev = pci_get_drvdata(pci_physfn(mdev->pdev)); 34157c9f131fSEli Cohen err = mlx5_mpfs_add_mac(pfmdev, config->mac); 34167c9f131fSEli Cohen if (err) 3417759ae7f9SEli Cohen goto err_alloc; 3418deeacf35SSi-Wei Liu } else if ((add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) == 0) { 3419deeacf35SSi-Wei Liu /* 3420deeacf35SSi-Wei Liu * We used to clear _F_MAC feature bit if seeing 3421deeacf35SSi-Wei Liu * zero mac address when device features are not 3422deeacf35SSi-Wei Liu * specifically provisioned. Keep the behaviour 3423deeacf35SSi-Wei Liu * so old scripts do not break. 3424deeacf35SSi-Wei Liu */ 3425deeacf35SSi-Wei Liu device_features &= ~BIT_ULL(VIRTIO_NET_F_MAC); 3426deeacf35SSi-Wei Liu } else if (device_features & BIT_ULL(VIRTIO_NET_F_MAC)) { 3427deeacf35SSi-Wei Liu /* Don't provision zero mac address for _F_MAC */ 3428deeacf35SSi-Wei Liu mlx5_vdpa_warn(&ndev->mvdev, 3429deeacf35SSi-Wei Liu "No mac address provisioned?\n"); 3430deeacf35SSi-Wei Liu err = -EINVAL; 3431deeacf35SSi-Wei Liu goto err_alloc; 34327c9f131fSEli Cohen } 34337c9f131fSEli Cohen 3434deeacf35SSi-Wei Liu if (device_features & BIT_ULL(VIRTIO_NET_F_MQ)) 3435acde3929SEli Cohen config->max_virtqueue_pairs = cpu_to_mlx5vdpa16(mvdev, max_vqs / 2); 3436deeacf35SSi-Wei Liu 3437deeacf35SSi-Wei Liu ndev->mvdev.mlx_features = device_features; 34387d23dcdfSEli Cohen mvdev->vdev.dma_dev = &mdev->pdev->dev; 34391a86b377SEli Cohen err = mlx5_vdpa_alloc_resources(&ndev->mvdev); 34401a86b377SEli Cohen if (err) 34417c9f131fSEli Cohen goto err_mpfs; 34421a86b377SEli Cohen 34436f5312f8SEli Cohen if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) { 344438fc462fSEli Cohen err = mlx5_vdpa_create_mr(mvdev, NULL, 0); 34451a86b377SEli Cohen if (err) 34461a86b377SEli Cohen goto err_res; 34476f5312f8SEli Cohen } 34486f5312f8SEli Cohen 34496f5312f8SEli Cohen err = alloc_resources(ndev); 34506f5312f8SEli Cohen if (err) 34516f5312f8SEli Cohen goto err_mr; 34521a86b377SEli Cohen 345355ebf0d6SJason Wang ndev->cvq_ent.mvdev = mvdev; 345455ebf0d6SJason Wang INIT_WORK(&ndev->cvq_ent.work, mlx5_cvq_kick_handler); 3455218bdd20SEli Cohen mvdev->wq = create_singlethread_workqueue("mlx5_vdpa_wq"); 34565262912eSEli Cohen if (!mvdev->wq) { 34575262912eSEli Cohen err = -ENOMEM; 34585262912eSEli Cohen goto err_res2; 34595262912eSEli Cohen } 34605262912eSEli Cohen 346158926c8aSEli Cohen mvdev->vdev.mdev = &mgtdev->mgtdev; 3462acde3929SEli Cohen err = _vdpa_register_device(&mvdev->vdev, max_vqs + 1); 34631a86b377SEli Cohen if (err) 34641a86b377SEli Cohen goto err_reg; 34651a86b377SEli Cohen 346658926c8aSEli Cohen mgtdev->ndev = ndev; 346774c9729dSLeon Romanovsky return 0; 34681a86b377SEli Cohen 34691a86b377SEli Cohen err_reg: 34705262912eSEli Cohen destroy_workqueue(mvdev->wq); 34715262912eSEli Cohen err_res2: 34721a86b377SEli Cohen free_resources(ndev); 34736f5312f8SEli Cohen err_mr: 34746f5312f8SEli Cohen mlx5_vdpa_destroy_mr(mvdev); 34751a86b377SEli Cohen err_res: 34761a86b377SEli Cohen mlx5_vdpa_free_resources(&ndev->mvdev); 34777c9f131fSEli Cohen err_mpfs: 34787c9f131fSEli Cohen if (!is_zero_ether_addr(config->mac)) 34797c9f131fSEli Cohen mlx5_mpfs_del_mac(pfmdev, config->mac); 348075560522SEli Cohen err_alloc: 34811a86b377SEli Cohen put_device(&mvdev->vdev.dev); 348274c9729dSLeon Romanovsky return err; 34831a86b377SEli Cohen } 34841a86b377SEli Cohen 348558926c8aSEli Cohen static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device *dev) 348658926c8aSEli Cohen { 348758926c8aSEli Cohen struct mlx5_vdpa_mgmtdev *mgtdev = container_of(v_mdev, struct mlx5_vdpa_mgmtdev, mgtdev); 34885262912eSEli Cohen struct mlx5_vdpa_dev *mvdev = to_mvdev(dev); 3489edf747afSEli Cohen struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); 3490ad6dc1daSEli Cohen struct workqueue_struct *wq; 349158926c8aSEli Cohen 349229422100SEli Cohen mlx5_vdpa_remove_debugfs(ndev->debugfs); 349329422100SEli Cohen ndev->debugfs = NULL; 3494c384c240SEli Cohen unregister_link_notifier(ndev); 349573790bdfSDragos Tatulea _vdpa_unregister_device(dev); 3496ad6dc1daSEli Cohen wq = mvdev->wq; 3497ad6dc1daSEli Cohen mvdev->wq = NULL; 3498ad6dc1daSEli Cohen destroy_workqueue(wq); 349958926c8aSEli Cohen mgtdev->ndev = NULL; 350058926c8aSEli Cohen } 350158926c8aSEli Cohen 350258926c8aSEli Cohen static const struct vdpa_mgmtdev_ops mdev_ops = { 350358926c8aSEli Cohen .dev_add = mlx5_vdpa_dev_add, 350458926c8aSEli Cohen .dev_del = mlx5_vdpa_dev_del, 350558926c8aSEli Cohen }; 350658926c8aSEli Cohen 350758926c8aSEli Cohen static struct virtio_device_id id_table[] = { 350858926c8aSEli Cohen { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID }, 350958926c8aSEli Cohen { 0 }, 351058926c8aSEli Cohen }; 351158926c8aSEli Cohen 351258926c8aSEli Cohen static int mlx5v_probe(struct auxiliary_device *adev, 351358926c8aSEli Cohen const struct auxiliary_device_id *id) 351458926c8aSEli Cohen 351558926c8aSEli Cohen { 351658926c8aSEli Cohen struct mlx5_adev *madev = container_of(adev, struct mlx5_adev, adev); 351758926c8aSEli Cohen struct mlx5_core_dev *mdev = madev->mdev; 351858926c8aSEli Cohen struct mlx5_vdpa_mgmtdev *mgtdev; 351958926c8aSEli Cohen int err; 352058926c8aSEli Cohen 352158926c8aSEli Cohen mgtdev = kzalloc(sizeof(*mgtdev), GFP_KERNEL); 352258926c8aSEli Cohen if (!mgtdev) 352358926c8aSEli Cohen return -ENOMEM; 352458926c8aSEli Cohen 352558926c8aSEli Cohen mgtdev->mgtdev.ops = &mdev_ops; 352658926c8aSEli Cohen mgtdev->mgtdev.device = mdev->device; 352758926c8aSEli Cohen mgtdev->mgtdev.id_table = id_table; 352875560522SEli Cohen mgtdev->mgtdev.config_attr_mask = BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR) | 35291e00e821SEli Cohen BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP) | 3530deeacf35SSi-Wei Liu BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MTU) | 3531deeacf35SSi-Wei Liu BIT_ULL(VDPA_ATTR_DEV_FEATURES); 353279de65edSEli Cohen mgtdev->mgtdev.max_supported_vqs = 353379de65edSEli Cohen MLX5_CAP_DEV_VDPA_EMULATION(mdev, max_num_virtio_queues) + 1; 353479de65edSEli Cohen mgtdev->mgtdev.supported_features = get_supported_features(mdev); 353558926c8aSEli Cohen mgtdev->madev = madev; 353658926c8aSEli Cohen 353758926c8aSEli Cohen err = vdpa_mgmtdev_register(&mgtdev->mgtdev); 353858926c8aSEli Cohen if (err) 353958926c8aSEli Cohen goto reg_err; 354058926c8aSEli Cohen 354145e3a279SDavid E. Box auxiliary_set_drvdata(adev, mgtdev); 354258926c8aSEli Cohen 354358926c8aSEli Cohen return 0; 354458926c8aSEli Cohen 354558926c8aSEli Cohen reg_err: 354658926c8aSEli Cohen kfree(mgtdev); 354758926c8aSEli Cohen return err; 354858926c8aSEli Cohen } 354958926c8aSEli Cohen 355074c9729dSLeon Romanovsky static void mlx5v_remove(struct auxiliary_device *adev) 35511a86b377SEli Cohen { 355258926c8aSEli Cohen struct mlx5_vdpa_mgmtdev *mgtdev; 355374c9729dSLeon Romanovsky 355445e3a279SDavid E. Box mgtdev = auxiliary_get_drvdata(adev); 355558926c8aSEli Cohen vdpa_mgmtdev_unregister(&mgtdev->mgtdev); 355658926c8aSEli Cohen kfree(mgtdev); 35571a86b377SEli Cohen } 355874c9729dSLeon Romanovsky 3559bc9a2b3eSEli Cohen static void mlx5v_shutdown(struct auxiliary_device *auxdev) 3560bc9a2b3eSEli Cohen { 3561bc9a2b3eSEli Cohen struct mlx5_vdpa_mgmtdev *mgtdev; 3562bc9a2b3eSEli Cohen struct mlx5_vdpa_net *ndev; 3563bc9a2b3eSEli Cohen 3564bc9a2b3eSEli Cohen mgtdev = auxiliary_get_drvdata(auxdev); 3565bc9a2b3eSEli Cohen ndev = mgtdev->ndev; 3566bc9a2b3eSEli Cohen 3567bc9a2b3eSEli Cohen free_irqs(ndev); 3568bc9a2b3eSEli Cohen } 3569bc9a2b3eSEli Cohen 357074c9729dSLeon Romanovsky static const struct auxiliary_device_id mlx5v_id_table[] = { 357174c9729dSLeon Romanovsky { .name = MLX5_ADEV_NAME ".vnet", }, 357274c9729dSLeon Romanovsky {}, 357374c9729dSLeon Romanovsky }; 357474c9729dSLeon Romanovsky 357574c9729dSLeon Romanovsky MODULE_DEVICE_TABLE(auxiliary, mlx5v_id_table); 357674c9729dSLeon Romanovsky 357774c9729dSLeon Romanovsky static struct auxiliary_driver mlx5v_driver = { 357874c9729dSLeon Romanovsky .name = "vnet", 357974c9729dSLeon Romanovsky .probe = mlx5v_probe, 358074c9729dSLeon Romanovsky .remove = mlx5v_remove, 3581bc9a2b3eSEli Cohen .shutdown = mlx5v_shutdown, 358274c9729dSLeon Romanovsky .id_table = mlx5v_id_table, 358374c9729dSLeon Romanovsky }; 358474c9729dSLeon Romanovsky 358574c9729dSLeon Romanovsky module_auxiliary_driver(mlx5v_driver); 3586