Commit 53c25cea7d59525ca9aa3fb01cc6947bafbbfb61
1 parent
d8ee7665
Separate virtio PCI code
Split the PCI host bindings from the VRing transport implementation. Signed-off-by: Paul Brook <paul@codesourcery.com>
Showing
14 changed files
with
474 additions
and
300 deletions
Makefile.target
| ... | ... | @@ -489,7 +489,8 @@ OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o dma-helpers.o \ |
| 489 | 489 | gdbstub.o gdbstub-xml.o sysbus.o |
| 490 | 490 | # virtio has to be here due to weird dependency between PCI and virtio-net. |
| 491 | 491 | # need to fix this properly |
| 492 | -OBJS+=virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o | |
| 492 | +OBJS+=virtio.o virtio-pci.o | |
| 493 | +OBJS+=virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o | |
| 493 | 494 | OBJS+=fw_cfg.o |
| 494 | 495 | ifdef CONFIG_KVM |
| 495 | 496 | OBJS+=kvm.o kvm-all.o | ... | ... |
hw/pc.c
| ... | ... | @@ -1137,21 +1137,21 @@ static void pc_init1(ram_addr_t ram_size, |
| 1137 | 1137 | int unit_id = 0; |
| 1138 | 1138 | |
| 1139 | 1139 | while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) { |
| 1140 | - pci_create_simple(pci_bus, -1, "virtio-blk"); | |
| 1140 | + pci_create_simple(pci_bus, -1, "virtio-blk-pci"); | |
| 1141 | 1141 | unit_id++; |
| 1142 | 1142 | } |
| 1143 | 1143 | } |
| 1144 | 1144 | |
| 1145 | 1145 | /* Add virtio balloon device */ |
| 1146 | 1146 | if (pci_enabled) { |
| 1147 | - pci_create_simple(pci_bus, -1, "virtio-balloon"); | |
| 1147 | + pci_create_simple(pci_bus, -1, "virtio-balloon-pci"); | |
| 1148 | 1148 | } |
| 1149 | 1149 | |
| 1150 | 1150 | /* Add virtio console devices */ |
| 1151 | 1151 | if (pci_enabled) { |
| 1152 | 1152 | for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) { |
| 1153 | 1153 | if (virtcon_hds[i]) { |
| 1154 | - pci_create_simple(pci_bus, -1, "virtio-console"); | |
| 1154 | + pci_create_simple(pci_bus, -1, "virtio-console-pci"); | |
| 1155 | 1155 | } |
| 1156 | 1156 | } |
| 1157 | 1157 | } | ... | ... |
hw/pci-hotplug.c
| ... | ... | @@ -120,7 +120,7 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, PCIBus *pci_bus, |
| 120 | 120 | opaque = pci_create_simple(pci_bus, -1, "lsi53c895a"); |
| 121 | 121 | break; |
| 122 | 122 | case IF_VIRTIO: |
| 123 | - opaque = pci_create_simple(pci_bus, -1, "virtio-blk"); | |
| 123 | + opaque = pci_create_simple(pci_bus, -1, "virtio-blk-pci"); | |
| 124 | 124 | qdev_init(opaque); |
| 125 | 125 | break; |
| 126 | 126 | } | ... | ... |
hw/pci.c
hw/ppc440_bamboo.c
| ... | ... | @@ -111,14 +111,14 @@ static void bamboo_init(ram_addr_t ram_size, |
| 111 | 111 | |
| 112 | 112 | /* Add virtio block devices. */ |
| 113 | 113 | while ((i = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) { |
| 114 | - pci_create_simple(pcibus, -1, "virtio-blk"); | |
| 114 | + pci_create_simple(pcibus, -1, "virtio-blk-pci"); | |
| 115 | 115 | unit_id++; |
| 116 | 116 | } |
| 117 | 117 | |
| 118 | 118 | /* Add virtio console devices */ |
| 119 | 119 | for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) { |
| 120 | 120 | if (virtcon_hds[i]) { |
| 121 | - pci_create_simple(pcibus, -1, "virtio-console"); | |
| 121 | + pci_create_simple(pcibus, -1, "virtio-console-pci"); | |
| 122 | 122 | } |
| 123 | 123 | } |
| 124 | 124 | ... | ... |
hw/ppce500_mpc8544ds.c
| ... | ... | @@ -220,7 +220,7 @@ static void mpc8544ds_init(ram_addr_t ram_size, |
| 220 | 220 | |
| 221 | 221 | /* Add virtio block devices. */ |
| 222 | 222 | while ((i = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) { |
| 223 | - pci_create_simple(pci_bus, -1, "virtio-blk"); | |
| 223 | + pci_create_simple(pci_bus, -1, "virtio-blk-pci"); | |
| 224 | 224 | unit_id++; |
| 225 | 225 | } |
| 226 | 226 | ... | ... |
hw/virtio-balloon.c
| ... | ... | @@ -169,17 +169,13 @@ static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id) |
| 169 | 169 | return 0; |
| 170 | 170 | } |
| 171 | 171 | |
| 172 | -static void virtio_balloon_init(PCIDevice *pci_dev) | |
| 172 | +VirtIODevice *virtio_balloon_init(DeviceState *dev) | |
| 173 | 173 | { |
| 174 | 174 | VirtIOBalloon *s; |
| 175 | 175 | |
| 176 | - s = (VirtIOBalloon *)virtio_init_pci(pci_dev, "virtio-balloon", | |
| 177 | - PCI_VENDOR_ID_REDHAT_QUMRANET, | |
| 178 | - PCI_DEVICE_ID_VIRTIO_BALLOON, | |
| 179 | - PCI_VENDOR_ID_REDHAT_QUMRANET, | |
| 180 | - VIRTIO_ID_BALLOON, | |
| 181 | - PCI_CLASS_MEMORY_RAM, 0x00, | |
| 182 | - 8); | |
| 176 | + s = (VirtIOBalloon *)virtio_common_init("virtio-balloon", | |
| 177 | + VIRTIO_ID_BALLOON, | |
| 178 | + 8, sizeof(VirtIOBalloon)); | |
| 183 | 179 | |
| 184 | 180 | s->vdev.get_config = virtio_balloon_get_config; |
| 185 | 181 | s->vdev.set_config = virtio_balloon_set_config; |
| ... | ... | @@ -191,12 +187,6 @@ static void virtio_balloon_init(PCIDevice *pci_dev) |
| 191 | 187 | qemu_add_balloon_handler(virtio_balloon_to_target, s); |
| 192 | 188 | |
| 193 | 189 | register_savevm("virtio-balloon", -1, 1, virtio_balloon_save, virtio_balloon_load, s); |
| 194 | -} | |
| 195 | 190 | |
| 196 | -static void virtio_balloon_register_devices(void) | |
| 197 | -{ | |
| 198 | - pci_qdev_register("virtio-balloon", sizeof(VirtIOBalloon), | |
| 199 | - virtio_balloon_init); | |
| 191 | + return &s->vdev; | |
| 200 | 192 | } |
| 201 | - | |
| 202 | -device_init(virtio_balloon_register_devices) | ... | ... |
hw/virtio-blk.c
| ... | ... | @@ -348,28 +348,24 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) |
| 348 | 348 | return 0; |
| 349 | 349 | } |
| 350 | 350 | |
| 351 | -static void virtio_blk_init(PCIDevice *pci_dev) | |
| 351 | +VirtIODevice *virtio_blk_init(DeviceState *dev) | |
| 352 | 352 | { |
| 353 | 353 | VirtIOBlock *s; |
| 354 | 354 | int cylinders, heads, secs; |
| 355 | 355 | static int virtio_blk_id; |
| 356 | 356 | BlockDriverState *bs; |
| 357 | 357 | |
| 358 | - s = (VirtIOBlock *)virtio_init_pci(pci_dev, "virtio-blk", | |
| 359 | - PCI_VENDOR_ID_REDHAT_QUMRANET, | |
| 360 | - PCI_DEVICE_ID_VIRTIO_BLOCK, | |
| 361 | - PCI_VENDOR_ID_REDHAT_QUMRANET, | |
| 362 | - VIRTIO_ID_BLOCK, | |
| 363 | - PCI_CLASS_STORAGE_OTHER, 0x00, | |
| 364 | - sizeof(struct virtio_blk_config)); | |
| 358 | + s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK, | |
| 359 | + sizeof(struct virtio_blk_config), | |
| 360 | + sizeof(VirtIOBlock)); | |
| 365 | 361 | |
| 366 | - bs = qdev_init_bdrv(&pci_dev->qdev, IF_VIRTIO); | |
| 362 | + bs = qdev_init_bdrv(dev, IF_VIRTIO); | |
| 367 | 363 | s->vdev.get_config = virtio_blk_update_config; |
| 368 | 364 | s->vdev.get_features = virtio_blk_get_features; |
| 369 | 365 | s->vdev.reset = virtio_blk_reset; |
| 370 | 366 | s->bs = bs; |
| 371 | 367 | s->rq = NULL; |
| 372 | - bs->private = &s->vdev.pci_dev; | |
| 368 | + bs->private = dev; | |
| 373 | 369 | bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs); |
| 374 | 370 | bdrv_set_geometry_hint(s->bs, cylinders, heads, secs); |
| 375 | 371 | |
| ... | ... | @@ -378,11 +374,6 @@ static void virtio_blk_init(PCIDevice *pci_dev) |
| 378 | 374 | qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); |
| 379 | 375 | register_savevm("virtio-blk", virtio_blk_id++, 2, |
| 380 | 376 | virtio_blk_save, virtio_blk_load, s); |
| 381 | -} | |
| 382 | 377 | |
| 383 | -static void virtio_blk_register_devices(void) | |
| 384 | -{ | |
| 385 | - pci_qdev_register("virtio-blk", sizeof(VirtIOBlock), virtio_blk_init); | |
| 378 | + return &s->vdev; | |
| 386 | 379 | } |
| 387 | - | |
| 388 | -device_init(virtio_blk_register_devices) | ... | ... |
hw/virtio-blk.h
hw/virtio-console.c
| ... | ... | @@ -123,31 +123,21 @@ static int virtio_console_load(QEMUFile *f, void *opaque, int version_id) |
| 123 | 123 | return 0; |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | -static void virtio_console_init(PCIDevice *pci_dev) | |
| 126 | +VirtIODevice *virtio_console_init(DeviceState *dev) | |
| 127 | 127 | { |
| 128 | 128 | VirtIOConsole *s; |
| 129 | - s = (VirtIOConsole *)virtio_init_pci(pci_dev, "virtio-console", | |
| 130 | - PCI_VENDOR_ID_REDHAT_QUMRANET, | |
| 131 | - PCI_DEVICE_ID_VIRTIO_CONSOLE, | |
| 132 | - PCI_VENDOR_ID_REDHAT_QUMRANET, | |
| 133 | - VIRTIO_ID_CONSOLE, | |
| 134 | - PCI_CLASS_DISPLAY_OTHER, 0x00, | |
| 135 | - 0); | |
| 129 | + s = (VirtIOConsole *)virtio_common_init("virtio-console", | |
| 130 | + VIRTIO_ID_CONSOLE, | |
| 131 | + 0, sizeof(VirtIOConsole)); | |
| 136 | 132 | s->vdev.get_features = virtio_console_get_features; |
| 137 | 133 | |
| 138 | 134 | s->ivq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_input); |
| 139 | 135 | s->dvq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_output); |
| 140 | 136 | |
| 141 | - s->chr = qdev_init_chardev(&pci_dev->qdev); | |
| 137 | + s->chr = qdev_init_chardev(dev); | |
| 142 | 138 | qemu_chr_add_handlers(s->chr, vcon_can_read, vcon_read, vcon_event, s); |
| 143 | 139 | |
| 144 | 140 | register_savevm("virtio-console", -1, 1, virtio_console_save, virtio_console_load, s); |
| 145 | -} | |
| 146 | 141 | |
| 147 | -static void virtio_console_register_devices(void) | |
| 148 | -{ | |
| 149 | - pci_qdev_register("virtio-console", sizeof(VirtIOConsole), | |
| 150 | - virtio_console_init); | |
| 142 | + return &s->vdev; | |
| 151 | 143 | } |
| 152 | - | |
| 153 | -device_init(virtio_console_register_devices) | ... | ... |
hw/virtio-net.c
| ... | ... | @@ -585,18 +585,14 @@ static void virtio_net_cleanup(VLANClientState *vc) |
| 585 | 585 | virtio_cleanup(&n->vdev); |
| 586 | 586 | } |
| 587 | 587 | |
| 588 | -static void virtio_net_init(PCIDevice *pci_dev) | |
| 588 | +VirtIODevice *virtio_net_init(DeviceState *dev) | |
| 589 | 589 | { |
| 590 | 590 | VirtIONet *n; |
| 591 | 591 | static int virtio_net_id; |
| 592 | 592 | |
| 593 | - n = (VirtIONet *)virtio_init_pci(pci_dev, "virtio-net", | |
| 594 | - PCI_VENDOR_ID_REDHAT_QUMRANET, | |
| 595 | - PCI_DEVICE_ID_VIRTIO_NET, | |
| 596 | - PCI_VENDOR_ID_REDHAT_QUMRANET, | |
| 597 | - VIRTIO_ID_NET, | |
| 598 | - PCI_CLASS_NETWORK_ETHERNET, 0x00, | |
| 599 | - sizeof(struct virtio_net_config)); | |
| 593 | + n = (VirtIONet *)virtio_common_init("virtio-net", VIRTIO_ID_NET, | |
| 594 | + sizeof(struct virtio_net_config), | |
| 595 | + sizeof(VirtIONet)); | |
| 600 | 596 | |
| 601 | 597 | n->vdev.get_config = virtio_net_get_config; |
| 602 | 598 | n->vdev.set_config = virtio_net_set_config; |
| ... | ... | @@ -607,9 +603,9 @@ static void virtio_net_init(PCIDevice *pci_dev) |
| 607 | 603 | n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); |
| 608 | 604 | n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx); |
| 609 | 605 | n->ctrl_vq = virtio_add_queue(&n->vdev, 16, virtio_net_handle_ctrl); |
| 610 | - qdev_get_macaddr(&pci_dev->qdev, n->mac); | |
| 606 | + qdev_get_macaddr(dev, n->mac); | |
| 611 | 607 | n->status = VIRTIO_NET_S_LINK_UP; |
| 612 | - n->vc = qdev_get_vlan_client(&pci_dev->qdev, | |
| 608 | + n->vc = qdev_get_vlan_client(dev, | |
| 613 | 609 | virtio_net_receive, |
| 614 | 610 | virtio_net_can_receive, |
| 615 | 611 | virtio_net_cleanup, n); |
| ... | ... | @@ -628,11 +624,6 @@ static void virtio_net_init(PCIDevice *pci_dev) |
| 628 | 624 | |
| 629 | 625 | register_savevm("virtio-net", virtio_net_id++, VIRTIO_NET_VM_VERSION, |
| 630 | 626 | virtio_net_save, virtio_net_load, n); |
| 631 | -} | |
| 632 | 627 | |
| 633 | -static void virtio_net_register_devices(void) | |
| 634 | -{ | |
| 635 | - pci_qdev_register("virtio_net", sizeof(VirtIONet), virtio_net_init); | |
| 628 | + return &n->vdev; | |
| 636 | 629 | } |
| 637 | - | |
| 638 | -device_init(virtio_net_register_devices) | ... | ... |
hw/virtio-pci.c
0 โ 100644
| 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 | + * | |
| 14 | + */ | |
| 15 | + | |
| 16 | +#include <inttypes.h> | |
| 17 | + | |
| 18 | +#include "virtio.h" | |
| 19 | +#include "pci.h" | |
| 20 | +#include "sysemu.h" | |
| 21 | + | |
| 22 | +/* from Linux's linux/virtio_pci.h */ | |
| 23 | + | |
| 24 | +/* A 32-bit r/o bitmask of the features supported by the host */ | |
| 25 | +#define VIRTIO_PCI_HOST_FEATURES 0 | |
| 26 | + | |
| 27 | +/* A 32-bit r/w bitmask of features activated by the guest */ | |
| 28 | +#define VIRTIO_PCI_GUEST_FEATURES 4 | |
| 29 | + | |
| 30 | +/* A 32-bit r/w PFN for the currently selected queue */ | |
| 31 | +#define VIRTIO_PCI_QUEUE_PFN 8 | |
| 32 | + | |
| 33 | +/* A 16-bit r/o queue size for the currently selected queue */ | |
| 34 | +#define VIRTIO_PCI_QUEUE_NUM 12 | |
| 35 | + | |
| 36 | +/* A 16-bit r/w queue selector */ | |
| 37 | +#define VIRTIO_PCI_QUEUE_SEL 14 | |
| 38 | + | |
| 39 | +/* A 16-bit r/w queue notifier */ | |
| 40 | +#define VIRTIO_PCI_QUEUE_NOTIFY 16 | |
| 41 | + | |
| 42 | +/* An 8-bit device status register. */ | |
| 43 | +#define VIRTIO_PCI_STATUS 18 | |
| 44 | + | |
| 45 | +/* An 8-bit r/o interrupt status register. Reading the value will return the | |
| 46 | + * current contents of the ISR and will also clear it. This is effectively | |
| 47 | + * a read-and-acknowledge. */ | |
| 48 | +#define VIRTIO_PCI_ISR 19 | |
| 49 | + | |
| 50 | +#define VIRTIO_PCI_CONFIG 20 | |
| 51 | + | |
| 52 | +/* Virtio ABI version, if we increment this, we break the guest driver. */ | |
| 53 | +#define VIRTIO_PCI_ABI_VERSION 0 | |
| 54 | + | |
| 55 | +/* How many bits to shift physical queue address written to QUEUE_PFN. | |
| 56 | + * 12 is historical, and due to x86 page size. */ | |
| 57 | +#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12 | |
| 58 | + | |
| 59 | +/* QEMU doesn't strictly need write barriers since everything runs in | |
| 60 | + * lock-step. We'll leave the calls to wmb() in though to make it obvious for | |
| 61 | + * KVM or if kqemu gets SMP support. | |
| 62 | + */ | |
| 63 | +#define wmb() do { } while (0) | |
| 64 | + | |
| 65 | +/* PCI bindings. */ | |
| 66 | + | |
| 67 | +typedef struct { | |
| 68 | + PCIDevice pci_dev; | |
| 69 | + VirtIODevice *vdev; | |
| 70 | + uint32_t addr; | |
| 71 | + | |
| 72 | + uint16_t vendor; | |
| 73 | + uint16_t device; | |
| 74 | + uint16_t subvendor; | |
| 75 | + uint16_t class_code; | |
| 76 | + uint8_t pif; | |
| 77 | +} VirtIOPCIProxy; | |
| 78 | + | |
| 79 | +/* virtio device */ | |
| 80 | + | |
| 81 | +static void virtio_pci_update_irq(void *opaque) | |
| 82 | +{ | |
| 83 | + VirtIOPCIProxy *proxy = opaque; | |
| 84 | + | |
| 85 | + qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1); | |
| 86 | +} | |
| 87 | + | |
| 88 | +static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) | |
| 89 | +{ | |
| 90 | + VirtIOPCIProxy *proxy = opaque; | |
| 91 | + VirtIODevice *vdev = proxy->vdev; | |
| 92 | + target_phys_addr_t pa; | |
| 93 | + | |
| 94 | + addr -= proxy->addr; | |
| 95 | + | |
| 96 | + switch (addr) { | |
| 97 | + case VIRTIO_PCI_GUEST_FEATURES: | |
| 98 | + /* Guest does not negotiate properly? We have to assume nothing. */ | |
| 99 | + if (val & (1 << VIRTIO_F_BAD_FEATURE)) { | |
| 100 | + if (vdev->bad_features) | |
| 101 | + val = vdev->bad_features(vdev); | |
| 102 | + else | |
| 103 | + val = 0; | |
| 104 | + } | |
| 105 | + if (vdev->set_features) | |
| 106 | + vdev->set_features(vdev, val); | |
| 107 | + vdev->features = val; | |
| 108 | + break; | |
| 109 | + case VIRTIO_PCI_QUEUE_PFN: | |
| 110 | + pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; | |
| 111 | + virtio_queue_set_addr(vdev, vdev->queue_sel, pa); | |
| 112 | + break; | |
| 113 | + case VIRTIO_PCI_QUEUE_SEL: | |
| 114 | + if (val < VIRTIO_PCI_QUEUE_MAX) | |
| 115 | + vdev->queue_sel = val; | |
| 116 | + break; | |
| 117 | + case VIRTIO_PCI_QUEUE_NOTIFY: | |
| 118 | + virtio_queue_notify(vdev, val); | |
| 119 | + break; | |
| 120 | + case VIRTIO_PCI_STATUS: | |
| 121 | + vdev->status = val & 0xFF; | |
| 122 | + if (vdev->status == 0) | |
| 123 | + virtio_reset(vdev); | |
| 124 | + break; | |
| 125 | + } | |
| 126 | +} | |
| 127 | + | |
| 128 | +static uint32_t virtio_ioport_read(void *opaque, uint32_t addr) | |
| 129 | +{ | |
| 130 | + VirtIOPCIProxy *proxy = opaque; | |
| 131 | + VirtIODevice *vdev = proxy->vdev; | |
| 132 | + uint32_t ret = 0xFFFFFFFF; | |
| 133 | + | |
| 134 | + addr -= proxy->addr; | |
| 135 | + | |
| 136 | + switch (addr) { | |
| 137 | + case VIRTIO_PCI_HOST_FEATURES: | |
| 138 | + ret = vdev->get_features(vdev); | |
| 139 | + ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY) | (1 << VIRTIO_F_BAD_FEATURE); | |
| 140 | + break; | |
| 141 | + case VIRTIO_PCI_GUEST_FEATURES: | |
| 142 | + ret = vdev->features; | |
| 143 | + break; | |
| 144 | + case VIRTIO_PCI_QUEUE_PFN: | |
| 145 | + ret = virtio_queue_get_addr(vdev, vdev->queue_sel) | |
| 146 | + >> VIRTIO_PCI_QUEUE_ADDR_SHIFT; | |
| 147 | + break; | |
| 148 | + case VIRTIO_PCI_QUEUE_NUM: | |
| 149 | + ret = virtio_queue_get_num(vdev, vdev->queue_sel); | |
| 150 | + break; | |
| 151 | + case VIRTIO_PCI_QUEUE_SEL: | |
| 152 | + ret = vdev->queue_sel; | |
| 153 | + break; | |
| 154 | + case VIRTIO_PCI_STATUS: | |
| 155 | + ret = vdev->status; | |
| 156 | + break; | |
| 157 | + case VIRTIO_PCI_ISR: | |
| 158 | + /* reading from the ISR also clears it. */ | |
| 159 | + ret = vdev->isr; | |
| 160 | + vdev->isr = 0; | |
| 161 | + virtio_update_irq(vdev); | |
| 162 | + break; | |
| 163 | + default: | |
| 164 | + break; | |
| 165 | + } | |
| 166 | + | |
| 167 | + return ret; | |
| 168 | +} | |
| 169 | + | |
| 170 | +static uint32_t virtio_pci_config_readb(void *opaque, uint32_t addr) | |
| 171 | +{ | |
| 172 | + VirtIOPCIProxy *proxy = opaque; | |
| 173 | + addr -= proxy->addr + VIRTIO_PCI_CONFIG; | |
| 174 | + return virtio_config_readb(proxy->vdev, addr); | |
| 175 | +} | |
| 176 | + | |
| 177 | +static uint32_t virtio_pci_config_readw(void *opaque, uint32_t addr) | |
| 178 | +{ | |
| 179 | + VirtIOPCIProxy *proxy = opaque; | |
| 180 | + addr -= proxy->addr + VIRTIO_PCI_CONFIG; | |
| 181 | + return virtio_config_readw(proxy->vdev, addr); | |
| 182 | +} | |
| 183 | + | |
| 184 | +static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr) | |
| 185 | +{ | |
| 186 | + VirtIOPCIProxy *proxy = opaque; | |
| 187 | + addr -= proxy->addr + VIRTIO_PCI_CONFIG; | |
| 188 | + return virtio_config_readl(proxy->vdev, addr); | |
| 189 | +} | |
| 190 | + | |
| 191 | +static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t val) | |
| 192 | +{ | |
| 193 | + VirtIOPCIProxy *proxy = opaque; | |
| 194 | + addr -= proxy->addr + VIRTIO_PCI_CONFIG; | |
| 195 | + virtio_config_writeb(proxy->vdev, addr, val); | |
| 196 | +} | |
| 197 | + | |
| 198 | +static void virtio_pci_config_writew(void *opaque, uint32_t addr, uint32_t val) | |
| 199 | +{ | |
| 200 | + VirtIOPCIProxy *proxy = opaque; | |
| 201 | + addr -= proxy->addr + VIRTIO_PCI_CONFIG; | |
| 202 | + virtio_config_writew(proxy->vdev, addr, val); | |
| 203 | +} | |
| 204 | + | |
| 205 | +static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val) | |
| 206 | +{ | |
| 207 | + VirtIOPCIProxy *proxy = opaque; | |
| 208 | + addr -= proxy->addr + VIRTIO_PCI_CONFIG; | |
| 209 | + virtio_config_writel(proxy->vdev, addr, val); | |
| 210 | +} | |
| 211 | + | |
| 212 | +static void virtio_map(PCIDevice *pci_dev, int region_num, | |
| 213 | + uint32_t addr, uint32_t size, int type) | |
| 214 | +{ | |
| 215 | + VirtIOPCIProxy *proxy = container_of(pci_dev, VirtIOPCIProxy, pci_dev); | |
| 216 | + VirtIODevice *vdev = proxy->vdev; | |
| 217 | + int i; | |
| 218 | + | |
| 219 | + proxy->addr = addr; | |
| 220 | + for (i = 0; i < 3; i++) { | |
| 221 | + register_ioport_write(addr, VIRTIO_PCI_CONFIG, 1 << i, | |
| 222 | + virtio_ioport_write, proxy); | |
| 223 | + register_ioport_read(addr, VIRTIO_PCI_CONFIG, 1 << i, | |
| 224 | + virtio_ioport_read, proxy); | |
| 225 | + } | |
| 226 | + | |
| 227 | + if (vdev->config_len) { | |
| 228 | + register_ioport_write(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 1, | |
| 229 | + virtio_pci_config_writeb, proxy); | |
| 230 | + register_ioport_write(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 2, | |
| 231 | + virtio_pci_config_writew, proxy); | |
| 232 | + register_ioport_write(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 4, | |
| 233 | + virtio_pci_config_writel, proxy); | |
| 234 | + register_ioport_read(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 1, | |
| 235 | + virtio_pci_config_readb, proxy); | |
| 236 | + register_ioport_read(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 2, | |
| 237 | + virtio_pci_config_readw, proxy); | |
| 238 | + register_ioport_read(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 4, | |
| 239 | + virtio_pci_config_readl, proxy); | |
| 240 | + | |
| 241 | + vdev->get_config(vdev, vdev->config); | |
| 242 | + } | |
| 243 | +} | |
| 244 | + | |
| 245 | +static const VirtIOBindings virtio_pci_bindings = { | |
| 246 | + .update_irq = virtio_pci_update_irq | |
| 247 | +}; | |
| 248 | + | |
| 249 | +static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev, | |
| 250 | + uint16_t vendor, uint16_t device, | |
| 251 | + uint16_t class_code, uint8_t pif) | |
| 252 | +{ | |
| 253 | + uint8_t *config; | |
| 254 | + uint32_t size; | |
| 255 | + | |
| 256 | + proxy->vdev = vdev; | |
| 257 | + | |
| 258 | + config = proxy->pci_dev.config; | |
| 259 | + pci_config_set_vendor_id(config, vendor); | |
| 260 | + pci_config_set_device_id(config, device); | |
| 261 | + | |
| 262 | + config[0x08] = VIRTIO_PCI_ABI_VERSION; | |
| 263 | + | |
| 264 | + config[0x09] = pif; | |
| 265 | + pci_config_set_class(config, class_code); | |
| 266 | + config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; | |
| 267 | + | |
| 268 | + config[0x2c] = vendor & 0xFF; | |
| 269 | + config[0x2d] = (vendor >> 8) & 0xFF; | |
| 270 | + config[0x2e] = vdev->device_id & 0xFF; | |
| 271 | + config[0x2f] = (vdev->device_id >> 8) & 0xFF; | |
| 272 | + | |
| 273 | + config[0x3d] = 1; | |
| 274 | + | |
| 275 | + size = 20 + vdev->config_len; | |
| 276 | + if (size & (size-1)) | |
| 277 | + size = 1 << qemu_fls(size); | |
| 278 | + | |
| 279 | + pci_register_io_region(&proxy->pci_dev, 0, size, PCI_ADDRESS_SPACE_IO, | |
| 280 | + virtio_map); | |
| 281 | + | |
| 282 | + virtio_bind_device(vdev, &virtio_pci_bindings, proxy); | |
| 283 | +} | |
| 284 | + | |
| 285 | +static void virtio_blk_init_pci(PCIDevice *pci_dev) | |
| 286 | +{ | |
| 287 | + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); | |
| 288 | + VirtIODevice *vdev; | |
| 289 | + | |
| 290 | + vdev = virtio_blk_init(&pci_dev->qdev); | |
| 291 | + virtio_init_pci(proxy, vdev, | |
| 292 | + PCI_VENDOR_ID_REDHAT_QUMRANET, | |
| 293 | + PCI_DEVICE_ID_VIRTIO_BLOCK, | |
| 294 | + PCI_CLASS_STORAGE_OTHER, | |
| 295 | + 0x00); | |
| 296 | +} | |
| 297 | + | |
| 298 | +static void virtio_console_init_pci(PCIDevice *pci_dev) | |
| 299 | +{ | |
| 300 | + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); | |
| 301 | + VirtIODevice *vdev; | |
| 302 | + | |
| 303 | + vdev = virtio_console_init(&pci_dev->qdev); | |
| 304 | + virtio_init_pci(proxy, vdev, | |
| 305 | + PCI_VENDOR_ID_REDHAT_QUMRANET, | |
| 306 | + PCI_DEVICE_ID_VIRTIO_CONSOLE, | |
| 307 | + PCI_CLASS_DISPLAY_OTHER, | |
| 308 | + 0x00); | |
| 309 | +} | |
| 310 | + | |
| 311 | +static void virtio_net_init_pci(PCIDevice *pci_dev) | |
| 312 | +{ | |
| 313 | + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); | |
| 314 | + VirtIODevice *vdev; | |
| 315 | + | |
| 316 | + vdev = virtio_net_init(&pci_dev->qdev); | |
| 317 | + virtio_init_pci(proxy, vdev, | |
| 318 | + PCI_VENDOR_ID_REDHAT_QUMRANET, | |
| 319 | + PCI_DEVICE_ID_VIRTIO_NET, | |
| 320 | + PCI_CLASS_NETWORK_ETHERNET, | |
| 321 | + 0x00); | |
| 322 | +} | |
| 323 | + | |
| 324 | +static void virtio_balloon_init_pci(PCIDevice *pci_dev) | |
| 325 | +{ | |
| 326 | + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); | |
| 327 | + VirtIODevice *vdev; | |
| 328 | + | |
| 329 | + vdev = virtio_balloon_init(&pci_dev->qdev); | |
| 330 | + virtio_init_pci(proxy, vdev, | |
| 331 | + PCI_VENDOR_ID_REDHAT_QUMRANET, | |
| 332 | + PCI_DEVICE_ID_VIRTIO_BALLOON, | |
| 333 | + PCI_CLASS_MEMORY_RAM, | |
| 334 | + 0x00); | |
| 335 | +} | |
| 336 | + | |
| 337 | +static void virtio_pci_register_devices(void) | |
| 338 | +{ | |
| 339 | + pci_qdev_register("virtio-blk-pci", sizeof(VirtIOPCIProxy), | |
| 340 | + virtio_blk_init_pci); | |
| 341 | + pci_qdev_register("virtio-net-pci", sizeof(VirtIOPCIProxy), | |
| 342 | + virtio_net_init_pci); | |
| 343 | + pci_qdev_register("virtio-console-pci", sizeof(VirtIOPCIProxy), | |
| 344 | + virtio_console_init_pci); | |
| 345 | + pci_qdev_register("virtio-balloon-pci", sizeof(VirtIOPCIProxy), | |
| 346 | + virtio_balloon_init_pci); | |
| 347 | +} | |
| 348 | + | |
| 349 | +device_init(virtio_pci_register_devices) | ... | ... |
hw/virtio.c
| ... | ... | @@ -16,43 +16,6 @@ |
| 16 | 16 | #include "virtio.h" |
| 17 | 17 | #include "sysemu.h" |
| 18 | 18 | |
| 19 | -/* from Linux's linux/virtio_pci.h */ | |
| 20 | - | |
| 21 | -/* A 32-bit r/o bitmask of the features supported by the host */ | |
| 22 | -#define VIRTIO_PCI_HOST_FEATURES 0 | |
| 23 | - | |
| 24 | -/* A 32-bit r/w bitmask of features activated by the guest */ | |
| 25 | -#define VIRTIO_PCI_GUEST_FEATURES 4 | |
| 26 | - | |
| 27 | -/* A 32-bit r/w PFN for the currently selected queue */ | |
| 28 | -#define VIRTIO_PCI_QUEUE_PFN 8 | |
| 29 | - | |
| 30 | -/* A 16-bit r/o queue size for the currently selected queue */ | |
| 31 | -#define VIRTIO_PCI_QUEUE_NUM 12 | |
| 32 | - | |
| 33 | -/* A 16-bit r/w queue selector */ | |
| 34 | -#define VIRTIO_PCI_QUEUE_SEL 14 | |
| 35 | - | |
| 36 | -/* A 16-bit r/w queue notifier */ | |
| 37 | -#define VIRTIO_PCI_QUEUE_NOTIFY 16 | |
| 38 | - | |
| 39 | -/* An 8-bit device status register. */ | |
| 40 | -#define VIRTIO_PCI_STATUS 18 | |
| 41 | - | |
| 42 | -/* An 8-bit r/o interrupt status register. Reading the value will return the | |
| 43 | - * current contents of the ISR and will also clear it. This is effectively | |
| 44 | - * a read-and-acknowledge. */ | |
| 45 | -#define VIRTIO_PCI_ISR 19 | |
| 46 | - | |
| 47 | -#define VIRTIO_PCI_CONFIG 20 | |
| 48 | - | |
| 49 | -/* Virtio ABI version, if we increment this, we break the guest driver. */ | |
| 50 | -#define VIRTIO_PCI_ABI_VERSION 0 | |
| 51 | - | |
| 52 | -/* How many bits to shift physical queue address written to QUEUE_PFN. | |
| 53 | - * 12 is historical, and due to x86 page size. */ | |
| 54 | -#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12 | |
| 55 | - | |
| 56 | 19 | /* The alignment to use between consumer and producer parts of vring. |
| 57 | 20 | * x86 pagesize again. */ |
| 58 | 21 | #define VIRTIO_PCI_VRING_ALIGN 4096 |
| ... | ... | @@ -102,7 +65,7 @@ typedef struct VRing |
| 102 | 65 | struct VirtQueue |
| 103 | 66 | { |
| 104 | 67 | VRing vring; |
| 105 | - uint32_t pfn; | |
| 68 | + target_phys_addr_t pa; | |
| 106 | 69 | uint16_t last_avail_idx; |
| 107 | 70 | int inuse; |
| 108 | 71 | void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq); |
| ... | ... | @@ -111,8 +74,10 @@ struct VirtQueue |
| 111 | 74 | #define VIRTIO_PCI_QUEUE_MAX 16 |
| 112 | 75 | |
| 113 | 76 | /* virt queue functions */ |
| 114 | -static void virtqueue_init(VirtQueue *vq, target_phys_addr_t pa) | |
| 77 | +static void virtqueue_init(VirtQueue *vq) | |
| 115 | 78 | { |
| 79 | + target_phys_addr_t pa = vq->pa; | |
| 80 | + | |
| 116 | 81 | vq->vring.desc = pa; |
| 117 | 82 | vq->vring.avail = pa + vq->vring.num * sizeof(VRingDesc); |
| 118 | 83 | vq->vring.used = vring_align(vq->vring.avail + |
| ... | ... | @@ -409,17 +374,14 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) |
| 409 | 374 | |
| 410 | 375 | /* virtio device */ |
| 411 | 376 | |
| 412 | -static VirtIODevice *to_virtio_device(PCIDevice *pci_dev) | |
| 377 | +void virtio_update_irq(VirtIODevice *vdev) | |
| 413 | 378 | { |
| 414 | - return (VirtIODevice *)pci_dev; | |
| 415 | -} | |
| 416 | - | |
| 417 | -static void virtio_update_irq(VirtIODevice *vdev) | |
| 418 | -{ | |
| 419 | - qemu_set_irq(vdev->pci_dev.irq[0], vdev->isr & 1); | |
| 379 | + if (vdev->binding->update_irq) { | |
| 380 | + vdev->binding->update_irq(vdev->binding_opaque); | |
| 381 | + } | |
| 420 | 382 | } |
| 421 | 383 | |
| 422 | -static void virtio_reset(void *opaque) | |
| 384 | +void virtio_reset(void *opaque) | |
| 423 | 385 | { |
| 424 | 386 | VirtIODevice *vdev = opaque; |
| 425 | 387 | int i; |
| ... | ... | @@ -438,103 +400,16 @@ static void virtio_reset(void *opaque) |
| 438 | 400 | vdev->vq[i].vring.avail = 0; |
| 439 | 401 | vdev->vq[i].vring.used = 0; |
| 440 | 402 | vdev->vq[i].last_avail_idx = 0; |
| 441 | - vdev->vq[i].pfn = 0; | |
| 403 | + vdev->vq[i].pa = 0; | |
| 442 | 404 | } |
| 443 | 405 | } |
| 444 | 406 | |
| 445 | -static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) | |
| 446 | -{ | |
| 447 | - VirtIODevice *vdev = to_virtio_device(opaque); | |
| 448 | - ram_addr_t pa; | |
| 449 | - | |
| 450 | - addr -= vdev->addr; | |
| 451 | - | |
| 452 | - switch (addr) { | |
| 453 | - case VIRTIO_PCI_GUEST_FEATURES: | |
| 454 | - /* Guest does not negotiate properly? We have to assume nothing. */ | |
| 455 | - if (val & (1 << VIRTIO_F_BAD_FEATURE)) { | |
| 456 | - if (vdev->bad_features) | |
| 457 | - val = vdev->bad_features(vdev); | |
| 458 | - else | |
| 459 | - val = 0; | |
| 460 | - } | |
| 461 | - if (vdev->set_features) | |
| 462 | - vdev->set_features(vdev, val); | |
| 463 | - vdev->features = val; | |
| 464 | - break; | |
| 465 | - case VIRTIO_PCI_QUEUE_PFN: | |
| 466 | - pa = (ram_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; | |
| 467 | - vdev->vq[vdev->queue_sel].pfn = val; | |
| 468 | - if (pa == 0) { | |
| 469 | - virtio_reset(vdev); | |
| 470 | - } else { | |
| 471 | - virtqueue_init(&vdev->vq[vdev->queue_sel], pa); | |
| 472 | - } | |
| 473 | - break; | |
| 474 | - case VIRTIO_PCI_QUEUE_SEL: | |
| 475 | - if (val < VIRTIO_PCI_QUEUE_MAX) | |
| 476 | - vdev->queue_sel = val; | |
| 477 | - break; | |
| 478 | - case VIRTIO_PCI_QUEUE_NOTIFY: | |
| 479 | - if (val < VIRTIO_PCI_QUEUE_MAX && vdev->vq[val].vring.desc) | |
| 480 | - vdev->vq[val].handle_output(vdev, &vdev->vq[val]); | |
| 481 | - break; | |
| 482 | - case VIRTIO_PCI_STATUS: | |
| 483 | - vdev->status = val & 0xFF; | |
| 484 | - if (vdev->status == 0) | |
| 485 | - virtio_reset(vdev); | |
| 486 | - break; | |
| 487 | - } | |
| 488 | -} | |
| 489 | - | |
| 490 | -static uint32_t virtio_ioport_read(void *opaque, uint32_t addr) | |
| 491 | -{ | |
| 492 | - VirtIODevice *vdev = to_virtio_device(opaque); | |
| 493 | - uint32_t ret = 0xFFFFFFFF; | |
| 494 | - | |
| 495 | - addr -= vdev->addr; | |
| 496 | - | |
| 497 | - switch (addr) { | |
| 498 | - case VIRTIO_PCI_HOST_FEATURES: | |
| 499 | - ret = vdev->get_features(vdev); | |
| 500 | - ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY) | (1 << VIRTIO_F_BAD_FEATURE); | |
| 501 | - break; | |
| 502 | - case VIRTIO_PCI_GUEST_FEATURES: | |
| 503 | - ret = vdev->features; | |
| 504 | - break; | |
| 505 | - case VIRTIO_PCI_QUEUE_PFN: | |
| 506 | - ret = vdev->vq[vdev->queue_sel].pfn; | |
| 507 | - break; | |
| 508 | - case VIRTIO_PCI_QUEUE_NUM: | |
| 509 | - ret = vdev->vq[vdev->queue_sel].vring.num; | |
| 510 | - break; | |
| 511 | - case VIRTIO_PCI_QUEUE_SEL: | |
| 512 | - ret = vdev->queue_sel; | |
| 513 | - break; | |
| 514 | - case VIRTIO_PCI_STATUS: | |
| 515 | - ret = vdev->status; | |
| 516 | - break; | |
| 517 | - case VIRTIO_PCI_ISR: | |
| 518 | - /* reading from the ISR also clears it. */ | |
| 519 | - ret = vdev->isr; | |
| 520 | - vdev->isr = 0; | |
| 521 | - virtio_update_irq(vdev); | |
| 522 | - break; | |
| 523 | - default: | |
| 524 | - break; | |
| 525 | - } | |
| 526 | - | |
| 527 | - return ret; | |
| 528 | -} | |
| 529 | - | |
| 530 | -static uint32_t virtio_config_readb(void *opaque, uint32_t addr) | |
| 407 | +uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr) | |
| 531 | 408 | { |
| 532 | - VirtIODevice *vdev = opaque; | |
| 533 | 409 | uint8_t val; |
| 534 | 410 | |
| 535 | 411 | vdev->get_config(vdev, vdev->config); |
| 536 | 412 | |
| 537 | - addr -= vdev->addr + VIRTIO_PCI_CONFIG; | |
| 538 | 413 | if (addr > (vdev->config_len - sizeof(val))) |
| 539 | 414 | return (uint32_t)-1; |
| 540 | 415 | |
| ... | ... | @@ -542,14 +417,12 @@ static uint32_t virtio_config_readb(void *opaque, uint32_t addr) |
| 542 | 417 | return val; |
| 543 | 418 | } |
| 544 | 419 | |
| 545 | -static uint32_t virtio_config_readw(void *opaque, uint32_t addr) | |
| 420 | +uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr) | |
| 546 | 421 | { |
| 547 | - VirtIODevice *vdev = opaque; | |
| 548 | 422 | uint16_t val; |
| 549 | 423 | |
| 550 | 424 | vdev->get_config(vdev, vdev->config); |
| 551 | 425 | |
| 552 | - addr -= vdev->addr + VIRTIO_PCI_CONFIG; | |
| 553 | 426 | if (addr > (vdev->config_len - sizeof(val))) |
| 554 | 427 | return (uint32_t)-1; |
| 555 | 428 | |
| ... | ... | @@ -557,14 +430,12 @@ static uint32_t virtio_config_readw(void *opaque, uint32_t addr) |
| 557 | 430 | return val; |
| 558 | 431 | } |
| 559 | 432 | |
| 560 | -static uint32_t virtio_config_readl(void *opaque, uint32_t addr) | |
| 433 | +uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr) | |
| 561 | 434 | { |
| 562 | - VirtIODevice *vdev = opaque; | |
| 563 | 435 | uint32_t val; |
| 564 | 436 | |
| 565 | 437 | vdev->get_config(vdev, vdev->config); |
| 566 | 438 | |
| 567 | - addr -= vdev->addr + VIRTIO_PCI_CONFIG; | |
| 568 | 439 | if (addr > (vdev->config_len - sizeof(val))) |
| 569 | 440 | return (uint32_t)-1; |
| 570 | 441 | |
| ... | ... | @@ -572,12 +443,10 @@ static uint32_t virtio_config_readl(void *opaque, uint32_t addr) |
| 572 | 443 | return val; |
| 573 | 444 | } |
| 574 | 445 | |
| 575 | -static void virtio_config_writeb(void *opaque, uint32_t addr, uint32_t data) | |
| 446 | +void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data) | |
| 576 | 447 | { |
| 577 | - VirtIODevice *vdev = opaque; | |
| 578 | 448 | uint8_t val = data; |
| 579 | 449 | |
| 580 | - addr -= vdev->addr + VIRTIO_PCI_CONFIG; | |
| 581 | 450 | if (addr > (vdev->config_len - sizeof(val))) |
| 582 | 451 | return; |
| 583 | 452 | |
| ... | ... | @@ -587,12 +456,10 @@ static void virtio_config_writeb(void *opaque, uint32_t addr, uint32_t data) |
| 587 | 456 | vdev->set_config(vdev, vdev->config); |
| 588 | 457 | } |
| 589 | 458 | |
| 590 | -static void virtio_config_writew(void *opaque, uint32_t addr, uint32_t data) | |
| 459 | +void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data) | |
| 591 | 460 | { |
| 592 | - VirtIODevice *vdev = opaque; | |
| 593 | 461 | uint16_t val = data; |
| 594 | 462 | |
| 595 | - addr -= vdev->addr + VIRTIO_PCI_CONFIG; | |
| 596 | 463 | if (addr > (vdev->config_len - sizeof(val))) |
| 597 | 464 | return; |
| 598 | 465 | |
| ... | ... | @@ -602,12 +469,10 @@ static void virtio_config_writew(void *opaque, uint32_t addr, uint32_t data) |
| 602 | 469 | vdev->set_config(vdev, vdev->config); |
| 603 | 470 | } |
| 604 | 471 | |
| 605 | -static void virtio_config_writel(void *opaque, uint32_t addr, uint32_t data) | |
| 472 | +void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data) | |
| 606 | 473 | { |
| 607 | - VirtIODevice *vdev = opaque; | |
| 608 | 474 | uint32_t val = data; |
| 609 | 475 | |
| 610 | - addr -= vdev->addr + VIRTIO_PCI_CONFIG; | |
| 611 | 476 | if (addr > (vdev->config_len - sizeof(val))) |
| 612 | 477 | return; |
| 613 | 478 | |
| ... | ... | @@ -617,33 +482,30 @@ static void virtio_config_writel(void *opaque, uint32_t addr, uint32_t data) |
| 617 | 482 | vdev->set_config(vdev, vdev->config); |
| 618 | 483 | } |
| 619 | 484 | |
| 620 | -static void virtio_map(PCIDevice *pci_dev, int region_num, | |
| 621 | - uint32_t addr, uint32_t size, int type) | |
| 485 | +void virtio_queue_set_addr(VirtIODevice *vdev, int n, target_phys_addr_t addr) | |
| 622 | 486 | { |
| 623 | - VirtIODevice *vdev = to_virtio_device(pci_dev); | |
| 624 | - int i; | |
| 625 | - | |
| 626 | - vdev->addr = addr; | |
| 627 | - for (i = 0; i < 3; i++) { | |
| 628 | - register_ioport_write(addr, 20, 1 << i, virtio_ioport_write, vdev); | |
| 629 | - register_ioport_read(addr, 20, 1 << i, virtio_ioport_read, vdev); | |
| 487 | + if (addr == 0) { | |
| 488 | + virtio_reset(vdev); | |
| 489 | + } else { | |
| 490 | + vdev->vq[n].pa = addr; | |
| 491 | + virtqueue_init(&vdev->vq[n]); | |
| 630 | 492 | } |
| 493 | +} | |
| 494 | + | |
| 495 | +target_phys_addr_t virtio_queue_get_addr(VirtIODevice *vdev, int n) | |
| 496 | +{ | |
| 497 | + return vdev->vq[n].pa; | |
| 498 | +} | |
| 499 | + | |
| 500 | +int virtio_queue_get_num(VirtIODevice *vdev, int n) | |
| 501 | +{ | |
| 502 | + return vdev->vq[n].vring.num; | |
| 503 | +} | |
| 631 | 504 | |
| 632 | - if (vdev->config_len) { | |
| 633 | - register_ioport_write(addr + 20, vdev->config_len, 1, | |
| 634 | - virtio_config_writeb, vdev); | |
| 635 | - register_ioport_write(addr + 20, vdev->config_len, 2, | |
| 636 | - virtio_config_writew, vdev); | |
| 637 | - register_ioport_write(addr + 20, vdev->config_len, 4, | |
| 638 | - virtio_config_writel, vdev); | |
| 639 | - register_ioport_read(addr + 20, vdev->config_len, 1, | |
| 640 | - virtio_config_readb, vdev); | |
| 641 | - register_ioport_read(addr + 20, vdev->config_len, 2, | |
| 642 | - virtio_config_readw, vdev); | |
| 643 | - register_ioport_read(addr + 20, vdev->config_len, 4, | |
| 644 | - virtio_config_readl, vdev); | |
| 645 | - | |
| 646 | - vdev->get_config(vdev, vdev->config); | |
| 505 | +void virtio_queue_notify(VirtIODevice *vdev, int n) | |
| 506 | +{ | |
| 507 | + if (n < VIRTIO_PCI_QUEUE_MAX && vdev->vq[n].vring.desc) { | |
| 508 | + vdev->vq[n].handle_output(vdev, &vdev->vq[n]); | |
| 647 | 509 | } |
| 648 | 510 | } |
| 649 | 511 | |
| ... | ... | @@ -691,9 +553,9 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) |
| 691 | 553 | { |
| 692 | 554 | int i; |
| 693 | 555 | |
| 694 | - pci_device_save(&vdev->pci_dev, f); | |
| 556 | + /* FIXME: load/save binding. */ | |
| 557 | + //pci_device_save(&vdev->pci_dev, f); | |
| 695 | 558 | |
| 696 | - qemu_put_be32s(f, &vdev->addr); | |
| 697 | 559 | qemu_put_8s(f, &vdev->status); |
| 698 | 560 | qemu_put_8s(f, &vdev->isr); |
| 699 | 561 | qemu_put_be16s(f, &vdev->queue_sel); |
| ... | ... | @@ -713,7 +575,7 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) |
| 713 | 575 | break; |
| 714 | 576 | |
| 715 | 577 | qemu_put_be32(f, vdev->vq[i].vring.num); |
| 716 | - qemu_put_be32s(f, &vdev->vq[i].pfn); | |
| 578 | + qemu_put_be64(f, vdev->vq[i].pa); | |
| 717 | 579 | qemu_put_be16s(f, &vdev->vq[i].last_avail_idx); |
| 718 | 580 | } |
| 719 | 581 | } |
| ... | ... | @@ -722,9 +584,9 @@ void virtio_load(VirtIODevice *vdev, QEMUFile *f) |
| 722 | 584 | { |
| 723 | 585 | int num, i; |
| 724 | 586 | |
| 725 | - pci_device_load(&vdev->pci_dev, f); | |
| 587 | + /* FIXME: load/save binding. */ | |
| 588 | + //pci_device_load(&vdev->pci_dev, f); | |
| 726 | 589 | |
| 727 | - qemu_get_be32s(f, &vdev->addr); | |
| 728 | 590 | qemu_get_8s(f, &vdev->status); |
| 729 | 591 | qemu_get_8s(f, &vdev->isr); |
| 730 | 592 | qemu_get_be16s(f, &vdev->queue_sel); |
| ... | ... | @@ -736,14 +598,11 @@ void virtio_load(VirtIODevice *vdev, QEMUFile *f) |
| 736 | 598 | |
| 737 | 599 | for (i = 0; i < num; i++) { |
| 738 | 600 | vdev->vq[i].vring.num = qemu_get_be32(f); |
| 739 | - qemu_get_be32s(f, &vdev->vq[i].pfn); | |
| 601 | + vdev->vq[i].pa = qemu_get_be64(f); | |
| 740 | 602 | qemu_get_be16s(f, &vdev->vq[i].last_avail_idx); |
| 741 | 603 | |
| 742 | - if (vdev->vq[i].pfn) { | |
| 743 | - target_phys_addr_t pa; | |
| 744 | - | |
| 745 | - pa = (ram_addr_t)vdev->vq[i].pfn << VIRTIO_PCI_QUEUE_ADDR_SHIFT; | |
| 746 | - virtqueue_init(&vdev->vq[i], pa); | |
| 604 | + if (vdev->vq[i].pa) { | |
| 605 | + virtqueue_init(&vdev->vq[i]); | |
| 747 | 606 | } |
| 748 | 607 | } |
| 749 | 608 | |
| ... | ... | @@ -757,40 +616,19 @@ void virtio_cleanup(VirtIODevice *vdev) |
| 757 | 616 | qemu_free(vdev->vq); |
| 758 | 617 | } |
| 759 | 618 | |
| 760 | -VirtIODevice *virtio_init_pci(PCIDevice *pci_dev, const char *name, | |
| 761 | - uint16_t vendor, uint16_t device, | |
| 762 | - uint16_t subvendor, uint16_t subdevice, | |
| 763 | - uint16_t class_code, uint8_t pif, | |
| 764 | - size_t config_size) | |
| 619 | +VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, | |
| 620 | + size_t config_size, size_t struct_size) | |
| 765 | 621 | { |
| 766 | 622 | VirtIODevice *vdev; |
| 767 | - uint8_t *config; | |
| 768 | - uint32_t size; | |
| 769 | 623 | |
| 770 | - vdev = to_virtio_device(pci_dev); | |
| 624 | + vdev = qemu_mallocz(struct_size); | |
| 771 | 625 | |
| 626 | + vdev->device_id = device_id; | |
| 772 | 627 | vdev->status = 0; |
| 773 | 628 | vdev->isr = 0; |
| 774 | 629 | vdev->queue_sel = 0; |
| 775 | 630 | vdev->vq = qemu_mallocz(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX); |
| 776 | 631 | |
| 777 | - config = pci_dev->config; | |
| 778 | - pci_config_set_vendor_id(config, vendor); | |
| 779 | - pci_config_set_device_id(config, device); | |
| 780 | - | |
| 781 | - config[0x08] = VIRTIO_PCI_ABI_VERSION; | |
| 782 | - | |
| 783 | - config[0x09] = pif; | |
| 784 | - pci_config_set_class(config, class_code); | |
| 785 | - config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; | |
| 786 | - | |
| 787 | - config[0x2c] = subvendor & 0xFF; | |
| 788 | - config[0x2d] = (subvendor >> 8) & 0xFF; | |
| 789 | - config[0x2e] = subdevice & 0xFF; | |
| 790 | - config[0x2f] = (subdevice >> 8) & 0xFF; | |
| 791 | - | |
| 792 | - config[0x3d] = 1; | |
| 793 | - | |
| 794 | 632 | vdev->name = name; |
| 795 | 633 | vdev->config_len = config_size; |
| 796 | 634 | if (vdev->config_len) |
| ... | ... | @@ -798,13 +636,13 @@ VirtIODevice *virtio_init_pci(PCIDevice *pci_dev, const char *name, |
| 798 | 636 | else |
| 799 | 637 | vdev->config = NULL; |
| 800 | 638 | |
| 801 | - size = 20 + config_size; | |
| 802 | - if (size & (size-1)) | |
| 803 | - size = 1 << qemu_fls(size); | |
| 804 | - | |
| 805 | - pci_register_io_region(pci_dev, 0, size, PCI_ADDRESS_SPACE_IO, | |
| 806 | - virtio_map); | |
| 807 | 639 | qemu_register_reset(virtio_reset, vdev); |
| 808 | - | |
| 809 | 640 | return vdev; |
| 810 | 641 | } |
| 642 | + | |
| 643 | +void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, | |
| 644 | + void *opaque) | |
| 645 | +{ | |
| 646 | + vdev->binding = binding; | |
| 647 | + vdev->binding_opaque = opaque; | |
| 648 | +} | ... | ... |
hw/virtio.h
| ... | ... | @@ -15,7 +15,7 @@ |
| 15 | 15 | #define _QEMU_VIRTIO_H |
| 16 | 16 | |
| 17 | 17 | #include "hw.h" |
| 18 | -#include "pci.h" | |
| 18 | +#include "qdev.h" | |
| 19 | 19 | |
| 20 | 20 | /* from Linux's linux/virtio_config.h */ |
| 21 | 21 | |
| ... | ... | @@ -70,13 +70,15 @@ typedef struct VirtQueueElement |
| 70 | 70 | struct iovec out_sg[VIRTQUEUE_MAX_SIZE]; |
| 71 | 71 | } VirtQueueElement; |
| 72 | 72 | |
| 73 | +typedef struct { | |
| 74 | + void (*update_irq)(void * opaque); | |
| 75 | +} VirtIOBindings; | |
| 76 | + | |
| 73 | 77 | #define VIRTIO_PCI_QUEUE_MAX 16 |
| 74 | 78 | |
| 75 | 79 | struct VirtIODevice |
| 76 | 80 | { |
| 77 | - PCIDevice pci_dev; | |
| 78 | 81 | const char *name; |
| 79 | - uint32_t addr; | |
| 80 | 82 | uint8_t status; |
| 81 | 83 | uint8_t isr; |
| 82 | 84 | uint16_t queue_sel; |
| ... | ... | @@ -90,14 +92,11 @@ struct VirtIODevice |
| 90 | 92 | void (*set_config)(VirtIODevice *vdev, const uint8_t *config); |
| 91 | 93 | void (*reset)(VirtIODevice *vdev); |
| 92 | 94 | VirtQueue *vq; |
| 95 | + const VirtIOBindings *binding; | |
| 96 | + void *binding_opaque; | |
| 97 | + uint16_t device_id; | |
| 93 | 98 | }; |
| 94 | 99 | |
| 95 | -VirtIODevice *virtio_init_pci(PCIDevice *pci_dev, const char *name, | |
| 96 | - uint16_t vendor, uint16_t device, | |
| 97 | - uint16_t subvendor, uint16_t subdevice, | |
| 98 | - uint16_t class_code, uint8_t pif, | |
| 99 | - size_t config_size); | |
| 100 | - | |
| 101 | 100 | VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, |
| 102 | 101 | void (*handle_output)(VirtIODevice *, |
| 103 | 102 | VirtQueue *)); |
| ... | ... | @@ -127,4 +126,30 @@ int virtio_queue_ready(VirtQueue *vq); |
| 127 | 126 | |
| 128 | 127 | int virtio_queue_empty(VirtQueue *vq); |
| 129 | 128 | |
| 129 | +/* Host binding interface. */ | |
| 130 | + | |
| 131 | +VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, | |
| 132 | + size_t config_size, size_t struct_size); | |
| 133 | +uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr); | |
| 134 | +uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr); | |
| 135 | +uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr); | |
| 136 | +void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data); | |
| 137 | +void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data); | |
| 138 | +void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data); | |
| 139 | +void virtio_queue_set_addr(VirtIODevice *vdev, int n, target_phys_addr_t addr); | |
| 140 | +target_phys_addr_t virtio_queue_get_addr(VirtIODevice *vdev, int n); | |
| 141 | +int virtio_queue_get_num(VirtIODevice *vdev, int n); | |
| 142 | +void virtio_queue_notify(VirtIODevice *vdev, int n); | |
| 143 | +void virtio_reset(void *opaque); | |
| 144 | +void virtio_update_irq(VirtIODevice *vdev); | |
| 145 | + | |
| 146 | +void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, | |
| 147 | + void *opaque); | |
| 148 | + | |
| 149 | +/* Base devices. */ | |
| 150 | +VirtIODevice *virtio_blk_init(DeviceState *dev); | |
| 151 | +VirtIODevice *virtio_net_init(DeviceState *dev); | |
| 152 | +VirtIODevice *virtio_console_init(DeviceState *dev); | |
| 153 | +VirtIODevice *virtio_balloon_init(DeviceState *dev); | |
| 154 | + | |
| 130 | 155 | #endif | ... | ... |