xref: /kvmtool/virtio/pci.c (revision 36f5dc916e7f0a5bf900aa188c7dbf7c34b55fcc)
1 #include "kvm/virtio-pci.h"
2 
3 #include "kvm/ioport.h"
4 #include "kvm/kvm.h"
5 #include "kvm/virtio-pci-dev.h"
6 #include "kvm/irq.h"
7 #include "kvm/virtio.h"
8 
9 #include <linux/virtio_pci.h>
10 #include <string.h>
11 
12 static bool virtio_pci__specific_io_in(struct kvm *kvm, struct virtio_pci *vpci, u16 port,
13 					void *data, int size, int offset)
14 {
15 	u32 config_offset;
16 	int type = virtio__get_dev_specific_field(offset - 20, vpci->msix_enabled,
17 							0, &config_offset);
18 	if (type == VIRTIO_PCI_O_MSIX) {
19 		switch (offset) {
20 		case VIRTIO_MSI_CONFIG_VECTOR:
21 			ioport__write16(data, vpci->config_vector);
22 			break;
23 		case VIRTIO_MSI_QUEUE_VECTOR:
24 			ioport__write16(data, vpci->vq_vector[vpci->queue_selector]);
25 			break;
26 		};
27 
28 		return true;
29 	} else if (type == VIRTIO_PCI_O_CONFIG) {
30 		u8 cfg;
31 
32 		cfg = vpci->ops.get_config(kvm, vpci->dev, config_offset);
33 		ioport__write8(data, cfg);
34 		return true;
35 	}
36 
37 	return false;
38 }
39 
40 static bool virtio_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
41 {
42 	unsigned long offset;
43 	bool ret = true;
44 	struct virtio_pci *vpci;
45 	u32 val;
46 
47 	vpci = ioport->priv;
48 	offset = port - vpci->base_addr;
49 
50 	switch (offset) {
51 	case VIRTIO_PCI_HOST_FEATURES:
52 		val = vpci->ops.get_host_features(kvm, vpci->dev);
53 		ioport__write32(data, val);
54 		break;
55 	case VIRTIO_PCI_QUEUE_PFN:
56 		val = vpci->ops.get_pfn_vq(kvm, vpci->dev, vpci->queue_selector);
57 		ioport__write32(data, val);
58 		break;
59 	case VIRTIO_PCI_QUEUE_NUM:
60 		val = vpci->ops.get_size_vq(kvm, vpci->dev, vpci->queue_selector);
61 		ioport__write32(data, val);
62 		break;
63 		break;
64 	case VIRTIO_PCI_STATUS:
65 		ioport__write8(data, vpci->status);
66 		break;
67 	case VIRTIO_PCI_ISR:
68 		ioport__write8(data, vpci->isr);
69 		kvm__irq_line(kvm, vpci->pci_hdr.irq_line, VIRTIO_IRQ_LOW);
70 		vpci->isr = VIRTIO_IRQ_LOW;
71 		break;
72 	default:
73 		ret = virtio_pci__specific_io_in(kvm, vpci, port, data, size, offset);
74 		break;
75 	};
76 
77 	return ret;
78 }
79 
80 static bool virtio_pci__specific_io_out(struct kvm *kvm, struct virtio_pci *vpci, u16 port,
81 					void *data, int size, int offset)
82 {
83 	u32 config_offset, gsi, vec;
84 	int type = virtio__get_dev_specific_field(offset - 20, vpci->msix_enabled,
85 							0, &config_offset);
86 	if (type == VIRTIO_PCI_O_MSIX) {
87 		switch (offset) {
88 		case VIRTIO_MSI_CONFIG_VECTOR:
89 			vec = vpci->config_vector = ioport__read16(data);
90 
91 			gsi = irq__add_msix_route(kvm,
92 						  vpci->pci_hdr.msix.table[vec].low,
93 						  vpci->pci_hdr.msix.table[vec].high,
94 						  vpci->pci_hdr.msix.table[vec].data);
95 
96 			vpci->config_gsi = gsi;
97 			break;
98 		case VIRTIO_MSI_QUEUE_VECTOR: {
99 			vec = vpci->vq_vector[vpci->queue_selector] = ioport__read16(data);
100 
101 			gsi = irq__add_msix_route(kvm,
102 						  vpci->pci_hdr.msix.table[vec].low,
103 						  vpci->pci_hdr.msix.table[vec].high,
104 						  vpci->pci_hdr.msix.table[vec].data);
105 			vpci->gsis[vpci->queue_selector] = gsi;
106 			break;
107 		}
108 		};
109 
110 		return true;
111 	} else if (type == VIRTIO_PCI_O_CONFIG) {
112 		vpci->ops.set_config(kvm, vpci->dev, *(u8 *)data, config_offset);
113 
114 		return true;
115 	}
116 
117 	return false;
118 }
119 
120 static bool virtio_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
121 {
122 	unsigned long offset;
123 	bool ret = true;
124 	struct virtio_pci *vpci;
125 	u32 val;
126 
127 	vpci = ioport->priv;
128 	offset = port - vpci->base_addr;
129 
130 	switch (offset) {
131 	case VIRTIO_PCI_GUEST_FEATURES:
132 		val = ioport__read32(data);
133 		vpci->ops.set_guest_features(kvm, vpci, val);
134 		break;
135 	case VIRTIO_PCI_QUEUE_PFN:
136 		val = ioport__read32(data);
137 		vpci->ops.init_vq(kvm, vpci->dev, vpci->queue_selector, val);
138 		break;
139 	case VIRTIO_PCI_QUEUE_SEL:
140 		vpci->queue_selector	= ioport__read16(data);
141 		break;
142 	case VIRTIO_PCI_QUEUE_NOTIFY:
143 		val			= ioport__read16(data);
144 		vpci->ops.notify_vq(kvm, vpci->dev, val);
145 		break;
146 	case VIRTIO_PCI_STATUS:
147 		vpci->status		= ioport__read8(data);
148 		break;
149 	default:
150 		ret = virtio_pci__specific_io_out(kvm, vpci, port, data, size, offset);
151 		break;
152 	};
153 
154 	return ret;
155 }
156 
157 static struct ioport_operations virtio_pci__io_ops = {
158 	.io_in	= virtio_pci__io_in,
159 	.io_out	= virtio_pci__io_out,
160 };
161 
162 static void callback_mmio(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr)
163 {
164 	struct virtio_pci *vpci = ptr;
165 	void *table = &vpci->pci_hdr.msix.table;
166 
167 	vpci->msix_enabled = 1;
168 	if (is_write)
169 		memcpy(table + addr - vpci->msix_io_block, data, len);
170 	else
171 		memcpy(data, table + addr - vpci->msix_io_block, len);
172 }
173 
174 int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_pci *vpci, u32 vq)
175 {
176 	kvm__irq_line(kvm, vpci->gsis[vq], VIRTIO_IRQ_HIGH);
177 
178 	return 0;
179 }
180 
181 int virtio_pci__signal_config(struct kvm *kvm, struct virtio_pci *vpci)
182 {
183 	kvm__irq_line(kvm, vpci->config_gsi, VIRTIO_IRQ_HIGH);
184 
185 	return 0;
186 }
187 
188 int virtio_pci__init(struct kvm *kvm, struct virtio_pci *vpci, void *dev,
189 			int device_id, int subsys_id)
190 {
191 	u8 pin, line, ndev;
192 
193 	vpci->dev = dev;
194 	vpci->msix_io_block = pci_get_io_space_block();
195 
196 	vpci->base_addr = ioport__register(IOPORT_EMPTY, &virtio_pci__io_ops, IOPORT_SIZE, vpci);
197 	kvm__register_mmio(kvm, vpci->msix_io_block, 0x100, callback_mmio, vpci);
198 
199 	vpci->pci_hdr = (struct pci_device_header) {
200 		.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
201 		.device_id		= device_id,
202 		.header_type		= PCI_HEADER_TYPE_NORMAL,
203 		.revision_id		= 0,
204 		.class			= 0x010000,
205 		.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
206 		.subsys_id		= subsys_id,
207 		.bar[0]			= vpci->base_addr | PCI_BASE_ADDRESS_SPACE_IO,
208 		.bar[1]			= vpci->msix_io_block |
209 					PCI_BASE_ADDRESS_SPACE_MEMORY |
210 					PCI_BASE_ADDRESS_MEM_TYPE_64,
211 		/* bar[2] is the continuation of bar[1] for 64bit addressing */
212 		.bar[2]			= 0,
213 		.status			= PCI_STATUS_CAP_LIST,
214 		.capabilities		= (void *)&vpci->pci_hdr.msix - (void *)&vpci->pci_hdr,
215 	};
216 
217 	vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX;
218 	vpci->pci_hdr.msix.next = 0;
219 	vpci->pci_hdr.msix.table_size = (VIRTIO_PCI_MAX_VQ + 1) | PCI_MSIX_FLAGS_ENABLE;
220 	vpci->pci_hdr.msix.table_offset = 1; /* Use BAR 1 */
221 	vpci->config_vector = 0;
222 
223 	if (irq__register_device(VIRTIO_ID_RNG, &ndev, &pin, &line) < 0)
224 		return -1;
225 
226 	vpci->pci_hdr.irq_pin	= pin;
227 	vpci->pci_hdr.irq_line	= line;
228 	pci__register(&vpci->pci_hdr, ndev);
229 
230 	return 0;
231 }
232