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