blob: e9b722dd9601f09de2bd49941253e7f40f7a3c89 [file] [log] [blame]
Paul Brook53c25ce2009-05-18 14:51:59 +01001/*
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 *
Paolo Bonzini6b620ca2012-01-13 17:44:23 +010014 * Contributions after 2012-01-13 are licensed under the terms of the
15 * GNU GPL, version 2 or (at your option) any later version.
Paul Brook53c25ce2009-05-18 14:51:59 +010016 */
17
18#include <inttypes.h>
19
20#include "virtio.h"
Michael S. Tsirkin81725392010-01-10 13:52:53 +020021#include "virtio-blk.h"
22#include "virtio-net.h"
Amit Shah6b331ef2011-02-03 11:22:32 +053023#include "virtio-serial.h"
Stefan Hajnoczi973abc72011-02-11 08:40:59 +000024#include "virtio-scsi.h"
Michael S. Tsirkina2cb15b2012-12-12 14:24:50 +020025#include "pci/pci.h"
Markus Armbruster2f792012010-02-18 16:24:31 +010026#include "qemu-error.h"
Michael S. Tsirkina2cb15b2012-12-12 14:24:50 +020027#include "pci/msi.h"
28#include "pci/msix.h"
Gerd Hoffmanna1e0fea2009-07-15 13:48:25 +020029#include "net.h"
Gerd Hoffmann97b15622009-10-21 15:25:35 +020030#include "loader.h"
Michael S. Tsirkinade80dc2010-03-17 13:08:13 +020031#include "kvm.h"
Blue Swirl24463332010-08-24 15:22:24 +000032#include "blockdev.h"
Aneesh Kumar K.V9fe1ebe2011-06-01 12:35:13 +053033#include "virtio-pci.h"
Michael S. Tsirkin11297142011-07-27 11:08:20 +030034#include "range.h"
Paul Brook53c25ce2009-05-18 14:51:59 +010035
36/* from Linux's linux/virtio_pci.h */
37
38/* A 32-bit r/o bitmask of the features supported by the host */
39#define VIRTIO_PCI_HOST_FEATURES 0
40
41/* A 32-bit r/w bitmask of features activated by the guest */
42#define VIRTIO_PCI_GUEST_FEATURES 4
43
44/* A 32-bit r/w PFN for the currently selected queue */
45#define VIRTIO_PCI_QUEUE_PFN 8
46
47/* A 16-bit r/o queue size for the currently selected queue */
48#define VIRTIO_PCI_QUEUE_NUM 12
49
50/* A 16-bit r/w queue selector */
51#define VIRTIO_PCI_QUEUE_SEL 14
52
53/* A 16-bit r/w queue notifier */
54#define VIRTIO_PCI_QUEUE_NOTIFY 16
55
56/* An 8-bit device status register. */
57#define VIRTIO_PCI_STATUS 18
58
59/* An 8-bit r/o interrupt status register. Reading the value will return the
60 * current contents of the ISR and will also clear it. This is effectively
61 * a read-and-acknowledge. */
62#define VIRTIO_PCI_ISR 19
63
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +030064/* MSI-X registers: only enabled if MSI-X is enabled. */
65/* A 16-bit vector for configuration changes. */
66#define VIRTIO_MSI_CONFIG_VECTOR 20
67/* A 16-bit vector for selected queue notifications. */
68#define VIRTIO_MSI_QUEUE_VECTOR 22
69
70/* Config space size */
71#define VIRTIO_PCI_CONFIG_NOMSI 20
72#define VIRTIO_PCI_CONFIG_MSI 24
73#define VIRTIO_PCI_REGION_SIZE(dev) (msix_present(dev) ? \
74 VIRTIO_PCI_CONFIG_MSI : \
75 VIRTIO_PCI_CONFIG_NOMSI)
76
77/* The remaining space is defined by each driver as the per-driver
78 * configuration space */
79#define VIRTIO_PCI_CONFIG(dev) (msix_enabled(dev) ? \
80 VIRTIO_PCI_CONFIG_MSI : \
81 VIRTIO_PCI_CONFIG_NOMSI)
Paul Brook53c25ce2009-05-18 14:51:59 +010082
Paul Brook53c25ce2009-05-18 14:51:59 +010083/* How many bits to shift physical queue address written to QUEUE_PFN.
84 * 12 is historical, and due to x86 page size. */
85#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12
86
Stefan Hajnoczi3dbca8e2010-12-17 12:01:49 +000087/* Flags track per-device state like workarounds for quirks in older guests. */
88#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG (1 << 0)
Alexander Grafc81131d2010-03-16 19:18:07 +010089
Paul Brook53c25ce2009-05-18 14:51:59 +010090/* QEMU doesn't strictly need write barriers since everything runs in
91 * lock-step. We'll leave the calls to wmb() in though to make it obvious for
92 * KVM or if kqemu gets SMP support.
93 */
94#define wmb() do { } while (0)
95
Benjamin Herrenschmidt82afa582012-01-10 01:35:11 +000096/* HACK for virtio to determine if it's running a big endian guest */
97bool virtio_is_big_endian(void);
98
Paul Brook53c25ce2009-05-18 14:51:59 +010099/* virtio device */
100
Michael S. Tsirkin7055e682009-06-21 19:50:13 +0300101static void virtio_pci_notify(void *opaque, uint16_t vector)
Paul Brook53c25ce2009-05-18 14:51:59 +0100102{
103 VirtIOPCIProxy *proxy = opaque;
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +0300104 if (msix_enabled(&proxy->pci_dev))
105 msix_notify(&proxy->pci_dev, vector);
106 else
107 qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1);
Paul Brook53c25ce2009-05-18 14:51:59 +0100108}
109
Michael S. Tsirkinff24bd52009-06-21 19:50:40 +0300110static void virtio_pci_save_config(void * opaque, QEMUFile *f)
111{
112 VirtIOPCIProxy *proxy = opaque;
113 pci_device_save(&proxy->pci_dev, f);
114 msix_save(&proxy->pci_dev, f);
115 if (msix_present(&proxy->pci_dev))
116 qemu_put_be16(f, proxy->vdev->config_vector);
117}
118
119static void virtio_pci_save_queue(void * opaque, int n, QEMUFile *f)
120{
121 VirtIOPCIProxy *proxy = opaque;
122 if (msix_present(&proxy->pci_dev))
123 qemu_put_be16(f, virtio_queue_vector(proxy->vdev, n));
124}
125
126static int virtio_pci_load_config(void * opaque, QEMUFile *f)
127{
128 VirtIOPCIProxy *proxy = opaque;
129 int ret;
130 ret = pci_device_load(&proxy->pci_dev, f);
Michael S. Tsirkine6da7682009-07-05 16:02:34 +0300131 if (ret) {
Michael S. Tsirkinff24bd52009-06-21 19:50:40 +0300132 return ret;
Michael S. Tsirkine6da7682009-07-05 16:02:34 +0300133 }
Michael S. Tsirkin3cac0012012-08-29 19:40:56 +0300134 msix_unuse_all_vectors(&proxy->pci_dev);
Michael S. Tsirkinff24bd52009-06-21 19:50:40 +0300135 msix_load(&proxy->pci_dev, f);
Michael S. Tsirkine6da7682009-07-05 16:02:34 +0300136 if (msix_present(&proxy->pci_dev)) {
Michael S. Tsirkinff24bd52009-06-21 19:50:40 +0300137 qemu_get_be16s(f, &proxy->vdev->config_vector);
Michael S. Tsirkine6da7682009-07-05 16:02:34 +0300138 } else {
139 proxy->vdev->config_vector = VIRTIO_NO_VECTOR;
140 }
141 if (proxy->vdev->config_vector != VIRTIO_NO_VECTOR) {
142 return msix_vector_use(&proxy->pci_dev, proxy->vdev->config_vector);
143 }
Michael S. Tsirkinff24bd52009-06-21 19:50:40 +0300144 return 0;
145}
146
147static int virtio_pci_load_queue(void * opaque, int n, QEMUFile *f)
148{
149 VirtIOPCIProxy *proxy = opaque;
150 uint16_t vector;
Michael S. Tsirkine6da7682009-07-05 16:02:34 +0300151 if (msix_present(&proxy->pci_dev)) {
152 qemu_get_be16s(f, &vector);
153 } else {
154 vector = VIRTIO_NO_VECTOR;
155 }
Michael S. Tsirkinff24bd52009-06-21 19:50:40 +0300156 virtio_queue_set_vector(proxy->vdev, n, vector);
Michael S. Tsirkine6da7682009-07-05 16:02:34 +0300157 if (vector != VIRTIO_NO_VECTOR) {
158 return msix_vector_use(&proxy->pci_dev, vector);
159 }
Michael S. Tsirkinff24bd52009-06-21 19:50:40 +0300160 return 0;
161}
162
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000163static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
Paolo Bonzini26b9b5f2012-08-06 15:26:14 +0200164 int n, bool assign, bool set_handler)
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000165{
166 VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
167 EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
Avi Kivityda146d02011-08-08 16:09:13 +0300168 int r = 0;
169
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000170 if (assign) {
171 r = event_notifier_init(notifier, 1);
172 if (r < 0) {
Michael S. Tsirkinb36e3912011-01-11 14:10:15 +0200173 error_report("%s: unable to init event notifier: %d",
174 __func__, r);
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000175 return r;
176 }
Paolo Bonzini26b9b5f2012-08-06 15:26:14 +0200177 virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
Avi Kivityda146d02011-08-08 16:09:13 +0300178 memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
Paolo Bonzini753d5e12012-07-05 17:16:27 +0200179 true, n, notifier);
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000180 } else {
Avi Kivityda146d02011-08-08 16:09:13 +0300181 memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
Paolo Bonzini753d5e12012-07-05 17:16:27 +0200182 true, n, notifier);
Paolo Bonzini26b9b5f2012-08-06 15:26:14 +0200183 virtio_queue_set_host_notifier_fd_handler(vq, false, false);
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000184 event_notifier_cleanup(notifier);
185 }
186 return r;
187}
188
Michael S. Tsirkinb36e3912011-01-11 14:10:15 +0200189static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000190{
191 int n, r;
192
193 if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
194 proxy->ioeventfd_disabled ||
195 proxy->ioeventfd_started) {
Michael S. Tsirkinb36e3912011-01-11 14:10:15 +0200196 return;
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000197 }
198
199 for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
200 if (!virtio_queue_get_num(proxy->vdev, n)) {
201 continue;
202 }
203
Paolo Bonzini26b9b5f2012-08-06 15:26:14 +0200204 r = virtio_pci_set_host_notifier_internal(proxy, n, true, true);
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000205 if (r < 0) {
206 goto assign_error;
207 }
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000208 }
209 proxy->ioeventfd_started = true;
Michael S. Tsirkinb36e3912011-01-11 14:10:15 +0200210 return;
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000211
212assign_error:
213 while (--n >= 0) {
214 if (!virtio_queue_get_num(proxy->vdev, n)) {
215 continue;
216 }
217
Paolo Bonzini26b9b5f2012-08-06 15:26:14 +0200218 r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
Michael S. Tsirkinb36e3912011-01-11 14:10:15 +0200219 assert(r >= 0);
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000220 }
221 proxy->ioeventfd_started = false;
Michael S. Tsirkinb36e3912011-01-11 14:10:15 +0200222 error_report("%s: failed. Fallback to a userspace (slower).", __func__);
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000223}
224
Michael S. Tsirkinb36e3912011-01-11 14:10:15 +0200225static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000226{
Michael S. Tsirkinb36e3912011-01-11 14:10:15 +0200227 int r;
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000228 int n;
229
230 if (!proxy->ioeventfd_started) {
Michael S. Tsirkinb36e3912011-01-11 14:10:15 +0200231 return;
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000232 }
233
234 for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
235 if (!virtio_queue_get_num(proxy->vdev, n)) {
236 continue;
237 }
238
Paolo Bonzini26b9b5f2012-08-06 15:26:14 +0200239 r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
Michael S. Tsirkinb36e3912011-01-11 14:10:15 +0200240 assert(r >= 0);
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000241 }
242 proxy->ioeventfd_started = false;
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000243}
244
Aneesh Kumar K.V8798d6c2011-12-04 22:35:28 +0530245void virtio_pci_reset(DeviceState *d)
Michael S. Tsirkin7055e682009-06-21 19:50:13 +0300246{
Michael S. Tsirkine4890302009-09-16 13:40:37 +0300247 VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev);
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000248 virtio_pci_stop_ioeventfd(proxy);
Michael S. Tsirkin7055e682009-06-21 19:50:13 +0300249 virtio_reset(proxy->vdev);
Michael S. Tsirkin3cac0012012-08-29 19:40:56 +0300250 msix_unuse_all_vectors(&proxy->pci_dev);
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000251 proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
Michael S. Tsirkin7055e682009-06-21 19:50:13 +0300252}
253
Paul Brook53c25ce2009-05-18 14:51:59 +0100254static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
255{
256 VirtIOPCIProxy *proxy = opaque;
257 VirtIODevice *vdev = proxy->vdev;
Avi Kivitya8170e52012-10-23 12:30:10 +0200258 hwaddr pa;
Paul Brook53c25ce2009-05-18 14:51:59 +0100259
Paul Brook53c25ce2009-05-18 14:51:59 +0100260 switch (addr) {
261 case VIRTIO_PCI_GUEST_FEATURES:
262 /* Guest does not negotiate properly? We have to assume nothing. */
263 if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
Paolo Bonziniad0c9332011-11-24 13:28:52 +0100264 val = vdev->bad_features ? vdev->bad_features(vdev) : 0;
Paul Brook53c25ce2009-05-18 14:51:59 +0100265 }
Paolo Bonziniad0c9332011-11-24 13:28:52 +0100266 virtio_set_features(vdev, val);
Paul Brook53c25ce2009-05-18 14:51:59 +0100267 break;
268 case VIRTIO_PCI_QUEUE_PFN:
Avi Kivitya8170e52012-10-23 12:30:10 +0200269 pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
Michael S. Tsirkin1b8e9b22009-11-24 16:45:35 +0200270 if (pa == 0) {
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000271 virtio_pci_stop_ioeventfd(proxy);
Michael S. Tsirkin1b8e9b22009-11-24 16:45:35 +0200272 virtio_reset(proxy->vdev);
273 msix_unuse_all_vectors(&proxy->pci_dev);
274 }
Michael S. Tsirkin7055e682009-06-21 19:50:13 +0300275 else
276 virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
Paul Brook53c25ce2009-05-18 14:51:59 +0100277 break;
278 case VIRTIO_PCI_QUEUE_SEL:
279 if (val < VIRTIO_PCI_QUEUE_MAX)
280 vdev->queue_sel = val;
281 break;
282 case VIRTIO_PCI_QUEUE_NOTIFY:
Stefan Hajnoczi7157e2e2011-05-08 22:29:07 +0100283 if (val < VIRTIO_PCI_QUEUE_MAX) {
284 virtio_queue_notify(vdev, val);
285 }
Paul Brook53c25ce2009-05-18 14:51:59 +0100286 break;
287 case VIRTIO_PCI_STATUS:
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000288 if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
289 virtio_pci_stop_ioeventfd(proxy);
290 }
291
Michael S. Tsirkin3e607cb2010-03-17 13:08:05 +0200292 virtio_set_status(vdev, val & 0xFF);
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000293
294 if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
295 virtio_pci_start_ioeventfd(proxy);
296 }
297
Michael S. Tsirkin1b8e9b22009-11-24 16:45:35 +0200298 if (vdev->status == 0) {
299 virtio_reset(proxy->vdev);
300 msix_unuse_all_vectors(&proxy->pci_dev);
301 }
Alexander Grafc81131d2010-03-16 19:18:07 +0100302
303 /* Linux before 2.6.34 sets the device as OK without enabling
304 the PCI device bus master bit. In this case we need to disable
305 some safety checks. */
306 if ((val & VIRTIO_CONFIG_S_DRIVER_OK) &&
307 !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
Stefan Hajnoczi3dbca8e2010-12-17 12:01:49 +0000308 proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
Alexander Grafc81131d2010-03-16 19:18:07 +0100309 }
Paul Brook53c25ce2009-05-18 14:51:59 +0100310 break;
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +0300311 case VIRTIO_MSI_CONFIG_VECTOR:
312 msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
313 /* Make it possible for guest to discover an error took place. */
314 if (msix_vector_use(&proxy->pci_dev, val) < 0)
315 val = VIRTIO_NO_VECTOR;
316 vdev->config_vector = val;
317 break;
318 case VIRTIO_MSI_QUEUE_VECTOR:
319 msix_vector_unuse(&proxy->pci_dev,
320 virtio_queue_vector(vdev, vdev->queue_sel));
321 /* Make it possible for guest to discover an error took place. */
322 if (msix_vector_use(&proxy->pci_dev, val) < 0)
323 val = VIRTIO_NO_VECTOR;
324 virtio_queue_set_vector(vdev, vdev->queue_sel, val);
325 break;
326 default:
Stefan Hajnoczi4e02d462010-11-15 20:44:38 +0000327 error_report("%s: unexpected address 0x%x value 0x%x",
328 __func__, addr, val);
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +0300329 break;
Paul Brook53c25ce2009-05-18 14:51:59 +0100330 }
331}
332
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +0300333static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
Paul Brook53c25ce2009-05-18 14:51:59 +0100334{
Paul Brook53c25ce2009-05-18 14:51:59 +0100335 VirtIODevice *vdev = proxy->vdev;
336 uint32_t ret = 0xFFFFFFFF;
337
Paul Brook53c25ce2009-05-18 14:51:59 +0100338 switch (addr) {
339 case VIRTIO_PCI_HOST_FEATURES:
Michael S. Tsirkin81725392010-01-10 13:52:53 +0200340 ret = proxy->host_features;
Paul Brook53c25ce2009-05-18 14:51:59 +0100341 break;
342 case VIRTIO_PCI_GUEST_FEATURES:
Michael S. Tsirkin704a76f2010-01-10 13:52:47 +0200343 ret = vdev->guest_features;
Paul Brook53c25ce2009-05-18 14:51:59 +0100344 break;
345 case VIRTIO_PCI_QUEUE_PFN:
346 ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
347 >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
348 break;
349 case VIRTIO_PCI_QUEUE_NUM:
350 ret = virtio_queue_get_num(vdev, vdev->queue_sel);
351 break;
352 case VIRTIO_PCI_QUEUE_SEL:
353 ret = vdev->queue_sel;
354 break;
355 case VIRTIO_PCI_STATUS:
356 ret = vdev->status;
357 break;
358 case VIRTIO_PCI_ISR:
359 /* reading from the ISR also clears it. */
360 ret = vdev->isr;
361 vdev->isr = 0;
Michael S. Tsirkin7055e682009-06-21 19:50:13 +0300362 qemu_set_irq(proxy->pci_dev.irq[0], 0);
Paul Brook53c25ce2009-05-18 14:51:59 +0100363 break;
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +0300364 case VIRTIO_MSI_CONFIG_VECTOR:
365 ret = vdev->config_vector;
366 break;
367 case VIRTIO_MSI_QUEUE_VECTOR:
368 ret = virtio_queue_vector(vdev, vdev->queue_sel);
369 break;
Paul Brook53c25ce2009-05-18 14:51:59 +0100370 default:
371 break;
372 }
373
374 return ret;
375}
376
Alexander Grafdf6db5b2012-10-08 13:02:30 +0200377static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
378 unsigned size)
Paul Brook53c25ce2009-05-18 14:51:59 +0100379{
380 VirtIOPCIProxy *proxy = opaque;
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +0300381 uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
Alexander Grafdf6db5b2012-10-08 13:02:30 +0200382 uint64_t val = 0;
383 if (addr < config) {
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +0300384 return virtio_ioport_read(proxy, addr);
Alexander Grafdf6db5b2012-10-08 13:02:30 +0200385 }
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +0300386 addr -= config;
Paul Brook53c25ce2009-05-18 14:51:59 +0100387
Alexander Grafdf6db5b2012-10-08 13:02:30 +0200388 switch (size) {
389 case 1:
390 val = virtio_config_readb(proxy->vdev, addr);
391 break;
392 case 2:
393 val = virtio_config_readw(proxy->vdev, addr);
394 if (virtio_is_big_endian()) {
395 val = bswap16(val);
396 }
397 break;
398 case 4:
399 val = virtio_config_readl(proxy->vdev, addr);
400 if (virtio_is_big_endian()) {
401 val = bswap32(val);
402 }
403 break;
Benjamin Herrenschmidt82afa582012-01-10 01:35:11 +0000404 }
405 return val;
Paul Brook53c25ce2009-05-18 14:51:59 +0100406}
407
Alexander Grafdf6db5b2012-10-08 13:02:30 +0200408static void virtio_pci_config_write(void *opaque, hwaddr addr,
409 uint64_t val, unsigned size)
Paul Brook53c25ce2009-05-18 14:51:59 +0100410{
411 VirtIOPCIProxy *proxy = opaque;
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +0300412 uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +0300413 if (addr < config) {
414 virtio_ioport_write(proxy, addr, val);
415 return;
416 }
417 addr -= config;
Alexander Grafdf6db5b2012-10-08 13:02:30 +0200418 /*
419 * Virtio-PCI is odd. Ioports are LE but config space is target native
420 * endian.
421 */
422 switch (size) {
423 case 1:
424 virtio_config_writeb(proxy->vdev, addr, val);
425 break;
426 case 2:
427 if (virtio_is_big_endian()) {
428 val = bswap16(val);
429 }
430 virtio_config_writew(proxy->vdev, addr, val);
431 break;
432 case 4:
433 if (virtio_is_big_endian()) {
434 val = bswap32(val);
435 }
436 virtio_config_writel(proxy->vdev, addr, val);
437 break;
438 }
Paul Brook53c25ce2009-05-18 14:51:59 +0100439}
440
Avi Kivityda146d02011-08-08 16:09:13 +0300441static const MemoryRegionOps virtio_pci_config_ops = {
Alexander Grafdf6db5b2012-10-08 13:02:30 +0200442 .read = virtio_pci_config_read,
443 .write = virtio_pci_config_write,
444 .impl = {
445 .min_access_size = 1,
446 .max_access_size = 4,
447 },
Avi Kivityda146d02011-08-08 16:09:13 +0300448 .endianness = DEVICE_LITTLE_ENDIAN,
449};
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +0300450
451static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
452 uint32_t val, int len)
453{
Yan Vugenfirered757e12009-09-08 10:49:41 -0400454 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
455
Michael S. Tsirkin11297142011-07-27 11:08:20 +0300456 pci_default_write_config(pci_dev, address, val, len);
457
458 if (range_covers_byte(address, len, PCI_COMMAND) &&
459 !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) &&
460 !(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) {
461 virtio_pci_stop_ioeventfd(proxy);
462 virtio_set_status(proxy->vdev,
463 proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
Yan Vugenfirered757e12009-09-08 10:49:41 -0400464 }
Paul Brook53c25ce2009-05-18 14:51:59 +0100465}
466
Michael S. Tsirkin6d74ca52009-12-08 20:07:48 +0200467static unsigned virtio_pci_get_features(void *opaque)
468{
Michael S. Tsirkin81725392010-01-10 13:52:53 +0200469 VirtIOPCIProxy *proxy = opaque;
470 return proxy->host_features;
Michael S. Tsirkin6d74ca52009-12-08 20:07:48 +0200471}
472
Jan Kiszka7d37d352012-05-17 10:32:39 -0300473static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
474 unsigned int queue_no,
475 unsigned int vector,
476 MSIMessage msg)
477{
478 VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
Paolo Bonzini15b2bd12012-07-05 17:16:30 +0200479 EventNotifier *n = virtio_queue_get_guest_notifier(vq);
Jan Kiszka7d37d352012-05-17 10:32:39 -0300480 VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
Paolo Bonzini15b2bd12012-07-05 17:16:30 +0200481 int ret;
Jan Kiszka7d37d352012-05-17 10:32:39 -0300482
483 if (irqfd->users == 0) {
484 ret = kvm_irqchip_add_msi_route(kvm_state, msg);
485 if (ret < 0) {
486 return ret;
487 }
488 irqfd->virq = ret;
489 }
490 irqfd->users++;
491
Jan Kiszkab131c742012-08-20 10:55:56 +0200492 ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq);
Jan Kiszka7d37d352012-05-17 10:32:39 -0300493 if (ret < 0) {
494 if (--irqfd->users == 0) {
495 kvm_irqchip_release_virq(kvm_state, irqfd->virq);
496 }
497 return ret;
498 }
499
Paolo Bonzini15b2bd12012-07-05 17:16:30 +0200500 virtio_queue_set_guest_notifier_fd_handler(vq, true, true);
Jan Kiszka7d37d352012-05-17 10:32:39 -0300501 return 0;
502}
503
504static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
505 unsigned int queue_no,
506 unsigned int vector)
507{
508 VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
Paolo Bonzini15b2bd12012-07-05 17:16:30 +0200509 EventNotifier *n = virtio_queue_get_guest_notifier(vq);
Jan Kiszka7d37d352012-05-17 10:32:39 -0300510 VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
Paolo Bonzini15b2bd12012-07-05 17:16:30 +0200511 int ret;
Jan Kiszka7d37d352012-05-17 10:32:39 -0300512
Jan Kiszkab131c742012-08-20 10:55:56 +0200513 ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq);
Jan Kiszka7d37d352012-05-17 10:32:39 -0300514 assert(ret == 0);
515
516 if (--irqfd->users == 0) {
517 kvm_irqchip_release_virq(kvm_state, irqfd->virq);
518 }
519
Paolo Bonzini15b2bd12012-07-05 17:16:30 +0200520 virtio_queue_set_guest_notifier_fd_handler(vq, true, false);
Jan Kiszka7d37d352012-05-17 10:32:39 -0300521}
522
523static int kvm_virtio_pci_vector_use(PCIDevice *dev, unsigned vector,
524 MSIMessage msg)
525{
526 VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
527 VirtIODevice *vdev = proxy->vdev;
528 int ret, queue_no;
529
530 for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) {
531 if (!virtio_queue_get_num(vdev, queue_no)) {
532 break;
533 }
534 if (virtio_queue_vector(vdev, queue_no) != vector) {
535 continue;
536 }
537 ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg);
538 if (ret < 0) {
539 goto undo;
540 }
541 }
542 return 0;
543
544undo:
545 while (--queue_no >= 0) {
546 if (virtio_queue_vector(vdev, queue_no) != vector) {
547 continue;
548 }
549 kvm_virtio_pci_vq_vector_release(proxy, queue_no, vector);
550 }
551 return ret;
552}
553
554static void kvm_virtio_pci_vector_release(PCIDevice *dev, unsigned vector)
555{
556 VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
557 VirtIODevice *vdev = proxy->vdev;
558 int queue_no;
559
560 for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) {
561 if (!virtio_queue_get_num(vdev, queue_no)) {
562 break;
563 }
564 if (virtio_queue_vector(vdev, queue_no) != vector) {
565 continue;
566 }
567 kvm_virtio_pci_vq_vector_release(proxy, queue_no, vector);
568 }
569}
570
Michael S. Tsirkinade80dc2010-03-17 13:08:13 +0200571static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign)
572{
573 VirtIOPCIProxy *proxy = opaque;
574 VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
575 EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
576
577 if (assign) {
578 int r = event_notifier_init(notifier, 0);
579 if (r < 0) {
580 return r;
581 }
Paolo Bonzini15b2bd12012-07-05 17:16:30 +0200582 virtio_queue_set_guest_notifier_fd_handler(vq, true, false);
Michael S. Tsirkinade80dc2010-03-17 13:08:13 +0200583 } else {
Paolo Bonzini15b2bd12012-07-05 17:16:30 +0200584 virtio_queue_set_guest_notifier_fd_handler(vq, false, false);
Michael S. Tsirkinade80dc2010-03-17 13:08:13 +0200585 event_notifier_cleanup(notifier);
586 }
587
588 return 0;
589}
590
mst@redhat.com5430a282011-02-01 22:13:42 +0200591static bool virtio_pci_query_guest_notifiers(void *opaque)
592{
593 VirtIOPCIProxy *proxy = opaque;
594 return msix_enabled(&proxy->pci_dev);
595}
596
Michael S. Tsirkin54dd9322010-10-06 15:20:17 +0200597static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
598{
599 VirtIOPCIProxy *proxy = opaque;
600 VirtIODevice *vdev = proxy->vdev;
601 int r, n;
602
Jan Kiszka7d37d352012-05-17 10:32:39 -0300603 /* Must unset vector notifier while guest notifier is still assigned */
Peter Maydell614e41b2012-07-26 15:35:15 +0100604 if (kvm_msi_via_irqfd_enabled() && !assign) {
Jan Kiszka7d37d352012-05-17 10:32:39 -0300605 msix_unset_vector_notifiers(&proxy->pci_dev);
606 g_free(proxy->vector_irqfd);
607 proxy->vector_irqfd = NULL;
608 }
609
Michael S. Tsirkin54dd9322010-10-06 15:20:17 +0200610 for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
611 if (!virtio_queue_get_num(vdev, n)) {
612 break;
613 }
614
615 r = virtio_pci_set_guest_notifier(opaque, n, assign);
616 if (r < 0) {
617 goto assign_error;
618 }
619 }
620
Jan Kiszka7d37d352012-05-17 10:32:39 -0300621 /* Must set vector notifier after guest notifier has been assigned */
Peter Maydell614e41b2012-07-26 15:35:15 +0100622 if (kvm_msi_via_irqfd_enabled() && assign) {
Jan Kiszka7d37d352012-05-17 10:32:39 -0300623 proxy->vector_irqfd =
624 g_malloc0(sizeof(*proxy->vector_irqfd) *
625 msix_nr_vectors_allocated(&proxy->pci_dev));
626 r = msix_set_vector_notifiers(&proxy->pci_dev,
627 kvm_virtio_pci_vector_use,
628 kvm_virtio_pci_vector_release);
629 if (r < 0) {
630 goto assign_error;
631 }
632 }
633
Michael S. Tsirkin54dd9322010-10-06 15:20:17 +0200634 return 0;
635
636assign_error:
637 /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
Jan Kiszka7d37d352012-05-17 10:32:39 -0300638 assert(assign);
Michael S. Tsirkin54dd9322010-10-06 15:20:17 +0200639 while (--n >= 0) {
640 virtio_pci_set_guest_notifier(opaque, n, !assign);
641 }
642 return r;
643}
644
Michael S. Tsirkinade80dc2010-03-17 13:08:13 +0200645static int virtio_pci_set_host_notifier(void *opaque, int n, bool assign)
646{
647 VirtIOPCIProxy *proxy = opaque;
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000648
649 /* Stop using ioeventfd for virtqueue kick if the device starts using host
650 * notifiers. This makes it easy to avoid stepping on each others' toes.
651 */
652 proxy->ioeventfd_disabled = assign;
Michael S. Tsirkinade80dc2010-03-17 13:08:13 +0200653 if (assign) {
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000654 virtio_pci_stop_ioeventfd(proxy);
Michael S. Tsirkinade80dc2010-03-17 13:08:13 +0200655 }
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000656 /* We don't need to start here: it's not needed because backend
657 * currently only stops on status change away from ok,
658 * reset, vmstop and such. If we do add code to start here,
659 * need to check vmstate, device state etc. */
Paolo Bonzini26b9b5f2012-08-06 15:26:14 +0200660 return virtio_pci_set_host_notifier_internal(proxy, n, assign, false);
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000661}
662
663static void virtio_pci_vmstate_change(void *opaque, bool running)
664{
665 VirtIOPCIProxy *proxy = opaque;
666
667 if (running) {
Michael S. Tsirkin89c473f2011-03-19 19:28:19 +0200668 /* Try to find out if the guest has bus master disabled, but is
669 in ready state. Then we have a buggy guest OS. */
670 if ((proxy->vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
671 !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
672 proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
673 }
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000674 virtio_pci_start_ioeventfd(proxy);
675 } else {
676 virtio_pci_stop_ioeventfd(proxy);
677 }
Michael S. Tsirkinade80dc2010-03-17 13:08:13 +0200678}
679
Paul Brook53c25ce2009-05-18 14:51:59 +0100680static const VirtIOBindings virtio_pci_bindings = {
Michael S. Tsirkinff24bd52009-06-21 19:50:40 +0300681 .notify = virtio_pci_notify,
682 .save_config = virtio_pci_save_config,
683 .load_config = virtio_pci_load_config,
684 .save_queue = virtio_pci_save_queue,
685 .load_queue = virtio_pci_load_queue,
Michael S. Tsirkin6d74ca52009-12-08 20:07:48 +0200686 .get_features = virtio_pci_get_features,
mst@redhat.com5430a282011-02-01 22:13:42 +0200687 .query_guest_notifiers = virtio_pci_query_guest_notifiers,
Michael S. Tsirkinade80dc2010-03-17 13:08:13 +0200688 .set_host_notifier = virtio_pci_set_host_notifier,
Michael S. Tsirkin54dd9322010-10-06 15:20:17 +0200689 .set_guest_notifiers = virtio_pci_set_guest_notifiers,
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000690 .vmstate_change = virtio_pci_vmstate_change,
Paul Brook53c25ce2009-05-18 14:51:59 +0100691};
692
Michael S. Tsirkinbefeac42011-06-14 17:51:11 +0300693void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev)
Paul Brook53c25ce2009-05-18 14:51:59 +0100694{
695 uint8_t *config;
696 uint32_t size;
697
698 proxy->vdev = vdev;
699
700 config = proxy->pci_dev.config;
Paul Brook53c25ce2009-05-18 14:51:59 +0100701
Isaku Yamahatae75ccf22011-05-25 10:58:36 +0900702 if (proxy->class_code) {
703 pci_config_set_class(config, proxy->class_code);
704 }
Hui Kai Ranad3d11e2011-12-08 13:49:13 +0800705 pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
706 pci_get_word(config + PCI_VENDOR_ID));
707 pci_set_word(config + PCI_SUBSYSTEM_ID, vdev->device_id);
708 config[PCI_INTERRUPT_PIN] = 1;
Paul Brook53c25ce2009-05-18 14:51:59 +0100709
Alex Williamsonb2357c42012-06-14 12:16:10 -0600710 if (vdev->nvectors &&
711 msix_init_exclusive_bar(&proxy->pci_dev, vdev->nvectors, 1)) {
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +0300712 vdev->nvectors = 0;
Alex Williamsonb2357c42012-06-14 12:16:10 -0600713 }
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +0300714
Yan Vugenfirered757e12009-09-08 10:49:41 -0400715 proxy->pci_dev.config_write = virtio_write_config;
716
Michael S. Tsirkinaba800a2009-06-21 19:50:26 +0300717 size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + vdev->config_len;
Paul Brook53c25ce2009-05-18 14:51:59 +0100718 if (size & (size-1))
719 size = 1 << qemu_fls(size);
720
Avi Kivityda146d02011-08-08 16:09:13 +0300721 memory_region_init_io(&proxy->bar, &virtio_pci_config_ops, proxy,
722 "virtio-pci", size);
Avi Kivitye824b2c2011-08-08 16:09:31 +0300723 pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
724 &proxy->bar);
Paul Brook53c25ce2009-05-18 14:51:59 +0100725
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000726 if (!kvm_has_many_ioeventfds()) {
727 proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
728 }
729
Paul Brook53c25ce2009-05-18 14:51:59 +0100730 virtio_bind_device(vdev, &virtio_pci_bindings, proxy);
Michael S. Tsirkin81725392010-01-10 13:52:53 +0200731 proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
732 proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
733 proxy->host_features = vdev->get_features(vdev, proxy->host_features);
Paul Brook53c25ce2009-05-18 14:51:59 +0100734}
735
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200736static int virtio_blk_init_pci(PCIDevice *pci_dev)
Paul Brook53c25ce2009-05-18 14:51:59 +0100737{
738 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
739 VirtIODevice *vdev;
740
Mark McLoughlin85c2c732009-07-30 11:29:13 +0100741 if (proxy->class_code != PCI_CLASS_STORAGE_SCSI &&
742 proxy->class_code != PCI_CLASS_STORAGE_OTHER)
743 proxy->class_code = PCI_CLASS_STORAGE_SCSI;
744
Paolo Bonzini12c56742012-05-16 12:54:05 +0200745 vdev = virtio_blk_init(&pci_dev->qdev, &proxy->blk);
Markus Armbrusterac0c14d2010-07-06 14:37:42 +0200746 if (!vdev) {
747 return -1;
748 }
Gerd Hoffmann177539e2009-08-12 12:47:24 +0200749 vdev->nvectors = proxy->nvectors;
Isaku Yamahatae75ccf22011-05-25 10:58:36 +0900750 virtio_init_pci(proxy, vdev);
Gerd Hoffmann177539e2009-08-12 12:47:24 +0200751 /* make the actual value visible */
752 proxy->nvectors = vdev->nvectors;
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200753 return 0;
Mark McLoughlin21d58b52009-07-07 12:09:58 +0100754}
755
Alex Williamsonf90c2bc2012-07-03 22:39:27 -0600756static void virtio_exit_pci(PCIDevice *pci_dev)
Michael S. Tsirkin0f457d92009-10-05 23:02:20 +0200757{
Avi Kivityda146d02011-08-08 16:09:13 +0300758 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
759
760 memory_region_destroy(&proxy->bar);
Alex Williamsonb2357c42012-06-14 12:16:10 -0600761 msix_uninit_exclusive_bar(pci_dev);
Michael S. Tsirkin0f457d92009-10-05 23:02:20 +0200762}
763
Alex Williamsonf90c2bc2012-07-03 22:39:27 -0600764static void virtio_blk_exit_pci(PCIDevice *pci_dev)
Gerd Hoffmann56a14932009-09-25 21:42:46 +0200765{
766 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
767
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000768 virtio_pci_stop_ioeventfd(proxy);
Alex Williamson9d0d3132010-07-20 11:14:22 -0600769 virtio_blk_exit(proxy->vdev);
Alex Williamsonf90c2bc2012-07-03 22:39:27 -0600770 virtio_exit_pci(pci_dev);
Gerd Hoffmann56a14932009-09-25 21:42:46 +0200771}
772
Amit Shah98b19252010-01-20 00:36:52 +0530773static int virtio_serial_init_pci(PCIDevice *pci_dev)
Mark McLoughlin21d58b52009-07-07 12:09:58 +0100774{
Gerd Hoffmannd6beee92009-07-15 13:48:24 +0200775 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
Mark McLoughlin85c2c732009-07-30 11:29:13 +0100776 VirtIODevice *vdev;
777
Gerd Hoffmannd6beee92009-07-15 13:48:24 +0200778 if (proxy->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
779 proxy->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
780 proxy->class_code != PCI_CLASS_OTHERS) /* qemu-kvm */
781 proxy->class_code = PCI_CLASS_COMMUNICATION_OTHER;
782
Amit Shah6b331ef2011-02-03 11:22:32 +0530783 vdev = virtio_serial_init(&pci_dev->qdev, &proxy->serial);
Amit Shah25fe3652009-09-29 15:51:04 +0530784 if (!vdev) {
785 return -1;
786 }
Amit Shah573fb602010-02-25 17:24:44 +0530787 vdev->nvectors = proxy->nvectors == DEV_NVECTORS_UNSPECIFIED
Amit Shah6b331ef2011-02-03 11:22:32 +0530788 ? proxy->serial.max_virtserial_ports + 1
Amit Shah573fb602010-02-25 17:24:44 +0530789 : proxy->nvectors;
Isaku Yamahatae75ccf22011-05-25 10:58:36 +0900790 virtio_init_pci(proxy, vdev);
Amit Shaha1829202010-01-20 00:36:58 +0530791 proxy->nvectors = vdev->nvectors;
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200792 return 0;
Paul Brook53c25ce2009-05-18 14:51:59 +0100793}
794
Alex Williamsonf90c2bc2012-07-03 22:39:27 -0600795static void virtio_serial_exit_pci(PCIDevice *pci_dev)
Amit Shah8b53a862010-08-19 06:51:04 +0530796{
797 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
798
Amit Shah32059222011-02-17 12:31:10 +0530799 virtio_pci_stop_ioeventfd(proxy);
Amit Shah8b53a862010-08-19 06:51:04 +0530800 virtio_serial_exit(proxy->vdev);
Alex Williamsonf90c2bc2012-07-03 22:39:27 -0600801 virtio_exit_pci(pci_dev);
Amit Shah8b53a862010-08-19 06:51:04 +0530802}
803
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200804static int virtio_net_init_pci(PCIDevice *pci_dev)
Paul Brook53c25ce2009-05-18 14:51:59 +0100805{
806 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
807 VirtIODevice *vdev;
808
Alex Williamsonf0c07c72010-09-02 09:00:50 -0600809 vdev = virtio_net_init(&pci_dev->qdev, &proxy->nic, &proxy->net);
Gerd Hoffmanna1e0fea2009-07-15 13:48:25 +0200810
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200811 vdev->nvectors = proxy->nvectors;
Isaku Yamahatae75ccf22011-05-25 10:58:36 +0900812 virtio_init_pci(proxy, vdev);
Gerd Hoffmanna1e0fea2009-07-15 13:48:25 +0200813
814 /* make the actual value visible */
815 proxy->nvectors = vdev->nvectors;
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200816 return 0;
Paul Brook53c25ce2009-05-18 14:51:59 +0100817}
818
Alex Williamsonf90c2bc2012-07-03 22:39:27 -0600819static void virtio_net_exit_pci(PCIDevice *pci_dev)
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200820{
821 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
822
Stefan Hajnoczi25db9eb2010-12-17 12:01:50 +0000823 virtio_pci_stop_ioeventfd(proxy);
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200824 virtio_net_exit(proxy->vdev);
Alex Williamsonf90c2bc2012-07-03 22:39:27 -0600825 virtio_exit_pci(pci_dev);
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200826}
827
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200828static int virtio_balloon_init_pci(PCIDevice *pci_dev)
Paul Brook53c25ce2009-05-18 14:51:59 +0100829{
830 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
831 VirtIODevice *vdev;
832
David Gibson2ba1d382012-04-03 17:24:11 +0300833 if (proxy->class_code != PCI_CLASS_OTHERS &&
834 proxy->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
835 proxy->class_code = PCI_CLASS_OTHERS;
836 }
837
Paul Brook53c25ce2009-05-18 14:51:59 +0100838 vdev = virtio_balloon_init(&pci_dev->qdev);
Amit Shahf76f6652011-07-27 12:29:33 +0530839 if (!vdev) {
840 return -1;
841 }
Isaku Yamahatae75ccf22011-05-25 10:58:36 +0900842 virtio_init_pci(proxy, vdev);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200843 return 0;
Paul Brook53c25ce2009-05-18 14:51:59 +0100844}
845
Alex Williamsonf90c2bc2012-07-03 22:39:27 -0600846static void virtio_balloon_exit_pci(PCIDevice *pci_dev)
Amit Shah855d7e22011-07-27 13:50:41 +0530847{
848 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
849
850 virtio_pci_stop_ioeventfd(proxy);
851 virtio_balloon_exit(proxy->vdev);
Alex Williamsonf90c2bc2012-07-03 22:39:27 -0600852 virtio_exit_pci(pci_dev);
Amit Shah855d7e22011-07-27 13:50:41 +0530853}
854
Amit Shah16c915b2012-06-20 12:29:32 +0530855static int virtio_rng_init_pci(PCIDevice *pci_dev)
856{
857 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
858 VirtIODevice *vdev;
859
Anthony Liguori500054f2012-10-26 12:05:49 -0500860 if (proxy->rng.rng == NULL) {
861 proxy->rng.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
862
863 object_property_add_child(OBJECT(pci_dev),
864 "default-backend",
865 OBJECT(proxy->rng.default_backend),
866 NULL);
867
868 object_property_set_link(OBJECT(pci_dev),
869 OBJECT(proxy->rng.default_backend),
870 "rng", NULL);
871 }
872
Amit Shah16c915b2012-06-20 12:29:32 +0530873 vdev = virtio_rng_init(&pci_dev->qdev, &proxy->rng);
874 if (!vdev) {
875 return -1;
876 }
877 virtio_init_pci(proxy, vdev);
878 return 0;
879}
880
881static void virtio_rng_exit_pci(PCIDevice *pci_dev)
882{
883 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
884
885 virtio_pci_stop_ioeventfd(proxy);
886 virtio_rng_exit(proxy->vdev);
887 virtio_exit_pci(pci_dev);
888}
889
Anthony Liguori40021f02011-12-04 12:22:06 -0600890static Property virtio_blk_properties[] = {
891 DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
Paolo Bonzini12c56742012-05-16 12:54:05 +0200892 DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, blk.conf),
Markus Armbrustere63e7fd2012-07-10 11:12:43 +0200893 DEFINE_BLOCK_CHS_PROPERTIES(VirtIOPCIProxy, blk.conf),
Paolo Bonzini12c56742012-05-16 12:54:05 +0200894 DEFINE_PROP_STRING("serial", VirtIOPCIProxy, blk.serial),
Paolo Bonzinia6c5c842012-05-16 12:54:06 +0200895#ifdef __linux__
896 DEFINE_PROP_BIT("scsi", VirtIOPCIProxy, blk.scsi, 0, true),
897#endif
Stefan Hajnoczieec7f962012-08-16 09:57:49 +0100898 DEFINE_PROP_BIT("config-wce", VirtIOPCIProxy, blk.config_wce, 0, true),
Anthony Liguori40021f02011-12-04 12:22:06 -0600899 DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
900 DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
901 DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
902 DEFINE_PROP_END_OF_LIST(),
Anthony Liguorie8557612011-12-06 19:32:44 -0600903};
904
Anthony Liguori40021f02011-12-04 12:22:06 -0600905static void virtio_blk_class_init(ObjectClass *klass, void *data)
906{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600907 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori40021f02011-12-04 12:22:06 -0600908 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
909
910 k->init = virtio_blk_init_pci;
911 k->exit = virtio_blk_exit_pci;
912 k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
913 k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
914 k->revision = VIRTIO_PCI_ABI_VERSION;
915 k->class_id = PCI_CLASS_STORAGE_SCSI;
Anthony Liguori39bffca2011-12-07 21:34:16 -0600916 dc->reset = virtio_pci_reset;
917 dc->props = virtio_blk_properties;
Anthony Liguori40021f02011-12-04 12:22:06 -0600918}
919
Anthony Liguori39bffca2011-12-07 21:34:16 -0600920static TypeInfo virtio_blk_info = {
921 .name = "virtio-blk-pci",
922 .parent = TYPE_PCI_DEVICE,
923 .instance_size = sizeof(VirtIOPCIProxy),
924 .class_init = virtio_blk_class_init,
Anthony Liguorie8557612011-12-06 19:32:44 -0600925};
926
Anthony Liguori40021f02011-12-04 12:22:06 -0600927static Property virtio_net_properties[] = {
928 DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
929 DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
930 DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
931 DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
932 DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy, net.txtimer, TX_TIMER_INTERVAL),
933 DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy, net.txburst, TX_BURST),
934 DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
935 DEFINE_PROP_END_OF_LIST(),
Anthony Liguorie8557612011-12-06 19:32:44 -0600936};
937
Anthony Liguori40021f02011-12-04 12:22:06 -0600938static void virtio_net_class_init(ObjectClass *klass, void *data)
939{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600940 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori40021f02011-12-04 12:22:06 -0600941 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
942
943 k->init = virtio_net_init_pci;
944 k->exit = virtio_net_exit_pci;
945 k->romfile = "pxe-virtio.rom";
946 k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
947 k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
948 k->revision = VIRTIO_PCI_ABI_VERSION;
949 k->class_id = PCI_CLASS_NETWORK_ETHERNET;
Anthony Liguori39bffca2011-12-07 21:34:16 -0600950 dc->reset = virtio_pci_reset;
951 dc->props = virtio_net_properties;
Anthony Liguori40021f02011-12-04 12:22:06 -0600952}
953
Anthony Liguori39bffca2011-12-07 21:34:16 -0600954static TypeInfo virtio_net_info = {
955 .name = "virtio-net-pci",
956 .parent = TYPE_PCI_DEVICE,
957 .instance_size = sizeof(VirtIOPCIProxy),
958 .class_init = virtio_net_class_init,
Anthony Liguori40021f02011-12-04 12:22:06 -0600959};
960
961static Property virtio_serial_properties[] = {
962 DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
963 DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, DEV_NVECTORS_UNSPECIFIED),
964 DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
965 DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
966 DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, serial.max_virtserial_ports, 31),
967 DEFINE_PROP_END_OF_LIST(),
968};
969
970static void virtio_serial_class_init(ObjectClass *klass, void *data)
971{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600972 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori40021f02011-12-04 12:22:06 -0600973 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
974
975 k->init = virtio_serial_init_pci;
976 k->exit = virtio_serial_exit_pci;
977 k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
978 k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
979 k->revision = VIRTIO_PCI_ABI_VERSION;
980 k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
Anthony Liguori39bffca2011-12-07 21:34:16 -0600981 dc->reset = virtio_pci_reset;
982 dc->props = virtio_serial_properties;
Anthony Liguori40021f02011-12-04 12:22:06 -0600983}
984
Anthony Liguori39bffca2011-12-07 21:34:16 -0600985static TypeInfo virtio_serial_info = {
986 .name = "virtio-serial-pci",
987 .parent = TYPE_PCI_DEVICE,
988 .instance_size = sizeof(VirtIOPCIProxy),
989 .class_init = virtio_serial_class_init,
Anthony Liguori40021f02011-12-04 12:22:06 -0600990};
991
992static Property virtio_balloon_properties[] = {
993 DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
David Gibson2ba1d382012-04-03 17:24:11 +0300994 DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
Anthony Liguori40021f02011-12-04 12:22:06 -0600995 DEFINE_PROP_END_OF_LIST(),
996};
997
998static void virtio_balloon_class_init(ObjectClass *klass, void *data)
999{
Anthony Liguori39bffca2011-12-07 21:34:16 -06001000 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori40021f02011-12-04 12:22:06 -06001001 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1002
1003 k->init = virtio_balloon_init_pci;
1004 k->exit = virtio_balloon_exit_pci;
1005 k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1006 k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
1007 k->revision = VIRTIO_PCI_ABI_VERSION;
David Gibson2ba1d382012-04-03 17:24:11 +03001008 k->class_id = PCI_CLASS_OTHERS;
Anthony Liguori39bffca2011-12-07 21:34:16 -06001009 dc->reset = virtio_pci_reset;
1010 dc->props = virtio_balloon_properties;
Anthony Liguori40021f02011-12-04 12:22:06 -06001011}
1012
Anthony Liguori39bffca2011-12-07 21:34:16 -06001013static TypeInfo virtio_balloon_info = {
1014 .name = "virtio-balloon-pci",
1015 .parent = TYPE_PCI_DEVICE,
1016 .instance_size = sizeof(VirtIOPCIProxy),
1017 .class_init = virtio_balloon_class_init,
Gerd Hoffmann0aab0d32009-06-30 14:12:07 +02001018};
1019
Amit Shah16c915b2012-06-20 12:29:32 +05301020static void virtio_rng_initfn(Object *obj)
1021{
1022 PCIDevice *pci_dev = PCI_DEVICE(obj);
1023 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
1024
1025 object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
1026 (Object **)&proxy->rng.rng, NULL);
1027}
1028
1029static Property virtio_rng_properties[] = {
1030 DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
Anthony Liguori904d6f52012-10-30 17:45:05 -05001031 /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s. If
1032 you have an entropy source capable of generating more entropy than this
1033 and you can pass it through via virtio-rng, then hats off to you. Until
1034 then, this is unlimited for all practical purposes.
1035 */
1036 DEFINE_PROP_UINT64("max-bytes", VirtIOPCIProxy, rng.max_bytes, INT64_MAX),
1037 DEFINE_PROP_UINT32("period", VirtIOPCIProxy, rng.period_ms, 1 << 16),
Amit Shah16c915b2012-06-20 12:29:32 +05301038 DEFINE_PROP_END_OF_LIST(),
1039};
1040
1041static void virtio_rng_class_init(ObjectClass *klass, void *data)
1042{
1043 DeviceClass *dc = DEVICE_CLASS(klass);
1044 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1045
1046 k->init = virtio_rng_init_pci;
1047 k->exit = virtio_rng_exit_pci;
1048 k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1049 k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
1050 k->revision = VIRTIO_PCI_ABI_VERSION;
1051 k->class_id = PCI_CLASS_OTHERS;
1052 dc->reset = virtio_pci_reset;
1053 dc->props = virtio_rng_properties;
1054}
1055
1056static TypeInfo virtio_rng_info = {
1057 .name = "virtio-rng-pci",
1058 .parent = TYPE_PCI_DEVICE,
1059 .instance_size = sizeof(VirtIOPCIProxy),
1060 .instance_init = virtio_rng_initfn,
1061 .class_init = virtio_rng_class_init,
1062};
1063
Stefan Hajnoczi973abc72011-02-11 08:40:59 +00001064static int virtio_scsi_init_pci(PCIDevice *pci_dev)
1065{
1066 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
1067 VirtIODevice *vdev;
1068
1069 vdev = virtio_scsi_init(&pci_dev->qdev, &proxy->scsi);
1070 if (!vdev) {
1071 return -EINVAL;
1072 }
1073
Paolo Bonzini4c205d02012-07-27 14:38:03 +02001074 vdev->nvectors = proxy->nvectors == DEV_NVECTORS_UNSPECIFIED
1075 ? proxy->scsi.num_queues + 3
1076 : proxy->nvectors;
Stefan Hajnoczi973abc72011-02-11 08:40:59 +00001077 virtio_init_pci(proxy, vdev);
1078
1079 /* make the actual value visible */
1080 proxy->nvectors = vdev->nvectors;
1081 return 0;
1082}
1083
Alex Williamsonf90c2bc2012-07-03 22:39:27 -06001084static void virtio_scsi_exit_pci(PCIDevice *pci_dev)
Stefan Hajnoczi973abc72011-02-11 08:40:59 +00001085{
1086 VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
1087
1088 virtio_scsi_exit(proxy->vdev);
Alex Williamsonf90c2bc2012-07-03 22:39:27 -06001089 virtio_exit_pci(pci_dev);
Stefan Hajnoczi973abc72011-02-11 08:40:59 +00001090}
1091
1092static Property virtio_scsi_properties[] = {
Paolo Bonzini3f910902012-07-27 14:36:07 +02001093 DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
Paolo Bonzini4c205d02012-07-27 14:38:03 +02001094 DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, DEV_NVECTORS_UNSPECIFIED),
Stefan Hajnoczi973abc72011-02-11 08:40:59 +00001095 DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOPCIProxy, host_features, scsi),
1096 DEFINE_PROP_END_OF_LIST(),
1097};
1098
1099static void virtio_scsi_class_init(ObjectClass *klass, void *data)
1100{
1101 DeviceClass *dc = DEVICE_CLASS(klass);
1102 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1103
1104 k->init = virtio_scsi_init_pci;
1105 k->exit = virtio_scsi_exit_pci;
1106 k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1107 k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
1108 k->revision = 0x00;
1109 k->class_id = PCI_CLASS_STORAGE_SCSI;
1110 dc->reset = virtio_pci_reset;
1111 dc->props = virtio_scsi_properties;
1112}
1113
1114static TypeInfo virtio_scsi_info = {
1115 .name = "virtio-scsi-pci",
1116 .parent = TYPE_PCI_DEVICE,
1117 .instance_size = sizeof(VirtIOPCIProxy),
1118 .class_init = virtio_scsi_class_init,
1119};
1120
Andreas Färber83f7d432012-02-09 15:20:55 +01001121static void virtio_pci_register_types(void)
Paul Brook53c25ce2009-05-18 14:51:59 +01001122{
Anthony Liguori39bffca2011-12-07 21:34:16 -06001123 type_register_static(&virtio_blk_info);
Anthony Liguori39bffca2011-12-07 21:34:16 -06001124 type_register_static(&virtio_net_info);
Anthony Liguori39bffca2011-12-07 21:34:16 -06001125 type_register_static(&virtio_serial_info);
Anthony Liguori39bffca2011-12-07 21:34:16 -06001126 type_register_static(&virtio_balloon_info);
Stefan Hajnoczi973abc72011-02-11 08:40:59 +00001127 type_register_static(&virtio_scsi_info);
Amit Shah16c915b2012-06-20 12:29:32 +05301128 type_register_static(&virtio_rng_info);
Paul Brook53c25ce2009-05-18 14:51:59 +01001129}
1130
Andreas Färber83f7d432012-02-09 15:20:55 +01001131type_init(virtio_pci_register_types)