xref: /kvmtool/virtio/balloon.c (revision bc10d2c1c84c6acf57292013fb1fd9e2cfe3ee51)
182d2f21eSSasha Levin #include "kvm/virtio-balloon.h"
282d2f21eSSasha Levin 
382d2f21eSSasha Levin #include "kvm/virtio-pci-dev.h"
482d2f21eSSasha Levin 
582d2f21eSSasha Levin #include "kvm/disk-image.h"
682d2f21eSSasha Levin #include "kvm/virtio.h"
782d2f21eSSasha Levin #include "kvm/ioport.h"
882d2f21eSSasha Levin #include "kvm/util.h"
982d2f21eSSasha Levin #include "kvm/kvm.h"
1082d2f21eSSasha Levin #include "kvm/pci.h"
1182d2f21eSSasha Levin #include "kvm/threadpool.h"
1282d2f21eSSasha Levin #include "kvm/irq.h"
1382d2f21eSSasha Levin #include "kvm/ioeventfd.h"
1482d2f21eSSasha Levin 
1582d2f21eSSasha Levin #include <linux/virtio_ring.h>
1682d2f21eSSasha Levin #include <linux/virtio_balloon.h>
1782d2f21eSSasha Levin 
1882d2f21eSSasha Levin #include <linux/list.h>
1982d2f21eSSasha Levin #include <fcntl.h>
2082d2f21eSSasha Levin #include <sys/types.h>
2182d2f21eSSasha Levin #include <sys/stat.h>
2282d2f21eSSasha Levin #include <pthread.h>
2382d2f21eSSasha Levin 
24*bc10d2c1SSasha Levin #define NUM_VIRT_QUEUES		3
2582d2f21eSSasha Levin #define VIRTIO_BLN_QUEUE_SIZE	128
2682d2f21eSSasha Levin #define VIRTIO_BLN_INFLATE	0
2782d2f21eSSasha Levin #define VIRTIO_BLN_DEFLATE	1
28*bc10d2c1SSasha Levin #define VIRTIO_BLN_STATS	2
2982d2f21eSSasha Levin 
3082d2f21eSSasha Levin struct bln_dev {
3182d2f21eSSasha Levin 	struct pci_device_header pci_hdr;
3282d2f21eSSasha Levin 	struct list_head	list;
3382d2f21eSSasha Levin 
3482d2f21eSSasha Levin 	u16			base_addr;
3582d2f21eSSasha Levin 	u8			status;
3682d2f21eSSasha Levin 	u8			isr;
3782d2f21eSSasha Levin 	u16			config_vector;
3882d2f21eSSasha Levin 	u32			host_features;
3982d2f21eSSasha Levin 
4082d2f21eSSasha Levin 	/* virtio queue */
4182d2f21eSSasha Levin 	u16			queue_selector;
4282d2f21eSSasha Levin 	struct virt_queue	vqs[NUM_VIRT_QUEUES];
435cac5d9cSSasha Levin 	struct thread_pool__job	jobs[NUM_VIRT_QUEUES];
4482d2f21eSSasha Levin 
45*bc10d2c1SSasha Levin 	struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
46*bc10d2c1SSasha Levin 	struct virtio_balloon_stat *cur_stat;
47*bc10d2c1SSasha Levin 	u32			cur_stat_head;
48*bc10d2c1SSasha Levin 	u16			stat_count;
49*bc10d2c1SSasha Levin 	int			stat_waitfd;
50*bc10d2c1SSasha Levin 
5182d2f21eSSasha Levin 	struct virtio_balloon_config config;
5282d2f21eSSasha Levin };
5382d2f21eSSasha Levin 
5482d2f21eSSasha Levin static struct bln_dev bdev;
5582d2f21eSSasha Levin extern struct kvm *kvm;
5682d2f21eSSasha Levin 
5782d2f21eSSasha Levin static bool virtio_bln_dev_in(void *data, unsigned long offset, int size, u32 count)
5882d2f21eSSasha Levin {
5982d2f21eSSasha Levin 	u8 *config_space = (u8 *) &bdev.config;
6082d2f21eSSasha Levin 
6182d2f21eSSasha Levin 	if (size != 1 || count != 1)
6282d2f21eSSasha Levin 		return false;
6382d2f21eSSasha Levin 
6482d2f21eSSasha Levin 	ioport__write8(data, config_space[offset - VIRTIO_MSI_CONFIG_VECTOR]);
6582d2f21eSSasha Levin 
6682d2f21eSSasha Levin 	return true;
6782d2f21eSSasha Levin }
6882d2f21eSSasha Levin 
6982d2f21eSSasha Levin static bool virtio_bln_dev_out(void *data, unsigned long offset, int size, u32 count)
7082d2f21eSSasha Levin {
7182d2f21eSSasha Levin 	u8 *config_space = (u8 *) &bdev.config;
7282d2f21eSSasha Levin 
7382d2f21eSSasha Levin 	if (size != 1 || count != 1)
7482d2f21eSSasha Levin 		return false;
7582d2f21eSSasha Levin 
7682d2f21eSSasha Levin 	config_space[offset - VIRTIO_MSI_CONFIG_VECTOR] = *(u8 *)data;
7782d2f21eSSasha Levin 
7882d2f21eSSasha Levin 	return true;
7982d2f21eSSasha Levin }
8082d2f21eSSasha Levin 
8182d2f21eSSasha Levin static bool virtio_bln_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
8282d2f21eSSasha Levin {
8382d2f21eSSasha Levin 	unsigned long offset;
8482d2f21eSSasha Levin 	bool ret = true;
8582d2f21eSSasha Levin 
8682d2f21eSSasha Levin 	offset = port - bdev.base_addr;
8782d2f21eSSasha Levin 
8882d2f21eSSasha Levin 	switch (offset) {
8982d2f21eSSasha Levin 	case VIRTIO_PCI_HOST_FEATURES:
9082d2f21eSSasha Levin 		ioport__write32(data, bdev.host_features);
9182d2f21eSSasha Levin 		break;
9282d2f21eSSasha Levin 	case VIRTIO_PCI_GUEST_FEATURES:
9382d2f21eSSasha Levin 	case VIRTIO_PCI_QUEUE_SEL:
9482d2f21eSSasha Levin 	case VIRTIO_PCI_QUEUE_NOTIFY:
9582d2f21eSSasha Levin 		ret		= false;
9682d2f21eSSasha Levin 		break;
9782d2f21eSSasha Levin 	case VIRTIO_PCI_QUEUE_PFN:
9882d2f21eSSasha Levin 		ioport__write32(data, bdev.vqs[bdev.queue_selector].pfn);
9982d2f21eSSasha Levin 		break;
10082d2f21eSSasha Levin 	case VIRTIO_PCI_QUEUE_NUM:
10182d2f21eSSasha Levin 		ioport__write16(data, VIRTIO_BLN_QUEUE_SIZE);
10282d2f21eSSasha Levin 		break;
10382d2f21eSSasha Levin 	case VIRTIO_PCI_STATUS:
10482d2f21eSSasha Levin 		ioport__write8(data, bdev.status);
10582d2f21eSSasha Levin 		break;
10682d2f21eSSasha Levin 	case VIRTIO_PCI_ISR:
10782d2f21eSSasha Levin 		ioport__write8(data, bdev.isr);
10882d2f21eSSasha Levin 		kvm__irq_line(kvm, bdev.pci_hdr.irq_line, VIRTIO_IRQ_LOW);
10982d2f21eSSasha Levin 		bdev.isr = VIRTIO_IRQ_LOW;
11082d2f21eSSasha Levin 		break;
11182d2f21eSSasha Levin 	default:
11282d2f21eSSasha Levin 		ret = virtio_bln_dev_in(data, offset, size, count);
11382d2f21eSSasha Levin 		break;
11482d2f21eSSasha Levin 	};
11582d2f21eSSasha Levin 
11682d2f21eSSasha Levin 	return ret;
11782d2f21eSSasha Levin }
11882d2f21eSSasha Levin 
11982d2f21eSSasha Levin static bool virtio_bln_do_io_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue)
12082d2f21eSSasha Levin {
12182d2f21eSSasha Levin 	struct iovec iov[VIRTIO_BLN_QUEUE_SIZE];
12282d2f21eSSasha Levin 	unsigned int len = 0;
12382d2f21eSSasha Levin 	u16 out, in, head;
12482d2f21eSSasha Levin 	u32 *ptrs, i;
12582d2f21eSSasha Levin 
12682d2f21eSSasha Levin 	head		= virt_queue__get_iov(queue, iov, &out, &in, kvm);
12782d2f21eSSasha Levin 	ptrs		= iov[0].iov_base;
12882d2f21eSSasha Levin 	len		= iov[0].iov_len / sizeof(u32);
12982d2f21eSSasha Levin 
13082d2f21eSSasha Levin 	for (i = 0 ; i < len ; i++) {
13182d2f21eSSasha Levin 		void *guest_ptr;
13282d2f21eSSasha Levin 
13382d2f21eSSasha Levin 		guest_ptr = guest_flat_to_host(kvm, ptrs[i] << VIRTIO_BALLOON_PFN_SHIFT);
13482d2f21eSSasha Levin 		if (queue == &bdev->vqs[VIRTIO_BLN_INFLATE]) {
13582d2f21eSSasha Levin 			madvise(guest_ptr, 1 << VIRTIO_BALLOON_PFN_SHIFT, MADV_DONTNEED);
13682d2f21eSSasha Levin 			bdev->config.actual++;
137*bc10d2c1SSasha Levin 		} else if (queue == &bdev->vqs[VIRTIO_BLN_DEFLATE]) {
13882d2f21eSSasha Levin 			bdev->config.actual--;
13982d2f21eSSasha Levin 		}
14082d2f21eSSasha Levin 	}
14182d2f21eSSasha Levin 
14282d2f21eSSasha Levin 	virt_queue__set_used_elem(queue, head, len);
14382d2f21eSSasha Levin 
14482d2f21eSSasha Levin 	return true;
14582d2f21eSSasha Levin }
14682d2f21eSSasha Levin 
147*bc10d2c1SSasha Levin static bool virtio_bln_do_stat_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue)
148*bc10d2c1SSasha Levin {
149*bc10d2c1SSasha Levin 	struct iovec iov[VIRTIO_BLN_QUEUE_SIZE];
150*bc10d2c1SSasha Levin 	u16 out, in, head;
151*bc10d2c1SSasha Levin 	struct virtio_balloon_stat *stat;
152*bc10d2c1SSasha Levin 	u64 wait_val = 1;
153*bc10d2c1SSasha Levin 
154*bc10d2c1SSasha Levin 	head = virt_queue__get_iov(queue, iov, &out, &in, kvm);
155*bc10d2c1SSasha Levin 	stat = iov[0].iov_base;
156*bc10d2c1SSasha Levin 
157*bc10d2c1SSasha Levin 	/* Initial empty stat buffer */
158*bc10d2c1SSasha Levin 	if (bdev->cur_stat == NULL) {
159*bc10d2c1SSasha Levin 		bdev->cur_stat = stat;
160*bc10d2c1SSasha Levin 		bdev->cur_stat_head = head;
161*bc10d2c1SSasha Levin 
162*bc10d2c1SSasha Levin 		return true;
163*bc10d2c1SSasha Levin 	}
164*bc10d2c1SSasha Levin 
165*bc10d2c1SSasha Levin 	memcpy(bdev->stats, stat, iov[0].iov_len);
166*bc10d2c1SSasha Levin 
167*bc10d2c1SSasha Levin 	bdev->stat_count = iov[0].iov_len / sizeof(struct virtio_balloon_stat);
168*bc10d2c1SSasha Levin 	bdev->cur_stat = stat;
169*bc10d2c1SSasha Levin 	bdev->cur_stat_head = head;
170*bc10d2c1SSasha Levin 
171*bc10d2c1SSasha Levin 	if (write(bdev->stat_waitfd, &wait_val, sizeof(wait_val)) <= 0)
172*bc10d2c1SSasha Levin 		return -EFAULT;
173*bc10d2c1SSasha Levin 
174*bc10d2c1SSasha Levin 	return 1;
175*bc10d2c1SSasha Levin }
176*bc10d2c1SSasha Levin 
17782d2f21eSSasha Levin static void virtio_bln_do_io(struct kvm *kvm, void *param)
17882d2f21eSSasha Levin {
17982d2f21eSSasha Levin 	struct virt_queue *vq = param;
18082d2f21eSSasha Levin 
181*bc10d2c1SSasha Levin 	if (vq == &bdev.vqs[VIRTIO_BLN_STATS]) {
182*bc10d2c1SSasha Levin 		virtio_bln_do_stat_request(kvm, &bdev, vq);
183*bc10d2c1SSasha Levin 		virt_queue__trigger_irq(vq, bdev.pci_hdr.irq_line, &bdev.isr, kvm);
184*bc10d2c1SSasha Levin 		return;
185*bc10d2c1SSasha Levin 	}
186*bc10d2c1SSasha Levin 
18782d2f21eSSasha Levin 	while (virt_queue__available(vq)) {
18882d2f21eSSasha Levin 		virtio_bln_do_io_request(kvm, &bdev, vq);
18982d2f21eSSasha Levin 		virt_queue__trigger_irq(vq, bdev.pci_hdr.irq_line, &bdev.isr, kvm);
19082d2f21eSSasha Levin 	}
19182d2f21eSSasha Levin }
19282d2f21eSSasha Levin 
19382d2f21eSSasha Levin static void ioevent_callback(struct kvm *kvm, void *param)
19482d2f21eSSasha Levin {
19582d2f21eSSasha Levin 	thread_pool__do_job(param);
19682d2f21eSSasha Levin }
19782d2f21eSSasha Levin 
19882d2f21eSSasha Levin static bool virtio_bln_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
19982d2f21eSSasha Levin {
20082d2f21eSSasha Levin 	unsigned long offset;
20182d2f21eSSasha Levin 	bool ret = true;
20282d2f21eSSasha Levin 	struct ioevent ioevent;
20382d2f21eSSasha Levin 
20482d2f21eSSasha Levin 	offset = port - bdev.base_addr;
20582d2f21eSSasha Levin 
20682d2f21eSSasha Levin 	switch (offset) {
20782d2f21eSSasha Levin 	case VIRTIO_MSI_QUEUE_VECTOR:
20882d2f21eSSasha Levin 	case VIRTIO_PCI_GUEST_FEATURES:
20982d2f21eSSasha Levin 		break;
21082d2f21eSSasha Levin 	case VIRTIO_PCI_QUEUE_PFN: {
21182d2f21eSSasha Levin 		struct virt_queue *queue;
21282d2f21eSSasha Levin 		void *p;
21382d2f21eSSasha Levin 
21482d2f21eSSasha Levin 		queue			= &bdev.vqs[bdev.queue_selector];
21582d2f21eSSasha Levin 		queue->pfn		= ioport__read32(data);
21682d2f21eSSasha Levin 		p			= guest_pfn_to_host(kvm, queue->pfn);
21782d2f21eSSasha Levin 
21882d2f21eSSasha Levin 		vring_init(&queue->vring, VIRTIO_BLN_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
21982d2f21eSSasha Levin 
2205cac5d9cSSasha Levin 		thread_pool__init_job(&bdev.jobs[bdev.queue_selector], kvm, virtio_bln_do_io, queue);
22182d2f21eSSasha Levin 
22282d2f21eSSasha Levin 		ioevent = (struct ioevent) {
22382d2f21eSSasha Levin 			.io_addr		= bdev.base_addr + VIRTIO_PCI_QUEUE_NOTIFY,
22482d2f21eSSasha Levin 			.io_len			= sizeof(u16),
22582d2f21eSSasha Levin 			.fn			= ioevent_callback,
2265cac5d9cSSasha Levin 			.fn_ptr			= &bdev.jobs[bdev.queue_selector],
22782d2f21eSSasha Levin 			.datamatch		= bdev.queue_selector,
22882d2f21eSSasha Levin 			.fn_kvm			= kvm,
22982d2f21eSSasha Levin 			.fd			= eventfd(0, 0),
23082d2f21eSSasha Levin 		};
23182d2f21eSSasha Levin 
23282d2f21eSSasha Levin 		ioeventfd__add_event(&ioevent);
23382d2f21eSSasha Levin 
23482d2f21eSSasha Levin 		break;
23582d2f21eSSasha Levin 	}
23682d2f21eSSasha Levin 	case VIRTIO_PCI_QUEUE_SEL:
23782d2f21eSSasha Levin 		bdev.queue_selector	= ioport__read16(data);
23882d2f21eSSasha Levin 		break;
23982d2f21eSSasha Levin 	case VIRTIO_PCI_QUEUE_NOTIFY: {
24082d2f21eSSasha Levin 		u16 queue_index;
24182d2f21eSSasha Levin 		queue_index		= ioport__read16(data);
2425cac5d9cSSasha Levin 		thread_pool__do_job(&bdev.jobs[queue_index]);
24382d2f21eSSasha Levin 		break;
24482d2f21eSSasha Levin 	}
24582d2f21eSSasha Levin 	case VIRTIO_PCI_STATUS:
24682d2f21eSSasha Levin 		bdev.status		= ioport__read8(data);
24782d2f21eSSasha Levin 		break;
24882d2f21eSSasha Levin 	case VIRTIO_MSI_CONFIG_VECTOR:
24982d2f21eSSasha Levin 		bdev.config_vector	= VIRTIO_MSI_NO_VECTOR;
25082d2f21eSSasha Levin 		break;
25182d2f21eSSasha Levin 	default:
25282d2f21eSSasha Levin 		ret = virtio_bln_dev_out(data, offset, size, count);
25382d2f21eSSasha Levin 		break;
25482d2f21eSSasha Levin 	};
25582d2f21eSSasha Levin 
25682d2f21eSSasha Levin 	return ret;
25782d2f21eSSasha Levin }
25882d2f21eSSasha Levin 
25982d2f21eSSasha Levin static struct ioport_operations virtio_bln_io_ops = {
26082d2f21eSSasha Levin 	.io_in				= virtio_bln_pci_io_in,
26182d2f21eSSasha Levin 	.io_out				= virtio_bln_pci_io_out,
26282d2f21eSSasha Levin };
26382d2f21eSSasha Levin 
264*bc10d2c1SSasha Levin static int virtio_bln__collect_stats(void)
265*bc10d2c1SSasha Levin {
266*bc10d2c1SSasha Levin 	u64 tmp;
267*bc10d2c1SSasha Levin 
268*bc10d2c1SSasha Levin 	virt_queue__set_used_elem(&bdev.vqs[VIRTIO_BLN_STATS], bdev.cur_stat_head,
269*bc10d2c1SSasha Levin 				  sizeof(struct virtio_balloon_stat));
270*bc10d2c1SSasha Levin 	virt_queue__trigger_irq(&bdev.vqs[VIRTIO_BLN_STATS], bdev.pci_hdr.irq_line,
271*bc10d2c1SSasha Levin 				&bdev.isr, kvm);
272*bc10d2c1SSasha Levin 
273*bc10d2c1SSasha Levin 	if (read(bdev.stat_waitfd, &tmp, sizeof(tmp)) <= 0)
274*bc10d2c1SSasha Levin 		return -EFAULT;
275*bc10d2c1SSasha Levin 
276*bc10d2c1SSasha Levin 	return 0;
277*bc10d2c1SSasha Levin }
278*bc10d2c1SSasha Levin 
279*bc10d2c1SSasha Levin static int virtio_bln__print_stats(void)
280*bc10d2c1SSasha Levin {
281*bc10d2c1SSasha Levin 	u16 i;
282*bc10d2c1SSasha Levin 
283*bc10d2c1SSasha Levin 	if (virtio_bln__collect_stats() < 0)
284*bc10d2c1SSasha Levin 		return -EFAULT;
285*bc10d2c1SSasha Levin 
286*bc10d2c1SSasha Levin 	printf("\n\n\t*** Guest memory statistics ***\n\n");
287*bc10d2c1SSasha Levin 	for (i = 0; i < bdev.stat_count; i++) {
288*bc10d2c1SSasha Levin 		switch (bdev.stats[i].tag) {
289*bc10d2c1SSasha Levin 		case VIRTIO_BALLOON_S_SWAP_IN:
290*bc10d2c1SSasha Levin 			printf("The amount of memory that has been swapped in (in bytes):");
291*bc10d2c1SSasha Levin 			break;
292*bc10d2c1SSasha Levin 		case VIRTIO_BALLOON_S_SWAP_OUT:
293*bc10d2c1SSasha Levin 			printf("The amount of memory that has been swapped out to disk (in bytes):");
294*bc10d2c1SSasha Levin 			break;
295*bc10d2c1SSasha Levin 		case VIRTIO_BALLOON_S_MAJFLT:
296*bc10d2c1SSasha Levin 			printf("The number of major page faults that have occurred:");
297*bc10d2c1SSasha Levin 			break;
298*bc10d2c1SSasha Levin 		case VIRTIO_BALLOON_S_MINFLT:
299*bc10d2c1SSasha Levin 			printf("The number of minor page faults that have occurred:");
300*bc10d2c1SSasha Levin 			break;
301*bc10d2c1SSasha Levin 		case VIRTIO_BALLOON_S_MEMFREE:
302*bc10d2c1SSasha Levin 			printf("The amount of memory not being used for any purpose (in bytes):");
303*bc10d2c1SSasha Levin 			break;
304*bc10d2c1SSasha Levin 		case VIRTIO_BALLOON_S_MEMTOT:
305*bc10d2c1SSasha Levin 			printf("The total amount of memory available (in bytes):");
306*bc10d2c1SSasha Levin 			break;
307*bc10d2c1SSasha Levin 		}
308*bc10d2c1SSasha Levin 		printf("%llu\n", bdev.stats[i].val);
309*bc10d2c1SSasha Levin 	}
310*bc10d2c1SSasha Levin 	printf("\n");
311*bc10d2c1SSasha Levin 
312*bc10d2c1SSasha Levin 	return 0;
313*bc10d2c1SSasha Levin }
314*bc10d2c1SSasha Levin 
31582d2f21eSSasha Levin static void handle_sigmem(int sig)
31682d2f21eSSasha Levin {
31742bcd3eeSLiming Wang 	if (sig == SIGKVMADDMEM) {
31882d2f21eSSasha Levin 		bdev.config.num_pages += 256;
319*bc10d2c1SSasha Levin 	} else if (sig == SIGKVMDELMEM) {
32042bcd3eeSLiming Wang 		if (bdev.config.num_pages < 256)
32142bcd3eeSLiming Wang 			return;
32242bcd3eeSLiming Wang 
32382d2f21eSSasha Levin 		bdev.config.num_pages -= 256;
324*bc10d2c1SSasha Levin 	} else if (sig == SIGKVMMEMSTAT) {
325*bc10d2c1SSasha Levin 		virtio_bln__print_stats();
326*bc10d2c1SSasha Levin 
327*bc10d2c1SSasha Levin 		return;
32842bcd3eeSLiming Wang 	}
32982d2f21eSSasha Levin 
33082d2f21eSSasha Levin 	/* Notify that the configuration space has changed */
33182d2f21eSSasha Levin 	bdev.isr = VIRTIO_PCI_ISR_CONFIG;
33282d2f21eSSasha Levin 	kvm__irq_line(kvm, bdev.pci_hdr.irq_line, 1);
33382d2f21eSSasha Levin }
33482d2f21eSSasha Levin 
33582d2f21eSSasha Levin void virtio_bln__init(struct kvm *kvm)
33682d2f21eSSasha Levin {
33782d2f21eSSasha Levin 	u8 pin, line, dev;
33882d2f21eSSasha Levin 	u16 bdev_base_addr;
33982d2f21eSSasha Levin 
34082d2f21eSSasha Levin 	signal(SIGKVMADDMEM, handle_sigmem);
34182d2f21eSSasha Levin 	signal(SIGKVMDELMEM, handle_sigmem);
342*bc10d2c1SSasha Levin 	signal(SIGKVMMEMSTAT, handle_sigmem);
34382d2f21eSSasha Levin 
34482d2f21eSSasha Levin 	bdev_base_addr = ioport__register(IOPORT_EMPTY, &virtio_bln_io_ops, IOPORT_SIZE, &bdev);
34582d2f21eSSasha Levin 
34682d2f21eSSasha Levin 	bdev.pci_hdr = (struct pci_device_header) {
34782d2f21eSSasha Levin 		.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
34882d2f21eSSasha Levin 		.device_id		= PCI_DEVICE_ID_VIRTIO_BLN,
34982d2f21eSSasha Levin 		.header_type		= PCI_HEADER_TYPE_NORMAL,
35082d2f21eSSasha Levin 		.revision_id		= 0,
35182d2f21eSSasha Levin 		.class			= 0x010000,
35282d2f21eSSasha Levin 		.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
35382d2f21eSSasha Levin 		.subsys_id		= VIRTIO_ID_BALLOON,
35482d2f21eSSasha Levin 		.bar[0]			= bdev_base_addr | PCI_BASE_ADDRESS_SPACE_IO,
35582d2f21eSSasha Levin 	};
35682d2f21eSSasha Levin 
35782d2f21eSSasha Levin 	bdev.base_addr = bdev_base_addr;
35882d2f21eSSasha Levin 
35982d2f21eSSasha Levin 	if (irq__register_device(VIRTIO_ID_RNG, &dev, &pin, &line) < 0)
36082d2f21eSSasha Levin 		return;
36182d2f21eSSasha Levin 
36282d2f21eSSasha Levin 	bdev.pci_hdr.irq_pin	= pin;
36382d2f21eSSasha Levin 	bdev.pci_hdr.irq_line	= line;
364*bc10d2c1SSasha Levin 	bdev.host_features	= 1 << VIRTIO_BALLOON_F_STATS_VQ;
365*bc10d2c1SSasha Levin 	bdev.stat_waitfd	= eventfd(0, 0);
36682d2f21eSSasha Levin 	memset(&bdev.config, 0, sizeof(struct virtio_balloon_config));
36782d2f21eSSasha Levin 
36882d2f21eSSasha Levin 	pci__register(&bdev.pci_hdr, dev);
36982d2f21eSSasha Levin }
370