xref: /kvmtool/virtio/pci.c (revision a463650caad6b8a47dbd75a934ac01fb1e67c389)
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 
1043c81c74SSasha Levin #include <sys/ioctl.h>
1136f5dc91SSasha Levin #include <linux/virtio_pci.h>
12aa73be70SMatt Evans #include <linux/byteorder.h>
1336f5dc91SSasha Levin #include <string.h>
1436f5dc91SSasha Levin 
151599d724SSasha Levin static void virtio_pci__ioevent_callback(struct kvm *kvm, void *param)
161599d724SSasha Levin {
171599d724SSasha Levin 	struct virtio_pci_ioevent_param *ioeventfd = param;
1802eca50cSAsias He 	struct virtio_pci *vpci = ioeventfd->vdev->virtio;
191599d724SSasha Levin 
2002eca50cSAsias He 	ioeventfd->vdev->ops->notify_vq(kvm, vpci->dev, ioeventfd->vq);
211599d724SSasha Levin }
221599d724SSasha Levin 
2302eca50cSAsias He static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
241599d724SSasha Levin {
251599d724SSasha Levin 	struct ioevent ioevent;
2602eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
27*a463650cSWill Deacon 	int i, r, flags = IOEVENTFD_FLAG_PIO;
28*a463650cSWill Deacon 	int fds[2];
291599d724SSasha Levin 
301599d724SSasha Levin 	vpci->ioeventfds[vq] = (struct virtio_pci_ioevent_param) {
3102eca50cSAsias He 		.vdev		= vdev,
321599d724SSasha Levin 		.vq		= vq,
331599d724SSasha Levin 	};
341599d724SSasha Levin 
351599d724SSasha Levin 	ioevent = (struct ioevent) {
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 	};
411599d724SSasha Levin 
42627d6874SAsias He 	/*
43*a463650cSWill Deacon 	 * Vhost will poll the eventfd in host kernel side, otherwise we
44*a463650cSWill Deacon 	 * need to poll in userspace.
45627d6874SAsias He 	 */
46*a463650cSWill Deacon 	if (!vdev->use_vhost)
47*a463650cSWill Deacon 		flags |= IOEVENTFD_FLAG_USER_POLL;
48*a463650cSWill Deacon 
49*a463650cSWill Deacon 	/* ioport */
50*a463650cSWill Deacon 	ioevent.io_addr	= vpci->port_addr + VIRTIO_PCI_QUEUE_NOTIFY;
51*a463650cSWill Deacon 	ioevent.io_len	= sizeof(u16);
52*a463650cSWill Deacon 	ioevent.fd	= fds[0] = eventfd(0, 0);
53*a463650cSWill Deacon 	r = ioeventfd__add_event(&ioevent, flags);
54ea6eeb1cSSasha Levin 	if (r)
55ea6eeb1cSSasha Levin 		return r;
561599d724SSasha Levin 
57*a463650cSWill Deacon 	/* mmio */
58*a463650cSWill Deacon 	ioevent.io_addr	= vpci->mmio_addr + VIRTIO_PCI_QUEUE_NOTIFY;
59*a463650cSWill Deacon 	ioevent.io_len	= sizeof(u32);
60*a463650cSWill Deacon 	ioevent.fd	= fds[1] = eventfd(0, 0);
61*a463650cSWill Deacon 	r = ioeventfd__add_event(&ioevent, flags);
62*a463650cSWill Deacon 	if (r)
63*a463650cSWill Deacon 		goto free_ioport_evt;
64263b80e8SSasha Levin 
65*a463650cSWill Deacon 	if (vdev->ops->notify_vq_eventfd)
66*a463650cSWill Deacon 		for (i = 0; i < 2; ++i)
67*a463650cSWill Deacon 			vdev->ops->notify_vq_eventfd(kvm, vpci->dev, vq,
68*a463650cSWill Deacon 						     fds[i]);
691599d724SSasha Levin 	return 0;
70*a463650cSWill Deacon 
71*a463650cSWill Deacon free_ioport_evt:
72*a463650cSWill Deacon 	ioeventfd__del_event(vpci->port_addr + VIRTIO_PCI_QUEUE_NOTIFY, vq);
73*a463650cSWill Deacon 	return r;
741599d724SSasha Levin }
751599d724SSasha Levin 
7606f48103SSasha Levin static inline bool virtio_pci__msix_enabled(struct virtio_pci *vpci)
7706f48103SSasha Levin {
78aa73be70SMatt Evans 	return vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE);
7906f48103SSasha Levin }
8006f48103SSasha Levin 
8102eca50cSAsias He static bool virtio_pci__specific_io_in(struct kvm *kvm, struct virtio_device *vdev, u16 port,
8236f5dc91SSasha Levin 					void *data, int size, int offset)
8336f5dc91SSasha Levin {
8436f5dc91SSasha Levin 	u32 config_offset;
8502eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
8606f48103SSasha Levin 	int type = virtio__get_dev_specific_field(offset - 20,
8706f48103SSasha Levin 							virtio_pci__msix_enabled(vpci),
881382aba0SSasha Levin 							&config_offset);
8936f5dc91SSasha Levin 	if (type == VIRTIO_PCI_O_MSIX) {
9036f5dc91SSasha Levin 		switch (offset) {
9136f5dc91SSasha Levin 		case VIRTIO_MSI_CONFIG_VECTOR:
9236f5dc91SSasha Levin 			ioport__write16(data, vpci->config_vector);
9336f5dc91SSasha Levin 			break;
9436f5dc91SSasha Levin 		case VIRTIO_MSI_QUEUE_VECTOR:
9536f5dc91SSasha Levin 			ioport__write16(data, vpci->vq_vector[vpci->queue_selector]);
9636f5dc91SSasha Levin 			break;
9736f5dc91SSasha Levin 		};
9836f5dc91SSasha Levin 
9936f5dc91SSasha Levin 		return true;
10036f5dc91SSasha Levin 	} else if (type == VIRTIO_PCI_O_CONFIG) {
10136f5dc91SSasha Levin 		u8 cfg;
10236f5dc91SSasha Levin 
103c5ae742bSSasha Levin 		cfg = vdev->ops->get_config(kvm, vpci->dev)[config_offset];
10436f5dc91SSasha Levin 		ioport__write8(data, cfg);
10536f5dc91SSasha Levin 		return true;
10636f5dc91SSasha Levin 	}
10736f5dc91SSasha Levin 
10836f5dc91SSasha Levin 	return false;
10936f5dc91SSasha Levin }
11036f5dc91SSasha Levin 
11136f5dc91SSasha Levin static bool virtio_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
11236f5dc91SSasha Levin {
11336f5dc91SSasha Levin 	unsigned long offset;
11436f5dc91SSasha Levin 	bool ret = true;
11502eca50cSAsias He 	struct virtio_device *vdev;
11636f5dc91SSasha Levin 	struct virtio_pci *vpci;
11736f5dc91SSasha Levin 	u32 val;
11836f5dc91SSasha Levin 
11902eca50cSAsias He 	vdev = ioport->priv;
12002eca50cSAsias He 	vpci = vdev->virtio;
121*a463650cSWill Deacon 	offset = port - vpci->port_addr;
12236f5dc91SSasha Levin 
12336f5dc91SSasha Levin 	switch (offset) {
12436f5dc91SSasha Levin 	case VIRTIO_PCI_HOST_FEATURES:
12502eca50cSAsias He 		val = vdev->ops->get_host_features(kvm, vpci->dev);
12636f5dc91SSasha Levin 		ioport__write32(data, val);
12736f5dc91SSasha Levin 		break;
12836f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_PFN:
12902eca50cSAsias He 		val = vdev->ops->get_pfn_vq(kvm, vpci->dev, vpci->queue_selector);
13036f5dc91SSasha Levin 		ioport__write32(data, val);
13136f5dc91SSasha Levin 		break;
13236f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_NUM:
13302eca50cSAsias He 		val = vdev->ops->get_size_vq(kvm, vpci->dev, vpci->queue_selector);
134657ee18bSMatt Evans 		ioport__write16(data, val);
13536f5dc91SSasha Levin 		break;
13636f5dc91SSasha Levin 	case VIRTIO_PCI_STATUS:
13736f5dc91SSasha Levin 		ioport__write8(data, vpci->status);
13836f5dc91SSasha Levin 		break;
13936f5dc91SSasha Levin 	case VIRTIO_PCI_ISR:
14036f5dc91SSasha Levin 		ioport__write8(data, vpci->isr);
14136f5dc91SSasha Levin 		kvm__irq_line(kvm, vpci->pci_hdr.irq_line, VIRTIO_IRQ_LOW);
14236f5dc91SSasha Levin 		vpci->isr = VIRTIO_IRQ_LOW;
14336f5dc91SSasha Levin 		break;
14436f5dc91SSasha Levin 	default:
14502eca50cSAsias He 		ret = virtio_pci__specific_io_in(kvm, vdev, port, data, size, offset);
14636f5dc91SSasha Levin 		break;
14736f5dc91SSasha Levin 	};
14836f5dc91SSasha Levin 
14936f5dc91SSasha Levin 	return ret;
15036f5dc91SSasha Levin }
15136f5dc91SSasha Levin 
15202eca50cSAsias He static bool virtio_pci__specific_io_out(struct kvm *kvm, struct virtio_device *vdev, u16 port,
15336f5dc91SSasha Levin 					void *data, int size, int offset)
15436f5dc91SSasha Levin {
15502eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
15636f5dc91SSasha Levin 	u32 config_offset, gsi, vec;
15706f48103SSasha Levin 	int type = virtio__get_dev_specific_field(offset - 20, virtio_pci__msix_enabled(vpci),
1581382aba0SSasha Levin 							&config_offset);
15936f5dc91SSasha Levin 	if (type == VIRTIO_PCI_O_MSIX) {
16036f5dc91SSasha Levin 		switch (offset) {
16136f5dc91SSasha Levin 		case VIRTIO_MSI_CONFIG_VECTOR:
16236f5dc91SSasha Levin 			vec = vpci->config_vector = ioport__read16(data);
163f8327b05SSasha Levin 			if (vec == VIRTIO_MSI_NO_VECTOR)
164f8327b05SSasha Levin 				break;
16536f5dc91SSasha Levin 
1661de74957SSasha Levin 			gsi = irq__add_msix_route(kvm, &vpci->msix_table[vec].msg);
16736f5dc91SSasha Levin 
16836f5dc91SSasha Levin 			vpci->config_gsi = gsi;
16936f5dc91SSasha Levin 			break;
1703a60be06SSasha Levin 		case VIRTIO_MSI_QUEUE_VECTOR:
17136f5dc91SSasha Levin 			vec = vpci->vq_vector[vpci->queue_selector] = ioport__read16(data);
17236f5dc91SSasha Levin 
173f8327b05SSasha Levin 			if (vec == VIRTIO_MSI_NO_VECTOR)
174f8327b05SSasha Levin 				break;
175f8327b05SSasha Levin 
1761de74957SSasha Levin 			gsi = irq__add_msix_route(kvm, &vpci->msix_table[vec].msg);
17736f5dc91SSasha Levin 			vpci->gsis[vpci->queue_selector] = gsi;
17802eca50cSAsias He 			if (vdev->ops->notify_vq_gsi)
17902eca50cSAsias He 				vdev->ops->notify_vq_gsi(kvm, vpci->dev,
180263b80e8SSasha Levin 							vpci->queue_selector, gsi);
18136f5dc91SSasha Levin 			break;
18236f5dc91SSasha Levin 		};
18336f5dc91SSasha Levin 
18436f5dc91SSasha Levin 		return true;
18536f5dc91SSasha Levin 	} else if (type == VIRTIO_PCI_O_CONFIG) {
186c5ae742bSSasha Levin 		vdev->ops->get_config(kvm, vpci->dev)[config_offset] = *(u8 *)data;
18736f5dc91SSasha Levin 
18836f5dc91SSasha Levin 		return true;
18936f5dc91SSasha Levin 	}
19036f5dc91SSasha Levin 
19136f5dc91SSasha Levin 	return false;
19236f5dc91SSasha Levin }
19336f5dc91SSasha Levin 
19436f5dc91SSasha Levin static bool virtio_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
19536f5dc91SSasha Levin {
19636f5dc91SSasha Levin 	unsigned long offset;
19736f5dc91SSasha Levin 	bool ret = true;
19802eca50cSAsias He 	struct virtio_device *vdev;
19936f5dc91SSasha Levin 	struct virtio_pci *vpci;
20036f5dc91SSasha Levin 	u32 val;
20136f5dc91SSasha Levin 
20202eca50cSAsias He 	vdev = ioport->priv;
20302eca50cSAsias He 	vpci = vdev->virtio;
204*a463650cSWill Deacon 	offset = port - vpci->port_addr;
20536f5dc91SSasha Levin 
20636f5dc91SSasha Levin 	switch (offset) {
20736f5dc91SSasha Levin 	case VIRTIO_PCI_GUEST_FEATURES:
20836f5dc91SSasha Levin 		val = ioport__read32(data);
20902eca50cSAsias He 		vdev->ops->set_guest_features(kvm, vpci->dev, val);
21036f5dc91SSasha Levin 		break;
21136f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_PFN:
21236f5dc91SSasha Levin 		val = ioport__read32(data);
21302eca50cSAsias He 		virtio_pci__init_ioeventfd(kvm, vdev, vpci->queue_selector);
214c59ba304SWill Deacon 		vdev->ops->init_vq(kvm, vpci->dev, vpci->queue_selector,
215c59ba304SWill Deacon 				   1 << VIRTIO_PCI_QUEUE_ADDR_SHIFT,
216c59ba304SWill Deacon 				   VIRTIO_PCI_VRING_ALIGN, val);
21736f5dc91SSasha Levin 		break;
21836f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_SEL:
21936f5dc91SSasha Levin 		vpci->queue_selector = ioport__read16(data);
22036f5dc91SSasha Levin 		break;
22136f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_NOTIFY:
22236f5dc91SSasha Levin 		val = ioport__read16(data);
22302eca50cSAsias He 		vdev->ops->notify_vq(kvm, vpci->dev, val);
22436f5dc91SSasha Levin 		break;
22536f5dc91SSasha Levin 	case VIRTIO_PCI_STATUS:
22636f5dc91SSasha Levin 		vpci->status = ioport__read8(data);
22704b53c16SSasha Levin 		if (vdev->ops->notify_status)
22804b53c16SSasha Levin 			vdev->ops->notify_status(kvm, vpci->dev, vpci->status);
22936f5dc91SSasha Levin 		break;
23036f5dc91SSasha Levin 	default:
23102eca50cSAsias He 		ret = virtio_pci__specific_io_out(kvm, vdev, port, data, size, offset);
23236f5dc91SSasha Levin 		break;
23336f5dc91SSasha Levin 	};
23436f5dc91SSasha Levin 
23536f5dc91SSasha Levin 	return ret;
23636f5dc91SSasha Levin }
23736f5dc91SSasha Levin 
23836f5dc91SSasha Levin static struct ioport_operations virtio_pci__io_ops = {
23936f5dc91SSasha Levin 	.io_in	= virtio_pci__io_in,
24036f5dc91SSasha Levin 	.io_out	= virtio_pci__io_out,
24136f5dc91SSasha Levin };
24236f5dc91SSasha Levin 
243*a463650cSWill Deacon static void virtio_pci__msix_mmio_callback(u64 addr, u8 *data, u32 len,
244*a463650cSWill Deacon 					   u8 is_write, void *ptr)
24536f5dc91SSasha Levin {
24636f5dc91SSasha Levin 	struct virtio_pci *vpci = ptr;
2479c26dab4SSasha Levin 	void *table;
2489c26dab4SSasha Levin 	u32 offset;
24936f5dc91SSasha Levin 
2509c26dab4SSasha Levin 	if (addr > vpci->msix_io_block + PCI_IO_SIZE) {
2519c26dab4SSasha Levin 		table	= &vpci->msix_pba;
2529c26dab4SSasha Levin 		offset	= vpci->msix_io_block + PCI_IO_SIZE;
2539c26dab4SSasha Levin 	} else {
2549c26dab4SSasha Levin 		table	= &vpci->msix_table;
2559c26dab4SSasha Levin 		offset	= vpci->msix_io_block;
25636f5dc91SSasha Levin 	}
25736f5dc91SSasha Levin 
25806f48103SSasha Levin 	if (is_write)
2599c26dab4SSasha Levin 		memcpy(table + addr - offset, data, len);
26006f48103SSasha Levin 	else
2619c26dab4SSasha Levin 		memcpy(data, table + addr - offset, len);
26206f48103SSasha Levin }
26306f48103SSasha Levin 
26443c81c74SSasha Levin static void virtio_pci__signal_msi(struct kvm *kvm, struct virtio_pci *vpci, int vec)
26543c81c74SSasha Levin {
26643c81c74SSasha Levin 	struct kvm_msi msi = {
26743c81c74SSasha Levin 		.address_lo = vpci->msix_table[vec].msg.address_lo,
26843c81c74SSasha Levin 		.address_hi = vpci->msix_table[vec].msg.address_hi,
26943c81c74SSasha Levin 		.data = vpci->msix_table[vec].msg.data,
27043c81c74SSasha Levin 	};
27143c81c74SSasha Levin 
27243c81c74SSasha Levin 	ioctl(kvm->vm_fd, KVM_SIGNAL_MSI, &msi);
27343c81c74SSasha Levin }
27443c81c74SSasha Levin 
27502eca50cSAsias He int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
27636f5dc91SSasha Levin {
27702eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
27806f48103SSasha Levin 	int tbl = vpci->vq_vector[vq];
27936f5dc91SSasha Levin 
280f8327b05SSasha Levin 	if (virtio_pci__msix_enabled(vpci) && tbl != VIRTIO_MSI_NO_VECTOR) {
281aa73be70SMatt Evans 		if (vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_MASKALL) ||
282aa73be70SMatt Evans 		    vpci->msix_table[tbl].ctrl & cpu_to_le16(PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
28306f48103SSasha Levin 
28406f48103SSasha Levin 			vpci->msix_pba |= 1 << tbl;
28506f48103SSasha Levin 			return 0;
28606f48103SSasha Levin 		}
28706f48103SSasha Levin 
28843c81c74SSasha Levin 		if (vpci->features & VIRTIO_PCI_F_SIGNAL_MSI)
28943c81c74SSasha Levin 			virtio_pci__signal_msi(kvm, vpci, vpci->vq_vector[vq]);
29043c81c74SSasha Levin 		else
29106f48103SSasha Levin 			kvm__irq_trigger(kvm, vpci->gsis[vq]);
29206f48103SSasha Levin 	} else {
293a36eca7bSSasha Levin 		vpci->isr = VIRTIO_IRQ_HIGH;
29406f48103SSasha Levin 		kvm__irq_trigger(kvm, vpci->pci_hdr.irq_line);
29506f48103SSasha Levin 	}
29636f5dc91SSasha Levin 	return 0;
29736f5dc91SSasha Levin }
29836f5dc91SSasha Levin 
29902eca50cSAsias He int virtio_pci__signal_config(struct kvm *kvm, struct virtio_device *vdev)
30036f5dc91SSasha Levin {
30102eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
30206f48103SSasha Levin 	int tbl = vpci->config_vector;
30306f48103SSasha Levin 
304f8327b05SSasha Levin 	if (virtio_pci__msix_enabled(vpci) && tbl != VIRTIO_MSI_NO_VECTOR) {
305aa73be70SMatt Evans 		if (vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_MASKALL) ||
306aa73be70SMatt Evans 		    vpci->msix_table[tbl].ctrl & cpu_to_le16(PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
30706f48103SSasha Levin 
30806f48103SSasha Levin 			vpci->msix_pba |= 1 << tbl;
30906f48103SSasha Levin 			return 0;
31006f48103SSasha Levin 		}
31106f48103SSasha Levin 
31243c81c74SSasha Levin 		if (vpci->features & VIRTIO_PCI_F_SIGNAL_MSI)
313f8327b05SSasha Levin 			virtio_pci__signal_msi(kvm, vpci, tbl);
31443c81c74SSasha Levin 		else
31506f48103SSasha Levin 			kvm__irq_trigger(kvm, vpci->config_gsi);
31606f48103SSasha Levin 	} else {
31706f48103SSasha Levin 		vpci->isr = VIRTIO_PCI_ISR_CONFIG;
31806f48103SSasha Levin 		kvm__irq_trigger(kvm, vpci->pci_hdr.irq_line);
31906f48103SSasha Levin 	}
32036f5dc91SSasha Levin 
32136f5dc91SSasha Levin 	return 0;
32236f5dc91SSasha Levin }
32336f5dc91SSasha Levin 
324*a463650cSWill Deacon static void virtio_pci__io_mmio_callback(u64 addr, u8 *data, u32 len,
325*a463650cSWill Deacon 					 u8 is_write, void *ptr)
326*a463650cSWill Deacon {
327*a463650cSWill Deacon 	struct virtio_pci *vpci = ptr;
328*a463650cSWill Deacon 	int direction = is_write ? KVM_EXIT_IO_OUT : KVM_EXIT_IO_IN;
329*a463650cSWill Deacon 	u16 port = vpci->port_addr + (addr & (IOPORT_SIZE - 1));
330*a463650cSWill Deacon 
331*a463650cSWill Deacon 	kvm__emulate_io(vpci->kvm, port, data, direction, len, 1);
332*a463650cSWill Deacon }
333*a463650cSWill Deacon 
33402eca50cSAsias He int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
335507e02d8SAsias He 		     int device_id, int subsys_id, int class)
33636f5dc91SSasha Levin {
33702eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
33821ff329dSWill Deacon 	u8 pin, line;
3397af40b91SSasha Levin 	int r;
34036f5dc91SSasha Levin 
341*a463650cSWill Deacon 	vpci->kvm = kvm;
34236f5dc91SSasha Levin 	vpci->dev = dev;
34336f5dc91SSasha Levin 
3444346fd8fSSasha Levin 	r = ioport__register(kvm, IOPORT_EMPTY, &virtio_pci__io_ops, IOPORT_SIZE, vdev);
3457af40b91SSasha Levin 	if (r < 0)
3467af40b91SSasha Levin 		return r;
347*a463650cSWill Deacon 	vpci->port_addr = (u16)r;
3487af40b91SSasha Levin 
349*a463650cSWill Deacon 	vpci->mmio_addr = pci_get_io_space_block(IOPORT_SIZE);
350*a463650cSWill Deacon 	r = kvm__register_mmio(kvm, vpci->mmio_addr, IOPORT_SIZE, false,
351*a463650cSWill Deacon 			       virtio_pci__io_mmio_callback, vpci);
352495fbd4eSSasha Levin 	if (r < 0)
353495fbd4eSSasha Levin 		goto free_ioport;
35436f5dc91SSasha Levin 
355*a463650cSWill Deacon 	vpci->msix_io_block = pci_get_io_space_block(PCI_IO_SIZE * 2);
356*a463650cSWill Deacon 	r = kvm__register_mmio(kvm, vpci->msix_io_block, PCI_IO_SIZE * 2, false,
357*a463650cSWill Deacon 			       virtio_pci__msix_mmio_callback, vpci);
358*a463650cSWill Deacon 	if (r < 0)
359*a463650cSWill Deacon 		goto free_mmio;
360*a463650cSWill Deacon 
36136f5dc91SSasha Levin 	vpci->pci_hdr = (struct pci_device_header) {
362aa73be70SMatt Evans 		.vendor_id		= cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
363aa73be70SMatt Evans 		.device_id		= cpu_to_le16(device_id),
36436f5dc91SSasha Levin 		.header_type		= PCI_HEADER_TYPE_NORMAL,
36536f5dc91SSasha Levin 		.revision_id		= 0,
366aa73be70SMatt Evans 		.class[0]		= class & 0xff,
367aa73be70SMatt Evans 		.class[1]		= (class >> 8) & 0xff,
368aa73be70SMatt Evans 		.class[2]		= (class >> 16) & 0xff,
369aa73be70SMatt Evans 		.subsys_vendor_id	= cpu_to_le16(PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET),
370aa73be70SMatt Evans 		.subsys_id		= cpu_to_le16(subsys_id),
371*a463650cSWill Deacon 		.bar[0]			= cpu_to_le32(vpci->mmio_addr
372*a463650cSWill Deacon 							| PCI_BASE_ADDRESS_SPACE_MEMORY),
373*a463650cSWill Deacon 		.bar[1]			= cpu_to_le32(vpci->port_addr
3749c26dab4SSasha Levin 							| PCI_BASE_ADDRESS_SPACE_IO),
375*a463650cSWill Deacon 		.bar[2]			= cpu_to_le32(vpci->msix_io_block
376b4dab816SSasha Levin 							| PCI_BASE_ADDRESS_SPACE_MEMORY),
377aa73be70SMatt Evans 		.status			= cpu_to_le16(PCI_STATUS_CAP_LIST),
37836f5dc91SSasha Levin 		.capabilities		= (void *)&vpci->pci_hdr.msix - (void *)&vpci->pci_hdr,
3796b868987SMatt Evans 		.bar_size[0]		= IOPORT_SIZE,
380*a463650cSWill Deacon 		.bar_size[1]		= IOPORT_SIZE,
381*a463650cSWill Deacon 		.bar_size[2]		= PCI_IO_SIZE * 2,
38236f5dc91SSasha Levin 	};
38336f5dc91SSasha Levin 
38421ff329dSWill Deacon 	vpci->dev_hdr = (struct device_header) {
38521ff329dSWill Deacon 		.bus_type		= DEVICE_BUS_PCI,
38621ff329dSWill Deacon 		.data			= &vpci->pci_hdr,
38721ff329dSWill Deacon 	};
38821ff329dSWill Deacon 
38936f5dc91SSasha Levin 	vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX;
39036f5dc91SSasha Levin 	vpci->pci_hdr.msix.next = 0;
39114bba8a0SAsias He 	/*
39214bba8a0SAsias He 	 * We at most have VIRTIO_PCI_MAX_VQ entries for virt queue,
39314bba8a0SAsias He 	 * VIRTIO_PCI_MAX_CONFIG entries for config.
39414bba8a0SAsias He 	 *
39514bba8a0SAsias He 	 * To quote the PCI spec:
39614bba8a0SAsias He 	 *
39714bba8a0SAsias He 	 * System software reads this field to determine the
39814bba8a0SAsias He 	 * MSI-X Table Size N, which is encoded as N-1.
39914bba8a0SAsias He 	 * For example, a returned value of "00000000011"
40014bba8a0SAsias He 	 * indicates a table size of 4.
40114bba8a0SAsias He 	 */
402aa73be70SMatt Evans 	vpci->pci_hdr.msix.ctrl = cpu_to_le16(VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG - 1);
40306f48103SSasha Levin 
404*a463650cSWill Deacon 	/* Both table and PBA are mapped to the same BAR (2) */
405*a463650cSWill Deacon 	vpci->pci_hdr.msix.table_offset = cpu_to_le32(2);
406*a463650cSWill Deacon 	vpci->pci_hdr.msix.pba_offset = cpu_to_le32(2 | PCI_IO_SIZE);
40736f5dc91SSasha Levin 	vpci->config_vector = 0;
40836f5dc91SSasha Levin 
40921ff329dSWill Deacon 	r = irq__register_device(subsys_id, &pin, &line);
410495fbd4eSSasha Levin 	if (r < 0)
411*a463650cSWill Deacon 		goto free_msix_mmio;
41236f5dc91SSasha Levin 
41343c81c74SSasha Levin 	if (kvm__supports_extension(kvm, KVM_CAP_SIGNAL_MSI))
41443c81c74SSasha Levin 		vpci->features |= VIRTIO_PCI_F_SIGNAL_MSI;
41543c81c74SSasha Levin 
41636f5dc91SSasha Levin 	vpci->pci_hdr.irq_pin	= pin;
41736f5dc91SSasha Levin 	vpci->pci_hdr.irq_line	= line;
41821ff329dSWill Deacon 	r = device__register(&vpci->dev_hdr);
419495fbd4eSSasha Levin 	if (r < 0)
420*a463650cSWill Deacon 		goto free_msix_mmio;
421495fbd4eSSasha Levin 
422495fbd4eSSasha Levin 	return 0;
423495fbd4eSSasha Levin 
424*a463650cSWill Deacon free_msix_mmio:
425495fbd4eSSasha Levin 	kvm__deregister_mmio(kvm, vpci->msix_io_block);
426*a463650cSWill Deacon free_mmio:
427*a463650cSWill Deacon 	kvm__deregister_mmio(kvm, vpci->mmio_addr);
428495fbd4eSSasha Levin free_ioport:
429*a463650cSWill Deacon 	ioport__unregister(kvm, vpci->port_addr);
430495fbd4eSSasha Levin 	return r;
431495fbd4eSSasha Levin }
432495fbd4eSSasha Levin 
43302eca50cSAsias He int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev)
434495fbd4eSSasha Levin {
43502eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
436495fbd4eSSasha Levin 	int i;
437495fbd4eSSasha Levin 
438*a463650cSWill Deacon 	kvm__deregister_mmio(kvm, vpci->mmio_addr);
439495fbd4eSSasha Levin 	kvm__deregister_mmio(kvm, vpci->msix_io_block);
440*a463650cSWill Deacon 	ioport__unregister(kvm, vpci->port_addr);
441495fbd4eSSasha Levin 
442*a463650cSWill Deacon 	for (i = 0; i < VIRTIO_PCI_MAX_VQ; i++) {
443*a463650cSWill Deacon 		ioeventfd__del_event(vpci->port_addr + VIRTIO_PCI_QUEUE_NOTIFY, i);
444*a463650cSWill Deacon 		ioeventfd__del_event(vpci->mmio_addr + VIRTIO_PCI_QUEUE_NOTIFY, i);
445*a463650cSWill Deacon 	}
44636f5dc91SSasha Levin 
44736f5dc91SSasha Levin 	return 0;
44836f5dc91SSasha Levin }
449