xref: /kvmtool/virtio/pci.c (revision 9594e883b553d278f9d4f205faa1e20da506c690)
136f5dc91SSasha Levin #include "kvm/virtio-pci.h"
236f5dc91SSasha Levin 
336f5dc91SSasha Levin #include "kvm/ioport.h"
436f5dc91SSasha Levin #include "kvm/kvm.h"
536f5dc91SSasha Levin #include "kvm/virtio-pci-dev.h"
636f5dc91SSasha Levin #include "kvm/irq.h"
736f5dc91SSasha Levin #include "kvm/virtio.h"
81599d724SSasha Levin #include "kvm/ioeventfd.h"
936f5dc91SSasha Levin 
1036f5dc91SSasha Levin #include <linux/virtio_pci.h>
11aa73be70SMatt Evans #include <linux/byteorder.h>
1236f5dc91SSasha Levin #include <string.h>
1336f5dc91SSasha Levin 
141599d724SSasha Levin static void virtio_pci__ioevent_callback(struct kvm *kvm, void *param)
151599d724SSasha Levin {
161599d724SSasha Levin 	struct virtio_pci_ioevent_param *ioeventfd = param;
1702eca50cSAsias He 	struct virtio_pci *vpci = ioeventfd->vdev->virtio;
181599d724SSasha Levin 
1902eca50cSAsias He 	ioeventfd->vdev->ops->notify_vq(kvm, vpci->dev, ioeventfd->vq);
201599d724SSasha Levin }
211599d724SSasha Levin 
2202eca50cSAsias He static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
231599d724SSasha Levin {
241599d724SSasha Levin 	struct ioevent ioevent;
2502eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
26ea6eeb1cSSasha Levin 	int r;
271599d724SSasha Levin 
281599d724SSasha Levin 	vpci->ioeventfds[vq] = (struct virtio_pci_ioevent_param) {
2902eca50cSAsias He 		.vdev		= vdev,
301599d724SSasha Levin 		.vq		= vq,
311599d724SSasha Levin 	};
321599d724SSasha Levin 
331599d724SSasha Levin 	ioevent = (struct ioevent) {
341599d724SSasha Levin 		.io_addr	= vpci->base_addr + VIRTIO_PCI_QUEUE_NOTIFY,
351599d724SSasha Levin 		.io_len		= sizeof(u16),
361599d724SSasha Levin 		.fn		= virtio_pci__ioevent_callback,
371599d724SSasha Levin 		.fn_ptr		= &vpci->ioeventfds[vq],
381599d724SSasha Levin 		.datamatch	= vq,
391599d724SSasha Levin 		.fn_kvm		= kvm,
401599d724SSasha Levin 		.fd		= eventfd(0, 0),
411599d724SSasha Levin 	};
421599d724SSasha Levin 
439ff91339SAsias He 	r = ioeventfd__add_event(&ioevent, true);
44ea6eeb1cSSasha Levin 	if (r)
45ea6eeb1cSSasha Levin 		return r;
461599d724SSasha Levin 
4702eca50cSAsias He 	if (vdev->ops->notify_vq_eventfd)
4802eca50cSAsias He 		vdev->ops->notify_vq_eventfd(kvm, vpci->dev, vq, ioevent.fd);
49263b80e8SSasha Levin 
501599d724SSasha Levin 	return 0;
511599d724SSasha Levin }
521599d724SSasha Levin 
5306f48103SSasha Levin static inline bool virtio_pci__msix_enabled(struct virtio_pci *vpci)
5406f48103SSasha Levin {
55aa73be70SMatt Evans 	return vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE);
5606f48103SSasha Levin }
5706f48103SSasha Levin 
5802eca50cSAsias He static bool virtio_pci__specific_io_in(struct kvm *kvm, struct virtio_device *vdev, u16 port,
5936f5dc91SSasha Levin 					void *data, int size, int offset)
6036f5dc91SSasha Levin {
6136f5dc91SSasha Levin 	u32 config_offset;
6202eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
6306f48103SSasha Levin 	int type = virtio__get_dev_specific_field(offset - 20,
6406f48103SSasha Levin 							virtio_pci__msix_enabled(vpci),
651382aba0SSasha Levin 							&config_offset);
6636f5dc91SSasha Levin 	if (type == VIRTIO_PCI_O_MSIX) {
6736f5dc91SSasha Levin 		switch (offset) {
6836f5dc91SSasha Levin 		case VIRTIO_MSI_CONFIG_VECTOR:
6936f5dc91SSasha Levin 			ioport__write16(data, vpci->config_vector);
7036f5dc91SSasha Levin 			break;
7136f5dc91SSasha Levin 		case VIRTIO_MSI_QUEUE_VECTOR:
7236f5dc91SSasha Levin 			ioport__write16(data, vpci->vq_vector[vpci->queue_selector]);
7336f5dc91SSasha Levin 			break;
7436f5dc91SSasha Levin 		};
7536f5dc91SSasha Levin 
7636f5dc91SSasha Levin 		return true;
7736f5dc91SSasha Levin 	} else if (type == VIRTIO_PCI_O_CONFIG) {
7836f5dc91SSasha Levin 		u8 cfg;
7936f5dc91SSasha Levin 
8002eca50cSAsias He 		cfg = vdev->ops->get_config(kvm, vpci->dev, config_offset);
8136f5dc91SSasha Levin 		ioport__write8(data, cfg);
8236f5dc91SSasha Levin 		return true;
8336f5dc91SSasha Levin 	}
8436f5dc91SSasha Levin 
8536f5dc91SSasha Levin 	return false;
8636f5dc91SSasha Levin }
8736f5dc91SSasha Levin 
8836f5dc91SSasha Levin static bool virtio_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
8936f5dc91SSasha Levin {
9036f5dc91SSasha Levin 	unsigned long offset;
9136f5dc91SSasha Levin 	bool ret = true;
9202eca50cSAsias He 	struct virtio_device *vdev;
9336f5dc91SSasha Levin 	struct virtio_pci *vpci;
9436f5dc91SSasha Levin 	u32 val;
9536f5dc91SSasha Levin 
9602eca50cSAsias He 	vdev = ioport->priv;
9702eca50cSAsias He 	vpci = vdev->virtio;
9836f5dc91SSasha Levin 	offset = port - vpci->base_addr;
9936f5dc91SSasha Levin 
10036f5dc91SSasha Levin 	switch (offset) {
10136f5dc91SSasha Levin 	case VIRTIO_PCI_HOST_FEATURES:
10202eca50cSAsias He 		val = vdev->ops->get_host_features(kvm, vpci->dev);
10336f5dc91SSasha Levin 		ioport__write32(data, val);
10436f5dc91SSasha Levin 		break;
10536f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_PFN:
10602eca50cSAsias He 		val = vdev->ops->get_pfn_vq(kvm, vpci->dev, vpci->queue_selector);
10736f5dc91SSasha Levin 		ioport__write32(data, val);
10836f5dc91SSasha Levin 		break;
10936f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_NUM:
11002eca50cSAsias He 		val = vdev->ops->get_size_vq(kvm, vpci->dev, vpci->queue_selector);
111657ee18bSMatt Evans 		ioport__write16(data, val);
11236f5dc91SSasha Levin 		break;
11336f5dc91SSasha Levin 	case VIRTIO_PCI_STATUS:
11436f5dc91SSasha Levin 		ioport__write8(data, vpci->status);
11536f5dc91SSasha Levin 		break;
11636f5dc91SSasha Levin 	case VIRTIO_PCI_ISR:
11736f5dc91SSasha Levin 		ioport__write8(data, vpci->isr);
11836f5dc91SSasha Levin 		kvm__irq_line(kvm, vpci->pci_hdr.irq_line, VIRTIO_IRQ_LOW);
11936f5dc91SSasha Levin 		vpci->isr = VIRTIO_IRQ_LOW;
12036f5dc91SSasha Levin 		break;
12136f5dc91SSasha Levin 	default:
12202eca50cSAsias He 		ret = virtio_pci__specific_io_in(kvm, vdev, port, data, size, offset);
12336f5dc91SSasha Levin 		break;
12436f5dc91SSasha Levin 	};
12536f5dc91SSasha Levin 
12636f5dc91SSasha Levin 	return ret;
12736f5dc91SSasha Levin }
12836f5dc91SSasha Levin 
12902eca50cSAsias He static bool virtio_pci__specific_io_out(struct kvm *kvm, struct virtio_device *vdev, u16 port,
13036f5dc91SSasha Levin 					void *data, int size, int offset)
13136f5dc91SSasha Levin {
13202eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
13336f5dc91SSasha Levin 	u32 config_offset, gsi, vec;
13406f48103SSasha Levin 	int type = virtio__get_dev_specific_field(offset - 20, virtio_pci__msix_enabled(vpci),
1351382aba0SSasha Levin 							&config_offset);
13636f5dc91SSasha Levin 	if (type == VIRTIO_PCI_O_MSIX) {
13736f5dc91SSasha Levin 		switch (offset) {
13836f5dc91SSasha Levin 		case VIRTIO_MSI_CONFIG_VECTOR:
13936f5dc91SSasha Levin 			vec = vpci->config_vector = ioport__read16(data);
14036f5dc91SSasha Levin 
1411de74957SSasha Levin 			gsi = irq__add_msix_route(kvm, &vpci->msix_table[vec].msg);
14236f5dc91SSasha Levin 
14336f5dc91SSasha Levin 			vpci->config_gsi = gsi;
14436f5dc91SSasha Levin 			break;
1453a60be06SSasha Levin 		case VIRTIO_MSI_QUEUE_VECTOR:
14636f5dc91SSasha Levin 			vec = vpci->vq_vector[vpci->queue_selector] = ioport__read16(data);
14736f5dc91SSasha Levin 
1481de74957SSasha Levin 			gsi = irq__add_msix_route(kvm, &vpci->msix_table[vec].msg);
14936f5dc91SSasha Levin 			vpci->gsis[vpci->queue_selector] = gsi;
15002eca50cSAsias He 			if (vdev->ops->notify_vq_gsi)
15102eca50cSAsias He 				vdev->ops->notify_vq_gsi(kvm, vpci->dev,
152263b80e8SSasha Levin 							vpci->queue_selector, gsi);
15336f5dc91SSasha Levin 			break;
15436f5dc91SSasha Levin 		};
15536f5dc91SSasha Levin 
15636f5dc91SSasha Levin 		return true;
15736f5dc91SSasha Levin 	} else if (type == VIRTIO_PCI_O_CONFIG) {
15802eca50cSAsias He 		vdev->ops->set_config(kvm, vpci->dev, *(u8 *)data, config_offset);
15936f5dc91SSasha Levin 
16036f5dc91SSasha Levin 		return true;
16136f5dc91SSasha Levin 	}
16236f5dc91SSasha Levin 
16336f5dc91SSasha Levin 	return false;
16436f5dc91SSasha Levin }
16536f5dc91SSasha Levin 
16636f5dc91SSasha Levin static bool virtio_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
16736f5dc91SSasha Levin {
16836f5dc91SSasha Levin 	unsigned long offset;
16936f5dc91SSasha Levin 	bool ret = true;
17002eca50cSAsias He 	struct virtio_device *vdev;
17136f5dc91SSasha Levin 	struct virtio_pci *vpci;
17236f5dc91SSasha Levin 	u32 val;
17336f5dc91SSasha Levin 
17402eca50cSAsias He 	vdev = ioport->priv;
17502eca50cSAsias He 	vpci = vdev->virtio;
17636f5dc91SSasha Levin 	offset = port - vpci->base_addr;
17736f5dc91SSasha Levin 
17836f5dc91SSasha Levin 	switch (offset) {
17936f5dc91SSasha Levin 	case VIRTIO_PCI_GUEST_FEATURES:
18036f5dc91SSasha Levin 		val = ioport__read32(data);
18102eca50cSAsias He 		vdev->ops->set_guest_features(kvm, vpci->dev, val);
18236f5dc91SSasha Levin 		break;
18336f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_PFN:
18436f5dc91SSasha Levin 		val = ioport__read32(data);
18502eca50cSAsias He 		virtio_pci__init_ioeventfd(kvm, vdev, vpci->queue_selector);
18602eca50cSAsias He 		vdev->ops->init_vq(kvm, vpci->dev, vpci->queue_selector, val);
18736f5dc91SSasha Levin 		break;
18836f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_SEL:
18936f5dc91SSasha Levin 		vpci->queue_selector = ioport__read16(data);
19036f5dc91SSasha Levin 		break;
19136f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_NOTIFY:
19236f5dc91SSasha Levin 		val = ioport__read16(data);
19302eca50cSAsias He 		vdev->ops->notify_vq(kvm, vpci->dev, val);
19436f5dc91SSasha Levin 		break;
19536f5dc91SSasha Levin 	case VIRTIO_PCI_STATUS:
19636f5dc91SSasha Levin 		vpci->status = ioport__read8(data);
19736f5dc91SSasha Levin 		break;
19836f5dc91SSasha Levin 	default:
19902eca50cSAsias He 		ret = virtio_pci__specific_io_out(kvm, vdev, port, data, size, offset);
20036f5dc91SSasha Levin 		break;
20136f5dc91SSasha Levin 	};
20236f5dc91SSasha Levin 
20336f5dc91SSasha Levin 	return ret;
20436f5dc91SSasha Levin }
20536f5dc91SSasha Levin 
20636f5dc91SSasha Levin static struct ioport_operations virtio_pci__io_ops = {
20736f5dc91SSasha Levin 	.io_in	= virtio_pci__io_in,
20836f5dc91SSasha Levin 	.io_out	= virtio_pci__io_out,
20936f5dc91SSasha Levin };
21036f5dc91SSasha Levin 
211*9594e883SAsias He static void virtio_pci__mmio_callback(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr)
21236f5dc91SSasha Levin {
21336f5dc91SSasha Levin 	struct virtio_pci *vpci = ptr;
2149c26dab4SSasha Levin 	void *table;
2159c26dab4SSasha Levin 	u32 offset;
21636f5dc91SSasha Levin 
2179c26dab4SSasha Levin 	if (addr > vpci->msix_io_block + PCI_IO_SIZE) {
2189c26dab4SSasha Levin 		table	= &vpci->msix_pba;
2199c26dab4SSasha Levin 		offset	= vpci->msix_io_block + PCI_IO_SIZE;
2209c26dab4SSasha Levin 	} else {
2219c26dab4SSasha Levin 		table	= &vpci->msix_table;
2229c26dab4SSasha Levin 		offset	= vpci->msix_io_block;
22336f5dc91SSasha Levin 	}
22436f5dc91SSasha Levin 
22506f48103SSasha Levin 	if (is_write)
2269c26dab4SSasha Levin 		memcpy(table + addr - offset, data, len);
22706f48103SSasha Levin 	else
2289c26dab4SSasha Levin 		memcpy(data, table + addr - offset, len);
22906f48103SSasha Levin }
23006f48103SSasha Levin 
23102eca50cSAsias He int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
23236f5dc91SSasha Levin {
23302eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
23406f48103SSasha Levin 	int tbl = vpci->vq_vector[vq];
23536f5dc91SSasha Levin 
23606f48103SSasha Levin 	if (virtio_pci__msix_enabled(vpci)) {
237aa73be70SMatt Evans 		if (vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_MASKALL) ||
238aa73be70SMatt Evans 		    vpci->msix_table[tbl].ctrl & cpu_to_le16(PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
23906f48103SSasha Levin 
24006f48103SSasha Levin 			vpci->msix_pba |= 1 << tbl;
24106f48103SSasha Levin 			return 0;
24206f48103SSasha Levin 		}
24306f48103SSasha Levin 
24406f48103SSasha Levin 		kvm__irq_trigger(kvm, vpci->gsis[vq]);
24506f48103SSasha Levin 	} else {
246a36eca7bSSasha Levin 		vpci->isr = VIRTIO_IRQ_HIGH;
24706f48103SSasha Levin 		kvm__irq_trigger(kvm, vpci->pci_hdr.irq_line);
24806f48103SSasha Levin 	}
24936f5dc91SSasha Levin 	return 0;
25036f5dc91SSasha Levin }
25136f5dc91SSasha Levin 
25202eca50cSAsias He int virtio_pci__signal_config(struct kvm *kvm, struct virtio_device *vdev)
25336f5dc91SSasha Levin {
25402eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
25506f48103SSasha Levin 	int tbl = vpci->config_vector;
25606f48103SSasha Levin 
25706f48103SSasha Levin 	if (virtio_pci__msix_enabled(vpci)) {
258aa73be70SMatt Evans 		if (vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_MASKALL) ||
259aa73be70SMatt Evans 		    vpci->msix_table[tbl].ctrl & cpu_to_le16(PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
26006f48103SSasha Levin 
26106f48103SSasha Levin 			vpci->msix_pba |= 1 << tbl;
26206f48103SSasha Levin 			return 0;
26306f48103SSasha Levin 		}
26406f48103SSasha Levin 
26506f48103SSasha Levin 		kvm__irq_trigger(kvm, vpci->config_gsi);
26606f48103SSasha Levin 	} else {
26706f48103SSasha Levin 		vpci->isr = VIRTIO_PCI_ISR_CONFIG;
26806f48103SSasha Levin 		kvm__irq_trigger(kvm, vpci->pci_hdr.irq_line);
26906f48103SSasha Levin 	}
27036f5dc91SSasha Levin 
27136f5dc91SSasha Levin 	return 0;
27236f5dc91SSasha Levin }
27336f5dc91SSasha Levin 
27402eca50cSAsias He int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
275507e02d8SAsias He 		     int device_id, int subsys_id, int class)
27636f5dc91SSasha Levin {
27702eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
27836f5dc91SSasha Levin 	u8 pin, line, ndev;
2797af40b91SSasha Levin 	int r;
28036f5dc91SSasha Levin 
28136f5dc91SSasha Levin 	vpci->dev = dev;
2829c26dab4SSasha Levin 	vpci->msix_io_block = pci_get_io_space_block(PCI_IO_SIZE * 2);
28336f5dc91SSasha Levin 
28402eca50cSAsias He 	r = ioport__register(IOPORT_EMPTY, &virtio_pci__io_ops, IOPORT_SIZE, vdev);
2857af40b91SSasha Levin 	if (r < 0)
2867af40b91SSasha Levin 		return r;
2877af40b91SSasha Levin 
2887af40b91SSasha Levin 	vpci->base_addr = (u16)r;
28902eca50cSAsias He 	r = kvm__register_mmio(kvm, vpci->msix_io_block, PCI_IO_SIZE, false,
290*9594e883SAsias He 			       virtio_pci__mmio_callback, vpci);
291495fbd4eSSasha Levin 	if (r < 0)
292495fbd4eSSasha Levin 		goto free_ioport;
29336f5dc91SSasha Levin 
29436f5dc91SSasha Levin 	vpci->pci_hdr = (struct pci_device_header) {
295aa73be70SMatt Evans 		.vendor_id		= cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
296aa73be70SMatt Evans 		.device_id		= cpu_to_le16(device_id),
29736f5dc91SSasha Levin 		.header_type		= PCI_HEADER_TYPE_NORMAL,
29836f5dc91SSasha Levin 		.revision_id		= 0,
299aa73be70SMatt Evans 		.class[0]		= class & 0xff,
300aa73be70SMatt Evans 		.class[1]		= (class >> 8) & 0xff,
301aa73be70SMatt Evans 		.class[2]		= (class >> 16) & 0xff,
302aa73be70SMatt Evans 		.subsys_vendor_id	= cpu_to_le16(PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET),
303aa73be70SMatt Evans 		.subsys_id		= cpu_to_le16(subsys_id),
3049c26dab4SSasha Levin 		.bar[0]			= cpu_to_le32(vpci->base_addr
3059c26dab4SSasha Levin 							| PCI_BASE_ADDRESS_SPACE_IO),
306b4dab816SSasha Levin 		.bar[1]			= cpu_to_le32(vpci->msix_io_block
307b4dab816SSasha Levin 							| PCI_BASE_ADDRESS_SPACE_MEMORY),
308aa73be70SMatt Evans 		.status			= cpu_to_le16(PCI_STATUS_CAP_LIST),
30936f5dc91SSasha Levin 		.capabilities		= (void *)&vpci->pci_hdr.msix - (void *)&vpci->pci_hdr,
3106b868987SMatt Evans 		.bar_size[0]		= IOPORT_SIZE,
3116b868987SMatt Evans 		.bar_size[1]		= PCI_IO_SIZE,
3126b868987SMatt Evans 		.bar_size[3]		= PCI_IO_SIZE,
31336f5dc91SSasha Levin 	};
31436f5dc91SSasha Levin 
31536f5dc91SSasha Levin 	vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX;
31636f5dc91SSasha Levin 	vpci->pci_hdr.msix.next = 0;
31714bba8a0SAsias He 	/*
31814bba8a0SAsias He 	 * We at most have VIRTIO_PCI_MAX_VQ entries for virt queue,
31914bba8a0SAsias He 	 * VIRTIO_PCI_MAX_CONFIG entries for config.
32014bba8a0SAsias He 	 *
32114bba8a0SAsias He 	 * To quote the PCI spec:
32214bba8a0SAsias He 	 *
32314bba8a0SAsias He 	 * System software reads this field to determine the
32414bba8a0SAsias He 	 * MSI-X Table Size N, which is encoded as N-1.
32514bba8a0SAsias He 	 * For example, a returned value of "00000000011"
32614bba8a0SAsias He 	 * indicates a table size of 4.
32714bba8a0SAsias He 	 */
328aa73be70SMatt Evans 	vpci->pci_hdr.msix.ctrl = cpu_to_le16(VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG - 1);
32906f48103SSasha Levin 
33006f48103SSasha Levin 	/*
33106f48103SSasha Levin 	 * Both table and PBA could be mapped on the same BAR, but for now
33206f48103SSasha Levin 	 * we're not in short of BARs
33306f48103SSasha Levin 	 */
334aa73be70SMatt Evans 	vpci->pci_hdr.msix.table_offset = cpu_to_le32(1); /* Use BAR 1 */
3359c26dab4SSasha Levin 	vpci->pci_hdr.msix.pba_offset = cpu_to_le32(1 | PCI_IO_SIZE); /* Use BAR 3 */
33636f5dc91SSasha Levin 	vpci->config_vector = 0;
33736f5dc91SSasha Levin 
338495fbd4eSSasha Levin 	r = irq__register_device(subsys_id, &ndev, &pin, &line);
339495fbd4eSSasha Levin 	if (r < 0)
340495fbd4eSSasha Levin 		goto free_mmio;
34136f5dc91SSasha Levin 
34236f5dc91SSasha Levin 	vpci->pci_hdr.irq_pin	= pin;
34336f5dc91SSasha Levin 	vpci->pci_hdr.irq_line	= line;
344495fbd4eSSasha Levin 	r = pci__register(&vpci->pci_hdr, ndev);
345495fbd4eSSasha Levin 	if (r < 0)
346495fbd4eSSasha Levin 		goto free_ioport;
347495fbd4eSSasha Levin 
348495fbd4eSSasha Levin 	return 0;
349495fbd4eSSasha Levin 
350495fbd4eSSasha Levin free_mmio:
351495fbd4eSSasha Levin 	kvm__deregister_mmio(kvm, vpci->msix_io_block);
352495fbd4eSSasha Levin free_ioport:
353495fbd4eSSasha Levin 	ioport__unregister(vpci->base_addr);
354495fbd4eSSasha Levin 	return r;
355495fbd4eSSasha Levin }
356495fbd4eSSasha Levin 
35702eca50cSAsias He int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev)
358495fbd4eSSasha Levin {
35902eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
360495fbd4eSSasha Levin 	int i;
361495fbd4eSSasha Levin 
362495fbd4eSSasha Levin 	kvm__deregister_mmio(kvm, vpci->msix_io_block);
363495fbd4eSSasha Levin 	ioport__unregister(vpci->base_addr);
364495fbd4eSSasha Levin 
365495fbd4eSSasha Levin 	for (i = 0; i < VIRTIO_PCI_MAX_VQ; i++)
366495fbd4eSSasha Levin 		ioeventfd__del_event(vpci->base_addr + VIRTIO_PCI_QUEUE_NOTIFY, i);
36736f5dc91SSasha Levin 
36836f5dc91SSasha Levin 	return 0;
36936f5dc91SSasha Levin }
370