xref: /linux/drivers/vdpa/virtio_pci/vp_vdpa.c (revision 94e48d6aafef23143f92eadd010c505c49487576)
164b9f64fSJason Wang // SPDX-License-Identifier: GPL-2.0-only
264b9f64fSJason Wang /*
364b9f64fSJason Wang  * vDPA bridge driver for modern virtio-pci device
464b9f64fSJason Wang  *
564b9f64fSJason Wang  * Copyright (c) 2020, Red Hat Inc. All rights reserved.
664b9f64fSJason Wang  * Author: Jason Wang <jasowang@redhat.com>
764b9f64fSJason Wang  *
864b9f64fSJason Wang  * Based on virtio_pci_modern.c.
964b9f64fSJason Wang  */
1064b9f64fSJason Wang 
1164b9f64fSJason Wang #include <linux/interrupt.h>
1264b9f64fSJason Wang #include <linux/module.h>
1364b9f64fSJason Wang #include <linux/pci.h>
1464b9f64fSJason Wang #include <linux/vdpa.h>
1564b9f64fSJason Wang #include <linux/virtio.h>
1664b9f64fSJason Wang #include <linux/virtio_config.h>
1764b9f64fSJason Wang #include <linux/virtio_ring.h>
1864b9f64fSJason Wang #include <linux/virtio_pci.h>
1964b9f64fSJason Wang #include <linux/virtio_pci_modern.h>
2064b9f64fSJason Wang 
2164b9f64fSJason Wang #define VP_VDPA_QUEUE_MAX 256
2264b9f64fSJason Wang #define VP_VDPA_DRIVER_NAME "vp_vdpa"
2364b9f64fSJason Wang #define VP_VDPA_NAME_SIZE 256
2464b9f64fSJason Wang 
2564b9f64fSJason Wang struct vp_vring {
2664b9f64fSJason Wang 	void __iomem *notify;
2764b9f64fSJason Wang 	char msix_name[VP_VDPA_NAME_SIZE];
2864b9f64fSJason Wang 	struct vdpa_callback cb;
29526cb858SJason Wang 	resource_size_t notify_pa;
3064b9f64fSJason Wang 	int irq;
3164b9f64fSJason Wang };
3264b9f64fSJason Wang 
3364b9f64fSJason Wang struct vp_vdpa {
3464b9f64fSJason Wang 	struct vdpa_device vdpa;
3564b9f64fSJason Wang 	struct virtio_pci_modern_device mdev;
3664b9f64fSJason Wang 	struct vp_vring *vring;
3764b9f64fSJason Wang 	struct vdpa_callback config_cb;
3864b9f64fSJason Wang 	char msix_name[VP_VDPA_NAME_SIZE];
3964b9f64fSJason Wang 	int config_irq;
4064b9f64fSJason Wang 	int queues;
4164b9f64fSJason Wang 	int vectors;
4264b9f64fSJason Wang };
4364b9f64fSJason Wang 
4464b9f64fSJason Wang static struct vp_vdpa *vdpa_to_vp(struct vdpa_device *vdpa)
4564b9f64fSJason Wang {
4664b9f64fSJason Wang 	return container_of(vdpa, struct vp_vdpa, vdpa);
4764b9f64fSJason Wang }
4864b9f64fSJason Wang 
4964b9f64fSJason Wang static struct virtio_pci_modern_device *vdpa_to_mdev(struct vdpa_device *vdpa)
5064b9f64fSJason Wang {
5164b9f64fSJason Wang 	struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa);
5264b9f64fSJason Wang 
5364b9f64fSJason Wang 	return &vp_vdpa->mdev;
5464b9f64fSJason Wang }
5564b9f64fSJason Wang 
5664b9f64fSJason Wang static u64 vp_vdpa_get_features(struct vdpa_device *vdpa)
5764b9f64fSJason Wang {
5864b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa);
5964b9f64fSJason Wang 
6064b9f64fSJason Wang 	return vp_modern_get_features(mdev);
6164b9f64fSJason Wang }
6264b9f64fSJason Wang 
6364b9f64fSJason Wang static int vp_vdpa_set_features(struct vdpa_device *vdpa, u64 features)
6464b9f64fSJason Wang {
6564b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa);
6664b9f64fSJason Wang 
6764b9f64fSJason Wang 	vp_modern_set_features(mdev, features);
6864b9f64fSJason Wang 
6964b9f64fSJason Wang 	return 0;
7064b9f64fSJason Wang }
7164b9f64fSJason Wang 
7264b9f64fSJason Wang static u8 vp_vdpa_get_status(struct vdpa_device *vdpa)
7364b9f64fSJason Wang {
7464b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa);
7564b9f64fSJason Wang 
7664b9f64fSJason Wang 	return vp_modern_get_status(mdev);
7764b9f64fSJason Wang }
7864b9f64fSJason Wang 
7964b9f64fSJason Wang static void vp_vdpa_free_irq(struct vp_vdpa *vp_vdpa)
8064b9f64fSJason Wang {
8164b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev;
8264b9f64fSJason Wang 	struct pci_dev *pdev = mdev->pci_dev;
8364b9f64fSJason Wang 	int i;
8464b9f64fSJason Wang 
8564b9f64fSJason Wang 	for (i = 0; i < vp_vdpa->queues; i++) {
8664b9f64fSJason Wang 		if (vp_vdpa->vring[i].irq != VIRTIO_MSI_NO_VECTOR) {
8764b9f64fSJason Wang 			vp_modern_queue_vector(mdev, i, VIRTIO_MSI_NO_VECTOR);
8864b9f64fSJason Wang 			devm_free_irq(&pdev->dev, vp_vdpa->vring[i].irq,
8964b9f64fSJason Wang 				      &vp_vdpa->vring[i]);
9064b9f64fSJason Wang 			vp_vdpa->vring[i].irq = VIRTIO_MSI_NO_VECTOR;
9164b9f64fSJason Wang 		}
9264b9f64fSJason Wang 	}
9364b9f64fSJason Wang 
9464b9f64fSJason Wang 	if (vp_vdpa->config_irq != VIRTIO_MSI_NO_VECTOR) {
9564b9f64fSJason Wang 		vp_modern_config_vector(mdev, VIRTIO_MSI_NO_VECTOR);
9664b9f64fSJason Wang 		devm_free_irq(&pdev->dev, vp_vdpa->config_irq, vp_vdpa);
9764b9f64fSJason Wang 		vp_vdpa->config_irq = VIRTIO_MSI_NO_VECTOR;
9864b9f64fSJason Wang 	}
9964b9f64fSJason Wang 
10064b9f64fSJason Wang 	if (vp_vdpa->vectors) {
10164b9f64fSJason Wang 		pci_free_irq_vectors(pdev);
10264b9f64fSJason Wang 		vp_vdpa->vectors = 0;
10364b9f64fSJason Wang 	}
10464b9f64fSJason Wang }
10564b9f64fSJason Wang 
10664b9f64fSJason Wang static irqreturn_t vp_vdpa_vq_handler(int irq, void *arg)
10764b9f64fSJason Wang {
10864b9f64fSJason Wang 	struct vp_vring *vring = arg;
10964b9f64fSJason Wang 
11064b9f64fSJason Wang 	if (vring->cb.callback)
11164b9f64fSJason Wang 		return vring->cb.callback(vring->cb.private);
11264b9f64fSJason Wang 
11364b9f64fSJason Wang 	return IRQ_HANDLED;
11464b9f64fSJason Wang }
11564b9f64fSJason Wang 
11664b9f64fSJason Wang static irqreturn_t vp_vdpa_config_handler(int irq, void *arg)
11764b9f64fSJason Wang {
11864b9f64fSJason Wang 	struct vp_vdpa *vp_vdpa = arg;
11964b9f64fSJason Wang 
12064b9f64fSJason Wang 	if (vp_vdpa->config_cb.callback)
12164b9f64fSJason Wang 		return vp_vdpa->config_cb.callback(vp_vdpa->config_cb.private);
12264b9f64fSJason Wang 
12364b9f64fSJason Wang 	return IRQ_HANDLED;
12464b9f64fSJason Wang }
12564b9f64fSJason Wang 
12664b9f64fSJason Wang static int vp_vdpa_request_irq(struct vp_vdpa *vp_vdpa)
12764b9f64fSJason Wang {
12864b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev;
12964b9f64fSJason Wang 	struct pci_dev *pdev = mdev->pci_dev;
13064b9f64fSJason Wang 	int i, ret, irq;
13164b9f64fSJason Wang 	int queues = vp_vdpa->queues;
13264b9f64fSJason Wang 	int vectors = queues + 1;
13364b9f64fSJason Wang 
13464b9f64fSJason Wang 	ret = pci_alloc_irq_vectors(pdev, vectors, vectors, PCI_IRQ_MSIX);
13564b9f64fSJason Wang 	if (ret != vectors) {
13664b9f64fSJason Wang 		dev_err(&pdev->dev,
13764b9f64fSJason Wang 			"vp_vdpa: fail to allocate irq vectors want %d but %d\n",
13864b9f64fSJason Wang 			vectors, ret);
13964b9f64fSJason Wang 		return ret;
14064b9f64fSJason Wang 	}
14164b9f64fSJason Wang 
14264b9f64fSJason Wang 	vp_vdpa->vectors = vectors;
14364b9f64fSJason Wang 
14464b9f64fSJason Wang 	for (i = 0; i < queues; i++) {
14564b9f64fSJason Wang 		snprintf(vp_vdpa->vring[i].msix_name, VP_VDPA_NAME_SIZE,
14664b9f64fSJason Wang 			"vp-vdpa[%s]-%d\n", pci_name(pdev), i);
14764b9f64fSJason Wang 		irq = pci_irq_vector(pdev, i);
14864b9f64fSJason Wang 		ret = devm_request_irq(&pdev->dev, irq,
14964b9f64fSJason Wang 				       vp_vdpa_vq_handler,
15064b9f64fSJason Wang 				       0, vp_vdpa->vring[i].msix_name,
15164b9f64fSJason Wang 				       &vp_vdpa->vring[i]);
15264b9f64fSJason Wang 		if (ret) {
15364b9f64fSJason Wang 			dev_err(&pdev->dev,
15464b9f64fSJason Wang 				"vp_vdpa: fail to request irq for vq %d\n", i);
15564b9f64fSJason Wang 			goto err;
15664b9f64fSJason Wang 		}
15764b9f64fSJason Wang 		vp_modern_queue_vector(mdev, i, i);
15864b9f64fSJason Wang 		vp_vdpa->vring[i].irq = irq;
15964b9f64fSJason Wang 	}
16064b9f64fSJason Wang 
16164b9f64fSJason Wang 	snprintf(vp_vdpa->msix_name, VP_VDPA_NAME_SIZE, "vp-vdpa[%s]-config\n",
16264b9f64fSJason Wang 		 pci_name(pdev));
16364b9f64fSJason Wang 	irq = pci_irq_vector(pdev, queues);
16464b9f64fSJason Wang 	ret = devm_request_irq(&pdev->dev, irq,	vp_vdpa_config_handler, 0,
16564b9f64fSJason Wang 			       vp_vdpa->msix_name, vp_vdpa);
16664b9f64fSJason Wang 	if (ret) {
16764b9f64fSJason Wang 		dev_err(&pdev->dev,
16864b9f64fSJason Wang 			"vp_vdpa: fail to request irq for vq %d\n", i);
16964b9f64fSJason Wang 			goto err;
17064b9f64fSJason Wang 	}
17164b9f64fSJason Wang 	vp_modern_config_vector(mdev, queues);
17264b9f64fSJason Wang 	vp_vdpa->config_irq = irq;
17364b9f64fSJason Wang 
17464b9f64fSJason Wang 	return 0;
17564b9f64fSJason Wang err:
17664b9f64fSJason Wang 	vp_vdpa_free_irq(vp_vdpa);
17764b9f64fSJason Wang 	return ret;
17864b9f64fSJason Wang }
17964b9f64fSJason Wang 
18064b9f64fSJason Wang static void vp_vdpa_set_status(struct vdpa_device *vdpa, u8 status)
18164b9f64fSJason Wang {
18264b9f64fSJason Wang 	struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa);
18364b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev;
18464b9f64fSJason Wang 	u8 s = vp_vdpa_get_status(vdpa);
18564b9f64fSJason Wang 
18664b9f64fSJason Wang 	if (status & VIRTIO_CONFIG_S_DRIVER_OK &&
18764b9f64fSJason Wang 	    !(s & VIRTIO_CONFIG_S_DRIVER_OK)) {
18864b9f64fSJason Wang 		vp_vdpa_request_irq(vp_vdpa);
18964b9f64fSJason Wang 	}
19064b9f64fSJason Wang 
19164b9f64fSJason Wang 	vp_modern_set_status(mdev, status);
19264b9f64fSJason Wang 
19364b9f64fSJason Wang 	if (!(status & VIRTIO_CONFIG_S_DRIVER_OK) &&
19464b9f64fSJason Wang 	    (s & VIRTIO_CONFIG_S_DRIVER_OK))
19564b9f64fSJason Wang 		vp_vdpa_free_irq(vp_vdpa);
19664b9f64fSJason Wang }
19764b9f64fSJason Wang 
19864b9f64fSJason Wang static u16 vp_vdpa_get_vq_num_max(struct vdpa_device *vdpa)
19964b9f64fSJason Wang {
20064b9f64fSJason Wang 	return VP_VDPA_QUEUE_MAX;
20164b9f64fSJason Wang }
20264b9f64fSJason Wang 
20364b9f64fSJason Wang static int vp_vdpa_get_vq_state(struct vdpa_device *vdpa, u16 qid,
20464b9f64fSJason Wang 				struct vdpa_vq_state *state)
20564b9f64fSJason Wang {
20664b9f64fSJason Wang 	/* Note that this is not supported by virtio specification, so
20764b9f64fSJason Wang 	 * we return -EOPNOTSUPP here. This means we can't support live
20864b9f64fSJason Wang 	 * migration, vhost device start/stop.
20964b9f64fSJason Wang 	 */
21064b9f64fSJason Wang 	return -EOPNOTSUPP;
21164b9f64fSJason Wang }
21264b9f64fSJason Wang 
21364b9f64fSJason Wang static int vp_vdpa_set_vq_state(struct vdpa_device *vdpa, u16 qid,
21464b9f64fSJason Wang 				const struct vdpa_vq_state *state)
21564b9f64fSJason Wang {
21664b9f64fSJason Wang 	/* Note that this is not supported by virtio specification, so
21764b9f64fSJason Wang 	 * we return -ENOPOTSUPP here. This means we can't support live
21864b9f64fSJason Wang 	 * migration, vhost device start/stop.
21964b9f64fSJason Wang 	 */
22064b9f64fSJason Wang 	return -EOPNOTSUPP;
22164b9f64fSJason Wang }
22264b9f64fSJason Wang 
22364b9f64fSJason Wang static void vp_vdpa_set_vq_cb(struct vdpa_device *vdpa, u16 qid,
22464b9f64fSJason Wang 			      struct vdpa_callback *cb)
22564b9f64fSJason Wang {
22664b9f64fSJason Wang 	struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa);
22764b9f64fSJason Wang 
22864b9f64fSJason Wang 	vp_vdpa->vring[qid].cb = *cb;
22964b9f64fSJason Wang }
23064b9f64fSJason Wang 
23164b9f64fSJason Wang static void vp_vdpa_set_vq_ready(struct vdpa_device *vdpa,
23264b9f64fSJason Wang 				 u16 qid, bool ready)
23364b9f64fSJason Wang {
23464b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa);
23564b9f64fSJason Wang 
23664b9f64fSJason Wang 	vp_modern_set_queue_enable(mdev, qid, ready);
23764b9f64fSJason Wang }
23864b9f64fSJason Wang 
23964b9f64fSJason Wang static bool vp_vdpa_get_vq_ready(struct vdpa_device *vdpa, u16 qid)
24064b9f64fSJason Wang {
24164b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa);
24264b9f64fSJason Wang 
24364b9f64fSJason Wang 	return vp_modern_get_queue_enable(mdev, qid);
24464b9f64fSJason Wang }
24564b9f64fSJason Wang 
24664b9f64fSJason Wang static void vp_vdpa_set_vq_num(struct vdpa_device *vdpa, u16 qid,
24764b9f64fSJason Wang 			       u32 num)
24864b9f64fSJason Wang {
24964b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa);
25064b9f64fSJason Wang 
25164b9f64fSJason Wang 	vp_modern_set_queue_size(mdev, qid, num);
25264b9f64fSJason Wang }
25364b9f64fSJason Wang 
25464b9f64fSJason Wang static int vp_vdpa_set_vq_address(struct vdpa_device *vdpa, u16 qid,
25564b9f64fSJason Wang 				  u64 desc_area, u64 driver_area,
25664b9f64fSJason Wang 				  u64 device_area)
25764b9f64fSJason Wang {
25864b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa);
25964b9f64fSJason Wang 
26064b9f64fSJason Wang 	vp_modern_queue_address(mdev, qid, desc_area,
26164b9f64fSJason Wang 				driver_area, device_area);
26264b9f64fSJason Wang 
26364b9f64fSJason Wang 	return 0;
26464b9f64fSJason Wang }
26564b9f64fSJason Wang 
26664b9f64fSJason Wang static void vp_vdpa_kick_vq(struct vdpa_device *vdpa, u16 qid)
26764b9f64fSJason Wang {
26864b9f64fSJason Wang 	struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa);
26964b9f64fSJason Wang 
27064b9f64fSJason Wang 	vp_iowrite16(qid, vp_vdpa->vring[qid].notify);
27164b9f64fSJason Wang }
27264b9f64fSJason Wang 
27364b9f64fSJason Wang static u32 vp_vdpa_get_generation(struct vdpa_device *vdpa)
27464b9f64fSJason Wang {
27564b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa);
27664b9f64fSJason Wang 
27764b9f64fSJason Wang 	return vp_modern_generation(mdev);
27864b9f64fSJason Wang }
27964b9f64fSJason Wang 
28064b9f64fSJason Wang static u32 vp_vdpa_get_device_id(struct vdpa_device *vdpa)
28164b9f64fSJason Wang {
28264b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa);
28364b9f64fSJason Wang 
28464b9f64fSJason Wang 	return mdev->id.device;
28564b9f64fSJason Wang }
28664b9f64fSJason Wang 
28764b9f64fSJason Wang static u32 vp_vdpa_get_vendor_id(struct vdpa_device *vdpa)
28864b9f64fSJason Wang {
28964b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa);
29064b9f64fSJason Wang 
29164b9f64fSJason Wang 	return mdev->id.vendor;
29264b9f64fSJason Wang }
29364b9f64fSJason Wang 
29464b9f64fSJason Wang static u32 vp_vdpa_get_vq_align(struct vdpa_device *vdpa)
29564b9f64fSJason Wang {
29664b9f64fSJason Wang 	return PAGE_SIZE;
29764b9f64fSJason Wang }
29864b9f64fSJason Wang 
299442706f9SStefano Garzarella static size_t vp_vdpa_get_config_size(struct vdpa_device *vdpa)
300442706f9SStefano Garzarella {
301442706f9SStefano Garzarella 	struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa);
302442706f9SStefano Garzarella 
303442706f9SStefano Garzarella 	return mdev->device_len;
304442706f9SStefano Garzarella }
305442706f9SStefano Garzarella 
30664b9f64fSJason Wang static void vp_vdpa_get_config(struct vdpa_device *vdpa,
30764b9f64fSJason Wang 			       unsigned int offset,
30864b9f64fSJason Wang 			       void *buf, unsigned int len)
30964b9f64fSJason Wang {
31064b9f64fSJason Wang 	struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa);
31164b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev;
31264b9f64fSJason Wang 	u8 old, new;
31364b9f64fSJason Wang 	u8 *p;
31464b9f64fSJason Wang 	int i;
31564b9f64fSJason Wang 
31664b9f64fSJason Wang 	do {
31764b9f64fSJason Wang 		old = vp_ioread8(&mdev->common->config_generation);
31864b9f64fSJason Wang 		p = buf;
31964b9f64fSJason Wang 		for (i = 0; i < len; i++)
32064b9f64fSJason Wang 			*p++ = vp_ioread8(mdev->device + offset + i);
32164b9f64fSJason Wang 
32264b9f64fSJason Wang 		new = vp_ioread8(&mdev->common->config_generation);
32364b9f64fSJason Wang 	} while (old != new);
32464b9f64fSJason Wang }
32564b9f64fSJason Wang 
32664b9f64fSJason Wang static void vp_vdpa_set_config(struct vdpa_device *vdpa,
32764b9f64fSJason Wang 			       unsigned int offset, const void *buf,
32864b9f64fSJason Wang 			       unsigned int len)
32964b9f64fSJason Wang {
33064b9f64fSJason Wang 	struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa);
33164b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev;
33264b9f64fSJason Wang 	const u8 *p = buf;
33364b9f64fSJason Wang 	int i;
33464b9f64fSJason Wang 
33564b9f64fSJason Wang 	for (i = 0; i < len; i++)
33664b9f64fSJason Wang 		vp_iowrite8(*p++, mdev->device + offset + i);
33764b9f64fSJason Wang }
33864b9f64fSJason Wang 
33964b9f64fSJason Wang static void vp_vdpa_set_config_cb(struct vdpa_device *vdpa,
34064b9f64fSJason Wang 				  struct vdpa_callback *cb)
34164b9f64fSJason Wang {
34264b9f64fSJason Wang 	struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa);
34364b9f64fSJason Wang 
34464b9f64fSJason Wang 	vp_vdpa->config_cb = *cb;
34564b9f64fSJason Wang }
34664b9f64fSJason Wang 
347526cb858SJason Wang static struct vdpa_notification_area
348526cb858SJason Wang vp_vdpa_get_vq_notification(struct vdpa_device *vdpa, u16 qid)
349526cb858SJason Wang {
350526cb858SJason Wang 	struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa);
351526cb858SJason Wang 	struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev;
352526cb858SJason Wang 	struct vdpa_notification_area notify;
353526cb858SJason Wang 
354526cb858SJason Wang 	notify.addr = vp_vdpa->vring[qid].notify_pa;
355526cb858SJason Wang 	notify.size = mdev->notify_offset_multiplier;
356526cb858SJason Wang 
357526cb858SJason Wang 	return notify;
358526cb858SJason Wang }
359526cb858SJason Wang 
36064b9f64fSJason Wang static const struct vdpa_config_ops vp_vdpa_ops = {
36164b9f64fSJason Wang 	.get_features	= vp_vdpa_get_features,
36264b9f64fSJason Wang 	.set_features	= vp_vdpa_set_features,
36364b9f64fSJason Wang 	.get_status	= vp_vdpa_get_status,
36464b9f64fSJason Wang 	.set_status	= vp_vdpa_set_status,
36564b9f64fSJason Wang 	.get_vq_num_max	= vp_vdpa_get_vq_num_max,
36664b9f64fSJason Wang 	.get_vq_state	= vp_vdpa_get_vq_state,
367526cb858SJason Wang 	.get_vq_notification = vp_vdpa_get_vq_notification,
36864b9f64fSJason Wang 	.set_vq_state	= vp_vdpa_set_vq_state,
36964b9f64fSJason Wang 	.set_vq_cb	= vp_vdpa_set_vq_cb,
37064b9f64fSJason Wang 	.set_vq_ready	= vp_vdpa_set_vq_ready,
37164b9f64fSJason Wang 	.get_vq_ready	= vp_vdpa_get_vq_ready,
37264b9f64fSJason Wang 	.set_vq_num	= vp_vdpa_set_vq_num,
37364b9f64fSJason Wang 	.set_vq_address	= vp_vdpa_set_vq_address,
37464b9f64fSJason Wang 	.kick_vq	= vp_vdpa_kick_vq,
37564b9f64fSJason Wang 	.get_generation	= vp_vdpa_get_generation,
37664b9f64fSJason Wang 	.get_device_id	= vp_vdpa_get_device_id,
37764b9f64fSJason Wang 	.get_vendor_id	= vp_vdpa_get_vendor_id,
37864b9f64fSJason Wang 	.get_vq_align	= vp_vdpa_get_vq_align,
379442706f9SStefano Garzarella 	.get_config_size = vp_vdpa_get_config_size,
38064b9f64fSJason Wang 	.get_config	= vp_vdpa_get_config,
38164b9f64fSJason Wang 	.set_config	= vp_vdpa_set_config,
38264b9f64fSJason Wang 	.set_config_cb  = vp_vdpa_set_config_cb,
38364b9f64fSJason Wang };
38464b9f64fSJason Wang 
38564b9f64fSJason Wang static void vp_vdpa_free_irq_vectors(void *data)
38664b9f64fSJason Wang {
38764b9f64fSJason Wang 	pci_free_irq_vectors(data);
38864b9f64fSJason Wang }
38964b9f64fSJason Wang 
39064b9f64fSJason Wang static int vp_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
39164b9f64fSJason Wang {
39264b9f64fSJason Wang 	struct virtio_pci_modern_device *mdev;
39364b9f64fSJason Wang 	struct device *dev = &pdev->dev;
39464b9f64fSJason Wang 	struct vp_vdpa *vp_vdpa;
39564b9f64fSJason Wang 	int ret, i;
39664b9f64fSJason Wang 
39764b9f64fSJason Wang 	ret = pcim_enable_device(pdev);
39864b9f64fSJason Wang 	if (ret)
39964b9f64fSJason Wang 		return ret;
40064b9f64fSJason Wang 
40164b9f64fSJason Wang 	vp_vdpa = vdpa_alloc_device(struct vp_vdpa, vdpa,
40264b9f64fSJason Wang 				    dev, &vp_vdpa_ops, NULL);
40364b9f64fSJason Wang 	if (vp_vdpa == NULL) {
40464b9f64fSJason Wang 		dev_err(dev, "vp_vdpa: Failed to allocate vDPA structure\n");
40564b9f64fSJason Wang 		return -ENOMEM;
40664b9f64fSJason Wang 	}
40764b9f64fSJason Wang 
40864b9f64fSJason Wang 	mdev = &vp_vdpa->mdev;
40964b9f64fSJason Wang 	mdev->pci_dev = pdev;
41064b9f64fSJason Wang 
41164b9f64fSJason Wang 	ret = vp_modern_probe(mdev);
41264b9f64fSJason Wang 	if (ret) {
41364b9f64fSJason Wang 		dev_err(&pdev->dev, "Failed to probe modern PCI device\n");
41464b9f64fSJason Wang 		goto err;
41564b9f64fSJason Wang 	}
41664b9f64fSJason Wang 
41764b9f64fSJason Wang 	pci_set_master(pdev);
41864b9f64fSJason Wang 	pci_set_drvdata(pdev, vp_vdpa);
41964b9f64fSJason Wang 
42064b9f64fSJason Wang 	vp_vdpa->vdpa.dma_dev = &pdev->dev;
42164b9f64fSJason Wang 	vp_vdpa->queues = vp_modern_get_num_queues(mdev);
42264b9f64fSJason Wang 
42364b9f64fSJason Wang 	ret = devm_add_action_or_reset(dev, vp_vdpa_free_irq_vectors, pdev);
42464b9f64fSJason Wang 	if (ret) {
42564b9f64fSJason Wang 		dev_err(&pdev->dev,
42664b9f64fSJason Wang 			"Failed for adding devres for freeing irq vectors\n");
42764b9f64fSJason Wang 		goto err;
42864b9f64fSJason Wang 	}
42964b9f64fSJason Wang 
43064b9f64fSJason Wang 	vp_vdpa->vring = devm_kcalloc(&pdev->dev, vp_vdpa->queues,
43164b9f64fSJason Wang 				      sizeof(*vp_vdpa->vring),
43264b9f64fSJason Wang 				      GFP_KERNEL);
43364b9f64fSJason Wang 	if (!vp_vdpa->vring) {
43464b9f64fSJason Wang 		ret = -ENOMEM;
43564b9f64fSJason Wang 		dev_err(&pdev->dev, "Fail to allocate virtqueues\n");
43664b9f64fSJason Wang 		goto err;
43764b9f64fSJason Wang 	}
43864b9f64fSJason Wang 
43964b9f64fSJason Wang 	for (i = 0; i < vp_vdpa->queues; i++) {
44064b9f64fSJason Wang 		vp_vdpa->vring[i].irq = VIRTIO_MSI_NO_VECTOR;
4419e311bcaSJason Wang 		vp_vdpa->vring[i].notify =
442526cb858SJason Wang 			vp_modern_map_vq_notify(mdev, i,
443526cb858SJason Wang 						&vp_vdpa->vring[i].notify_pa);
44411d8ffedSJason Wang 		if (!vp_vdpa->vring[i].notify) {
445*94e48d6aSJason Wang 			ret = -EINVAL;
44611d8ffedSJason Wang 			dev_warn(&pdev->dev, "Fail to map vq notify %d\n", i);
44711d8ffedSJason Wang 			goto err;
44811d8ffedSJason Wang 		}
44964b9f64fSJason Wang 	}
45064b9f64fSJason Wang 	vp_vdpa->config_irq = VIRTIO_MSI_NO_VECTOR;
45164b9f64fSJason Wang 
45264b9f64fSJason Wang 	ret = vdpa_register_device(&vp_vdpa->vdpa, vp_vdpa->queues);
45364b9f64fSJason Wang 	if (ret) {
45464b9f64fSJason Wang 		dev_err(&pdev->dev, "Failed to register to vdpa bus\n");
45564b9f64fSJason Wang 		goto err;
45664b9f64fSJason Wang 	}
45764b9f64fSJason Wang 
45864b9f64fSJason Wang 	return 0;
45964b9f64fSJason Wang 
46064b9f64fSJason Wang err:
46164b9f64fSJason Wang 	put_device(&vp_vdpa->vdpa.dev);
46264b9f64fSJason Wang 	return ret;
46364b9f64fSJason Wang }
46464b9f64fSJason Wang 
46564b9f64fSJason Wang static void vp_vdpa_remove(struct pci_dev *pdev)
46664b9f64fSJason Wang {
46764b9f64fSJason Wang 	struct vp_vdpa *vp_vdpa = pci_get_drvdata(pdev);
46864b9f64fSJason Wang 
46964b9f64fSJason Wang 	vdpa_unregister_device(&vp_vdpa->vdpa);
47064b9f64fSJason Wang 	vp_modern_remove(&vp_vdpa->mdev);
47164b9f64fSJason Wang }
47264b9f64fSJason Wang 
47364b9f64fSJason Wang static struct pci_driver vp_vdpa_driver = {
47464b9f64fSJason Wang 	.name		= "vp-vdpa",
47564b9f64fSJason Wang 	.id_table	= NULL, /* only dynamic ids */
47664b9f64fSJason Wang 	.probe		= vp_vdpa_probe,
47764b9f64fSJason Wang 	.remove		= vp_vdpa_remove,
47864b9f64fSJason Wang };
47964b9f64fSJason Wang 
48064b9f64fSJason Wang module_pci_driver(vp_vdpa_driver);
48164b9f64fSJason Wang 
48264b9f64fSJason Wang MODULE_AUTHOR("Jason Wang <jasowang@redhat.com>");
48364b9f64fSJason Wang MODULE_DESCRIPTION("vp-vdpa");
48464b9f64fSJason Wang MODULE_LICENSE("GPL");
48564b9f64fSJason Wang MODULE_VERSION("1");
486