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