xref: /kvmtool/virtio/balloon.c (revision 4b2e0a7a74a7720212d75694df9cd376aaea5f9d)
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"
14*4b2e0a7aSSasha Levin #include "kvm/guest_compat.h"
1582d2f21eSSasha Levin 
1682d2f21eSSasha Levin #include <linux/virtio_ring.h>
1782d2f21eSSasha Levin #include <linux/virtio_balloon.h>
1882d2f21eSSasha Levin 
1982d2f21eSSasha Levin #include <linux/list.h>
2082d2f21eSSasha Levin #include <fcntl.h>
2182d2f21eSSasha Levin #include <sys/types.h>
2282d2f21eSSasha Levin #include <sys/stat.h>
2382d2f21eSSasha Levin #include <pthread.h>
2482d2f21eSSasha Levin 
25bc10d2c1SSasha Levin #define NUM_VIRT_QUEUES		3
2682d2f21eSSasha Levin #define VIRTIO_BLN_QUEUE_SIZE	128
2782d2f21eSSasha Levin #define VIRTIO_BLN_INFLATE	0
2882d2f21eSSasha Levin #define VIRTIO_BLN_DEFLATE	1
29bc10d2c1SSasha Levin #define VIRTIO_BLN_STATS	2
3082d2f21eSSasha Levin 
3182d2f21eSSasha Levin struct bln_dev {
3282d2f21eSSasha Levin 	struct pci_device_header pci_hdr;
3382d2f21eSSasha Levin 	struct list_head	list;
3482d2f21eSSasha Levin 
3582d2f21eSSasha Levin 	u16			base_addr;
3682d2f21eSSasha Levin 	u8			status;
3782d2f21eSSasha Levin 	u8			isr;
3882d2f21eSSasha Levin 	u16			config_vector;
3982d2f21eSSasha Levin 	u32			host_features;
4082d2f21eSSasha Levin 
4182d2f21eSSasha Levin 	/* virtio queue */
4282d2f21eSSasha Levin 	u16			queue_selector;
4382d2f21eSSasha Levin 	struct virt_queue	vqs[NUM_VIRT_QUEUES];
445cac5d9cSSasha Levin 	struct thread_pool__job	jobs[NUM_VIRT_QUEUES];
4582d2f21eSSasha Levin 
46bc10d2c1SSasha Levin 	struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
47bc10d2c1SSasha Levin 	struct virtio_balloon_stat *cur_stat;
48bc10d2c1SSasha Levin 	u32			cur_stat_head;
49bc10d2c1SSasha Levin 	u16			stat_count;
50bc10d2c1SSasha Levin 	int			stat_waitfd;
51bc10d2c1SSasha Levin 
52*4b2e0a7aSSasha Levin 	int			compat_id;
5382d2f21eSSasha Levin 	struct virtio_balloon_config config;
5482d2f21eSSasha Levin };
5582d2f21eSSasha Levin 
5682d2f21eSSasha Levin static struct bln_dev bdev;
5782d2f21eSSasha Levin extern struct kvm *kvm;
5882d2f21eSSasha Levin 
59c9f6a037SXiao Guangrong static bool virtio_bln_dev_in(void *data, unsigned long offset, int size)
6082d2f21eSSasha Levin {
6182d2f21eSSasha Levin 	u8 *config_space = (u8 *) &bdev.config;
6282d2f21eSSasha Levin 
63c9f6a037SXiao Guangrong 	if (size != 1)
6482d2f21eSSasha Levin 		return false;
6582d2f21eSSasha Levin 
6682d2f21eSSasha Levin 	ioport__write8(data, config_space[offset - VIRTIO_MSI_CONFIG_VECTOR]);
6782d2f21eSSasha Levin 
6882d2f21eSSasha Levin 	return true;
6982d2f21eSSasha Levin }
7082d2f21eSSasha Levin 
71c9f6a037SXiao Guangrong static bool virtio_bln_dev_out(void *data, unsigned long offset, int size)
7282d2f21eSSasha Levin {
7382d2f21eSSasha Levin 	u8 *config_space = (u8 *) &bdev.config;
7482d2f21eSSasha Levin 
75c9f6a037SXiao Guangrong 	if (size != 1)
7682d2f21eSSasha Levin 		return false;
7782d2f21eSSasha Levin 
7882d2f21eSSasha Levin 	config_space[offset - VIRTIO_MSI_CONFIG_VECTOR] = *(u8 *)data;
7982d2f21eSSasha Levin 
8082d2f21eSSasha Levin 	return true;
8182d2f21eSSasha Levin }
8282d2f21eSSasha Levin 
83c9f6a037SXiao Guangrong static bool virtio_bln_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
8482d2f21eSSasha Levin {
8582d2f21eSSasha Levin 	unsigned long offset;
8682d2f21eSSasha Levin 	bool ret = true;
8782d2f21eSSasha Levin 
8882d2f21eSSasha Levin 	offset = port - bdev.base_addr;
8982d2f21eSSasha Levin 
9082d2f21eSSasha Levin 	switch (offset) {
9182d2f21eSSasha Levin 	case VIRTIO_PCI_HOST_FEATURES:
9282d2f21eSSasha Levin 		ioport__write32(data, bdev.host_features);
9382d2f21eSSasha Levin 		break;
9482d2f21eSSasha Levin 	case VIRTIO_PCI_GUEST_FEATURES:
9582d2f21eSSasha Levin 	case VIRTIO_PCI_QUEUE_SEL:
9682d2f21eSSasha Levin 	case VIRTIO_PCI_QUEUE_NOTIFY:
9782d2f21eSSasha Levin 		ret		= false;
9882d2f21eSSasha Levin 		break;
9982d2f21eSSasha Levin 	case VIRTIO_PCI_QUEUE_PFN:
10082d2f21eSSasha Levin 		ioport__write32(data, bdev.vqs[bdev.queue_selector].pfn);
10182d2f21eSSasha Levin 		break;
10282d2f21eSSasha Levin 	case VIRTIO_PCI_QUEUE_NUM:
10382d2f21eSSasha Levin 		ioport__write16(data, VIRTIO_BLN_QUEUE_SIZE);
10482d2f21eSSasha Levin 		break;
10582d2f21eSSasha Levin 	case VIRTIO_PCI_STATUS:
10682d2f21eSSasha Levin 		ioport__write8(data, bdev.status);
10782d2f21eSSasha Levin 		break;
10882d2f21eSSasha Levin 	case VIRTIO_PCI_ISR:
10982d2f21eSSasha Levin 		ioport__write8(data, bdev.isr);
11082d2f21eSSasha Levin 		kvm__irq_line(kvm, bdev.pci_hdr.irq_line, VIRTIO_IRQ_LOW);
11182d2f21eSSasha Levin 		bdev.isr = VIRTIO_IRQ_LOW;
11282d2f21eSSasha Levin 		break;
11382d2f21eSSasha Levin 	default:
114c9f6a037SXiao Guangrong 		ret = virtio_bln_dev_in(data, offset, size);
11582d2f21eSSasha Levin 		break;
11682d2f21eSSasha Levin 	};
11782d2f21eSSasha Levin 
11882d2f21eSSasha Levin 	return ret;
11982d2f21eSSasha Levin }
12082d2f21eSSasha Levin 
12182d2f21eSSasha Levin static bool virtio_bln_do_io_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue)
12282d2f21eSSasha Levin {
12382d2f21eSSasha Levin 	struct iovec iov[VIRTIO_BLN_QUEUE_SIZE];
12482d2f21eSSasha Levin 	unsigned int len = 0;
12582d2f21eSSasha Levin 	u16 out, in, head;
12682d2f21eSSasha Levin 	u32 *ptrs, i;
12782d2f21eSSasha Levin 
12882d2f21eSSasha Levin 	head		= virt_queue__get_iov(queue, iov, &out, &in, kvm);
12982d2f21eSSasha Levin 	ptrs		= iov[0].iov_base;
13082d2f21eSSasha Levin 	len		= iov[0].iov_len / sizeof(u32);
13182d2f21eSSasha Levin 
13282d2f21eSSasha Levin 	for (i = 0 ; i < len ; i++) {
13382d2f21eSSasha Levin 		void *guest_ptr;
13482d2f21eSSasha Levin 
13582d2f21eSSasha Levin 		guest_ptr = guest_flat_to_host(kvm, ptrs[i] << VIRTIO_BALLOON_PFN_SHIFT);
13682d2f21eSSasha Levin 		if (queue == &bdev->vqs[VIRTIO_BLN_INFLATE]) {
13782d2f21eSSasha Levin 			madvise(guest_ptr, 1 << VIRTIO_BALLOON_PFN_SHIFT, MADV_DONTNEED);
13882d2f21eSSasha Levin 			bdev->config.actual++;
139bc10d2c1SSasha Levin 		} else if (queue == &bdev->vqs[VIRTIO_BLN_DEFLATE]) {
14082d2f21eSSasha Levin 			bdev->config.actual--;
14182d2f21eSSasha Levin 		}
14282d2f21eSSasha Levin 	}
14382d2f21eSSasha Levin 
14482d2f21eSSasha Levin 	virt_queue__set_used_elem(queue, head, len);
14582d2f21eSSasha Levin 
14682d2f21eSSasha Levin 	return true;
14782d2f21eSSasha Levin }
14882d2f21eSSasha Levin 
149bc10d2c1SSasha Levin static bool virtio_bln_do_stat_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue)
150bc10d2c1SSasha Levin {
151bc10d2c1SSasha Levin 	struct iovec iov[VIRTIO_BLN_QUEUE_SIZE];
152bc10d2c1SSasha Levin 	u16 out, in, head;
153bc10d2c1SSasha Levin 	struct virtio_balloon_stat *stat;
154bc10d2c1SSasha Levin 	u64 wait_val = 1;
155bc10d2c1SSasha Levin 
156bc10d2c1SSasha Levin 	head = virt_queue__get_iov(queue, iov, &out, &in, kvm);
157bc10d2c1SSasha Levin 	stat = iov[0].iov_base;
158bc10d2c1SSasha Levin 
159bc10d2c1SSasha Levin 	/* Initial empty stat buffer */
160bc10d2c1SSasha Levin 	if (bdev->cur_stat == NULL) {
161bc10d2c1SSasha Levin 		bdev->cur_stat = stat;
162bc10d2c1SSasha Levin 		bdev->cur_stat_head = head;
163bc10d2c1SSasha Levin 
164bc10d2c1SSasha Levin 		return true;
165bc10d2c1SSasha Levin 	}
166bc10d2c1SSasha Levin 
167bc10d2c1SSasha Levin 	memcpy(bdev->stats, stat, iov[0].iov_len);
168bc10d2c1SSasha Levin 
169bc10d2c1SSasha Levin 	bdev->stat_count = iov[0].iov_len / sizeof(struct virtio_balloon_stat);
170bc10d2c1SSasha Levin 	bdev->cur_stat = stat;
171bc10d2c1SSasha Levin 	bdev->cur_stat_head = head;
172bc10d2c1SSasha Levin 
173bc10d2c1SSasha Levin 	if (write(bdev->stat_waitfd, &wait_val, sizeof(wait_val)) <= 0)
174bc10d2c1SSasha Levin 		return -EFAULT;
175bc10d2c1SSasha Levin 
176bc10d2c1SSasha Levin 	return 1;
177bc10d2c1SSasha Levin }
178bc10d2c1SSasha Levin 
17982d2f21eSSasha Levin static void virtio_bln_do_io(struct kvm *kvm, void *param)
18082d2f21eSSasha Levin {
18182d2f21eSSasha Levin 	struct virt_queue *vq = param;
18282d2f21eSSasha Levin 
183bc10d2c1SSasha Levin 	if (vq == &bdev.vqs[VIRTIO_BLN_STATS]) {
184bc10d2c1SSasha Levin 		virtio_bln_do_stat_request(kvm, &bdev, vq);
185bc10d2c1SSasha Levin 		virt_queue__trigger_irq(vq, bdev.pci_hdr.irq_line, &bdev.isr, kvm);
186bc10d2c1SSasha Levin 		return;
187bc10d2c1SSasha Levin 	}
188bc10d2c1SSasha Levin 
18982d2f21eSSasha Levin 	while (virt_queue__available(vq)) {
19082d2f21eSSasha Levin 		virtio_bln_do_io_request(kvm, &bdev, vq);
19182d2f21eSSasha Levin 		virt_queue__trigger_irq(vq, bdev.pci_hdr.irq_line, &bdev.isr, kvm);
19282d2f21eSSasha Levin 	}
19382d2f21eSSasha Levin }
19482d2f21eSSasha Levin 
19582d2f21eSSasha Levin static void ioevent_callback(struct kvm *kvm, void *param)
19682d2f21eSSasha Levin {
19782d2f21eSSasha Levin 	thread_pool__do_job(param);
19882d2f21eSSasha Levin }
19982d2f21eSSasha Levin 
200c9f6a037SXiao Guangrong static bool virtio_bln_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
20182d2f21eSSasha Levin {
20282d2f21eSSasha Levin 	unsigned long offset;
20382d2f21eSSasha Levin 	bool ret = true;
20482d2f21eSSasha Levin 	struct ioevent ioevent;
20582d2f21eSSasha Levin 
20682d2f21eSSasha Levin 	offset = port - bdev.base_addr;
20782d2f21eSSasha Levin 
20882d2f21eSSasha Levin 	switch (offset) {
20982d2f21eSSasha Levin 	case VIRTIO_MSI_QUEUE_VECTOR:
21082d2f21eSSasha Levin 	case VIRTIO_PCI_GUEST_FEATURES:
21182d2f21eSSasha Levin 		break;
21282d2f21eSSasha Levin 	case VIRTIO_PCI_QUEUE_PFN: {
21382d2f21eSSasha Levin 		struct virt_queue *queue;
21482d2f21eSSasha Levin 		void *p;
21582d2f21eSSasha Levin 
216*4b2e0a7aSSasha Levin 		compat__remove_message(bdev.compat_id);
217*4b2e0a7aSSasha Levin 
21882d2f21eSSasha Levin 		queue			= &bdev.vqs[bdev.queue_selector];
21982d2f21eSSasha Levin 		queue->pfn		= ioport__read32(data);
22082d2f21eSSasha Levin 		p			= guest_pfn_to_host(kvm, queue->pfn);
22182d2f21eSSasha Levin 
22282d2f21eSSasha Levin 		vring_init(&queue->vring, VIRTIO_BLN_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
22382d2f21eSSasha Levin 
2245cac5d9cSSasha Levin 		thread_pool__init_job(&bdev.jobs[bdev.queue_selector], kvm, virtio_bln_do_io, queue);
22582d2f21eSSasha Levin 
22682d2f21eSSasha Levin 		ioevent = (struct ioevent) {
22782d2f21eSSasha Levin 			.io_addr		= bdev.base_addr + VIRTIO_PCI_QUEUE_NOTIFY,
22882d2f21eSSasha Levin 			.io_len			= sizeof(u16),
22982d2f21eSSasha Levin 			.fn			= ioevent_callback,
2305cac5d9cSSasha Levin 			.fn_ptr			= &bdev.jobs[bdev.queue_selector],
23182d2f21eSSasha Levin 			.datamatch		= bdev.queue_selector,
23282d2f21eSSasha Levin 			.fn_kvm			= kvm,
23382d2f21eSSasha Levin 			.fd			= eventfd(0, 0),
23482d2f21eSSasha Levin 		};
23582d2f21eSSasha Levin 
23682d2f21eSSasha Levin 		ioeventfd__add_event(&ioevent);
23782d2f21eSSasha Levin 
23882d2f21eSSasha Levin 		break;
23982d2f21eSSasha Levin 	}
24082d2f21eSSasha Levin 	case VIRTIO_PCI_QUEUE_SEL:
24182d2f21eSSasha Levin 		bdev.queue_selector	= ioport__read16(data);
24282d2f21eSSasha Levin 		break;
24382d2f21eSSasha Levin 	case VIRTIO_PCI_QUEUE_NOTIFY: {
24482d2f21eSSasha Levin 		u16 queue_index;
24582d2f21eSSasha Levin 		queue_index		= ioport__read16(data);
2465cac5d9cSSasha Levin 		thread_pool__do_job(&bdev.jobs[queue_index]);
24782d2f21eSSasha Levin 		break;
24882d2f21eSSasha Levin 	}
24982d2f21eSSasha Levin 	case VIRTIO_PCI_STATUS:
25082d2f21eSSasha Levin 		bdev.status		= ioport__read8(data);
25182d2f21eSSasha Levin 		break;
25282d2f21eSSasha Levin 	case VIRTIO_MSI_CONFIG_VECTOR:
25382d2f21eSSasha Levin 		bdev.config_vector	= VIRTIO_MSI_NO_VECTOR;
25482d2f21eSSasha Levin 		break;
25582d2f21eSSasha Levin 	default:
256c9f6a037SXiao Guangrong 		ret = virtio_bln_dev_out(data, offset, size);
25782d2f21eSSasha Levin 		break;
25882d2f21eSSasha Levin 	};
25982d2f21eSSasha Levin 
26082d2f21eSSasha Levin 	return ret;
26182d2f21eSSasha Levin }
26282d2f21eSSasha Levin 
26382d2f21eSSasha Levin static struct ioport_operations virtio_bln_io_ops = {
26482d2f21eSSasha Levin 	.io_in				= virtio_bln_pci_io_in,
26582d2f21eSSasha Levin 	.io_out				= virtio_bln_pci_io_out,
26682d2f21eSSasha Levin };
26782d2f21eSSasha Levin 
268bc10d2c1SSasha Levin static int virtio_bln__collect_stats(void)
269bc10d2c1SSasha Levin {
270bc10d2c1SSasha Levin 	u64 tmp;
271bc10d2c1SSasha Levin 
272bc10d2c1SSasha Levin 	virt_queue__set_used_elem(&bdev.vqs[VIRTIO_BLN_STATS], bdev.cur_stat_head,
273bc10d2c1SSasha Levin 				  sizeof(struct virtio_balloon_stat));
274bc10d2c1SSasha Levin 	virt_queue__trigger_irq(&bdev.vqs[VIRTIO_BLN_STATS], bdev.pci_hdr.irq_line,
275bc10d2c1SSasha Levin 				&bdev.isr, kvm);
276bc10d2c1SSasha Levin 
277bc10d2c1SSasha Levin 	if (read(bdev.stat_waitfd, &tmp, sizeof(tmp)) <= 0)
278bc10d2c1SSasha Levin 		return -EFAULT;
279bc10d2c1SSasha Levin 
280bc10d2c1SSasha Levin 	return 0;
281bc10d2c1SSasha Levin }
282bc10d2c1SSasha Levin 
283bc10d2c1SSasha Levin static int virtio_bln__print_stats(void)
284bc10d2c1SSasha Levin {
285bc10d2c1SSasha Levin 	u16 i;
286bc10d2c1SSasha Levin 
287bc10d2c1SSasha Levin 	if (virtio_bln__collect_stats() < 0)
288bc10d2c1SSasha Levin 		return -EFAULT;
289bc10d2c1SSasha Levin 
290bc10d2c1SSasha Levin 	printf("\n\n\t*** Guest memory statistics ***\n\n");
291bc10d2c1SSasha Levin 	for (i = 0; i < bdev.stat_count; i++) {
292bc10d2c1SSasha Levin 		switch (bdev.stats[i].tag) {
293bc10d2c1SSasha Levin 		case VIRTIO_BALLOON_S_SWAP_IN:
294bc10d2c1SSasha Levin 			printf("The amount of memory that has been swapped in (in bytes):");
295bc10d2c1SSasha Levin 			break;
296bc10d2c1SSasha Levin 		case VIRTIO_BALLOON_S_SWAP_OUT:
297bc10d2c1SSasha Levin 			printf("The amount of memory that has been swapped out to disk (in bytes):");
298bc10d2c1SSasha Levin 			break;
299bc10d2c1SSasha Levin 		case VIRTIO_BALLOON_S_MAJFLT:
300bc10d2c1SSasha Levin 			printf("The number of major page faults that have occurred:");
301bc10d2c1SSasha Levin 			break;
302bc10d2c1SSasha Levin 		case VIRTIO_BALLOON_S_MINFLT:
303bc10d2c1SSasha Levin 			printf("The number of minor page faults that have occurred:");
304bc10d2c1SSasha Levin 			break;
305bc10d2c1SSasha Levin 		case VIRTIO_BALLOON_S_MEMFREE:
306bc10d2c1SSasha Levin 			printf("The amount of memory not being used for any purpose (in bytes):");
307bc10d2c1SSasha Levin 			break;
308bc10d2c1SSasha Levin 		case VIRTIO_BALLOON_S_MEMTOT:
309bc10d2c1SSasha Levin 			printf("The total amount of memory available (in bytes):");
310bc10d2c1SSasha Levin 			break;
311bc10d2c1SSasha Levin 		}
312bc10d2c1SSasha Levin 		printf("%llu\n", bdev.stats[i].val);
313bc10d2c1SSasha Levin 	}
314bc10d2c1SSasha Levin 	printf("\n");
315bc10d2c1SSasha Levin 
316bc10d2c1SSasha Levin 	return 0;
317bc10d2c1SSasha Levin }
318bc10d2c1SSasha Levin 
31982d2f21eSSasha Levin static void handle_sigmem(int sig)
32082d2f21eSSasha Levin {
32142bcd3eeSLiming Wang 	if (sig == SIGKVMADDMEM) {
32282d2f21eSSasha Levin 		bdev.config.num_pages += 256;
323bc10d2c1SSasha Levin 	} else if (sig == SIGKVMDELMEM) {
32442bcd3eeSLiming Wang 		if (bdev.config.num_pages < 256)
32542bcd3eeSLiming Wang 			return;
32642bcd3eeSLiming Wang 
32782d2f21eSSasha Levin 		bdev.config.num_pages -= 256;
328bc10d2c1SSasha Levin 	} else if (sig == SIGKVMMEMSTAT) {
329bc10d2c1SSasha Levin 		virtio_bln__print_stats();
330bc10d2c1SSasha Levin 
331bc10d2c1SSasha Levin 		return;
33242bcd3eeSLiming Wang 	}
33382d2f21eSSasha Levin 
33482d2f21eSSasha Levin 	/* Notify that the configuration space has changed */
33582d2f21eSSasha Levin 	bdev.isr = VIRTIO_PCI_ISR_CONFIG;
33682d2f21eSSasha Levin 	kvm__irq_line(kvm, bdev.pci_hdr.irq_line, 1);
33782d2f21eSSasha Levin }
33882d2f21eSSasha Levin 
33982d2f21eSSasha Levin void virtio_bln__init(struct kvm *kvm)
34082d2f21eSSasha Levin {
34182d2f21eSSasha Levin 	u8 pin, line, dev;
34282d2f21eSSasha Levin 	u16 bdev_base_addr;
34382d2f21eSSasha Levin 
34482d2f21eSSasha Levin 	signal(SIGKVMADDMEM, handle_sigmem);
34582d2f21eSSasha Levin 	signal(SIGKVMDELMEM, handle_sigmem);
346bc10d2c1SSasha Levin 	signal(SIGKVMMEMSTAT, handle_sigmem);
34782d2f21eSSasha Levin 
34882d2f21eSSasha Levin 	bdev_base_addr = ioport__register(IOPORT_EMPTY, &virtio_bln_io_ops, IOPORT_SIZE, &bdev);
34982d2f21eSSasha Levin 
35082d2f21eSSasha Levin 	bdev.pci_hdr = (struct pci_device_header) {
35182d2f21eSSasha Levin 		.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
35282d2f21eSSasha Levin 		.device_id		= PCI_DEVICE_ID_VIRTIO_BLN,
35382d2f21eSSasha Levin 		.header_type		= PCI_HEADER_TYPE_NORMAL,
35482d2f21eSSasha Levin 		.revision_id		= 0,
35582d2f21eSSasha Levin 		.class			= 0x010000,
35682d2f21eSSasha Levin 		.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
35782d2f21eSSasha Levin 		.subsys_id		= VIRTIO_ID_BALLOON,
35882d2f21eSSasha Levin 		.bar[0]			= bdev_base_addr | PCI_BASE_ADDRESS_SPACE_IO,
35982d2f21eSSasha Levin 	};
36082d2f21eSSasha Levin 
36182d2f21eSSasha Levin 	bdev.base_addr = bdev_base_addr;
36282d2f21eSSasha Levin 
36380c71af0SLiming Wang 	if (irq__register_device(VIRTIO_ID_BALLOON, &dev, &pin, &line) < 0)
36482d2f21eSSasha Levin 		return;
36582d2f21eSSasha Levin 
36682d2f21eSSasha Levin 	bdev.pci_hdr.irq_pin	= pin;
36782d2f21eSSasha Levin 	bdev.pci_hdr.irq_line	= line;
368bc10d2c1SSasha Levin 	bdev.host_features	= 1 << VIRTIO_BALLOON_F_STATS_VQ;
369bc10d2c1SSasha Levin 	bdev.stat_waitfd	= eventfd(0, 0);
37082d2f21eSSasha Levin 	memset(&bdev.config, 0, sizeof(struct virtio_balloon_config));
37182d2f21eSSasha Levin 
37282d2f21eSSasha Levin 	pci__register(&bdev.pci_hdr, dev);
373*4b2e0a7aSSasha Levin 
374*4b2e0a7aSSasha Levin 	bdev.compat_id = compat__add_message("virtio-balloon device was not detected",
375*4b2e0a7aSSasha Levin 						"While you have requested a virtio-balloon device, "
376*4b2e0a7aSSasha Levin 						"the guest kernel didn't seem to detect it.\n"
377*4b2e0a7aSSasha Levin 						"Please make sure that the kernel was compiled"
378*4b2e0a7aSSasha Levin 						"with CONFIG_VIRTIO_BALLOON.");
37982d2f21eSSasha Levin }
380