xref: /kvmtool/virtio/pci.c (revision 04b53c1615e8dc2bded7a445ef7e9abae6f92afc)
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;
27ea6eeb1cSSasha Levin 	int r;
281599d724SSasha Levin 
291599d724SSasha Levin 	vpci->ioeventfds[vq] = (struct virtio_pci_ioevent_param) {
3002eca50cSAsias He 		.vdev		= vdev,
311599d724SSasha Levin 		.vq		= vq,
321599d724SSasha Levin 	};
331599d724SSasha Levin 
341599d724SSasha Levin 	ioevent = (struct ioevent) {
351599d724SSasha Levin 		.io_addr	= vpci->base_addr + VIRTIO_PCI_QUEUE_NOTIFY,
361599d724SSasha Levin 		.io_len		= sizeof(u16),
371599d724SSasha Levin 		.fn		= virtio_pci__ioevent_callback,
381599d724SSasha Levin 		.fn_ptr		= &vpci->ioeventfds[vq],
391599d724SSasha Levin 		.datamatch	= vq,
401599d724SSasha Levin 		.fn_kvm		= kvm,
411599d724SSasha Levin 		.fd		= eventfd(0, 0),
421599d724SSasha Levin 	};
431599d724SSasha Levin 
44627d6874SAsias He 	if (vdev->use_vhost)
45627d6874SAsias He 		/*
46627d6874SAsias He 		 * Vhost will poll the eventfd in host kernel side,
47627d6874SAsias He 		 * no need to poll in userspace.
48627d6874SAsias He 		 */
49627d6874SAsias He 		r = ioeventfd__add_event(&ioevent, true, false);
50627d6874SAsias He 	else
51627d6874SAsias He 		/* Need to poll in userspace. */
52627d6874SAsias He 		r = ioeventfd__add_event(&ioevent, true, true);
53ea6eeb1cSSasha Levin 	if (r)
54ea6eeb1cSSasha Levin 		return r;
551599d724SSasha Levin 
5602eca50cSAsias He 	if (vdev->ops->notify_vq_eventfd)
5702eca50cSAsias He 		vdev->ops->notify_vq_eventfd(kvm, vpci->dev, vq, ioevent.fd);
58263b80e8SSasha Levin 
591599d724SSasha Levin 	return 0;
601599d724SSasha Levin }
611599d724SSasha Levin 
6206f48103SSasha Levin static inline bool virtio_pci__msix_enabled(struct virtio_pci *vpci)
6306f48103SSasha Levin {
64aa73be70SMatt Evans 	return vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE);
6506f48103SSasha Levin }
6606f48103SSasha Levin 
6702eca50cSAsias He static bool virtio_pci__specific_io_in(struct kvm *kvm, struct virtio_device *vdev, u16 port,
6836f5dc91SSasha Levin 					void *data, int size, int offset)
6936f5dc91SSasha Levin {
7036f5dc91SSasha Levin 	u32 config_offset;
7102eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
7206f48103SSasha Levin 	int type = virtio__get_dev_specific_field(offset - 20,
7306f48103SSasha Levin 							virtio_pci__msix_enabled(vpci),
741382aba0SSasha Levin 							&config_offset);
7536f5dc91SSasha Levin 	if (type == VIRTIO_PCI_O_MSIX) {
7636f5dc91SSasha Levin 		switch (offset) {
7736f5dc91SSasha Levin 		case VIRTIO_MSI_CONFIG_VECTOR:
7836f5dc91SSasha Levin 			ioport__write16(data, vpci->config_vector);
7936f5dc91SSasha Levin 			break;
8036f5dc91SSasha Levin 		case VIRTIO_MSI_QUEUE_VECTOR:
8136f5dc91SSasha Levin 			ioport__write16(data, vpci->vq_vector[vpci->queue_selector]);
8236f5dc91SSasha Levin 			break;
8336f5dc91SSasha Levin 		};
8436f5dc91SSasha Levin 
8536f5dc91SSasha Levin 		return true;
8636f5dc91SSasha Levin 	} else if (type == VIRTIO_PCI_O_CONFIG) {
8736f5dc91SSasha Levin 		u8 cfg;
8836f5dc91SSasha Levin 
89c5ae742bSSasha Levin 		cfg = vdev->ops->get_config(kvm, vpci->dev)[config_offset];
9036f5dc91SSasha Levin 		ioport__write8(data, cfg);
9136f5dc91SSasha Levin 		return true;
9236f5dc91SSasha Levin 	}
9336f5dc91SSasha Levin 
9436f5dc91SSasha Levin 	return false;
9536f5dc91SSasha Levin }
9636f5dc91SSasha Levin 
9736f5dc91SSasha Levin static bool virtio_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
9836f5dc91SSasha Levin {
9936f5dc91SSasha Levin 	unsigned long offset;
10036f5dc91SSasha Levin 	bool ret = true;
10102eca50cSAsias He 	struct virtio_device *vdev;
10236f5dc91SSasha Levin 	struct virtio_pci *vpci;
10336f5dc91SSasha Levin 	u32 val;
10436f5dc91SSasha Levin 
10502eca50cSAsias He 	vdev = ioport->priv;
10602eca50cSAsias He 	vpci = vdev->virtio;
10736f5dc91SSasha Levin 	offset = port - vpci->base_addr;
10836f5dc91SSasha Levin 
10936f5dc91SSasha Levin 	switch (offset) {
11036f5dc91SSasha Levin 	case VIRTIO_PCI_HOST_FEATURES:
11102eca50cSAsias He 		val = vdev->ops->get_host_features(kvm, vpci->dev);
11236f5dc91SSasha Levin 		ioport__write32(data, val);
11336f5dc91SSasha Levin 		break;
11436f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_PFN:
11502eca50cSAsias He 		val = vdev->ops->get_pfn_vq(kvm, vpci->dev, vpci->queue_selector);
11636f5dc91SSasha Levin 		ioport__write32(data, val);
11736f5dc91SSasha Levin 		break;
11836f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_NUM:
11902eca50cSAsias He 		val = vdev->ops->get_size_vq(kvm, vpci->dev, vpci->queue_selector);
120657ee18bSMatt Evans 		ioport__write16(data, val);
12136f5dc91SSasha Levin 		break;
12236f5dc91SSasha Levin 	case VIRTIO_PCI_STATUS:
12336f5dc91SSasha Levin 		ioport__write8(data, vpci->status);
12436f5dc91SSasha Levin 		break;
12536f5dc91SSasha Levin 	case VIRTIO_PCI_ISR:
12636f5dc91SSasha Levin 		ioport__write8(data, vpci->isr);
12736f5dc91SSasha Levin 		kvm__irq_line(kvm, vpci->pci_hdr.irq_line, VIRTIO_IRQ_LOW);
12836f5dc91SSasha Levin 		vpci->isr = VIRTIO_IRQ_LOW;
12936f5dc91SSasha Levin 		break;
13036f5dc91SSasha Levin 	default:
13102eca50cSAsias He 		ret = virtio_pci__specific_io_in(kvm, vdev, port, data, size, offset);
13236f5dc91SSasha Levin 		break;
13336f5dc91SSasha Levin 	};
13436f5dc91SSasha Levin 
13536f5dc91SSasha Levin 	return ret;
13636f5dc91SSasha Levin }
13736f5dc91SSasha Levin 
13802eca50cSAsias He static bool virtio_pci__specific_io_out(struct kvm *kvm, struct virtio_device *vdev, u16 port,
13936f5dc91SSasha Levin 					void *data, int size, int offset)
14036f5dc91SSasha Levin {
14102eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
14236f5dc91SSasha Levin 	u32 config_offset, gsi, vec;
14306f48103SSasha Levin 	int type = virtio__get_dev_specific_field(offset - 20, virtio_pci__msix_enabled(vpci),
1441382aba0SSasha Levin 							&config_offset);
14536f5dc91SSasha Levin 	if (type == VIRTIO_PCI_O_MSIX) {
14636f5dc91SSasha Levin 		switch (offset) {
14736f5dc91SSasha Levin 		case VIRTIO_MSI_CONFIG_VECTOR:
14836f5dc91SSasha Levin 			vec = vpci->config_vector = ioport__read16(data);
149f8327b05SSasha Levin 			if (vec == VIRTIO_MSI_NO_VECTOR)
150f8327b05SSasha Levin 				break;
15136f5dc91SSasha Levin 
1521de74957SSasha Levin 			gsi = irq__add_msix_route(kvm, &vpci->msix_table[vec].msg);
15336f5dc91SSasha Levin 
15436f5dc91SSasha Levin 			vpci->config_gsi = gsi;
15536f5dc91SSasha Levin 			break;
1563a60be06SSasha Levin 		case VIRTIO_MSI_QUEUE_VECTOR:
15736f5dc91SSasha Levin 			vec = vpci->vq_vector[vpci->queue_selector] = ioport__read16(data);
15836f5dc91SSasha Levin 
159f8327b05SSasha Levin 			if (vec == VIRTIO_MSI_NO_VECTOR)
160f8327b05SSasha Levin 				break;
161f8327b05SSasha Levin 
1621de74957SSasha Levin 			gsi = irq__add_msix_route(kvm, &vpci->msix_table[vec].msg);
16336f5dc91SSasha Levin 			vpci->gsis[vpci->queue_selector] = gsi;
16402eca50cSAsias He 			if (vdev->ops->notify_vq_gsi)
16502eca50cSAsias He 				vdev->ops->notify_vq_gsi(kvm, vpci->dev,
166263b80e8SSasha Levin 							vpci->queue_selector, gsi);
16736f5dc91SSasha Levin 			break;
16836f5dc91SSasha Levin 		};
16936f5dc91SSasha Levin 
17036f5dc91SSasha Levin 		return true;
17136f5dc91SSasha Levin 	} else if (type == VIRTIO_PCI_O_CONFIG) {
172c5ae742bSSasha Levin 		vdev->ops->get_config(kvm, vpci->dev)[config_offset] = *(u8 *)data;
17336f5dc91SSasha Levin 
17436f5dc91SSasha Levin 		return true;
17536f5dc91SSasha Levin 	}
17636f5dc91SSasha Levin 
17736f5dc91SSasha Levin 	return false;
17836f5dc91SSasha Levin }
17936f5dc91SSasha Levin 
18036f5dc91SSasha Levin static bool virtio_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
18136f5dc91SSasha Levin {
18236f5dc91SSasha Levin 	unsigned long offset;
18336f5dc91SSasha Levin 	bool ret = true;
18402eca50cSAsias He 	struct virtio_device *vdev;
18536f5dc91SSasha Levin 	struct virtio_pci *vpci;
18636f5dc91SSasha Levin 	u32 val;
18736f5dc91SSasha Levin 
18802eca50cSAsias He 	vdev = ioport->priv;
18902eca50cSAsias He 	vpci = vdev->virtio;
19036f5dc91SSasha Levin 	offset = port - vpci->base_addr;
19136f5dc91SSasha Levin 
19236f5dc91SSasha Levin 	switch (offset) {
19336f5dc91SSasha Levin 	case VIRTIO_PCI_GUEST_FEATURES:
19436f5dc91SSasha Levin 		val = ioport__read32(data);
19502eca50cSAsias He 		vdev->ops->set_guest_features(kvm, vpci->dev, val);
19636f5dc91SSasha Levin 		break;
19736f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_PFN:
19836f5dc91SSasha Levin 		val = ioport__read32(data);
19902eca50cSAsias He 		virtio_pci__init_ioeventfd(kvm, vdev, vpci->queue_selector);
200c59ba304SWill Deacon 		vdev->ops->init_vq(kvm, vpci->dev, vpci->queue_selector,
201c59ba304SWill Deacon 				   1 << VIRTIO_PCI_QUEUE_ADDR_SHIFT,
202c59ba304SWill Deacon 				   VIRTIO_PCI_VRING_ALIGN, val);
20336f5dc91SSasha Levin 		break;
20436f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_SEL:
20536f5dc91SSasha Levin 		vpci->queue_selector = ioport__read16(data);
20636f5dc91SSasha Levin 		break;
20736f5dc91SSasha Levin 	case VIRTIO_PCI_QUEUE_NOTIFY:
20836f5dc91SSasha Levin 		val = ioport__read16(data);
20902eca50cSAsias He 		vdev->ops->notify_vq(kvm, vpci->dev, val);
21036f5dc91SSasha Levin 		break;
21136f5dc91SSasha Levin 	case VIRTIO_PCI_STATUS:
21236f5dc91SSasha Levin 		vpci->status = ioport__read8(data);
213*04b53c16SSasha Levin 		if (vdev->ops->notify_status)
214*04b53c16SSasha Levin 			vdev->ops->notify_status(kvm, vpci->dev, vpci->status);
21536f5dc91SSasha Levin 		break;
21636f5dc91SSasha Levin 	default:
21702eca50cSAsias He 		ret = virtio_pci__specific_io_out(kvm, vdev, port, data, size, offset);
21836f5dc91SSasha Levin 		break;
21936f5dc91SSasha Levin 	};
22036f5dc91SSasha Levin 
22136f5dc91SSasha Levin 	return ret;
22236f5dc91SSasha Levin }
22336f5dc91SSasha Levin 
22436f5dc91SSasha Levin static struct ioport_operations virtio_pci__io_ops = {
22536f5dc91SSasha Levin 	.io_in	= virtio_pci__io_in,
22636f5dc91SSasha Levin 	.io_out	= virtio_pci__io_out,
22736f5dc91SSasha Levin };
22836f5dc91SSasha Levin 
2299594e883SAsias He static void virtio_pci__mmio_callback(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr)
23036f5dc91SSasha Levin {
23136f5dc91SSasha Levin 	struct virtio_pci *vpci = ptr;
2329c26dab4SSasha Levin 	void *table;
2339c26dab4SSasha Levin 	u32 offset;
23436f5dc91SSasha Levin 
2359c26dab4SSasha Levin 	if (addr > vpci->msix_io_block + PCI_IO_SIZE) {
2369c26dab4SSasha Levin 		table	= &vpci->msix_pba;
2379c26dab4SSasha Levin 		offset	= vpci->msix_io_block + PCI_IO_SIZE;
2389c26dab4SSasha Levin 	} else {
2399c26dab4SSasha Levin 		table	= &vpci->msix_table;
2409c26dab4SSasha Levin 		offset	= vpci->msix_io_block;
24136f5dc91SSasha Levin 	}
24236f5dc91SSasha Levin 
24306f48103SSasha Levin 	if (is_write)
2449c26dab4SSasha Levin 		memcpy(table + addr - offset, data, len);
24506f48103SSasha Levin 	else
2469c26dab4SSasha Levin 		memcpy(data, table + addr - offset, len);
24706f48103SSasha Levin }
24806f48103SSasha Levin 
24943c81c74SSasha Levin static void virtio_pci__signal_msi(struct kvm *kvm, struct virtio_pci *vpci, int vec)
25043c81c74SSasha Levin {
25143c81c74SSasha Levin 	struct kvm_msi msi = {
25243c81c74SSasha Levin 		.address_lo = vpci->msix_table[vec].msg.address_lo,
25343c81c74SSasha Levin 		.address_hi = vpci->msix_table[vec].msg.address_hi,
25443c81c74SSasha Levin 		.data = vpci->msix_table[vec].msg.data,
25543c81c74SSasha Levin 	};
25643c81c74SSasha Levin 
25743c81c74SSasha Levin 	ioctl(kvm->vm_fd, KVM_SIGNAL_MSI, &msi);
25843c81c74SSasha Levin }
25943c81c74SSasha Levin 
26002eca50cSAsias He int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
26136f5dc91SSasha Levin {
26202eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
26306f48103SSasha Levin 	int tbl = vpci->vq_vector[vq];
26436f5dc91SSasha Levin 
265f8327b05SSasha Levin 	if (virtio_pci__msix_enabled(vpci) && tbl != VIRTIO_MSI_NO_VECTOR) {
266aa73be70SMatt Evans 		if (vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_MASKALL) ||
267aa73be70SMatt Evans 		    vpci->msix_table[tbl].ctrl & cpu_to_le16(PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
26806f48103SSasha Levin 
26906f48103SSasha Levin 			vpci->msix_pba |= 1 << tbl;
27006f48103SSasha Levin 			return 0;
27106f48103SSasha Levin 		}
27206f48103SSasha Levin 
27343c81c74SSasha Levin 		if (vpci->features & VIRTIO_PCI_F_SIGNAL_MSI)
27443c81c74SSasha Levin 			virtio_pci__signal_msi(kvm, vpci, vpci->vq_vector[vq]);
27543c81c74SSasha Levin 		else
27606f48103SSasha Levin 			kvm__irq_trigger(kvm, vpci->gsis[vq]);
27706f48103SSasha Levin 	} else {
278a36eca7bSSasha Levin 		vpci->isr = VIRTIO_IRQ_HIGH;
27906f48103SSasha Levin 		kvm__irq_trigger(kvm, vpci->pci_hdr.irq_line);
28006f48103SSasha Levin 	}
28136f5dc91SSasha Levin 	return 0;
28236f5dc91SSasha Levin }
28336f5dc91SSasha Levin 
28402eca50cSAsias He int virtio_pci__signal_config(struct kvm *kvm, struct virtio_device *vdev)
28536f5dc91SSasha Levin {
28602eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
28706f48103SSasha Levin 	int tbl = vpci->config_vector;
28806f48103SSasha Levin 
289f8327b05SSasha Levin 	if (virtio_pci__msix_enabled(vpci) && tbl != VIRTIO_MSI_NO_VECTOR) {
290aa73be70SMatt Evans 		if (vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_MASKALL) ||
291aa73be70SMatt Evans 		    vpci->msix_table[tbl].ctrl & cpu_to_le16(PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
29206f48103SSasha Levin 
29306f48103SSasha Levin 			vpci->msix_pba |= 1 << tbl;
29406f48103SSasha Levin 			return 0;
29506f48103SSasha Levin 		}
29606f48103SSasha Levin 
29743c81c74SSasha Levin 		if (vpci->features & VIRTIO_PCI_F_SIGNAL_MSI)
298f8327b05SSasha Levin 			virtio_pci__signal_msi(kvm, vpci, tbl);
29943c81c74SSasha Levin 		else
30006f48103SSasha Levin 			kvm__irq_trigger(kvm, vpci->config_gsi);
30106f48103SSasha Levin 	} else {
30206f48103SSasha Levin 		vpci->isr = VIRTIO_PCI_ISR_CONFIG;
30306f48103SSasha Levin 		kvm__irq_trigger(kvm, vpci->pci_hdr.irq_line);
30406f48103SSasha Levin 	}
30536f5dc91SSasha Levin 
30636f5dc91SSasha Levin 	return 0;
30736f5dc91SSasha Levin }
30836f5dc91SSasha Levin 
30902eca50cSAsias He int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
310507e02d8SAsias He 		     int device_id, int subsys_id, int class)
31136f5dc91SSasha Levin {
31202eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
31321ff329dSWill Deacon 	u8 pin, line;
3147af40b91SSasha Levin 	int r;
31536f5dc91SSasha Levin 
31636f5dc91SSasha Levin 	vpci->dev = dev;
3179c26dab4SSasha Levin 	vpci->msix_io_block = pci_get_io_space_block(PCI_IO_SIZE * 2);
31836f5dc91SSasha Levin 
3194346fd8fSSasha Levin 	r = ioport__register(kvm, IOPORT_EMPTY, &virtio_pci__io_ops, IOPORT_SIZE, vdev);
3207af40b91SSasha Levin 	if (r < 0)
3217af40b91SSasha Levin 		return r;
3227af40b91SSasha Levin 
3237af40b91SSasha Levin 	vpci->base_addr = (u16)r;
32402eca50cSAsias He 	r = kvm__register_mmio(kvm, vpci->msix_io_block, PCI_IO_SIZE, false,
3259594e883SAsias He 			       virtio_pci__mmio_callback, vpci);
326495fbd4eSSasha Levin 	if (r < 0)
327495fbd4eSSasha Levin 		goto free_ioport;
32836f5dc91SSasha Levin 
32936f5dc91SSasha Levin 	vpci->pci_hdr = (struct pci_device_header) {
330aa73be70SMatt Evans 		.vendor_id		= cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
331aa73be70SMatt Evans 		.device_id		= cpu_to_le16(device_id),
33236f5dc91SSasha Levin 		.header_type		= PCI_HEADER_TYPE_NORMAL,
33336f5dc91SSasha Levin 		.revision_id		= 0,
334aa73be70SMatt Evans 		.class[0]		= class & 0xff,
335aa73be70SMatt Evans 		.class[1]		= (class >> 8) & 0xff,
336aa73be70SMatt Evans 		.class[2]		= (class >> 16) & 0xff,
337aa73be70SMatt Evans 		.subsys_vendor_id	= cpu_to_le16(PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET),
338aa73be70SMatt Evans 		.subsys_id		= cpu_to_le16(subsys_id),
3399c26dab4SSasha Levin 		.bar[0]			= cpu_to_le32(vpci->base_addr
3409c26dab4SSasha Levin 							| PCI_BASE_ADDRESS_SPACE_IO),
341b4dab816SSasha Levin 		.bar[1]			= cpu_to_le32(vpci->msix_io_block
342b4dab816SSasha Levin 							| PCI_BASE_ADDRESS_SPACE_MEMORY),
343aa73be70SMatt Evans 		.status			= cpu_to_le16(PCI_STATUS_CAP_LIST),
34436f5dc91SSasha Levin 		.capabilities		= (void *)&vpci->pci_hdr.msix - (void *)&vpci->pci_hdr,
3456b868987SMatt Evans 		.bar_size[0]		= IOPORT_SIZE,
3466b868987SMatt Evans 		.bar_size[1]		= PCI_IO_SIZE,
3476b868987SMatt Evans 		.bar_size[3]		= PCI_IO_SIZE,
34836f5dc91SSasha Levin 	};
34936f5dc91SSasha Levin 
35021ff329dSWill Deacon 	vpci->dev_hdr = (struct device_header) {
35121ff329dSWill Deacon 		.bus_type		= DEVICE_BUS_PCI,
35221ff329dSWill Deacon 		.data			= &vpci->pci_hdr,
35321ff329dSWill Deacon 	};
35421ff329dSWill Deacon 
35536f5dc91SSasha Levin 	vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX;
35636f5dc91SSasha Levin 	vpci->pci_hdr.msix.next = 0;
35714bba8a0SAsias He 	/*
35814bba8a0SAsias He 	 * We at most have VIRTIO_PCI_MAX_VQ entries for virt queue,
35914bba8a0SAsias He 	 * VIRTIO_PCI_MAX_CONFIG entries for config.
36014bba8a0SAsias He 	 *
36114bba8a0SAsias He 	 * To quote the PCI spec:
36214bba8a0SAsias He 	 *
36314bba8a0SAsias He 	 * System software reads this field to determine the
36414bba8a0SAsias He 	 * MSI-X Table Size N, which is encoded as N-1.
36514bba8a0SAsias He 	 * For example, a returned value of "00000000011"
36614bba8a0SAsias He 	 * indicates a table size of 4.
36714bba8a0SAsias He 	 */
368aa73be70SMatt Evans 	vpci->pci_hdr.msix.ctrl = cpu_to_le16(VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG - 1);
36906f48103SSasha Levin 
37006f48103SSasha Levin 	/*
37106f48103SSasha Levin 	 * Both table and PBA could be mapped on the same BAR, but for now
37206f48103SSasha Levin 	 * we're not in short of BARs
37306f48103SSasha Levin 	 */
374aa73be70SMatt Evans 	vpci->pci_hdr.msix.table_offset = cpu_to_le32(1); /* Use BAR 1 */
3759c26dab4SSasha Levin 	vpci->pci_hdr.msix.pba_offset = cpu_to_le32(1 | PCI_IO_SIZE); /* Use BAR 3 */
37636f5dc91SSasha Levin 	vpci->config_vector = 0;
37736f5dc91SSasha Levin 
37821ff329dSWill Deacon 	r = irq__register_device(subsys_id, &pin, &line);
379495fbd4eSSasha Levin 	if (r < 0)
380495fbd4eSSasha Levin 		goto free_mmio;
38136f5dc91SSasha Levin 
38243c81c74SSasha Levin 	if (kvm__supports_extension(kvm, KVM_CAP_SIGNAL_MSI))
38343c81c74SSasha Levin 		vpci->features |= VIRTIO_PCI_F_SIGNAL_MSI;
38443c81c74SSasha Levin 
38536f5dc91SSasha Levin 	vpci->pci_hdr.irq_pin	= pin;
38636f5dc91SSasha Levin 	vpci->pci_hdr.irq_line	= line;
38721ff329dSWill Deacon 	r = device__register(&vpci->dev_hdr);
388495fbd4eSSasha Levin 	if (r < 0)
389495fbd4eSSasha Levin 		goto free_ioport;
390495fbd4eSSasha Levin 
391495fbd4eSSasha Levin 	return 0;
392495fbd4eSSasha Levin 
393495fbd4eSSasha Levin free_mmio:
394495fbd4eSSasha Levin 	kvm__deregister_mmio(kvm, vpci->msix_io_block);
395495fbd4eSSasha Levin free_ioport:
3964346fd8fSSasha Levin 	ioport__unregister(kvm, vpci->base_addr);
397495fbd4eSSasha Levin 	return r;
398495fbd4eSSasha Levin }
399495fbd4eSSasha Levin 
40002eca50cSAsias He int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev)
401495fbd4eSSasha Levin {
40202eca50cSAsias He 	struct virtio_pci *vpci = vdev->virtio;
403495fbd4eSSasha Levin 	int i;
404495fbd4eSSasha Levin 
405495fbd4eSSasha Levin 	kvm__deregister_mmio(kvm, vpci->msix_io_block);
4064346fd8fSSasha Levin 	ioport__unregister(kvm, vpci->base_addr);
407495fbd4eSSasha Levin 
408495fbd4eSSasha Levin 	for (i = 0; i < VIRTIO_PCI_MAX_VQ; i++)
409495fbd4eSSasha Levin 		ioeventfd__del_event(vpci->base_addr + VIRTIO_PCI_QUEUE_NOTIFY, i);
41036f5dc91SSasha Levin 
41136f5dc91SSasha Levin 	return 0;
41236f5dc91SSasha Levin }
413