]>
Commit | Line | Data |
---|---|---|
53c25cea PB |
1 | /* |
2 | * Virtio PCI Bindings | |
3 | * | |
4 | * Copyright IBM, Corp. 2007 | |
5 | * Copyright (c) 2009 CodeSourcery | |
6 | * | |
7 | * Authors: | |
8 | * Anthony Liguori <aliguori@us.ibm.com> | |
9 | * Paul Brook <paul@codesourcery.com> | |
10 | * | |
11 | * This work is licensed under the terms of the GNU GPL, version 2. See | |
12 | * the COPYING file in the top-level directory. | |
13 | * | |
6b620ca3 PB |
14 | * Contributions after 2012-01-13 are licensed under the terms of the |
15 | * GNU GPL, version 2 or (at your option) any later version. | |
53c25cea PB |
16 | */ |
17 | ||
18 | #include <inttypes.h> | |
19 | ||
0d09e41a PB |
20 | #include "hw/virtio/virtio.h" |
21 | #include "hw/virtio/virtio-blk.h" | |
22 | #include "hw/virtio/virtio-net.h" | |
23 | #include "hw/virtio/virtio-serial.h" | |
24 | #include "hw/virtio/virtio-scsi.h" | |
25 | #include "hw/virtio/virtio-balloon.h" | |
83c9f4ca | 26 | #include "hw/pci/pci.h" |
1de7afc9 | 27 | #include "qemu/error-report.h" |
83c9f4ca PB |
28 | #include "hw/pci/msi.h" |
29 | #include "hw/pci/msix.h" | |
30 | #include "hw/loader.h" | |
9c17d615 PB |
31 | #include "sysemu/kvm.h" |
32 | #include "sysemu/blockdev.h" | |
47b43a1f | 33 | #include "virtio-pci.h" |
1de7afc9 | 34 | #include "qemu/range.h" |
0d09e41a | 35 | #include "hw/virtio/virtio-bus.h" |
24a6e7f4 | 36 | #include "qapi/visitor.h" |
53c25cea PB |
37 | |
38 | /* from Linux's linux/virtio_pci.h */ | |
39 | ||
40 | /* A 32-bit r/o bitmask of the features supported by the host */ | |
41 | #define VIRTIO_PCI_HOST_FEATURES 0 | |
42 | ||
43 | /* A 32-bit r/w bitmask of features activated by the guest */ | |
44 | #define VIRTIO_PCI_GUEST_FEATURES 4 | |
45 | ||
46 | /* A 32-bit r/w PFN for the currently selected queue */ | |
47 | #define VIRTIO_PCI_QUEUE_PFN 8 | |
48 | ||
49 | /* A 16-bit r/o queue size for the currently selected queue */ | |
50 | #define VIRTIO_PCI_QUEUE_NUM 12 | |
51 | ||
52 | /* A 16-bit r/w queue selector */ | |
53 | #define VIRTIO_PCI_QUEUE_SEL 14 | |
54 | ||
55 | /* A 16-bit r/w queue notifier */ | |
56 | #define VIRTIO_PCI_QUEUE_NOTIFY 16 | |
57 | ||
58 | /* An 8-bit device status register. */ | |
59 | #define VIRTIO_PCI_STATUS 18 | |
60 | ||
61 | /* An 8-bit r/o interrupt status register. Reading the value will return the | |
62 | * current contents of the ISR and will also clear it. This is effectively | |
63 | * a read-and-acknowledge. */ | |
64 | #define VIRTIO_PCI_ISR 19 | |
65 | ||
aba800a3 MT |
66 | /* MSI-X registers: only enabled if MSI-X is enabled. */ |
67 | /* A 16-bit vector for configuration changes. */ | |
68 | #define VIRTIO_MSI_CONFIG_VECTOR 20 | |
69 | /* A 16-bit vector for selected queue notifications. */ | |
70 | #define VIRTIO_MSI_QUEUE_VECTOR 22 | |
71 | ||
72 | /* Config space size */ | |
73 | #define VIRTIO_PCI_CONFIG_NOMSI 20 | |
74 | #define VIRTIO_PCI_CONFIG_MSI 24 | |
75 | #define VIRTIO_PCI_REGION_SIZE(dev) (msix_present(dev) ? \ | |
76 | VIRTIO_PCI_CONFIG_MSI : \ | |
77 | VIRTIO_PCI_CONFIG_NOMSI) | |
78 | ||
79 | /* The remaining space is defined by each driver as the per-driver | |
80 | * configuration space */ | |
81 | #define VIRTIO_PCI_CONFIG(dev) (msix_enabled(dev) ? \ | |
82 | VIRTIO_PCI_CONFIG_MSI : \ | |
83 | VIRTIO_PCI_CONFIG_NOMSI) | |
53c25cea | 84 | |
53c25cea PB |
85 | /* How many bits to shift physical queue address written to QUEUE_PFN. |
86 | * 12 is historical, and due to x86 page size. */ | |
87 | #define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12 | |
88 | ||
3dbca8e6 SH |
89 | /* Flags track per-device state like workarounds for quirks in older guests. */ |
90 | #define VIRTIO_PCI_FLAG_BUS_MASTER_BUG (1 << 0) | |
c81131db | 91 | |
53c25cea PB |
92 | /* QEMU doesn't strictly need write barriers since everything runs in |
93 | * lock-step. We'll leave the calls to wmb() in though to make it obvious for | |
94 | * KVM or if kqemu gets SMP support. | |
95 | */ | |
96 | #define wmb() do { } while (0) | |
97 | ||
8e4a424b BS |
98 | /* HACK for virtio to determine if it's running a big endian guest */ |
99 | bool virtio_is_big_endian(void); | |
100 | ||
53c25cea | 101 | /* virtio device */ |
d2a0ccc6 MT |
102 | /* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */ |
103 | static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d) | |
104 | { | |
105 | return container_of(d, VirtIOPCIProxy, pci_dev.qdev); | |
106 | } | |
53c25cea | 107 | |
d2a0ccc6 MT |
108 | /* DeviceState to VirtIOPCIProxy. Note: used on datapath, |
109 | * be careful and test performance if you change this. | |
110 | */ | |
111 | static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d) | |
53c25cea | 112 | { |
d2a0ccc6 MT |
113 | return container_of(d, VirtIOPCIProxy, pci_dev.qdev); |
114 | } | |
115 | ||
116 | static void virtio_pci_notify(DeviceState *d, uint16_t vector) | |
117 | { | |
118 | VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d); | |
aba800a3 MT |
119 | if (msix_enabled(&proxy->pci_dev)) |
120 | msix_notify(&proxy->pci_dev, vector); | |
121 | else | |
122 | qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1); | |
53c25cea PB |
123 | } |
124 | ||
d2a0ccc6 | 125 | static void virtio_pci_save_config(DeviceState *d, QEMUFile *f) |
ff24bd58 | 126 | { |
d2a0ccc6 | 127 | VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); |
ff24bd58 MT |
128 | pci_device_save(&proxy->pci_dev, f); |
129 | msix_save(&proxy->pci_dev, f); | |
130 | if (msix_present(&proxy->pci_dev)) | |
131 | qemu_put_be16(f, proxy->vdev->config_vector); | |
132 | } | |
133 | ||
d2a0ccc6 | 134 | static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f) |
ff24bd58 | 135 | { |
d2a0ccc6 | 136 | VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); |
ff24bd58 MT |
137 | if (msix_present(&proxy->pci_dev)) |
138 | qemu_put_be16(f, virtio_queue_vector(proxy->vdev, n)); | |
139 | } | |
140 | ||
d2a0ccc6 | 141 | static int virtio_pci_load_config(DeviceState *d, QEMUFile *f) |
ff24bd58 | 142 | { |
d2a0ccc6 | 143 | VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); |
ff24bd58 MT |
144 | int ret; |
145 | ret = pci_device_load(&proxy->pci_dev, f); | |
e6da7680 | 146 | if (ret) { |
ff24bd58 | 147 | return ret; |
e6da7680 | 148 | } |
3cac001e | 149 | msix_unuse_all_vectors(&proxy->pci_dev); |
ff24bd58 | 150 | msix_load(&proxy->pci_dev, f); |
e6da7680 | 151 | if (msix_present(&proxy->pci_dev)) { |
ff24bd58 | 152 | qemu_get_be16s(f, &proxy->vdev->config_vector); |
e6da7680 MT |
153 | } else { |
154 | proxy->vdev->config_vector = VIRTIO_NO_VECTOR; | |
155 | } | |
156 | if (proxy->vdev->config_vector != VIRTIO_NO_VECTOR) { | |
157 | return msix_vector_use(&proxy->pci_dev, proxy->vdev->config_vector); | |
158 | } | |
ff24bd58 MT |
159 | return 0; |
160 | } | |
161 | ||
d2a0ccc6 | 162 | static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f) |
ff24bd58 | 163 | { |
d2a0ccc6 | 164 | VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); |
ff24bd58 | 165 | uint16_t vector; |
e6da7680 MT |
166 | if (msix_present(&proxy->pci_dev)) { |
167 | qemu_get_be16s(f, &vector); | |
168 | } else { | |
169 | vector = VIRTIO_NO_VECTOR; | |
170 | } | |
ff24bd58 | 171 | virtio_queue_set_vector(proxy->vdev, n, vector); |
e6da7680 MT |
172 | if (vector != VIRTIO_NO_VECTOR) { |
173 | return msix_vector_use(&proxy->pci_dev, vector); | |
174 | } | |
ff24bd58 MT |
175 | return 0; |
176 | } | |
177 | ||
25db9ebe | 178 | static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy, |
26b9b5fe | 179 | int n, bool assign, bool set_handler) |
25db9ebe SH |
180 | { |
181 | VirtQueue *vq = virtio_get_queue(proxy->vdev, n); | |
182 | EventNotifier *notifier = virtio_queue_get_host_notifier(vq); | |
da146d0a AK |
183 | int r = 0; |
184 | ||
25db9ebe SH |
185 | if (assign) { |
186 | r = event_notifier_init(notifier, 1); | |
187 | if (r < 0) { | |
b36e3914 MT |
188 | error_report("%s: unable to init event notifier: %d", |
189 | __func__, r); | |
25db9ebe SH |
190 | return r; |
191 | } | |
26b9b5fe | 192 | virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler); |
da146d0a | 193 | memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2, |
753d5e14 | 194 | true, n, notifier); |
25db9ebe | 195 | } else { |
da146d0a | 196 | memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2, |
753d5e14 | 197 | true, n, notifier); |
26b9b5fe | 198 | virtio_queue_set_host_notifier_fd_handler(vq, false, false); |
25db9ebe SH |
199 | event_notifier_cleanup(notifier); |
200 | } | |
201 | return r; | |
202 | } | |
203 | ||
b36e3914 | 204 | static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy) |
25db9ebe SH |
205 | { |
206 | int n, r; | |
207 | ||
208 | if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) || | |
209 | proxy->ioeventfd_disabled || | |
210 | proxy->ioeventfd_started) { | |
b36e3914 | 211 | return; |
25db9ebe SH |
212 | } |
213 | ||
214 | for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { | |
215 | if (!virtio_queue_get_num(proxy->vdev, n)) { | |
216 | continue; | |
217 | } | |
218 | ||
26b9b5fe | 219 | r = virtio_pci_set_host_notifier_internal(proxy, n, true, true); |
25db9ebe SH |
220 | if (r < 0) { |
221 | goto assign_error; | |
222 | } | |
25db9ebe SH |
223 | } |
224 | proxy->ioeventfd_started = true; | |
b36e3914 | 225 | return; |
25db9ebe SH |
226 | |
227 | assign_error: | |
228 | while (--n >= 0) { | |
229 | if (!virtio_queue_get_num(proxy->vdev, n)) { | |
230 | continue; | |
231 | } | |
232 | ||
26b9b5fe | 233 | r = virtio_pci_set_host_notifier_internal(proxy, n, false, false); |
b36e3914 | 234 | assert(r >= 0); |
25db9ebe SH |
235 | } |
236 | proxy->ioeventfd_started = false; | |
b36e3914 | 237 | error_report("%s: failed. Fallback to a userspace (slower).", __func__); |
25db9ebe SH |
238 | } |
239 | ||
b36e3914 | 240 | static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy) |
25db9ebe | 241 | { |
b36e3914 | 242 | int r; |
25db9ebe SH |
243 | int n; |
244 | ||
245 | if (!proxy->ioeventfd_started) { | |
b36e3914 | 246 | return; |
25db9ebe SH |
247 | } |
248 | ||
249 | for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { | |
250 | if (!virtio_queue_get_num(proxy->vdev, n)) { | |
251 | continue; | |
252 | } | |
253 | ||
26b9b5fe | 254 | r = virtio_pci_set_host_notifier_internal(proxy, n, false, false); |
b36e3914 | 255 | assert(r >= 0); |
25db9ebe SH |
256 | } |
257 | proxy->ioeventfd_started = false; | |
25db9ebe SH |
258 | } |
259 | ||
53c25cea PB |
260 | static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
261 | { | |
262 | VirtIOPCIProxy *proxy = opaque; | |
263 | VirtIODevice *vdev = proxy->vdev; | |
a8170e5e | 264 | hwaddr pa; |
53c25cea | 265 | |
53c25cea PB |
266 | switch (addr) { |
267 | case VIRTIO_PCI_GUEST_FEATURES: | |
268 | /* Guest does not negotiate properly? We have to assume nothing. */ | |
269 | if (val & (1 << VIRTIO_F_BAD_FEATURE)) { | |
ad0c9332 | 270 | val = vdev->bad_features ? vdev->bad_features(vdev) : 0; |
53c25cea | 271 | } |
ad0c9332 | 272 | virtio_set_features(vdev, val); |
53c25cea PB |
273 | break; |
274 | case VIRTIO_PCI_QUEUE_PFN: | |
a8170e5e | 275 | pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; |
1b8e9b27 | 276 | if (pa == 0) { |
25db9ebe | 277 | virtio_pci_stop_ioeventfd(proxy); |
1b8e9b27 MT |
278 | virtio_reset(proxy->vdev); |
279 | msix_unuse_all_vectors(&proxy->pci_dev); | |
280 | } | |
7055e687 MT |
281 | else |
282 | virtio_queue_set_addr(vdev, vdev->queue_sel, pa); | |
53c25cea PB |
283 | break; |
284 | case VIRTIO_PCI_QUEUE_SEL: | |
285 | if (val < VIRTIO_PCI_QUEUE_MAX) | |
286 | vdev->queue_sel = val; | |
287 | break; | |
288 | case VIRTIO_PCI_QUEUE_NOTIFY: | |
7157e2e2 SH |
289 | if (val < VIRTIO_PCI_QUEUE_MAX) { |
290 | virtio_queue_notify(vdev, val); | |
291 | } | |
53c25cea PB |
292 | break; |
293 | case VIRTIO_PCI_STATUS: | |
25db9ebe SH |
294 | if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) { |
295 | virtio_pci_stop_ioeventfd(proxy); | |
296 | } | |
297 | ||
3e607cb5 | 298 | virtio_set_status(vdev, val & 0xFF); |
25db9ebe SH |
299 | |
300 | if (val & VIRTIO_CONFIG_S_DRIVER_OK) { | |
301 | virtio_pci_start_ioeventfd(proxy); | |
302 | } | |
303 | ||
1b8e9b27 MT |
304 | if (vdev->status == 0) { |
305 | virtio_reset(proxy->vdev); | |
306 | msix_unuse_all_vectors(&proxy->pci_dev); | |
307 | } | |
c81131db AG |
308 | |
309 | /* Linux before 2.6.34 sets the device as OK without enabling | |
310 | the PCI device bus master bit. In this case we need to disable | |
311 | some safety checks. */ | |
312 | if ((val & VIRTIO_CONFIG_S_DRIVER_OK) && | |
313 | !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { | |
3dbca8e6 | 314 | proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG; |
c81131db | 315 | } |
53c25cea | 316 | break; |
aba800a3 MT |
317 | case VIRTIO_MSI_CONFIG_VECTOR: |
318 | msix_vector_unuse(&proxy->pci_dev, vdev->config_vector); | |
319 | /* Make it possible for guest to discover an error took place. */ | |
320 | if (msix_vector_use(&proxy->pci_dev, val) < 0) | |
321 | val = VIRTIO_NO_VECTOR; | |
322 | vdev->config_vector = val; | |
323 | break; | |
324 | case VIRTIO_MSI_QUEUE_VECTOR: | |
325 | msix_vector_unuse(&proxy->pci_dev, | |
326 | virtio_queue_vector(vdev, vdev->queue_sel)); | |
327 | /* Make it possible for guest to discover an error took place. */ | |
328 | if (msix_vector_use(&proxy->pci_dev, val) < 0) | |
329 | val = VIRTIO_NO_VECTOR; | |
330 | virtio_queue_set_vector(vdev, vdev->queue_sel, val); | |
331 | break; | |
332 | default: | |
4e02d460 SH |
333 | error_report("%s: unexpected address 0x%x value 0x%x", |
334 | __func__, addr, val); | |
aba800a3 | 335 | break; |
53c25cea PB |
336 | } |
337 | } | |
338 | ||
aba800a3 | 339 | static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr) |
53c25cea | 340 | { |
53c25cea PB |
341 | VirtIODevice *vdev = proxy->vdev; |
342 | uint32_t ret = 0xFFFFFFFF; | |
343 | ||
53c25cea PB |
344 | switch (addr) { |
345 | case VIRTIO_PCI_HOST_FEATURES: | |
8172539d | 346 | ret = proxy->host_features; |
53c25cea PB |
347 | break; |
348 | case VIRTIO_PCI_GUEST_FEATURES: | |
704a76fc | 349 | ret = vdev->guest_features; |
53c25cea PB |
350 | break; |
351 | case VIRTIO_PCI_QUEUE_PFN: | |
352 | ret = virtio_queue_get_addr(vdev, vdev->queue_sel) | |
353 | >> VIRTIO_PCI_QUEUE_ADDR_SHIFT; | |
354 | break; | |
355 | case VIRTIO_PCI_QUEUE_NUM: | |
356 | ret = virtio_queue_get_num(vdev, vdev->queue_sel); | |
357 | break; | |
358 | case VIRTIO_PCI_QUEUE_SEL: | |
359 | ret = vdev->queue_sel; | |
360 | break; | |
361 | case VIRTIO_PCI_STATUS: | |
362 | ret = vdev->status; | |
363 | break; | |
364 | case VIRTIO_PCI_ISR: | |
365 | /* reading from the ISR also clears it. */ | |
366 | ret = vdev->isr; | |
367 | vdev->isr = 0; | |
7055e687 | 368 | qemu_set_irq(proxy->pci_dev.irq[0], 0); |
53c25cea | 369 | break; |
aba800a3 MT |
370 | case VIRTIO_MSI_CONFIG_VECTOR: |
371 | ret = vdev->config_vector; | |
372 | break; | |
373 | case VIRTIO_MSI_QUEUE_VECTOR: | |
374 | ret = virtio_queue_vector(vdev, vdev->queue_sel); | |
375 | break; | |
53c25cea PB |
376 | default: |
377 | break; | |
378 | } | |
379 | ||
380 | return ret; | |
381 | } | |
382 | ||
df6db5b3 AG |
383 | static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr, |
384 | unsigned size) | |
53c25cea PB |
385 | { |
386 | VirtIOPCIProxy *proxy = opaque; | |
aba800a3 | 387 | uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); |
df6db5b3 | 388 | uint64_t val = 0; |
aba800a3 | 389 | if (addr < config) { |
df6db5b3 | 390 | return virtio_ioport_read(proxy, addr); |
aba800a3 MT |
391 | } |
392 | addr -= config; | |
53c25cea | 393 | |
df6db5b3 AG |
394 | switch (size) { |
395 | case 1: | |
396 | val = virtio_config_readb(proxy->vdev, addr); | |
397 | break; | |
398 | case 2: | |
399 | val = virtio_config_readw(proxy->vdev, addr); | |
8e4a424b BS |
400 | if (virtio_is_big_endian()) { |
401 | val = bswap16(val); | |
402 | } | |
df6db5b3 AG |
403 | break; |
404 | case 4: | |
405 | val = virtio_config_readl(proxy->vdev, addr); | |
8e4a424b BS |
406 | if (virtio_is_big_endian()) { |
407 | val = bswap32(val); | |
408 | } | |
df6db5b3 | 409 | break; |
82afa586 | 410 | } |
df6db5b3 | 411 | return val; |
53c25cea PB |
412 | } |
413 | ||
df6db5b3 AG |
414 | static void virtio_pci_config_write(void *opaque, hwaddr addr, |
415 | uint64_t val, unsigned size) | |
53c25cea PB |
416 | { |
417 | VirtIOPCIProxy *proxy = opaque; | |
aba800a3 | 418 | uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); |
aba800a3 MT |
419 | if (addr < config) { |
420 | virtio_ioport_write(proxy, addr, val); | |
421 | return; | |
422 | } | |
423 | addr -= config; | |
df6db5b3 AG |
424 | /* |
425 | * Virtio-PCI is odd. Ioports are LE but config space is target native | |
426 | * endian. | |
427 | */ | |
428 | switch (size) { | |
429 | case 1: | |
430 | virtio_config_writeb(proxy->vdev, addr, val); | |
431 | break; | |
432 | case 2: | |
8e4a424b BS |
433 | if (virtio_is_big_endian()) { |
434 | val = bswap16(val); | |
435 | } | |
df6db5b3 AG |
436 | virtio_config_writew(proxy->vdev, addr, val); |
437 | break; | |
438 | case 4: | |
8e4a424b BS |
439 | if (virtio_is_big_endian()) { |
440 | val = bswap32(val); | |
441 | } | |
df6db5b3 AG |
442 | virtio_config_writel(proxy->vdev, addr, val); |
443 | break; | |
82afa586 | 444 | } |
53c25cea PB |
445 | } |
446 | ||
da146d0a | 447 | static const MemoryRegionOps virtio_pci_config_ops = { |
df6db5b3 AG |
448 | .read = virtio_pci_config_read, |
449 | .write = virtio_pci_config_write, | |
450 | .impl = { | |
451 | .min_access_size = 1, | |
452 | .max_access_size = 4, | |
453 | }, | |
8e4a424b | 454 | .endianness = DEVICE_LITTLE_ENDIAN, |
da146d0a | 455 | }; |
aba800a3 MT |
456 | |
457 | static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, | |
458 | uint32_t val, int len) | |
459 | { | |
ed757e14 YV |
460 | VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); |
461 | ||
1129714f MT |
462 | pci_default_write_config(pci_dev, address, val, len); |
463 | ||
464 | if (range_covers_byte(address, len, PCI_COMMAND) && | |
465 | !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) && | |
466 | !(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) { | |
467 | virtio_pci_stop_ioeventfd(proxy); | |
468 | virtio_set_status(proxy->vdev, | |
469 | proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK); | |
ed757e14 | 470 | } |
53c25cea PB |
471 | } |
472 | ||
d2a0ccc6 | 473 | static unsigned virtio_pci_get_features(DeviceState *d) |
6d74ca5a | 474 | { |
d2a0ccc6 | 475 | VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); |
8172539d | 476 | return proxy->host_features; |
6d74ca5a MT |
477 | } |
478 | ||
7d37d351 JK |
479 | static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, |
480 | unsigned int queue_no, | |
481 | unsigned int vector, | |
482 | MSIMessage msg) | |
483 | { | |
7d37d351 | 484 | VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; |
15b2bd18 | 485 | int ret; |
7d37d351 JK |
486 | |
487 | if (irqfd->users == 0) { | |
488 | ret = kvm_irqchip_add_msi_route(kvm_state, msg); | |
489 | if (ret < 0) { | |
490 | return ret; | |
491 | } | |
492 | irqfd->virq = ret; | |
493 | } | |
494 | irqfd->users++; | |
7d37d351 JK |
495 | return 0; |
496 | } | |
497 | ||
498 | static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, | |
7d37d351 | 499 | unsigned int vector) |
774345f9 MT |
500 | { |
501 | VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; | |
502 | if (--irqfd->users == 0) { | |
503 | kvm_irqchip_release_virq(kvm_state, irqfd->virq); | |
504 | } | |
505 | } | |
506 | ||
f1d0f15a MT |
507 | static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, |
508 | unsigned int queue_no, | |
509 | unsigned int vector) | |
510 | { | |
511 | VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; | |
512 | VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); | |
513 | EventNotifier *n = virtio_queue_get_guest_notifier(vq); | |
514 | int ret; | |
515 | ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq); | |
516 | return ret; | |
517 | } | |
518 | ||
519 | static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, | |
520 | unsigned int queue_no, | |
521 | unsigned int vector) | |
7d37d351 JK |
522 | { |
523 | VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); | |
15b2bd18 | 524 | EventNotifier *n = virtio_queue_get_guest_notifier(vq); |
7d37d351 | 525 | VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; |
15b2bd18 | 526 | int ret; |
7d37d351 | 527 | |
b131c74a | 528 | ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq); |
7d37d351 | 529 | assert(ret == 0); |
f1d0f15a | 530 | } |
7d37d351 | 531 | |
774345f9 MT |
532 | static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) |
533 | { | |
534 | PCIDevice *dev = &proxy->pci_dev; | |
535 | VirtIODevice *vdev = proxy->vdev; | |
536 | unsigned int vector; | |
537 | int ret, queue_no; | |
538 | MSIMessage msg; | |
539 | ||
540 | for (queue_no = 0; queue_no < nvqs; queue_no++) { | |
541 | if (!virtio_queue_get_num(vdev, queue_no)) { | |
542 | break; | |
543 | } | |
544 | vector = virtio_queue_vector(vdev, queue_no); | |
545 | if (vector >= msix_nr_vectors_allocated(dev)) { | |
546 | continue; | |
547 | } | |
548 | msg = msix_get_message(dev, vector); | |
549 | ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg); | |
550 | if (ret < 0) { | |
551 | goto undo; | |
7d37d351 | 552 | } |
f1d0f15a MT |
553 | /* If guest supports masking, set up irqfd now. |
554 | * Otherwise, delay until unmasked in the frontend. | |
555 | */ | |
556 | if (proxy->vdev->guest_notifier_mask) { | |
557 | ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); | |
558 | if (ret < 0) { | |
559 | kvm_virtio_pci_vq_vector_release(proxy, vector); | |
560 | goto undo; | |
561 | } | |
562 | } | |
7d37d351 | 563 | } |
7d37d351 | 564 | return 0; |
774345f9 MT |
565 | |
566 | undo: | |
567 | while (--queue_no >= 0) { | |
568 | vector = virtio_queue_vector(vdev, queue_no); | |
569 | if (vector >= msix_nr_vectors_allocated(dev)) { | |
570 | continue; | |
571 | } | |
f1d0f15a | 572 | if (proxy->vdev->guest_notifier_mask) { |
e387f99e | 573 | kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); |
f1d0f15a | 574 | } |
774345f9 MT |
575 | kvm_virtio_pci_vq_vector_release(proxy, vector); |
576 | } | |
577 | return ret; | |
7d37d351 JK |
578 | } |
579 | ||
774345f9 MT |
580 | static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) |
581 | { | |
582 | PCIDevice *dev = &proxy->pci_dev; | |
583 | VirtIODevice *vdev = proxy->vdev; | |
584 | unsigned int vector; | |
585 | int queue_no; | |
586 | ||
587 | for (queue_no = 0; queue_no < nvqs; queue_no++) { | |
588 | if (!virtio_queue_get_num(vdev, queue_no)) { | |
589 | break; | |
590 | } | |
591 | vector = virtio_queue_vector(vdev, queue_no); | |
592 | if (vector >= msix_nr_vectors_allocated(dev)) { | |
593 | continue; | |
594 | } | |
f1d0f15a MT |
595 | /* If guest supports masking, clean up irqfd now. |
596 | * Otherwise, it was cleaned when masked in the frontend. | |
597 | */ | |
598 | if (proxy->vdev->guest_notifier_mask) { | |
e387f99e | 599 | kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); |
f1d0f15a | 600 | } |
774345f9 MT |
601 | kvm_virtio_pci_vq_vector_release(proxy, vector); |
602 | } | |
603 | } | |
604 | ||
a38b2c49 MT |
605 | static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, |
606 | unsigned int queue_no, | |
607 | unsigned int vector, | |
608 | MSIMessage msg) | |
774345f9 MT |
609 | { |
610 | VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); | |
611 | EventNotifier *n = virtio_queue_get_guest_notifier(vq); | |
a38b2c49 | 612 | VirtIOIRQFD *irqfd; |
53510bfc | 613 | int ret = 0; |
774345f9 | 614 | |
a38b2c49 MT |
615 | if (proxy->vector_irqfd) { |
616 | irqfd = &proxy->vector_irqfd[vector]; | |
617 | if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) { | |
618 | ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg); | |
619 | if (ret < 0) { | |
620 | return ret; | |
621 | } | |
774345f9 MT |
622 | } |
623 | } | |
624 | ||
f1d0f15a MT |
625 | /* If guest supports masking, irqfd is already setup, unmask it. |
626 | * Otherwise, set it up now. | |
627 | */ | |
628 | if (proxy->vdev->guest_notifier_mask) { | |
629 | proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, false); | |
630 | /* Test after unmasking to avoid losing events. */ | |
631 | if (proxy->vdev->guest_notifier_pending && | |
632 | proxy->vdev->guest_notifier_pending(proxy->vdev, queue_no)) { | |
633 | event_notifier_set(n); | |
634 | } | |
635 | } else { | |
636 | ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); | |
7d37d351 | 637 | } |
774345f9 | 638 | return ret; |
7d37d351 JK |
639 | } |
640 | ||
a38b2c49 | 641 | static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, |
7d37d351 JK |
642 | unsigned int queue_no, |
643 | unsigned int vector) | |
644 | { | |
f1d0f15a MT |
645 | /* If guest supports masking, keep irqfd but mask it. |
646 | * Otherwise, clean it up now. | |
647 | */ | |
648 | if (proxy->vdev->guest_notifier_mask) { | |
649 | proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, true); | |
650 | } else { | |
e387f99e | 651 | kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); |
f1d0f15a | 652 | } |
7d37d351 JK |
653 | } |
654 | ||
a38b2c49 MT |
655 | static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, |
656 | MSIMessage msg) | |
7d37d351 JK |
657 | { |
658 | VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); | |
659 | VirtIODevice *vdev = proxy->vdev; | |
660 | int ret, queue_no; | |
661 | ||
2d620f59 | 662 | for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { |
7d37d351 JK |
663 | if (!virtio_queue_get_num(vdev, queue_no)) { |
664 | break; | |
665 | } | |
666 | if (virtio_queue_vector(vdev, queue_no) != vector) { | |
667 | continue; | |
668 | } | |
a38b2c49 | 669 | ret = virtio_pci_vq_vector_unmask(proxy, queue_no, vector, msg); |
7d37d351 JK |
670 | if (ret < 0) { |
671 | goto undo; | |
672 | } | |
673 | } | |
674 | return 0; | |
675 | ||
676 | undo: | |
677 | while (--queue_no >= 0) { | |
678 | if (virtio_queue_vector(vdev, queue_no) != vector) { | |
679 | continue; | |
680 | } | |
a38b2c49 | 681 | virtio_pci_vq_vector_mask(proxy, queue_no, vector); |
7d37d351 JK |
682 | } |
683 | return ret; | |
684 | } | |
685 | ||
a38b2c49 | 686 | static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) |
7d37d351 JK |
687 | { |
688 | VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); | |
689 | VirtIODevice *vdev = proxy->vdev; | |
690 | int queue_no; | |
691 | ||
2d620f59 | 692 | for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { |
7d37d351 JK |
693 | if (!virtio_queue_get_num(vdev, queue_no)) { |
694 | break; | |
695 | } | |
696 | if (virtio_queue_vector(vdev, queue_no) != vector) { | |
697 | continue; | |
698 | } | |
a38b2c49 | 699 | virtio_pci_vq_vector_mask(proxy, queue_no, vector); |
7d37d351 JK |
700 | } |
701 | } | |
702 | ||
a38b2c49 MT |
703 | static void virtio_pci_vector_poll(PCIDevice *dev, |
704 | unsigned int vector_start, | |
705 | unsigned int vector_end) | |
89d62be9 MT |
706 | { |
707 | VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); | |
708 | VirtIODevice *vdev = proxy->vdev; | |
709 | int queue_no; | |
710 | unsigned int vector; | |
711 | EventNotifier *notifier; | |
712 | VirtQueue *vq; | |
713 | ||
2d620f59 | 714 | for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { |
89d62be9 MT |
715 | if (!virtio_queue_get_num(vdev, queue_no)) { |
716 | break; | |
717 | } | |
718 | vector = virtio_queue_vector(vdev, queue_no); | |
719 | if (vector < vector_start || vector >= vector_end || | |
720 | !msix_is_masked(dev, vector)) { | |
721 | continue; | |
722 | } | |
723 | vq = virtio_get_queue(vdev, queue_no); | |
724 | notifier = virtio_queue_get_guest_notifier(vq); | |
f1d0f15a MT |
725 | if (vdev->guest_notifier_pending) { |
726 | if (vdev->guest_notifier_pending(vdev, queue_no)) { | |
727 | msix_set_pending(dev, vector); | |
728 | } | |
729 | } else if (event_notifier_test_and_clear(notifier)) { | |
89d62be9 MT |
730 | msix_set_pending(dev, vector); |
731 | } | |
732 | } | |
733 | } | |
734 | ||
735 | static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, | |
736 | bool with_irqfd) | |
ade80dc8 | 737 | { |
d2a0ccc6 | 738 | VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); |
ade80dc8 MT |
739 | VirtQueue *vq = virtio_get_queue(proxy->vdev, n); |
740 | EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); | |
741 | ||
742 | if (assign) { | |
743 | int r = event_notifier_init(notifier, 0); | |
744 | if (r < 0) { | |
745 | return r; | |
746 | } | |
89d62be9 | 747 | virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); |
ade80dc8 | 748 | } else { |
89d62be9 | 749 | virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); |
ade80dc8 MT |
750 | event_notifier_cleanup(notifier); |
751 | } | |
752 | ||
753 | return 0; | |
754 | } | |
755 | ||
d2a0ccc6 | 756 | static bool virtio_pci_query_guest_notifiers(DeviceState *d) |
5430a28f | 757 | { |
d2a0ccc6 | 758 | VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); |
5430a28f MT |
759 | return msix_enabled(&proxy->pci_dev); |
760 | } | |
761 | ||
2d620f59 | 762 | static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) |
54dd9321 | 763 | { |
d2a0ccc6 | 764 | VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); |
54dd9321 MT |
765 | VirtIODevice *vdev = proxy->vdev; |
766 | int r, n; | |
89d62be9 MT |
767 | bool with_irqfd = msix_enabled(&proxy->pci_dev) && |
768 | kvm_msi_via_irqfd_enabled(); | |
54dd9321 | 769 | |
2d620f59 MT |
770 | nvqs = MIN(nvqs, VIRTIO_PCI_QUEUE_MAX); |
771 | ||
772 | /* When deassigning, pass a consistent nvqs value | |
773 | * to avoid leaking notifiers. | |
774 | */ | |
775 | assert(assign || nvqs == proxy->nvqs_with_notifiers); | |
776 | ||
777 | proxy->nvqs_with_notifiers = nvqs; | |
778 | ||
7d37d351 | 779 | /* Must unset vector notifier while guest notifier is still assigned */ |
a38b2c49 | 780 | if ((proxy->vector_irqfd || vdev->guest_notifier_mask) && !assign) { |
7d37d351 | 781 | msix_unset_vector_notifiers(&proxy->pci_dev); |
a38b2c49 MT |
782 | if (proxy->vector_irqfd) { |
783 | kvm_virtio_pci_vector_release(proxy, nvqs); | |
784 | g_free(proxy->vector_irqfd); | |
785 | proxy->vector_irqfd = NULL; | |
786 | } | |
7d37d351 JK |
787 | } |
788 | ||
2d620f59 | 789 | for (n = 0; n < nvqs; n++) { |
54dd9321 MT |
790 | if (!virtio_queue_get_num(vdev, n)) { |
791 | break; | |
792 | } | |
793 | ||
89d62be9 MT |
794 | r = virtio_pci_set_guest_notifier(d, n, assign, |
795 | kvm_msi_via_irqfd_enabled()); | |
54dd9321 MT |
796 | if (r < 0) { |
797 | goto assign_error; | |
798 | } | |
799 | } | |
800 | ||
7d37d351 | 801 | /* Must set vector notifier after guest notifier has been assigned */ |
a38b2c49 MT |
802 | if ((with_irqfd || vdev->guest_notifier_mask) && assign) { |
803 | if (with_irqfd) { | |
804 | proxy->vector_irqfd = | |
805 | g_malloc0(sizeof(*proxy->vector_irqfd) * | |
806 | msix_nr_vectors_allocated(&proxy->pci_dev)); | |
807 | r = kvm_virtio_pci_vector_use(proxy, nvqs); | |
808 | if (r < 0) { | |
809 | goto assign_error; | |
810 | } | |
774345f9 | 811 | } |
7d37d351 | 812 | r = msix_set_vector_notifiers(&proxy->pci_dev, |
a38b2c49 MT |
813 | virtio_pci_vector_unmask, |
814 | virtio_pci_vector_mask, | |
815 | virtio_pci_vector_poll); | |
7d37d351 | 816 | if (r < 0) { |
774345f9 | 817 | goto notifiers_error; |
7d37d351 JK |
818 | } |
819 | } | |
820 | ||
54dd9321 MT |
821 | return 0; |
822 | ||
774345f9 | 823 | notifiers_error: |
a38b2c49 MT |
824 | if (with_irqfd) { |
825 | assert(assign); | |
826 | kvm_virtio_pci_vector_release(proxy, nvqs); | |
827 | } | |
774345f9 | 828 | |
54dd9321 MT |
829 | assign_error: |
830 | /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ | |
7d37d351 | 831 | assert(assign); |
54dd9321 | 832 | while (--n >= 0) { |
89d62be9 | 833 | virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd); |
54dd9321 MT |
834 | } |
835 | return r; | |
836 | } | |
837 | ||
d2a0ccc6 | 838 | static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign) |
ade80dc8 | 839 | { |
d2a0ccc6 | 840 | VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); |
25db9ebe SH |
841 | |
842 | /* Stop using ioeventfd for virtqueue kick if the device starts using host | |
843 | * notifiers. This makes it easy to avoid stepping on each others' toes. | |
844 | */ | |
845 | proxy->ioeventfd_disabled = assign; | |
ade80dc8 | 846 | if (assign) { |
25db9ebe SH |
847 | virtio_pci_stop_ioeventfd(proxy); |
848 | } | |
849 | /* We don't need to start here: it's not needed because backend | |
850 | * currently only stops on status change away from ok, | |
851 | * reset, vmstop and such. If we do add code to start here, | |
852 | * need to check vmstate, device state etc. */ | |
26b9b5fe | 853 | return virtio_pci_set_host_notifier_internal(proxy, n, assign, false); |
25db9ebe SH |
854 | } |
855 | ||
d2a0ccc6 | 856 | static void virtio_pci_vmstate_change(DeviceState *d, bool running) |
25db9ebe | 857 | { |
d2a0ccc6 | 858 | VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); |
25db9ebe SH |
859 | |
860 | if (running) { | |
89c473fd MT |
861 | /* Try to find out if the guest has bus master disabled, but is |
862 | in ready state. Then we have a buggy guest OS. */ | |
863 | if ((proxy->vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) && | |
864 | !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { | |
865 | proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG; | |
866 | } | |
25db9ebe | 867 | virtio_pci_start_ioeventfd(proxy); |
ade80dc8 | 868 | } else { |
25db9ebe | 869 | virtio_pci_stop_ioeventfd(proxy); |
ade80dc8 | 870 | } |
ade80dc8 MT |
871 | } |
872 | ||
53c25cea | 873 | static const VirtIOBindings virtio_pci_bindings = { |
ff24bd58 MT |
874 | .notify = virtio_pci_notify, |
875 | .save_config = virtio_pci_save_config, | |
876 | .load_config = virtio_pci_load_config, | |
877 | .save_queue = virtio_pci_save_queue, | |
878 | .load_queue = virtio_pci_load_queue, | |
6d74ca5a | 879 | .get_features = virtio_pci_get_features, |
5430a28f | 880 | .query_guest_notifiers = virtio_pci_query_guest_notifiers, |
ade80dc8 | 881 | .set_host_notifier = virtio_pci_set_host_notifier, |
54dd9321 | 882 | .set_guest_notifiers = virtio_pci_set_guest_notifiers, |
25db9ebe | 883 | .vmstate_change = virtio_pci_vmstate_change, |
53c25cea PB |
884 | }; |
885 | ||
befeac45 | 886 | void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev) |
53c25cea PB |
887 | { |
888 | uint8_t *config; | |
889 | uint32_t size; | |
890 | ||
891 | proxy->vdev = vdev; | |
892 | ||
893 | config = proxy->pci_dev.config; | |
53c25cea | 894 | |
e75ccf2c IY |
895 | if (proxy->class_code) { |
896 | pci_config_set_class(config, proxy->class_code); | |
897 | } | |
ad3d11e6 HKR |
898 | pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID, |
899 | pci_get_word(config + PCI_VENDOR_ID)); | |
900 | pci_set_word(config + PCI_SUBSYSTEM_ID, vdev->device_id); | |
901 | config[PCI_INTERRUPT_PIN] = 1; | |
53c25cea | 902 | |
b2357c48 AW |
903 | if (vdev->nvectors && |
904 | msix_init_exclusive_bar(&proxy->pci_dev, vdev->nvectors, 1)) { | |
aba800a3 | 905 | vdev->nvectors = 0; |
b2357c48 | 906 | } |
aba800a3 | 907 | |
ed757e14 YV |
908 | proxy->pci_dev.config_write = virtio_write_config; |
909 | ||
aba800a3 | 910 | size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + vdev->config_len; |
53c25cea PB |
911 | if (size & (size-1)) |
912 | size = 1 << qemu_fls(size); | |
913 | ||
da146d0a AK |
914 | memory_region_init_io(&proxy->bar, &virtio_pci_config_ops, proxy, |
915 | "virtio-pci", size); | |
e824b2cc AK |
916 | pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, |
917 | &proxy->bar); | |
53c25cea | 918 | |
25db9ebe SH |
919 | if (!kvm_has_many_ioeventfds()) { |
920 | proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD; | |
921 | } | |
922 | ||
d2a0ccc6 | 923 | virtio_bind_device(vdev, &virtio_pci_bindings, DEVICE(proxy)); |
8172539d MT |
924 | proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY; |
925 | proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE; | |
926 | proxy->host_features = vdev->get_features(vdev, proxy->host_features); | |
53c25cea PB |
927 | } |
928 | ||
f90c2bcd | 929 | static void virtio_exit_pci(PCIDevice *pci_dev) |
0f457d91 | 930 | { |
da146d0a AK |
931 | VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); |
932 | ||
933 | memory_region_destroy(&proxy->bar); | |
b2357c48 | 934 | msix_uninit_exclusive_bar(pci_dev); |
0f457d91 MT |
935 | } |
936 | ||
60653b28 | 937 | #ifdef CONFIG_VIRTFS |
234a336f | 938 | static int virtio_9p_init_pci(VirtIOPCIProxy *vpci_dev) |
60653b28 | 939 | { |
234a336f FK |
940 | V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev); |
941 | DeviceState *vdev = DEVICE(&dev->vdev); | |
60653b28 | 942 | |
234a336f FK |
943 | qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); |
944 | if (qdev_init(vdev) < 0) { | |
945 | return -1; | |
946 | } | |
60653b28 PB |
947 | return 0; |
948 | } | |
949 | ||
234a336f FK |
950 | static Property virtio_9p_pci_properties[] = { |
951 | DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, | |
952 | VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), | |
60653b28 PB |
953 | DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), |
954 | DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), | |
234a336f | 955 | DEFINE_VIRTIO_9P_PROPERTIES(V9fsPCIState, vdev.fsconf), |
60653b28 PB |
956 | DEFINE_PROP_END_OF_LIST(), |
957 | }; | |
958 | ||
234a336f | 959 | static void virtio_9p_pci_class_init(ObjectClass *klass, void *data) |
60653b28 PB |
960 | { |
961 | DeviceClass *dc = DEVICE_CLASS(klass); | |
234a336f FK |
962 | PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); |
963 | VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); | |
60653b28 PB |
964 | |
965 | k->init = virtio_9p_init_pci; | |
234a336f FK |
966 | pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; |
967 | pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P; | |
968 | pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; | |
969 | pcidev_k->class_id = 0x2; | |
970 | dc->props = virtio_9p_pci_properties; | |
60653b28 PB |
971 | } |
972 | ||
234a336f FK |
973 | static void virtio_9p_pci_instance_init(Object *obj) |
974 | { | |
975 | V9fsPCIState *dev = VIRTIO_9P_PCI(obj); | |
976 | object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_9P); | |
977 | object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); | |
978 | } | |
979 | ||
980 | static const TypeInfo virtio_9p_pci_info = { | |
981 | .name = TYPE_VIRTIO_9P_PCI, | |
982 | .parent = TYPE_VIRTIO_PCI, | |
983 | .instance_size = sizeof(V9fsPCIState), | |
984 | .instance_init = virtio_9p_pci_instance_init, | |
985 | .class_init = virtio_9p_pci_class_init, | |
60653b28 | 986 | }; |
234a336f | 987 | #endif /* CONFIG_VIRTFS */ |
60653b28 | 988 | |
085bccb7 FK |
989 | /* |
990 | * virtio-pci: This is the PCIDevice which has a virtio-pci-bus. | |
991 | */ | |
992 | ||
993 | /* This is called by virtio-bus just after the device is plugged. */ | |
994 | static void virtio_pci_device_plugged(DeviceState *d) | |
995 | { | |
996 | VirtIOPCIProxy *proxy = VIRTIO_PCI(d); | |
997 | VirtioBusState *bus = &proxy->bus; | |
998 | uint8_t *config; | |
999 | uint32_t size; | |
1000 | ||
1001 | proxy->vdev = bus->vdev; | |
1002 | ||
1003 | config = proxy->pci_dev.config; | |
1004 | if (proxy->class_code) { | |
1005 | pci_config_set_class(config, proxy->class_code); | |
1006 | } | |
1007 | pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID, | |
1008 | pci_get_word(config + PCI_VENDOR_ID)); | |
1009 | pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus)); | |
1010 | config[PCI_INTERRUPT_PIN] = 1; | |
1011 | ||
1012 | if (proxy->nvectors && | |
1013 | msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) { | |
1014 | proxy->nvectors = 0; | |
1015 | } | |
1016 | ||
1017 | proxy->pci_dev.config_write = virtio_write_config; | |
1018 | ||
1019 | size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) | |
1020 | + virtio_bus_get_vdev_config_len(bus); | |
1021 | if (size & (size - 1)) { | |
1022 | size = 1 << qemu_fls(size); | |
1023 | } | |
1024 | ||
1025 | memory_region_init_io(&proxy->bar, &virtio_pci_config_ops, proxy, | |
1026 | "virtio-pci", size); | |
1027 | pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, | |
1028 | &proxy->bar); | |
1029 | ||
1030 | if (!kvm_has_many_ioeventfds()) { | |
1031 | proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD; | |
1032 | } | |
1033 | ||
1034 | proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY; | |
1035 | proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE; | |
1036 | proxy->host_features = virtio_bus_get_vdev_features(bus, | |
1037 | proxy->host_features); | |
1038 | } | |
1039 | ||
085bccb7 FK |
1040 | static int virtio_pci_init(PCIDevice *pci_dev) |
1041 | { | |
1042 | VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev); | |
1043 | VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev); | |
1044 | virtio_pci_bus_new(&dev->bus, dev); | |
1045 | if (k->init != NULL) { | |
1046 | return k->init(dev); | |
1047 | } | |
1048 | return 0; | |
1049 | } | |
1050 | ||
1051 | static void virtio_pci_exit(PCIDevice *pci_dev) | |
1052 | { | |
1053 | VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev); | |
10479a80 | 1054 | virtio_pci_stop_ioeventfd(proxy); |
085bccb7 FK |
1055 | virtio_exit_pci(pci_dev); |
1056 | } | |
1057 | ||
59ccd20a | 1058 | static void virtio_pci_reset(DeviceState *qdev) |
085bccb7 FK |
1059 | { |
1060 | VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev); | |
1061 | VirtioBusState *bus = VIRTIO_BUS(&proxy->bus); | |
1062 | virtio_pci_stop_ioeventfd(proxy); | |
1063 | virtio_bus_reset(bus); | |
1064 | msix_unuse_all_vectors(&proxy->pci_dev); | |
1065 | proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG; | |
1066 | } | |
1067 | ||
1068 | static void virtio_pci_class_init(ObjectClass *klass, void *data) | |
1069 | { | |
1070 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1071 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); | |
1072 | ||
1073 | k->init = virtio_pci_init; | |
1074 | k->exit = virtio_pci_exit; | |
1075 | k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; | |
1076 | k->revision = VIRTIO_PCI_ABI_VERSION; | |
1077 | k->class_id = PCI_CLASS_OTHERS; | |
59ccd20a | 1078 | dc->reset = virtio_pci_reset; |
085bccb7 FK |
1079 | } |
1080 | ||
1081 | static const TypeInfo virtio_pci_info = { | |
1082 | .name = TYPE_VIRTIO_PCI, | |
1083 | .parent = TYPE_PCI_DEVICE, | |
1084 | .instance_size = sizeof(VirtIOPCIProxy), | |
1085 | .class_init = virtio_pci_class_init, | |
1086 | .class_size = sizeof(VirtioPCIClass), | |
1087 | .abstract = true, | |
1088 | }; | |
1089 | ||
653ced07 FK |
1090 | /* virtio-blk-pci */ |
1091 | ||
1092 | static Property virtio_blk_pci_properties[] = { | |
1093 | DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), | |
1094 | DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, | |
1095 | VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), | |
1096 | DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), | |
1097 | #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE | |
1098 | DEFINE_PROP_BIT("x-data-plane", VirtIOBlkPCI, blk.data_plane, 0, false), | |
1099 | #endif | |
1100 | DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features), | |
1101 | DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkPCI, blk), | |
1102 | DEFINE_PROP_END_OF_LIST(), | |
1103 | }; | |
1104 | ||
1105 | static int virtio_blk_pci_init(VirtIOPCIProxy *vpci_dev) | |
1106 | { | |
1107 | VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev); | |
1108 | DeviceState *vdev = DEVICE(&dev->vdev); | |
1109 | virtio_blk_set_conf(vdev, &(dev->blk)); | |
1110 | qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); | |
1111 | if (qdev_init(vdev) < 0) { | |
1112 | return -1; | |
1113 | } | |
1114 | return 0; | |
1115 | } | |
1116 | ||
1117 | static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) | |
1118 | { | |
1119 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1120 | VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); | |
1121 | PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); | |
1122 | ||
1123 | dc->props = virtio_blk_pci_properties; | |
1124 | k->init = virtio_blk_pci_init; | |
1125 | pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; | |
1126 | pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; | |
1127 | pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; | |
1128 | pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; | |
1129 | } | |
1130 | ||
1131 | static void virtio_blk_pci_instance_init(Object *obj) | |
1132 | { | |
1133 | VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj); | |
1134 | object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BLK); | |
1135 | object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); | |
1136 | } | |
1137 | ||
1138 | static const TypeInfo virtio_blk_pci_info = { | |
1139 | .name = TYPE_VIRTIO_BLK_PCI, | |
1140 | .parent = TYPE_VIRTIO_PCI, | |
1141 | .instance_size = sizeof(VirtIOBlkPCI), | |
1142 | .instance_init = virtio_blk_pci_instance_init, | |
1143 | .class_init = virtio_blk_pci_class_init, | |
1144 | }; | |
1145 | ||
bc7b90a0 FK |
1146 | /* virtio-scsi-pci */ |
1147 | ||
1148 | static Property virtio_scsi_pci_properties[] = { | |
1149 | DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, | |
1150 | VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), | |
1151 | DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, | |
1152 | DEV_NVECTORS_UNSPECIFIED), | |
1153 | DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features), | |
292c8e50 | 1154 | DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIPCI, vdev.parent_obj.conf), |
bc7b90a0 FK |
1155 | DEFINE_PROP_END_OF_LIST(), |
1156 | }; | |
1157 | ||
1158 | static int virtio_scsi_pci_init_pci(VirtIOPCIProxy *vpci_dev) | |
1159 | { | |
1160 | VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev); | |
1161 | DeviceState *vdev = DEVICE(&dev->vdev); | |
292c8e50 | 1162 | VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); |
bc7b90a0 FK |
1163 | |
1164 | if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { | |
292c8e50 | 1165 | vpci_dev->nvectors = vs->conf.num_queues + 3; |
bc7b90a0 FK |
1166 | } |
1167 | ||
1168 | qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); | |
1169 | if (qdev_init(vdev) < 0) { | |
1170 | return -1; | |
1171 | } | |
1172 | return 0; | |
1173 | } | |
1174 | ||
1175 | static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data) | |
1176 | { | |
1177 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1178 | VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); | |
1179 | PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); | |
1180 | k->init = virtio_scsi_pci_init_pci; | |
1181 | dc->props = virtio_scsi_pci_properties; | |
1182 | pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; | |
1183 | pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; | |
1184 | pcidev_k->revision = 0x00; | |
1185 | pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; | |
1186 | } | |
1187 | ||
1188 | static void virtio_scsi_pci_instance_init(Object *obj) | |
1189 | { | |
1190 | VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj); | |
1191 | object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_SCSI); | |
1192 | object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); | |
1193 | } | |
1194 | ||
1195 | static const TypeInfo virtio_scsi_pci_info = { | |
1196 | .name = TYPE_VIRTIO_SCSI_PCI, | |
1197 | .parent = TYPE_VIRTIO_PCI, | |
1198 | .instance_size = sizeof(VirtIOSCSIPCI), | |
1199 | .instance_init = virtio_scsi_pci_instance_init, | |
1200 | .class_init = virtio_scsi_pci_class_init, | |
1201 | }; | |
1202 | ||
50787628 NB |
1203 | /* vhost-scsi-pci */ |
1204 | ||
1205 | #ifdef CONFIG_VHOST_SCSI | |
1206 | static Property vhost_scsi_pci_properties[] = { | |
1207 | DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, | |
1208 | DEV_NVECTORS_UNSPECIFIED), | |
1209 | DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), | |
1210 | DEFINE_VHOST_SCSI_PROPERTIES(VHostSCSIPCI, vdev.parent_obj.conf), | |
1211 | DEFINE_PROP_END_OF_LIST(), | |
1212 | }; | |
1213 | ||
1214 | static int vhost_scsi_pci_init_pci(VirtIOPCIProxy *vpci_dev) | |
1215 | { | |
1216 | VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev); | |
1217 | DeviceState *vdev = DEVICE(&dev->vdev); | |
1218 | VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); | |
1219 | ||
1220 | if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { | |
1221 | vpci_dev->nvectors = vs->conf.num_queues + 3; | |
1222 | } | |
1223 | ||
1224 | qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); | |
1225 | if (qdev_init(vdev) < 0) { | |
1226 | return -1; | |
1227 | } | |
1228 | return 0; | |
1229 | } | |
1230 | ||
1231 | static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data) | |
1232 | { | |
1233 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1234 | VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); | |
1235 | PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); | |
1236 | k->init = vhost_scsi_pci_init_pci; | |
1237 | dc->props = vhost_scsi_pci_properties; | |
1238 | pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; | |
1239 | pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; | |
1240 | pcidev_k->revision = 0x00; | |
1241 | pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; | |
1242 | } | |
1243 | ||
1244 | static void vhost_scsi_pci_instance_init(Object *obj) | |
1245 | { | |
1246 | VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj); | |
1247 | object_initialize(OBJECT(&dev->vdev), TYPE_VHOST_SCSI); | |
1248 | object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); | |
1249 | } | |
1250 | ||
1251 | static const TypeInfo vhost_scsi_pci_info = { | |
1252 | .name = TYPE_VHOST_SCSI_PCI, | |
1253 | .parent = TYPE_VIRTIO_PCI, | |
1254 | .instance_size = sizeof(VHostSCSIPCI), | |
1255 | .instance_init = vhost_scsi_pci_instance_init, | |
1256 | .class_init = vhost_scsi_pci_class_init, | |
1257 | }; | |
1258 | #endif | |
1259 | ||
e378e88d FK |
1260 | /* virtio-balloon-pci */ |
1261 | ||
24a6e7f4 FK |
1262 | static void balloon_pci_stats_get_all(Object *obj, struct Visitor *v, |
1263 | void *opaque, const char *name, | |
1264 | Error **errp) | |
1265 | { | |
1266 | VirtIOBalloonPCI *dev = opaque; | |
1267 | object_property_get(OBJECT(&dev->vdev), v, "guest-stats", errp); | |
1268 | } | |
1269 | ||
1270 | static void balloon_pci_stats_get_poll_interval(Object *obj, struct Visitor *v, | |
1271 | void *opaque, const char *name, | |
1272 | Error **errp) | |
1273 | { | |
1274 | VirtIOBalloonPCI *dev = opaque; | |
1275 | object_property_get(OBJECT(&dev->vdev), v, "guest-stats-polling-interval", | |
1276 | errp); | |
1277 | } | |
1278 | ||
1279 | static void balloon_pci_stats_set_poll_interval(Object *obj, struct Visitor *v, | |
1280 | void *opaque, const char *name, | |
1281 | Error **errp) | |
1282 | { | |
1283 | VirtIOBalloonPCI *dev = opaque; | |
1284 | object_property_set(OBJECT(&dev->vdev), v, "guest-stats-polling-interval", | |
1285 | errp); | |
1286 | } | |
1287 | ||
e378e88d FK |
1288 | static Property virtio_balloon_pci_properties[] = { |
1289 | DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), | |
1290 | DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), | |
1291 | DEFINE_PROP_END_OF_LIST(), | |
1292 | }; | |
1293 | ||
1294 | static int virtio_balloon_pci_init(VirtIOPCIProxy *vpci_dev) | |
1295 | { | |
1296 | VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev); | |
1297 | DeviceState *vdev = DEVICE(&dev->vdev); | |
1298 | ||
1299 | if (vpci_dev->class_code != PCI_CLASS_OTHERS && | |
1300 | vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */ | |
1301 | vpci_dev->class_code = PCI_CLASS_OTHERS; | |
1302 | } | |
1303 | ||
1304 | qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); | |
1305 | if (qdev_init(vdev) < 0) { | |
1306 | return -1; | |
1307 | } | |
1308 | return 0; | |
1309 | } | |
1310 | ||
1311 | static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data) | |
1312 | { | |
1313 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1314 | VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); | |
1315 | PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); | |
1316 | k->init = virtio_balloon_pci_init; | |
1317 | dc->props = virtio_balloon_pci_properties; | |
1318 | pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; | |
1319 | pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON; | |
1320 | pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; | |
1321 | pcidev_k->class_id = PCI_CLASS_OTHERS; | |
1322 | } | |
1323 | ||
1324 | static void virtio_balloon_pci_instance_init(Object *obj) | |
1325 | { | |
1326 | VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj); | |
1327 | object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BALLOON); | |
1328 | object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); | |
24a6e7f4 FK |
1329 | |
1330 | object_property_add(obj, "guest-stats", "guest statistics", | |
1331 | balloon_pci_stats_get_all, NULL, NULL, dev, | |
1332 | NULL); | |
1333 | ||
1334 | object_property_add(obj, "guest-stats-polling-interval", "int", | |
1335 | balloon_pci_stats_get_poll_interval, | |
1336 | balloon_pci_stats_set_poll_interval, | |
1337 | NULL, dev, NULL); | |
e378e88d FK |
1338 | } |
1339 | ||
1340 | static const TypeInfo virtio_balloon_pci_info = { | |
1341 | .name = TYPE_VIRTIO_BALLOON_PCI, | |
1342 | .parent = TYPE_VIRTIO_PCI, | |
1343 | .instance_size = sizeof(VirtIOBalloonPCI), | |
1344 | .instance_init = virtio_balloon_pci_instance_init, | |
1345 | .class_init = virtio_balloon_pci_class_init, | |
1346 | }; | |
1347 | ||
f7f7464a FK |
1348 | /* virtio-serial-pci */ |
1349 | ||
1350 | static int virtio_serial_pci_init(VirtIOPCIProxy *vpci_dev) | |
1351 | { | |
1352 | VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev); | |
1353 | DeviceState *vdev = DEVICE(&dev->vdev); | |
1354 | ||
1355 | if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER && | |
1356 | vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */ | |
1357 | vpci_dev->class_code != PCI_CLASS_OTHERS) { /* qemu-kvm */ | |
1358 | vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER; | |
1359 | } | |
1360 | ||
1361 | /* backwards-compatibility with machines that were created with | |
1362 | DEV_NVECTORS_UNSPECIFIED */ | |
1363 | if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { | |
1364 | vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1; | |
1365 | } | |
1366 | ||
1367 | qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); | |
1368 | if (qdev_init(vdev) < 0) { | |
1369 | return -1; | |
1370 | } | |
1371 | return 0; | |
1372 | } | |
1373 | ||
1374 | static Property virtio_serial_pci_properties[] = { | |
1375 | DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, | |
1376 | VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), | |
1377 | DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), | |
1378 | DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), | |
1379 | DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), | |
1380 | DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtIOSerialPCI, vdev.serial), | |
1381 | DEFINE_PROP_END_OF_LIST(), | |
1382 | }; | |
1383 | ||
1384 | static void virtio_serial_pci_class_init(ObjectClass *klass, void *data) | |
1385 | { | |
1386 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1387 | VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); | |
1388 | PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); | |
1389 | k->init = virtio_serial_pci_init; | |
1390 | dc->props = virtio_serial_pci_properties; | |
1391 | pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; | |
1392 | pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE; | |
1393 | pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; | |
1394 | pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; | |
1395 | } | |
1396 | ||
1397 | static void virtio_serial_pci_instance_init(Object *obj) | |
1398 | { | |
1399 | VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj); | |
1400 | object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_SERIAL); | |
1401 | object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); | |
1402 | } | |
1403 | ||
1404 | static const TypeInfo virtio_serial_pci_info = { | |
1405 | .name = TYPE_VIRTIO_SERIAL_PCI, | |
1406 | .parent = TYPE_VIRTIO_PCI, | |
1407 | .instance_size = sizeof(VirtIOSerialPCI), | |
1408 | .instance_init = virtio_serial_pci_instance_init, | |
1409 | .class_init = virtio_serial_pci_class_init, | |
1410 | }; | |
1411 | ||
e37da394 FK |
1412 | /* virtio-net-pci */ |
1413 | ||
1414 | static Property virtio_net_properties[] = { | |
1415 | DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, | |
1416 | VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false), | |
1417 | DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), | |
1418 | DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features), | |
1419 | DEFINE_NIC_PROPERTIES(VirtIONetPCI, vdev.nic_conf), | |
1420 | DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetPCI, vdev.net_conf), | |
1421 | DEFINE_PROP_END_OF_LIST(), | |
1422 | }; | |
1423 | ||
1424 | static int virtio_net_pci_init(VirtIOPCIProxy *vpci_dev) | |
1425 | { | |
1426 | VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev); | |
1427 | DeviceState *vdev = DEVICE(&dev->vdev); | |
1428 | ||
1429 | virtio_net_set_config_size(&dev->vdev, vpci_dev->host_features); | |
1430 | qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); | |
1431 | if (qdev_init(vdev) < 0) { | |
1432 | return -1; | |
1433 | } | |
1434 | return 0; | |
1435 | } | |
1436 | ||
1437 | static void virtio_net_pci_class_init(ObjectClass *klass, void *data) | |
1438 | { | |
1439 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1440 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); | |
1441 | VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass); | |
1442 | ||
1443 | k->romfile = "efi-virtio.rom"; | |
1444 | k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; | |
1445 | k->device_id = PCI_DEVICE_ID_VIRTIO_NET; | |
1446 | k->revision = VIRTIO_PCI_ABI_VERSION; | |
1447 | k->class_id = PCI_CLASS_NETWORK_ETHERNET; | |
1448 | dc->props = virtio_net_properties; | |
1449 | vpciklass->init = virtio_net_pci_init; | |
1450 | } | |
1451 | ||
1452 | static void virtio_net_pci_instance_init(Object *obj) | |
1453 | { | |
1454 | VirtIONetPCI *dev = VIRTIO_NET_PCI(obj); | |
1455 | object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_NET); | |
1456 | object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); | |
1457 | } | |
1458 | ||
1459 | static const TypeInfo virtio_net_pci_info = { | |
1460 | .name = TYPE_VIRTIO_NET_PCI, | |
1461 | .parent = TYPE_VIRTIO_PCI, | |
1462 | .instance_size = sizeof(VirtIONetPCI), | |
1463 | .instance_init = virtio_net_pci_instance_init, | |
1464 | .class_init = virtio_net_pci_class_init, | |
1465 | }; | |
1466 | ||
59ccd20a FK |
1467 | /* virtio-rng-pci */ |
1468 | ||
1469 | static Property virtio_rng_pci_properties[] = { | |
1470 | DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), | |
1471 | DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORngPCI, vdev.conf), | |
1472 | DEFINE_PROP_END_OF_LIST(), | |
1473 | }; | |
1474 | ||
1475 | static int virtio_rng_pci_init(VirtIOPCIProxy *vpci_dev) | |
1476 | { | |
1477 | VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev); | |
1478 | DeviceState *vdev = DEVICE(&vrng->vdev); | |
1479 | ||
1480 | qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); | |
1481 | if (qdev_init(vdev) < 0) { | |
1482 | return -1; | |
1483 | } | |
1484 | ||
1485 | object_property_set_link(OBJECT(vrng), | |
1486 | OBJECT(vrng->vdev.conf.default_backend), "rng", | |
1487 | NULL); | |
1488 | ||
1489 | return 0; | |
1490 | } | |
1491 | ||
1492 | static void virtio_rng_pci_class_init(ObjectClass *klass, void *data) | |
1493 | { | |
1494 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1495 | VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); | |
1496 | PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); | |
1497 | ||
1498 | k->init = virtio_rng_pci_init; | |
1499 | dc->props = virtio_rng_pci_properties; | |
1500 | ||
1501 | pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; | |
1502 | pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG; | |
1503 | pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; | |
1504 | pcidev_k->class_id = PCI_CLASS_OTHERS; | |
1505 | } | |
1506 | ||
1507 | static void virtio_rng_initfn(Object *obj) | |
1508 | { | |
1509 | VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj); | |
1510 | object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_RNG); | |
1511 | object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); | |
1512 | object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, | |
1513 | (Object **)&dev->vdev.conf.rng, NULL); | |
1514 | ||
1515 | } | |
1516 | ||
1517 | static const TypeInfo virtio_rng_pci_info = { | |
1518 | .name = TYPE_VIRTIO_RNG_PCI, | |
1519 | .parent = TYPE_VIRTIO_PCI, | |
1520 | .instance_size = sizeof(VirtIORngPCI), | |
1521 | .instance_init = virtio_rng_initfn, | |
1522 | .class_init = virtio_rng_pci_class_init, | |
1523 | }; | |
1524 | ||
0a2acf5e FK |
1525 | /* virtio-pci-bus */ |
1526 | ||
1527 | void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev) | |
1528 | { | |
1529 | DeviceState *qdev = DEVICE(dev); | |
1530 | BusState *qbus; | |
1531 | qbus_create_inplace((BusState *)bus, TYPE_VIRTIO_PCI_BUS, qdev, NULL); | |
1532 | qbus = BUS(bus); | |
cbd19063 | 1533 | qbus->allow_hotplug = 1; |
0a2acf5e FK |
1534 | } |
1535 | ||
1536 | static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) | |
1537 | { | |
1538 | BusClass *bus_class = BUS_CLASS(klass); | |
1539 | VirtioBusClass *k = VIRTIO_BUS_CLASS(klass); | |
1540 | bus_class->max_dev = 1; | |
1541 | k->notify = virtio_pci_notify; | |
1542 | k->save_config = virtio_pci_save_config; | |
1543 | k->load_config = virtio_pci_load_config; | |
1544 | k->save_queue = virtio_pci_save_queue; | |
1545 | k->load_queue = virtio_pci_load_queue; | |
1546 | k->get_features = virtio_pci_get_features; | |
1547 | k->query_guest_notifiers = virtio_pci_query_guest_notifiers; | |
1548 | k->set_host_notifier = virtio_pci_set_host_notifier; | |
1549 | k->set_guest_notifiers = virtio_pci_set_guest_notifiers; | |
1550 | k->vmstate_change = virtio_pci_vmstate_change; | |
085bccb7 | 1551 | k->device_plugged = virtio_pci_device_plugged; |
0a2acf5e FK |
1552 | } |
1553 | ||
1554 | static const TypeInfo virtio_pci_bus_info = { | |
1555 | .name = TYPE_VIRTIO_PCI_BUS, | |
1556 | .parent = TYPE_VIRTIO_BUS, | |
1557 | .instance_size = sizeof(VirtioPCIBusState), | |
1558 | .class_init = virtio_pci_bus_class_init, | |
1559 | }; | |
1560 | ||
83f7d43a | 1561 | static void virtio_pci_register_types(void) |
53c25cea | 1562 | { |
59ccd20a | 1563 | type_register_static(&virtio_rng_pci_info); |
0a2acf5e | 1564 | type_register_static(&virtio_pci_bus_info); |
085bccb7 | 1565 | type_register_static(&virtio_pci_info); |
60653b28 | 1566 | #ifdef CONFIG_VIRTFS |
234a336f | 1567 | type_register_static(&virtio_9p_pci_info); |
60653b28 | 1568 | #endif |
653ced07 | 1569 | type_register_static(&virtio_blk_pci_info); |
bc7b90a0 | 1570 | type_register_static(&virtio_scsi_pci_info); |
e378e88d | 1571 | type_register_static(&virtio_balloon_pci_info); |
f7f7464a | 1572 | type_register_static(&virtio_serial_pci_info); |
e37da394 | 1573 | type_register_static(&virtio_net_pci_info); |
50787628 NB |
1574 | #ifdef CONFIG_VHOST_SCSI |
1575 | type_register_static(&vhost_scsi_pci_info); | |
1576 | #endif | |
53c25cea PB |
1577 | } |
1578 | ||
83f7d43a | 1579 | type_init(virtio_pci_register_types) |