xref: /kvmtool/virtio/blk.c (revision 8b1ff07e1f5e4f685492de9b34bec25662ae57cb)
1b30d05adSPekka Enberg #include "kvm/blk-virtio.h"
2b30d05adSPekka Enberg 
3984b7ae0SPekka Enberg #include "kvm/virtio_pci.h"
4b30d05adSPekka Enberg #include "kvm/ioport.h"
5*8b1ff07eSPekka Enberg #include "kvm/kvm.h"
6b30d05adSPekka Enberg #include "kvm/pci.h"
7b30d05adSPekka Enberg 
8*8b1ff07eSPekka Enberg #define VIRTIO_BLK_IRQ		14
9984b7ae0SPekka Enberg 
10fbc2fbf9SPekka Enberg struct device {
11fbc2fbf9SPekka Enberg 	uint32_t		guest_features;
12fbc2fbf9SPekka Enberg 	uint8_t			status;
13fbc2fbf9SPekka Enberg };
14fbc2fbf9SPekka Enberg 
15fbc2fbf9SPekka Enberg static struct device device;
16fbc2fbf9SPekka Enberg 
17fbc2fbf9SPekka Enberg static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
18fbc2fbf9SPekka Enberg {
19fbc2fbf9SPekka Enberg 	unsigned long offset;
20fbc2fbf9SPekka Enberg 
21fbc2fbf9SPekka Enberg 	offset		= port - IOPORT_VIRTIO;
22fbc2fbf9SPekka Enberg 
23*8b1ff07eSPekka Enberg 	/* XXX: Let virtio block device handle this */
24*8b1ff07eSPekka Enberg 	if (offset >= VIRTIO_PCI_CONFIG_NOMSI)
25*8b1ff07eSPekka Enberg 		return true;
26*8b1ff07eSPekka Enberg 
27fbc2fbf9SPekka Enberg 	switch (offset) {
28fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_HOST_FEATURES:
29fbc2fbf9SPekka Enberg 		ioport__write32(data, 0x00);
30fbc2fbf9SPekka Enberg 		break;
31fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_GUEST_FEATURES:
32*8b1ff07eSPekka Enberg 		return false;
33fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_PFN:
34*8b1ff07eSPekka Enberg 		ioport__write32(data, 0x00);
35*8b1ff07eSPekka Enberg 		break;
36fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_NUM:
37*8b1ff07eSPekka Enberg 		ioport__write16(data, 0x10);
38*8b1ff07eSPekka Enberg 		break;
39fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_SEL:
40fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_NOTIFY:
41fbc2fbf9SPekka Enberg 		return false;
42fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_STATUS:
43fbc2fbf9SPekka Enberg 		ioport__write8(data, device.status);
44fbc2fbf9SPekka Enberg 		break;
45fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_ISR:
46*8b1ff07eSPekka Enberg 		ioport__write8(data, 0x1);
47*8b1ff07eSPekka Enberg 		kvm__irq_line(self, VIRTIO_BLK_IRQ, 0);
48*8b1ff07eSPekka Enberg 		return true;
49fbc2fbf9SPekka Enberg 	case VIRTIO_MSI_CONFIG_VECTOR:
50fbc2fbf9SPekka Enberg 	default:
51fbc2fbf9SPekka Enberg 		return false;
52fbc2fbf9SPekka Enberg 	};
53fbc2fbf9SPekka Enberg 
54fbc2fbf9SPekka Enberg 	return true;
55fbc2fbf9SPekka Enberg }
56fbc2fbf9SPekka Enberg 
57fbc2fbf9SPekka Enberg static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
58fbc2fbf9SPekka Enberg {
59fbc2fbf9SPekka Enberg 	unsigned long offset;
60fbc2fbf9SPekka Enberg 
61fbc2fbf9SPekka Enberg 	offset		= port - IOPORT_VIRTIO;
62fbc2fbf9SPekka Enberg 
63*8b1ff07eSPekka Enberg 	/* XXX: Let virtio block device handle this */
64*8b1ff07eSPekka Enberg 	if (offset >= VIRTIO_PCI_CONFIG_NOMSI)
65*8b1ff07eSPekka Enberg 		return true;
66*8b1ff07eSPekka Enberg 
67fbc2fbf9SPekka Enberg 	switch (offset) {
68fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_GUEST_FEATURES:
69fbc2fbf9SPekka Enberg 		device.guest_features	= ioport__read32(data);
70fbc2fbf9SPekka Enberg 		break;
71fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_PFN:
72*8b1ff07eSPekka Enberg 		return true;
73fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_SEL:
74*8b1ff07eSPekka Enberg 		return true;
75*8b1ff07eSPekka Enberg 	case VIRTIO_PCI_QUEUE_NOTIFY: {
76*8b1ff07eSPekka Enberg 		kvm__irq_line(self, VIRTIO_BLK_IRQ, 1);
77*8b1ff07eSPekka Enberg 		return true;
78*8b1ff07eSPekka Enberg 	}
79fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_STATUS:
80fbc2fbf9SPekka Enberg 		device.status		= ioport__read8(data);
81fbc2fbf9SPekka Enberg 		break;
82fbc2fbf9SPekka Enberg 	case VIRTIO_MSI_CONFIG_VECTOR:
83fbc2fbf9SPekka Enberg 	case VIRTIO_MSI_QUEUE_VECTOR:
84fbc2fbf9SPekka Enberg 	default:
85fbc2fbf9SPekka Enberg 		return false;
86fbc2fbf9SPekka Enberg 	};
87fbc2fbf9SPekka Enberg 
88fbc2fbf9SPekka Enberg 	return true;
89fbc2fbf9SPekka Enberg }
90fbc2fbf9SPekka Enberg 
91fbc2fbf9SPekka Enberg static struct ioport_operations blk_virtio_io_ops = {
92fbc2fbf9SPekka Enberg 	.io_in		= blk_virtio_in,
93fbc2fbf9SPekka Enberg 	.io_out		= blk_virtio_out,
94fbc2fbf9SPekka Enberg };
95fbc2fbf9SPekka Enberg 
96b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET		0x1af4
97b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK		0x1001
98b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET	0x1af4
99b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK		0x0002
100b30d05adSPekka Enberg 
101fbc2fbf9SPekka Enberg static struct pci_device_header blk_virtio_pci_device = {
102b30d05adSPekka Enberg 	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
103b30d05adSPekka Enberg 	.device_id		= PCI_DEVICE_ID_VIRTIO_BLK,
104b30d05adSPekka Enberg 	.header_type		= PCI_HEADER_TYPE_NORMAL,
105b30d05adSPekka Enberg 	.revision_id		= 0,
106b30d05adSPekka Enberg 	.class			= 0x010000,
107b30d05adSPekka Enberg 	.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
108b30d05adSPekka Enberg 	.subsys_id		= PCI_SUBSYSTEM_ID_VIRTIO_BLK,
109b30d05adSPekka Enberg 	.bar[0]			= IOPORT_VIRTIO | PCI_BASE_ADDRESS_SPACE_IO,
110*8b1ff07eSPekka Enberg 	/* XXX: Is this IRQ setup OK? */
111*8b1ff07eSPekka Enberg 	.irq_pin		= 1,
112*8b1ff07eSPekka Enberg 	.irq_line		= VIRTIO_BLK_IRQ,
113b30d05adSPekka Enberg };
114b30d05adSPekka Enberg 
115b30d05adSPekka Enberg void blk_virtio__init(void)
116b30d05adSPekka Enberg {
117fbc2fbf9SPekka Enberg 	pci__register(&blk_virtio_pci_device, 1);
118b30d05adSPekka Enberg 
119*8b1ff07eSPekka Enberg 	ioport__register(IOPORT_VIRTIO, &blk_virtio_io_ops, 256);
120b30d05adSPekka Enberg }
121