[Spice-commits] 139 commits - .gitignore Makefile Makefile.objs Makefile.target arch_init.c audio/audio.c audio/audio_int.h audio/spiceaudio.c block-migration.c block.c block.h block/blkdebug.c block/blkverify.c block/cow.c block/qcow.c block/qcow2-cluster.c block/qcow2-refcount.c block/qcow2.c block/raw-posix.c block/raw-win32.c block/raw.c block/vdi.c block/vmdk.c block/vpc.c block_int.h blockdev.c configure cutils.c default-configs/arm-softmmu.mak default-configs/cris-softmmu.mak default-configs/i386-softmmu.mak default-configs/m68k-softmmu.mak default-configs/microblaze-softmmu.mak default-configs/mips-softmmu.mak default-configs/mips64-softmmu.mak default-configs/mips64el-softmmu.mak default-configs/mipsel-softmmu.mak default-configs/pci.mak default-configs/ppc-softmmu.mak default-configs/ppc64-softmmu.mak default-configs/ppcemb-softmmu.mak default-configs/s390x-softmmu.mak default-configs/sh4-softmmu.mak default-configs/sh4eb-softmmu.mak default-configs/sparc-softmmu.mak defau lt-configs/sparc64-softmmu.mak default-configs/x86_64-softmmu.mak hmp-commands.hx hw/acpi_piix4.c hw/apb_pci.c hw/apic.c hw/audiodev.h hw/dec_pci.c hw/e1000.c hw/eepro100.c hw/hda-audio.c hw/hw.h hw/ide hw/intel-hda-defs.h hw/intel-hda.c hw/intel-hda.h hw/ioh3420.c hw/ioh3420.h hw/mips_malta.c hw/msi.c hw/msi.h hw/msix.c hw/multiboot.c hw/pc.c hw/pc.h hw/pc_piix.c hw/pci.c hw/pci.h hw/pci_bridge.c hw/pci_bridge.h hw/pci_ids.h hw/pci_internals.h hw/pcie.c hw/pcie.h hw/pcie_port.c hw/pcie_port.h hw/pcie_regs.h hw/pcnet-pci.c hw/pcnet.c hw/pcnet.h hw/ppc_newworld.c hw/ppc_oldworld.c hw/ppc_prep.c hw/scsi-disk.c hw/sun4u.c hw/usb-net.c hw/vga-pci.c hw/vga.c hw/vga_int.h hw/virtio-blk.c hw/virtio-net.c hw/virtio-pci.c hw/virtio.c hw/vmware_vga.c hw/xio3130_downstream.c hw/xio3130_downstream.h hw/xio3130_upstream.c hw/xio3130_upstream.h ioport.c ioport.h iorange.h linux-user/signal.c make_device_config.sh migration.c monitor.c net.c net/tap.c pc-bios/optionrom pc-bios/vgabios-cirr us.bin pc-bios/vgabios-stdvga.bin pc-bios/vgabios-vmware.bin pc-bios/vgabios.bin qemu-char.c qemu-common.h qemu-config.c qemu-doc.texi qemu-options.hx roms/vgabios savevm.c simpletrace.h slirp/misc.c slirp/slirp.h slirp/slirp_config.h target-i386/cpu.h target-i386/cpuid.c target-i386/kvm.c target-i386/machine.c trace-events tracetool ui/qemu-spice.h ui/spice-core.c ui/spice-display.c ui/spice-display.h usb-linux.c vl.c
Gerd Hoffmann
kraxel at kemper.freedesktop.org
Tue Nov 30 04:06:00 PST 2010
.gitignore | 2
Makefile | 62 +
Makefile.objs | 43 -
Makefile.target | 38
arch_init.c | 13
audio/audio.c | 27
audio/audio_int.h | 1
audio/spiceaudio.c | 346 ++++++++
block-migration.c | 61 +
block.c | 75 +
block.h | 2
block/blkdebug.c | 4
block/blkverify.c | 8
block/cow.c | 4
block/qcow.c | 4
block/qcow2-cluster.c | 1
block/qcow2-refcount.c | 1
block/qcow2.c | 4
block/raw-posix.c | 4
block/raw-win32.c | 11
block/raw.c | 4
block/vdi.c | 4
block/vmdk.c | 4
block/vpc.c | 21
block_int.h | 2
blockdev.c | 6
configure | 25
cutils.c | 88 ++
default-configs/arm-softmmu.mak | 3
default-configs/cris-softmmu.mak | 1
default-configs/i386-softmmu.mak | 4
default-configs/m68k-softmmu.mak | 2
default-configs/microblaze-softmmu.mak | 1
default-configs/mips-softmmu.mak | 3
default-configs/mips64-softmmu.mak | 3
default-configs/mips64el-softmmu.mak | 3
default-configs/mipsel-softmmu.mak | 3
default-configs/pci.mak | 12
default-configs/ppc-softmmu.mak | 3
default-configs/ppc64-softmmu.mak | 3
default-configs/ppcemb-softmmu.mak | 3
default-configs/s390x-softmmu.mak | 1
default-configs/sh4-softmmu.mak | 3
default-configs/sh4eb-softmmu.mak | 3
default-configs/sparc-softmmu.mak | 2
default-configs/sparc64-softmmu.mak | 2
default-configs/x86_64-softmmu.mak | 4
hmp-commands.hx | 5
hw/acpi_piix4.c | 70 -
hw/apb_pci.c | 56 +
hw/apic.c | 4
hw/audiodev.h | 3
hw/dec_pci.c | 46 -
hw/e1000.c | 18
hw/eepro100.c | 4
hw/hda-audio.c | 926 +++++++++++++++++++++++
hw/hw.h | 14
hw/ide/core.c | 12
hw/intel-hda-defs.h | 717 ++++++++++++++++++
hw/intel-hda.c | 1307 +++++++++++++++++++++++++++++++++
hw/intel-hda.h | 62 +
hw/ioh3420.c | 186 ++++
hw/ioh3420.h | 10
hw/mips_malta.c | 2
hw/msi.c | 347 ++++++++
hw/msi.h | 41 +
hw/msix.c | 8
hw/multiboot.c | 6
hw/pc.c | 24
hw/pc.h | 3
hw/pc_piix.c | 34
hw/pci.c | 333 ++------
hw/pci.h | 115 ++
hw/pci_bridge.c | 266 ++++++
hw/pci_bridge.h | 66 +
hw/pci_ids.h | 2
hw/pci_internals.h | 47 +
hw/pcie.c | 543 +++++++++++++
hw/pcie.h | 120 +++
hw/pcie_port.c | 116 ++
hw/pcie_port.h | 51 +
hw/pcie_regs.h | 154 +++
hw/pcnet-pci.c | 345 ++++++++
hw/pcnet.c | 316 -------
hw/pcnet.h | 3
hw/ppc_newworld.c | 2
hw/ppc_oldworld.c | 2
hw/ppc_prep.c | 2
hw/scsi-disk.c | 147 ++-
hw/sun4u.c | 2
hw/usb-net.c | 2
hw/vga-pci.c | 44 -
hw/vga.c | 2
hw/vga_int.h | 2
hw/virtio-blk.c | 6
hw/virtio-net.c | 41 -
hw/virtio-pci.c | 9
hw/virtio.c | 36
hw/vmware_vga.c | 12
hw/xio3130_downstream.c | 188 ++++
hw/xio3130_downstream.h | 11
hw/xio3130_upstream.c | 174 ++++
hw/xio3130_upstream.h | 10
ioport.c | 64 +
ioport.h | 2
iorange.h | 30
linux-user/signal.c | 18
make_device_config.sh | 28
migration.c | 4
monitor.c | 47 -
net.c | 16
net/tap.c | 7
pc-bios/optionrom/signrom.sh | 7
pc-bios/vgabios-cirrus.bin |binary
pc-bios/vgabios-stdvga.bin |binary
pc-bios/vgabios-vmware.bin |binary
pc-bios/vgabios.bin |binary
qemu-char.c | 8
qemu-common.h | 5
qemu-config.c | 57 +
qemu-doc.texi | 2
qemu-options.hx | 52 +
roms/vgabios | 2
savevm.c | 21
simpletrace.h | 6
slirp/misc.c | 42 -
slirp/slirp.h | 14
slirp/slirp_config.h | 6
target-i386/cpu.h | 1
target-i386/cpuid.c | 2
target-i386/kvm.c | 14
target-i386/machine.c | 26
trace-events | 3
tracetool | 242 +++++-
ui/qemu-spice.h | 1
ui/spice-core.c | 211 +++++
ui/spice-display.c | 27
ui/spice-display.h | 1
usb-linux.c | 75 +
vl.c | 47 -
140 files changed, 7964 insertions(+), 1122 deletions(-)
New commits:
commit 661a1799ba6544a54888283db19dd51469da01e5
Author: Paul Brook <paul at codesourcery.com>
Date: Sat Nov 27 11:56:02 2010 +0000
Add pcnet-pci.c
Add file missing from last commit.
Signed-off-by: Paul Brook <paul at codesourcery.com>
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
new file mode 100644
index 0000000..3dfbe46
--- /dev/null
+++ b/hw/pcnet-pci.c
@@ -0,0 +1,345 @@
+/*
+ * QEMU AMD PC-Net II (Am79C970A) PCI emulation
+ *
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* This software was written to be compatible with the specification:
+ * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
+ * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
+ */
+
+#include "pci.h"
+#include "net.h"
+#include "loader.h"
+#include "qemu-timer.h"
+
+#include "pcnet.h"
+
+//#define PCNET_DEBUG
+//#define PCNET_DEBUG_IO
+//#define PCNET_DEBUG_BCR
+//#define PCNET_DEBUG_CSR
+//#define PCNET_DEBUG_RMD
+//#define PCNET_DEBUG_TMD
+//#define PCNET_DEBUG_MATCH
+
+
+typedef struct {
+ PCIDevice pci_dev;
+ PCNetState state;
+} PCIPCNetState;
+
+static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ PCNetState *s = opaque;
+#ifdef PCNET_DEBUG
+ printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
+#endif
+ /* Check APROMWE bit to enable write access */
+ if (pcnet_bcr_readw(s,2) & 0x100)
+ s->prom[addr & 15] = val;
+}
+
+static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
+{
+ PCNetState *s = opaque;
+ uint32_t val = s->prom[addr & 15];
+#ifdef PCNET_DEBUG
+ printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
+#endif
+ return val;
+}
+
+static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
+ pcibus_t addr, pcibus_t size, int type)
+{
+ PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
+
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n",
+ addr, size);
+#endif
+
+ register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
+ register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
+
+ register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
+ register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
+ register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
+ register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
+}
+
+static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr,
+ val);
+#endif
+ if (!(addr & 0x10))
+ pcnet_aprom_writeb(d, addr & 0x0f, val);
+}
+
+static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+ PCNetState *d = opaque;
+ uint32_t val = -1;
+ if (!(addr & 0x10))
+ val = pcnet_aprom_readb(d, addr & 0x0f);
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr,
+ val & 0xff);
+#endif
+ return val;
+}
+
+static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr,
+ val);
+#endif
+ if (addr & 0x10)
+ pcnet_ioport_writew(d, addr & 0x0f, val);
+ else {
+ addr &= 0x0f;
+ pcnet_aprom_writeb(d, addr, val & 0xff);
+ pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
+ }
+}
+
+static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+ PCNetState *d = opaque;
+ uint32_t val = -1;
+ if (addr & 0x10)
+ val = pcnet_ioport_readw(d, addr & 0x0f);
+ else {
+ addr &= 0x0f;
+ val = pcnet_aprom_readb(d, addr+1);
+ val <<= 8;
+ val |= pcnet_aprom_readb(d, addr);
+ }
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr,
+ val & 0xffff);
+#endif
+ return val;
+}
+
+static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr,
+ val);
+#endif
+ if (addr & 0x10)
+ pcnet_ioport_writel(d, addr & 0x0f, val);
+ else {
+ addr &= 0x0f;
+ pcnet_aprom_writeb(d, addr, val & 0xff);
+ pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
+ pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
+ pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
+ }
+}
+
+static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+ PCNetState *d = opaque;
+ uint32_t val;
+ if (addr & 0x10)
+ val = pcnet_ioport_readl(d, addr & 0x0f);
+ else {
+ addr &= 0x0f;
+ val = pcnet_aprom_readb(d, addr+3);
+ val <<= 8;
+ val |= pcnet_aprom_readb(d, addr+2);
+ val <<= 8;
+ val |= pcnet_aprom_readb(d, addr+1);
+ val <<= 8;
+ val |= pcnet_aprom_readb(d, addr);
+ }
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr,
+ val);
+#endif
+ return val;
+}
+
+static const VMStateDescription vmstate_pci_pcnet = {
+ .name = "pcnet",
+ .version_id = 3,
+ .minimum_version_id = 2,
+ .minimum_version_id_old = 2,
+ .fields = (VMStateField []) {
+ VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState),
+ VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+/* PCI interface */
+
+static CPUWriteMemoryFunc * const pcnet_mmio_write[] = {
+ &pcnet_mmio_writeb,
+ &pcnet_mmio_writew,
+ &pcnet_mmio_writel
+};
+
+static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
+ &pcnet_mmio_readb,
+ &pcnet_mmio_readw,
+ &pcnet_mmio_readl
+};
+
+static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
+ pcibus_t addr, pcibus_t size, int type)
+{
+ PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
+
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
+ addr, size);
+#endif
+
+ cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->state.mmio_index);
+}
+
+static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
+ uint8_t *buf, int len, int do_bswap)
+{
+ cpu_physical_memory_write(addr, buf, len);
+}
+
+static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
+ uint8_t *buf, int len, int do_bswap)
+{
+ cpu_physical_memory_read(addr, buf, len);
+}
+
+static void pci_pcnet_cleanup(VLANClientState *nc)
+{
+ PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque;
+
+ pcnet_common_cleanup(d);
+}
+
+static int pci_pcnet_uninit(PCIDevice *dev)
+{
+ PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
+
+ cpu_unregister_io_memory(d->state.mmio_index);
+ qemu_del_timer(d->state.poll_timer);
+ qemu_free_timer(d->state.poll_timer);
+ qemu_del_vlan_client(&d->state.nic->nc);
+ return 0;
+}
+
+static NetClientInfo net_pci_pcnet_info = {
+ .type = NET_CLIENT_TYPE_NIC,
+ .size = sizeof(NICState),
+ .can_receive = pcnet_can_receive,
+ .receive = pcnet_receive,
+ .cleanup = pci_pcnet_cleanup,
+};
+
+static int pci_pcnet_init(PCIDevice *pci_dev)
+{
+ PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
+ PCNetState *s = &d->state;
+ uint8_t *pci_conf;
+
+#if 0
+ printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
+ sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
+#endif
+
+ pci_conf = pci_dev->config;
+
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE);
+ pci_set_word(pci_conf + PCI_STATUS,
+ PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
+ pci_conf[PCI_REVISION_ID] = 0x10;
+ pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
+
+ pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
+ pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
+
+ pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
+ pci_conf[PCI_MIN_GNT] = 0x06;
+ pci_conf[PCI_MAX_LAT] = 0xff;
+
+ /* Handler for memory-mapped I/O */
+ s->mmio_index =
+ cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state);
+
+ pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE,
+ PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
+
+ pci_register_bar(pci_dev, 1, PCNET_PNPMMIO_SIZE,
+ PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map);
+
+ s->irq = pci_dev->irq[0];
+ s->phys_mem_read = pci_physical_memory_read;
+ s->phys_mem_write = pci_physical_memory_write;
+
+ if (!pci_dev->qdev.hotplugged) {
+ static int loaded = 0;
+ if (!loaded) {
+ rom_add_option("pxe-pcnet.bin");
+ loaded = 1;
+ }
+ }
+
+ return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info);
+}
+
+static void pci_reset(DeviceState *dev)
+{
+ PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev);
+
+ pcnet_h_reset(&d->state);
+}
+
+static PCIDeviceInfo pcnet_info = {
+ .qdev.name = "pcnet",
+ .qdev.size = sizeof(PCIPCNetState),
+ .qdev.reset = pci_reset,
+ .qdev.vmsd = &vmstate_pci_pcnet,
+ .init = pci_pcnet_init,
+ .exit = pci_pcnet_uninit,
+ .qdev.props = (Property[]) {
+ DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void pci_pcnet_register_devices(void)
+{
+ pci_qdev_register(&pcnet_info);
+}
+
+device_init(pci_pcnet_register_devices)
commit a4c75a21f3749b8dc5a8cc252bc57adb3f43453c
Author: Paul Brook <paul at codesourcery.com>
Date: Sat Nov 27 11:23:34 2010 +0000
Split out common pcnet code
The core pcnet emulation code is used by both the PCI "pcnet" device
and the SPARC "lance" device. Split the common code frm the PCI code so
that that can be configures independantly.
Signed-off-by: Paul Brook <paul at codesourcery.com>
diff --git a/Makefile.objs b/Makefile.objs
index 72c6c7f..13ba26f 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -222,7 +222,8 @@ hw-obj-$(CONFIG_PCI) += pcie.o pcie_port.o
# PCI network cards
hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o
hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
-hw-obj-$(CONFIG_PCNET_PCI) += pcnet.o
+hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o
+hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
hw-obj-$(CONFIG_SMC91C111) += smc91c111.o
hw-obj-$(CONFIG_LAN9118) += lan9118.o
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index 0ddfb37..c74a99f 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -6,6 +6,7 @@ CONFIG_USB_OHCI=y
CONFIG_NE2000_PCI=y
CONFIG_EEPRO100_PCI=y
CONFIG_PCNET_PCI=y
+CONFIG_PCNET_COMMON=y
CONFIG_LSI_SCSI_PCI=y
CONFIG_RTL8139_PCI=y
CONFIG_E1000_PCI=y
diff --git a/default-configs/sparc-softmmu.mak b/default-configs/sparc-softmmu.mak
index 436d2a6..b0310c5 100644
--- a/default-configs/sparc-softmmu.mak
+++ b/default-configs/sparc-softmmu.mak
@@ -7,3 +7,4 @@ CONFIG_M48T59=y
CONFIG_PTIMER=y
CONFIG_FDC=y
CONFIG_EMPTY_SLOT=y
+CONFIG_PCNET_COMMON=y
diff --git a/hw/pcnet.c b/hw/pcnet.c
index f970bda..37010b8 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -35,9 +35,8 @@
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
*/
-#include "pci.h"
+#include "qdev.h"
#include "net.h"
-#include "loader.h"
#include "qemu-timer.h"
#include "qemu_socket.h"
@@ -52,11 +51,6 @@
//#define PCNET_DEBUG_MATCH
-typedef struct {
- PCIDevice pci_dev;
- PCNetState state;
-} PCIPCNetState;
-
struct qemu_ether_header {
uint8_t ether_dhost[6];
uint8_t ether_shost[6];
@@ -704,7 +698,6 @@ static void pcnet_poll_timer(void *opaque);
static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
-static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
static void pcnet_s_reset(PCNetState *s)
{
@@ -1538,7 +1531,7 @@ static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
}
}
-static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
+uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
{
uint32_t val;
rap &= 127;
@@ -1595,27 +1588,6 @@ void pcnet_h_reset(void *opaque)
pcnet_poll_timer(s);
}
-static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- PCNetState *s = opaque;
-#ifdef PCNET_DEBUG
- printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
-#endif
- /* Check APROMWE bit to enable write access */
- if (pcnet_bcr_readw(s,2) & 0x100)
- s->prom[addr & 15] = val;
-}
-
-static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
-{
- PCNetState *s = opaque;
- uint32_t val = s->prom[addr & 15];
-#ifdef PCNET_DEBUG
- printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
-#endif
- return val;
-}
-
void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
{
PCNetState *s = opaque;
@@ -1668,7 +1640,7 @@ uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
return val;
}
-static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
{
PCNetState *s = opaque;
pcnet_poll_timer(s);
@@ -1698,7 +1670,7 @@ static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
pcnet_update_irq(s);
}
-static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
+uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
{
PCNetState *s = opaque;
uint32_t val = -1;
@@ -1727,125 +1699,6 @@ static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
return val;
}
-static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
-
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n",
- addr, size);
-#endif
-
- register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
- register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
-
- register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
- register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
- register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
- register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
-}
-
-static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr,
- val);
-#endif
- if (!(addr & 0x10))
- pcnet_aprom_writeb(d, addr & 0x0f, val);
-}
-
-static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
-{
- PCNetState *d = opaque;
- uint32_t val = -1;
- if (!(addr & 0x10))
- val = pcnet_aprom_readb(d, addr & 0x0f);
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr,
- val & 0xff);
-#endif
- return val;
-}
-
-static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr,
- val);
-#endif
- if (addr & 0x10)
- pcnet_ioport_writew(d, addr & 0x0f, val);
- else {
- addr &= 0x0f;
- pcnet_aprom_writeb(d, addr, val & 0xff);
- pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
- }
-}
-
-static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
-{
- PCNetState *d = opaque;
- uint32_t val = -1;
- if (addr & 0x10)
- val = pcnet_ioport_readw(d, addr & 0x0f);
- else {
- addr &= 0x0f;
- val = pcnet_aprom_readb(d, addr+1);
- val <<= 8;
- val |= pcnet_aprom_readb(d, addr);
- }
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr,
- val & 0xffff);
-#endif
- return val;
-}
-
-static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr,
- val);
-#endif
- if (addr & 0x10)
- pcnet_ioport_writel(d, addr & 0x0f, val);
- else {
- addr &= 0x0f;
- pcnet_aprom_writeb(d, addr, val & 0xff);
- pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
- pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
- pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
- }
-}
-
-static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
-{
- PCNetState *d = opaque;
- uint32_t val;
- if (addr & 0x10)
- val = pcnet_ioport_readl(d, addr & 0x0f);
- else {
- addr &= 0x0f;
- val = pcnet_aprom_readb(d, addr+3);
- val <<= 8;
- val |= pcnet_aprom_readb(d, addr+2);
- val <<= 8;
- val |= pcnet_aprom_readb(d, addr+1);
- val <<= 8;
- val |= pcnet_aprom_readb(d, addr);
- }
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr,
- val);
-#endif
- return val;
-}
-
static bool is_version_2(void *opaque, int version_id)
{
return version_id == 2;
@@ -1875,18 +1728,6 @@ const VMStateDescription vmstate_pcnet = {
}
};
-static const VMStateDescription vmstate_pci_pcnet = {
- .name = "pcnet",
- .version_id = 3,
- .minimum_version_id = 2,
- .minimum_version_id_old = 2,
- .fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState),
- VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState),
- VMSTATE_END_OF_LIST()
- }
-};
-
void pcnet_common_cleanup(PCNetState *d)
{
d->nic = NULL;
@@ -1901,147 +1742,3 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
return 0;
}
-
-/* PCI interface */
-
-static CPUWriteMemoryFunc * const pcnet_mmio_write[] = {
- &pcnet_mmio_writeb,
- &pcnet_mmio_writew,
- &pcnet_mmio_writel
-};
-
-static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
- &pcnet_mmio_readb,
- &pcnet_mmio_readw,
- &pcnet_mmio_readl
-};
-
-static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
-
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
- addr, size);
-#endif
-
- cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->state.mmio_index);
-}
-
-static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
- uint8_t *buf, int len, int do_bswap)
-{
- cpu_physical_memory_write(addr, buf, len);
-}
-
-static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
- uint8_t *buf, int len, int do_bswap)
-{
- cpu_physical_memory_read(addr, buf, len);
-}
-
-static void pci_pcnet_cleanup(VLANClientState *nc)
-{
- PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque;
-
- pcnet_common_cleanup(d);
-}
-
-static int pci_pcnet_uninit(PCIDevice *dev)
-{
- PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
-
- cpu_unregister_io_memory(d->state.mmio_index);
- qemu_del_timer(d->state.poll_timer);
- qemu_free_timer(d->state.poll_timer);
- qemu_del_vlan_client(&d->state.nic->nc);
- return 0;
-}
-
-static NetClientInfo net_pci_pcnet_info = {
- .type = NET_CLIENT_TYPE_NIC,
- .size = sizeof(NICState),
- .can_receive = pcnet_can_receive,
- .receive = pcnet_receive,
- .cleanup = pci_pcnet_cleanup,
-};
-
-static int pci_pcnet_init(PCIDevice *pci_dev)
-{
- PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
- PCNetState *s = &d->state;
- uint8_t *pci_conf;
-
-#if 0
- printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
- sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
-#endif
-
- pci_conf = pci_dev->config;
-
- pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD);
- pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE);
- pci_set_word(pci_conf + PCI_STATUS,
- PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
- pci_conf[PCI_REVISION_ID] = 0x10;
- pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
-
- pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
- pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
-
- pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
- pci_conf[PCI_MIN_GNT] = 0x06;
- pci_conf[PCI_MAX_LAT] = 0xff;
-
- /* Handler for memory-mapped I/O */
- s->mmio_index =
- cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state);
-
- pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE,
- PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
-
- pci_register_bar(pci_dev, 1, PCNET_PNPMMIO_SIZE,
- PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map);
-
- s->irq = pci_dev->irq[0];
- s->phys_mem_read = pci_physical_memory_read;
- s->phys_mem_write = pci_physical_memory_write;
-
- if (!pci_dev->qdev.hotplugged) {
- static int loaded = 0;
- if (!loaded) {
- rom_add_option("pxe-pcnet.bin");
- loaded = 1;
- }
- }
-
- return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info);
-}
-
-static void pci_reset(DeviceState *dev)
-{
- PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev);
-
- pcnet_h_reset(&d->state);
-}
-
-static PCIDeviceInfo pcnet_info = {
- .qdev.name = "pcnet",
- .qdev.size = sizeof(PCIPCNetState),
- .qdev.reset = pci_reset,
- .qdev.vmsd = &vmstate_pci_pcnet,
- .init = pci_pcnet_init,
- .exit = pci_pcnet_uninit,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
-static void pcnet_register_devices(void)
-{
- pci_qdev_register(&pcnet_info);
-}
-
-device_init(pcnet_register_devices)
diff --git a/hw/pcnet.h b/hw/pcnet.h
index efacc9f..534bdf9 100644
--- a/hw/pcnet.h
+++ b/hw/pcnet.h
@@ -32,6 +32,9 @@ struct PCNetState_st {
void pcnet_h_reset(void *opaque);
void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val);
uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr);
+void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val);
+uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr);
+uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
int pcnet_can_receive(VLANClientState *nc);
ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_);
void pcnet_common_cleanup(PCNetState *d);
commit 129cac5b5af110cfa94eae1a570c33ce795f0104
Author: Paul Brook <paul at codesourcery.com>
Date: Sat Nov 27 10:33:55 2010 +0000
Remove PCI from sparc32 target
None of the (current) sparc32 machines have a PCI bus, so remove the PCI
code from these configs.
Signed-off-by: Paul Brook <paul at codesourcery.com>
diff --git a/default-configs/sparc-softmmu.mak b/default-configs/sparc-softmmu.mak
index 7c788b8..436d2a6 100644
--- a/default-configs/sparc-softmmu.mak
+++ b/default-configs/sparc-softmmu.mak
@@ -1,6 +1,5 @@
# Default configuration for sparc-softmmu
-include pci.mak
CONFIG_ECC=y
CONFIG_ESP=y
CONFIG_ESCC=y
commit cf66924f81f022942e14b4e613f1bf0dd2bdf0eb
Author: Paul Brook <paul at codesourcery.com>
Date: Sat Nov 27 00:43:04 2010 +0000
Detect missing config includes
Terminate make_device_config.sh if the awk command fails.
Typically this means a missing file.
Signed-off-by: Paul Brook <paul at codesourcery.com>
diff --git a/make_device_config.sh b/make_device_config.sh
index 59f267b..8abadfe 100644
--- a/make_device_config.sh
+++ b/make_device_config.sh
@@ -18,7 +18,8 @@ process_includes () {
f=$src
while [ -n "$f" ] ; do
- f=`awk '/^include / {print "'$src_dir'/" $2}' $f`
+ f=`awk '/^include / {ORS=" " ; print "'$src_dir'/" $2}' $f`
+ [ $? = 0 ] || exit 1
all_includes="$all_includes $f"
done
process_includes $src > $dest
commit 050e27c8c942151c0685342fe2cbac6a80eb1325
Author: Paul Brook <paul at codesourcery.com>
Date: Sat Nov 27 00:34:15 2010 +0000
Fix previous commit
Fix breakage from previous commit (missing pci.mak, and incorrect
include in default-configs/s390x-softmmu.mak).
Signed-off-by: Paul Brook <paul at codesourcery.com>
diff --git a/default-configs/cris-softmmu.mak b/default-configs/cris-softmmu.mak
index 5f1fd1e..1a479cd 100644
--- a/default-configs/cris-softmmu.mak
+++ b/default-configs/cris-softmmu.mak
@@ -1,6 +1,5 @@
# Default configuration for cris-softmmu
-#include pci.mak
CONFIG_NAND=y
CONFIG_PTIMER=y
CONFIG_PFLASH_CFI02=y
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
new file mode 100644
index 0000000..0ddfb37
--- /dev/null
+++ b/default-configs/pci.mak
@@ -0,0 +1,11 @@
+CONFIG_PCI=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO=y
+CONFIG_USB_UHCI=y
+CONFIG_USB_OHCI=y
+CONFIG_NE2000_PCI=y
+CONFIG_EEPRO100_PCI=y
+CONFIG_PCNET_PCI=y
+CONFIG_LSI_SCSI_PCI=y
+CONFIG_RTL8139_PCI=y
+CONFIG_E1000_PCI=y
diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak
index 16d7259..3005729 100644
--- a/default-configs/s390x-softmmu.mak
+++ b/default-configs/s390x-softmmu.mak
@@ -1 +1 @@
-include virtio.mak
+CONFIG_VIRTIO=y
commit 01af7daf5596e8860c71e72349e1d539b81d9c80
Author: Paul Brook <paul at codesourcery.com>
Date: Fri Nov 26 22:08:48 2010 +0000
VirtIO config option
Make virtio devices optional. Selecting individual devices is not useful
as the host bindings are all in one file.
Signed-off-by: Paul Brook <paul at codesourcery.com>
diff --git a/Makefile.objs b/Makefile.objs
index 9e85b04..72c6c7f 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -42,6 +42,11 @@ net-nested-$(CONFIG_SLIRP) += slirp.o
net-nested-$(CONFIG_VDE) += vde.o
net-obj-y += $(addprefix net/, $(net-nested-y))
+ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS),yy)
+# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
+# only pull in the actual virtio-9p device if we also enabled virtio.
+CONFIG_REALLY_VIRTFS=y
+endif
fsdev-nested-$(CONFIG_VIRTFS) = qemu-fsdev.o
fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y))
@@ -159,7 +164,7 @@ user-obj-y += cutils.o cache-utils.o
hw-obj-y =
hw-obj-y += vl.o loader.o
-hw-obj-y += virtio.o virtio-console.o
+hw-obj-$(CONFIG_VIRTIO) += virtio.o virtio-console.o
hw-obj-y += fw_cfg.o
# FIXME: Core PCI code and its direct dependencies are required by the
# QMP query-pci command.
@@ -264,7 +269,8 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
-hw-obj-$(CONFIG_VIRTFS) += virtio-9p-debug.o virtio-9p-local.o virtio-9p-xattr.o
+hw-obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p-debug.o
+hw-obj-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
hw-obj-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
######################################################################
diff --git a/Makefile.target b/Makefile.target
index 853045a..5784844 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -188,11 +188,11 @@ ifdef CONFIG_SOFTMMU
obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o
# virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly
-obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
+obj-$(CONFIG_VIRTIO) += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
obj-y += vhost_net.o
obj-$(CONFIG_VHOST_NET) += vhost.o
-obj-$(CONFIG_VIRTFS) += virtio-9p.o
+obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p.o
obj-y += rwhandler.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak
index e69de29..16d7259 100644
--- a/default-configs/s390x-softmmu.mak
+++ b/default-configs/s390x-softmmu.mak
@@ -0,0 +1 @@
+include virtio.mak
commit f8f5cfbaa49387a513fddd9c9bf1aeb0ecc64cce
Author: Paul Brook <paul at codesourcery.com>
Date: Fri Nov 26 21:39:42 2010 +0000
PCI config include
Split PCI config options into a separate file
Signed-off-by: Paul Brook <paul at codesourcery.com>
diff --git a/Makefile.objs b/Makefile.objs
index 4f4aba3..9e85b04 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -161,8 +161,11 @@ hw-obj-y =
hw-obj-y += vl.o loader.o
hw-obj-y += virtio.o virtio-console.o
hw-obj-y += fw_cfg.o
-hw-obj-$(CONFIG_PCI) += pci.o pci_host.o pcie_host.o pci_bridge.o
-hw-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o
+# FIXME: Core PCI code and its direct dependencies are required by the
+# QMP query-pci command.
+hw-obj-y += pci.o pci_bridge.o msix.o msi.o
+hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
+hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
hw-obj-y += watchdog.o
hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
hw-obj-$(CONFIG_ECC) += ecc.o
@@ -207,15 +210,14 @@ hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o
hw-obj-$(CONFIG_PIIX4) += piix4.o
# PCI watchdog devices
-hw-obj-y += wdt_i6300esb.o
+hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
-hw-obj-y += pcie.o pcie_port.o
-hw-obj-y += msix.o msi.o
+hw-obj-$(CONFIG_PCI) += pcie.o pcie_port.o
# PCI network cards
-hw-obj-y += ne2000.o
-hw-obj-y += eepro100.o
-hw-obj-y += pcnet.o
+hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o
+hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
+hw-obj-$(CONFIG_PCNET_PCI) += pcnet.o
hw-obj-$(CONFIG_SMC91C111) += smc91c111.o
hw-obj-$(CONFIG_LAN9118) += lan9118.o
@@ -232,7 +234,7 @@ hw-obj-$(CONFIG_IDE_MACIO) += ide/macio.o
hw-obj-$(CONFIG_IDE_VIA) += ide/via.o
# SCSI layer
-hw-obj-y += lsi53c895a.o
+hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
hw-obj-$(CONFIG_ESP) += esp.o
hw-obj-y += dma-helpers.o sysbus.o isa-bus.o
diff --git a/Makefile.target b/Makefile.target
index 2800f47..853045a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -210,8 +210,8 @@ obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
obj-$(CONFIG_USB_OHCI) += usb-ohci.o
# PCI network cards
-obj-y += rtl8139.o
-obj-y += e1000.o
+obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
+obj-$(CONFIG_E1000_PCI) += e1000.o
# Inter-VM PCI shared memory
obj-$(CONFIG_KVM) += ivshmem.o
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index e7a4e84..ac48dc1 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -1,7 +1,7 @@
# Default configuration for arm-softmmu
+include pci.mak
CONFIG_GDBSTUB_XML=y
-CONFIG_USB_OHCI=y
CONFIG_ISA_MMIO=y
CONFIG_NAND=y
CONFIG_ECC=y
@@ -25,6 +25,5 @@ CONFIG_SSI_SD=y
CONFIG_LAN9118=y
CONFIG_SMC91C111=y
CONFIG_DS1338=y
-CONFIG_VIRTIO_PCI=y
CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y
diff --git a/default-configs/cris-softmmu.mak b/default-configs/cris-softmmu.mak
index e0d2cab..5f1fd1e 100644
--- a/default-configs/cris-softmmu.mak
+++ b/default-configs/cris-softmmu.mak
@@ -1,6 +1,6 @@
# Default configuration for cris-softmmu
+#include pci.mak
CONFIG_NAND=y
CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
CONFIG_PFLASH_CFI02=y
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index ed00471..ce905d2 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -1,6 +1,6 @@
# Default configuration for i386-softmmu
-CONFIG_USB_OHCI=y
+include pci.mak
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VMWARE_VGA=y
@@ -9,7 +9,6 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y
CONFIG_PCSPK=y
CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
CONFIG_FDC=y
CONFIG_ACPI=y
CONFIG_APM=y
@@ -22,4 +21,3 @@ CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y
CONFIG_PIIX_PCI=y
CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
diff --git a/default-configs/m68k-softmmu.mak b/default-configs/m68k-softmmu.mak
index 69ca3ed..3e2ec37 100644
--- a/default-configs/m68k-softmmu.mak
+++ b/default-configs/m68k-softmmu.mak
@@ -1,5 +1,5 @@
# Default configuration for m68k-softmmu
+include pci.mak
CONFIG_GDBSTUB_XML=y
CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
diff --git a/default-configs/microblaze-softmmu.mak b/default-configs/microblaze-softmmu.mak
index 6c4f4f2..4399b8b 100644
--- a/default-configs/microblaze-softmmu.mak
+++ b/default-configs/microblaze-softmmu.mak
@@ -1,5 +1,4 @@
# Default configuration for microblaze-softmmu
CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
CONFIG_PFLASH_CFI01=y
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index 3d0af83..565e611 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -1,5 +1,6 @@
# Default configuration for mips-softmmu
+include pci.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA_PCI=y
@@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y
CONFIG_PCSPK=y
CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
CONFIG_FDC=y
CONFIG_ACPI=y
CONFIG_APM=y
@@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y
CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
CONFIG_RC4030=y
CONFIG_DP8393X=y
CONFIG_DS1225Y=y
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index 0030de4..03bd8eb 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -1,5 +1,6 @@
# Default configuration for mips64-softmmu
+include pci.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA_PCI=y
@@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y
CONFIG_PCSPK=y
CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
CONFIG_FDC=y
CONFIG_ACPI=y
CONFIG_APM=y
@@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y
CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
CONFIG_RC4030=y
CONFIG_DP8393X=y
CONFIG_DS1225Y=y
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index fa2a3ff..4661617 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -1,5 +1,6 @@
# Default configuration for mips64el-softmmu
+include pci.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA_PCI=y
@@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y
CONFIG_PCSPK=y
CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
CONFIG_FDC=y
CONFIG_ACPI=y
CONFIG_APM=y
@@ -25,7 +25,6 @@ CONFIG_IDE_PIIX=y
CONFIG_IDE_VIA=y
CONFIG_NE2000_ISA=y
CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
CONFIG_RC4030=y
CONFIG_DP8393X=y
CONFIG_DS1225Y=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index 238b73a..92fc473 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -1,5 +1,6 @@
# Default configuration for mipsel-softmmu
+include pci.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA_PCI=y
@@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y
CONFIG_PCSPK=y
CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
CONFIG_FDC=y
CONFIG_ACPI=y
CONFIG_APM=y
@@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y
CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
CONFIG_RC4030=y
CONFIG_DP8393X=y
CONFIG_DS1225Y=y
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 940f4bf..f1cb99e 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -1,7 +1,7 @@
# Default configuration for ppc-softmmu
+include pci.mak
CONFIG_GDBSTUB_XML=y
-CONFIG_USB_OHCI=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
CONFIG_M48T59=y
@@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y
CONFIG_IDE_MACIO=y
CONFIG_NE2000_ISA=y
CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y
CONFIG_PTIMER=y
diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
index e1bc6b8..83cbe97 100644
--- a/default-configs/ppc64-softmmu.mak
+++ b/default-configs/ppc64-softmmu.mak
@@ -1,7 +1,7 @@
# Default configuration for ppc64-softmmu
+include pci.mak
CONFIG_GDBSTUB_XML=y
-CONFIG_USB_OHCI=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
CONFIG_M48T59=y
@@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y
CONFIG_IDE_MACIO=y
CONFIG_NE2000_ISA=y
CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y
CONFIG_PTIMER=y
diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
index 8f1cc09..2b52d4a 100644
--- a/default-configs/ppcemb-softmmu.mak
+++ b/default-configs/ppcemb-softmmu.mak
@@ -1,7 +1,7 @@
# Default configuration for ppcemb-softmmu
+include pci.mak
CONFIG_GDBSTUB_XML=y
-CONFIG_USB_OHCI=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
CONFIG_M48T59=y
@@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y
CONFIG_IDE_MACIO=y
CONFIG_NE2000_ISA=y
CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y
CONFIG_PTIMER=y
diff --git a/default-configs/sh4-softmmu.mak b/default-configs/sh4-softmmu.mak
index 866ed7d..87247a4 100644
--- a/default-configs/sh4-softmmu.mak
+++ b/default-configs/sh4-softmmu.mak
@@ -1,9 +1,8 @@
# Default configuration for sh4-softmmu
-CONFIG_USB_OHCI=y
+include pci.mak
CONFIG_SERIAL=y
CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
CONFIG_IDE_CORE=y
CONFIG_PFLASH_CFI02=y
CONFIG_ISA_MMIO=y
diff --git a/default-configs/sh4eb-softmmu.mak b/default-configs/sh4eb-softmmu.mak
index e3e08b7..5b8a16e 100644
--- a/default-configs/sh4eb-softmmu.mak
+++ b/default-configs/sh4eb-softmmu.mak
@@ -1,9 +1,8 @@
# Default configuration for sh4eb-softmmu
-CONFIG_USB_OHCI=y
+include pci.mak
CONFIG_SERIAL=y
CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
CONFIG_IDE_CORE=y
CONFIG_PFLASH_CFI02=y
CONFIG_ISA_MMIO=y
diff --git a/default-configs/sparc-softmmu.mak b/default-configs/sparc-softmmu.mak
index becf880..7c788b8 100644
--- a/default-configs/sparc-softmmu.mak
+++ b/default-configs/sparc-softmmu.mak
@@ -1,10 +1,10 @@
# Default configuration for sparc-softmmu
+include pci.mak
CONFIG_ECC=y
CONFIG_ESP=y
CONFIG_ESCC=y
CONFIG_M48T59=y
CONFIG_PTIMER=y
CONFIG_FDC=y
-CONFIG_VIRTIO_PCI=y
CONFIG_EMPTY_SLOT=y
diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak
index 1cc3f13..ecc3122 100644
--- a/default-configs/sparc64-softmmu.mak
+++ b/default-configs/sparc64-softmmu.mak
@@ -1,5 +1,6 @@
# Default configuration for sparc64-softmmu
+include pci.mak
CONFIG_ISA_MMIO=y
CONFIG_M48T59=y
CONFIG_PTIMER=y
@@ -13,4 +14,3 @@ CONFIG_IDE_QDEV=y
CONFIG_IDE_PCI=y
CONFIG_IDE_ISA=y
CONFIG_IDE_CMD646=y
-CONFIG_VIRTIO_PCI=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 5183203..7f22599 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -1,6 +1,6 @@
# Default configuration for x86_64-softmmu
-CONFIG_USB_OHCI=y
+include pci.mak
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VMWARE_VGA=y
@@ -9,7 +9,6 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y
CONFIG_PCSPK=y
CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
CONFIG_FDC=y
CONFIG_ACPI=y
CONFIG_APM=y
@@ -22,4 +21,3 @@ CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y
CONFIG_PIIX_PCI=y
CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
commit bd9141bb2e53195e3c1abf29275365d7f554beb5
Author: Paul Brook <paul at codesourcery.com>
Date: Fri Nov 26 18:47:45 2010 +0000
Include directives in default configs
Allow default configs to be split into several files.
Signed-off-by: Paul Brook <paul at codesourcery.com>
diff --git a/Makefile b/Makefile
index 3389775..d3bc0f2 100644
--- a/Makefile
+++ b/Makefile
@@ -39,18 +39,19 @@ endif
SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory)
SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
+SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS))
config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
$(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@," GEN $@")
+-include $(SUBDIR_DEVICES_MAK_DEP)
+
%/config-devices.mak: default-configs/%.mak
- $(call quiet-command,cat $< > $@.tmp, " GEN $@")
+ $(call quiet-command,$(SHELL) $(SRC_PATH)/make_device_config.sh $@ $<, " GEN $@")
@if test -f $@; then \
if cmp -s $@.old $@; then \
- if ! cmp -s $@ $@.tmp; then \
- mv $@.tmp $@; \
- cp -p $@ $@.old; \
- fi; \
+ mv $@.tmp $@; \
+ cp -p $@ $@.old; \
else \
if test -f $@.old; then \
echo "WARNING: $@ (user modified) out of date.";\
diff --git a/Makefile.objs b/Makefile.objs
index 23b17ce..4f4aba3 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -160,7 +160,8 @@ user-obj-y += cutils.o cache-utils.o
hw-obj-y =
hw-obj-y += vl.o loader.o
hw-obj-y += virtio.o virtio-console.o
-hw-obj-y += fw_cfg.o pci.o pci_host.o pcie_host.o pci_bridge.o
+hw-obj-y += fw_cfg.o
+hw-obj-$(CONFIG_PCI) += pci.o pci_host.o pcie_host.o pci_bridge.o
hw-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o
hw-obj-y += watchdog.o
hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
diff --git a/make_device_config.sh b/make_device_config.sh
new file mode 100644
index 0000000..59f267b
--- /dev/null
+++ b/make_device_config.sh
@@ -0,0 +1,27 @@
+#! /bin/sh
+# Construct a target device config file from a default, pulling in any
+# files from include directives.
+
+dest=$1.tmp
+dep=$1.d
+src=$2
+src_dir=`dirname $src`
+all_includes=
+
+process_includes () {
+ cat $1 | grep '^include' | \
+ while read include file ; do
+ all_includes="$all_includes $src_dir/$file"
+ process_includes $src_dir/$file
+ done
+}
+
+f=$src
+while [ -n "$f" ] ; do
+ f=`awk '/^include / {print "'$src_dir'/" $2}' $f`
+ all_includes="$all_includes $f"
+done
+process_includes $src > $dest
+
+cat $src $all_includes | grep -v '^include' > $dest
+echo "$1: $all_includes" > $dep
commit 6e14404aab26f74a448747d1e793ac16bde8a92b
Author: Paul Brook <paul at codesourcery.com>
Date: Fri Nov 26 18:46:03 2010 +0000
Add missing dependency.
Teach Makefile that cmd.o depends on a generated header (specifically
config-host.h).
Signed-off-by: Paul Brook <paul at codesourcery.com>
diff --git a/Makefile b/Makefile
index 4e120a2..3389775 100644
--- a/Makefile
+++ b/Makefile
@@ -150,7 +150,7 @@ version-obj-$(CONFIG_WIN32) += version.o
######################################################################
qemu-img.o: qemu-img-cmds.h
-qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o: $(GENERATED_HEADERS)
+qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o: $(GENERATED_HEADERS)
qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
commit f711df67d611e4762966a249742a5f7499e19f99
Author: Richard Henderson <rth at redhat.com>
Date: Mon Nov 22 14:57:52 2010 -0800
microblaze: target-ify target_ucontext
Rename the members of target_ucontext so that they don't conflict
with possible host macros for ucontext members. This has already
been done for the other targets.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Edgar E. Iglesias <edgar at axis.com>
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 77683f7..7c62fac 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -3071,11 +3071,11 @@ struct target_stack_t {
};
struct target_ucontext {
- abi_ulong uc_flags;
- abi_ulong uc_link;
- struct target_stack_t uc_stack;
- struct target_sigcontext sc;
- uint32_t extramask[TARGET_NSIG_WORDS - 1];
+ abi_ulong tuc_flags;
+ abi_ulong tuc_link;
+ struct target_stack_t tuc_stack;
+ struct target_sigcontext tuc_mcontext;
+ uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
};
/* Signal frames. */
@@ -3189,7 +3189,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
goto badframe;
/* Save the mask. */
- err |= __put_user(set->sig[0], &frame->uc.sc.oldmask);
+ err |= __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
if (err)
goto badframe;
@@ -3198,7 +3198,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
goto badframe;
}
- setup_sigcontext(&frame->uc.sc, env);
+ setup_sigcontext(&frame->uc.tuc_mcontext, env);
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
@@ -3261,7 +3261,7 @@ long do_sigreturn(CPUState *env)
goto badframe;
/* Restore blocked signals */
- if (__get_user(target_set.sig[0], &frame->uc.sc.oldmask))
+ if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask))
goto badframe;
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
@@ -3270,7 +3270,7 @@ long do_sigreturn(CPUState *env)
target_to_host_sigset_internal(&set, &target_set);
sigprocmask(SIG_SETMASK, &set, NULL);
- restore_sigcontext(&frame->uc.sc, env);
+ restore_sigcontext(&frame->uc.tuc_mcontext, env);
/* We got here through a sigreturn syscall, our path back is via an
rtb insn so setup r14 for that. */
env->regs[14] = env->sregs[SR_PC];
commit 4e02d460dd4b60847a1e8b689cb676e3e1f3de95
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Mon Nov 15 20:44:38 2010 +0000
virtio-pci: Convert fprintf() to error_report()
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 3610d7e..c65765a 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -254,8 +254,8 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
virtio_queue_set_vector(vdev, vdev->queue_sel, val);
break;
default:
- fprintf(stderr, "%s: unexpected address 0x%x value 0x%x\n",
- __func__, addr, val);
+ error_report("%s: unexpected address 0x%x value 0x%x",
+ __func__, addr, val);
break;
}
}
commit e7b43f7e60a0a170356e82b01b8ffdcecafad7ed
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Mon Nov 15 20:44:37 2010 +0000
virtio-net: Convert fprintf() to error_report()
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 7e1688c..1d61f19 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -120,8 +120,8 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
if (!n->vhost_started) {
int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
if (r < 0) {
- fprintf(stderr, "unable to start vhost net: %d: "
- "falling back on userspace virtio\n", -r);
+ error_report("unable to start vhost net: %d: "
+ "falling back on userspace virtio", -r);
} else {
n->vhost_started = 1;
}
@@ -271,7 +271,7 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
uint8_t on;
if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(on)) {
- fprintf(stderr, "virtio-net ctrl invalid rx mode command\n");
+ error_report("virtio-net ctrl invalid rx mode command");
exit(1);
}
@@ -353,7 +353,7 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
uint16_t vid;
if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(vid)) {
- fprintf(stderr, "virtio-net ctrl invalid vlan command\n");
+ error_report("virtio-net ctrl invalid vlan command");
return VIRTIO_NET_ERR;
}
@@ -381,13 +381,13 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
while (virtqueue_pop(vq, &elem)) {
if ((elem.in_num < 1) || (elem.out_num < 1)) {
- fprintf(stderr, "virtio-net ctrl missing headers\n");
+ error_report("virtio-net ctrl missing headers");
exit(1);
}
if (elem.out_sg[0].iov_len < sizeof(ctrl) ||
elem.in_sg[elem.in_num - 1].iov_len < sizeof(status)) {
- fprintf(stderr, "virtio-net ctrl header not in correct element\n");
+ error_report("virtio-net ctrl header not in correct element");
exit(1);
}
@@ -591,21 +591,21 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
if (virtqueue_pop(n->rx_vq, &elem) == 0) {
if (i == 0)
return -1;
- fprintf(stderr, "virtio-net unexpected empty queue: "
+ error_report("virtio-net unexpected empty queue: "
"i %zd mergeable %d offset %zd, size %zd, "
- "guest hdr len %zd, host hdr len %zd guest features 0x%x\n",
+ "guest hdr len %zd, host hdr len %zd guest features 0x%x",
i, n->mergeable_rx_bufs, offset, size,
guest_hdr_len, host_hdr_len, n->vdev.guest_features);
exit(1);
}
if (elem.in_num < 1) {
- fprintf(stderr, "virtio-net receive queue contains no in buffers\n");
+ error_report("virtio-net receive queue contains no in buffers");
exit(1);
}
if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != guest_hdr_len) {
- fprintf(stderr, "virtio-net header not in first element\n");
+ error_report("virtio-net header not in first element");
exit(1);
}
@@ -630,12 +630,11 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
* Otherwise, drop it. */
if (!n->mergeable_rx_bufs && offset < size) {
#if 0
- fprintf(stderr, "virtio-net truncated non-mergeable packet: "
-
- "i %zd mergeable %d offset %zd, size %zd, "
- "guest hdr len %zd, host hdr len %zd\n",
- i, n->mergeable_rx_bufs,
- offset, size, guest_hdr_len, host_hdr_len);
+ error_report("virtio-net truncated non-mergeable packet: "
+ "i %zd mergeable %d offset %zd, size %zd, "
+ "guest hdr len %zd, host hdr len %zd",
+ i, n->mergeable_rx_bufs,
+ offset, size, guest_hdr_len, host_hdr_len);
#endif
return size;
}
@@ -695,7 +694,7 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
sizeof(struct virtio_net_hdr);
if (out_num < 1 || out_sg->iov_len != hdr_len) {
- fprintf(stderr, "virtio-net header not in first element\n");
+ error_report("virtio-net header not in first element");
exit(1);
}
@@ -981,10 +980,10 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
if (net->tx && strcmp(net->tx, "timer") && strcmp(net->tx, "bh")) {
- fprintf(stderr, "virtio-net: "
- "Unknown option tx=%s, valid options: \"timer\" \"bh\"\n",
- net->tx);
- fprintf(stderr, "Defaulting to \"bh\"\n");
+ error_report("virtio-net: "
+ "Unknown option tx=%s, valid options: \"timer\" \"bh\"",
+ net->tx);
+ error_report("Defaulting to \"bh\"");
}
if (net->tx && !strcmp(net->tx, "timer")) {
commit cd92f4cc22fbe12a7bf60c9430731f768dc1537c
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Mon Nov 15 20:44:36 2010 +0000
virtio: Convert fprintf() to error_report()
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/virtio.c b/hw/virtio.c
index a2a657e..849a60f 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -14,6 +14,7 @@
#include <inttypes.h>
#include "trace.h"
+#include "qemu-error.h"
#include "virtio.h"
#include "sysemu.h"
@@ -253,8 +254,8 @@ static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx)
/* Check it isn't doing very strange things with descriptor numbers. */
if (num_heads > vq->vring.num) {
- fprintf(stderr, "Guest moved used index from %u to %u",
- idx, vring_avail_idx(vq));
+ error_report("Guest moved used index from %u to %u",
+ idx, vring_avail_idx(vq));
exit(1);
}
@@ -271,7 +272,7 @@ static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx)
/* If their number is silly, that's a fatal mistake. */
if (head >= vq->vring.num) {
- fprintf(stderr, "Guest says index %u is available", head);
+ error_report("Guest says index %u is available", head);
exit(1);
}
@@ -293,7 +294,7 @@ static unsigned virtqueue_next_desc(target_phys_addr_t desc_pa,
wmb();
if (next >= max) {
- fprintf(stderr, "Desc next is %u", next);
+ error_report("Desc next is %u", next);
exit(1);
}
@@ -320,13 +321,13 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes)
if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
- fprintf(stderr, "Invalid size for indirect buffer table\n");
+ error_report("Invalid size for indirect buffer table");
exit(1);
}
/* If we've got too many, that implies a descriptor loop. */
if (num_bufs >= max) {
- fprintf(stderr, "Looped descriptor");
+ error_report("Looped descriptor");
exit(1);
}
@@ -340,7 +341,7 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes)
do {
/* If we've got too many, that implies a descriptor loop. */
if (++num_bufs > max) {
- fprintf(stderr, "Looped descriptor");
+ error_report("Looped descriptor");
exit(1);
}
@@ -374,7 +375,7 @@ void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr,
len = sg[i].iov_len;
sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
if (sg[i].iov_base == NULL || len != sg[i].iov_len) {
- fprintf(stderr, "virtio: trying to map MMIO memory\n");
+ error_report("virtio: trying to map MMIO memory");
exit(1);
}
}
@@ -397,7 +398,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
- fprintf(stderr, "Invalid size for indirect buffer table\n");
+ error_report("Invalid size for indirect buffer table");
exit(1);
}
@@ -423,7 +424,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
/* If we've got too many, that implies a descriptor loop. */
if ((elem->in_num + elem->out_num) > max) {
- fprintf(stderr, "Looped descriptor");
+ error_report("Looped descriptor");
exit(1);
}
} while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
@@ -694,8 +695,8 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
qemu_get_be16s(f, &vdev->queue_sel);
qemu_get_be32s(f, &features);
if (features & ~supported_features) {
- fprintf(stderr, "Features 0x%x unsupported. Allowed features: 0x%x\n",
- features, supported_features);
+ error_report("Features 0x%x unsupported. Allowed features: 0x%x",
+ features, supported_features);
return -1;
}
if (vdev->set_features)
@@ -717,11 +718,11 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
num_heads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
/* Check it isn't doing very strange things with descriptor numbers. */
if (num_heads > vdev->vq[i].vring.num) {
- fprintf(stderr, "VQ %d size 0x%x Guest index 0x%x "
- "inconsistent with Host index 0x%x: delta 0x%x\n",
- i, vdev->vq[i].vring.num,
- vring_avail_idx(&vdev->vq[i]),
- vdev->vq[i].last_avail_idx, num_heads);
+ error_report("VQ %d size 0x%x Guest index 0x%x "
+ "inconsistent with Host index 0x%x: delta 0x%x",
+ i, vdev->vq[i].vring.num,
+ vring_avail_idx(&vdev->vq[i]),
+ vdev->vq[i].last_avail_idx, num_heads);
return -1;
}
if (vdev->binding->load_queue) {
commit 870cef1dae88f131ee3e17fe0aaf45d609798ce1
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Mon Nov 15 20:44:35 2010 +0000
virtio-blk: Convert fprintf() to error_report()
Errors should be logged using error_report() so they go to the
appropriate monitor.
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 49528a9..e5f9b27 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -324,13 +324,13 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req,
MultiReqBuffer *mrb)
{
if (req->elem.out_num < 1 || req->elem.in_num < 1) {
- fprintf(stderr, "virtio-blk missing headers\n");
+ error_report("virtio-blk missing headers");
exit(1);
}
if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
- fprintf(stderr, "virtio-blk header not in correct element\n");
+ error_report("virtio-blk header not in correct element");
exit(1);
}
commit 281a26b15b4adcecb8604216738975abd754bea8
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Wed Nov 17 12:06:44 2010 +0100
vgabios update: handle compatibility with older qemu versions
As pointed out by avi the vgabios update is guest-visible and thus has
migration implications.
One change is that the vga has a valid pci rom bar now. We already have
a pci bus property to enable/disable the rom bar and we'll load the bios
via fw_cfg as fallback for the no-rom-bar case. So we just have to add
compat properties to handle this case.
A second change is that the magic bochs lfb @ 0xe0000000 is gone. When
live-migrating a guest from a older qemu version it might be using the
lfb though, so we have to keep it for the old machine types. The patch
enables the bochs lfb in case we don't have the pci rom bar enabled
(i.e. we are in 0.13+older compat mode).
This patch depends on these patches which add (and use) the pc-0.13
machine type:
http://patchwork.ozlabs.org/patch/70797/
http://patchwork.ozlabs.org/patch/70798/
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Cc: avi at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 31c80d2..7d29d43 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -230,6 +230,14 @@ static QEMUMachine pc_machine_v0_13 = {
.driver = "virtio-9p-pci",
.property = "vectors",
.value = stringify(0),
+ },{
+ .driver = "VGA",
+ .property = "rombar",
+ .value = stringify(0),
+ },{
+ .driver = "vmware-svga",
+ .property = "rombar",
+ .value = stringify(0),
},
{ /* end of list */ }
},
@@ -249,6 +257,14 @@ static QEMUMachine pc_machine_v0_12 = {
.driver = "virtio-serial-pci",
.property = "vectors",
.value = stringify(0),
+ },{
+ .driver = "VGA",
+ .property = "rombar",
+ .value = stringify(0),
+ },{
+ .driver = "vmware-svga",
+ .property = "rombar",
+ .value = stringify(0),
},
{ /* end of list */ }
}
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index b09789c..791ca22 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -92,6 +92,11 @@ static int pci_vga_initfn(PCIDevice *dev)
pci_register_bar(&d->dev, 0, VGA_RAM_SIZE,
PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
+ if (!dev->rom_bar) {
+ /* compatibility with pc-0.13 and older */
+ vga_init_vbe(s);
+ }
+
return 0;
}
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 9337fdb..d0f4e1b 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1301,6 +1301,11 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
vmsvga_init(&s->chip, VGA_RAM_SIZE);
+ if (!dev->rom_bar) {
+ /* compatibility with pc-0.13 and older */
+ vga_init_vbe(&s->chip.vga);
+ }
+
return 0;
}
commit c1ded3dc9f2d6caeb62eb3005510837a62b795d2
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date: Tue Oct 19 17:03:24 2010 +0200
pcnet: Do not receive external frames in loopback mode
While not explicitly stated in the spec, it was observed on real systems
that enabling loopback testing on the pcnet controller disables
reception of external frames. And some legacy software relies on it, so
provide this behavior.
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/pcnet.c b/hw/pcnet.c
index b52935a..f970bda 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -1048,9 +1048,10 @@ ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_)
int crc_err = 0;
int size = size_;
- if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size)
+ if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size ||
+ (CSR_LOOP(s) && !s->looptest)) {
return -1;
-
+ }
#ifdef PCNET_DEBUG
printf("pcnet_receive size=%d\n", size);
#endif
commit 2871a3f6b64966bc78fce0d4033bf32fcd42401c
Author: Avi Kivity <avi at redhat.com>
Date: Wed Nov 17 11:50:10 2010 +0200
piix4 acpi: convert io BAR to type-safe ioport callbacks
Acked-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Avi Kivity <avi at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index f549089..173d781 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -52,6 +52,7 @@ struct pci_status {
typedef struct PIIX4PMState {
PCIDevice dev;
+ IORange ioport;
uint16_t pmsts;
uint16_t pmen;
uint16_t pmcntrl;
@@ -128,10 +129,16 @@ static void pm_tmr_timer(void *opaque)
pm_update_sci(s);
}
-static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width,
+ uint64_t val)
{
- PIIX4PMState *s = opaque;
- addr &= 0x3f;
+ PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport);
+
+ if (width != 2) {
+ PIIX4_DPRINTF("PM write port=0x%04x width=%d val=0x%08x\n",
+ (unsigned)addr, width, (unsigned)val);
+ }
+
switch(addr) {
case 0x00:
{
@@ -184,12 +191,12 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", addr, val);
}
-static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
+static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width,
+ uint64_t *data)
{
- PIIX4PMState *s = opaque;
+ PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport);
uint32_t val;
- addr &= 0x3f;
switch(addr) {
case 0x00:
val = get_pmsts(s);
@@ -200,27 +207,6 @@ static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
case 0x04:
val = s->pmcntrl;
break;
- default:
- val = 0;
- break;
- }
- PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", addr, val);
- return val;
-}
-
-static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- // PIIX4PMState *s = opaque;
- PIIX4_DPRINTF("PM writel port=0x%04x val=0x%08x\n", addr & 0x3f, val);
-}
-
-static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
-{
- PIIX4PMState *s = opaque;
- uint32_t val;
-
- addr &= 0x3f;
- switch(addr) {
case 0x08:
val = get_pmtmr(s);
break;
@@ -228,10 +214,15 @@ static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
val = 0;
break;
}
- PIIX4_DPRINTF("PM readl port=0x%04x val=0x%08x\n", addr, val);
- return val;
+ PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", addr, val);
+ *data = val;
}
+static const IORangeOps pm_iorange_ops = {
+ .read = pm_ioport_read,
+ .write = pm_ioport_write,
+};
+
static void apm_ctrl_changed(uint32_t val, void *arg)
{
PIIX4PMState *s = arg;
@@ -265,10 +256,8 @@ static void pm_io_space_update(PIIX4PMState *s)
/* XXX: need to improve memory and ioport allocation */
PIIX4_DPRINTF("PM: mapping to 0x%x\n", pm_io_base);
- register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s);
- register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s);
- register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
- register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
+ iorange_init(&s->ioport, &pm_iorange_ops, pm_io_base, 64);
+ ioport_register(&s->ioport);
}
}
commit acd1c812b5548c8426e093075362b6d4119db6ac
Author: Avi Kivity <avi at redhat.com>
Date: Wed Nov 17 11:50:09 2010 +0200
Type-safe ioport callbacks
The current ioport callbacks are not type-safe, in that they accept an "opaque"
pointer as an argument whose type must match the argument to the registration
function; this is not checked by the compiler.
This patch adds an alternative that is type-safe. Instead of an opaque
argument, both registation and the callback use a new IOPort type. The
callback then uses container_of() to access its main structures.
Currently the old and new methods exist side by side; once the old way is gone,
we can also save a bunch of memory since the new method requires one pointer
per ioport instead of 6.
Acked-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Avi Kivity <avi at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/ioport.c b/ioport.c
index ec3dc65..aa4188a 100644
--- a/ioport.c
+++ b/ioport.c
@@ -174,6 +174,70 @@ int register_ioport_write(pio_addr_t start, int length, int size,
return 0;
}
+static uint32_t ioport_readb_thunk(void *opaque, uint32_t addr)
+{
+ IORange *ioport = opaque;
+ uint64_t data;
+
+ ioport->ops->read(ioport, addr - ioport->base, 1, &data);
+ return data;
+}
+
+static uint32_t ioport_readw_thunk(void *opaque, uint32_t addr)
+{
+ IORange *ioport = opaque;
+ uint64_t data;
+
+ ioport->ops->read(ioport, addr - ioport->base, 2, &data);
+ return data;
+}
+
+static uint32_t ioport_readl_thunk(void *opaque, uint32_t addr)
+{
+ IORange *ioport = opaque;
+ uint64_t data;
+
+ ioport->ops->read(ioport, addr - ioport->base, 4, &data);
+ return data;
+}
+
+static void ioport_writeb_thunk(void *opaque, uint32_t addr, uint32_t data)
+{
+ IORange *ioport = opaque;
+
+ ioport->ops->write(ioport, addr - ioport->base, 1, data);
+}
+
+static void ioport_writew_thunk(void *opaque, uint32_t addr, uint32_t data)
+{
+ IORange *ioport = opaque;
+
+ ioport->ops->write(ioport, addr - ioport->base, 2, data);
+}
+
+static void ioport_writel_thunk(void *opaque, uint32_t addr, uint32_t data)
+{
+ IORange *ioport = opaque;
+
+ ioport->ops->write(ioport, addr - ioport->base, 4, data);
+}
+
+void ioport_register(IORange *ioport)
+{
+ register_ioport_read(ioport->base, ioport->len, 1,
+ ioport_readb_thunk, ioport);
+ register_ioport_read(ioport->base, ioport->len, 2,
+ ioport_readw_thunk, ioport);
+ register_ioport_read(ioport->base, ioport->len, 4,
+ ioport_readl_thunk, ioport);
+ register_ioport_write(ioport->base, ioport->len, 1,
+ ioport_writeb_thunk, ioport);
+ register_ioport_write(ioport->base, ioport->len, 2,
+ ioport_writew_thunk, ioport);
+ register_ioport_write(ioport->base, ioport->len, 4,
+ ioport_writel_thunk, ioport);
+}
+
void isa_unassign_ioport(pio_addr_t start, int length)
{
int i;
diff --git a/ioport.h b/ioport.h
index 3d3c8a3..5ae62a3 100644
--- a/ioport.h
+++ b/ioport.h
@@ -25,6 +25,7 @@
#define IOPORT_H
#include "qemu-common.h"
+#include "iorange.h"
typedef uint32_t pio_addr_t;
#define FMT_pioaddr PRIx32
@@ -36,6 +37,7 @@ typedef uint32_t pio_addr_t;
typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data);
typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address);
+void ioport_register(IORange *iorange);
int register_ioport_read(pio_addr_t start, int length, int size,
IOPortReadFunc *func, void *opaque);
int register_ioport_write(pio_addr_t start, int length, int size,
diff --git a/iorange.h b/iorange.h
new file mode 100644
index 0000000..9783168
--- /dev/null
+++ b/iorange.h
@@ -0,0 +1,30 @@
+#ifndef IORANGE_H
+#define IORANGE_H
+
+#include <stdint.h>
+
+typedef struct IORange IORange;
+typedef struct IORangeOps IORangeOps;
+
+struct IORangeOps {
+ void (*read)(IORange *iorange, uint64_t offset, unsigned width,
+ uint64_t *data);
+ void (*write)(IORange *iorange, uint64_t offset, unsigned width,
+ uint64_t data);
+};
+
+struct IORange {
+ const IORangeOps *ops;
+ uint64_t base;
+ uint64_t len;
+};
+
+static inline void iorange_init(IORange *iorange, const IORangeOps *ops,
+ uint64_t base, uint64_t len)
+{
+ iorange->ops = ops;
+ iorange->base = base;
+ iorange->len = len;
+}
+
+#endif
commit 94b0b5ff5f5c3ab946fa926d464738edb3713ed4
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Tue Nov 16 12:20:25 2010 +0000
trace: Trace vm_start()/vm_stop()
VM state change notifications are invoked from vm_start()/vm_stop().
Trace these state changes so we can reason about the state of the VM
from trace output.
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/trace-events b/trace-events
index 947f8b0..da03d4b 100644
--- a/trace-events
+++ b/trace-events
@@ -189,3 +189,6 @@ disable sun4m_iommu_mem_writel_pgflush(uint32_t val) "page flush %x"
disable sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr %"PRIx64" => pte %"PRIx64", *pte = %x"
disable sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x"
disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64""
+
+# vl.c
+disable vm_state_notify(int running, int reason) "running %d reason %d"
diff --git a/vl.c b/vl.c
index 9ee6479..805e11f 100644
--- a/vl.c
+++ b/vl.c
@@ -158,6 +158,7 @@ int main(int argc, char **argv)
#include "slirp/libslirp.h"
+#include "trace.h"
#include "qemu-queue.h"
#include "cpus.h"
#include "arch_init.h"
@@ -1074,6 +1075,8 @@ void vm_state_notify(int running, int reason)
{
VMChangeStateEntry *e;
+ trace_vm_state_notify(running, reason);
+
for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {
e->cb(e->opaque, running, reason);
}
commit 9dbcca5aa13cb9ab40788ac4c56bc227d94ca920
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Nov 11 12:59:26 2010 +0100
virtfs: enable MSI-X
This patch enables MSI-X for virtfs-9p-pci. It also adds a
compat property to pc-0.13 which turns it of there to stay
compatible to 0.13-stable.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index e17e878..31c80d2 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -225,6 +225,14 @@ static QEMUMachine pc_machine_v0_13 = {
.desc = "Standard PC",
.init = pc_init_pci,
.max_cpus = 255,
+ .compat_props = (GlobalProperty[]) {
+ {
+ .driver = "virtio-9p-pci",
+ .property = "vectors",
+ .value = stringify(0),
+ },
+ { /* end of list */ }
+ },
};
static QEMUMachine pc_machine_v0_12 = {
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 729917d..3610d7e 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -684,12 +684,14 @@ static int virtio_9p_init_pci(PCIDevice *pci_dev)
VirtIODevice *vdev;
vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
+ vdev->nvectors = proxy->nvectors;
virtio_init_pci(proxy, vdev,
PCI_VENDOR_ID_REDHAT_QUMRANET,
0x1009,
0x2,
0x00);
-
+ /* make the actual value visible */
+ proxy->nvectors = vdev->nvectors;
return 0;
}
#endif
@@ -758,6 +760,7 @@ static PCIDeviceInfo virtio_info[] = {
.qdev.size = sizeof(VirtIOPCIProxy),
.init = virtio_9p_init_pci,
.qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
commit b903a0f721f28283e5eaab00a3cb2ada96c2eae0
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Nov 11 12:59:25 2010 +0100
pc: add 0.13 pc machine type
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 12359a7..e17e878 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -212,7 +212,7 @@ static void pc_init_isa(ram_addr_t ram_size,
}
static QEMUMachine pc_machine = {
- .name = "pc-0.13",
+ .name = "pc-0.14",
.alias = "pc",
.desc = "Standard PC",
.init = pc_init_pci,
@@ -220,6 +220,13 @@ static QEMUMachine pc_machine = {
.is_default = 1,
};
+static QEMUMachine pc_machine_v0_13 = {
+ .name = "pc-0.13",
+ .desc = "Standard PC",
+ .init = pc_init_pci,
+ .max_cpus = 255,
+};
+
static QEMUMachine pc_machine_v0_12 = {
.name = "pc-0.12",
.desc = "Standard PC",
@@ -331,6 +338,7 @@ static QEMUMachine isapc_machine = {
static void pc_machine_init(void)
{
qemu_register_machine(&pc_machine);
+ qemu_register_machine(&pc_machine_v0_13);
qemu_register_machine(&pc_machine_v0_12);
qemu_register_machine(&pc_machine_v0_11);
qemu_register_machine(&pc_machine_v0_10);
commit 0b2c508856fa23695900c29b6ada57c07843bc6f
Author: Stefan Weil <weil at mail.berlios.de>
Date: Mon Nov 15 21:17:06 2010 +0100
trace: Use fprintf_function (format checking)
fprintf_function adds format checking with GCC_FMT_ATTR.
Cc: Blue Swirl <blauwirbel at gmail.com>
Signed-off-by: Stefan Weil <weil at mail.berlios.de>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/simpletrace.h b/simpletrace.h
index 72614ec..2f44ed3 100644
--- a/simpletrace.h
+++ b/simpletrace.h
@@ -29,10 +29,10 @@ void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3);
void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4);
void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5);
void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6);
-void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
-void st_print_trace_events(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
+void st_print_trace(FILE *stream, fprintf_function stream_printf);
+void st_print_trace_events(FILE *stream, fprintf_function stream_printf);
bool st_change_trace_event_state(const char *tname, bool tstate);
-void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
+void st_print_trace_file_status(FILE *stream, fprintf_function stream_printf);
void st_set_trace_file_enabled(bool enable);
bool st_set_trace_file(const char *file);
void st_flush_trace_buffer(void);
commit 9eca6cc64392b4ad8bd8723e840f491fa36524ad
Author: Stefan Weil <weil at mail.berlios.de>
Date: Mon Nov 15 21:15:26 2010 +0100
slirp: Remove unused code for bad sprintf
Neither DECLARE_SPRINTF nor BAD_SPRINTF are needed for QEMU.
QEMU won't support systems with missing or bad declarations
for sprintf. The unused code was detected while looking for
functions with missing format checking. Instead of adding
GCC_FMT_ATTR, the unused code was removed.
Cc: Blue Swirl <blauwirbel at gmail.com>
Signed-off-by: Stefan Weil <weil at mail.berlios.de>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/slirp/misc.c b/slirp/misc.c
index 1aeb401..19dbec4 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -264,48 +264,6 @@ void lprint(const char *format, ...)
va_end(args);
}
-#ifdef BAD_SPRINTF
-
-#undef vsprintf
-#undef sprintf
-
-/*
- * Some BSD-derived systems have a sprintf which returns char *
- */
-
-int
-vsprintf_len(string, format, args)
- char *string;
- const char *format;
- va_list args;
-{
- vsprintf(string, format, args);
- return strlen(string);
-}
-
-int
-#ifdef __STDC__
-sprintf_len(char *string, const char *format, ...)
-#else
-sprintf_len(va_alist) va_dcl
-#endif
-{
- va_list args;
-#ifdef __STDC__
- va_start(args, format);
-#else
- char *string;
- char *format;
- va_start(args);
- string = va_arg(args, char *);
- format = va_arg(args, char *);
-#endif
- vsprintf(string, format, args);
- return strlen(string);
-}
-
-#endif
-
void
u_sleep(int usec)
{
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 462292d..dfd977a 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -237,20 +237,6 @@ void if_start(Slirp *);
void if_start(struct ttys *);
#endif
-#ifdef BAD_SPRINTF
-# define vsprintf vsprintf_len
-# define sprintf sprintf_len
- extern int vsprintf_len(char *, const char *, va_list);
- extern int sprintf_len(char *, const char *, ...);
-#endif
-
-#ifdef DECLARE_SPRINTF
-# ifndef BAD_SPRINTF
- extern int vsprintf(char *, const char *, va_list);
-# endif
- extern int vfprintf(FILE *, const char *, va_list);
-#endif
-
#ifndef HAVE_STRERROR
extern char *strerror(int error);
#endif
diff --git a/slirp/slirp_config.h b/slirp/slirp_config.h
index f19c703..18db45c 100644
--- a/slirp/slirp_config.h
+++ b/slirp/slirp_config.h
@@ -85,9 +85,6 @@
/* Define if the machine is big endian */
//#undef HOST_WORDS_BIGENDIAN
-/* Define if your sprintf returns char * instead of int */
-#undef BAD_SPRINTF
-
/* Define if you have readv */
#undef HAVE_READV
@@ -97,9 +94,6 @@
#define DECLARE_IOVEC
#endif
-/* Define if a declaration of sprintf/fprintf is needed */
-#undef DECLARE_SPRINTF
-
/* Define if you have a POSIX.1 sys/wait.h */
#undef HAVE_SYS_WAIT_H
commit 0550f9c1b58896a6ca1d1256e26c78f84de2ed55
Author: Bernhard Kohl <bernhard.kohl at nsn.com>
Date: Tue Nov 16 13:28:37 2010 +0100
pc: disable the BOCHS BIOS panic port
We have an OS which writes to port 0x400 when probing for special hardware.
This causes an exit of the VM. With SeaBIOS this port isn't used anyway.
Signed-off-by: Alexander Graf <agraf at suse.de>
Reviewed-By: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Bernhard Kohl <bernhard.kohl at nsn.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/pc.c b/hw/pc.c
index c34d194..119c110 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -430,8 +430,8 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
/* Bochs BIOS messages */
case 0x400:
case 0x401:
- fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val);
- exit(1);
+ /* used to be panic, now unused */
+ break;
case 0x402:
case 0x403:
#ifdef DEBUG_BIOS
commit 33bbd1de5ec9b8802d63e811908f2351ba83884c
Author: Avi Kivity <avi at redhat.com>
Date: Tue Nov 16 16:33:17 2010 +0200
optionrom: fix bugs in signrom.sh
signrom.sh has multiple bugs:
- the last byte is considered when calculating the existing checksum, but not
when computing the correction
- apprently the 'expr' expression overflows and produces incorrect results with
larger roms
- if the checksum happened to be zero, we calculated the correction byte to be
256
Instead of rewriting this in half a line of python, this patch fixes the bugs.
Signed-off-by: Avi Kivity <avi at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/pc-bios/optionrom/signrom.sh b/pc-bios/optionrom/signrom.sh
index 975b27d..9dc5c63 100755
--- a/pc-bios/optionrom/signrom.sh
+++ b/pc-bios/optionrom/signrom.sh
@@ -31,14 +31,13 @@ x=`dd if="$1" bs=1 count=1 skip=2 2>/dev/null | od -t u1 -A n`
size=$(( $x * 512 - 1 ))
# now get the checksum
-nums=`od -A n -t u1 -v "$1"`
+nums=`od -A n -t u1 -v -N $size "$1"`
for i in ${nums}; do
# add each byte's value to sum
- sum=`expr $sum + $i`
+ sum=`expr \( $sum + $i \) % 256`
done
-sum=$(( $sum % 256 ))
-sum=$(( 256 - $sum ))
+sum=$(( (256 - $sum) % 256 ))
sum_octal=$( printf "%o" $sum )
# and write the output file
commit e71e00ed258202052570ae631536f4d7b65792fa
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date: Fri Nov 12 12:55:46 2010 -0200
Makefile: Fix check dependency breakage
Commit b152aa84d52882bb1846485a89baf13aa07c86bc broke the unit-tests
build, fix it.
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/Makefile b/Makefile
index 747e47c..4e120a2 100644
--- a/Makefile
+++ b/Makefile
@@ -163,12 +163,14 @@ qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS)
-check-qint: check-qint.o qint.o qemu-malloc.o $(trace-obj-y)
-check-qstring: check-qstring.o qstring.o qemu-malloc.o $(trace-obj-y)
-check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o $(trace-obj-y)
-check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o $(trace-obj-y)
-check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o $(trace-obj-y)
-check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o qemu-malloc.o $(trace-obj-y)
+CHECK_PROG_DEPS = qemu-malloc.o $(oslib-obj-y) $(trace-obj-y)
+
+check-qint: check-qint.o qint.o $(CHECK_PROG_DEPS)
+check-qstring: check-qstring.o qstring.o $(CHECK_PROG_DEPS)
+check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(CHECK_PROG_DEPS)
+check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
+check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
+check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o $(CHECK_PROG_DEPS)
clean:
# avoid old build problems by removing potentially incorrect old files
commit 33656af70230d5ccebe29e2f3bee38afe17db9b2
Author: Marcelo Tosatti <mtosatti at redhat.com>
Date: Mon Nov 8 17:02:56 2010 -0200
block migration: do not submit multiple AIOs for same sector
Block migration can submit multiple AIO reads for the same sector/chunk, but
completion of such reads can happen out of order:
migration guest
- get_dirty(N)
- aio_read(N)
- clear_dirty(N)
write(N)
set_dirty(N)
- get_dirty(N)
- aio_read(N)
If the first aio_read completes after the second, stale data will be
migrated to the destination.
Fix by not allowing multiple AIOs inflight for the same sector.
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/block-migration.c b/block-migration.c
index 0bfdb73..3e66f49 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -49,12 +49,14 @@ typedef struct BlkMigDevState {
int64_t total_sectors;
int64_t dirty;
QSIMPLEQ_ENTRY(BlkMigDevState) entry;
+ unsigned long *aio_bitmap;
} BlkMigDevState;
typedef struct BlkMigBlock {
uint8_t *buf;
BlkMigDevState *bmds;
int64_t sector;
+ int nr_sectors;
struct iovec iov;
QEMUIOVector qiov;
BlockDriverAIOCB *aiocb;
@@ -140,6 +142,57 @@ static inline long double compute_read_bwidth(void)
return (block_mig_state.reads * BLOCK_SIZE)/ block_mig_state.total_time;
}
+static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
+{
+ int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
+
+ if (bmds->aio_bitmap &&
+ (sector << BDRV_SECTOR_BITS) < bdrv_getlength(bmds->bs)) {
+ return !!(bmds->aio_bitmap[chunk / (sizeof(unsigned long) * 8)] &
+ (1UL << (chunk % (sizeof(unsigned long) * 8))));
+ } else {
+ return 0;
+ }
+}
+
+static void bmds_set_aio_inflight(BlkMigDevState *bmds, int64_t sector_num,
+ int nb_sectors, int set)
+{
+ int64_t start, end;
+ unsigned long val, idx, bit;
+
+ start = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK;
+ end = (sector_num + nb_sectors - 1) / BDRV_SECTORS_PER_DIRTY_CHUNK;
+
+ for (; start <= end; start++) {
+ idx = start / (sizeof(unsigned long) * 8);
+ bit = start % (sizeof(unsigned long) * 8);
+ val = bmds->aio_bitmap[idx];
+ if (set) {
+ if (!(val & (1UL << bit))) {
+ val |= 1UL << bit;
+ }
+ } else {
+ if (val & (1UL << bit)) {
+ val &= ~(1UL << bit);
+ }
+ }
+ bmds->aio_bitmap[idx] = val;
+ }
+}
+
+static void alloc_aio_bitmap(BlkMigDevState *bmds)
+{
+ BlockDriverState *bs = bmds->bs;
+ int64_t bitmap_size;
+
+ bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) +
+ BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
+ bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;
+
+ bmds->aio_bitmap = qemu_mallocz(bitmap_size);
+}
+
static void blk_mig_read_cb(void *opaque, int ret)
{
BlkMigBlock *blk = opaque;
@@ -151,6 +204,7 @@ static void blk_mig_read_cb(void *opaque, int ret)
add_avg_read_time(blk->time);
QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
+ bmds_set_aio_inflight(blk->bmds, blk->sector, blk->nr_sectors, 0);
block_mig_state.submitted--;
block_mig_state.read_done++;
@@ -194,6 +248,7 @@ static int mig_save_device_bulk(Monitor *mon, QEMUFile *f,
blk->buf = qemu_malloc(BLOCK_SIZE);
blk->bmds = bmds;
blk->sector = cur_sector;
+ blk->nr_sectors = nr_sectors;
blk->iov.iov_base = blk->buf;
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
@@ -248,6 +303,7 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
bmds->total_sectors = sectors;
bmds->completed_sectors = 0;
bmds->shared_base = block_mig_state.shared_base;
+ alloc_aio_bitmap(bmds);
block_mig_state.total_sector_sum += sectors;
@@ -329,6 +385,8 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
int nr_sectors;
for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) {
+ if (bmds_aio_inflight(bmds, sector))
+ qemu_aio_flush();
if (bdrv_get_dirty(bmds->bs, sector)) {
if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
@@ -340,6 +398,7 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
blk->buf = qemu_malloc(BLOCK_SIZE);
blk->bmds = bmds;
blk->sector = sector;
+ blk->nr_sectors = nr_sectors;
if (is_async) {
blk->iov.iov_base = blk->buf;
@@ -354,6 +413,7 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
goto error;
}
block_mig_state.submitted++;
+ bmds_set_aio_inflight(bmds, sector, nr_sectors, 1);
} else {
if (bdrv_read(bmds->bs, sector, blk->buf,
nr_sectors) < 0) {
@@ -474,6 +534,7 @@ static void blk_mig_cleanup(Monitor *mon)
while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
+ qemu_free(bmds->aio_bitmap);
qemu_free(bmds);
}
commit 4dcafbb1eba2ee201ec86027982659b669f99c70
Author: Marcelo Tosatti <mtosatti at redhat.com>
Date: Mon Nov 8 17:02:55 2010 -0200
block: set sector dirty on AIO write completion
Sectors are marked dirty in the bitmap on AIO submission. This is wrong
since data has not reached storage.
Set a given sector as dirty in the dirty bitmap on AIO completion, so that
reading a sector marked as dirty is guaranteed to return uptodate data.
Reviewed-by: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/block.c b/block.c
index 53a10de..63effd8 100644
--- a/block.c
+++ b/block.c
@@ -2031,12 +2031,49 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
return ret;
}
+typedef struct BlockCompleteData {
+ BlockDriverCompletionFunc *cb;
+ void *opaque;
+ BlockDriverState *bs;
+ int64_t sector_num;
+ int nb_sectors;
+} BlockCompleteData;
+
+static void block_complete_cb(void *opaque, int ret)
+{
+ BlockCompleteData *b = opaque;
+
+ if (b->bs->dirty_bitmap) {
+ set_dirty_bitmap(b->bs, b->sector_num, b->nb_sectors, 1);
+ }
+ b->cb(b->opaque, ret);
+ qemu_free(b);
+}
+
+static BlockCompleteData *blk_dirty_cb_alloc(BlockDriverState *bs,
+ int64_t sector_num,
+ int nb_sectors,
+ BlockDriverCompletionFunc *cb,
+ void *opaque)
+{
+ BlockCompleteData *blkdata = qemu_mallocz(sizeof(BlockCompleteData));
+
+ blkdata->bs = bs;
+ blkdata->cb = cb;
+ blkdata->opaque = opaque;
+ blkdata->sector_num = sector_num;
+ blkdata->nb_sectors = nb_sectors;
+
+ return blkdata;
+}
+
BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
BlockDriver *drv = bs->drv;
BlockDriverAIOCB *ret;
+ BlockCompleteData *blk_cb_data;
trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
@@ -2048,7 +2085,10 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
return NULL;
if (bs->dirty_bitmap) {
- set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+ blk_cb_data = blk_dirty_cb_alloc(bs, sector_num, nb_sectors, cb,
+ opaque);
+ cb = &block_complete_cb;
+ opaque = blk_cb_data;
}
ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
commit 6d59fec11eeff8a784dc4991c8fe4f8538510475
Author: Marcelo Tosatti <mtosatti at redhat.com>
Date: Mon Nov 8 17:02:54 2010 -0200
block: fix shift in dirty bitmap calculation
Otherwise upper 32 bits of bitmap entries are not correctly calculated.
Reviewed-by: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/block.c b/block.c
index 6b505fb..53a10de 100644
--- a/block.c
+++ b/block.c
@@ -930,14 +930,14 @@ static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
bit = start % (sizeof(unsigned long) * 8);
val = bs->dirty_bitmap[idx];
if (dirty) {
- if (!(val & (1 << bit))) {
+ if (!(val & (1UL << bit))) {
bs->dirty_count++;
- val |= 1 << bit;
+ val |= 1UL << bit;
}
} else {
- if (val & (1 << bit)) {
+ if (val & (1UL << bit)) {
bs->dirty_count--;
- val &= ~(1 << bit);
+ val &= ~(1UL << bit);
}
}
bs->dirty_bitmap[idx] = val;
@@ -2685,8 +2685,8 @@ int bdrv_get_dirty(BlockDriverState *bs, int64_t sector)
if (bs->dirty_bitmap &&
(sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) {
- return bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] &
- (1 << (chunk % (sizeof(unsigned long) * 8)));
+ return !!(bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] &
+ (1UL << (chunk % (sizeof(unsigned long) * 8))));
} else {
return 0;
}
commit c276b17da65b7ff01627722a1abf2b7a684c8fd8
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Fri Nov 12 13:20:25 2010 +0000
Add support for generating a systemtap tapset static probes
This introduces generation of a qemu.stp/qemu-system-XXX.stp
files which provides tapsets with friendly names for static
probes & their arguments. Instead of
probe process("qemu").mark("qemu_malloc") {
printf("Malloc %d %p\n", $arg1, $arg2);
}
It is now possible todo
probe qemu.system.i386.qemu_malloc {
printf("Malloc %d %p\n", size, ptr);
}
There is one tapset defined per target arch, for both
user and system emulators.
* Makefile.target: Generate stp files for each target
* tracetool: Support for generating systemtap tapsets
* configure: Check for whether systemtap is available
with the DTrace backend
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/Makefile.target b/Makefile.target
index 31c968c..2800f47 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -41,7 +41,27 @@ kvm.o kvm-all.o vhost.o vhost_net.o: QEMU_CFLAGS+=$(KVM_CFLAGS)
config-target.h: config-target.h-timestamp
config-target.h-timestamp: config-target.mak
-all: $(PROGS)
+ifdef CONFIG_SYSTEMTAP_TRACE
+stap: $(QEMU_PROG).stp
+
+ifdef CONFIG_USER_ONLY
+TARGET_TYPE=user
+else
+TARGET_TYPE=system
+endif
+
+$(QEMU_PROG).stp:
+ $(call quiet-command,sh $(SRC_PATH)/tracetool \
+ --$(TRACE_BACKEND) \
+ --binary $(bindir)/$(QEMU_PROG) \
+ --target-arch $(TARGET_ARCH) \
+ --target-type $(TARGET_TYPE) \
+ --stap < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).stp")
+else
+stap:
+endif
+
+all: $(PROGS) stap
# Dummy command so that make thinks it has done something
@true
@@ -341,6 +361,9 @@ clean:
rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
rm -f *.d */*.d tcg/*.o ide/*.o
rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c
+ifdef CONFIG_SYSTEMTAP_TRACE
+ rm -f *.stp
+endif
install: all
ifneq ($(PROGS),)
@@ -349,6 +372,10 @@ ifneq ($(STRIP),)
$(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS))
endif
endif
+ifdef CONFIG_SYSTEMTAP_TRACE
+ $(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset"
+ $(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(datadir)/../systemtap/tapset"
+endif
# Include automatically generated dependency files
-include $(wildcard *.d */*.d)
diff --git a/configure b/configure
index f8dad3e..2917874 100755
--- a/configure
+++ b/configure
@@ -2203,6 +2203,10 @@ if test "$trace_backend" = "dtrace"; then
echo
exit 1
fi
+ trace_backend_stap="no"
+ if has 'stap' ; then
+ trace_backend_stap="yes"
+ fi
fi
##########################################
@@ -2645,6 +2649,9 @@ fi
if test "$trace_backend" = "simple"; then
trace_file="\"$trace_file-%u\""
fi
+if test "$trace_backend" = "dtrace" -a "$trace_backend_stap" = "yes" ; then
+ echo "CONFIG_SYSTEMTAP_TRACE=y" >> $config_host_mak
+fi
echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
echo "TOOLS=$tools" >> $config_host_mak
diff --git a/tracetool b/tracetool
index 1ade103..fce491c 100755
--- a/tracetool
+++ b/tracetool
@@ -23,9 +23,16 @@ Backends:
--dtrace DTrace/SystemTAP backend
Output formats:
- -h Generate .h file
- -c Generate .c file
- -d Generate .d file (DTrace only)
+ -h Generate .h file
+ -c Generate .c file
+ -d Generate .d file (DTrace only)
+ --stap Generate .stp file (DTrace with SystemTAP only)
+
+Options:
+ --binary [path] Full path to QEMU binary
+ --target-arch [arch] QEMU emulator target arch
+ --target-type [type] QEMU emulator target type ('system' or 'user')
+
EOF
exit 1
}
@@ -396,6 +403,51 @@ linetod_end_dtrace()
EOF
}
+linetostap_begin_dtrace()
+{
+ return
+}
+
+linetostap_dtrace()
+{
+ local i arg name args arglist state
+ name=$(get_name "$1")
+ args=$(get_args "$1")
+ arglist=$(get_argnames "$1", "")
+ state=$(get_state "$1")
+ if [ "$state" = "0" ] ; then
+ name=${name##disable }
+ fi
+
+ # Define prototype for probe arguments
+ cat <<EOF
+probe qemu.$targettype.$targetarch.$name = process("$binary").mark("$name")
+{
+EOF
+
+ i=1
+ for arg in $arglist
+ do
+ # 'limit' is a reserved keyword
+ if [ "$arg" = "limit" ]; then
+ arg="_limit"
+ fi
+ cat <<EOF
+ $arg = \$arg$i;
+EOF
+ i="$((i+1))"
+ done
+
+ cat <<EOF
+}
+EOF
+}
+
+linetostap_end_dtrace()
+{
+ return
+}
+
# Process stdin by calling begin, line, and end functions for the backend
convert()
{
@@ -461,19 +513,61 @@ tracetod()
convert d
}
-# Choose backend
-case "$1" in
-"--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
-*) usage ;;
-esac
-shift
-
-case "$1" in
-"-h") tracetoh ;;
-"-c") tracetoc ;;
-"-d") tracetod ;;
-"--check-backend") exit 0 ;; # used by ./configure to test for backend
-*) usage ;;
-esac
+tracetostap()
+{
+ if [ $backend != "dtrace" ]; then
+ echo "SystemTAP tapset generator not applicable to $backend backend"
+ exit 1
+ fi
+ if [ -z "$binary" ]; then
+ echo "--binary is required for SystemTAP tapset generator"
+ exit 1
+ fi
+ if [ -z "$targettype" ]; then
+ echo "--target-type is required for SystemTAP tapset generator"
+ exit 1
+ fi
+ if [ -z "$targetarch" ]; then
+ echo "--target-arch is required for SystemTAP tapset generator"
+ exit 1
+ fi
+ echo "/* This file is autogenerated by tracetool, do not edit. */"
+ convert stap
+}
+
+
+backend=
+output=
+binary=
+targettype=
+targetarch=
+
+
+until [ -z "$1" ]
+do
+ case "$1" in
+ "--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
+
+ "--binary") shift ; binary="$1" ;;
+ "--target-arch") shift ; targetarch="$1" ;;
+ "--target-type") shift ; targettype="$1" ;;
+
+ "-h" | "-c" | "-d") output="${1#-}" ;;
+ "--stap") output="${1#--}" ;;
+
+ "--check-backend") exit 0 ;; # used by ./configure to test for backend
+
+ *)
+ usage;;
+ esac
+ shift
+done
+
+if [ "$backend" = "" -o "$output" = "" ]; then
+ usage
+fi
+
+gen="traceto$output"
+"$gen"
exit 0
commit b3d08c029dd78ded5e35b74eaaa3d361821f83a7
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Fri Nov 12 13:20:24 2010 +0000
Add a DTrace tracing backend targetted for SystemTAP compatability
This introduces a new tracing backend that targets the SystemTAP
implementation of DTrace userspace tracing. The core functionality
should be applicable and standard across any DTrace implementation
on Solaris, OS-X, *BSD, but the Makefile rules will likely need
some small additional changes to cope with OS specific build
requirements.
This backend builds a little differently from the other tracing
backends. Specifically there is no 'trace.c' file, because the
'dtrace' command line tool generates a '.o' file directly from
the dtrace probe definition file. The probe definition is usually
named with a '.d' extension but QEMU uses '.d' files for its
external makefile dependancy tracking, so this uses '.dtrace' as
the extension for the probe definition file.
The 'tracetool' program gains the ability to generate a trace.h
file for DTrace, and also to generate the trace.d file containing
the dtrace probe definition.
Example usage of a dtrace probe in systemtap looks like:
probe process("qemu").mark("qemu_malloc") {
printf("Malloc %d %p\n", $arg1, $arg2);
}
* .gitignore: Ignore trace-dtrace.*
* Makefile: Extra rules for generating DTrace files
* Makefile.obj: Don't build trace.o for DTrace, use
trace-dtrace.o generated by 'dtrace' instead
* tracetool: Support for generating DTrace data files
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/.gitignore b/.gitignore
index a43e4d1..3efb4ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,8 @@ config-host.*
config-target.*
trace.h
trace.c
+trace-dtrace.h
+trace-dtrace.dtrace
*-timestamp
*-softmmu
*-darwin-user
diff --git a/Makefile b/Makefile
index 6896319..747e47c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,9 @@
# Makefile for QEMU.
GENERATED_HEADERS = config-host.h trace.h qemu-options.def
+ifeq ($(TRACE_BACKEND),dtrace)
+GENERATED_HEADERS += trace-dtrace.h
+endif
ifneq ($(wildcard config-host.mak),)
# Put the all: rule here so that config-host.mak can contain dependencies.
@@ -108,7 +111,11 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
+ifeq ($(TRACE_BACKEND),dtrace)
+trace.h: trace.h-timestamp trace-dtrace.h
+else
trace.h: trace.h-timestamp
+endif
trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h")
@cmp -s $@ trace.h || cp $@ trace.h
@@ -120,6 +127,20 @@ trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak
trace.o: trace.c $(GENERATED_HEADERS)
+trace-dtrace.h: trace-dtrace.dtrace
+ $(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h")
+
+# Normal practice is to name DTrace probe file with a '.d' extension
+# but that gets picked up by QEMU's Makefile as an external dependancy
+# rule file. So we use '.dtrace' instead
+trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
+trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
+ $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace")
+ @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
+
+trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
+ $(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o")
+
simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
version.o: $(SRC_PATH)/version.rc config-host.mak
@@ -157,6 +178,8 @@ clean:
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
rm -f qemu-img-cmds.h
rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
+ rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
+ rm -f trace-dtrace.h trace-dtrace.h-timestamp
$(MAKE) -C tests clean
for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
diff --git a/Makefile.objs b/Makefile.objs
index 15569af..23b17ce 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -286,11 +286,15 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
######################################################################
# trace
+ifeq ($(TRACE_BACKEND),dtrace)
+trace-obj-y = trace-dtrace.o
+else
trace-obj-y = trace.o
ifeq ($(TRACE_BACKEND),simple)
trace-obj-y += simpletrace.o
user-obj-y += qemu-timer-common.o
endif
+endif
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/configure b/configure
index 7025d2b..f8dad3e 100755
--- a/configure
+++ b/configure
@@ -929,7 +929,7 @@ echo " --enable-docs enable documentation build"
echo " --disable-docs disable documentation build"
echo " --disable-vhost-net disable vhost-net acceleration support"
echo " --enable-vhost-net enable vhost-net acceleration support"
-echo " --trace-backend=B Trace backend nop simple ust"
+echo " --trace-backend=B Trace backend nop simple ust dtrace"
echo " --trace-file=NAME Full PATH,NAME of file to store traces"
echo " Default:trace-<pid>"
echo " --disable-spice disable spice"
@@ -2193,6 +2193,18 @@ EOF
exit 1
fi
fi
+
+##########################################
+# For 'dtrace' backend, test if 'dtrace' command is present
+if test "$trace_backend" = "dtrace"; then
+ if ! has 'dtrace' ; then
+ echo
+ echo "Error: dtrace command is not found in PATH $PATH"
+ echo
+ exit 1
+ fi
+fi
+
##########################################
# End of CC checks
# After here, no more $cc or $ld runs
diff --git a/tracetool b/tracetool
index 7010858..1ade103 100755
--- a/tracetool
+++ b/tracetool
@@ -20,10 +20,12 @@ Backends:
--nop Tracing disabled
--simple Simple built-in backend
--ust LTTng User Space Tracing backend
+ --dtrace DTrace/SystemTAP backend
Output formats:
-h Generate .h file
-c Generate .c file
+ -d Generate .d file (DTrace only)
EOF
exit 1
}
@@ -46,8 +48,9 @@ get_args()
# Get the argument name list of a trace event
get_argnames()
{
- local nfields field name
+ local nfields field name sep
nfields=0
+ sep="$2"
for field in $(get_args "$1"); do
nfields=$((nfields + 1))
@@ -58,7 +61,7 @@ get_argnames()
name=${field%,}
test "$field" = "$name" && continue
- printf "%s" "$name, "
+ printf "%s%s " $name $sep
done
# Last argument name
@@ -73,7 +76,7 @@ get_argc()
{
local name argc
argc=0
- for name in $(get_argnames "$1"); do
+ for name in $(get_argnames "$1", ","); do
argc=$((argc + 1))
done
echo $argc
@@ -154,7 +157,7 @@ EOF
cast_args_to_uint64_t()
{
local arg
- for arg in $(get_argnames "$1"); do
+ for arg in $(get_argnames "$1", ","); do
printf "%s" "(uint64_t)(uintptr_t)$arg"
done
}
@@ -247,7 +250,7 @@ linetoh_ust()
local name args argnames
name=$(get_name "$1")
args=$(get_args "$1")
- argnames=$(get_argnames "$1")
+ argnames=$(get_argnames "$1", ",")
cat <<EOF
DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
@@ -274,7 +277,7 @@ linetoc_ust()
local name args argnames fmt
name=$(get_name "$1")
args=$(get_args "$1")
- argnames=$(get_argnames "$1")
+ argnames=$(get_argnames "$1", ",")
fmt=$(get_fmt "$1")
cat <<EOF
@@ -306,6 +309,93 @@ EOF
echo "}"
}
+linetoh_begin_dtrace()
+{
+ cat <<EOF
+#include "trace-dtrace.h"
+EOF
+}
+
+linetoh_dtrace()
+{
+ local name args argnames state nameupper
+ name=$(get_name "$1")
+ args=$(get_args "$1")
+ argnames=$(get_argnames "$1", ",")
+ state=$(get_state "$1")
+ if [ "$state" = "0" ] ; then
+ name=${name##disable }
+ fi
+
+ nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
+
+ # Define an empty function for the trace event
+ cat <<EOF
+static inline void trace_$name($args) {
+ if (QEMU_${nameupper}_ENABLED()) {
+ QEMU_${nameupper}($argnames);
+ }
+}
+EOF
+}
+
+linetoh_end_dtrace()
+{
+ return
+}
+
+linetoc_begin_dtrace()
+{
+ return
+}
+
+linetoc_dtrace()
+{
+ # No need for function definitions in dtrace backend
+ return
+}
+
+linetoc_end_dtrace()
+{
+ return
+}
+
+linetod_begin_dtrace()
+{
+ cat <<EOF
+provider qemu {
+EOF
+}
+
+linetod_dtrace()
+{
+ local name args state
+ name=$(get_name "$1")
+ args=$(get_args "$1")
+ state=$(get_state "$1")
+ if [ "$state" = "0" ] ; then
+ name=${name##disable }
+ fi
+
+ # DTrace provider syntax expects foo() for empty
+ # params, not foo(void)
+ if [ "$args" = "void" ]; then
+ args=""
+ fi
+
+ # Define prototype for probe arguments
+ cat <<EOF
+ probe $name($args);
+EOF
+}
+
+linetod_end_dtrace()
+{
+ cat <<EOF
+};
+EOF
+}
+
# Process stdin by calling begin, line, and end functions for the backend
convert()
{
@@ -324,9 +414,10 @@ convert()
disable=${str%%disable *}
echo
if test -z "$disable"; then
- # Pass the disabled state as an arg to lineto$1_simple().
- # For all other cases, call lineto$1_nop()
- if [ $backend = "simple" ]; then
+ # Pass the disabled state as an arg for the simple
+ # or DTrace backends which handle it dynamically.
+ # For all other backends, call lineto$1_nop()
+ if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
"$process_line" "$str"
else
"lineto$1_nop" "${str##disable }"
@@ -360,9 +451,19 @@ tracetoc()
convert c
}
+tracetod()
+{
+ if [ $backend != "dtrace" ]; then
+ echo "DTrace probe generator not applicable to $backend backend"
+ exit 1
+ fi
+ echo "/* This file is autogenerated by tracetool, do not edit. */"
+ convert d
+}
+
# Choose backend
case "$1" in
-"--nop" | "--simple" | "--ust") backend="${1#--}" ;;
+"--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
*) usage ;;
esac
shift
@@ -370,6 +471,7 @@ shift
case "$1" in
"-h") tracetoh ;;
"-c") tracetoc ;;
+"-d") tracetod ;;
"--check-backend") exit 0 ;; # used by ./configure to test for backend
*) usage ;;
esac
commit 06da6e44d725117be404c3f342ef539099043fe4
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Nov 17 18:06:06 2010 -0600
Revert "Add a DTrace tracing backend targetted for SystemTAP compatability"
This reverts commit 4addb1127f6327c7ebcbd150a6b589e7677adc92.
diff --git a/.gitignore b/.gitignore
index 3efb4ec..a43e4d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,8 +4,6 @@ config-host.*
config-target.*
trace.h
trace.c
-trace-dtrace.h
-trace-dtrace.dtrace
*-timestamp
*-softmmu
*-darwin-user
diff --git a/Makefile b/Makefile
index 747e47c..6896319 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,6 @@
# Makefile for QEMU.
GENERATED_HEADERS = config-host.h trace.h qemu-options.def
-ifeq ($(TRACE_BACKEND),dtrace)
-GENERATED_HEADERS += trace-dtrace.h
-endif
ifneq ($(wildcard config-host.mak),)
# Put the all: rule here so that config-host.mak can contain dependencies.
@@ -111,11 +108,7 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
-ifeq ($(TRACE_BACKEND),dtrace)
-trace.h: trace.h-timestamp trace-dtrace.h
-else
trace.h: trace.h-timestamp
-endif
trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h")
@cmp -s $@ trace.h || cp $@ trace.h
@@ -127,20 +120,6 @@ trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak
trace.o: trace.c $(GENERATED_HEADERS)
-trace-dtrace.h: trace-dtrace.dtrace
- $(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h")
-
-# Normal practice is to name DTrace probe file with a '.d' extension
-# but that gets picked up by QEMU's Makefile as an external dependancy
-# rule file. So we use '.dtrace' instead
-trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
-trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
- $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace")
- @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
-
-trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
- $(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o")
-
simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
version.o: $(SRC_PATH)/version.rc config-host.mak
@@ -178,8 +157,6 @@ clean:
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
rm -f qemu-img-cmds.h
rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
- rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
- rm -f trace-dtrace.h trace-dtrace.h-timestamp
$(MAKE) -C tests clean
for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
diff --git a/Makefile.objs b/Makefile.objs
index 23b17ce..15569af 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -286,15 +286,11 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
######################################################################
# trace
-ifeq ($(TRACE_BACKEND),dtrace)
-trace-obj-y = trace-dtrace.o
-else
trace-obj-y = trace.o
ifeq ($(TRACE_BACKEND),simple)
trace-obj-y += simpletrace.o
user-obj-y += qemu-timer-common.o
endif
-endif
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/configure b/configure
index f8dad3e..7025d2b 100755
--- a/configure
+++ b/configure
@@ -929,7 +929,7 @@ echo " --enable-docs enable documentation build"
echo " --disable-docs disable documentation build"
echo " --disable-vhost-net disable vhost-net acceleration support"
echo " --enable-vhost-net enable vhost-net acceleration support"
-echo " --trace-backend=B Trace backend nop simple ust dtrace"
+echo " --trace-backend=B Trace backend nop simple ust"
echo " --trace-file=NAME Full PATH,NAME of file to store traces"
echo " Default:trace-<pid>"
echo " --disable-spice disable spice"
@@ -2193,18 +2193,6 @@ EOF
exit 1
fi
fi
-
-##########################################
-# For 'dtrace' backend, test if 'dtrace' command is present
-if test "$trace_backend" = "dtrace"; then
- if ! has 'dtrace' ; then
- echo
- echo "Error: dtrace command is not found in PATH $PATH"
- echo
- exit 1
- fi
-fi
-
##########################################
# End of CC checks
# After here, no more $cc or $ld runs
diff --git a/tracetool b/tracetool
index 5b6636a..7010858 100755
--- a/tracetool
+++ b/tracetool
@@ -20,12 +20,10 @@ Backends:
--nop Tracing disabled
--simple Simple built-in backend
--ust LTTng User Space Tracing backend
- --dtrace DTrace/SystemTAP backend
Output formats:
-h Generate .h file
-c Generate .c file
- -d Generate .d file (DTrace only)
EOF
exit 1
}
@@ -48,9 +46,8 @@ get_args()
# Get the argument name list of a trace event
get_argnames()
{
- local nfields field name sep
+ local nfields field name
nfields=0
- sep="$2"
for field in $(get_args "$1"); do
nfields=$((nfields + 1))
@@ -61,7 +58,7 @@ get_argnames()
name=${field%,}
test "$field" = "$name" && continue
- printf "%s%s " $name $sep
+ printf "%s" "$name, "
done
# Last argument name
@@ -76,7 +73,7 @@ get_argc()
{
local name argc
argc=0
- for name in $(get_argnames "$1", ","); do
+ for name in $(get_argnames "$1"); do
argc=$((argc + 1))
done
echo $argc
@@ -157,7 +154,7 @@ EOF
cast_args_to_uint64_t()
{
local arg
- for arg in $(get_argnames "$1", ","); do
+ for arg in $(get_argnames "$1"); do
printf "%s" "(uint64_t)(uintptr_t)$arg"
done
}
@@ -250,7 +247,7 @@ linetoh_ust()
local name args argnames
name=$(get_name "$1")
args=$(get_args "$1")
- argnames=$(get_argnames "$1", ",")
+ argnames=$(get_argnames "$1")
cat <<EOF
DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
@@ -277,7 +274,7 @@ linetoc_ust()
local name args argnames fmt
name=$(get_name "$1")
args=$(get_args "$1")
- argnames=$(get_argnames "$1", ",")
+ argnames=$(get_argnames "$1")
fmt=$(get_fmt "$1")
cat <<EOF
@@ -309,87 +306,6 @@ EOF
echo "}"
}
-linetoh_begin_dtrace()
-{
- cat <<EOF
-#include "trace-dtrace.h"
-EOF
-}
-
-linetoh_dtrace()
-{
- local name args argnames state nameupper
- name=$(get_name "$1")
- args=$(get_args "$1")
- argnames=$(get_argnames "$1", ",")
- state=$(get_state "$1")
- if [ "$state" = "0" ] ; then
- name=${name##disable }
- fi
-
- nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
-
- # Define an empty function for the trace event
- cat <<EOF
-static inline void trace_$name($args) {
- if (QEMU_${nameupper}_ENABLED()) {
- QEMU_${nameupper}($argnames);
- }
-}
-EOF
-}
-
-linetoh_end_dtrace()
-{
- return
-}
-
-linetoc_begin_dtrace()
-{
- return
-}
-
-linetoc_dtrace()
-{
- # No need for function definitions in dtrace backend
- return
-}
-
-linetoc_end_dtrace()
-{
- return
-}
-
-linetod_begin_dtrace()
-{
- cat <<EOF
-provider qemu {
-EOF
-}
-
-linetod_dtrace()
-{
- local name args state
- name=$(get_name "$1")
- args=$(get_args "$1")
- state=$(get_state "$1")
- if [ "$state" = "0" ] ; then
- name=${name##disable }
- fi
-
- # Define prototype for probe arguments
- cat <<EOF
- probe $name($args);
-EOF
-}
-
-linetod_end_dtrace()
-{
- cat <<EOF
-};
-EOF
-}
-
# Process stdin by calling begin, line, and end functions for the backend
convert()
{
@@ -408,10 +324,9 @@ convert()
disable=${str%%disable *}
echo
if test -z "$disable"; then
- # Pass the disabled state as an arg for the simple
- # or DTrace backends which handle it dynamically.
- # For all other backends, call lineto$1_nop()
- if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
+ # Pass the disabled state as an arg to lineto$1_simple().
+ # For all other cases, call lineto$1_nop()
+ if [ $backend = "simple" ]; then
"$process_line" "$str"
else
"lineto$1_nop" "${str##disable }"
@@ -445,19 +360,9 @@ tracetoc()
convert c
}
-tracetod()
-{
- if [ $backend != "dtrace" ]; then
- echo "DTrace probe generator not applicable to $backend backend"
- exit 1
- fi
- echo "/* This file is autogenerated by tracetool, do not edit. */"
- convert d
-}
-
# Choose backend
case "$1" in
-"--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
+"--nop" | "--simple" | "--ust") backend="${1#--}" ;;
*) usage ;;
esac
shift
@@ -465,7 +370,6 @@ shift
case "$1" in
"-h") tracetoh ;;
"-c") tracetoc ;;
-"-d") tracetod ;;
"--check-backend") exit 0 ;; # used by ./configure to test for backend
*) usage ;;
esac
commit 371c338ecae44bb28cc19138484256b1df831e99
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Nov 17 18:05:58 2010 -0600
Revert "Add support for generating a systemtap tapset static probes"
This reverts commit 2834c3e0140c3b0ed4422909dfa0607b7213d95d.
Conflicts:
Makefile.target
diff --git a/Makefile.target b/Makefile.target
index 652c7d2..31c968c 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -41,18 +41,7 @@ kvm.o kvm-all.o vhost.o vhost_net.o: QEMU_CFLAGS+=$(KVM_CFLAGS)
config-target.h: config-target.h-timestamp
config-target.h-timestamp: config-target.mak
-ifdef CONFIG_SYSTEMTAP_TRACE
-STPFILES+=$(QEMU_PROG).stp
-
-$(QEMU_PROG).stp:
- $(call quiet-command,sh $(SRC_PATH)/tracetool \
- --$(TRACE_BACKEND) \
- --bindir $(bindir) \
- --target $(TARGET_ARCH) \
- -s < $(SRC_PATH)/trace-events > $@," GEN $@")
-endif
-
-all: $(PROGS) $(STPFILES)
+all: $(PROGS)
# Dummy command so that make thinks it has done something
@true
@@ -360,10 +349,6 @@ ifneq ($(STRIP),)
$(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS))
endif
endif
-ifdef CONFIG_SYSTEMTAP_TRACE
- $(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset"
- $(INSTALL_DATA) $(STPFILES) "$(DESTDIR)$(datadir)/../systemtap/tapset"
-endif
# Include automatically generated dependency files
-include $(wildcard *.d */*.d)
diff --git a/configure b/configure
index e560f87..f8dad3e 100755
--- a/configure
+++ b/configure
@@ -2192,10 +2192,6 @@ EOF
echo
exit 1
fi
- trace_backend_stap="no"
- if has 'stap' ; then
- trace_backend_stap="yes"
- fi
fi
##########################################
@@ -2649,9 +2645,6 @@ fi
if test "$trace_backend" = "simple"; then
trace_file="\"$trace_file-%u\""
fi
-if test "$trace_backend" = "dtrace" -a "$trace_backend_stap" = "yes" ; then
- echo "CONFIG_SYSTEMTAP_TRACE=y" >> $config_host_mak
-fi
echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
echo "TOOLS=$tools" >> $config_host_mak
diff --git a/tracetool b/tracetool
index d797ab7..5b6636a 100755
--- a/tracetool
+++ b/tracetool
@@ -26,12 +26,6 @@ Output formats:
-h Generate .h file
-c Generate .c file
-d Generate .d file (DTrace only)
- -s Generate .stp file (DTrace with SystemTAP only)
-
-Options:
- --bindir [bindir] QEMU binary install location
- --target [arch] QEMU target architecture
-
EOF
exit 1
}
@@ -396,54 +390,6 @@ linetod_end_dtrace()
EOF
}
-linetos_begin_dtrace()
-{
- return
-}
-
-linetos_dtrace()
-{
- local name args arglist state
- name=$(get_name "$1")
- args=$(get_args "$1")
- arglist=$(get_argnames "$1", "")
- state=$(get_state "$1")
- if [ "$state" = "0" ] ; then
- name=${name##disable }
- fi
-
- if [ "$target" = "i386" ]
- then
- binary="qemu"
- else
- binary="qemu-system-$target"
- fi
-
- # Define prototype for probe arguments
- cat <<EOF
-probe qemu.system.$target.$name = process("$bindir/$binary").mark("$name")
-{
-EOF
-
- i=1
- for arg in $arglist
- do
- cat <<EOF
- $arg = \$arg$i;
-EOF
- i="$((i+1))"
- done
-
- cat <<EOF
-}
-EOF
-}
-
-linetos_end_dtrace()
-{
- return
-}
-
# Process stdin by calling begin, line, and end functions for the backend
convert()
{
@@ -509,24 +455,6 @@ tracetod()
convert d
}
-tracetos()
-{
- if [ $backend != "dtrace" ]; then
- echo "SystemTAP tapset generator not applicable to $backend backend"
- exit 1
- fi
- if [ -z "$target" ]; then
- echo "--target is required for SystemTAP tapset generator"
- exit 1
- fi
- if [ -z "$bindir" ]; then
- echo "--bindir is required for SystemTAP tapset generator"
- exit 1
- fi
- echo "/* This file is autogenerated by tracetool, do not edit. */"
- convert s
-}
-
# Choose backend
case "$1" in
"--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
@@ -534,30 +462,10 @@ case "$1" in
esac
shift
-bindir=
-case "$1" in
- "--bindir")
- bindir=$2
- shift
- shift
- ;;
-esac
-
-target=
-case "$1" in
- "--target")
- target=$2
- shift
- shift
- ;;
-esac
-
-
case "$1" in
"-h") tracetoh ;;
"-c") tracetoc ;;
"-d") tracetod ;;
-"-s") tracetos ;;
"--check-backend") exit 0 ;; # used by ./configure to test for backend
*) usage ;;
esac
commit 39deb1e496de81957167daebf5cf5d1fbd5e47c2
Author: malc <av1474 at comtv.ru>
Date: Thu Nov 18 14:30:12 2010 +0300
audio: Only use audio timer when necessary
Originally proposed by Gerd Hoffmann.
Signed-off-by: malc <av1474 at comtv.ru>
Acked-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/audio/audio.c b/audio/audio.c
index ade342e..1707446 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1096,15 +1096,6 @@ static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
/*
* Timer
*/
-static void audio_timer (void *opaque)
-{
- AudioState *s = opaque;
-
- audio_run ("timer");
- qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
-}
-
-
static int audio_is_timer_needed (void)
{
HWVoiceIn *hwi = NULL;
@@ -1119,10 +1110,8 @@ static int audio_is_timer_needed (void)
return 0;
}
-static void audio_reset_timer (void)
+static void audio_reset_timer (AudioState *s)
{
- AudioState *s = &glob_audio_state;
-
if (audio_is_timer_needed ()) {
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
}
@@ -1131,6 +1120,12 @@ static void audio_reset_timer (void)
}
}
+static void audio_timer (void *opaque)
+{
+ audio_run ("timer");
+ audio_reset_timer (opaque);
+}
+
/*
* Public API
*/
@@ -1195,7 +1190,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
hw->enabled = 1;
if (s->vm_running) {
hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out);
- audio_reset_timer ();
+ audio_reset_timer (s);
}
}
}
@@ -1240,6 +1235,7 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
hw->enabled = 1;
if (s->vm_running) {
hw->pcm_ops->ctl_in (hw, VOICE_ENABLE, conf.try_poll_in);
+ audio_reset_timer (s);
}
}
sw->total_hw_samples_acquired = hw->total_samples_captured;
@@ -1761,7 +1757,7 @@ static void audio_vm_change_state_handler (void *opaque, int running,
while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in);
}
- audio_reset_timer ();
+ audio_reset_timer (s);
}
static void audio_atexit (void)
commit 8ca209ad90bdb678932a6b18caf32b461dbe5eee
Author: Alex Williamson <alex.williamson at redhat.com>
Date: Sun Nov 7 20:57:00 2010 -0700
pc: Fix e820 fw_cfg for big endian
Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/pc.c b/hw/pc.c
index e7f7ac6..c34d194 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -467,19 +467,19 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
{
- int index = e820_table.count;
+ int index = le32_to_cpu(e820_table.count);
struct e820_entry *entry;
if (index >= E820_NR_ENTRIES)
return -EBUSY;
- entry = &e820_table.entry[index];
+ entry = &e820_table.entry[index++];
- entry->address = address;
- entry->length = length;
- entry->type = type;
+ entry->address = cpu_to_le64(address);
+ entry->length = cpu_to_le64(length);
+ entry->type = cpu_to_le32(type);
- e820_table.count++;
- return e820_table.count;
+ e820_table.count = cpu_to_le32(index);
+ return index;
}
static void *bochs_bios_init(void)
commit 67d4b0c1907455f42ad8cea445ff10b81b49eebc
Author: Alex Williamson <alex.williamson at redhat.com>
Date: Fri Nov 5 15:40:38 2010 -0600
pc: e820 qemu_cfg tables need to be packed
We can't let the compiler define the alignment for qemu_cfg data.
Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/pc.c b/hw/pc.c
index 0e44df8..e7f7ac6 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -75,12 +75,12 @@ struct e820_entry {
uint64_t address;
uint64_t length;
uint32_t type;
-};
+} __attribute((__packed__, __aligned__(4)));
struct e820_table {
uint32_t count;
struct e820_entry entry[E820_NR_ENTRIES];
-};
+} __attribute((__packed__, __aligned__(4)));
static struct e820_table e820_table;
commit b88417062d5f73e2e8137e94b360ca4412942f33
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Tue Nov 16 20:07:07 2010 +0000
Fix compilation failure with simple trace when srcdir==objdir
Fix a makefile error that meant that qemu would not compile if
the source and object directories were the same.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/Makefile.target b/Makefile.target
index a5e6410..652c7d2 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -30,6 +30,7 @@ endif
endif
PROGS=$(QEMU_PROG)
+STPFILES=
ifndef CONFIG_HAIKU
LIBS+=-lm
@@ -41,19 +42,17 @@ config-target.h: config-target.h-timestamp
config-target.h-timestamp: config-target.mak
ifdef CONFIG_SYSTEMTAP_TRACE
-trace: $(QEMU_PROG).stp
+STPFILES+=$(QEMU_PROG).stp
$(QEMU_PROG).stp:
$(call quiet-command,sh $(SRC_PATH)/tracetool \
--$(TRACE_BACKEND) \
--bindir $(bindir) \
--target $(TARGET_ARCH) \
- -s < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).stp")
-else
-trace:
+ -s < $(SRC_PATH)/trace-events > $@," GEN $@")
endif
-all: $(PROGS) trace
+all: $(PROGS) $(STPFILES)
# Dummy command so that make thinks it has done something
@true
@@ -363,7 +362,7 @@ endif
endif
ifdef CONFIG_SYSTEMTAP_TRACE
$(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset"
- $(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(datadir)/../systemtap/tapset"
+ $(INSTALL_DATA) $(STPFILES) "$(DESTDIR)$(datadir)/../systemtap/tapset"
endif
# Include automatically generated dependency files
commit 0290b57bdfec83ca78b6d119ea9847bb17943328
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Wed Nov 3 14:29:44 2010 +0000
Delete IOHandlers after potentially running them
Since commit 4bed9837309e58d208183f81d8344996744292cf an .fd_read()
handler that deletes its IOHandler is exposed to .fd_write() being
called on the deleted IOHandler.
This patch fixes deletion so that .fd_read() and .fd_write() are never
called on an IOHandler that is marked for deletion.
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/vl.c b/vl.c
index c58583d..9ee6479 100644
--- a/vl.c
+++ b/vl.c
@@ -1249,17 +1249,18 @@ void main_loop_wait(int nonblocking)
IOHandlerRecord *pioh;
QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
- if (ioh->deleted) {
- QLIST_REMOVE(ioh, next);
- qemu_free(ioh);
- continue;
- }
- if (ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
+ if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
ioh->fd_read(ioh->opaque);
}
- if (ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
+ if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
ioh->fd_write(ioh->opaque);
}
+
+ /* Do this last in case read/write handlers marked it for deletion */
+ if (ioh->deleted) {
+ QLIST_REMOVE(ioh, next);
+ qemu_free(ioh);
+ }
}
}
commit 2cc59d8cb0ebcfa9cf3476c0528e50478997ab0c
Author: Hans de Goede <hdegoede at redhat.com>
Date: Wed Nov 10 10:06:25 2010 +0100
usb-linux: Get the active configuration from sysfs rather then asking the dev
Some devices seem to choke on receiving a USB_REQ_GET_CONFIGURATION ctrl msg
(witnessed with a digital picture frame usb id 1908:1320).
When usb_fs_type == USB_FS_SYS, the active configuration can be read directly
from sysfs, which allows using this device through qemu's usb redirection.
More in general it seems a good idea to not send needless control msg's to
devices, esp. as the code in question is called every time a set_interface
is done. Which happens multiple times during virtual machine startup, and
when device drivers are activating the usb device.
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/usb-linux.c b/usb-linux.c
index 111fe1c..ccf7073 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -152,6 +152,8 @@ static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs)
static int usb_host_close(USBHostDevice *dev);
static int parse_filter(const char *spec, struct USBAutoFilter *f);
static void usb_host_auto_check(void *unused);
+static int usb_host_read_file(char *line, size_t line_size,
+ const char *device_file, const char *device_name);
static int is_isoc(USBHostDevice *s, int ep)
{
@@ -781,6 +783,23 @@ static int usb_linux_get_configuration(USBHostDevice *s)
struct usb_ctrltransfer ct;
int ret;
+ if (usb_fs_type == USB_FS_SYS) {
+ char device_name[32], line[1024];
+ int configuration;
+
+ sprintf(device_name, "%d-%d", s->bus_num, s->devpath);
+
+ if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
+ device_name)) {
+ goto usbdevfs;
+ }
+ if (sscanf(line, "%d", &configuration) != 1) {
+ goto usbdevfs;
+ }
+ return configuration;
+ }
+
+usbdevfs:
ct.bRequestType = USB_DIR_IN;
ct.bRequest = USB_REQ_GET_CONFIGURATION;
ct.wValue = 0;
commit 71d71bbdeb39544ac1602c5e307d9e14c78f9d5d
Author: Hans de Goede <hdegoede at redhat.com>
Date: Wed Nov 10 10:06:24 2010 +0100
usb-linux: introduce a usb_linux_get_configuration function
The next patch in this series introduces multiple ways to get the
configuration dependent upon usb_fs_type, it is cleaner to put this
into its own function.
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/usb-linux.c b/usb-linux.c
index 0b154c2..111fe1c 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -775,13 +775,11 @@ static int usb_host_handle_packet(USBDevice *s, USBPacket *p)
}
}
-/* returns 1 on problem encountered or 0 for success */
-static int usb_linux_update_endp_table(USBHostDevice *s)
+static int usb_linux_get_configuration(USBHostDevice *s)
{
- uint8_t *descriptors;
- uint8_t devep, type, configuration, alt_interface;
+ uint8_t configuration;
struct usb_ctrltransfer ct;
- int interface, ret, length, i;
+ int ret;
ct.bRequestType = USB_DIR_IN;
ct.bRequest = USB_REQ_GET_CONFIGURATION;
@@ -793,15 +791,31 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
if (ret < 0) {
- perror("usb_linux_update_endp_table");
- return 1;
+ perror("usb_linux_get_configuration");
+ return -1;
}
/* in address state */
if (configuration == 0) {
- return 1;
+ return -1;
}
+ return configuration;
+}
+
+/* returns 1 on problem encountered or 0 for success */
+static int usb_linux_update_endp_table(USBHostDevice *s)
+{
+ uint8_t *descriptors;
+ uint8_t devep, type, configuration, alt_interface;
+ struct usb_ctrltransfer ct;
+ int interface, ret, length, i;
+
+ i = usb_linux_get_configuration(s);
+ if (i < 0)
+ return 1;
+ configuration = i;
+
/* get the desired configuration, interface, and endpoint descriptors
* from device description */
descriptors = &s->descr[18];
commit 0f5160d1ea8bcd69d539f8a87a1b350d98fa5d52
Author: Hans de Goede <hdegoede at redhat.com>
Date: Wed Nov 10 10:06:23 2010 +0100
usb-linux: Store devpath into USBHostDevice when usb_fs_type == USB_FS_SYS
This allows us to recreate the sysfspath used during scanning later
(which will be used in a later patch in this series).
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/usb-linux.c b/usb-linux.c
index c3c38ec..0b154c2 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -62,8 +62,8 @@ struct usb_ctrlrequest {
uint16_t wLength;
};
-typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
- int vendor_id, int product_id,
+typedef int USBScanFunc(void *opaque, int bus_num, int addr, int devpath,
+ int class_id, int vendor_id, int product_id,
const char *product_name, int speed);
//#define DEBUG
@@ -141,6 +141,7 @@ typedef struct USBHostDevice {
/* Host side address */
int bus_num;
int addr;
+ int devpath;
struct USBAutoFilter match;
QTAILQ_ENTRY(USBHostDevice) next;
@@ -885,7 +886,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
}
static int usb_host_open(USBHostDevice *dev, int bus_num,
- int addr, const char *prod_name)
+ int addr, int devpath, const char *prod_name)
{
int fd = -1, ret;
struct usbdevfs_connectinfo ci;
@@ -911,6 +912,7 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
dev->bus_num = bus_num;
dev->addr = addr;
+ dev->devpath = devpath;
dev->fd = fd;
/* read the device description */
@@ -1173,7 +1175,7 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
if (line[0] == 'T' && line[1] == ':') {
if (device_count && (vendor_id || product_id)) {
/* New device. Add the previously discovered device. */
- ret = func(opaque, bus_num, addr, class_id, vendor_id,
+ ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
product_id, product_name, speed);
if (ret) {
goto the_end;
@@ -1226,7 +1228,7 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
}
if (device_count && (vendor_id || product_id)) {
/* Add the last device. */
- ret = func(opaque, bus_num, addr, class_id, vendor_id,
+ ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
product_id, product_name, speed);
}
the_end:
@@ -1275,7 +1277,7 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
{
DIR *dir = NULL;
char line[1024];
- int bus_num, addr, speed, class_id, product_id, vendor_id;
+ int bus_num, addr, devpath, speed, class_id, product_id, vendor_id;
int ret = 0;
char product_name[512];
struct dirent *de;
@@ -1292,7 +1294,9 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
if (!strncmp(de->d_name, "usb", 3)) {
tmpstr += 3;
}
- bus_num = atoi(tmpstr);
+ if (sscanf(tmpstr, "%d-%d", &bus_num, &devpath) < 1) {
+ goto the_end;
+ }
if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
goto the_end;
@@ -1343,7 +1347,7 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
speed = USB_SPEED_FULL;
}
- ret = func(opaque, bus_num, addr, class_id, vendor_id,
+ ret = func(opaque, bus_num, addr, devpath, class_id, vendor_id,
product_id, product_name, speed);
if (ret) {
goto the_end;
@@ -1434,7 +1438,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func)
static QEMUTimer *usb_auto_timer;
-static int usb_host_auto_scan(void *opaque, int bus_num, int addr,
+static int usb_host_auto_scan(void *opaque, int bus_num, int addr, int devpath,
int class_id, int vendor_id, int product_id,
const char *product_name, int speed)
{
@@ -1470,7 +1474,7 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr,
}
DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
- usb_host_open(s, bus_num, addr, product_name);
+ usb_host_open(s, bus_num, addr, devpath, product_name);
}
return 0;
@@ -1630,7 +1634,7 @@ static void usb_info_device(Monitor *mon, int bus_num, int addr, int class_id,
}
static int usb_host_info_device(void *opaque, int bus_num, int addr,
- int class_id,
+ int devpath, int class_id,
int vendor_id, int product_id,
const char *product_name,
int speed)
commit 43ad7e3e986dea82831debad68e68cff552b6746
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date: Thu Nov 11 16:10:04 2010 +0100
Add missing braces
This patch adds missing braces around if/else statements that call
macros which are likely to result in errors if the macro is
changed. It also makes the code comply better with CODING_STYLE.
Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/e1000.c b/hw/e1000.c
index 677165f..7811699 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -447,9 +447,10 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
// data descriptor
tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0;
- } else
+ } else {
// legacy descriptor
tp->cptse = 0;
+ }
if (vlan_enabled(s) && is_vlan_txd(txd_lower) &&
(tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
@@ -685,8 +686,9 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
(void *)(buf + vlan_offset), size);
desc.length = cpu_to_le16(size + fcs_len(s));
desc.status |= E1000_RXD_STAT_EOP|E1000_RXD_STAT_IXSM;
- } else // as per intel docs; skip descriptors with null buf addr
+ } else { // as per intel docs; skip descriptors with null buf addr
DBGOUT(RX, "Null RX descriptor!!\n");
+ }
cpu_physical_memory_write(base, (void *)&desc, sizeof(desc));
if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
@@ -858,13 +860,14 @@ e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val);
#endif
- if (index < NWRITEOPS && macreg_writeops[index])
+ if (index < NWRITEOPS && macreg_writeops[index]) {
macreg_writeops[index](s, index, val);
- else if (index < NREADOPS && macreg_readops[index])
+ } else if (index < NREADOPS && macreg_readops[index]) {
DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04x\n", index<<2, val);
- else
+ } else {
DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08x\n",
index<<2, val);
+ }
}
static void
commit d59f8ba938afd837182e666cce777dfb860559e4
Author: Gleb Natapov <gleb at redhat.com>
Date: Tue Nov 9 09:36:53 2010 +0200
Out off array access in usb-net
Properly check array bounds before accessing array element.
Signed-off-by: Gleb Natapov <gleb at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 70f9263..58c672f 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1142,7 +1142,7 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value,
break;
default:
- if (usb_net_stringtable[value & 0xff]) {
+ if (ARRAY_SIZE(usb_net_stringtable) > (value & 0xff)) {
ret = set_usb_string(data,
usb_net_stringtable[value & 0xff]);
break;
commit 43ae691e775707b854f9920797c81b6b298bde61
Merge: 2834c3e... 7466bc4...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Tue Nov 16 14:11:05 2010 -0600
Merge remote branch 'spice/bugfix.2' into staging
commit 2834c3e0140c3b0ed4422909dfa0607b7213d95d
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Nov 8 19:33:08 2010 +0000
Add support for generating a systemtap tapset static probes
This introduces generation of a qemu.stp/qemu-system-XXX.stp
files which provides tapsets with friendly names for static
probes & their arguments. Instead of
probe process("qemu").mark("qemu_malloc") {
printf("Malloc %d %p\n", $arg1, $arg2);
}
It is now possible todo
probe qemu.system.i386.qemu_malloc {
printf("Malloc %d %p\n", size, ptr);
}
There is one tapset defined per target arch.
* Makefile: Generate a qemu.stp file for systemtap
* tracetool: Support for generating systemtap tapsets
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/Makefile.target b/Makefile.target
index 91e6e74..a5e6410 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -40,7 +40,20 @@ kvm.o kvm-all.o vhost.o vhost_net.o: QEMU_CFLAGS+=$(KVM_CFLAGS)
config-target.h: config-target.h-timestamp
config-target.h-timestamp: config-target.mak
-all: $(PROGS)
+ifdef CONFIG_SYSTEMTAP_TRACE
+trace: $(QEMU_PROG).stp
+
+$(QEMU_PROG).stp:
+ $(call quiet-command,sh $(SRC_PATH)/tracetool \
+ --$(TRACE_BACKEND) \
+ --bindir $(bindir) \
+ --target $(TARGET_ARCH) \
+ -s < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).stp")
+else
+trace:
+endif
+
+all: $(PROGS) trace
# Dummy command so that make thinks it has done something
@true
@@ -348,6 +361,10 @@ ifneq ($(STRIP),)
$(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS))
endif
endif
+ifdef CONFIG_SYSTEMTAP_TRACE
+ $(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset"
+ $(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(datadir)/../systemtap/tapset"
+endif
# Include automatically generated dependency files
-include $(wildcard *.d */*.d)
diff --git a/configure b/configure
index f8dad3e..e560f87 100755
--- a/configure
+++ b/configure
@@ -2192,6 +2192,10 @@ EOF
echo
exit 1
fi
+ trace_backend_stap="no"
+ if has 'stap' ; then
+ trace_backend_stap="yes"
+ fi
fi
##########################################
@@ -2645,6 +2649,9 @@ fi
if test "$trace_backend" = "simple"; then
trace_file="\"$trace_file-%u\""
fi
+if test "$trace_backend" = "dtrace" -a "$trace_backend_stap" = "yes" ; then
+ echo "CONFIG_SYSTEMTAP_TRACE=y" >> $config_host_mak
+fi
echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
echo "TOOLS=$tools" >> $config_host_mak
diff --git a/tracetool b/tracetool
index 5b6636a..d797ab7 100755
--- a/tracetool
+++ b/tracetool
@@ -26,6 +26,12 @@ Output formats:
-h Generate .h file
-c Generate .c file
-d Generate .d file (DTrace only)
+ -s Generate .stp file (DTrace with SystemTAP only)
+
+Options:
+ --bindir [bindir] QEMU binary install location
+ --target [arch] QEMU target architecture
+
EOF
exit 1
}
@@ -390,6 +396,54 @@ linetod_end_dtrace()
EOF
}
+linetos_begin_dtrace()
+{
+ return
+}
+
+linetos_dtrace()
+{
+ local name args arglist state
+ name=$(get_name "$1")
+ args=$(get_args "$1")
+ arglist=$(get_argnames "$1", "")
+ state=$(get_state "$1")
+ if [ "$state" = "0" ] ; then
+ name=${name##disable }
+ fi
+
+ if [ "$target" = "i386" ]
+ then
+ binary="qemu"
+ else
+ binary="qemu-system-$target"
+ fi
+
+ # Define prototype for probe arguments
+ cat <<EOF
+probe qemu.system.$target.$name = process("$bindir/$binary").mark("$name")
+{
+EOF
+
+ i=1
+ for arg in $arglist
+ do
+ cat <<EOF
+ $arg = \$arg$i;
+EOF
+ i="$((i+1))"
+ done
+
+ cat <<EOF
+}
+EOF
+}
+
+linetos_end_dtrace()
+{
+ return
+}
+
# Process stdin by calling begin, line, and end functions for the backend
convert()
{
@@ -455,6 +509,24 @@ tracetod()
convert d
}
+tracetos()
+{
+ if [ $backend != "dtrace" ]; then
+ echo "SystemTAP tapset generator not applicable to $backend backend"
+ exit 1
+ fi
+ if [ -z "$target" ]; then
+ echo "--target is required for SystemTAP tapset generator"
+ exit 1
+ fi
+ if [ -z "$bindir" ]; then
+ echo "--bindir is required for SystemTAP tapset generator"
+ exit 1
+ fi
+ echo "/* This file is autogenerated by tracetool, do not edit. */"
+ convert s
+}
+
# Choose backend
case "$1" in
"--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
@@ -462,10 +534,30 @@ case "$1" in
esac
shift
+bindir=
+case "$1" in
+ "--bindir")
+ bindir=$2
+ shift
+ shift
+ ;;
+esac
+
+target=
+case "$1" in
+ "--target")
+ target=$2
+ shift
+ shift
+ ;;
+esac
+
+
case "$1" in
"-h") tracetoh ;;
"-c") tracetoc ;;
"-d") tracetod ;;
+"-s") tracetos ;;
"--check-backend") exit 0 ;; # used by ./configure to test for backend
*) usage ;;
esac
commit 4addb1127f6327c7ebcbd150a6b589e7677adc92
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Nov 8 19:33:07 2010 +0000
Add a DTrace tracing backend targetted for SystemTAP compatability
This introduces a new tracing backend that targets the SystemTAP
implementation of DTrace userspace tracing. The core functionality
should be applicable and standard across any DTrace implementation
on Solaris, OS-X, *BSD, but the Makefile rules will likely need
some small additional changes to cope with OS specific build
requirements.
This backend builds a little differently from the other tracing
backends. Specifically there is no 'trace.c' file, because the
'dtrace' command line tool generates a '.o' file directly from
the dtrace probe definition file. The probe definition is usually
named with a '.d' extension but QEMU uses '.d' files for its
external makefile dependancy tracking, so this uses '.dtrace' as
the extension for the probe definition file.
The 'tracetool' program gains the ability to generate a trace.h
file for DTrace, and also to generate the trace.d file containing
the dtrace probe definition.
Example usage of a dtrace probe in systemtap looks like:
probe process("qemu").mark("qemu_malloc") {
printf("Malloc %d %p\n", $arg1, $arg2);
}
* .gitignore: Ignore trace-dtrace.*
* Makefile: Extra rules for generating DTrace files
* Makefile.obj: Don't build trace.o for DTrace, use
trace-dtrace.o generated by 'dtrace' instead
* tracetool: Support for generating DTrace data files
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/.gitignore b/.gitignore
index a43e4d1..3efb4ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,8 @@ config-host.*
config-target.*
trace.h
trace.c
+trace-dtrace.h
+trace-dtrace.dtrace
*-timestamp
*-softmmu
*-darwin-user
diff --git a/Makefile b/Makefile
index 6896319..747e47c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,9 @@
# Makefile for QEMU.
GENERATED_HEADERS = config-host.h trace.h qemu-options.def
+ifeq ($(TRACE_BACKEND),dtrace)
+GENERATED_HEADERS += trace-dtrace.h
+endif
ifneq ($(wildcard config-host.mak),)
# Put the all: rule here so that config-host.mak can contain dependencies.
@@ -108,7 +111,11 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
+ifeq ($(TRACE_BACKEND),dtrace)
+trace.h: trace.h-timestamp trace-dtrace.h
+else
trace.h: trace.h-timestamp
+endif
trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h")
@cmp -s $@ trace.h || cp $@ trace.h
@@ -120,6 +127,20 @@ trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak
trace.o: trace.c $(GENERATED_HEADERS)
+trace-dtrace.h: trace-dtrace.dtrace
+ $(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h")
+
+# Normal practice is to name DTrace probe file with a '.d' extension
+# but that gets picked up by QEMU's Makefile as an external dependancy
+# rule file. So we use '.dtrace' instead
+trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
+trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
+ $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace")
+ @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
+
+trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
+ $(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o")
+
simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
version.o: $(SRC_PATH)/version.rc config-host.mak
@@ -157,6 +178,8 @@ clean:
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
rm -f qemu-img-cmds.h
rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
+ rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
+ rm -f trace-dtrace.h trace-dtrace.h-timestamp
$(MAKE) -C tests clean
for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
diff --git a/Makefile.objs b/Makefile.objs
index 15569af..23b17ce 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -286,11 +286,15 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
######################################################################
# trace
+ifeq ($(TRACE_BACKEND),dtrace)
+trace-obj-y = trace-dtrace.o
+else
trace-obj-y = trace.o
ifeq ($(TRACE_BACKEND),simple)
trace-obj-y += simpletrace.o
user-obj-y += qemu-timer-common.o
endif
+endif
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/configure b/configure
index 7025d2b..f8dad3e 100755
--- a/configure
+++ b/configure
@@ -929,7 +929,7 @@ echo " --enable-docs enable documentation build"
echo " --disable-docs disable documentation build"
echo " --disable-vhost-net disable vhost-net acceleration support"
echo " --enable-vhost-net enable vhost-net acceleration support"
-echo " --trace-backend=B Trace backend nop simple ust"
+echo " --trace-backend=B Trace backend nop simple ust dtrace"
echo " --trace-file=NAME Full PATH,NAME of file to store traces"
echo " Default:trace-<pid>"
echo " --disable-spice disable spice"
@@ -2193,6 +2193,18 @@ EOF
exit 1
fi
fi
+
+##########################################
+# For 'dtrace' backend, test if 'dtrace' command is present
+if test "$trace_backend" = "dtrace"; then
+ if ! has 'dtrace' ; then
+ echo
+ echo "Error: dtrace command is not found in PATH $PATH"
+ echo
+ exit 1
+ fi
+fi
+
##########################################
# End of CC checks
# After here, no more $cc or $ld runs
diff --git a/tracetool b/tracetool
index 7010858..5b6636a 100755
--- a/tracetool
+++ b/tracetool
@@ -20,10 +20,12 @@ Backends:
--nop Tracing disabled
--simple Simple built-in backend
--ust LTTng User Space Tracing backend
+ --dtrace DTrace/SystemTAP backend
Output formats:
-h Generate .h file
-c Generate .c file
+ -d Generate .d file (DTrace only)
EOF
exit 1
}
@@ -46,8 +48,9 @@ get_args()
# Get the argument name list of a trace event
get_argnames()
{
- local nfields field name
+ local nfields field name sep
nfields=0
+ sep="$2"
for field in $(get_args "$1"); do
nfields=$((nfields + 1))
@@ -58,7 +61,7 @@ get_argnames()
name=${field%,}
test "$field" = "$name" && continue
- printf "%s" "$name, "
+ printf "%s%s " $name $sep
done
# Last argument name
@@ -73,7 +76,7 @@ get_argc()
{
local name argc
argc=0
- for name in $(get_argnames "$1"); do
+ for name in $(get_argnames "$1", ","); do
argc=$((argc + 1))
done
echo $argc
@@ -154,7 +157,7 @@ EOF
cast_args_to_uint64_t()
{
local arg
- for arg in $(get_argnames "$1"); do
+ for arg in $(get_argnames "$1", ","); do
printf "%s" "(uint64_t)(uintptr_t)$arg"
done
}
@@ -247,7 +250,7 @@ linetoh_ust()
local name args argnames
name=$(get_name "$1")
args=$(get_args "$1")
- argnames=$(get_argnames "$1")
+ argnames=$(get_argnames "$1", ",")
cat <<EOF
DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
@@ -274,7 +277,7 @@ linetoc_ust()
local name args argnames fmt
name=$(get_name "$1")
args=$(get_args "$1")
- argnames=$(get_argnames "$1")
+ argnames=$(get_argnames "$1", ",")
fmt=$(get_fmt "$1")
cat <<EOF
@@ -306,6 +309,87 @@ EOF
echo "}"
}
+linetoh_begin_dtrace()
+{
+ cat <<EOF
+#include "trace-dtrace.h"
+EOF
+}
+
+linetoh_dtrace()
+{
+ local name args argnames state nameupper
+ name=$(get_name "$1")
+ args=$(get_args "$1")
+ argnames=$(get_argnames "$1", ",")
+ state=$(get_state "$1")
+ if [ "$state" = "0" ] ; then
+ name=${name##disable }
+ fi
+
+ nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
+
+ # Define an empty function for the trace event
+ cat <<EOF
+static inline void trace_$name($args) {
+ if (QEMU_${nameupper}_ENABLED()) {
+ QEMU_${nameupper}($argnames);
+ }
+}
+EOF
+}
+
+linetoh_end_dtrace()
+{
+ return
+}
+
+linetoc_begin_dtrace()
+{
+ return
+}
+
+linetoc_dtrace()
+{
+ # No need for function definitions in dtrace backend
+ return
+}
+
+linetoc_end_dtrace()
+{
+ return
+}
+
+linetod_begin_dtrace()
+{
+ cat <<EOF
+provider qemu {
+EOF
+}
+
+linetod_dtrace()
+{
+ local name args state
+ name=$(get_name "$1")
+ args=$(get_args "$1")
+ state=$(get_state "$1")
+ if [ "$state" = "0" ] ; then
+ name=${name##disable }
+ fi
+
+ # Define prototype for probe arguments
+ cat <<EOF
+ probe $name($args);
+EOF
+}
+
+linetod_end_dtrace()
+{
+ cat <<EOF
+};
+EOF
+}
+
# Process stdin by calling begin, line, and end functions for the backend
convert()
{
@@ -324,9 +408,10 @@ convert()
disable=${str%%disable *}
echo
if test -z "$disable"; then
- # Pass the disabled state as an arg to lineto$1_simple().
- # For all other cases, call lineto$1_nop()
- if [ $backend = "simple" ]; then
+ # Pass the disabled state as an arg for the simple
+ # or DTrace backends which handle it dynamically.
+ # For all other backends, call lineto$1_nop()
+ if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
"$process_line" "$str"
else
"lineto$1_nop" "${str##disable }"
@@ -360,9 +445,19 @@ tracetoc()
convert c
}
+tracetod()
+{
+ if [ $backend != "dtrace" ]; then
+ echo "DTrace probe generator not applicable to $backend backend"
+ exit 1
+ fi
+ echo "/* This file is autogenerated by tracetool, do not edit. */"
+ convert d
+}
+
# Choose backend
case "$1" in
-"--nop" | "--simple" | "--ust") backend="${1#--}" ;;
+"--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
*) usage ;;
esac
shift
@@ -370,6 +465,7 @@ shift
case "$1" in
"-h") tracetoh ;;
"-c") tracetoc ;;
+"-d") tracetod ;;
"--check-backend") exit 0 ;; # used by ./configure to test for backend
*) usage ;;
esac
commit 9696846600cac4bd0dfd6835e45e69d25ec2b11e
Author: Adam Lackorzynski <adam at os.inf.tu-dresden.de>
Date: Thu Nov 4 23:22:15 2010 +0100
multiboot: Prevent loading of x86_64 images
A via -kernel supplied x86_64 ELF image is being started in 32bit mode.
Detect and exit if a 64bit image has been supplied.
Signed-off-by: Adam Lackorzynski <adam at os.inf.tu-dresden.de>
Acked-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/multiboot.c b/hw/multiboot.c
index f9097a2..e710bbb 100644
--- a/hw/multiboot.c
+++ b/hw/multiboot.c
@@ -171,6 +171,12 @@ int load_multiboot(void *fw_cfg,
uint64_t elf_low, elf_high;
int kernel_size;
fclose(f);
+
+ if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) {
+ fprintf(stderr, "Cannot load x86-64 image, give a 32bit one.\n");
+ exit(1);
+ }
+
kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
&elf_low, &elf_high, 0, ELF_MACHINE, 0);
if (kernel_size < 0) {
commit b538e53ee7e8b9e2920d3286b480276cef209fd4
Author: Alex Williamson <alex.williamson at redhat.com>
Date: Fri Nov 5 16:01:29 2010 -0600
apic: Don't iterate past last used apic
local_apics are allocated sequentially and never removed, so
we can stop any iterations that go to MAX_APICS as soon as we
hit the first NULL. Looking at a small guest running a virtio-net
workload with oprofile, this drops apic_get_delivery_bitmask()
from #3 in the profile to down in the noise.
Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/apic.c b/hw/apic.c
index 63d62c7..5f4a87c 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -437,6 +437,8 @@ static int apic_find_dest(uint8_t dest)
apic = local_apics[i];
if (apic && apic->id == dest)
return i;
+ if (!apic)
+ break;
}
return -1;
@@ -472,6 +474,8 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
set_bit(deliver_bitmask, i);
}
}
+ } else {
+ break;
}
}
}
commit 4cff0a5994d0300e6e77e90d3354aa517a120539
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Fri Nov 12 16:21:35 2010 +0900
pci: allow hotplug removal of cold-plugged devices
This patch fixes hot unplug of cold plugged devices
(those present at system start), which got broken by
5beb8ad503c88a76f2b8106c3b74b4ce485a60e1 .
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
Acked-by: Cam Macdonell <cam at cs.ualberta.ca>
Tested-by: Cam Macdonell <cam at cs.ualberta.ca>
Reported-by: Cam Macdonell <cam at cs.ualberta.ca>.
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 66c7885..f549089 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -585,7 +585,8 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val);
}
-static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state);
+static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
+ PCIHotplugState state);
static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
{
@@ -615,18 +616,23 @@ static void disable_device(PIIX4PMState *s, int slot)
s->pci0_status.down |= (1 << slot);
}
-static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state)
+static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
+ PCIHotplugState state)
{
int slot = PCI_SLOT(dev->devfn);
PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev,
DO_UPCAST(PCIDevice, qdev, qdev));
- if (!dev->qdev.hotplugged)
+ /* Don't send event when device is enabled during qemu machine creation:
+ * it is present on boot, no hotplug event is necessary. We do send an
+ * event when the device is disabled later. */
+ if (state == PCI_COLDPLUG_ENABLED) {
return 0;
+ }
s->pci0_status.up = 0;
s->pci0_status.down = 0;
- if (state) {
+ if (state == PCI_HOTPLUG_ENABLED) {
enable_device(s, slot);
} else {
disable_device(s, slot);
diff --git a/hw/pci.c b/hw/pci.c
index 8f6fcf8..438c0d1 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1558,8 +1558,11 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
pci_add_option_rom(pci_dev);
if (bus->hotplug) {
- /* lower layer must check qdev->hotplugged */
- rc = bus->hotplug(bus->hotplug_qdev, pci_dev, 1);
+ /* Let buses differentiate between hotplug and when device is
+ * enabled during qemu machine creation. */
+ rc = bus->hotplug(bus->hotplug_qdev, pci_dev,
+ qdev->hotplugged ? PCI_HOTPLUG_ENABLED:
+ PCI_COLDPLUG_ENABLED);
if (rc != 0) {
int r = pci_unregister_device(&pci_dev->qdev);
assert(!r);
@@ -1573,7 +1576,8 @@ static int pci_unplug_device(DeviceState *qdev)
{
PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
- return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, 0);
+ return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
+ PCI_HOTPLUG_DISABLED);
}
void pci_qdev_register(PCIDeviceInfo *info)
diff --git a/hw/pci.h b/hw/pci.h
index 7100804..09b3e4c 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -214,7 +214,15 @@ int pci_device_load(PCIDevice *s, QEMUFile *f);
typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
-typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, int state);
+
+typedef enum {
+ PCI_HOTPLUG_DISABLED,
+ PCI_HOTPLUG_ENABLED,
+ PCI_COLDPLUG_ENABLED,
+} PCIHotplugState;
+
+typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev,
+ PCIHotplugState state);
void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
const char *name, int devfn_min);
PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min);
diff --git a/hw/pcie.c b/hw/pcie.c
index 35918f7..f461c1c 100644
--- a/hw/pcie.c
+++ b/hw/pcie.c
@@ -192,14 +192,16 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
}
static int pcie_cap_slot_hotplug(DeviceState *qdev,
- PCIDevice *pci_dev, int state)
+ PCIDevice *pci_dev, PCIHotplugState state)
{
PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
uint8_t *exp_cap = d->config + d->exp.exp_cap;
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
- if (!pci_dev->qdev.hotplugged) {
- assert(state); /* this case only happens at machine creation. */
+ /* Don't send event when device is enabled during qemu machine creation:
+ * it is present on boot, no hotplug event is necessary. We do send an
+ * event when the device is disabled later. */
+ if (state == PCI_COLDPLUG_ENABLED) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS);
return 0;
@@ -219,7 +221,7 @@ static int pcie_cap_slot_hotplug(DeviceState *qdev,
*/
assert(PCI_FUNC(pci_dev->devfn) == 0);
- if (state) {
+ if (state == PCI_HOTPLUG_ENABLED) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS);
pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
commit a6a9239cd87d1bcdade909cf71413686fb70f8d0
Author: Alex Williamson <alex.williamson at redhat.com>
Date: Mon Oct 4 15:53:11 2010 -0600
PCI: Bus number from the bridge, not the device
pcibus_dev_print() was erroneously retrieving the device bus
number from the secondary bus number offset of the device
instead of the bridge above the device. This ends of landing
in the 2nd byte of the 3rd BAR for devices, which thankfully
is usually zero.
Note: pcibus_get_dev_path() copied this code,
inheriting the same bug. pcibus_get_dev_path() is used for
ramblock naming, so changing it can effect migration. However,
I've only seen this byte be non-zero for an assigned device,
which can't migrate anyway, so hopefully we won't run into
any issues.
This patch does not touch pcibus_get_dev_path, as
bus number is guest assigned for nested buses,
so using it for migration is broken anyway.
Fix it properly later.
Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index 962886e..8f6fcf8 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1806,8 +1806,7 @@ static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent)
monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, "
"pci id %04x:%04x (sub %04x:%04x)\n",
- indent, "", ctxt,
- d->config[PCI_SECONDARY_BUS],
+ indent, "", ctxt, pci_bus_num(d->bus),
PCI_SLOT(d->devfn), PCI_FUNC(d->devfn),
pci_get_word(d->config + PCI_VENDOR_ID),
pci_get_word(d->config + PCI_DEVICE_ID),
commit 1f892feb37dabedbb2492c6b499b0c1b22631a1f
Author: Alex Williamson <alex.williamson at redhat.com>
Date: Fri Nov 5 14:52:08 2010 -0600
e1000: Fix TCP checksum overflow with TSO
When adding the length to the pseudo header, we're not properly
accounting for overflow.
From: Mark Wu <dwu at redhat.com>
Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/e1000.c b/hw/e1000.c
index 532efdc..677165f 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -384,9 +384,12 @@ xmit_seg(E1000State *s)
} else // UDP
cpu_to_be16wu((uint16_t *)(tp->data+css+4), len);
if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
+ unsigned int phsum;
// add pseudo-header length before checksum calculation
sp = (uint16_t *)(tp->data + tp->tucso);
- cpu_to_be16wu(sp, be16_to_cpup(sp) + len);
+ phsum = be16_to_cpup(sp) + len;
+ phsum = (phsum >> 16) + (phsum & 0xffff);
+ cpu_to_be16wu(sp, phsum);
}
tp->tso_frames++;
}
commit 27a6375de3edece2e5d115847d54c01e52331f7e
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Sun Oct 31 19:06:47 2010 +0200
tap: make set_offload a nop after netdev cleanup
virtio-net expects set_offload to succeed after
peer cleanup.
Since we don't have an open fd anymore, make it so.
Fixes warning about the failure of offload setting.
Reported-by: Jason Wang <jasowang at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/net/tap.c b/net/tap.c
index 937d942..eada34a 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -269,8 +269,11 @@ void tap_set_offload(VLANClientState *nc, int csum, int tso4,
int tso6, int ecn, int ufo)
{
TAPState *s = DO_UPCAST(TAPState, nc, nc);
+ if (s->fd < 0) {
+ return;
+ }
- return tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo);
+ tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo);
}
static void tap_cleanup(VLANClientState *nc)
@@ -290,6 +293,7 @@ static void tap_cleanup(VLANClientState *nc)
tap_read_poll(s, 0);
tap_write_poll(s, 0);
close(s->fd);
+ s->fd = -1;
}
static void tap_poll(VLANClientState *nc, bool enable)
commit f6584ee20338a74ef3b05b38b8f9dc5e7a7276a6
Author: Gleb Natapov <gleb at redhat.com>
Date: Sun Oct 24 14:27:55 2010 +0200
Add support for async page fault to qemu
Add save/restore of MSR for migration and cpuid bit.
Signed-off-by: Gleb Natapov <gleb at redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 2440d65..06e40f3 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -681,6 +681,7 @@ typedef struct CPUX86State {
#endif
uint64_t system_time_msr;
uint64_t wall_clock_msr;
+ uint64_t async_pf_en_msr;
uint64_t tsc;
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index 650a719..165045e 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -73,7 +73,7 @@ static const char *ext3_feature_name[] = {
};
static const char *kvm_feature_name[] = {
- "kvmclock", "kvm_nopiodelay", "kvm_mmu", NULL, NULL, NULL, NULL, NULL,
+ "kvmclock", "kvm_nopiodelay", "kvm_mmu", NULL, "kvm_asyncpf", NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index ae0a034..7dfc357 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -162,6 +162,9 @@ struct kvm_para_features {
#ifdef KVM_CAP_PV_MMU
{ KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP },
#endif
+#ifdef KVM_CAP_ASYNC_PF
+ { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF },
+#endif
{ -1, -1 }
};
@@ -838,6 +841,9 @@ static int kvm_put_msrs(CPUState *env, int level)
kvm_msr_entry_set(&msrs[n++], MSR_KVM_SYSTEM_TIME,
env->system_time_msr);
kvm_msr_entry_set(&msrs[n++], MSR_KVM_WALL_CLOCK, env->wall_clock_msr);
+#ifdef KVM_CAP_ASYNC_PF
+ kvm_msr_entry_set(&msrs[n++], MSR_KVM_ASYNC_PF_EN, env->async_pf_en_msr);
+#endif
}
#ifdef KVM_CAP_MCE
if (env->mcg_cap) {
@@ -1064,6 +1070,9 @@ static int kvm_get_msrs(CPUState *env)
#endif
msrs[n++].index = MSR_KVM_SYSTEM_TIME;
msrs[n++].index = MSR_KVM_WALL_CLOCK;
+#ifdef KVM_CAP_ASYNC_PF
+ msrs[n++].index = MSR_KVM_ASYNC_PF_EN;
+#endif
#ifdef KVM_CAP_MCE
if (env->mcg_cap) {
@@ -1135,6 +1144,11 @@ static int kvm_get_msrs(CPUState *env)
}
#endif
break;
+#ifdef KVM_CAP_ASYNC_PF
+ case MSR_KVM_ASYNC_PF_EN:
+ env->async_pf_en_msr = msrs[i].data;
+ break;
+#endif
}
}
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 5f8376c..d78eceb 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -373,6 +373,24 @@ static int cpu_post_load(void *opaque, int version_id)
return 0;
}
+static bool async_pf_msr_needed(void *opaque)
+{
+ CPUState *cpu = opaque;
+
+ return cpu->async_pf_en_msr != 0;
+}
+
+static const VMStateDescription vmstate_async_pf_msr = {
+ .name = "cpu/async_pf_msr",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT64(async_pf_en_msr, CPUState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_cpu = {
.name = "cpu",
.version_id = CPU_SAVE_VERSION,
@@ -475,6 +493,14 @@ static const VMStateDescription vmstate_cpu = {
VMSTATE_YMMH_REGS_VARS(ymmh_regs, CPUState, CPU_NB_REGS, 12),
VMSTATE_END_OF_LIST()
/* The above list is not sorted /wrt version numbers, watch out! */
+ },
+ .subsections = (VMStateSubsection []) {
+ {
+ .vmsd = &vmstate_async_pf_msr,
+ .needed = async_pf_msr_needed,
+ } , {
+ /* empty */
+ }
}
};
commit 43849424cff82803011fad21074531a1101e514e
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Wed Oct 27 20:03:43 2010 +0200
tap: clear vhost_net backend on cleanup
Frontends calling tap_get_vhost_net get an invalid pointer after the
peer backend has been deleted. Jason Wang <jasowang at redhat.com> reports
this leading to a crash in ack_features when we remove the vhost-net
bakend of a virtio nic.
The fix is simply to clear the backend pointer.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/net/tap.c b/net/tap.c
index 4afb314..937d942 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -279,6 +279,7 @@ static void tap_cleanup(VLANClientState *nc)
if (s->vhost_net) {
vhost_net_cleanup(s->vhost_net);
+ s->vhost_net = NULL;
}
qemu_purge_queued_packets(nc);
commit 788954270d339b4b271e1a537a481e7068ba3591
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Fri Oct 15 11:45:13 2010 +0200
more stdvga cleanups.
video.x is gone now. It was the only user of the
vga bios_offset + bios_size logic. Zap it.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 8026071..6be8aa7 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -977,7 +977,7 @@ void mips_malta_init (ram_addr_t ram_size,
} else if (vmsvga_enabled) {
pci_vmsvga_init(pci_bus);
} else if (std_vga_enabled) {
- pci_vga_init(pci_bus, 0, 0);
+ pci_vga_init(pci_bus);
}
}
diff --git a/hw/pc.c b/hw/pc.c
index 69b13bf..0e44df8 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -993,7 +993,7 @@ void pc_vga_init(PCIBus *pci_bus)
fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
} else if (std_vga_enabled) {
if (pci_bus) {
- pci_vga_init(pci_bus, 0, 0);
+ pci_vga_init(pci_bus);
} else {
isa_vga_init();
}
diff --git a/hw/pc.h b/hw/pc.h
index 63b0249..6852790 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -154,8 +154,7 @@ enum vga_retrace_method {
extern enum vga_retrace_method vga_retrace_method;
int isa_vga_init(void);
-int pci_vga_init(PCIBus *bus,
- unsigned long vga_bios_offset, int vga_bios_size);
+int pci_vga_init(PCIBus *bus);
int isa_vga_mm_init(target_phys_addr_t vram_base,
target_phys_addr_t ctrl_base, int it_shift);
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 4369337..305b2d4 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -316,7 +316,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
machine_arch = ARCH_MAC99;
}
/* init basic PC hardware */
- pci_vga_init(pci_bus, 0, 0);
+ pci_vga_init(pci_bus);
escc_mem_index = escc_init(0x80013000, pic[0x25], pic[0x24],
serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index a2f9ddf..5efc93d 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -227,7 +227,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
}
pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
pci_bus = pci_grackle_init(0xfec00000, pic);
- pci_vga_init(pci_bus, 0, 0);
+ pci_vga_init(pci_bus);
escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
serial_hds[1], ESCC_CLOCK, 4);
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index a6915f7..b1f9cc7 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -694,7 +694,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
/* init basic PC hardware */
- pci_vga_init(pci_bus, 0, 0);
+ pci_vga_init(pci_bus);
// openpic = openpic_init(0x00000000, 0xF0000000, 1);
// pit = pit_init(0x40, i8259[0]);
rtc_init(2000, NULL);
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 45a46d6..5292ac6 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -767,7 +767,7 @@ static void sun4uv_init(ram_addr_t RAM_size,
pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2,
&pci_bus3);
isa_mem_base = APB_PCI_IO_BASE;
- pci_vga_init(pci_bus, 0, 0);
+ pci_vga_init(pci_bus);
// XXX Should be pci_bus3
pci_ebus_init(pci_bus, -1);
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index eef0e3c..b09789c 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -52,14 +52,11 @@ static void vga_map(PCIDevice *pci_dev, int region_num,
{
PCIVGAState *d = (PCIVGAState *)pci_dev;
VGACommonState *s = &d->vga;
- if (region_num == PCI_ROM_SLOT) {
- cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
- } else {
- cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
- s->map_addr = addr;
- s->map_end = addr + s->vram_size;
- vga_dirty_log_start(s);
- }
+
+ cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
+ s->map_addr = addr;
+ s->map_end = addr + s->vram_size;
+ vga_dirty_log_start(s);
}
static void pci_vga_write_config(PCIDevice *d,
@@ -95,31 +92,12 @@ static int pci_vga_initfn(PCIDevice *dev)
pci_register_bar(&d->dev, 0, VGA_RAM_SIZE,
PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
- if (s->bios_size) {
- unsigned int bios_total_size;
- /* must be a power of two */
- bios_total_size = 1;
- while (bios_total_size < s->bios_size)
- bios_total_size <<= 1;
- pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size,
- PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
- } else {
- if (dev->romfile == NULL)
- dev->romfile = qemu_strdup("vgabios-stdvga.bin");
- }
return 0;
}
-int pci_vga_init(PCIBus *bus,
- unsigned long vga_bios_offset, int vga_bios_size)
+int pci_vga_init(PCIBus *bus)
{
- PCIDevice *dev;
-
- dev = pci_create(bus, -1, "VGA");
- qdev_prop_set_uint32(&dev->qdev, "bios-offset", vga_bios_offset);
- qdev_prop_set_uint32(&dev->qdev, "bios-size", vga_bios_size);
- qdev_init_nofail(&dev->qdev);
-
+ pci_create_simple(bus, -1, "VGA");
return 0;
}
@@ -129,11 +107,7 @@ static PCIDeviceInfo vga_info = {
.qdev.vmsd = &vmstate_vga_pci,
.init = pci_vga_initfn,
.config_write = pci_vga_write_config,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("bios-offset", PCIVGAState, vga.bios_offset, 0),
- DEFINE_PROP_HEX32("bios-size", PCIVGAState, vga.bios_size, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+ .romfile = "vgabios-stdvga.bin",
};
static void vga_register(void)
diff --git a/hw/vga.c b/hw/vga.c
index 966185e..c057f4f 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1934,8 +1934,6 @@ void vga_common_reset(VGACommonState *s)
s->map_addr = 0;
s->map_end = 0;
s->lfb_vram_mapped = 0;
- s->bios_offset = 0;
- s->bios_size = 0;
s->sr_index = 0;
memset(s->sr, '\0', sizeof(s->sr));
s->gr_index = 0;
diff --git a/hw/vga_int.h b/hw/vga_int.h
index 6a46a43..bc1327f 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -112,8 +112,6 @@ typedef struct VGACommonState {
uint32_t map_addr;
uint32_t map_end;
uint32_t lfb_vram_mapped; /* whether 0xa0000 is mapped as ram */
- uint32_t bios_offset;
- uint32_t bios_size;
uint32_t latch;
uint8_t sr_index;
uint8_t sr[256];
commit 4eccfec4943db1106c79a01069e18dd4f463219b
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu May 6 11:14:11 2010 +0200
switch vmware_vga to pci vgabios
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 3d25c14..9337fdb 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -114,14 +114,12 @@ struct pci_vmsvga_state_s {
# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT
# define SVGA_IO_MUL 1
# define SVGA_FIFO_SIZE 0x10000
-# define SVGA_MEM_BASE 0xe0000000
# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA2
#else
# define SVGA_ID SVGA_ID_1
# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT
# define SVGA_IO_MUL 4
# define SVGA_FIFO_SIZE 0x10000
-# define SVGA_MEM_BASE 0xe0000000
# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA
#endif
@@ -1219,10 +1217,6 @@ static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size)
vga_init(&s->vga);
vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
- vga_init_vbe(&s->vga);
-
- rom_add_vga(VGABIOS_FILENAME);
-
vmsvga_reset(s);
}
@@ -1320,6 +1314,7 @@ static PCIDeviceInfo vmsvga_info = {
.qdev.size = sizeof(struct pci_vmsvga_state_s),
.qdev.vmsd = &vmstate_vmware_vga,
.init = pci_vmsvga_initfn,
+ .romfile = "vgabios-vmware.bin",
};
static void vmsvga_register(void)
commit 543f8e3468e6df32bfde8f84ac36d05a7604e082
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu May 6 11:13:11 2010 +0200
switch stdvga to pci vgabios
Make stdvga provide the new vgabios binary (with pcibios support)
using the PCI option rom bar. Seabios will happily load it from
there. The new vga bios will also lookup the framebuffer address
in pci config space, so the magic bochs lfb @ 0xe0000000 is not
needed any more -> zap it.
Without the patch:
# dmesg | grep framebuffer
vesafb: framebuffer at 0xe0000000, mapped to 0xf7e80000, using 1875k, total 8192k
# lspci -vs2
00:02.0 VGA compatible controller: Technical Corp. Device 1111 (prog-if 00 [VGA controller])
Subsystem: Qumranet, Inc. Device 1100
Physical Slot: 2
Flags: fast devsel
Memory at f0000000 (32-bit, prefetchable) [size=8M]
Expansion ROM at <unassigned> [disabled]
With patch applied:
# dmesg | grep framebuffer
vesafb: framebuffer at 0xf0000000, mapped to 0xf7e80000, using 1875k, total 8192k
# lspci -vs2
00:02.0 VGA compatible controller: Technical Corp. Device 1111 (prog-if 00 [VGA controller])
Subsystem: Qumranet, Inc. Device 1100
Physical Slot: 2
Flags: fast devsel
Memory at f0000000 (32-bit, prefetchable) [size=8M]
Expansion ROM at f0800000 [disabled] [size=64K]
cheers,
Gerd
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index 2315f70..eef0e3c 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -103,11 +103,10 @@ static int pci_vga_initfn(PCIDevice *dev)
bios_total_size <<= 1;
pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size,
PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
+ } else {
+ if (dev->romfile == NULL)
+ dev->romfile = qemu_strdup("vgabios-stdvga.bin");
}
-
- vga_init_vbe(s);
- /* ROM BIOS */
- rom_add_vga(VGABIOS_FILENAME);
return 0;
}
commit 3b3d448e01ccfc6fdcb6e3d4ebf47418075e3bb4
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon Aug 23 12:10:46 2010 +0200
Add new vgabios binaries to blobs list.
aliguori: update VGA BIOS
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/Makefile b/Makefile
index 02698e9..6896319 100644
--- a/Makefile
+++ b/Makefile
@@ -178,8 +178,9 @@ ar de en-us fi fr-be hr it lv nl pl ru th \
common de-ch es fo fr-ca hu ja mk nl-be pt sl tr
ifdef INSTALL_BLOBS
-BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
-openbios-sparc32 openbios-sparc64 openbios-ppc \
+BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \
+vgabios-stdvga.bin vgabios-vmware.bin \
+ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
gpxe-eepro100-80861209.rom \
gpxe-eepro100-80861229.rom \
pxe-e1000.bin \
diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin
index 4fa8f99..424dd0c 100644
Binary files a/pc-bios/vgabios-cirrus.bin and b/pc-bios/vgabios-cirrus.bin differ
diff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin
new file mode 100644
index 0000000..5123c5f
Binary files /dev/null and b/pc-bios/vgabios-stdvga.bin differ
diff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin
new file mode 100644
index 0000000..5e8c06b
Binary files /dev/null and b/pc-bios/vgabios-vmware.bin differ
diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin
index fa6f815..892a2b5 100644
Binary files a/pc-bios/vgabios.bin and b/pc-bios/vgabios.bin differ
diff --git a/roms/vgabios b/roms/vgabios
index 6e62666..19ea12c 160000
--- a/roms/vgabios
+++ b/roms/vgabios
@@ -1 +1 @@
-Subproject commit 6e62666cfc19e7fd45dd0d7c3ad62fd8d0b5f67a
+Subproject commit 19ea12c230ded95928ecaef0db47a82231c2e485
commit cf2c1839a955482f2e208d7400594bf076c222f2
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Nov 11 13:07:52 2010 +0100
add copyright to spiceaudio
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index 51ba53a..373e4c4 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * maintained by Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
#include "hw/hw.h"
#include "qemu-timer.h"
#include "ui/qemu-spice.h"
commit 3e31375378f40558f1ee7c258f3cc63c85596bfc
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Tue Nov 9 17:29:46 2010 +0100
spice: add audio
Add support for the spice audio interface. With this patch applied
audio can be forwarded over the network from/to the spice client. Both
recording and playback is supported.
The driver is first in the driver list, but the can_be_default flag is
set only in case spice is active. So if you have the spice protocol
enabled the spice audio driver is the default one, otherwise whatever
comes first after spice in the list. Overriding the default using
QEMU_AUDIO_DRV works in any case.
[ v2: audio codestyle: add spaces before open parenthesis ]
[ v2: add const to silence array ]
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Cc: malc <av1474 at comtv.ru>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/Makefile.objs b/Makefile.objs
index faf485e..15569af 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -102,6 +102,7 @@ common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display.
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
audio-obj-$(CONFIG_SDL) += sdlaudio.o
audio-obj-$(CONFIG_OSS) += ossaudio.o
+audio-obj-$(CONFIG_SPICE) += spiceaudio.o
audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o
audio-obj-$(CONFIG_ALSA) += alsaaudio.o
audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o
diff --git a/audio/audio.c b/audio/audio.c
index ad51077..ade342e 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -44,6 +44,9 @@
that we generate the list.
*/
static struct audio_driver *drvtab[] = {
+#ifdef CONFIG_SPICE
+ &spice_audio_driver,
+#endif
CONFIG_AUDIO_DRIVERS
&no_audio_driver,
&wav_audio_driver
diff --git a/audio/audio_int.h b/audio/audio_int.h
index d8560b6..d66f2c3 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -209,6 +209,7 @@ extern struct audio_driver coreaudio_audio_driver;
extern struct audio_driver dsound_audio_driver;
extern struct audio_driver esd_audio_driver;
extern struct audio_driver pa_audio_driver;
+extern struct audio_driver spice_audio_driver;
extern struct audio_driver winwave_audio_driver;
extern struct mixeng_volume nominal_volume;
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
new file mode 100644
index 0000000..51ba53a
--- /dev/null
+++ b/audio/spiceaudio.c
@@ -0,0 +1,327 @@
+#include "hw/hw.h"
+#include "qemu-timer.h"
+#include "ui/qemu-spice.h"
+
+#define AUDIO_CAP "spice"
+#include "audio.h"
+#include "audio_int.h"
+
+#define LINE_IN_SAMPLES 1024
+#define LINE_OUT_SAMPLES 1024
+
+typedef struct SpiceRateCtl {
+ int64_t start_ticks;
+ int64_t bytes_sent;
+} SpiceRateCtl;
+
+typedef struct SpiceVoiceOut {
+ HWVoiceOut hw;
+ SpicePlaybackInstance sin;
+ SpiceRateCtl rate;
+ int active;
+ uint32_t *frame;
+ uint32_t *fpos;
+ uint32_t fsize;
+} SpiceVoiceOut;
+
+typedef struct SpiceVoiceIn {
+ HWVoiceIn hw;
+ SpiceRecordInstance sin;
+ SpiceRateCtl rate;
+ int active;
+ uint32_t samples[LINE_IN_SAMPLES];
+} SpiceVoiceIn;
+
+static const SpicePlaybackInterface playback_sif = {
+ .base.type = SPICE_INTERFACE_PLAYBACK,
+ .base.description = "playback",
+ .base.major_version = SPICE_INTERFACE_PLAYBACK_MAJOR,
+ .base.minor_version = SPICE_INTERFACE_PLAYBACK_MINOR,
+};
+
+static const SpiceRecordInterface record_sif = {
+ .base.type = SPICE_INTERFACE_RECORD,
+ .base.description = "record",
+ .base.major_version = SPICE_INTERFACE_RECORD_MAJOR,
+ .base.minor_version = SPICE_INTERFACE_RECORD_MINOR,
+};
+
+static void *spice_audio_init (void)
+{
+ if (!using_spice) {
+ return NULL;
+ }
+ return &spice_audio_init;
+}
+
+static void spice_audio_fini (void *opaque)
+{
+ /* nothing */
+}
+
+static void rate_start (SpiceRateCtl *rate)
+{
+ memset (rate, 0, sizeof (*rate));
+ rate->start_ticks = qemu_get_clock (vm_clock);
+}
+
+static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate)
+{
+ int64_t now;
+ int64_t ticks;
+ int64_t bytes;
+ int64_t samples;
+
+ now = qemu_get_clock (vm_clock);
+ ticks = now - rate->start_ticks;
+ bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ());
+ samples = (bytes - rate->bytes_sent) >> info->shift;
+ if (samples < 0 || samples > 65536) {
+ fprintf (stderr, "Resetting rate control (%" PRId64 " samples)\n", samples);
+ rate_start (rate);
+ samples = 0;
+ }
+ rate->bytes_sent += samples << info->shift;
+ return samples;
+}
+
+/* playback */
+
+static int line_out_init (HWVoiceOut *hw, struct audsettings *as)
+{
+ SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
+ struct audsettings settings;
+
+ settings.freq = SPICE_INTERFACE_PLAYBACK_FREQ;
+ settings.nchannels = SPICE_INTERFACE_PLAYBACK_CHAN;
+ settings.fmt = AUD_FMT_S16;
+ settings.endianness = AUDIO_HOST_ENDIANNESS;
+
+ audio_pcm_init_info (&hw->info, &settings);
+ hw->samples = LINE_OUT_SAMPLES;
+ out->active = 0;
+
+ out->sin.base.sif = &playback_sif.base;
+ qemu_spice_add_interface (&out->sin.base);
+ return 0;
+}
+
+static void line_out_fini (HWVoiceOut *hw)
+{
+ SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
+
+ spice_server_remove_interface (&out->sin.base);
+}
+
+static int line_out_run (HWVoiceOut *hw, int live)
+{
+ SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
+ int rpos, decr;
+ int samples;
+
+ if (!live) {
+ return 0;
+ }
+
+ decr = rate_get_samples (&hw->info, &out->rate);
+ decr = audio_MIN (live, decr);
+
+ samples = decr;
+ rpos = hw->rpos;
+ while (samples) {
+ int left_till_end_samples = hw->samples - rpos;
+ int len = audio_MIN (samples, left_till_end_samples);
+
+ if (!out->frame) {
+ spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize);
+ out->fpos = out->frame;
+ }
+ if (out->frame) {
+ len = audio_MIN (len, out->fsize);
+ hw->clip (out->fpos, hw->mix_buf + rpos, len);
+ out->fsize -= len;
+ out->fpos += len;
+ if (out->fsize == 0) {
+ spice_server_playback_put_samples (&out->sin, out->frame);
+ out->frame = out->fpos = NULL;
+ }
+ }
+ rpos = (rpos + len) % hw->samples;
+ samples -= len;
+ }
+ hw->rpos = rpos;
+ return decr;
+}
+
+static int line_out_write (SWVoiceOut *sw, void *buf, int len)
+{
+ return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
+{
+ SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
+
+ switch (cmd) {
+ case VOICE_ENABLE:
+ if (out->active) {
+ break;
+ }
+ out->active = 1;
+ rate_start (&out->rate);
+ spice_server_playback_start (&out->sin);
+ break;
+ case VOICE_DISABLE:
+ if (!out->active) {
+ break;
+ }
+ out->active = 0;
+ if (out->frame) {
+ memset (out->fpos, 0, out->fsize << 2);
+ spice_server_playback_put_samples (&out->sin, out->frame);
+ out->frame = out->fpos = NULL;
+ }
+ spice_server_playback_stop (&out->sin);
+ break;
+ }
+ return 0;
+}
+
+/* record */
+
+static int line_in_init (HWVoiceIn *hw, struct audsettings *as)
+{
+ SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
+ struct audsettings settings;
+
+ settings.freq = SPICE_INTERFACE_RECORD_FREQ;
+ settings.nchannels = SPICE_INTERFACE_RECORD_CHAN;
+ settings.fmt = AUD_FMT_S16;
+ settings.endianness = AUDIO_HOST_ENDIANNESS;
+
+ audio_pcm_init_info (&hw->info, &settings);
+ hw->samples = LINE_IN_SAMPLES;
+ in->active = 0;
+
+ in->sin.base.sif = &record_sif.base;
+ qemu_spice_add_interface (&in->sin.base);
+ return 0;
+}
+
+static void line_in_fini (HWVoiceIn *hw)
+{
+ SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
+
+ spice_server_remove_interface (&in->sin.base);
+}
+
+static int line_in_run (HWVoiceIn *hw)
+{
+ SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
+ int num_samples;
+ int ready;
+ int len[2];
+ uint64_t delta_samp;
+ const uint32_t *samples;
+
+ if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in (hw))) {
+ return 0;
+ }
+
+ delta_samp = rate_get_samples (&hw->info, &in->rate);
+ num_samples = audio_MIN (num_samples, delta_samp);
+
+ ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples);
+ samples = in->samples;
+ if (ready == 0) {
+ static const uint32_t silence[LINE_IN_SAMPLES];
+ samples = silence;
+ ready = LINE_IN_SAMPLES;
+ }
+
+ num_samples = audio_MIN (ready, num_samples);
+
+ if (hw->wpos + num_samples > hw->samples) {
+ len[0] = hw->samples - hw->wpos;
+ len[1] = num_samples - len[0];
+ } else {
+ len[0] = num_samples;
+ len[1] = 0;
+ }
+
+ hw->conv (hw->conv_buf + hw->wpos, samples, len[0], &nominal_volume);
+
+ if (len[1]) {
+ hw->conv (hw->conv_buf, samples + len[0], len[1],
+ &nominal_volume);
+ }
+
+ hw->wpos = (hw->wpos + num_samples) % hw->samples;
+
+ return num_samples;
+}
+
+static int line_in_read (SWVoiceIn *sw, void *buf, int size)
+{
+ return audio_pcm_sw_read (sw, buf, size);
+}
+
+static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
+{
+ SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
+
+ switch (cmd) {
+ case VOICE_ENABLE:
+ if (in->active) {
+ break;
+ }
+ in->active = 1;
+ rate_start (&in->rate);
+ spice_server_record_start (&in->sin);
+ break;
+ case VOICE_DISABLE:
+ if (!in->active) {
+ break;
+ }
+ in->active = 0;
+ spice_server_record_stop (&in->sin);
+ break;
+ }
+ return 0;
+}
+
+static struct audio_option audio_options[] = {
+ { /* end of list */ },
+};
+
+static struct audio_pcm_ops audio_callbacks = {
+ .init_out = line_out_init,
+ .fini_out = line_out_fini,
+ .run_out = line_out_run,
+ .write = line_out_write,
+ .ctl_out = line_out_ctl,
+
+ .init_in = line_in_init,
+ .fini_in = line_in_fini,
+ .run_in = line_in_run,
+ .read = line_in_read,
+ .ctl_in = line_in_ctl,
+};
+
+struct audio_driver spice_audio_driver = {
+ .name = "spice",
+ .descr = "spice audio driver",
+ .options = audio_options,
+ .init = spice_audio_init,
+ .fini = spice_audio_fini,
+ .pcm_ops = &audio_callbacks,
+ .max_voices_out = 1,
+ .max_voices_in = 1,
+ .voice_size_out = sizeof (SpiceVoiceOut),
+ .voice_size_in = sizeof (SpiceVoiceIn),
+};
+
+void qemu_spice_audio_init (void)
+{
+ spice_audio_driver.can_be_default = 1;
+}
diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h
index 063c7dc..0e3ad9b 100644
--- a/ui/qemu-spice.h
+++ b/ui/qemu-spice.h
@@ -29,6 +29,7 @@ extern int using_spice;
void qemu_spice_init(void);
void qemu_spice_input_init(void);
+void qemu_spice_audio_init(void);
void qemu_spice_display_init(DisplayState *ds);
int qemu_spice_add_interface(SpiceBaseInstance *sin);
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 6a1cf17..6c404b3 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -361,6 +361,7 @@ void qemu_spice_init(void)
using_spice = 1;
qemu_spice_input_init();
+ qemu_spice_audio_init();
qemu_free(x509_key_file);
qemu_free(x509_cert_file);
commit df0db2212d86e98c41774600c44cc960ddc2b68c
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Tue Nov 9 17:28:38 2010 +0100
intel-hda: fix codec addressing.
The HDA bus supports up to 15 codecs, with addresses 0 ... 14.
We get that wrong in two places:
* When handing out addresses we accept address 15 as valid.
* The bitmasks for two registers (WAKEEN and STATESTS) don't
have bit 14 set.
This patch fixes it.
[ v2: codestyle: add braces ]
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 5e13dc3..fe31624 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -56,8 +56,9 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
if (dev->cad == -1) {
dev->cad = bus->next_cad;
}
- if (dev->cad > 15)
+ if (dev->cad >= 15) {
return -1;
+ }
bus->next_cad = dev->cad + 1;
return info->init(dev);
}
@@ -643,15 +644,15 @@ static const struct IntelHDAReg regtab[] = {
[ ICH6_REG_WAKEEN ] = {
.name = "WAKEEN",
.size = 2,
- .wmask = 0x3fff,
+ .wmask = 0x7fff,
.offset = offsetof(IntelHDAState, wake_en),
.whandler = intel_hda_set_wake_en,
},
[ ICH6_REG_STATESTS ] = {
.name = "STATESTS",
.size = 2,
- .wmask = 0x3fff,
- .wclear = 0x3fff,
+ .wmask = 0x7fff,
+ .wclear = 0x7fff,
.offset = offsetof(IntelHDAState, state_sts),
.whandler = intel_hda_set_state_sts,
},
commit e2553eb44e4ddd0b22124216d3dd20b6a0fecefb
Author: malc <av1474 at comtv.ru>
Date: Tue Nov 9 19:14:15 2010 +0300
Revert "intel-hda: fix codec addressing."
Misses braces
This reverts commit acc086837e49b44f15eff6007bb1726844df7aec.
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index b34b140..5e13dc3 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -56,7 +56,7 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
if (dev->cad == -1) {
dev->cad = bus->next_cad;
}
- if (dev->cad >= 15)
+ if (dev->cad > 15)
return -1;
bus->next_cad = dev->cad + 1;
return info->init(dev);
@@ -643,15 +643,15 @@ static const struct IntelHDAReg regtab[] = {
[ ICH6_REG_WAKEEN ] = {
.name = "WAKEEN",
.size = 2,
- .wmask = 0x7fff,
+ .wmask = 0x3fff,
.offset = offsetof(IntelHDAState, wake_en),
.whandler = intel_hda_set_wake_en,
},
[ ICH6_REG_STATESTS ] = {
.name = "STATESTS",
.size = 2,
- .wmask = 0x7fff,
- .wclear = 0x7fff,
+ .wmask = 0x3fff,
+ .wclear = 0x3fff,
.offset = offsetof(IntelHDAState, state_sts),
.whandler = intel_hda_set_state_sts,
},
commit acc086837e49b44f15eff6007bb1726844df7aec
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Tue Nov 9 11:47:49 2010 +0100
intel-hda: fix codec addressing.
The HDA bus supports up to 15 codecs, with addresses 0 ... 14.
We get that wrong in two places:
* When handing out addresses we accept address 15 as valid.
* The bitmasks for two registers (WAKEEN and STATESTS) don't
have bit 14 set.
This patch fixes it.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 5e13dc3..b34b140 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -56,7 +56,7 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
if (dev->cad == -1) {
dev->cad = bus->next_cad;
}
- if (dev->cad > 15)
+ if (dev->cad >= 15)
return -1;
bus->next_cad = dev->cad + 1;
return info->init(dev);
@@ -643,15 +643,15 @@ static const struct IntelHDAReg regtab[] = {
[ ICH6_REG_WAKEEN ] = {
.name = "WAKEEN",
.size = 2,
- .wmask = 0x3fff,
+ .wmask = 0x7fff,
.offset = offsetof(IntelHDAState, wake_en),
.whandler = intel_hda_set_wake_en,
},
[ ICH6_REG_STATESTS ] = {
.name = "STATESTS",
.size = 2,
- .wmask = 0x3fff,
- .wclear = 0x3fff,
+ .wmask = 0x7fff,
+ .wclear = 0x7fff,
.offset = offsetof(IntelHDAState, state_sts),
.whandler = intel_hda_set_state_sts,
},
commit 17786d52acd3e18e77cd7e823f7d6bad9ece818e
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Tue Nov 9 11:47:48 2010 +0100
intel-hda: add msi support
This patch adds MSI support to the intel hda audio driver. It is
enabled by default, use '-device intel-hda,msi=0' to disable it.
[ v2: codestyle: add braces ]
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index e478e67..5e13dc3 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -19,6 +19,7 @@
#include "hw.h"
#include "pci.h"
+#include "msi.h"
#include "qemu-timer.h"
#include "audiodev.h"
#include "intel-hda.h"
@@ -188,6 +189,7 @@ struct IntelHDAState {
/* properties */
uint32_t debug;
+ uint32_t msi;
};
struct IntelHDAReg {
@@ -268,6 +270,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d)
static void intel_hda_update_irq(IntelHDAState *d)
{
+ int msi = d->msi && msi_enabled(&d->pci);
int level;
intel_hda_update_int_sts(d);
@@ -276,8 +279,15 @@ static void intel_hda_update_irq(IntelHDAState *d)
} else {
level = 0;
}
- dprint(d, 2, "%s: level %d\n", __FUNCTION__, level);
- qemu_set_irq(d->pci.irq[0], level);
+ dprint(d, 2, "%s: level %d [%s]\n", __FUNCTION__,
+ level, msi ? "msi" : "intx");
+ if (msi) {
+ if (level) {
+ msi_notify(&d->pci, 0);
+ }
+ } else {
+ qemu_set_irq(d->pci.irq[0], level);
+ }
}
static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
@@ -1148,6 +1158,9 @@ static int intel_hda_init(PCIDevice *pci)
intel_hda_mmio_write, d);
pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY,
intel_hda_map);
+ if (d->msi) {
+ msi_init(&d->pci, 0x50, 1, true, false);
+ }
hda_codec_bus_init(&d->pci.qdev, &d->codecs,
intel_hda_response, intel_hda_xfer);
@@ -1159,10 +1172,24 @@ static int intel_hda_exit(PCIDevice *pci)
{
IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+ if (d->msi) {
+ msi_uninit(&d->pci);
+ }
cpu_unregister_io_memory(d->mmio_addr);
return 0;
}
+static void intel_hda_write_config(PCIDevice *pci, uint32_t addr,
+ uint32_t val, int len)
+{
+ IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+
+ pci_default_write_config(pci, addr, val, len);
+ if (d->msi) {
+ msi_write_config(pci, addr, val, len);
+ }
+}
+
static int intel_hda_post_load(void *opaque, int version)
{
IntelHDAState* d = opaque;
@@ -1246,8 +1273,10 @@ static PCIDeviceInfo intel_hda_info = {
.qdev.reset = intel_hda_reset,
.init = intel_hda_init,
.exit = intel_hda_exit,
+ .config_write = intel_hda_write_config,
.qdev.props = (Property[]) {
DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
+ DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
DEFINE_PROP_END_OF_LIST(),
}
};
commit 6a0d02f5be44ee17cf0ce843f0658d08e97a68c2
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Tue Nov 9 11:47:47 2010 +0100
intel-hda: update irq status on WAKEEN changes.
When the guest updates the WAKEEN register we
must re-calculate the IRQ status.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 2c1ef12..e478e67 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -508,6 +508,11 @@ static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32
}
}
+static void intel_hda_set_wake_en(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+ intel_hda_update_irq(d);
+}
+
static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
{
intel_hda_update_irq(d);
@@ -630,6 +635,7 @@ static const struct IntelHDAReg regtab[] = {
.size = 2,
.wmask = 0x3fff,
.offset = offsetof(IntelHDAState, wake_en),
+ .whandler = intel_hda_set_wake_en,
},
[ ICH6_REG_STATESTS ] = {
.name = "STATESTS",
commit af93485cde810f3c2f488533e0b60c99eae5d01d
Author: François Revol <revol at free.fr>
Date: Tue Nov 9 11:47:46 2010 +0100
intel-hda: Honor WAKEEN bits.
HDA: Honor WAKEEN bits when deciding to raise an interrupt on codec
status change. This prevents an interrupt storm with the Haiku HDA
driver which does not handle codec status changes in the irq handler.
Signed-off-by: François Revol <revol at free.fr>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 78c32da..2c1ef12 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -246,7 +246,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d)
if (d->rirb_sts & ICH6_RBSTS_OVERRUN) {
sts |= (1 << 30);
}
- if (d->state_sts) {
+ if (d->state_sts & d->wake_en) {
sts |= (1 << 30);
}
@@ -628,6 +628,7 @@ static const struct IntelHDAReg regtab[] = {
[ ICH6_REG_WAKEEN ] = {
.name = "WAKEEN",
.size = 2,
+ .wmask = 0x3fff,
.offset = offsetof(IntelHDAState, wake_en),
},
[ ICH6_REG_STATESTS ] = {
commit 129dcd2c66c3f693425f8a50c553146b8f6f4fd6
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Tue Nov 9 11:47:45 2010 +0100
hda-audio: exit cleanup
Add exit callback to the driver. Unregister the sound card properly
on exit.
[ v2: codestyle: add braces ]
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index 1035774..c699d6f 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -808,6 +808,28 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
return 0;
}
+static int hda_audio_exit(HDACodecDevice *hda)
+{
+ HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+ HDAAudioStream *st;
+ int i;
+
+ dprint(a, 1, "%s\n", __FUNCTION__);
+ for (i = 0; i < ARRAY_SIZE(a->st); i++) {
+ st = a->st + i;
+ if (st->node == NULL) {
+ continue;
+ }
+ if (st->output) {
+ AUD_close_out(&a->card, st->voice.out);
+ } else {
+ AUD_close_in(&a->card, st->voice.in);
+ }
+ }
+ AUD_remove_card(&a->card);
+ return 0;
+}
+
static int hda_audio_post_load(void *opaque, int version)
{
HDAAudioState *a = opaque;
@@ -879,6 +901,7 @@ static HDACodecDeviceInfo hda_audio_info_output = {
.qdev.vmsd = &vmstate_hda_audio,
.qdev.props = hda_audio_properties,
.init = hda_audio_init_output,
+ .exit = hda_audio_exit,
.command = hda_audio_command,
.stream = hda_audio_stream,
};
@@ -890,6 +913,7 @@ static HDACodecDeviceInfo hda_audio_info_duplex = {
.qdev.vmsd = &vmstate_hda_audio,
.qdev.props = hda_audio_properties,
.init = hda_audio_init_duplex,
+ .exit = hda_audio_exit,
.command = hda_audio_command,
.stream = hda_audio_stream,
};
commit dc4b9240dc531f1fc8538e9dc968f2e34e169346
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Tue Nov 9 11:47:44 2010 +0100
intel-hda: exit cleanup
Add pci exit callback for the intel-hda device and cleanup properly.
Also add an exit callback to the HDA bus implementation and make sure
it is called on qdev_free().
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index ccb059d..78c32da 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -61,9 +61,20 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
return info->init(dev);
}
+static int hda_codec_dev_exit(DeviceState *qdev)
+{
+ HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+
+ if (dev->info->exit) {
+ dev->info->exit(dev);
+ }
+ return 0;
+}
+
void hda_codec_register(HDACodecDeviceInfo *info)
{
info->qdev.init = hda_codec_dev_init;
+ info->qdev.exit = hda_codec_dev_exit;
info->qdev.bus_info = &hda_codec_bus_info;
qdev_register(&info->qdev);
}
@@ -1137,6 +1148,14 @@ static int intel_hda_init(PCIDevice *pci)
return 0;
}
+static int intel_hda_exit(PCIDevice *pci)
+{
+ IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+
+ cpu_unregister_io_memory(d->mmio_addr);
+ return 0;
+}
+
static int intel_hda_post_load(void *opaque, int version)
{
IntelHDAState* d = opaque;
@@ -1219,6 +1238,7 @@ static PCIDeviceInfo intel_hda_info = {
.qdev.vmsd = &vmstate_intel_hda,
.qdev.reset = intel_hda_reset,
.init = intel_hda_init,
+ .exit = intel_hda_exit,
.qdev.props = (Property[]) {
DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/intel-hda.h b/hw/intel-hda.h
index ba290ec..4e44e38 100644
--- a/hw/intel-hda.h
+++ b/hw/intel-hda.h
@@ -32,6 +32,7 @@ struct HDACodecDevice {
struct HDACodecDeviceInfo {
DeviceInfo qdev;
int (*init)(HDACodecDevice *dev);
+ int (*exit)(HDACodecDevice *dev);
void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running);
};
commit cfd07e7abb1ef39373cd4ce312b015d61b9eea8d
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sun Nov 7 15:10:40 2010 +0000
Fix win32 build
Fix a return value change missed by
205ef7961f781496366e0a93a4ec621ad3724bd7.
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/block/raw-win32.c b/block/raw-win32.c
index 7f32778..06c9710 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -147,7 +147,7 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num,
return ret_count;
}
-static void raw_flush(BlockDriverState *bs)
+static int raw_flush(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
int ret;
commit d33ea50a958b2e050d2b28e5f17e3b55e91c6d74
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Oct 27 13:15:27 2010 +0200
scsi-disk: Fix immediate failure of bdrv_aio_*
Fix scsi-disk to use the usual completion paths that involve rerror/werror
handling instead of directly completing the requests in cases where
bdrv_aio_readv/writev returns NULL.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 6815239..dc71957 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -178,8 +178,9 @@ static void scsi_read_request(SCSIDiskReq *r)
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
scsi_read_complete, r);
- if (r->req.aiocb == NULL)
- scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
+ if (r->req.aiocb == NULL) {
+ scsi_read_complete(r, -EIO);
+ }
}
/* Read more data from scsi device into buffer. */
@@ -273,9 +274,9 @@ static void scsi_write_request(SCSIDiskReq *r)
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
scsi_write_complete, r);
- if (r->req.aiocb == NULL)
- scsi_command_complete(r, CHECK_CONDITION,
- HARDWARE_ERROR);
+ if (r->req.aiocb == NULL) {
+ scsi_write_complete(r, -EIO);
+ }
} else {
/* Invoke completion routine to fetch data from host. */
scsi_write_complete(r, 0);
commit 18a8d4214b861aff0caa5acfa921862d0be05bbb
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Oct 27 13:10:15 2010 +0200
virtio-blk: Handle immediate flush failure properly
Fix virtio-blk to use the usual completion path that involves werror handling
instead of directly completing the request in cases where bdrv_aio_flush
returns NULL.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index dbe2070..49528a9 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -273,7 +273,7 @@ static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
acb = bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req);
if (!acb) {
- virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
+ virtio_blk_flush_complete(req, -EIO);
}
}
commit b2df7531f3adc4f0f65067b917cef8c66ba812c5
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Oct 27 13:04:15 2010 +0200
ide: Handle immediate bdrv_aio_flush failure
If bdrv_aio_flush returns NULL, this should be treated as an error.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/ide/core.c b/hw/ide/core.c
index bc3e916..484e0ca 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -811,10 +811,16 @@ static void ide_flush_cb(void *opaque, int ret)
static void ide_flush_cache(IDEState *s)
{
- if (s->bs) {
- bdrv_aio_flush(s->bs, ide_flush_cb, s);
- } else {
+ BlockDriverAIOCB *acb;
+
+ if (s->bs == NULL) {
ide_flush_cb(s, 0);
+ return;
+ }
+
+ acb = bdrv_aio_flush(s->bs, ide_flush_cb, s);
+ if (acb == NULL) {
+ ide_flush_cb(s, -EIO);
}
}
commit a31335863648d1e707f59296cffb74205aedba96
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sat Oct 30 16:46:27 2010 +0000
block: avoid a warning on 64 bit hosts with long as int64_t
When building on a 64 bit host which uses 'long' for int64_t,
GCC emits a warning:
CC block/blkverify.o
/src/qemu/block/blkverify.c: In function `blkverify_verify_readv':
/src/qemu/block/blkverify.c:304: warning: long long int format, long
unsigned int arg (arg 3)
Rework a77cffe7e916f4dd28f2048982ea2e0d98143b11 to avoid the warning.
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/blkverify.c b/block/blkverify.c
index 0a8d691..c7522b4 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -300,8 +300,8 @@ static void blkverify_verify_readv(BlkverifyAIOCB *acb)
{
ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov);
if (offset != -1) {
- blkverify_err(acb, "contents mismatch in sector %lld",
- acb->sector_num + (offset / BDRV_SECTOR_SIZE));
+ blkverify_err(acb, "contents mismatch in sector %" PRId64,
+ acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE));
}
}
commit 1c02e2a17104fe7fc11893125864dc0daf1e6d5b
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu Oct 28 16:16:00 2010 +0200
qcow2: Invalidate cache after failed read
The cache content may be destroyed after a failed read, better not use it any
more.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 4f7dc59..b040208 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -188,6 +188,7 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
ret = bdrv_pread(bs->file, l2_offset, *l2_table,
s->l2_size * sizeof(uint64_t));
if (ret < 0) {
+ qcow2_l2_cache_reset(bs);
return ret;
}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 0efb676..a10453c 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -103,6 +103,7 @@ static int load_refcount_block(BlockDriverState *bs,
ret = bdrv_pread(bs->file, refcount_block_offset, s->refcount_block_cache,
s->cluster_size);
if (ret < 0) {
+ s->refcount_block_cache_offset = 0;
return ret;
}
commit 4a4111851fa75bc91028a26eb75dcdd136d9032d
Author: Kevin Wolf <kwolf at redhat.com>
Date: Fri Oct 22 16:17:57 2010 +0200
vpc: Implement bdrv_flush
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/vpc.c b/block/vpc.c
index e50509e..416f489 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -439,6 +439,10 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num,
return 0;
}
+static int vpc_flush(BlockDriverState *bs)
+{
+ return bdrv_flush(bs->file);
+}
/*
* Calculates the number of cylinders, heads and sectors per cylinder
@@ -618,14 +622,15 @@ static QEMUOptionParameter vpc_create_options[] = {
};
static BlockDriver bdrv_vpc = {
- .format_name = "vpc",
- .instance_size = sizeof(BDRVVPCState),
- .bdrv_probe = vpc_probe,
- .bdrv_open = vpc_open,
- .bdrv_read = vpc_read,
- .bdrv_write = vpc_write,
- .bdrv_close = vpc_close,
- .bdrv_create = vpc_create,
+ .format_name = "vpc",
+ .instance_size = sizeof(BDRVVPCState),
+ .bdrv_probe = vpc_probe,
+ .bdrv_open = vpc_open,
+ .bdrv_read = vpc_read,
+ .bdrv_write = vpc_write,
+ .bdrv_flush = vpc_flush,
+ .bdrv_close = vpc_close,
+ .bdrv_create = vpc_create,
.create_options = vpc_create_options,
};
commit 78ced65e6ec6d76059f0d943a82103122d4e6494
Author: Kevin Wolf <kwolf at redhat.com>
Date: Mon Oct 25 16:40:17 2010 +0200
scsi-disk: Implement werror for flushes
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 96acfe3..6815239 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -45,6 +45,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
#define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06
#define SCSI_REQ_STATUS_RETRY_READ 0x00
#define SCSI_REQ_STATUS_RETRY_WRITE 0x02
+#define SCSI_REQ_STATUS_RETRY_FLUSH 0x04
typedef struct SCSIDiskState SCSIDiskState;
@@ -74,6 +75,7 @@ struct SCSIDiskState
};
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
+static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf);
static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag,
uint32_t lun)
@@ -316,6 +318,8 @@ static void scsi_dma_restart_bh(void *opaque)
r = DO_UPCAST(SCSIDiskReq, req, req);
if (r->status & SCSI_REQ_STATUS_RETRY) {
int status = r->status;
+ int ret;
+
r->status &=
~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
@@ -326,6 +330,11 @@ static void scsi_dma_restart_bh(void *opaque)
case SCSI_REQ_STATUS_RETRY_WRITE:
scsi_write_request(r);
break;
+ case SCSI_REQ_STATUS_RETRY_FLUSH:
+ ret = scsi_disk_emulate_command(r, r->iov.iov_base);
+ if (ret == 0) {
+ scsi_command_complete(r, GOOD, NO_SENSE);
+ }
}
}
}
@@ -790,6 +799,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
uint64_t nb_sectors;
int buflen = 0;
+ int ret;
switch (req->cmd.buf[0]) {
case TEST_UNIT_READY:
@@ -880,7 +890,12 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
buflen = 8;
break;
case SYNCHRONIZE_CACHE:
- bdrv_flush(s->bs);
+ ret = bdrv_flush(s->bs);
+ if (ret < 0) {
+ if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
+ return -1;
+ }
+ }
break;
case GET_CONFIGURATION:
memset(outbuf, 0, 8);
commit 8af7a3ab51d9780f52b7d2581f144ab127097362
Author: Kevin Wolf <kwolf at redhat.com>
Date: Mon Oct 25 12:43:22 2010 +0200
scsi-disk: Complete failed requests in scsi_disk_emulate_command
This pulls the request completion for error cases from the caller to
scsi_disk_emulate_command. This should not change semantics, but allows to
reuse scsi_handle_write_error() for flushes in the next patch.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 43a5b59..96acfe3 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -784,8 +784,9 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
return toclen;
}
-static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
+static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
{
+ SCSIRequest *req = &r->req;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
uint64_t nb_sectors;
int buflen = 0;
@@ -943,12 +944,12 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
return buflen;
not_ready:
- scsi_req_set_status(req, CHECK_CONDITION, NOT_READY);
- return 0;
+ scsi_command_complete(r, CHECK_CONDITION, NOT_READY);
+ return -1;
illegal_request:
- scsi_req_set_status(req, CHECK_CONDITION, ILLEGAL_REQUEST);
- return 0;
+ scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
+ return -1;
}
/* Execute a scsi command. Returns the length of the data expected by the
@@ -1056,14 +1057,12 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
case REPORT_LUNS:
case VERIFY:
case REZERO_UNIT:
- rc = scsi_disk_emulate_command(&r->req, outbuf);
- if (rc > 0) {
- r->iov.iov_len = rc;
- } else {
- scsi_req_complete(&r->req);
- scsi_remove_request(r);
+ rc = scsi_disk_emulate_command(r, outbuf);
+ if (rc < 0) {
return 0;
}
+
+ r->iov.iov_len = rc;
break;
case READ_6:
case READ_10:
commit 205ef7961f781496366e0a93a4ec621ad3724bd7
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu Oct 21 16:43:43 2010 +0200
block: Allow bdrv_flush to return errors
This changes bdrv_flush to return 0 on success and -errno in case of failure.
It's a requirement for implementing proper error handle in users of bdrv_flush.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/block.c b/block.c
index 985d0b7..6b505fb 100644
--- a/block.c
+++ b/block.c
@@ -1453,14 +1453,27 @@ const char *bdrv_get_device_name(BlockDriverState *bs)
return bs->device_name;
}
-void bdrv_flush(BlockDriverState *bs)
+int bdrv_flush(BlockDriverState *bs)
{
if (bs->open_flags & BDRV_O_NO_FLUSH) {
- return;
+ return 0;
+ }
+
+ if (bs->drv && bs->drv->bdrv_flush) {
+ return bs->drv->bdrv_flush(bs);
}
- if (bs->drv && bs->drv->bdrv_flush)
- bs->drv->bdrv_flush(bs);
+ /*
+ * Some block drivers always operate in either writethrough or unsafe mode
+ * and don't support bdrv_flush therefore. Usually qemu doesn't know how
+ * the server works (because the behaviour is hardcoded or depends on
+ * server-side configuration), so we can't ensure that everything is safe
+ * on disk. Returning an error doesn't work because that would break guests
+ * even if the server operates in writethrough mode.
+ *
+ * Let's hope the user knows what he's doing.
+ */
+ return 0;
}
void bdrv_flush_all(void)
diff --git a/block.h b/block.h
index a4facf2..78ecfac 100644
--- a/block.h
+++ b/block.h
@@ -142,7 +142,7 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque);
/* Ensure contents are flushed to disk. */
-void bdrv_flush(BlockDriverState *bs);
+int bdrv_flush(BlockDriverState *bs);
void bdrv_flush_all(void);
void bdrv_close_all(void);
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 4d6ff0a..cd9eb80 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -397,9 +397,9 @@ static void blkdebug_close(BlockDriverState *bs)
}
}
-static void blkdebug_flush(BlockDriverState *bs)
+static int blkdebug_flush(BlockDriverState *bs)
{
- bdrv_flush(bs->file);
+ return bdrv_flush(bs->file);
}
static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
diff --git a/block/blkverify.c b/block/blkverify.c
index b2a12fe..0a8d691 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -116,12 +116,12 @@ static void blkverify_close(BlockDriverState *bs)
s->test_file = NULL;
}
-static void blkverify_flush(BlockDriverState *bs)
+static int blkverify_flush(BlockDriverState *bs)
{
BDRVBlkverifyState *s = bs->opaque;
/* Only flush test file, the raw file is not important */
- bdrv_flush(s->test_file);
+ return bdrv_flush(s->test_file);
}
static int64_t blkverify_getlength(BlockDriverState *bs)
diff --git a/block/cow.c b/block/cow.c
index eedcc48..4cf543c 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -282,9 +282,9 @@ exit:
return ret;
}
-static void cow_flush(BlockDriverState *bs)
+static int cow_flush(BlockDriverState *bs)
{
- bdrv_flush(bs->file);
+ return bdrv_flush(bs->file);
}
static QEMUOptionParameter cow_create_options[] = {
diff --git a/block/qcow.c b/block/qcow.c
index 816103d..9cd547d 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -910,9 +910,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
return 0;
}
-static void qcow_flush(BlockDriverState *bs)
+static int qcow_flush(BlockDriverState *bs)
{
- bdrv_flush(bs->file);
+ return bdrv_flush(bs->file);
}
static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
diff --git a/block/qcow2.c b/block/qcow2.c
index b816d87..537c479 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1148,9 +1148,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
return 0;
}
-static void qcow_flush(BlockDriverState *bs)
+static int qcow_flush(BlockDriverState *bs)
{
- bdrv_flush(bs->file);
+ return bdrv_flush(bs->file);
}
static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
diff --git a/block/raw-posix.c b/block/raw-posix.c
index d0393e0..d0960b8 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -734,10 +734,10 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
return result;
}
-static void raw_flush(BlockDriverState *bs)
+static int raw_flush(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
- qemu_fdatasync(s->fd);
+ return qemu_fdatasync(s->fd);
}
diff --git a/block/raw-win32.c b/block/raw-win32.c
index 503ed39..7f32778 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -150,7 +150,14 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num,
static void raw_flush(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
- FlushFileBuffers(s->hfile);
+ int ret;
+
+ ret = FlushFileBuffers(s->hfile);
+ if (ret != 0) {
+ return -EIO;
+ }
+
+ return 0;
}
static void raw_close(BlockDriverState *bs)
diff --git a/block/raw.c b/block/raw.c
index 9108779..1980deb 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -39,9 +39,9 @@ static void raw_close(BlockDriverState *bs)
{
}
-static void raw_flush(BlockDriverState *bs)
+static int raw_flush(BlockDriverState *bs)
{
- bdrv_flush(bs->file);
+ return bdrv_flush(bs->file);
}
static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
diff --git a/block/vdi.c b/block/vdi.c
index f72633c..3b51e53 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -900,10 +900,10 @@ static void vdi_close(BlockDriverState *bs)
{
}
-static void vdi_flush(BlockDriverState *bs)
+static int vdi_flush(BlockDriverState *bs)
{
logout("\n");
- bdrv_flush(bs->file);
+ return bdrv_flush(bs->file);
}
diff --git a/block/vmdk.c b/block/vmdk.c
index 2d4ba42..872aeba 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -823,9 +823,9 @@ static void vmdk_close(BlockDriverState *bs)
qemu_free(s->l2_cache);
}
-static void vmdk_flush(BlockDriverState *bs)
+static int vmdk_flush(BlockDriverState *bs)
{
- bdrv_flush(bs->file);
+ return bdrv_flush(bs->file);
}
diff --git a/block_int.h b/block_int.h
index 87e60b8..3c3adb5 100644
--- a/block_int.h
+++ b/block_int.h
@@ -59,7 +59,7 @@ struct BlockDriver {
const uint8_t *buf, int nb_sectors);
void (*bdrv_close)(BlockDriverState *bs);
int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
- void (*bdrv_flush)(BlockDriverState *bs);
+ int (*bdrv_flush)(BlockDriverState *bs);
int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum);
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
commit 5dba48a882c126ccc86db6506cfa6dcca97badab
Author: Kevin Wolf <kwolf at redhat.com>
Date: Mon Oct 25 14:52:21 2010 +0200
scsi-disk: Implement rerror option
This implements the rerror option for SCSI disks.
It also includes minor changes to the write path where the same code is used
that was criticized in the review for the changes to the read path required for
rerror support.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/blockdev.c b/blockdev.c
index ff7602b..6cb179a 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -314,7 +314,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
on_write_error = BLOCK_ERR_STOP_ENOSPC;
if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
- fprintf(stderr, "werror is no supported by this format\n");
+ fprintf(stderr, "werror is not supported by this format\n");
return NULL;
}
@@ -326,8 +326,8 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
on_read_error = BLOCK_ERR_REPORT;
if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
- if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) {
- fprintf(stderr, "rerror is no supported by this format\n");
+ if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) {
+ fprintf(stderr, "rerror is not supported by this format\n");
return NULL;
}
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 9628b39..43a5b59 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -41,7 +41,10 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
#define SCSI_DMA_BUF_SIZE 131072
#define SCSI_MAX_INQUIRY_LEN 256
-#define SCSI_REQ_STATUS_RETRY 0x01
+#define SCSI_REQ_STATUS_RETRY 0x01
+#define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06
+#define SCSI_REQ_STATUS_RETRY_READ 0x00
+#define SCSI_REQ_STATUS_RETRY_WRITE 0x02
typedef struct SCSIDiskState SCSIDiskState;
@@ -70,6 +73,8 @@ struct SCSIDiskState
char *serial;
};
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
+
static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag,
uint32_t lun)
{
@@ -127,34 +132,30 @@ static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
static void scsi_read_complete(void * opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+ int n;
r->req.aiocb = NULL;
if (ret) {
- DPRINTF("IO error\n");
- r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
- scsi_command_complete(r, CHECK_CONDITION, NO_SENSE);
- return;
+ if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
+ return;
+ }
}
+
DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
+ n = r->iov.iov_len / 512;
+ r->sector += n;
+ r->sector_count -= n;
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
}
-/* Read more data from scsi device into buffer. */
-static void scsi_read_data(SCSIDevice *d, uint32_t tag)
+
+static void scsi_read_request(SCSIDiskReq *r)
{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
- SCSIDiskReq *r;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t n;
- r = scsi_find_request(s, tag);
- if (!r) {
- BADF("Bad read tag 0x%x\n", tag);
- /* ??? This is the wrong error. */
- scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
- return;
- }
if (r->sector_count == (uint32_t)-1) {
DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
r->sector_count = 0;
@@ -177,29 +178,54 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
scsi_read_complete, r);
if (r->req.aiocb == NULL)
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
- r->sector += n;
- r->sector_count -= n;
}
-static int scsi_handle_write_error(SCSIDiskReq *r, int error)
+/* Read more data from scsi device into buffer. */
+static void scsi_read_data(SCSIDevice *d, uint32_t tag)
{
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
+ SCSIDiskReq *r;
+
+ r = scsi_find_request(s, tag);
+ if (!r) {
+ BADF("Bad read tag 0x%x\n", tag);
+ /* ??? This is the wrong error. */
+ scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
+ return;
+ }
+
+ /* No data transfer may already be in progress */
+ assert(r->req.aiocb == NULL);
+
+ scsi_read_request(r);
+}
+
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
+{
+ int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- BlockErrorAction action = bdrv_get_on_error(s->bs, 0);
+ BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
if (action == BLOCK_ERR_IGNORE) {
- bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, 0);
+ bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read);
return 0;
}
if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
|| action == BLOCK_ERR_STOP_ANY) {
- r->status |= SCSI_REQ_STATUS_RETRY;
- bdrv_mon_event(s->bs, BDRV_ACTION_STOP, 0);
+
+ type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK;
+ r->status |= SCSI_REQ_STATUS_RETRY | type;
+
+ bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
vm_stop(0);
} else {
+ if (type == SCSI_REQ_STATUS_RETRY_READ) {
+ r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
+ }
scsi_command_complete(r, CHECK_CONDITION,
HARDWARE_ERROR);
- bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, 0);
+ bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
}
return 1;
@@ -214,8 +240,9 @@ static void scsi_write_complete(void * opaque, int ret)
r->req.aiocb = NULL;
if (ret) {
- if (scsi_handle_write_error(r, -ret))
+ if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
return;
+ }
}
n = r->iov.iov_len / 512;
@@ -268,8 +295,8 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag)
return 1;
}
- if (r->req.aiocb)
- BADF("Data transfer already in progress\n");
+ /* No data transfer may already be in progress */
+ assert(r->req.aiocb == NULL);
scsi_write_request(r);
@@ -288,8 +315,18 @@ static void scsi_dma_restart_bh(void *opaque)
QTAILQ_FOREACH(req, &s->qdev.requests, next) {
r = DO_UPCAST(SCSIDiskReq, req, req);
if (r->status & SCSI_REQ_STATUS_RETRY) {
- r->status &= ~SCSI_REQ_STATUS_RETRY;
- scsi_write_request(r);
+ int status = r->status;
+ r->status &=
+ ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
+
+ switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) {
+ case SCSI_REQ_STATUS_RETRY_READ:
+ scsi_read_request(r);
+ break;
+ case SCSI_REQ_STATUS_RETRY_WRITE:
+ scsi_write_request(r);
+ break;
+ }
}
}
}
@@ -1152,11 +1189,6 @@ static int scsi_disk_initfn(SCSIDevice *dev)
return -1;
}
- if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
- error_report("Device doesn't support drive option rerror");
- return -1;
- }
-
if (!s->serial) {
/* try to fall back to value set with legacy -drive serial=... */
dinfo = drive_get_by_blockdev(s->bs);
commit 5fc9cfedfa09199e10b5f9b67dcd286bfeae4f7a
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date: Mon Nov 1 20:02:23 2010 +0100
Fold send_all() wrapper unix_write() into one function
The current send_all() wrapper for POSIX calls does nothing but call
unix_write(). Merge them to simplify the code.
Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/qemu-char.c b/qemu-char.c
index 6d2dce7..88997f9 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -508,9 +508,10 @@ int send_all(int fd, const void *buf, int len1)
#else
-static int unix_write(int fd, const uint8_t *buf, int len1)
+int send_all(int fd, const void *_buf, int len1)
{
int ret, len;
+ const uint8_t *buf = _buf;
len = len1;
while (len > 0) {
@@ -527,11 +528,6 @@ static int unix_write(int fd, const uint8_t *buf, int len1)
}
return len1 - len;
}
-
-int send_all(int fd, const void *buf, int len1)
-{
- return unix_write(fd, buf, len1);
-}
#endif /* !_WIN32 */
#ifndef _WIN32
commit 07de3e60b05d13f255d12f8dfac8e3b1e5e34d7d
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date: Thu Oct 21 17:15:49 2010 +0200
Remove obsolete 'f' double parameter type
'f' double is no longer used, and we should be using floating point
variables to store byte sizes. Remove it.
Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/monitor.c b/monitor.c
index be8761a..8cee35d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -83,10 +83,6 @@
* suffix, which multiplies the value by 2^40 for
* suffixes T and t, 2^30 for suffixes G and g, 2^20 for
* M and m, 2^10 for K and k
- * 'f' double
- * user mode accepts an optional G, g, M, m, K, k suffix,
- * which multiplies the value by 2^30 for suffixes G and
- * g, 2^20 for M and m, 2^10 for K and k
* 'T' double
* user mode accepts an optional ms, us, ns suffix,
* which divides the value by 1e3, 1e6, 1e9, respectively
@@ -3731,7 +3727,6 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
p = end;
}
break;
- case 'f':
case 'T':
{
double val;
@@ -3747,17 +3742,7 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
if (get_double(mon, &val, &p) < 0) {
goto fail;
}
- if (c == 'f' && *p) {
- switch (*p) {
- case 'K': case 'k':
- val *= 1 << 10; p++; break;
- case 'M': case 'm':
- val *= 1 << 20; p++; break;
- case 'G': case 'g':
- val *= 1 << 30; p++; break;
- }
- }
- if (c == 'T' && p[0] && p[1] == 's') {
+ if (p[0] && p[1] == 's') {
switch (*p) {
case 'm':
val /= 1e3; p += 2; break;
@@ -4240,7 +4225,6 @@ static int check_client_args_type(const QDict *client_args,
return -1;
}
break;
- case 'f':
case 'T':
if (qobject_type(client_arg) != QTYPE_QINT &&
qobject_type(client_arg) != QTYPE_QFLOAT) {
commit ed3d4a8075ac6f2437e100bc063bad82ff3a8671
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date: Thu Oct 21 17:15:48 2010 +0200
Switch migrate_set_speed() to take an 'o' argument rather than a float.
Clarify default value of MB in migration speed argument in monitor, if
no suffix is specified. This differ from previous default of bytes,
but is consistent with the rest of the places where we accept a size
argument.
Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 81999aa..e5585ba 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -754,9 +754,10 @@ ETEXI
{
.name = "migrate_set_speed",
- .args_type = "value:f",
+ .args_type = "value:o",
.params = "value",
- .help = "set maximum speed (in bytes) for migrations",
+ .help = "set maximum speed (in bytes) for migrations. "
+ "Defaults to MB if no size suffix is specified, ie. B/K/M/G/T",
.user_print = monitor_user_noop,
.mhandler.cmd_new = do_migrate_set_speed,
},
diff --git a/migration.c b/migration.c
index 468d517..9ee8b17 100644
--- a/migration.c
+++ b/migration.c
@@ -132,10 +132,10 @@ int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
- double d;
+ int64_t d;
FdMigrationState *s;
- d = qdict_get_double(qdict, "value");
+ d = qdict_get_int(qdict, "value");
d = MAX(0, MIN(UINT32_MAX, d));
max_throttle = d;
commit dbc0c67faff9f44ff6917eb4157a9c471902a453
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date: Thu Oct 21 17:15:47 2010 +0200
Add support for 'o' octet (bytes) format as monitor parameter.
Octet format relies on strtosz which supports K/k, M/m, G/g, T/t
suffixes and unit support for humans, like 1.3G
Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/monitor.c b/monitor.c
index 61607c5..be8761a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -78,6 +78,11 @@
* 'l' target long (32 or 64 bit)
* 'M' just like 'l', except in user mode the value is
* multiplied by 2^20 (think Mebibyte)
+ * 'o' octets (aka bytes)
+ * user mode accepts an optional T, t, G, g, M, m, K, k
+ * suffix, which multiplies the value by 2^40 for
+ * suffixes T and t, 2^30 for suffixes G and g, 2^20 for
+ * M and m, 2^10 for K and k
* 'f' double
* user mode accepts an optional G, g, M, m, K, k suffix,
* which multiplies the value by 2^30 for suffixes G and
@@ -3703,6 +3708,29 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
qdict_put(qdict, key, qint_from_int(val));
}
break;
+ case 'o':
+ {
+ ssize_t val;
+ char *end;
+
+ while (qemu_isspace(*p)) {
+ p++;
+ }
+ if (*typestr == '?') {
+ typestr++;
+ if (*p == '\0') {
+ break;
+ }
+ }
+ val = strtosz(p, &end);
+ if (val < 0) {
+ monitor_printf(mon, "invalid size\n");
+ goto fail;
+ }
+ qdict_put(qdict, key, qint_from_int(val));
+ p = end;
+ }
+ break;
case 'f':
case 'T':
{
@@ -4205,6 +4233,7 @@ static int check_client_args_type(const QDict *client_args,
case 'i':
case 'l':
case 'M':
+ case 'o':
if (qobject_type(client_arg) != QTYPE_QINT) {
qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
"int");
commit 9f9b17a4f0865286391e4d3a0a735230122a2289
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date: Thu Oct 21 17:15:46 2010 +0200
Introduce strtosz() library function to convert a string to a byte count.
strtosz() returns -1 on error. It now supports human unit formats in
eg. 1.0G, with better error handling.
The following suffixes are supported:
B/b = bytes
K/k = KB
M/m = MB
G/g = GB
T/t = TB
This patch changes -numa and -m input to use strtosz().
Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/cutils.c b/cutils.c
index 5883737..28089aa 100644
--- a/cutils.c
+++ b/cutils.c
@@ -23,6 +23,7 @@
*/
#include "qemu-common.h"
#include "host-utils.h"
+#include <math.h>
void pstrcpy(char *buf, int buf_size, const char *str)
{
@@ -283,3 +284,90 @@ int fcntl_setfl(int fd, int flag)
}
#endif
+/*
+ * Convert string to bytes, allowing either B/b for bytes, K/k for KB,
+ * M/m for MB, G/g for GB or T/t for TB. Default without any postfix
+ * is MB. End pointer will be returned in *end, if not NULL. A valid
+ * value must be terminated by whitespace, ',' or '\0'. Return -1 on
+ * error.
+ */
+ssize_t strtosz(const char *nptr, char **end)
+{
+ ssize_t retval = -1;
+ char *endptr, c;
+ int mul_required = 0;
+ double val, mul, integral, fraction;
+
+ errno = 0;
+ val = strtod(nptr, &endptr);
+ if (isnan(val) || endptr == nptr || errno != 0) {
+ goto fail;
+ }
+ integral = modf(val, &fraction);
+ if (integral != 0) {
+ mul_required = 1;
+ }
+ /*
+ * Any whitespace character is fine for terminating the number,
+ * in addition we accept ',' to handle strings where the size is
+ * part of a multi token argument.
+ */
+ c = *endptr;
+ if (isspace(c) || c == '\0' || c == ',') {
+ c = 0;
+ }
+ switch (c) {
+ case 'B':
+ case 'b':
+ mul = 1;
+ if (mul_required) {
+ goto fail;
+ }
+ break;
+ case 'K':
+ case 'k':
+ mul = 1 << 10;
+ break;
+ case 0:
+ if (mul_required) {
+ goto fail;
+ }
+ case 'M':
+ case 'm':
+ mul = 1ULL << 20;
+ break;
+ case 'G':
+ case 'g':
+ mul = 1ULL << 30;
+ break;
+ case 'T':
+ case 't':
+ mul = 1ULL << 40;
+ break;
+ default:
+ goto fail;
+ }
+ /*
+ * If not terminated by whitespace, ',', or \0, increment endptr
+ * to point to next character, then check that we are terminated
+ * by an appropriate separating character, ie. whitespace, ',', or
+ * \0. If not, we are seeing trailing garbage, thus fail.
+ */
+ if (c != 0) {
+ endptr++;
+ if (!isspace(*endptr) && *endptr != ',' && *endptr != 0) {
+ goto fail;
+ }
+ }
+ if ((val * mul >= ~(size_t)0) || val < 0) {
+ goto fail;
+ }
+ retval = val * mul;
+
+fail:
+ if (end) {
+ *end = endptr;
+ }
+
+ return retval;
+}
diff --git a/qemu-common.h b/qemu-common.h
index 21fc3a5..b3957f1 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -149,6 +149,7 @@ time_t mktimegm(struct tm *tm);
int qemu_fls(int i);
int qemu_fdatasync(int fd);
int fcntl_setfl(int fd, int flag);
+ssize_t strtosz(const char *nptr, char **end);
/* path.c */
void init_paths(const char *prefix);
diff --git a/vl.c b/vl.c
index 7038952..c58583d 100644
--- a/vl.c
+++ b/vl.c
@@ -710,16 +710,13 @@ static void numa_add(const char *optarg)
if (get_param_value(option, 128, "mem", optarg) == 0) {
node_mem[nodenr] = 0;
} else {
- value = strtoull(option, &endptr, 0);
- switch (*endptr) {
- case 0: case 'M': case 'm':
- value <<= 20;
- break;
- case 'G': case 'g':
- value <<= 30;
- break;
+ ssize_t sval;
+ sval = strtosz(option, NULL);
+ if (sval < 0) {
+ fprintf(stderr, "qemu: invalid numa mem size: %s\n", optarg);
+ exit(1);
}
- node_mem[nodenr] = value;
+ node_mem[nodenr] = sval;
}
if (get_param_value(option, 128, "cpus", optarg) == 0) {
node_cpumask[nodenr] = 0;
@@ -2139,18 +2136,10 @@ int main(int argc, char **argv, char **envp)
exit(0);
break;
case QEMU_OPTION_m: {
- uint64_t value;
- char *ptr;
+ ssize_t value;
- value = strtoul(optarg, &ptr, 10);
- switch (*ptr) {
- case 0: case 'M': case 'm':
- value <<= 20;
- break;
- case 'G': case 'g':
- value <<= 30;
- break;
- default:
+ value = strtosz(optarg, NULL);
+ if (value < 0) {
fprintf(stderr, "qemu: invalid ram size: %s\n", optarg);
exit(1);
}
commit 7466bc49107fbd84336ba680f860d5eadd6def13
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Oct 14 16:55:01 2010 +0200
spice-display: replace private lock with qemu mutex.
qemu_spice_create_update() must aquire the global qemu mutex to
make sure DisplayState doesn't change while we are accessing it.
Once this is in place the private lock is pretty pointless as
everything it protects is covered by the global qemu mutex now.
Drop it.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 7b4f5c1..020b423 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -64,10 +64,10 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
/*
* Called from spice server thread context (via interface_get_command).
- * We do *not* hold the global qemu mutex here, so extra care is needed
- * when calling qemu functions. Qemu interfaces used:
- * - pflib (is re-entrant).
- * - qemu_malloc (underlying glibc malloc is re-entrant).
+ *
+ * We must aquire the global qemu mutex here to make sure the
+ * DisplayState (+DisplaySurface) we are accessing doesn't change
+ * underneath us.
*/
SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
{
@@ -78,11 +78,12 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
uint8_t *src, *dst;
int by, bw, bh;
+ qemu_mutex_lock_iothread();
if (qemu_spice_rect_is_empty(&ssd->dirty)) {
+ qemu_mutex_unlock_iothread();
return NULL;
};
- pthread_mutex_lock(&ssd->lock);
dprint(2, "%s: lr %d -> %d, tb -> %d -> %d\n", __FUNCTION__,
ssd->dirty.left, ssd->dirty.right,
ssd->dirty.top, ssd->dirty.bottom);
@@ -140,7 +141,7 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
cmd->data = (intptr_t)drawable;
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
- pthread_mutex_unlock(&ssd->lock);
+ qemu_mutex_unlock_iothread();
return update;
}
@@ -184,14 +185,19 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
surface.type = 0;
surface.mem = (intptr_t)ssd->buf;
surface.group_id = MEMSLOT_GROUP_HOST;
+
+ qemu_mutex_unlock_iothread();
ssd->worker->create_primary_surface(ssd->worker, 0, &surface);
+ qemu_mutex_lock_iothread();
}
void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
{
dprint(1, "%s:\n", __FUNCTION__);
+ qemu_mutex_unlock_iothread();
ssd->worker->destroy_primary_surface(ssd->worker, 0);
+ qemu_mutex_lock_iothread();
}
void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
@@ -201,7 +207,9 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
if (running) {
ssd->worker->start(ssd->worker);
} else {
+ qemu_mutex_unlock_iothread();
ssd->worker->stop(ssd->worker);
+ qemu_mutex_lock_iothread();
}
ssd->running = running;
}
@@ -219,31 +227,25 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
update_area.top = y;
update_area.bottom = y + h;
- pthread_mutex_lock(&ssd->lock);
if (qemu_spice_rect_is_empty(&ssd->dirty)) {
ssd->notify++;
}
qemu_spice_rect_union(&ssd->dirty, &update_area);
- pthread_mutex_unlock(&ssd->lock);
}
void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
{
dprint(1, "%s:\n", __FUNCTION__);
- pthread_mutex_lock(&ssd->lock);
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
qemu_pf_conv_put(ssd->conv);
ssd->conv = NULL;
- pthread_mutex_unlock(&ssd->lock);
qemu_spice_destroy_host_primary(ssd);
qemu_spice_create_host_primary(ssd);
- pthread_mutex_lock(&ssd->lock);
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
ssd->notify++;
- pthread_mutex_unlock(&ssd->lock);
}
void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
@@ -398,7 +400,6 @@ void qemu_spice_display_init(DisplayState *ds)
sdpy.ds = ds;
sdpy.bufsize = (16 * 1024 * 1024);
sdpy.buf = qemu_malloc(sdpy.bufsize);
- pthread_mutex_init(&sdpy.lock, NULL);
register_displaychangelistener(ds, &display_listener);
sdpy.qxl.base.sif = &dpy_interface.base;
diff --git a/ui/spice-display.h b/ui/spice-display.h
index e17671c..aef0464 100644
--- a/ui/spice-display.h
+++ b/ui/spice-display.h
@@ -40,7 +40,6 @@ typedef struct SimpleSpiceDisplay {
uint32_t unique;
QemuPfConv *conv;
- pthread_mutex_t lock;
QXLRect dirty;
int notify;
int running;
commit f61d69607d58a81944a4bfcfc1f260d09a686460
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Tue Nov 2 12:21:50 2010 +0100
spice-core: fix warning when building with spice < 0.6.0
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 45807ed..e97a72d 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -240,7 +240,7 @@ void qemu_spice_init(void)
char *x509_key_file = NULL,
*x509_cert_file = NULL,
*x509_cacert_file = NULL;
- int port, tls_port, len, addr_flags, streaming_video;
+ int port, tls_port, len, addr_flags;
spice_image_compression_t compression;
spice_wan_compression_t wan_compr;
@@ -344,7 +344,7 @@ void qemu_spice_init(void)
str = qemu_opt_get(opts, "streaming-video");
if (str) {
- streaming_video = parse_stream_video(str);
+ int streaming_video = parse_stream_video(str);
spice_server_set_streaming_video(spice_server, streaming_video);
}
commit 3d6d306c104abe37610184f12e9342fcbc078395
Author: Hans de Goede <hdegoede at redhat.com>
Date: Fri Oct 15 09:47:53 2010 +0200
spice-core: fix watching for write events
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 6a1cf17..45807ed 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -95,7 +95,7 @@ static void watch_update_mask(SpiceWatch *watch, int event_mask)
on_read = watch_read;
}
if (watch->event_mask & SPICE_WATCH_EVENT_WRITE) {
- on_read = watch_write;
+ on_write = watch_write;
}
qemu_set_fd_handler(watch->fd, on_read, on_write, watch);
}
commit 7d72e76228351d18a856f1e4f5365b59d3205dc3
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon Nov 1 16:57:48 2010 +0100
intel-hda: documentation update
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/qemu-doc.texi b/qemu-doc.texi
index c376529..7ce8999 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -200,6 +200,8 @@ ENSONIQ AudioPCI ES1370 sound card
@item
Intel 82801AA AC97 Audio compatible sound card
@item
+Intel HD Audio Controller and HDA codec
+ at item
Adlib(OPL2) - Yamaha YM3812 compatible chip
@item
Gravis Ultrasound GF1 sound card
diff --git a/qemu-options.hx b/qemu-options.hx
index 9e38dfb..4d99a58 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -393,6 +393,7 @@ available sound hardware.
qemu -soundhw sb16,adlib disk.img
qemu -soundhw es1370 disk.img
qemu -soundhw ac97 disk.img
+qemu -soundhw hda disk.img
qemu -soundhw all disk.img
qemu -soundhw ?
@end example
commit e14056ad0573282513f15081be0ce9dc51e09426
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Mon Nov 1 18:09:38 2010 +0000
Fix out of tree build
df2943ba3c73ca21dbda063f15fa3e80064af864 broke out of tree build.
Fix breakage by adding $(SRC_PATH).
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/Makefile b/Makefile
index ec8a6bc..02698e9 100644
--- a/Makefile
+++ b/Makefile
@@ -71,7 +71,7 @@ build-all: $(DOCS) $(TOOLS) recurse-all
config-host.h: config-host.h-timestamp
config-host.h-timestamp: config-host.mak
-qemu-options.def: qemu-options.hx
+qemu-options.def: $(SRC_PATH)/qemu-options.hx
$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $@")
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
commit 2d8418ba8a3ab976fd7f9749f24aab8408643a02
Merge: 4f25ac5... 84a23f2...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Nov 1 13:02:56 2010 -0500
Merge remote branch 'spice/config.2' into staging
commit 4f25ac5f425d435d0c841ab876adfb541cb521a3
Merge: 9fe5497... b907b69...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Nov 1 10:33:45 2010 -0500
Merge remote branch 'mst/for_anthony' into staging
commit 9fe5497c4f5425c6d593c3f038e8e5bffc32edd6
Author: malc <av1474 at comtv.ru>
Date: Mon Nov 1 17:44:23 2010 +0300
hda-audio: Zap tabs
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index a21f9a1..1035774 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -559,9 +559,9 @@ static void hda_audio_set_amp(HDAAudioStream *st)
right = right * 255 / QEMU_HDA_AMP_STEPS;
if (st->output) {
- AUD_set_volume_out(st->voice.out, muted, left, right);
+ AUD_set_volume_out(st->voice.out, muted, left, right);
} else {
- AUD_set_volume_in(st->voice.in, muted, left, right);
+ AUD_set_volume_in(st->voice.in, muted, left, right);
}
}
commit d61a4ce8f01ac9f1810380e043db467d536eeb6b
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon Nov 1 13:05:32 2010 +0100
Add Intel HD Audio support to qemu.
This patch adds three devices to qemu:
intel-hda
Intel HD Audio Controller, the PCI device. Provides a HDA bus.
Emulates ICH6 at the moment. Adding a ICH9 PCIE
variant shouldn't be hard.
hda-duplex
HDA Codec. Attaches to the HDA bus. Supports 16bit stereo,
rates 16k -> 96k, playback, recording and volume control
(with CONFIG_MIXEMU=y).
hda-output
HDA Codec without recording support. Subset of the hda-duplex
codec. Use this if you don't want your guests access your mic.
Usage: add '-device intel-hda -device hda-duplex' to your command line.
Tested guests:
* Linux works.
* Win7 works.
* DOS (mpxplay) works.
* WinXP doesn't work.
[ v2 changes ]
* Fixed endianess, big endian hosts work now.
* Fixed some emulation bugs.
* Added immediate command emulation.
* Added vmstate support.
* Make it behave like all other sound card drivers:
- can be configured via '--audio-card-list=hda'
- can be added to a VM using '-soundhw hda'
* Code style fixups.
* Zapped guest-triggerable asserts.
* Handle partial reads/writes of audio data correctly.
Cc: malc <av1474 at comtv.ru>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/Makefile.objs b/Makefile.objs
index c88e82d..0f9142f 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -253,6 +253,7 @@ sound-obj-$(CONFIG_AC97) += ac97.o
sound-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o
sound-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o
sound-obj-$(CONFIG_CS4231A) += cs4231a.o
+sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
diff --git a/arch_init.c b/arch_init.c
index a910033..cea3c8b 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -499,6 +499,16 @@ struct soundhw soundhw[] = {
},
#endif
+#ifdef CONFIG_HDA
+ {
+ "hda",
+ "Intel HD Audio",
+ 0,
+ 0,
+ { .init_pci = intel_hda_and_codec_init }
+ },
+#endif
+
#endif /* HAS_AUDIO_CHOICE */
{ NULL, NULL, 0, 0, { NULL } }
diff --git a/configure b/configure
index f62c1fe..7025d2b 100755
--- a/configure
+++ b/configure
@@ -76,8 +76,8 @@ sparc_cpu=""
cross_prefix=""
cc="gcc"
audio_drv_list=""
-audio_card_list="ac97 es1370 sb16"
-audio_possible_cards="ac97 es1370 sb16 cs4231a adlib gus"
+audio_card_list="ac97 es1370 sb16 hda"
+audio_possible_cards="ac97 es1370 sb16 cs4231a adlib gus hda"
block_drv_whitelist=""
host_cc="gcc"
ar="ar"
diff --git a/hw/audiodev.h b/hw/audiodev.h
index 39a729b..8e930b2 100644
--- a/hw/audiodev.h
+++ b/hw/audiodev.h
@@ -15,3 +15,6 @@ int ac97_init(PCIBus *buf);
/* cs4231a.c */
int cs4231a_init(qemu_irq *pic);
+
+/* intel-hda.c + hda-audio.c */
+int intel_hda_and_codec_init(PCIBus *bus);
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
new file mode 100644
index 0000000..a21f9a1
--- /dev/null
+++ b/hw/hda-audio.c
@@ -0,0 +1,902 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * written by Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "pci.h"
+#include "intel-hda.h"
+#include "intel-hda-defs.h"
+#include "audio/audio.h"
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct desc_param {
+ uint32_t id;
+ uint32_t val;
+} desc_param;
+
+typedef struct desc_node {
+ uint32_t nid;
+ const char *name;
+ const desc_param *params;
+ uint32_t nparams;
+ uint32_t config;
+ uint32_t pinctl;
+ uint32_t *conn;
+ uint32_t stindex;
+} desc_node;
+
+typedef struct desc_codec {
+ const char *name;
+ uint32_t iid;
+ const desc_node *nodes;
+ uint32_t nnodes;
+} desc_codec;
+
+static const desc_param* hda_codec_find_param(const desc_node *node, uint32_t id)
+{
+ int i;
+
+ for (i = 0; i < node->nparams; i++) {
+ if (node->params[i].id == id) {
+ return &node->params[i];
+ }
+ }
+ return NULL;
+}
+
+static const desc_node* hda_codec_find_node(const desc_codec *codec, uint32_t nid)
+{
+ int i;
+
+ for (i = 0; i < codec->nnodes; i++) {
+ if (codec->nodes[i].nid == nid) {
+ return &codec->nodes[i];
+ }
+ }
+ return NULL;
+}
+
+static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
+{
+ if (format & AC_FMT_TYPE_NON_PCM) {
+ return;
+ }
+
+ as->freq = (format & AC_FMT_BASE_44K) ? 44100 : 48000;
+
+ switch ((format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT) {
+ case 1: as->freq *= 2; break;
+ case 2: as->freq *= 3; break;
+ case 3: as->freq *= 4; break;
+ }
+
+ switch ((format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT) {
+ case 1: as->freq /= 2; break;
+ case 2: as->freq /= 3; break;
+ case 3: as->freq /= 4; break;
+ case 4: as->freq /= 5; break;
+ case 5: as->freq /= 6; break;
+ case 6: as->freq /= 7; break;
+ case 7: as->freq /= 8; break;
+ }
+
+ switch (format & AC_FMT_BITS_MASK) {
+ case AC_FMT_BITS_8: as->fmt = AUD_FMT_S8; break;
+ case AC_FMT_BITS_16: as->fmt = AUD_FMT_S16; break;
+ case AC_FMT_BITS_32: as->fmt = AUD_FMT_S32; break;
+ }
+
+ as->nchannels = ((format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT) + 1;
+}
+
+/* -------------------------------------------------------------------------- */
+/*
+ * HDA codec descriptions
+ */
+
+/* some defines */
+
+#define QEMU_HDA_ID_VENDOR 0x1af4
+#define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x10)
+#define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x20)
+
+#define QEMU_HDA_PCM_FORMATS (AC_SUPPCM_BITS_16 | \
+ 0x1fc /* 16 -> 96 kHz */)
+#define QEMU_HDA_AMP_NONE (0)
+#define QEMU_HDA_AMP_STEPS 0x4a
+
+#ifdef CONFIG_MIXEMU
+#define QEMU_HDA_AMP_CAPS \
+ (AC_AMPCAP_MUTE | \
+ (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT) | \
+ (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) | \
+ (3 << AC_AMPCAP_STEP_SIZE_SHIFT))
+#else
+#define QEMU_HDA_AMP_CAPS QEMU_HDA_AMP_NONE
+#endif
+
+/* common: audio output widget */
+static const desc_param common_params_audio_dac[] = {
+ {
+ .id = AC_PAR_AUDIO_WIDGET_CAP,
+ .val = ((AC_WID_AUD_OUT << AC_WCAP_TYPE_SHIFT) |
+ AC_WCAP_FORMAT_OVRD |
+ AC_WCAP_AMP_OVRD |
+ AC_WCAP_OUT_AMP |
+ AC_WCAP_STEREO),
+ },{
+ .id = AC_PAR_PCM,
+ .val = QEMU_HDA_PCM_FORMATS,
+ },{
+ .id = AC_PAR_STREAM,
+ .val = AC_SUPFMT_PCM,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_CAPS,
+ },
+};
+
+/* common: pin widget (line-out) */
+static const desc_param common_params_audio_lineout[] = {
+ {
+ .id = AC_PAR_AUDIO_WIDGET_CAP,
+ .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
+ AC_WCAP_CONN_LIST |
+ AC_WCAP_STEREO),
+ },{
+ .id = AC_PAR_PIN_CAP,
+ .val = AC_PINCAP_OUT,
+ },{
+ .id = AC_PAR_CONNLIST_LEN,
+ .val = 1,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },
+};
+
+/* output: root node */
+static const desc_param output_params_root[] = {
+ {
+ .id = AC_PAR_VENDOR_ID,
+ .val = QEMU_HDA_ID_OUTPUT,
+ },{
+ .id = AC_PAR_SUBSYSTEM_ID,
+ .val = QEMU_HDA_ID_OUTPUT,
+ },{
+ .id = AC_PAR_REV_ID,
+ .val = 0x00100101,
+ },{
+ .id = AC_PAR_NODE_COUNT,
+ .val = 0x00010001,
+ },
+};
+
+/* output: audio function */
+static const desc_param output_params_audio_func[] = {
+ {
+ .id = AC_PAR_FUNCTION_TYPE,
+ .val = AC_GRP_AUDIO_FUNCTION,
+ },{
+ .id = AC_PAR_SUBSYSTEM_ID,
+ .val = QEMU_HDA_ID_OUTPUT,
+ },{
+ .id = AC_PAR_NODE_COUNT,
+ .val = 0x00020002,
+ },{
+ .id = AC_PAR_PCM,
+ .val = QEMU_HDA_PCM_FORMATS,
+ },{
+ .id = AC_PAR_STREAM,
+ .val = AC_SUPFMT_PCM,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_GPIO_CAP,
+ .val = 0,
+ },{
+ .id = AC_PAR_AUDIO_FG_CAP,
+ .val = 0x00000808,
+ },{
+ .id = AC_PAR_POWER_STATE,
+ .val = 0,
+ },
+};
+
+/* output: nodes */
+static const desc_node output_nodes[] = {
+ {
+ .nid = AC_NODE_ROOT,
+ .name = "root",
+ .params = output_params_root,
+ .nparams = ARRAY_SIZE(output_params_root),
+ },{
+ .nid = 1,
+ .name = "func",
+ .params = output_params_audio_func,
+ .nparams = ARRAY_SIZE(output_params_audio_func),
+ },{
+ .nid = 2,
+ .name = "dac",
+ .params = common_params_audio_dac,
+ .nparams = ARRAY_SIZE(common_params_audio_dac),
+ .stindex = 0,
+ },{
+ .nid = 3,
+ .name = "out",
+ .params = common_params_audio_lineout,
+ .nparams = ARRAY_SIZE(common_params_audio_lineout),
+ .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+ (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) |
+ (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+ (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) |
+ 0x10),
+ .pinctl = AC_PINCTL_OUT_EN,
+ .conn = (uint32_t[]) { 2 },
+ }
+};
+
+/* output: codec */
+static const desc_codec output = {
+ .name = "output",
+ .iid = QEMU_HDA_ID_OUTPUT,
+ .nodes = output_nodes,
+ .nnodes = ARRAY_SIZE(output_nodes),
+};
+
+/* duplex: root node */
+static const desc_param duplex_params_root[] = {
+ {
+ .id = AC_PAR_VENDOR_ID,
+ .val = QEMU_HDA_ID_DUPLEX,
+ },{
+ .id = AC_PAR_SUBSYSTEM_ID,
+ .val = QEMU_HDA_ID_DUPLEX,
+ },{
+ .id = AC_PAR_REV_ID,
+ .val = 0x00100101,
+ },{
+ .id = AC_PAR_NODE_COUNT,
+ .val = 0x00010001,
+ },
+};
+
+/* duplex: audio input widget */
+static const desc_param duplex_params_audio_adc[] = {
+ {
+ .id = AC_PAR_AUDIO_WIDGET_CAP,
+ .val = ((AC_WID_AUD_IN << AC_WCAP_TYPE_SHIFT) |
+ AC_WCAP_CONN_LIST |
+ AC_WCAP_FORMAT_OVRD |
+ AC_WCAP_AMP_OVRD |
+ AC_WCAP_IN_AMP |
+ AC_WCAP_STEREO),
+ },{
+ .id = AC_PAR_CONNLIST_LEN,
+ .val = 1,
+ },{
+ .id = AC_PAR_PCM,
+ .val = QEMU_HDA_PCM_FORMATS,
+ },{
+ .id = AC_PAR_STREAM,
+ .val = AC_SUPFMT_PCM,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_CAPS,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },
+};
+
+/* duplex: pin widget (line-in) */
+static const desc_param duplex_params_audio_linein[] = {
+ {
+ .id = AC_PAR_AUDIO_WIDGET_CAP,
+ .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
+ AC_WCAP_STEREO),
+ },{
+ .id = AC_PAR_PIN_CAP,
+ .val = AC_PINCAP_IN,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },
+};
+
+/* duplex: audio function */
+static const desc_param duplex_params_audio_func[] = {
+ {
+ .id = AC_PAR_FUNCTION_TYPE,
+ .val = AC_GRP_AUDIO_FUNCTION,
+ },{
+ .id = AC_PAR_SUBSYSTEM_ID,
+ .val = QEMU_HDA_ID_DUPLEX,
+ },{
+ .id = AC_PAR_NODE_COUNT,
+ .val = 0x00020004,
+ },{
+ .id = AC_PAR_PCM,
+ .val = QEMU_HDA_PCM_FORMATS,
+ },{
+ .id = AC_PAR_STREAM,
+ .val = AC_SUPFMT_PCM,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_GPIO_CAP,
+ .val = 0,
+ },{
+ .id = AC_PAR_AUDIO_FG_CAP,
+ .val = 0x00000808,
+ },{
+ .id = AC_PAR_POWER_STATE,
+ .val = 0,
+ },
+};
+
+/* duplex: nodes */
+static const desc_node duplex_nodes[] = {
+ {
+ .nid = AC_NODE_ROOT,
+ .name = "root",
+ .params = duplex_params_root,
+ .nparams = ARRAY_SIZE(duplex_params_root),
+ },{
+ .nid = 1,
+ .name = "func",
+ .params = duplex_params_audio_func,
+ .nparams = ARRAY_SIZE(duplex_params_audio_func),
+ },{
+ .nid = 2,
+ .name = "dac",
+ .params = common_params_audio_dac,
+ .nparams = ARRAY_SIZE(common_params_audio_dac),
+ .stindex = 0,
+ },{
+ .nid = 3,
+ .name = "out",
+ .params = common_params_audio_lineout,
+ .nparams = ARRAY_SIZE(common_params_audio_lineout),
+ .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+ (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) |
+ (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+ (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) |
+ 0x10),
+ .pinctl = AC_PINCTL_OUT_EN,
+ .conn = (uint32_t[]) { 2 },
+ },{
+ .nid = 4,
+ .name = "adc",
+ .params = duplex_params_audio_adc,
+ .nparams = ARRAY_SIZE(duplex_params_audio_adc),
+ .stindex = 1,
+ .conn = (uint32_t[]) { 5 },
+ },{
+ .nid = 5,
+ .name = "in",
+ .params = duplex_params_audio_linein,
+ .nparams = ARRAY_SIZE(duplex_params_audio_linein),
+ .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+ (AC_JACK_LINE_IN << AC_DEFCFG_DEVICE_SHIFT) |
+ (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+ (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) |
+ 0x20),
+ .pinctl = AC_PINCTL_IN_EN,
+ }
+};
+
+/* duplex: codec */
+static const desc_codec duplex = {
+ .name = "duplex",
+ .iid = QEMU_HDA_ID_DUPLEX,
+ .nodes = duplex_nodes,
+ .nnodes = ARRAY_SIZE(duplex_nodes),
+};
+
+/* -------------------------------------------------------------------------- */
+
+static const char *fmt2name[] = {
+ [ AUD_FMT_U8 ] = "PCM-U8",
+ [ AUD_FMT_S8 ] = "PCM-S8",
+ [ AUD_FMT_U16 ] = "PCM-U16",
+ [ AUD_FMT_S16 ] = "PCM-S16",
+ [ AUD_FMT_U32 ] = "PCM-U32",
+ [ AUD_FMT_S32 ] = "PCM-S32",
+};
+
+typedef struct HDAAudioState HDAAudioState;
+typedef struct HDAAudioStream HDAAudioStream;
+
+struct HDAAudioStream {
+ HDAAudioState *state;
+ const desc_node *node;
+ bool output, running;
+ uint32_t stream;
+ uint32_t channel;
+ uint32_t format;
+ uint32_t gain_left, gain_right;
+ bool mute_left, mute_right;
+ struct audsettings as;
+ union {
+ SWVoiceIn *in;
+ SWVoiceOut *out;
+ } voice;
+ uint8_t buf[HDA_BUFFER_SIZE];
+ uint32_t bpos;
+};
+
+struct HDAAudioState {
+ HDACodecDevice hda;
+ const char *name;
+
+ QEMUSoundCard card;
+ const desc_codec *desc;
+ HDAAudioStream st[4];
+ bool running[16];
+
+ /* properties */
+ uint32_t debug;
+};
+
+static void hda_audio_input_cb(void *opaque, int avail)
+{
+ HDAAudioStream *st = opaque;
+ int recv = 0;
+ int len;
+ bool rc;
+
+ while (avail - recv >= sizeof(st->buf)) {
+ if (st->bpos != sizeof(st->buf)) {
+ len = AUD_read(st->voice.in, st->buf + st->bpos,
+ sizeof(st->buf) - st->bpos);
+ st->bpos += len;
+ recv += len;
+ if (st->bpos != sizeof(st->buf)) {
+ break;
+ }
+ }
+ rc = hda_codec_xfer(&st->state->hda, st->stream, false,
+ st->buf, sizeof(st->buf));
+ if (!rc) {
+ break;
+ }
+ st->bpos = 0;
+ }
+}
+
+static void hda_audio_output_cb(void *opaque, int avail)
+{
+ HDAAudioStream *st = opaque;
+ int sent = 0;
+ int len;
+ bool rc;
+
+ while (avail - sent >= sizeof(st->buf)) {
+ if (st->bpos == sizeof(st->buf)) {
+ rc = hda_codec_xfer(&st->state->hda, st->stream, true,
+ st->buf, sizeof(st->buf));
+ if (!rc) {
+ break;
+ }
+ st->bpos = 0;
+ }
+ len = AUD_write(st->voice.out, st->buf + st->bpos,
+ sizeof(st->buf) - st->bpos);
+ st->bpos += len;
+ sent += len;
+ if (st->bpos != sizeof(st->buf)) {
+ break;
+ }
+ }
+}
+
+static void hda_audio_set_running(HDAAudioStream *st, bool running)
+{
+ if (st->node == NULL) {
+ return;
+ }
+ if (st->running == running) {
+ return;
+ }
+ st->running = running;
+ dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name,
+ st->running ? "on" : "off", st->stream);
+ if (st->output) {
+ AUD_set_active_out(st->voice.out, st->running);
+ } else {
+ AUD_set_active_in(st->voice.in, st->running);
+ }
+}
+
+static void hda_audio_set_amp(HDAAudioStream *st)
+{
+ bool muted;
+ uint32_t left, right;
+
+ if (st->node == NULL) {
+ return;
+ }
+
+ muted = st->mute_left && st->mute_right;
+ left = st->mute_left ? 0 : st->gain_left;
+ right = st->mute_right ? 0 : st->gain_right;
+
+ left = left * 255 / QEMU_HDA_AMP_STEPS;
+ right = right * 255 / QEMU_HDA_AMP_STEPS;
+
+ if (st->output) {
+ AUD_set_volume_out(st->voice.out, muted, left, right);
+ } else {
+ AUD_set_volume_in(st->voice.in, muted, left, right);
+ }
+}
+
+static void hda_audio_setup(HDAAudioStream *st)
+{
+ if (st->node == NULL) {
+ return;
+ }
+
+ dprint(st->state, 1, "%s: format: %d x %s @ %d Hz\n",
+ st->node->name, st->as.nchannels,
+ fmt2name[st->as.fmt], st->as.freq);
+
+ if (st->output) {
+ st->voice.out = AUD_open_out(&st->state->card, st->voice.out,
+ st->node->name, st,
+ hda_audio_output_cb, &st->as);
+ } else {
+ st->voice.in = AUD_open_in(&st->state->card, st->voice.in,
+ st->node->name, st,
+ hda_audio_input_cb, &st->as);
+ }
+}
+
+static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data)
+{
+ HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+ HDAAudioStream *st;
+ const desc_node *node = NULL;
+ const desc_param *param;
+ uint32_t verb, payload, response, count, shift;
+
+ if ((data & 0x70000) == 0x70000) {
+ /* 12/8 id/payload */
+ verb = (data >> 8) & 0xfff;
+ payload = data & 0x00ff;
+ } else {
+ /* 4/16 id/payload */
+ verb = (data >> 8) & 0xf00;
+ payload = data & 0xffff;
+ }
+
+ node = hda_codec_find_node(a->desc, nid);
+ if (node == NULL) {
+ goto fail;
+ }
+ dprint(a, 2, "%s: nid %d (%s), verb 0x%x, payload 0x%x\n",
+ __FUNCTION__, nid, node->name, verb, payload);
+
+ switch (verb) {
+ /* all nodes */
+ case AC_VERB_PARAMETERS:
+ param = hda_codec_find_param(node, payload);
+ if (param == NULL) {
+ goto fail;
+ }
+ hda_codec_response(hda, true, param->val);
+ break;
+ case AC_VERB_GET_SUBSYSTEM_ID:
+ hda_codec_response(hda, true, a->desc->iid);
+ break;
+
+ /* all functions */
+ case AC_VERB_GET_CONNECT_LIST:
+ param = hda_codec_find_param(node, AC_PAR_CONNLIST_LEN);
+ count = param ? param->val : 0;
+ response = 0;
+ shift = 0;
+ while (payload < count && shift < 32) {
+ response |= node->conn[payload] << shift;
+ payload++;
+ shift += 8;
+ }
+ hda_codec_response(hda, true, response);
+ break;
+
+ /* pin widget */
+ case AC_VERB_GET_CONFIG_DEFAULT:
+ hda_codec_response(hda, true, node->config);
+ break;
+ case AC_VERB_GET_PIN_WIDGET_CONTROL:
+ hda_codec_response(hda, true, node->pinctl);
+ break;
+ case AC_VERB_SET_PIN_WIDGET_CONTROL:
+ if (node->pinctl != payload) {
+ dprint(a, 1, "unhandled pin control bit\n");
+ }
+ hda_codec_response(hda, true, 0);
+ break;
+
+ /* audio in/out widget */
+ case AC_VERB_SET_CHANNEL_STREAMID:
+ st = a->st + node->stindex;
+ if (st->node == NULL) {
+ goto fail;
+ }
+ hda_audio_set_running(st, false);
+ st->stream = (payload >> 4) & 0x0f;
+ st->channel = payload & 0x0f;
+ dprint(a, 2, "%s: stream %d, channel %d\n",
+ st->node->name, st->stream, st->channel);
+ hda_audio_set_running(st, a->running[st->stream]);
+ hda_codec_response(hda, true, 0);
+ break;
+ case AC_VERB_GET_CONV:
+ st = a->st + node->stindex;
+ if (st->node == NULL) {
+ goto fail;
+ }
+ response = st->stream << 4 | st->channel;
+ hda_codec_response(hda, true, response);
+ break;
+ case AC_VERB_SET_STREAM_FORMAT:
+ st = a->st + node->stindex;
+ if (st->node == NULL) {
+ goto fail;
+ }
+ st->format = payload;
+ hda_codec_parse_fmt(st->format, &st->as);
+ hda_audio_setup(st);
+ hda_codec_response(hda, true, 0);
+ break;
+ case AC_VERB_GET_STREAM_FORMAT:
+ st = a->st + node->stindex;
+ if (st->node == NULL) {
+ goto fail;
+ }
+ hda_codec_response(hda, true, st->format);
+ break;
+ case AC_VERB_GET_AMP_GAIN_MUTE:
+ st = a->st + node->stindex;
+ if (st->node == NULL) {
+ goto fail;
+ }
+ if (payload & AC_AMP_GET_LEFT) {
+ response = st->gain_left | (st->mute_left ? AC_AMP_MUTE : 0);
+ } else {
+ response = st->gain_right | (st->mute_right ? AC_AMP_MUTE : 0);
+ }
+ hda_codec_response(hda, true, response);
+ break;
+ case AC_VERB_SET_AMP_GAIN_MUTE:
+ st = a->st + node->stindex;
+ if (st->node == NULL) {
+ goto fail;
+ }
+ dprint(a, 1, "amp (%s): %s%s%s%s index %d gain %3d %s\n",
+ st->node->name,
+ (payload & AC_AMP_SET_OUTPUT) ? "o" : "-",
+ (payload & AC_AMP_SET_INPUT) ? "i" : "-",
+ (payload & AC_AMP_SET_LEFT) ? "l" : "-",
+ (payload & AC_AMP_SET_RIGHT) ? "r" : "-",
+ (payload & AC_AMP_SET_INDEX) >> AC_AMP_SET_INDEX_SHIFT,
+ (payload & AC_AMP_GAIN),
+ (payload & AC_AMP_MUTE) ? "muted" : "");
+ if (payload & AC_AMP_SET_LEFT) {
+ st->gain_left = payload & AC_AMP_GAIN;
+ st->mute_left = payload & AC_AMP_MUTE;
+ }
+ if (payload & AC_AMP_SET_RIGHT) {
+ st->gain_right = payload & AC_AMP_GAIN;
+ st->mute_right = payload & AC_AMP_MUTE;
+ }
+ hda_audio_set_amp(st);
+ hda_codec_response(hda, true, 0);
+ break;
+
+ /* not supported */
+ case AC_VERB_SET_POWER_STATE:
+ case AC_VERB_GET_POWER_STATE:
+ case AC_VERB_GET_SDI_SELECT:
+ hda_codec_response(hda, true, 0);
+ break;
+ default:
+ goto fail;
+ }
+ return;
+
+fail:
+ dprint(a, 1, "%s: not handled: nid %d (%s), verb 0x%x, payload 0x%x\n",
+ __FUNCTION__, nid, node ? node->name : "?", verb, payload);
+ hda_codec_response(hda, true, 0);
+}
+
+static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running)
+{
+ HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+ int s;
+
+ a->running[stnr] = running;
+ for (s = 0; s < ARRAY_SIZE(a->st); s++) {
+ if (a->st[s].node == NULL) {
+ continue;
+ }
+ if (a->st[s].stream != stnr) {
+ continue;
+ }
+ hda_audio_set_running(&a->st[s], running);
+ }
+}
+
+static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
+{
+ HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+ HDAAudioStream *st;
+ const desc_node *node;
+ const desc_param *param;
+ uint32_t i, type;
+
+ a->desc = desc;
+ a->name = a->hda.qdev.info->name;
+ dprint(a, 1, "%s: cad %d\n", __FUNCTION__, a->hda.cad);
+
+ AUD_register_card("hda", &a->card);
+ for (i = 0; i < a->desc->nnodes; i++) {
+ node = a->desc->nodes + i;
+ param = hda_codec_find_param(node, AC_PAR_AUDIO_WIDGET_CAP);
+ if (NULL == param)
+ continue;
+ type = (param->val & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ switch (type) {
+ case AC_WID_AUD_OUT:
+ case AC_WID_AUD_IN:
+ assert(node->stindex < ARRAY_SIZE(a->st));
+ st = a->st + node->stindex;
+ st->state = a;
+ st->node = node;
+ if (type == AC_WID_AUD_OUT) {
+ /* unmute output by default */
+ st->gain_left = QEMU_HDA_AMP_STEPS;
+ st->gain_right = QEMU_HDA_AMP_STEPS;
+ st->bpos = sizeof(st->buf);
+ st->output = true;
+ } else {
+ st->output = false;
+ }
+ st->format = AC_FMT_TYPE_PCM | AC_FMT_BITS_16 |
+ (1 << AC_FMT_CHAN_SHIFT);
+ hda_codec_parse_fmt(st->format, &st->as);
+ hda_audio_setup(st);
+ break;
+ }
+ }
+ return 0;
+}
+
+static int hda_audio_post_load(void *opaque, int version)
+{
+ HDAAudioState *a = opaque;
+ HDAAudioStream *st;
+ int i;
+
+ dprint(a, 1, "%s\n", __FUNCTION__);
+ for (i = 0; i < ARRAY_SIZE(a->st); i++) {
+ st = a->st + i;
+ if (st->node == NULL)
+ continue;
+ hda_codec_parse_fmt(st->format, &st->as);
+ hda_audio_setup(st);
+ hda_audio_set_amp(st);
+ hda_audio_set_running(st, a->running[st->stream]);
+ }
+ return 0;
+}
+
+static const VMStateDescription vmstate_hda_audio_stream = {
+ .name = "hda-audio-stream",
+ .version_id = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32(stream, HDAAudioStream),
+ VMSTATE_UINT32(channel, HDAAudioStream),
+ VMSTATE_UINT32(format, HDAAudioStream),
+ VMSTATE_UINT32(gain_left, HDAAudioStream),
+ VMSTATE_UINT32(gain_right, HDAAudioStream),
+ VMSTATE_BOOL(mute_left, HDAAudioStream),
+ VMSTATE_BOOL(mute_right, HDAAudioStream),
+ VMSTATE_UINT32(bpos, HDAAudioStream),
+ VMSTATE_BUFFER(buf, HDAAudioStream),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_hda_audio = {
+ .name = "hda-audio",
+ .version_id = 1,
+ .post_load = hda_audio_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0,
+ vmstate_hda_audio_stream,
+ HDAAudioStream),
+ VMSTATE_BOOL_ARRAY(running, HDAAudioState, 16),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property hda_audio_properties[] = {
+ DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static int hda_audio_init_output(HDACodecDevice *hda)
+{
+ return hda_audio_init(hda, &output);
+}
+
+static int hda_audio_init_duplex(HDACodecDevice *hda)
+{
+ return hda_audio_init(hda, &duplex);
+}
+
+static HDACodecDeviceInfo hda_audio_info_output = {
+ .qdev.name = "hda-output",
+ .qdev.desc = "HDA Audio Codec, output-only",
+ .qdev.size = sizeof(HDAAudioState),
+ .qdev.vmsd = &vmstate_hda_audio,
+ .qdev.props = hda_audio_properties,
+ .init = hda_audio_init_output,
+ .command = hda_audio_command,
+ .stream = hda_audio_stream,
+};
+
+static HDACodecDeviceInfo hda_audio_info_duplex = {
+ .qdev.name = "hda-duplex",
+ .qdev.desc = "HDA Audio Codec, duplex",
+ .qdev.size = sizeof(HDAAudioState),
+ .qdev.vmsd = &vmstate_hda_audio,
+ .qdev.props = hda_audio_properties,
+ .init = hda_audio_init_duplex,
+ .command = hda_audio_command,
+ .stream = hda_audio_stream,
+};
+
+static void hda_audio_register(void)
+{
+ hda_codec_register(&hda_audio_info_output);
+ hda_codec_register(&hda_audio_info_duplex);
+}
+device_init(hda_audio_register);
diff --git a/hw/intel-hda-defs.h b/hw/intel-hda-defs.h
new file mode 100644
index 0000000..2e37e5b
--- /dev/null
+++ b/hw/intel-hda-defs.h
@@ -0,0 +1,717 @@
+#ifndef HW_INTEL_HDA_DEFS_H
+#define HW_INTEL_HDA_DEFS_H
+
+/* qemu */
+#define HDA_BUFFER_SIZE 256
+
+/* --------------------------------------------------------------------- */
+/* from linux/sound/pci/hda/hda_intel.c */
+
+/*
+ * registers
+ */
+#define ICH6_REG_GCAP 0x00
+#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */
+#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */
+#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */
+#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */
+#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */
+#define ICH6_REG_VMIN 0x02
+#define ICH6_REG_VMAJ 0x03
+#define ICH6_REG_OUTPAY 0x04
+#define ICH6_REG_INPAY 0x06
+#define ICH6_REG_GCTL 0x08
+#define ICH6_GCTL_RESET (1 << 0) /* controller reset */
+#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */
+#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */
+#define ICH6_REG_WAKEEN 0x0c
+#define ICH6_REG_STATESTS 0x0e
+#define ICH6_REG_GSTS 0x10
+#define ICH6_GSTS_FSTS (1 << 1) /* flush status */
+#define ICH6_REG_INTCTL 0x20
+#define ICH6_REG_INTSTS 0x24
+#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */
+#define ICH6_REG_SYNC 0x34
+#define ICH6_REG_CORBLBASE 0x40
+#define ICH6_REG_CORBUBASE 0x44
+#define ICH6_REG_CORBWP 0x48
+#define ICH6_REG_CORBRP 0x4a
+#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */
+#define ICH6_REG_CORBCTL 0x4c
+#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */
+#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */
+#define ICH6_REG_CORBSTS 0x4d
+#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */
+#define ICH6_REG_CORBSIZE 0x4e
+
+#define ICH6_REG_RIRBLBASE 0x50
+#define ICH6_REG_RIRBUBASE 0x54
+#define ICH6_REG_RIRBWP 0x58
+#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */
+#define ICH6_REG_RINTCNT 0x5a
+#define ICH6_REG_RIRBCTL 0x5c
+#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */
+#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */
+#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */
+#define ICH6_REG_RIRBSTS 0x5d
+#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */
+#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */
+#define ICH6_REG_RIRBSIZE 0x5e
+
+#define ICH6_REG_IC 0x60
+#define ICH6_REG_IR 0x64
+#define ICH6_REG_IRS 0x68
+#define ICH6_IRS_VALID (1<<1)
+#define ICH6_IRS_BUSY (1<<0)
+
+#define ICH6_REG_DPLBASE 0x70
+#define ICH6_REG_DPUBASE 0x74
+#define ICH6_DPLBASE_ENABLE 0x1 /* Enable position buffer */
+
+/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
+
+/* stream register offsets from stream base */
+#define ICH6_REG_SD_CTL 0x00
+#define ICH6_REG_SD_STS 0x03
+#define ICH6_REG_SD_LPIB 0x04
+#define ICH6_REG_SD_CBL 0x08
+#define ICH6_REG_SD_LVI 0x0c
+#define ICH6_REG_SD_FIFOW 0x0e
+#define ICH6_REG_SD_FIFOSIZE 0x10
+#define ICH6_REG_SD_FORMAT 0x12
+#define ICH6_REG_SD_BDLPL 0x18
+#define ICH6_REG_SD_BDLPU 0x1c
+
+/* PCI space */
+#define ICH6_PCIREG_TCSEL 0x44
+
+/*
+ * other constants
+ */
+
+/* max number of SDs */
+/* ICH, ATI and VIA have 4 playback and 4 capture */
+#define ICH6_NUM_CAPTURE 4
+#define ICH6_NUM_PLAYBACK 4
+
+/* ULI has 6 playback and 5 capture */
+#define ULI_NUM_CAPTURE 5
+#define ULI_NUM_PLAYBACK 6
+
+/* ATI HDMI has 1 playback and 0 capture */
+#define ATIHDMI_NUM_CAPTURE 0
+#define ATIHDMI_NUM_PLAYBACK 1
+
+/* TERA has 4 playback and 3 capture */
+#define TERA_NUM_CAPTURE 3
+#define TERA_NUM_PLAYBACK 4
+
+/* this number is statically defined for simplicity */
+#define MAX_AZX_DEV 16
+
+/* max number of fragments - we may use more if allocating more pages for BDL */
+#define BDL_SIZE 4096
+#define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16)
+#define AZX_MAX_FRAG 32
+/* max buffer size - no h/w limit, you can increase as you like */
+#define AZX_MAX_BUF_SIZE (1024*1024*1024)
+
+/* RIRB int mask: overrun[2], response[0] */
+#define RIRB_INT_RESPONSE 0x01
+#define RIRB_INT_OVERRUN 0x04
+#define RIRB_INT_MASK 0x05
+
+/* STATESTS int mask: S3,SD2,SD1,SD0 */
+#define AZX_MAX_CODECS 8
+#define AZX_DEFAULT_CODECS 4
+#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1)
+
+/* SD_CTL bits */
+#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
+#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */
+#define SD_CTL_STRIPE (3 << 16) /* stripe control */
+#define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */
+#define SD_CTL_DIR (1 << 19) /* bi-directional stream */
+#define SD_CTL_STREAM_TAG_MASK (0xf << 20)
+#define SD_CTL_STREAM_TAG_SHIFT 20
+
+/* SD_CTL and SD_STS */
+#define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */
+#define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */
+#define SD_INT_COMPLETE 0x04 /* completion interrupt */
+#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
+ SD_INT_COMPLETE)
+
+/* SD_STS */
+#define SD_STS_FIFO_READY 0x20 /* FIFO ready */
+
+/* INTCTL and INTSTS */
+#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */
+#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */
+#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */
+
+/* below are so far hardcoded - should read registers in future */
+#define ICH6_MAX_CORB_ENTRIES 256
+#define ICH6_MAX_RIRB_ENTRIES 256
+
+/* position fix mode */
+enum {
+ POS_FIX_AUTO,
+ POS_FIX_LPIB,
+ POS_FIX_POSBUF,
+};
+
+/* Defines for ATI HD Audio support in SB450 south bridge */
+#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42
+#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02
+
+/* Defines for Nvidia HDA support */
+#define NVIDIA_HDA_TRANSREG_ADDR 0x4e
+#define NVIDIA_HDA_ENABLE_COHBITS 0x0f
+#define NVIDIA_HDA_ISTRM_COH 0x4d
+#define NVIDIA_HDA_OSTRM_COH 0x4c
+#define NVIDIA_HDA_ENABLE_COHBIT 0x01
+
+/* Defines for Intel SCH HDA snoop control */
+#define INTEL_SCH_HDA_DEVC 0x78
+#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11)
+
+/* Define IN stream 0 FIFO size offset in VIA controller */
+#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90
+/* Define VIA HD Audio Device ID*/
+#define VIA_HDAC_DEVICE_ID 0x3288
+
+/* HD Audio class code */
+#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
+
+/* --------------------------------------------------------------------- */
+/* from linux/sound/pci/hda/hda_codec.h */
+
+/*
+ * nodes
+ */
+#define AC_NODE_ROOT 0x00
+
+/*
+ * function group types
+ */
+enum {
+ AC_GRP_AUDIO_FUNCTION = 0x01,
+ AC_GRP_MODEM_FUNCTION = 0x02,
+};
+
+/*
+ * widget types
+ */
+enum {
+ AC_WID_AUD_OUT, /* Audio Out */
+ AC_WID_AUD_IN, /* Audio In */
+ AC_WID_AUD_MIX, /* Audio Mixer */
+ AC_WID_AUD_SEL, /* Audio Selector */
+ AC_WID_PIN, /* Pin Complex */
+ AC_WID_POWER, /* Power */
+ AC_WID_VOL_KNB, /* Volume Knob */
+ AC_WID_BEEP, /* Beep Generator */
+ AC_WID_VENDOR = 0x0f /* Vendor specific */
+};
+
+/*
+ * GET verbs
+ */
+#define AC_VERB_GET_STREAM_FORMAT 0x0a00
+#define AC_VERB_GET_AMP_GAIN_MUTE 0x0b00
+#define AC_VERB_GET_PROC_COEF 0x0c00
+#define AC_VERB_GET_COEF_INDEX 0x0d00
+#define AC_VERB_PARAMETERS 0x0f00
+#define AC_VERB_GET_CONNECT_SEL 0x0f01
+#define AC_VERB_GET_CONNECT_LIST 0x0f02
+#define AC_VERB_GET_PROC_STATE 0x0f03
+#define AC_VERB_GET_SDI_SELECT 0x0f04
+#define AC_VERB_GET_POWER_STATE 0x0f05
+#define AC_VERB_GET_CONV 0x0f06
+#define AC_VERB_GET_PIN_WIDGET_CONTROL 0x0f07
+#define AC_VERB_GET_UNSOLICITED_RESPONSE 0x0f08
+#define AC_VERB_GET_PIN_SENSE 0x0f09
+#define AC_VERB_GET_BEEP_CONTROL 0x0f0a
+#define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c
+#define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d
+#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */
+#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f
+/* f10-f1a: GPIO */
+#define AC_VERB_GET_GPIO_DATA 0x0f15
+#define AC_VERB_GET_GPIO_MASK 0x0f16
+#define AC_VERB_GET_GPIO_DIRECTION 0x0f17
+#define AC_VERB_GET_GPIO_WAKE_MASK 0x0f18
+#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK 0x0f19
+#define AC_VERB_GET_GPIO_STICKY_MASK 0x0f1a
+#define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c
+/* f20: AFG/MFG */
+#define AC_VERB_GET_SUBSYSTEM_ID 0x0f20
+#define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d
+#define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e
+#define AC_VERB_GET_HDMI_ELDD 0x0f2f
+#define AC_VERB_GET_HDMI_DIP_INDEX 0x0f30
+#define AC_VERB_GET_HDMI_DIP_DATA 0x0f31
+#define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32
+#define AC_VERB_GET_HDMI_CP_CTRL 0x0f33
+#define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34
+
+/*
+ * SET verbs
+ */
+#define AC_VERB_SET_STREAM_FORMAT 0x200
+#define AC_VERB_SET_AMP_GAIN_MUTE 0x300
+#define AC_VERB_SET_PROC_COEF 0x400
+#define AC_VERB_SET_COEF_INDEX 0x500
+#define AC_VERB_SET_CONNECT_SEL 0x701
+#define AC_VERB_SET_PROC_STATE 0x703
+#define AC_VERB_SET_SDI_SELECT 0x704
+#define AC_VERB_SET_POWER_STATE 0x705
+#define AC_VERB_SET_CHANNEL_STREAMID 0x706
+#define AC_VERB_SET_PIN_WIDGET_CONTROL 0x707
+#define AC_VERB_SET_UNSOLICITED_ENABLE 0x708
+#define AC_VERB_SET_PIN_SENSE 0x709
+#define AC_VERB_SET_BEEP_CONTROL 0x70a
+#define AC_VERB_SET_EAPD_BTLENABLE 0x70c
+#define AC_VERB_SET_DIGI_CONVERT_1 0x70d
+#define AC_VERB_SET_DIGI_CONVERT_2 0x70e
+#define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f
+#define AC_VERB_SET_GPIO_DATA 0x715
+#define AC_VERB_SET_GPIO_MASK 0x716
+#define AC_VERB_SET_GPIO_DIRECTION 0x717
+#define AC_VERB_SET_GPIO_WAKE_MASK 0x718
+#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK 0x719
+#define AC_VERB_SET_GPIO_STICKY_MASK 0x71a
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f
+#define AC_VERB_SET_EAPD 0x788
+#define AC_VERB_SET_CODEC_RESET 0x7ff
+#define AC_VERB_SET_CVT_CHAN_COUNT 0x72d
+#define AC_VERB_SET_HDMI_DIP_INDEX 0x730
+#define AC_VERB_SET_HDMI_DIP_DATA 0x731
+#define AC_VERB_SET_HDMI_DIP_XMIT 0x732
+#define AC_VERB_SET_HDMI_CP_CTRL 0x733
+#define AC_VERB_SET_HDMI_CHAN_SLOT 0x734
+
+/*
+ * Parameter IDs
+ */
+#define AC_PAR_VENDOR_ID 0x00
+#define AC_PAR_SUBSYSTEM_ID 0x01
+#define AC_PAR_REV_ID 0x02
+#define AC_PAR_NODE_COUNT 0x04
+#define AC_PAR_FUNCTION_TYPE 0x05
+#define AC_PAR_AUDIO_FG_CAP 0x08
+#define AC_PAR_AUDIO_WIDGET_CAP 0x09
+#define AC_PAR_PCM 0x0a
+#define AC_PAR_STREAM 0x0b
+#define AC_PAR_PIN_CAP 0x0c
+#define AC_PAR_AMP_IN_CAP 0x0d
+#define AC_PAR_CONNLIST_LEN 0x0e
+#define AC_PAR_POWER_STATE 0x0f
+#define AC_PAR_PROC_CAP 0x10
+#define AC_PAR_GPIO_CAP 0x11
+#define AC_PAR_AMP_OUT_CAP 0x12
+#define AC_PAR_VOL_KNB_CAP 0x13
+#define AC_PAR_HDMI_LPCM_CAP 0x20
+
+/*
+ * AC_VERB_PARAMETERS results (32bit)
+ */
+
+/* Function Group Type */
+#define AC_FGT_TYPE (0xff<<0)
+#define AC_FGT_TYPE_SHIFT 0
+#define AC_FGT_UNSOL_CAP (1<<8)
+
+/* Audio Function Group Capabilities */
+#define AC_AFG_OUT_DELAY (0xf<<0)
+#define AC_AFG_IN_DELAY (0xf<<8)
+#define AC_AFG_BEEP_GEN (1<<16)
+
+/* Audio Widget Capabilities */
+#define AC_WCAP_STEREO (1<<0) /* stereo I/O */
+#define AC_WCAP_IN_AMP (1<<1) /* AMP-in present */
+#define AC_WCAP_OUT_AMP (1<<2) /* AMP-out present */
+#define AC_WCAP_AMP_OVRD (1<<3) /* AMP-parameter override */
+#define AC_WCAP_FORMAT_OVRD (1<<4) /* format override */
+#define AC_WCAP_STRIPE (1<<5) /* stripe */
+#define AC_WCAP_PROC_WID (1<<6) /* Proc Widget */
+#define AC_WCAP_UNSOL_CAP (1<<7) /* Unsol capable */
+#define AC_WCAP_CONN_LIST (1<<8) /* connection list */
+#define AC_WCAP_DIGITAL (1<<9) /* digital I/O */
+#define AC_WCAP_POWER (1<<10) /* power control */
+#define AC_WCAP_LR_SWAP (1<<11) /* L/R swap */
+#define AC_WCAP_CP_CAPS (1<<12) /* content protection */
+#define AC_WCAP_CHAN_CNT_EXT (7<<13) /* channel count ext */
+#define AC_WCAP_DELAY (0xf<<16)
+#define AC_WCAP_DELAY_SHIFT 16
+#define AC_WCAP_TYPE (0xf<<20)
+#define AC_WCAP_TYPE_SHIFT 20
+
+/* supported PCM rates and bits */
+#define AC_SUPPCM_RATES (0xfff << 0)
+#define AC_SUPPCM_BITS_8 (1<<16)
+#define AC_SUPPCM_BITS_16 (1<<17)
+#define AC_SUPPCM_BITS_20 (1<<18)
+#define AC_SUPPCM_BITS_24 (1<<19)
+#define AC_SUPPCM_BITS_32 (1<<20)
+
+/* supported PCM stream format */
+#define AC_SUPFMT_PCM (1<<0)
+#define AC_SUPFMT_FLOAT32 (1<<1)
+#define AC_SUPFMT_AC3 (1<<2)
+
+/* GP I/O count */
+#define AC_GPIO_IO_COUNT (0xff<<0)
+#define AC_GPIO_O_COUNT (0xff<<8)
+#define AC_GPIO_O_COUNT_SHIFT 8
+#define AC_GPIO_I_COUNT (0xff<<16)
+#define AC_GPIO_I_COUNT_SHIFT 16
+#define AC_GPIO_UNSOLICITED (1<<30)
+#define AC_GPIO_WAKE (1<<31)
+
+/* Converter stream, channel */
+#define AC_CONV_CHANNEL (0xf<<0)
+#define AC_CONV_STREAM (0xf<<4)
+#define AC_CONV_STREAM_SHIFT 4
+
+/* Input converter SDI select */
+#define AC_SDI_SELECT (0xf<<0)
+
+/* stream format id */
+#define AC_FMT_CHAN_SHIFT 0
+#define AC_FMT_CHAN_MASK (0x0f << 0)
+#define AC_FMT_BITS_SHIFT 4
+#define AC_FMT_BITS_MASK (7 << 4)
+#define AC_FMT_BITS_8 (0 << 4)
+#define AC_FMT_BITS_16 (1 << 4)
+#define AC_FMT_BITS_20 (2 << 4)
+#define AC_FMT_BITS_24 (3 << 4)
+#define AC_FMT_BITS_32 (4 << 4)
+#define AC_FMT_DIV_SHIFT 8
+#define AC_FMT_DIV_MASK (7 << 8)
+#define AC_FMT_MULT_SHIFT 11
+#define AC_FMT_MULT_MASK (7 << 11)
+#define AC_FMT_BASE_SHIFT 14
+#define AC_FMT_BASE_48K (0 << 14)
+#define AC_FMT_BASE_44K (1 << 14)
+#define AC_FMT_TYPE_SHIFT 15
+#define AC_FMT_TYPE_PCM (0 << 15)
+#define AC_FMT_TYPE_NON_PCM (1 << 15)
+
+/* Unsolicited response control */
+#define AC_UNSOL_TAG (0x3f<<0)
+#define AC_UNSOL_ENABLED (1<<7)
+#define AC_USRSP_EN AC_UNSOL_ENABLED
+
+/* Unsolicited responses */
+#define AC_UNSOL_RES_TAG (0x3f<<26)
+#define AC_UNSOL_RES_TAG_SHIFT 26
+#define AC_UNSOL_RES_SUBTAG (0x1f<<21)
+#define AC_UNSOL_RES_SUBTAG_SHIFT 21
+#define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */
+#define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */
+#define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */
+#define AC_UNSOL_RES_CP_READY (1<<0) /* content protection */
+
+/* Pin widget capabilies */
+#define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */
+#define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */
+#define AC_PINCAP_PRES_DETECT (1<<2) /* presence detect capable */
+#define AC_PINCAP_HP_DRV (1<<3) /* headphone drive capable */
+#define AC_PINCAP_OUT (1<<4) /* output capable */
+#define AC_PINCAP_IN (1<<5) /* input capable */
+#define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */
+/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification,
+ * but is marked reserved in the Intel HDA specification.
+ */
+#define AC_PINCAP_LR_SWAP (1<<7) /* L/R swap */
+/* Note: The same bit as LR_SWAP is newly defined as HDMI capability
+ * in HD-audio specification
+ */
+#define AC_PINCAP_HDMI (1<<7) /* HDMI pin */
+#define AC_PINCAP_DP (1<<24) /* DisplayPort pin, can
+ * coexist with AC_PINCAP_HDMI
+ */
+#define AC_PINCAP_VREF (0x37<<8)
+#define AC_PINCAP_VREF_SHIFT 8
+#define AC_PINCAP_EAPD (1<<16) /* EAPD capable */
+#define AC_PINCAP_HBR (1<<27) /* High Bit Rate */
+/* Vref status (used in pin cap) */
+#define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */
+#define AC_PINCAP_VREF_50 (1<<1) /* 50% */
+#define AC_PINCAP_VREF_GRD (1<<2) /* ground */
+#define AC_PINCAP_VREF_80 (1<<4) /* 80% */
+#define AC_PINCAP_VREF_100 (1<<5) /* 100% */
+
+/* Amplifier capabilities */
+#define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */
+#define AC_AMPCAP_OFFSET_SHIFT 0
+#define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */
+#define AC_AMPCAP_NUM_STEPS_SHIFT 8
+#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB
+ * in 0.25dB
+ */
+#define AC_AMPCAP_STEP_SIZE_SHIFT 16
+#define AC_AMPCAP_MUTE (1<<31) /* mute capable */
+#define AC_AMPCAP_MUTE_SHIFT 31
+
+/* Connection list */
+#define AC_CLIST_LENGTH (0x7f<<0)
+#define AC_CLIST_LONG (1<<7)
+
+/* Supported power status */
+#define AC_PWRST_D0SUP (1<<0)
+#define AC_PWRST_D1SUP (1<<1)
+#define AC_PWRST_D2SUP (1<<2)
+#define AC_PWRST_D3SUP (1<<3)
+#define AC_PWRST_D3COLDSUP (1<<4)
+#define AC_PWRST_S3D3COLDSUP (1<<29)
+#define AC_PWRST_CLKSTOP (1<<30)
+#define AC_PWRST_EPSS (1U<<31)
+
+/* Power state values */
+#define AC_PWRST_SETTING (0xf<<0)
+#define AC_PWRST_ACTUAL (0xf<<4)
+#define AC_PWRST_ACTUAL_SHIFT 4
+#define AC_PWRST_D0 0x00
+#define AC_PWRST_D1 0x01
+#define AC_PWRST_D2 0x02
+#define AC_PWRST_D3 0x03
+
+/* Processing capabilies */
+#define AC_PCAP_BENIGN (1<<0)
+#define AC_PCAP_NUM_COEF (0xff<<8)
+#define AC_PCAP_NUM_COEF_SHIFT 8
+
+/* Volume knobs capabilities */
+#define AC_KNBCAP_NUM_STEPS (0x7f<<0)
+#define AC_KNBCAP_DELTA (1<<7)
+
+/* HDMI LPCM capabilities */
+#define AC_LPCMCAP_48K_CP_CHNS (0x0f<<0) /* max channels w/ CP-on */
+#define AC_LPCMCAP_48K_NO_CHNS (0x0f<<4) /* max channels w/o CP-on */
+#define AC_LPCMCAP_48K_20BIT (1<<8) /* 20b bitrate supported */
+#define AC_LPCMCAP_48K_24BIT (1<<9) /* 24b bitrate supported */
+#define AC_LPCMCAP_96K_CP_CHNS (0x0f<<10) /* max channels w/ CP-on */
+#define AC_LPCMCAP_96K_NO_CHNS (0x0f<<14) /* max channels w/o CP-on */
+#define AC_LPCMCAP_96K_20BIT (1<<18) /* 20b bitrate supported */
+#define AC_LPCMCAP_96K_24BIT (1<<19) /* 24b bitrate supported */
+#define AC_LPCMCAP_192K_CP_CHNS (0x0f<<20) /* max channels w/ CP-on */
+#define AC_LPCMCAP_192K_NO_CHNS (0x0f<<24) /* max channels w/o CP-on */
+#define AC_LPCMCAP_192K_20BIT (1<<28) /* 20b bitrate supported */
+#define AC_LPCMCAP_192K_24BIT (1<<29) /* 24b bitrate supported */
+#define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */
+#define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */
+
+/*
+ * Control Parameters
+ */
+
+/* Amp gain/mute */
+#define AC_AMP_MUTE (1<<7)
+#define AC_AMP_GAIN (0x7f)
+#define AC_AMP_GET_INDEX (0xf<<0)
+
+#define AC_AMP_GET_LEFT (1<<13)
+#define AC_AMP_GET_RIGHT (0<<13)
+#define AC_AMP_GET_OUTPUT (1<<15)
+#define AC_AMP_GET_INPUT (0<<15)
+
+#define AC_AMP_SET_INDEX (0xf<<8)
+#define AC_AMP_SET_INDEX_SHIFT 8
+#define AC_AMP_SET_RIGHT (1<<12)
+#define AC_AMP_SET_LEFT (1<<13)
+#define AC_AMP_SET_INPUT (1<<14)
+#define AC_AMP_SET_OUTPUT (1<<15)
+
+/* DIGITAL1 bits */
+#define AC_DIG1_ENABLE (1<<0)
+#define AC_DIG1_V (1<<1)
+#define AC_DIG1_VCFG (1<<2)
+#define AC_DIG1_EMPHASIS (1<<3)
+#define AC_DIG1_COPYRIGHT (1<<4)
+#define AC_DIG1_NONAUDIO (1<<5)
+#define AC_DIG1_PROFESSIONAL (1<<6)
+#define AC_DIG1_LEVEL (1<<7)
+
+/* DIGITAL2 bits */
+#define AC_DIG2_CC (0x7f<<0)
+
+/* Pin widget control - 8bit */
+#define AC_PINCTL_EPT (0x3<<0)
+#define AC_PINCTL_EPT_NATIVE 0
+#define AC_PINCTL_EPT_HBR 3
+#define AC_PINCTL_VREFEN (0x7<<0)
+#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */
+#define AC_PINCTL_VREF_50 1 /* 50% */
+#define AC_PINCTL_VREF_GRD 2 /* ground */
+#define AC_PINCTL_VREF_80 4 /* 80% */
+#define AC_PINCTL_VREF_100 5 /* 100% */
+#define AC_PINCTL_IN_EN (1<<5)
+#define AC_PINCTL_OUT_EN (1<<6)
+#define AC_PINCTL_HP_EN (1<<7)
+
+/* Pin sense - 32bit */
+#define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff)
+#define AC_PINSENSE_PRESENCE (1<<31)
+#define AC_PINSENSE_ELDV (1<<30) /* ELD valid (HDMI) */
+
+/* EAPD/BTL enable - 32bit */
+#define AC_EAPDBTL_BALANCED (1<<0)
+#define AC_EAPDBTL_EAPD (1<<1)
+#define AC_EAPDBTL_LR_SWAP (1<<2)
+
+/* HDMI ELD data */
+#define AC_ELDD_ELD_VALID (1<<31)
+#define AC_ELDD_ELD_DATA 0xff
+
+/* HDMI DIP size */
+#define AC_DIPSIZE_ELD_BUF (1<<3) /* ELD buf size of packet size */
+#define AC_DIPSIZE_PACK_IDX (0x07<<0) /* packet index */
+
+/* HDMI DIP index */
+#define AC_DIPIDX_PACK_IDX (0x07<<5) /* packet idnex */
+#define AC_DIPIDX_BYTE_IDX (0x1f<<0) /* byte index */
+
+/* HDMI DIP xmit (transmit) control */
+#define AC_DIPXMIT_MASK (0x3<<6)
+#define AC_DIPXMIT_DISABLE (0x0<<6) /* disable xmit */
+#define AC_DIPXMIT_ONCE (0x2<<6) /* xmit once then disable */
+#define AC_DIPXMIT_BEST (0x3<<6) /* best effort */
+
+/* HDMI content protection (CP) control */
+#define AC_CPCTRL_CES (1<<9) /* current encryption state */
+#define AC_CPCTRL_READY (1<<8) /* ready bit */
+#define AC_CPCTRL_SUBTAG (0x1f<<3) /* subtag for unsol-resp */
+#define AC_CPCTRL_STATE (3<<0) /* current CP request state */
+
+/* Converter channel <-> HDMI slot mapping */
+#define AC_CVTMAP_HDMI_SLOT (0xf<<0) /* HDMI slot number */
+#define AC_CVTMAP_CHAN (0xf<<4) /* converter channel number */
+
+/* configuration default - 32bit */
+#define AC_DEFCFG_SEQUENCE (0xf<<0)
+#define AC_DEFCFG_DEF_ASSOC (0xf<<4)
+#define AC_DEFCFG_ASSOC_SHIFT 4
+#define AC_DEFCFG_MISC (0xf<<8)
+#define AC_DEFCFG_MISC_SHIFT 8
+#define AC_DEFCFG_MISC_NO_PRESENCE (1<<0)
+#define AC_DEFCFG_COLOR (0xf<<12)
+#define AC_DEFCFG_COLOR_SHIFT 12
+#define AC_DEFCFG_CONN_TYPE (0xf<<16)
+#define AC_DEFCFG_CONN_TYPE_SHIFT 16
+#define AC_DEFCFG_DEVICE (0xf<<20)
+#define AC_DEFCFG_DEVICE_SHIFT 20
+#define AC_DEFCFG_LOCATION (0x3f<<24)
+#define AC_DEFCFG_LOCATION_SHIFT 24
+#define AC_DEFCFG_PORT_CONN (0x3<<30)
+#define AC_DEFCFG_PORT_CONN_SHIFT 30
+
+/* device device types (0x0-0xf) */
+enum {
+ AC_JACK_LINE_OUT,
+ AC_JACK_SPEAKER,
+ AC_JACK_HP_OUT,
+ AC_JACK_CD,
+ AC_JACK_SPDIF_OUT,
+ AC_JACK_DIG_OTHER_OUT,
+ AC_JACK_MODEM_LINE_SIDE,
+ AC_JACK_MODEM_HAND_SIDE,
+ AC_JACK_LINE_IN,
+ AC_JACK_AUX,
+ AC_JACK_MIC_IN,
+ AC_JACK_TELEPHONY,
+ AC_JACK_SPDIF_IN,
+ AC_JACK_DIG_OTHER_IN,
+ AC_JACK_OTHER = 0xf,
+};
+
+/* jack connection types (0x0-0xf) */
+enum {
+ AC_JACK_CONN_UNKNOWN,
+ AC_JACK_CONN_1_8,
+ AC_JACK_CONN_1_4,
+ AC_JACK_CONN_ATAPI,
+ AC_JACK_CONN_RCA,
+ AC_JACK_CONN_OPTICAL,
+ AC_JACK_CONN_OTHER_DIGITAL,
+ AC_JACK_CONN_OTHER_ANALOG,
+ AC_JACK_CONN_DIN,
+ AC_JACK_CONN_XLR,
+ AC_JACK_CONN_RJ11,
+ AC_JACK_CONN_COMB,
+ AC_JACK_CONN_OTHER = 0xf,
+};
+
+/* jack colors (0x0-0xf) */
+enum {
+ AC_JACK_COLOR_UNKNOWN,
+ AC_JACK_COLOR_BLACK,
+ AC_JACK_COLOR_GREY,
+ AC_JACK_COLOR_BLUE,
+ AC_JACK_COLOR_GREEN,
+ AC_JACK_COLOR_RED,
+ AC_JACK_COLOR_ORANGE,
+ AC_JACK_COLOR_YELLOW,
+ AC_JACK_COLOR_PURPLE,
+ AC_JACK_COLOR_PINK,
+ AC_JACK_COLOR_WHITE = 0xe,
+ AC_JACK_COLOR_OTHER,
+};
+
+/* Jack location (0x0-0x3f) */
+/* common case */
+enum {
+ AC_JACK_LOC_NONE,
+ AC_JACK_LOC_REAR,
+ AC_JACK_LOC_FRONT,
+ AC_JACK_LOC_LEFT,
+ AC_JACK_LOC_RIGHT,
+ AC_JACK_LOC_TOP,
+ AC_JACK_LOC_BOTTOM,
+};
+/* bits 4-5 */
+enum {
+ AC_JACK_LOC_EXTERNAL = 0x00,
+ AC_JACK_LOC_INTERNAL = 0x10,
+ AC_JACK_LOC_SEPARATE = 0x20,
+ AC_JACK_LOC_OTHER = 0x30,
+};
+enum {
+ /* external on primary chasis */
+ AC_JACK_LOC_REAR_PANEL = 0x07,
+ AC_JACK_LOC_DRIVE_BAY,
+ /* internal */
+ AC_JACK_LOC_RISER = 0x17,
+ AC_JACK_LOC_HDMI,
+ AC_JACK_LOC_ATAPI,
+ /* others */
+ AC_JACK_LOC_MOBILE_IN = 0x37,
+ AC_JACK_LOC_MOBILE_OUT,
+};
+
+/* Port connectivity (0-3) */
+enum {
+ AC_JACK_PORT_COMPLEX,
+ AC_JACK_PORT_NONE,
+ AC_JACK_PORT_FIXED,
+ AC_JACK_PORT_BOTH,
+};
+
+/* max. connections to a widget */
+#define HDA_MAX_CONNECTIONS 32
+
+/* max. codec address */
+#define HDA_MAX_CODEC_ADDRESS 0x0f
+
+/* max number of PCM devics per card */
+#define HDA_MAX_PCMS 10
+
+/* --------------------------------------------------------------------- */
+
+#endif
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
new file mode 100644
index 0000000..ccb059d
--- /dev/null
+++ b/hw/intel-hda.c
@@ -0,0 +1,1250 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * written by Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "pci.h"
+#include "qemu-timer.h"
+#include "audiodev.h"
+#include "intel-hda.h"
+#include "intel-hda-defs.h"
+
+/* --------------------------------------------------------------------- */
+/* hda bus */
+
+static struct BusInfo hda_codec_bus_info = {
+ .name = "HDA",
+ .size = sizeof(HDACodecBus),
+ .props = (Property[]) {
+ DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1),
+ DEFINE_PROP_END_OF_LIST()
+ }
+};
+
+void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
+ hda_codec_response_func response,
+ hda_codec_xfer_func xfer)
+{
+ qbus_create_inplace(&bus->qbus, &hda_codec_bus_info, dev, NULL);
+ bus->response = response;
+ bus->xfer = xfer;
+}
+
+static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
+{
+ HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus);
+ HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+ HDACodecDeviceInfo *info = DO_UPCAST(HDACodecDeviceInfo, qdev, base);
+
+ dev->info = info;
+ if (dev->cad == -1) {
+ dev->cad = bus->next_cad;
+ }
+ if (dev->cad > 15)
+ return -1;
+ bus->next_cad = dev->cad + 1;
+ return info->init(dev);
+}
+
+void hda_codec_register(HDACodecDeviceInfo *info)
+{
+ info->qdev.init = hda_codec_dev_init;
+ info->qdev.bus_info = &hda_codec_bus_info;
+ qdev_register(&info->qdev);
+}
+
+HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
+{
+ DeviceState *qdev;
+ HDACodecDevice *cdev;
+
+ QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
+ cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+ if (cdev->cad == cad) {
+ return cdev;
+ }
+ }
+ return NULL;
+}
+
+void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response)
+{
+ HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+ bus->response(dev, solicited, response);
+}
+
+bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
+ uint8_t *buf, uint32_t len)
+{
+ HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+ return bus->xfer(dev, stnr, output, buf, len);
+}
+
+/* --------------------------------------------------------------------- */
+/* intel hda emulation */
+
+typedef struct IntelHDAStream IntelHDAStream;
+typedef struct IntelHDAState IntelHDAState;
+typedef struct IntelHDAReg IntelHDAReg;
+
+typedef struct bpl {
+ uint64_t addr;
+ uint32_t len;
+ uint32_t flags;
+} bpl;
+
+struct IntelHDAStream {
+ /* registers */
+ uint32_t ctl;
+ uint32_t lpib;
+ uint32_t cbl;
+ uint32_t lvi;
+ uint32_t fmt;
+ uint32_t bdlp_lbase;
+ uint32_t bdlp_ubase;
+
+ /* state */
+ bpl *bpl;
+ uint32_t bentries;
+ uint32_t bsize, be, bp;
+};
+
+struct IntelHDAState {
+ PCIDevice pci;
+ const char *name;
+ HDACodecBus codecs;
+
+ /* registers */
+ uint32_t g_ctl;
+ uint32_t wake_en;
+ uint32_t state_sts;
+ uint32_t int_ctl;
+ uint32_t int_sts;
+ uint32_t wall_clk;
+
+ uint32_t corb_lbase;
+ uint32_t corb_ubase;
+ uint32_t corb_rp;
+ uint32_t corb_wp;
+ uint32_t corb_ctl;
+ uint32_t corb_sts;
+ uint32_t corb_size;
+
+ uint32_t rirb_lbase;
+ uint32_t rirb_ubase;
+ uint32_t rirb_wp;
+ uint32_t rirb_cnt;
+ uint32_t rirb_ctl;
+ uint32_t rirb_sts;
+ uint32_t rirb_size;
+
+ uint32_t dp_lbase;
+ uint32_t dp_ubase;
+
+ uint32_t icw;
+ uint32_t irr;
+ uint32_t ics;
+
+ /* streams */
+ IntelHDAStream st[8];
+
+ /* state */
+ int mmio_addr;
+ uint32_t rirb_count;
+ int64_t wall_base_ns;
+
+ /* debug logging */
+ const IntelHDAReg *last_reg;
+ uint32_t last_val;
+ uint32_t last_write;
+ uint32_t last_sec;
+ uint32_t repeat_count;
+
+ /* properties */
+ uint32_t debug;
+};
+
+struct IntelHDAReg {
+ const char *name; /* register name */
+ uint32_t size; /* size in bytes */
+ uint32_t reset; /* reset value */
+ uint32_t wmask; /* write mask */
+ uint32_t wclear; /* write 1 to clear bits */
+ uint32_t offset; /* location in IntelHDAState */
+ uint32_t shift; /* byte access entries for dwords */
+ uint32_t stream;
+ void (*whandler)(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old);
+ void (*rhandler)(IntelHDAState *d, const IntelHDAReg *reg);
+};
+
+static void intel_hda_reset(DeviceState *dev);
+
+/* --------------------------------------------------------------------- */
+
+static target_phys_addr_t intel_hda_addr(uint32_t lbase, uint32_t ubase)
+{
+ target_phys_addr_t addr;
+
+#if TARGET_PHYS_ADDR_BITS == 32
+ addr = lbase;
+#else
+ addr = ubase;
+ addr <<= 32;
+ addr |= lbase;
+#endif
+ return addr;
+}
+
+static void stl_phys_le(target_phys_addr_t addr, uint32_t value)
+{
+ uint32_t value_le = cpu_to_le32(value);
+ cpu_physical_memory_write(addr, (uint8_t*)(&value_le), sizeof(value_le));
+}
+
+static uint32_t ldl_phys_le(target_phys_addr_t addr)
+{
+ uint32_t value_le;
+ cpu_physical_memory_read(addr, (uint8_t*)(&value_le), sizeof(value_le));
+ return le32_to_cpu(value_le);
+}
+
+static void intel_hda_update_int_sts(IntelHDAState *d)
+{
+ uint32_t sts = 0;
+ uint32_t i;
+
+ /* update controller status */
+ if (d->rirb_sts & ICH6_RBSTS_IRQ) {
+ sts |= (1 << 30);
+ }
+ if (d->rirb_sts & ICH6_RBSTS_OVERRUN) {
+ sts |= (1 << 30);
+ }
+ if (d->state_sts) {
+ sts |= (1 << 30);
+ }
+
+ /* update stream status */
+ for (i = 0; i < 8; i++) {
+ /* buffer completion interrupt */
+ if (d->st[i].ctl & (1 << 26)) {
+ sts |= (1 << i);
+ }
+ }
+
+ /* update global status */
+ if (sts & d->int_ctl) {
+ sts |= (1 << 31);
+ }
+
+ d->int_sts = sts;
+}
+
+static void intel_hda_update_irq(IntelHDAState *d)
+{
+ int level;
+
+ intel_hda_update_int_sts(d);
+ if (d->int_sts & (1 << 31) && d->int_ctl & (1 << 31)) {
+ level = 1;
+ } else {
+ level = 0;
+ }
+ dprint(d, 2, "%s: level %d\n", __FUNCTION__, level);
+ qemu_set_irq(d->pci.irq[0], level);
+}
+
+static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
+{
+ uint32_t cad, nid, data;
+ HDACodecDevice *codec;
+
+ cad = (verb >> 28) & 0x0f;
+ if (verb & (1 << 27)) {
+ /* indirect node addressing, not specified in HDA 1.0 */
+ dprint(d, 1, "%s: indirect node addressing (guest bug?)\n", __FUNCTION__);
+ return -1;
+ }
+ nid = (verb >> 20) & 0x7f;
+ data = verb & 0xfffff;
+
+ codec = hda_codec_find(&d->codecs, cad);
+ if (codec == NULL) {
+ dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__);
+ return -1;
+ }
+ codec->info->command(codec, nid, data);
+ return 0;
+}
+
+static void intel_hda_corb_run(IntelHDAState *d)
+{
+ target_phys_addr_t addr;
+ uint32_t rp, verb;
+
+ if (d->ics & ICH6_IRS_BUSY) {
+ dprint(d, 2, "%s: [icw] verb 0x%08x\n", __FUNCTION__, d->icw);
+ intel_hda_send_command(d, d->icw);
+ return;
+ }
+
+ for (;;) {
+ if (!(d->corb_ctl & ICH6_CORBCTL_RUN)) {
+ dprint(d, 2, "%s: !run\n", __FUNCTION__);
+ return;
+ }
+ if ((d->corb_rp & 0xff) == d->corb_wp) {
+ dprint(d, 2, "%s: corb ring empty\n", __FUNCTION__);
+ return;
+ }
+ if (d->rirb_count == d->rirb_cnt) {
+ dprint(d, 2, "%s: rirb count reached\n", __FUNCTION__);
+ return;
+ }
+
+ rp = (d->corb_rp + 1) & 0xff;
+ addr = intel_hda_addr(d->corb_lbase, d->corb_ubase);
+ verb = ldl_phys_le(addr + 4*rp);
+ d->corb_rp = rp;
+
+ dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb);
+ intel_hda_send_command(d, verb);
+ }
+}
+
+static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t response)
+{
+ HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+ IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
+ target_phys_addr_t addr;
+ uint32_t wp, ex;
+
+ if (d->ics & ICH6_IRS_BUSY) {
+ dprint(d, 2, "%s: [irr] response 0x%x, cad 0x%x\n",
+ __FUNCTION__, response, dev->cad);
+ d->irr = response;
+ d->ics &= ~(ICH6_IRS_BUSY | 0xf0);
+ d->ics |= (ICH6_IRS_VALID | (dev->cad << 4));
+ return;
+ }
+
+ if (!(d->rirb_ctl & ICH6_RBCTL_DMA_EN)) {
+ dprint(d, 1, "%s: rirb dma disabled, drop codec response\n", __FUNCTION__);
+ return;
+ }
+
+ ex = (solicited ? 0 : (1 << 4)) | dev->cad;
+ wp = (d->rirb_wp + 1) & 0xff;
+ addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase);
+ stl_phys_le(addr + 8*wp, response);
+ stl_phys_le(addr + 8*wp + 4, ex);
+ d->rirb_wp = wp;
+
+ dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n",
+ __FUNCTION__, wp, response, ex);
+
+ d->rirb_count++;
+ if (d->rirb_count == d->rirb_cnt) {
+ dprint(d, 2, "%s: rirb count reached (%d)\n", __FUNCTION__, d->rirb_count);
+ if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
+ d->rirb_sts |= ICH6_RBSTS_IRQ;
+ intel_hda_update_irq(d);
+ }
+ } else if ((d->corb_rp & 0xff) == d->corb_wp) {
+ dprint(d, 2, "%s: corb ring empty (%d/%d)\n", __FUNCTION__,
+ d->rirb_count, d->rirb_cnt);
+ if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
+ d->rirb_sts |= ICH6_RBSTS_IRQ;
+ intel_hda_update_irq(d);
+ }
+ }
+}
+
+static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
+ uint8_t *buf, uint32_t len)
+{
+ HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+ IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
+ IntelHDAStream *st = NULL;
+ target_phys_addr_t addr;
+ uint32_t s, copy, left;
+ bool irq = false;
+
+ for (s = 0; s < ARRAY_SIZE(d->st); s++) {
+ if (stnr == ((d->st[s].ctl >> 20) & 0x0f)) {
+ st = d->st + s;
+ break;
+ }
+ }
+ if (st == NULL) {
+ return false;
+ }
+ if (st->bpl == NULL) {
+ return false;
+ }
+ if (st->ctl & (1 << 26)) {
+ /*
+ * Wait with the next DMA xfer until the guest
+ * has acked the buffer completion interrupt
+ */
+ return false;
+ }
+
+ left = len;
+ while (left > 0) {
+ copy = left;
+ if (copy > st->bsize - st->lpib)
+ copy = st->bsize - st->lpib;
+ if (copy > st->bpl[st->be].len - st->bp)
+ copy = st->bpl[st->be].len - st->bp;
+
+ dprint(d, 3, "dma: entry %d, pos %d/%d, copy %d\n",
+ st->be, st->bp, st->bpl[st->be].len, copy);
+
+ cpu_physical_memory_rw(st->bpl[st->be].addr + st->bp,
+ buf, copy, !output);
+ st->lpib += copy;
+ st->bp += copy;
+ buf += copy;
+ left -= copy;
+
+ if (st->bpl[st->be].len == st->bp) {
+ /* bpl entry filled */
+ if (st->bpl[st->be].flags & 0x01) {
+ irq = true;
+ }
+ st->bp = 0;
+ st->be++;
+ if (st->be == st->bentries) {
+ /* bpl wrap around */
+ st->be = 0;
+ st->lpib = 0;
+ }
+ }
+ }
+ if (d->dp_lbase & 0x01) {
+ addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase);
+ stl_phys_le(addr + 8*s, st->lpib);
+ }
+ dprint(d, 3, "dma: --\n");
+
+ if (irq) {
+ st->ctl |= (1 << 26); /* buffer completion interrupt */
+ intel_hda_update_irq(d);
+ }
+ return true;
+}
+
+static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
+{
+ target_phys_addr_t addr;
+ uint8_t buf[16];
+ uint32_t i;
+
+ addr = intel_hda_addr(st->bdlp_lbase, st->bdlp_ubase);
+ st->bentries = st->lvi +1;
+ qemu_free(st->bpl);
+ st->bpl = qemu_malloc(sizeof(bpl) * st->bentries);
+ for (i = 0; i < st->bentries; i++, addr += 16) {
+ cpu_physical_memory_read(addr, buf, 16);
+ st->bpl[i].addr = le64_to_cpu(*(uint64_t *)buf);
+ st->bpl[i].len = le32_to_cpu(*(uint32_t *)(buf + 8));
+ st->bpl[i].flags = le32_to_cpu(*(uint32_t *)(buf + 12));
+ dprint(d, 1, "bdl/%d: 0x%" PRIx64 " +0x%x, 0x%x\n",
+ i, st->bpl[i].addr, st->bpl[i].len, st->bpl[i].flags);
+ }
+
+ st->bsize = st->cbl;
+ st->lpib = 0;
+ st->be = 0;
+ st->bp = 0;
+}
+
+static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running)
+{
+ DeviceState *qdev;
+ HDACodecDevice *cdev;
+
+ QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+ cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+ if (cdev->info->stream) {
+ cdev->info->stream(cdev, stream, running);
+ }
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+ if ((d->g_ctl & ICH6_GCTL_RESET) == 0) {
+ intel_hda_reset(&d->pci.qdev);
+ }
+}
+
+static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+ intel_hda_update_irq(d);
+}
+
+static void intel_hda_set_int_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+ intel_hda_update_irq(d);
+}
+
+static void intel_hda_get_wall_clk(IntelHDAState *d, const IntelHDAReg *reg)
+{
+ int64_t ns;
+
+ ns = qemu_get_clock_ns(vm_clock) - d->wall_base_ns;
+ d->wall_clk = (uint32_t)(ns * 24 / 1000); /* 24 MHz */
+}
+
+static void intel_hda_set_corb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+ intel_hda_corb_run(d);
+}
+
+static void intel_hda_set_corb_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+ intel_hda_corb_run(d);
+}
+
+static void intel_hda_set_rirb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+ if (d->rirb_wp & ICH6_RIRBWP_RST) {
+ d->rirb_wp = 0;
+ }
+}
+
+static void intel_hda_set_rirb_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+ intel_hda_update_irq(d);
+
+ if ((old & ICH6_RBSTS_IRQ) && !(d->rirb_sts & ICH6_RBSTS_IRQ)) {
+ /* cleared ICH6_RBSTS_IRQ */
+ d->rirb_count = 0;
+ intel_hda_corb_run(d);
+ }
+}
+
+static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+ if (d->ics & ICH6_IRS_BUSY) {
+ intel_hda_corb_run(d);
+ }
+}
+
+static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+ IntelHDAStream *st = d->st + reg->stream;
+
+ if (st->ctl & 0x01) {
+ /* reset */
+ dprint(d, 1, "st #%d: reset\n", reg->stream);
+ st->ctl = 0;
+ }
+ if ((st->ctl & 0x02) != (old & 0x02)) {
+ uint32_t stnr = (st->ctl >> 20) & 0x0f;
+ /* run bit flipped */
+ if (st->ctl & 0x02) {
+ /* start */
+ dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n",
+ reg->stream, stnr, st->cbl);
+ intel_hda_parse_bdl(d, st);
+ intel_hda_notify_codecs(d, stnr, true);
+ } else {
+ /* stop */
+ dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr);
+ intel_hda_notify_codecs(d, stnr, false);
+ }
+ }
+ intel_hda_update_irq(d);
+}
+
+/* --------------------------------------------------------------------- */
+
+#define ST_REG(_n, _o) (0x80 + (_n) * 0x20 + (_o))
+
+static const struct IntelHDAReg regtab[] = {
+ /* global */
+ [ ICH6_REG_GCAP ] = {
+ .name = "GCAP",
+ .size = 2,
+ .reset = 0x4401,
+ },
+ [ ICH6_REG_VMIN ] = {
+ .name = "VMIN",
+ .size = 1,
+ },
+ [ ICH6_REG_VMAJ ] = {
+ .name = "VMAJ",
+ .size = 1,
+ .reset = 1,
+ },
+ [ ICH6_REG_OUTPAY ] = {
+ .name = "OUTPAY",
+ .size = 2,
+ .reset = 0x3c,
+ },
+ [ ICH6_REG_INPAY ] = {
+ .name = "INPAY",
+ .size = 2,
+ .reset = 0x1d,
+ },
+ [ ICH6_REG_GCTL ] = {
+ .name = "GCTL",
+ .size = 4,
+ .wmask = 0x0103,
+ .offset = offsetof(IntelHDAState, g_ctl),
+ .whandler = intel_hda_set_g_ctl,
+ },
+ [ ICH6_REG_WAKEEN ] = {
+ .name = "WAKEEN",
+ .size = 2,
+ .offset = offsetof(IntelHDAState, wake_en),
+ },
+ [ ICH6_REG_STATESTS ] = {
+ .name = "STATESTS",
+ .size = 2,
+ .wmask = 0x3fff,
+ .wclear = 0x3fff,
+ .offset = offsetof(IntelHDAState, state_sts),
+ .whandler = intel_hda_set_state_sts,
+ },
+
+ /* interrupts */
+ [ ICH6_REG_INTCTL ] = {
+ .name = "INTCTL",
+ .size = 4,
+ .wmask = 0xc00000ff,
+ .offset = offsetof(IntelHDAState, int_ctl),
+ .whandler = intel_hda_set_int_ctl,
+ },
+ [ ICH6_REG_INTSTS ] = {
+ .name = "INTSTS",
+ .size = 4,
+ .wmask = 0xc00000ff,
+ .wclear = 0xc00000ff,
+ .offset = offsetof(IntelHDAState, int_sts),
+ },
+
+ /* misc */
+ [ ICH6_REG_WALLCLK ] = {
+ .name = "WALLCLK",
+ .size = 4,
+ .offset = offsetof(IntelHDAState, wall_clk),
+ .rhandler = intel_hda_get_wall_clk,
+ },
+ [ ICH6_REG_WALLCLK + 0x2000 ] = {
+ .name = "WALLCLK(alias)",
+ .size = 4,
+ .offset = offsetof(IntelHDAState, wall_clk),
+ .rhandler = intel_hda_get_wall_clk,
+ },
+
+ /* dma engine */
+ [ ICH6_REG_CORBLBASE ] = {
+ .name = "CORBLBASE",
+ .size = 4,
+ .wmask = 0xffffff80,
+ .offset = offsetof(IntelHDAState, corb_lbase),
+ },
+ [ ICH6_REG_CORBUBASE ] = {
+ .name = "CORBUBASE",
+ .size = 4,
+ .wmask = 0xffffffff,
+ .offset = offsetof(IntelHDAState, corb_ubase),
+ },
+ [ ICH6_REG_CORBWP ] = {
+ .name = "CORBWP",
+ .size = 2,
+ .wmask = 0xff,
+ .offset = offsetof(IntelHDAState, corb_wp),
+ .whandler = intel_hda_set_corb_wp,
+ },
+ [ ICH6_REG_CORBRP ] = {
+ .name = "CORBRP",
+ .size = 2,
+ .wmask = 0x80ff,
+ .offset = offsetof(IntelHDAState, corb_rp),
+ },
+ [ ICH6_REG_CORBCTL ] = {
+ .name = "CORBCTL",
+ .size = 1,
+ .wmask = 0x03,
+ .offset = offsetof(IntelHDAState, corb_ctl),
+ .whandler = intel_hda_set_corb_ctl,
+ },
+ [ ICH6_REG_CORBSTS ] = {
+ .name = "CORBSTS",
+ .size = 1,
+ .wmask = 0x01,
+ .wclear = 0x01,
+ .offset = offsetof(IntelHDAState, corb_sts),
+ },
+ [ ICH6_REG_CORBSIZE ] = {
+ .name = "CORBSIZE",
+ .size = 1,
+ .reset = 0x42,
+ .offset = offsetof(IntelHDAState, corb_size),
+ },
+ [ ICH6_REG_RIRBLBASE ] = {
+ .name = "RIRBLBASE",
+ .size = 4,
+ .wmask = 0xffffff80,
+ .offset = offsetof(IntelHDAState, rirb_lbase),
+ },
+ [ ICH6_REG_RIRBUBASE ] = {
+ .name = "RIRBUBASE",
+ .size = 4,
+ .wmask = 0xffffffff,
+ .offset = offsetof(IntelHDAState, rirb_ubase),
+ },
+ [ ICH6_REG_RIRBWP ] = {
+ .name = "RIRBWP",
+ .size = 2,
+ .wmask = 0x8000,
+ .offset = offsetof(IntelHDAState, rirb_wp),
+ .whandler = intel_hda_set_rirb_wp,
+ },
+ [ ICH6_REG_RINTCNT ] = {
+ .name = "RINTCNT",
+ .size = 2,
+ .wmask = 0xff,
+ .offset = offsetof(IntelHDAState, rirb_cnt),
+ },
+ [ ICH6_REG_RIRBCTL ] = {
+ .name = "RIRBCTL",
+ .size = 1,
+ .wmask = 0x07,
+ .offset = offsetof(IntelHDAState, rirb_ctl),
+ },
+ [ ICH6_REG_RIRBSTS ] = {
+ .name = "RIRBSTS",
+ .size = 1,
+ .wmask = 0x05,
+ .wclear = 0x05,
+ .offset = offsetof(IntelHDAState, rirb_sts),
+ .whandler = intel_hda_set_rirb_sts,
+ },
+ [ ICH6_REG_RIRBSIZE ] = {
+ .name = "RIRBSIZE",
+ .size = 1,
+ .reset = 0x42,
+ .offset = offsetof(IntelHDAState, rirb_size),
+ },
+
+ [ ICH6_REG_DPLBASE ] = {
+ .name = "DPLBASE",
+ .size = 4,
+ .wmask = 0xffffff81,
+ .offset = offsetof(IntelHDAState, dp_lbase),
+ },
+ [ ICH6_REG_DPUBASE ] = {
+ .name = "DPUBASE",
+ .size = 4,
+ .wmask = 0xffffffff,
+ .offset = offsetof(IntelHDAState, dp_ubase),
+ },
+
+ [ ICH6_REG_IC ] = {
+ .name = "ICW",
+ .size = 4,
+ .wmask = 0xffffffff,
+ .offset = offsetof(IntelHDAState, icw),
+ },
+ [ ICH6_REG_IR ] = {
+ .name = "IRR",
+ .size = 4,
+ .offset = offsetof(IntelHDAState, irr),
+ },
+ [ ICH6_REG_IRS ] = {
+ .name = "ICS",
+ .size = 2,
+ .wmask = 0x0003,
+ .wclear = 0x0002,
+ .offset = offsetof(IntelHDAState, ics),
+ .whandler = intel_hda_set_ics,
+ },
+
+#define HDA_STREAM(_t, _i) \
+ [ ST_REG(_i, ICH6_REG_SD_CTL) ] = { \
+ .stream = _i, \
+ .name = _t stringify(_i) " CTL", \
+ .size = 4, \
+ .wmask = 0x1cff001f, \
+ .offset = offsetof(IntelHDAState, st[_i].ctl), \
+ .whandler = intel_hda_set_st_ctl, \
+ }, \
+ [ ST_REG(_i, ICH6_REG_SD_CTL) + 2] = { \
+ .stream = _i, \
+ .name = _t stringify(_i) " CTL(stnr)", \
+ .size = 1, \
+ .shift = 16, \
+ .wmask = 0x00ff0000, \
+ .offset = offsetof(IntelHDAState, st[_i].ctl), \
+ .whandler = intel_hda_set_st_ctl, \
+ }, \
+ [ ST_REG(_i, ICH6_REG_SD_STS)] = { \
+ .stream = _i, \
+ .name = _t stringify(_i) " CTL(sts)", \
+ .size = 1, \
+ .shift = 24, \
+ .wmask = 0x1c000000, \
+ .wclear = 0x1c000000, \
+ .offset = offsetof(IntelHDAState, st[_i].ctl), \
+ .whandler = intel_hda_set_st_ctl, \
+ }, \
+ [ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \
+ .stream = _i, \
+ .name = _t stringify(_i) " LPIB", \
+ .size = 4, \
+ .offset = offsetof(IntelHDAState, st[_i].lpib), \
+ }, \
+ [ ST_REG(_i, ICH6_REG_SD_LPIB) + 0x2000 ] = { \
+ .stream = _i, \
+ .name = _t stringify(_i) " LPIB(alias)", \
+ .size = 4, \
+ .offset = offsetof(IntelHDAState, st[_i].lpib), \
+ }, \
+ [ ST_REG(_i, ICH6_REG_SD_CBL) ] = { \
+ .stream = _i, \
+ .name = _t stringify(_i) " CBL", \
+ .size = 4, \
+ .wmask = 0xffffffff, \
+ .offset = offsetof(IntelHDAState, st[_i].cbl), \
+ }, \
+ [ ST_REG(_i, ICH6_REG_SD_LVI) ] = { \
+ .stream = _i, \
+ .name = _t stringify(_i) " LVI", \
+ .size = 2, \
+ .wmask = 0x00ff, \
+ .offset = offsetof(IntelHDAState, st[_i].lvi), \
+ }, \
+ [ ST_REG(_i, ICH6_REG_SD_FIFOSIZE) ] = { \
+ .stream = _i, \
+ .name = _t stringify(_i) " FIFOS", \
+ .size = 2, \
+ .reset = HDA_BUFFER_SIZE, \
+ }, \
+ [ ST_REG(_i, ICH6_REG_SD_FORMAT) ] = { \
+ .stream = _i, \
+ .name = _t stringify(_i) " FMT", \
+ .size = 2, \
+ .wmask = 0x7f7f, \
+ .offset = offsetof(IntelHDAState, st[_i].fmt), \
+ }, \
+ [ ST_REG(_i, ICH6_REG_SD_BDLPL) ] = { \
+ .stream = _i, \
+ .name = _t stringify(_i) " BDLPL", \
+ .size = 4, \
+ .wmask = 0xffffff80, \
+ .offset = offsetof(IntelHDAState, st[_i].bdlp_lbase), \
+ }, \
+ [ ST_REG(_i, ICH6_REG_SD_BDLPU) ] = { \
+ .stream = _i, \
+ .name = _t stringify(_i) " BDLPU", \
+ .size = 4, \
+ .wmask = 0xffffffff, \
+ .offset = offsetof(IntelHDAState, st[_i].bdlp_ubase), \
+ }, \
+
+ HDA_STREAM("IN", 0)
+ HDA_STREAM("IN", 1)
+ HDA_STREAM("IN", 2)
+ HDA_STREAM("IN", 3)
+
+ HDA_STREAM("OUT", 4)
+ HDA_STREAM("OUT", 5)
+ HDA_STREAM("OUT", 6)
+ HDA_STREAM("OUT", 7)
+
+};
+
+static const IntelHDAReg *intel_hda_reg_find(IntelHDAState *d, target_phys_addr_t addr)
+{
+ const IntelHDAReg *reg;
+
+ if (addr >= sizeof(regtab)/sizeof(regtab[0])) {
+ goto noreg;
+ }
+ reg = regtab+addr;
+ if (reg->name == NULL) {
+ goto noreg;
+ }
+ return reg;
+
+noreg:
+ dprint(d, 1, "unknown register, addr 0x%x\n", (int) addr);
+ return NULL;
+}
+
+static uint32_t *intel_hda_reg_addr(IntelHDAState *d, const IntelHDAReg *reg)
+{
+ uint8_t *addr = (void*)d;
+
+ addr += reg->offset;
+ return (uint32_t*)addr;
+}
+
+static void intel_hda_reg_write(IntelHDAState *d, const IntelHDAReg *reg, uint32_t val,
+ uint32_t wmask)
+{
+ uint32_t *addr;
+ uint32_t old;
+
+ if (!reg) {
+ return;
+ }
+
+ if (d->debug) {
+ time_t now = time(NULL);
+ if (d->last_write && d->last_reg == reg && d->last_val == val) {
+ d->repeat_count++;
+ if (d->last_sec != now) {
+ dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+ d->last_sec = now;
+ d->repeat_count = 0;
+ }
+ } else {
+ if (d->repeat_count) {
+ dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+ }
+ dprint(d, 2, "write %-16s: 0x%x (%x)\n", reg->name, val, wmask);
+ d->last_write = 1;
+ d->last_reg = reg;
+ d->last_val = val;
+ d->last_sec = now;
+ d->repeat_count = 0;
+ }
+ }
+ assert(reg->offset != 0);
+
+ addr = intel_hda_reg_addr(d, reg);
+ old = *addr;
+
+ if (reg->shift) {
+ val <<= reg->shift;
+ wmask <<= reg->shift;
+ }
+ wmask &= reg->wmask;
+ *addr &= ~wmask;
+ *addr |= wmask & val;
+ *addr &= ~(val & reg->wclear);
+
+ if (reg->whandler) {
+ reg->whandler(d, reg, old);
+ }
+}
+
+static uint32_t intel_hda_reg_read(IntelHDAState *d, const IntelHDAReg *reg,
+ uint32_t rmask)
+{
+ uint32_t *addr, ret;
+
+ if (!reg) {
+ return 0;
+ }
+
+ if (reg->rhandler) {
+ reg->rhandler(d, reg);
+ }
+
+ if (reg->offset == 0) {
+ /* constant read-only register */
+ ret = reg->reset;
+ } else {
+ addr = intel_hda_reg_addr(d, reg);
+ ret = *addr;
+ if (reg->shift) {
+ ret >>= reg->shift;
+ }
+ ret &= rmask;
+ }
+ if (d->debug) {
+ time_t now = time(NULL);
+ if (!d->last_write && d->last_reg == reg && d->last_val == ret) {
+ d->repeat_count++;
+ if (d->last_sec != now) {
+ dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+ d->last_sec = now;
+ d->repeat_count = 0;
+ }
+ } else {
+ if (d->repeat_count) {
+ dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+ }
+ dprint(d, 2, "read %-16s: 0x%x (%x)\n", reg->name, ret, rmask);
+ d->last_write = 0;
+ d->last_reg = reg;
+ d->last_val = ret;
+ d->last_sec = now;
+ d->repeat_count = 0;
+ }
+ }
+ return ret;
+}
+
+static void intel_hda_regs_reset(IntelHDAState *d)
+{
+ uint32_t *addr;
+ int i;
+
+ for (i = 0; i < sizeof(regtab)/sizeof(regtab[0]); i++) {
+ if (regtab[i].name == NULL) {
+ continue;
+ }
+ if (regtab[i].offset == 0) {
+ continue;
+ }
+ addr = intel_hda_reg_addr(d, regtab + i);
+ *addr = regtab[i].reset;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void intel_hda_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ IntelHDAState *d = opaque;
+ const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+ intel_hda_reg_write(d, reg, val, 0xff);
+}
+
+static void intel_hda_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ IntelHDAState *d = opaque;
+ const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+ intel_hda_reg_write(d, reg, val, 0xffff);
+}
+
+static void intel_hda_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ IntelHDAState *d = opaque;
+ const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+ intel_hda_reg_write(d, reg, val, 0xffffffff);
+}
+
+static uint32_t intel_hda_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+ IntelHDAState *d = opaque;
+ const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+ return intel_hda_reg_read(d, reg, 0xff);
+}
+
+static uint32_t intel_hda_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+ IntelHDAState *d = opaque;
+ const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+ return intel_hda_reg_read(d, reg, 0xffff);
+}
+
+static uint32_t intel_hda_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+ IntelHDAState *d = opaque;
+ const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+ return intel_hda_reg_read(d, reg, 0xffffffff);
+}
+
+static CPUReadMemoryFunc * const intel_hda_mmio_read[3] = {
+ intel_hda_mmio_readb,
+ intel_hda_mmio_readw,
+ intel_hda_mmio_readl,
+};
+
+static CPUWriteMemoryFunc * const intel_hda_mmio_write[3] = {
+ intel_hda_mmio_writeb,
+ intel_hda_mmio_writew,
+ intel_hda_mmio_writel,
+};
+
+static void intel_hda_map(PCIDevice *pci, int region_num,
+ pcibus_t addr, pcibus_t size, int type)
+{
+ IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+
+ cpu_register_physical_memory(addr, 0x4000, d->mmio_addr);
+}
+
+/* --------------------------------------------------------------------- */
+
+static void intel_hda_reset(DeviceState *dev)
+{
+ IntelHDAState *d = DO_UPCAST(IntelHDAState, pci.qdev, dev);
+ DeviceState *qdev;
+ HDACodecDevice *cdev;
+
+ intel_hda_regs_reset(d);
+ d->wall_base_ns = qemu_get_clock(vm_clock);
+
+ /* reset codecs */
+ QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+ cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+ if (qdev->info->reset) {
+ qdev->info->reset(qdev);
+ }
+ d->state_sts |= (1 << cdev->cad);
+ }
+ intel_hda_update_irq(d);
+}
+
+static int intel_hda_init(PCIDevice *pci)
+{
+ IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+ uint8_t *conf = d->pci.config;
+
+ d->name = d->pci.qdev.info->name;
+
+ pci_config_set_vendor_id(conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(conf, 0x2668);
+ pci_config_set_revision(conf, 1);
+ pci_config_set_class(conf, PCI_CLASS_MULTIMEDIA_HD_AUDIO);
+ pci_config_set_interrupt_pin(conf, 1);
+
+ /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
+ conf[0x40] = 0x01;
+
+ d->mmio_addr = cpu_register_io_memory(intel_hda_mmio_read,
+ intel_hda_mmio_write, d);
+ pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY,
+ intel_hda_map);
+
+ hda_codec_bus_init(&d->pci.qdev, &d->codecs,
+ intel_hda_response, intel_hda_xfer);
+
+ return 0;
+}
+
+static int intel_hda_post_load(void *opaque, int version)
+{
+ IntelHDAState* d = opaque;
+ int i;
+
+ dprint(d, 1, "%s\n", __FUNCTION__);
+ for (i = 0; i < ARRAY_SIZE(d->st); i++) {
+ if (d->st[i].ctl & 0x02) {
+ intel_hda_parse_bdl(d, &d->st[i]);
+ }
+ }
+ intel_hda_update_irq(d);
+ return 0;
+}
+
+static const VMStateDescription vmstate_intel_hda_stream = {
+ .name = "intel-hda-stream",
+ .version_id = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32(ctl, IntelHDAStream),
+ VMSTATE_UINT32(lpib, IntelHDAStream),
+ VMSTATE_UINT32(cbl, IntelHDAStream),
+ VMSTATE_UINT32(lvi, IntelHDAStream),
+ VMSTATE_UINT32(fmt, IntelHDAStream),
+ VMSTATE_UINT32(bdlp_lbase, IntelHDAStream),
+ VMSTATE_UINT32(bdlp_ubase, IntelHDAStream),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_intel_hda = {
+ .name = "intel-hda",
+ .version_id = 1,
+ .post_load = intel_hda_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_PCI_DEVICE(pci, IntelHDAState),
+
+ /* registers */
+ VMSTATE_UINT32(g_ctl, IntelHDAState),
+ VMSTATE_UINT32(wake_en, IntelHDAState),
+ VMSTATE_UINT32(state_sts, IntelHDAState),
+ VMSTATE_UINT32(int_ctl, IntelHDAState),
+ VMSTATE_UINT32(int_sts, IntelHDAState),
+ VMSTATE_UINT32(wall_clk, IntelHDAState),
+ VMSTATE_UINT32(corb_lbase, IntelHDAState),
+ VMSTATE_UINT32(corb_ubase, IntelHDAState),
+ VMSTATE_UINT32(corb_rp, IntelHDAState),
+ VMSTATE_UINT32(corb_wp, IntelHDAState),
+ VMSTATE_UINT32(corb_ctl, IntelHDAState),
+ VMSTATE_UINT32(corb_sts, IntelHDAState),
+ VMSTATE_UINT32(corb_size, IntelHDAState),
+ VMSTATE_UINT32(rirb_lbase, IntelHDAState),
+ VMSTATE_UINT32(rirb_ubase, IntelHDAState),
+ VMSTATE_UINT32(rirb_wp, IntelHDAState),
+ VMSTATE_UINT32(rirb_cnt, IntelHDAState),
+ VMSTATE_UINT32(rirb_ctl, IntelHDAState),
+ VMSTATE_UINT32(rirb_sts, IntelHDAState),
+ VMSTATE_UINT32(rirb_size, IntelHDAState),
+ VMSTATE_UINT32(dp_lbase, IntelHDAState),
+ VMSTATE_UINT32(dp_ubase, IntelHDAState),
+ VMSTATE_UINT32(icw, IntelHDAState),
+ VMSTATE_UINT32(irr, IntelHDAState),
+ VMSTATE_UINT32(ics, IntelHDAState),
+ VMSTATE_STRUCT_ARRAY(st, IntelHDAState, 8, 0,
+ vmstate_intel_hda_stream,
+ IntelHDAStream),
+
+ /* additional state info */
+ VMSTATE_UINT32(rirb_count, IntelHDAState),
+ VMSTATE_INT64(wall_base_ns, IntelHDAState),
+
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static PCIDeviceInfo intel_hda_info = {
+ .qdev.name = "intel-hda",
+ .qdev.desc = "Intel HD Audio Controller",
+ .qdev.size = sizeof(IntelHDAState),
+ .qdev.vmsd = &vmstate_intel_hda,
+ .qdev.reset = intel_hda_reset,
+ .init = intel_hda_init,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void intel_hda_register(void)
+{
+ pci_qdev_register(&intel_hda_info);
+}
+device_init(intel_hda_register);
+
+/*
+ * create intel hda controller with codec attached to it,
+ * so '-soundhw hda' works.
+ */
+int intel_hda_and_codec_init(PCIBus *bus)
+{
+ PCIDevice *controller;
+ BusState *hdabus;
+ DeviceState *codec;
+
+ controller = pci_create_simple(bus, -1, "intel-hda");
+ hdabus = QLIST_FIRST(&controller->qdev.child_bus);
+ codec = qdev_create(hdabus, "hda-duplex");
+ qdev_init_nofail(codec);
+ return 0;
+}
+
diff --git a/hw/intel-hda.h b/hw/intel-hda.h
new file mode 100644
index 0000000..ba290ec
--- /dev/null
+++ b/hw/intel-hda.h
@@ -0,0 +1,61 @@
+#ifndef HW_INTEL_HDA_H
+#define HW_INTEL_HDA_H
+
+#include "qdev.h"
+
+/* --------------------------------------------------------------------- */
+/* hda bus */
+
+typedef struct HDACodecBus HDACodecBus;
+typedef struct HDACodecDevice HDACodecDevice;
+typedef struct HDACodecDeviceInfo HDACodecDeviceInfo;
+
+typedef void (*hda_codec_response_func)(HDACodecDevice *dev,
+ bool solicited, uint32_t response);
+typedef bool (*hda_codec_xfer_func)(HDACodecDevice *dev,
+ uint32_t stnr, bool output,
+ uint8_t *buf, uint32_t len);
+
+struct HDACodecBus {
+ BusState qbus;
+ uint32_t next_cad;
+ hda_codec_response_func response;
+ hda_codec_xfer_func xfer;
+};
+
+struct HDACodecDevice {
+ DeviceState qdev;
+ HDACodecDeviceInfo *info;
+ uint32_t cad; /* codec address */
+};
+
+struct HDACodecDeviceInfo {
+ DeviceInfo qdev;
+ int (*init)(HDACodecDevice *dev);
+ void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
+ void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running);
+};
+
+void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
+ hda_codec_response_func response,
+ hda_codec_xfer_func xfer);
+void hda_codec_register(HDACodecDeviceInfo *info);
+HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad);
+
+void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response);
+bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
+ uint8_t *buf, uint32_t len);
+
+/* --------------------------------------------------------------------- */
+
+#define dprint(_dev, _level, _fmt, ...) \
+ do { \
+ if (_dev->debug >= _level) { \
+ fprintf(stderr, "%s: ", _dev->name); \
+ fprintf(stderr, _fmt, ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+/* --------------------------------------------------------------------- */
+
+#endif
commit cdae5cfbd3a61a5d4de79b829fb41188073d3002
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon Nov 1 15:51:54 2010 +0100
add VMSTATE_BOOL
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/hw/hw.h b/hw/hw.h
index 4405092..9d2cfc2 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -333,6 +333,8 @@ struct VMStateDescription {
const VMStateSubsection *subsections;
};
+extern const VMStateInfo vmstate_info_bool;
+
extern const VMStateInfo vmstate_info_int8;
extern const VMStateInfo vmstate_info_int16;
extern const VMStateInfo vmstate_info_int32;
@@ -602,6 +604,9 @@ extern const VMStateDescription vmstate_i2c_slave;
#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type) \
VMSTATE_STRUCT_POINTER_TEST(_field, _state, NULL, _vmsd, _type)
+#define VMSTATE_BOOL_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_bool, bool)
+
#define VMSTATE_INT8_V(_f, _s, _v) \
VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int8, int8_t)
#define VMSTATE_INT16_V(_f, _s, _v) \
@@ -620,6 +625,9 @@ extern const VMStateDescription vmstate_i2c_slave;
#define VMSTATE_UINT64_V(_f, _s, _v) \
VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64, uint64_t)
+#define VMSTATE_BOOL(_f, _s) \
+ VMSTATE_BOOL_V(_f, _s, 0)
+
#define VMSTATE_INT8(_f, _s) \
VMSTATE_INT8_V(_f, _s, 0)
#define VMSTATE_INT16(_f, _s) \
@@ -674,6 +682,12 @@ extern const VMStateDescription vmstate_i2c_slave;
#define VMSTATE_PTIMER(_f, _s) \
VMSTATE_PTIMER_V(_f, _s, 0)
+#define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool)
+
+#define VMSTATE_BOOL_ARRAY(_f, _s, _n) \
+ VMSTATE_BOOL_ARRAY_V(_f, _s, _n, 0)
+
#define VMSTATE_UINT16_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint16, uint16_t)
diff --git a/savevm.c b/savevm.c
index 2d8cadc..4e49765 100644
--- a/savevm.c
+++ b/savevm.c
@@ -675,6 +675,27 @@ uint64_t qemu_get_be64(QEMUFile *f)
return v;
}
+/* bool */
+
+static int get_bool(QEMUFile *f, void *pv, size_t size)
+{
+ bool *v = pv;
+ *v = qemu_get_byte(f);
+ return 0;
+}
+
+static void put_bool(QEMUFile *f, void *pv, size_t size)
+{
+ bool *v = pv;
+ qemu_put_byte(f, *v);
+}
+
+const VMStateInfo vmstate_info_bool = {
+ .name = "bool",
+ .get = get_bool,
+ .put = put_bool,
+};
+
/* 8 bit int */
static int get_int8(QEMUFile *f, void *pv, size_t size)
commit b907b69dd75415bc28349d1dd1e9a598ddace463
Merge: df2943b... 804b207...
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Wed Oct 27 19:07:10 2010 +0200
Merge branch 'pci' into for_anthony
commit 804b207170cdccca3672b63caaf82312ad205a7f
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Wed Oct 27 17:48:42 2010 +0200
pcie: update satus on reset
Reset never triggers a new event, so it's enough to
update status.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pcie.c b/hw/pcie.c
index 373e33e..35918f7 100644
--- a/hw/pcie.c
+++ b/hw/pcie.c
@@ -307,7 +307,7 @@ void pcie_cap_slot_reset(PCIDevice *dev)
PCI_EXP_SLTSTA_PDC |
PCI_EXP_SLTSTA_ABP);
- hotplug_event_notify(dev);
+ hotplug_event_update_event_status(dev);
}
void pcie_cap_slot_write_config(PCIDevice *dev,
commit b794ec7ce8ac1aaac825e554c20d1aae1422374e
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Wed Oct 27 16:28:22 2010 +0200
msi: minor cleanups
Comment fixup (tell what it does not what it does not do),
typo fix, whitespace fix.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/msi.c b/hw/msi.c
index 016e7a4..f03f519 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -155,9 +155,8 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
pci_set_word(dev->wmask + msi_data_off(dev, msi64bit), 0xffff);
if (msi_per_vector_mask) {
+ /* Make mask bits 0 to nr_vectors - 1 writeable. */
pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit),
- /* (1U << nr_vectors) - 1 is undefined
- when nr_vectors = 32 */
0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors));
}
return config_offset;
@@ -225,7 +224,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
return;
}
- if (msi64bit){
+ if (msi64bit) {
address = pci_get_quad(dev->config + msi_address_lo_off(dev));
} else {
address = pci_get_long(dev->config + msi_address_lo_off(dev));
@@ -269,7 +268,7 @@ void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
flags,
pci_get_long(dev->config + msi_address_lo_off(dev)));
if (msi64bit) {
- fprintf(stderr, " addrss-hi: 0x%"PRIx32,
+ fprintf(stderr, " address-hi: 0x%"PRIx32,
pci_get_long(dev->config + msi_address_hi_off(dev)));
}
fprintf(stderr, " data: 0x%"PRIx16,
commit 531a0b82dd0ad352819d4deffe1ecd7f52975fbf
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Wed Oct 27 16:14:56 2010 +0200
msi: simplify range checks
config write handlers should be idempotent.
So no need for complex range checks: a simple
one checking that we are touching the relevant capability
will do.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/msi.c b/hw/msi.c
index 0f2913a..016e7a4 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -258,34 +258,29 @@ void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
uint32_t pending;
int i;
-#ifdef MSI_DEBUG
- if (ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
- MSI_DEV_PRINTF(dev, "addr 0x%"PRIx32" val 0x%"PRIx32" len %d\n",
- addr, val, len);
- MSI_DEV_PRINTF(dev, "ctrl: 0x%"PRIx16" address: 0x%"PRIx32,
- flags,
- pci_get_long(dev->config + msi_address_lo_off(dev)));
- if (msi64bit) {
- fprintf(stderr, " addrss-hi: 0x%"PRIx32,
- pci_get_long(dev->config + msi_address_hi_off(dev)));
- }
- fprintf(stderr, " data: 0x%"PRIx16,
- pci_get_word(dev->config + msi_data_off(dev, msi64bit)));
- if (flags & PCI_MSI_FLAGS_MASKBIT) {
- fprintf(stderr, " mask 0x%"PRIx32" pending 0x%"PRIx32,
- pci_get_long(dev->config + msi_mask_off(dev, msi64bit)),
- pci_get_long(dev->config + msi_pending_off(dev, msi64bit)));
- }
- fprintf(stderr, "\n");
+ if (!ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
+ return;
}
-#endif
- /* Are we modified? */
- if (!(ranges_overlap(addr, len, msi_flags_off(dev), 2) ||
- (msi_per_vector_mask &&
- ranges_overlap(addr, len, msi_mask_off(dev, msi64bit), 4)))) {
- return;
+#ifdef MSI_DEBUG
+ MSI_DEV_PRINTF(dev, "addr 0x%"PRIx32" val 0x%"PRIx32" len %d\n",
+ addr, val, len);
+ MSI_DEV_PRINTF(dev, "ctrl: 0x%"PRIx16" address: 0x%"PRIx32,
+ flags,
+ pci_get_long(dev->config + msi_address_lo_off(dev)));
+ if (msi64bit) {
+ fprintf(stderr, " addrss-hi: 0x%"PRIx32,
+ pci_get_long(dev->config + msi_address_hi_off(dev)));
}
+ fprintf(stderr, " data: 0x%"PRIx16,
+ pci_get_word(dev->config + msi_data_off(dev, msi64bit)));
+ if (flags & PCI_MSI_FLAGS_MASKBIT) {
+ fprintf(stderr, " mask 0x%"PRIx32" pending 0x%"PRIx32,
+ pci_get_long(dev->config + msi_mask_off(dev, msi64bit)),
+ pci_get_long(dev->config + msi_pending_off(dev, msi64bit)));
+ }
+ fprintf(stderr, "\n");
+#endif
if (!(flags & PCI_MSI_FLAGS_ENABLE)) {
return;
commit f9aebe2ef52ff0dcb733999f57e00a7b430303c6
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Wed Oct 27 16:01:25 2010 +0200
pci: improve w1c mask handling
- save/restore must not check w1c bits
since they are in fact guest controlled
- clear w1c bits on reset
Note: for express there are different kinds of
reset, some leave part of config space alone.
We will likely need a sticky bit mask to implement this.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index 409e2c0..5386f5a 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -140,7 +140,8 @@ static void pci_device_reset(PCIDevice *dev)
pci_update_irq_status(dev);
/* Clear all writeable bits */
pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
- pci_get_word(dev->wmask + PCI_COMMAND));
+ pci_get_word(dev->wmask + PCI_COMMAND) |
+ pci_get_word(dev->w1cmask + PCI_COMMAND));
dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
dev->config[PCI_INTERRUPT_LINE] = 0x0;
for (r = 0; r < PCI_NUM_REGIONS; ++r) {
@@ -292,7 +293,8 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
qemu_get_buffer(f, config, size);
for (i = 0; i < size; ++i) {
- if ((config[i] ^ s->config[i]) & s->cmask[i] & ~s->wmask[i]) {
+ if ((config[i] ^ s->config[i]) &
+ s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) {
qemu_free(config);
return -EINVAL;
}
commit 6bde6aaac6f2af14557ef65f5eb053cb135ca173
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Mon Oct 25 07:46:47 2010 +0200
pcie: clean up hot plug notification
Simplify logic for hotplug notification, by tracking state of the
logical interrupt condition. We then simply use this variable to make
the interrupt decision, according to spec.
API is made cleaner as we no longer force users to pass in
old slot control value.
Includes fixes by Isaku Yamahata.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
index 1f340d3..3cc129f 100644
--- a/hw/ioh3420.c
+++ b/hw/ioh3420.c
@@ -39,12 +39,9 @@
static void ioh3420_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len)
{
- uint16_t sltctl =
- pci_get_word(d->config + d->exp.exp_cap + PCI_EXP_SLTCTL);
-
pci_bridge_write_config(d, address, val, len);
msi_write_config(d, address, val, len);
- pcie_cap_slot_write_config(d, address, val, len, sltctl);
+ pcie_cap_slot_write_config(d, address, val, len);
/* TODO: AER */
}
@@ -142,6 +139,7 @@ static const VMStateDescription vmstate_ioh3420 = {
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
+ .post_load = pcie_cap_slot_post_load,
.fields = (VMStateField[]) {
VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot),
/* TODO: AER */
diff --git a/hw/pcie.c b/hw/pcie.c
index bfccf5e..373e33e 100644
--- a/hw/pcie.c
+++ b/hw/pcie.c
@@ -140,6 +140,40 @@ void pcie_cap_deverr_reset(PCIDevice *dev)
PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
}
+static void hotplug_event_update_event_status(PCIDevice *dev)
+{
+ uint32_t pos = dev->exp.exp_cap;
+ uint8_t *exp_cap = dev->config + pos;
+ uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
+ uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+
+ dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) &&
+ (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED);
+}
+
+static void hotplug_event_notify(PCIDevice *dev)
+{
+ bool prev = dev->exp.hpev_notified;
+
+ hotplug_event_update_event_status(dev);
+
+ if (prev == dev->exp.hpev_notified) {
+ return;
+ }
+
+ /* Note: the logic above does not take into account whether interrupts
+ * are masked. The result is that interrupt will be sent when it is
+ * subsequently unmasked. This appears to be legal: Section 6.7.3.4:
+ * The Port may optionally send an MSI when there are hot-plug events that
+ * occur while interrupt generation is disabled, and interrupt generation is
+ * subsequently enabled. */
+ if (!pci_msi_enabled(dev)) {
+ qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified);
+ } else if (dev->exp.hpev_notified) {
+ pci_msi_notify(dev, pcie_cap_flags_get_vector(dev));
+ }
+}
+
/*
* A PCI Express Hot-Plug Event has occured, so update slot status register
* and notify OS of the event if necessary.
@@ -149,28 +183,12 @@ void pcie_cap_deverr_reset(PCIDevice *dev)
*/
static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
{
- uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
- uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
- uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
-
- PCIE_DEV_PRINTF(dev,
- "sltctl: 0x%02"PRIx16" sltsta: 0x%02"PRIx16" event: %x\n",
- sltctl, sltsta, event);
-
- if (pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, event)) {
+ /* Minor optimization: if nothing changed - no event is needed. */
+ if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap +
+ PCI_EXP_SLTSTA, event)) {
return;
}
- sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
- PCIE_DEV_PRINTF(dev, "sltsta -> %02"PRIx16"\n", sltsta);
-
- if ((sltctl & PCI_EXP_SLTCTL_HPIE) &&
- (sltctl & event & PCI_EXP_HP_EV_SUPPORTED)) {
- if (pci_msi_enabled(dev)) {
- pci_msi_notify(dev, pcie_cap_flags_get_vector(dev));
- } else {
- qemu_set_irq(dev->irq[dev->exp.hpev_intx], 1);
- }
- }
+ hotplug_event_notify(dev);
}
static int pcie_cap_slot_hotplug(DeviceState *qdev,
@@ -258,6 +276,8 @@ void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot)
pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA,
PCI_EXP_HP_EV_SUPPORTED);
+ dev->exp.hpev_notified = false;
+
pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)),
pcie_cap_slot_hotplug, &dev->qdev);
}
@@ -286,31 +306,21 @@ void pcie_cap_slot_reset(PCIDevice *dev)
PCI_EXP_SLTSTA_CC |
PCI_EXP_SLTSTA_PDC |
PCI_EXP_SLTSTA_ABP);
+
+ hotplug_event_notify(dev);
}
void pcie_cap_slot_write_config(PCIDevice *dev,
- uint32_t addr, uint32_t val, int len,
- uint16_t sltctl_prev)
+ uint32_t addr, uint32_t val, int len)
{
uint32_t pos = dev->exp.exp_cap;
uint8_t *exp_cap = dev->config + pos;
- uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
return;
}
- PCIE_DEV_PRINTF(dev,
- "addr: 0x%"PRIx32" val: 0x%"PRIx32" len: %d\n"
- "\tsltctl_prev: 0x%02"PRIx16" sltctl: 0x%02"PRIx16
- " sltsta: 0x%02"PRIx16"\n",
- addr, val, len, sltctl_prev, sltctl, sltsta);
-
- /* SLTCTL */
- PCIE_DEV_PRINTF(dev, "sltctl: 0x%02"PRIx16" -> 0x%02"PRIx16"\n",
- sltctl_prev, sltctl);
-
if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
PCI_EXP_SLTCTL_EIC)) {
sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */
@@ -320,34 +330,7 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
sltsta);
}
- /*
- * The events control bits might be enabled or disabled,
- * Check if the software notificastion condition is satisfied
- * or disatisfied.
- *
- * 6.7.3.4 Software Notification of Hot-plug events
- */
- if (pci_msi_enabled(dev)) {
- bool msi_trigger =
- (sltctl & PCI_EXP_SLTCTL_HPIE) &&
- ((sltctl_prev ^ sltctl) & sltctl & /* stlctl: 0 -> 1 */
- sltsta & PCI_EXP_HP_EV_SUPPORTED);
- if (msi_trigger) {
- pci_msi_notify(dev, pcie_cap_flags_get_vector(dev));
- }
- } else {
- int int_level =
- (sltctl & PCI_EXP_SLTCTL_HPIE) &&
- (sltctl & sltsta & PCI_EXP_HP_EV_SUPPORTED);
- qemu_set_irq(dev->irq[dev->exp.hpev_intx], int_level);
- }
-
- if (!((sltctl_prev ^ sltctl) & PCI_EXP_SLTCTL_SUPPORTED)) {
- PCIE_DEV_PRINTF(dev,
- "sprious command completion slctl "
- "0x%"PRIx16" -> 0x%"PRIx16"\n",
- sltctl_prev, sltctl);
- }
+ hotplug_event_notify(dev);
/*
* 6.7.3.2 Command Completed Events
@@ -368,6 +351,13 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI);
}
+int pcie_cap_slot_post_load(void *opaque, int version_id)
+{
+ PCIDevice *dev = opaque;
+ hotplug_event_update_event_status(dev);
+ return 0;
+}
+
void pcie_cap_slot_push_attention_button(PCIDevice *dev)
{
pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP);
diff --git a/hw/pcie.h b/hw/pcie.h
index 2871e27..8708504 100644
--- a/hw/pcie.h
+++ b/hw/pcie.h
@@ -74,6 +74,11 @@ struct PCIExpressDevice {
* also initialize it when loaded as
* appropreately.
*/
+ bool hpev_notified; /* Logical AND of conditions for hot plug event.
+ Following 6.7.3.4:
+ Software Notification of Hot-Plug Events, an interrupt
+ is sent whenever the logical and of these conditions
+ transitions from false to true. */
};
/* PCI express capability helper functions */
@@ -89,8 +94,8 @@ void pcie_cap_deverr_reset(PCIDevice *dev);
void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot);
void pcie_cap_slot_reset(PCIDevice *dev);
void pcie_cap_slot_write_config(PCIDevice *dev,
- uint32_t addr, uint32_t val, int len,
- uint16_t sltctl_prev);
+ uint32_t addr, uint32_t val, int len);
+int pcie_cap_slot_post_load(void *opaque, int version_id);
void pcie_cap_slot_push_attention_button(PCIDevice *dev);
void pcie_cap_root_init(PCIDevice *dev);
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
index a44e188..854eba8 100644
--- a/hw/xio3130_downstream.c
+++ b/hw/xio3130_downstream.c
@@ -38,12 +38,9 @@
static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
uint32_t val, int len)
{
- uint16_t sltctl =
- pci_get_word(d->config + d->exp.exp_cap + PCI_EXP_SLTCTL);
-
pci_bridge_write_config(d, address, val, len);
pcie_cap_flr_write_config(d, address, val, len);
- pcie_cap_slot_write_config(d, address, val, len, sltctl);
+ pcie_cap_slot_write_config(d, address, val, len);
msi_write_config(d, address, val, len);
/* TODO: AER */
}
@@ -144,6 +141,7 @@ static const VMStateDescription vmstate_xio3130_downstream = {
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
+ .post_load = pcie_cap_slot_post_load,
.fields = (VMStateField[]) {
VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot),
/* TODO: AER */
commit ac0cdda347abee6c1aa8a08a7441fc52c6d7badc
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Mon Oct 25 07:03:24 2010 +0200
pcie: simplify range check
Simplify code slighly by reversing the polarity
for the range check
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
diff --git a/hw/pcie.c b/hw/pcie.c
index 881af78..bfccf5e 100644
--- a/hw/pcie.c
+++ b/hw/pcie.c
@@ -19,6 +19,7 @@
*/
#include "sysemu.h"
+#include "range.h"
#include "pci_bridge.h"
#include "pcie.h"
#include "msix.h"
@@ -296,6 +297,10 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+ if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
+ return;
+ }
+
PCIE_DEV_PRINTF(dev,
"addr: 0x%"PRIx32" val: 0x%"PRIx32" len: %d\n"
"\tsltctl_prev: 0x%02"PRIx16" sltctl: 0x%02"PRIx16
@@ -303,59 +308,64 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
addr, val, len, sltctl_prev, sltctl, sltsta);
/* SLTCTL */
- if (ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
- PCIE_DEV_PRINTF(dev, "sltctl: 0x%02"PRIx16" -> 0x%02"PRIx16"\n",
- sltctl_prev, sltctl);
- if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_EIC)) {
- sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */
- pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
- PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: "
- "sltsta -> 0x%02"PRIx16"\n",
- sltsta);
- }
-
- /*
- * The events control bits might be enabled or disabled,
- * Check if the software notificastion condition is satisfied
- * or disatisfied.
- *
- * 6.7.3.4 Software Notification of Hot-plug events
- */
- if (pci_msi_enabled(dev)) {
- bool msi_trigger =
- (sltctl & PCI_EXP_SLTCTL_HPIE) &&
- ((sltctl_prev ^ sltctl) & sltctl & /* stlctl: 0 -> 1 */
- sltsta & PCI_EXP_HP_EV_SUPPORTED);
- if (msi_trigger) {
- pci_msi_notify(dev, pcie_cap_flags_get_vector(dev));
- }
- } else {
- int int_level =
- (sltctl & PCI_EXP_SLTCTL_HPIE) &&
- (sltctl & sltsta & PCI_EXP_HP_EV_SUPPORTED);
- qemu_set_irq(dev->irq[dev->exp.hpev_intx], int_level);
- }
+ PCIE_DEV_PRINTF(dev, "sltctl: 0x%02"PRIx16" -> 0x%02"PRIx16"\n",
+ sltctl_prev, sltctl);
+
+ if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
+ PCI_EXP_SLTCTL_EIC)) {
+ sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */
+ pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
+ PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: "
+ "sltsta -> 0x%02"PRIx16"\n",
+ sltsta);
+ }
- if (!((sltctl_prev ^ sltctl) & PCI_EXP_SLTCTL_SUPPORTED)) {
- PCIE_DEV_PRINTF(dev,
- "sprious command completion slctl "
- "0x%"PRIx16" -> 0x%"PRIx16"\n",
- sltctl_prev, sltctl);
+ /*
+ * The events control bits might be enabled or disabled,
+ * Check if the software notificastion condition is satisfied
+ * or disatisfied.
+ *
+ * 6.7.3.4 Software Notification of Hot-plug events
+ */
+ if (pci_msi_enabled(dev)) {
+ bool msi_trigger =
+ (sltctl & PCI_EXP_SLTCTL_HPIE) &&
+ ((sltctl_prev ^ sltctl) & sltctl & /* stlctl: 0 -> 1 */
+ sltsta & PCI_EXP_HP_EV_SUPPORTED);
+ if (msi_trigger) {
+ pci_msi_notify(dev, pcie_cap_flags_get_vector(dev));
}
+ } else {
+ int int_level =
+ (sltctl & PCI_EXP_SLTCTL_HPIE) &&
+ (sltctl & sltsta & PCI_EXP_HP_EV_SUPPORTED);
+ qemu_set_irq(dev->irq[dev->exp.hpev_intx], int_level);
+ }
- /* command completion.
- * Real hardware might take a while to complete
- * requested command because physical movement would be involved
- * like locking the electromechanical lock.
- * However in our case, command is completed instantaneously above,
- * so send a command completion event right now.
- *
- * 6.7.3.2 Command Completed Events
- */
- /* set command completed bit */
- pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI);
+ if (!((sltctl_prev ^ sltctl) & PCI_EXP_SLTCTL_SUPPORTED)) {
+ PCIE_DEV_PRINTF(dev,
+ "sprious command completion slctl "
+ "0x%"PRIx16" -> 0x%"PRIx16"\n",
+ sltctl_prev, sltctl);
}
+
+ /*
+ * 6.7.3.2 Command Completed Events
+ *
+ * Software issues a command to a hot-plug capable Downstream Port by
+ * issuing a write transaction that targets any portion of the Portâs Slot
+ * Control register. A single write to the Slot Control register is
+ * considered to be a single command, even if the write affects more than
+ * one field in the Slot Control register. In response to this transaction,
+ * the Port must carry out the requested actions and then set the
+ * associated status field for the command completed event. */
+
+ /* Real hardware might take a while to complete requested command because
+ * physical movement would be involved like locking the electromechanical
+ * lock. However in our case, command is completed instantaneously above,
+ * so send a command completion event right now.
+ */
+ pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI);
}
void pcie_cap_slot_push_attention_button(PCIDevice *dev)
commit 5afb9869171c15c777eee09bc98624221009555f
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sat Sep 18 05:53:14 2010 +0000
Introduce range.h
Extract range functions from pci.h. These will be used by later patches
by non-PCI devices. Adjust current users.
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
(cherry picked from commit bf1b00712375bea65f2254dea8281fa646eebbd5)
diff --git a/hw/msi.c b/hw/msi.c
index a949d82..0f2913a 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -19,6 +19,7 @@
*/
#include "msi.h"
+#include "range.h"
/* Eventually those constants should go to Linux pci_regs.h */
#define PCI_MSI_PENDING_32 0x10
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 7e8488a..58cc2e4 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -31,6 +31,7 @@
#include "pci_bridge.h"
#include "pci_internals.h"
+#include "range.h"
/* PCI bridge subsystem vendor ID helper functions */
#define PCI_SSVID_SIZEOF 8
diff --git a/hw/pcie.c b/hw/pcie.c
index 53d1fce..881af78 100644
--- a/hw/pcie.c
+++ b/hw/pcie.c
@@ -25,6 +25,7 @@
#include "msi.h"
#include "pci_internals.h"
#include "pcie_regs.h"
+#include "range.h"
//#define DEBUG_PCIE
#ifdef DEBUG_PCIE
commit df2943ba3c73ca21dbda063f15fa3e80064af864
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Tue Oct 26 17:53:41 2010 +0200
qemu-options.def: add to generated header list
All files include qemu-options.h which pulls in qemu-options.def from
the root directory. Thus generating qemu-options.def from Makefile.objs
under the target directory is not effective.
Further, people expect .def file to get cleaned with make clean:
it does not have state so no reason to defer removing it
until distclean. Also add a rule to remove old files that might
be around.
This fixes the error: âQEMU_OPTION_spiceâ undeclared
(first use in this function) error that some people reported
which is really down to an out of date .def file.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/Makefile b/Makefile
index a1434b1..cf8f48a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
# Makefile for QEMU.
-GENERATED_HEADERS = config-host.h trace.h
+GENERATED_HEADERS = config-host.h trace.h qemu-options.def
ifneq ($(wildcard config-host.mak),)
# Put the all: rule here so that config-host.mak can contain dependencies.
@@ -71,6 +71,8 @@ build-all: $(DOCS) $(TOOLS) recurse-all
config-host.h: config-host.h-timestamp
config-host.h-timestamp: config-host.mak
+qemu-options.def: qemu-options.hx
+ $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $@")
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
@@ -150,6 +152,7 @@ check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjs
clean:
# avoid old build problems by removing potentially incorrect old files
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
+ rm -f qemu-options.def
rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
rm -f qemu-img-cmds.h
@@ -157,11 +160,11 @@ clean:
$(MAKE) -C tests clean
for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
+ rm -f $$d/qemu-options.def; \
done
distclean: clean
rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi
- rm -f qemu-options.def
rm -f config-all-devices.mak
rm -f roms/seabios/config.mak roms/vgabios/config.mak
rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.dvi qemu-doc.fn qemu-doc.info qemu-doc.ky qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp qemu-doc.vr
diff --git a/Makefile.objs b/Makefile.objs
index f07fb01..231219c 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -285,10 +285,3 @@ vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
-vl.o: qemu-options.def
-os-posix.o: qemu-options.def
-os-win32.o: qemu-options.def
-
-qemu-options.def: $(SRC_PATH)/qemu-options.hx
- $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
-
commit f7c31d6381f2cbac03e82fc23133f6863606edd8
Author: Jason Wang <jasowang at redhat.com>
Date: Mon Oct 25 13:39:59 2010 +0800
net: properly handle illegal fd/vhostfd from command line
When hanlding fd/vhostfd form command line through net_handle_fd_param(),
we need to check mon and return value of strtol() otherwise we could
get segmentation fault or invalid fd when user type an illegal fd/vhostfd.
This patch is based on the suggestions from
Luiz Capitulino <lcapitulino at redhat.com>.
Signed-off-by: Jason Wang <jasowang at redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/net.c b/net.c
index ed74c7f..c5e6063 100644
--- a/net.c
+++ b/net.c
@@ -774,19 +774,25 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models,
int net_handle_fd_param(Monitor *mon, const char *param)
{
- if (!qemu_isdigit(param[0])) {
- int fd;
+ int fd;
+
+ if (!qemu_isdigit(param[0]) && mon) {
fd = monitor_get_fd(mon, param);
if (fd == -1) {
error_report("No file descriptor named %s found", param);
return -1;
}
-
- return fd;
} else {
- return strtol(param, NULL, 0);
+ char *endptr = NULL;
+
+ fd = strtol(param, &endptr, 10);
+ if (*endptr || (fd == 0 && param == endptr)) {
+ return -1;
+ }
}
+
+ return fd;
}
static int net_init_nic(QemuOpts *opts,
commit 258dc7c96bb4b7ca71d5bee811e73933310e168c
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Sun Oct 17 20:23:48 2010 +0200
virtio: sanity-check available index
Checking available index upon load instead of
only when vm is running makes is easier to
debug failures.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/virtio.c b/hw/virtio.c
index c8a0fc6..a2a657e 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -681,6 +681,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
uint32_t features;
uint32_t supported_features =
vdev->binding->get_features(vdev->binding_opaque);
+ uint16_t num_heads;
if (vdev->binding->load_config) {
ret = vdev->binding->load_config(vdev->binding_opaque, f);
@@ -713,6 +714,16 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
if (vdev->vq[i].pa) {
virtqueue_init(&vdev->vq[i]);
}
+ num_heads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
+ /* Check it isn't doing very strange things with descriptor numbers. */
+ if (num_heads > vdev->vq[i].vring.num) {
+ fprintf(stderr, "VQ %d size 0x%x Guest index 0x%x "
+ "inconsistent with Host index 0x%x: delta 0x%x\n",
+ i, vdev->vq[i].vring.num,
+ vring_avail_idx(&vdev->vq[i]),
+ vdev->vq[i].last_avail_idx, num_heads);
+ return -1;
+ }
if (vdev->binding->load_queue) {
ret = vdev->binding->load_queue(vdev->binding_opaque, i, f);
if (ret)
commit 492fb99c4bef274a71178f5fab9b700c469a4230
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Sun Oct 17 20:43:40 2010 +0200
migration: don't segfault on invalid input
host_from_stream_offset returns NULL on error,
return error instead of trying to use that address,
to avoid segfault on invalid stream.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/arch_init.c b/arch_init.c
index a910033..4caadd0 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -390,6 +390,9 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
host = qemu_get_ram_ptr(addr);
else
host = host_from_stream_offset(f, addr, flags);
+ if (!host) {
+ return -EINVAL;
+ }
ch = qemu_get_byte(f);
memset(host, ch, TARGET_PAGE_SIZE);
commit 48ebf2f90f8fba8c03c0bfdb3bd4fe1e8fd5d61b
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Wed Oct 20 17:18:55 2010 +0900
x3130: pcie downstream port
Implement TI x3130 pcie downstream port switch.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/Makefile.objs b/Makefile.objs
index b1ef2bb..138e545 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -140,7 +140,7 @@ hw-obj-y =
hw-obj-y += vl.o loader.o
hw-obj-y += virtio.o virtio-console.o
hw-obj-y += fw_cfg.o pci.o pci_host.o pcie_host.o pci_bridge.o
-hw-obj-y += ioh3420.o xio3130_upstream.o
+hw-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o
hw-obj-y += watchdog.o
hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
hw-obj-$(CONFIG_ECC) += ecc.o
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
new file mode 100644
index 0000000..a44e188
--- /dev/null
+++ b/hw/xio3130_downstream.c
@@ -0,0 +1,190 @@
+/*
+ * x3130_downstream.c
+ * TI X3130 pci express downstream port switch
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci_ids.h"
+#include "msi.h"
+#include "pcie.h"
+#include "xio3130_downstream.h"
+
+#define PCI_DEVICE_ID_TI_XIO3130D 0x8233 /* downstream port */
+#define XIO3130_REVISION 0x1
+#define XIO3130_MSI_OFFSET 0x70
+#define XIO3130_MSI_SUPPORTED_FLAGS PCI_MSI_FLAGS_64BIT
+#define XIO3130_MSI_NR_VECTOR 1
+#define XIO3130_SSVID_OFFSET 0x80
+#define XIO3130_SSVID_SVID 0
+#define XIO3130_SSVID_SSID 0
+#define XIO3130_EXP_OFFSET 0x90
+#define XIO3130_AER_OFFSET 0x100
+
+static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
+ uint32_t val, int len)
+{
+ uint16_t sltctl =
+ pci_get_word(d->config + d->exp.exp_cap + PCI_EXP_SLTCTL);
+
+ pci_bridge_write_config(d, address, val, len);
+ pcie_cap_flr_write_config(d, address, val, len);
+ pcie_cap_slot_write_config(d, address, val, len, sltctl);
+ msi_write_config(d, address, val, len);
+ /* TODO: AER */
+}
+
+static void xio3130_downstream_reset(DeviceState *qdev)
+{
+ PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+ msi_reset(d);
+ pcie_cap_deverr_reset(d);
+ pcie_cap_slot_reset(d);
+ pcie_cap_ari_reset(d);
+ pci_bridge_reset(qdev);
+}
+
+static int xio3130_downstream_initfn(PCIDevice *d)
+{
+ PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+ PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+ PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
+ int rc;
+
+ rc = pci_bridge_initfn(d);
+ if (rc < 0) {
+ return rc;
+ }
+
+ pcie_port_init_reg(d);
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_TI);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_TI_XIO3130D);
+ d->config[PCI_REVISION_ID] = XIO3130_REVISION;
+
+ rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
+ XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
+ XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+ if (rc < 0) {
+ return rc;
+ }
+ rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
+ XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
+ if (rc < 0) {
+ return rc;
+ }
+ rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM,
+ p->port);
+ if (rc < 0) {
+ return rc;
+ }
+ pcie_cap_flr_init(d); /* TODO: implement FLR */
+ pcie_cap_deverr_init(d);
+ pcie_cap_slot_init(d, s->slot);
+ pcie_chassis_create(s->chassis);
+ rc = pcie_chassis_add_slot(s);
+ if (rc < 0) {
+ return rc;
+ }
+ pcie_cap_ari_init(d);
+ /* TODO: AER */
+
+ return 0;
+}
+
+static int xio3130_downstream_exitfn(PCIDevice *d)
+{
+ /* TODO: AER */
+ msi_uninit(d);
+ pcie_cap_exit(d);
+ return pci_bridge_exitfn(d);
+}
+
+PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction,
+ const char *bus_name, pci_map_irq_fn map_irq,
+ uint8_t port, uint8_t chassis,
+ uint16_t slot)
+{
+ PCIDevice *d;
+ PCIBridge *br;
+ DeviceState *qdev;
+
+ d = pci_create_multifunction(bus, devfn, multifunction,
+ "xio3130-downstream");
+ if (!d) {
+ return NULL;
+ }
+ br = DO_UPCAST(PCIBridge, dev, d);
+
+ qdev = &br->dev.qdev;
+ pci_bridge_map_irq(br, bus_name, map_irq);
+ qdev_prop_set_uint8(qdev, "port", port);
+ qdev_prop_set_uint8(qdev, "chassis", chassis);
+ qdev_prop_set_uint16(qdev, "slot", slot);
+ qdev_init_nofail(qdev);
+
+ return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br));
+}
+
+static const VMStateDescription vmstate_xio3130_downstream = {
+ .name = "xio3130-express-downstream-port",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot),
+ /* TODO: AER */
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static PCIDeviceInfo xio3130_downstream_info = {
+ .qdev.name = "xio3130-downstream",
+ .qdev.desc = "TI X3130 Downstream Port of PCI Express Switch",
+ .qdev.size = sizeof(PCIESlot),
+ .qdev.reset = xio3130_downstream_reset,
+ .qdev.vmsd = &vmstate_xio3130_downstream,
+
+ .is_express = 1,
+ .is_bridge = 1,
+ .config_write = xio3130_downstream_write_config,
+ .init = xio3130_downstream_initfn,
+ .exit = xio3130_downstream_exitfn,
+
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
+ DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
+ DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
+ /* TODO: AER */
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void xio3130_downstream_register(void)
+{
+ pci_qdev_register(&xio3130_downstream_info);
+}
+
+device_init(xio3130_downstream_register);
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tab-mode: nil
+ * End:
+ */
diff --git a/hw/xio3130_downstream.h b/hw/xio3130_downstream.h
new file mode 100644
index 0000000..010487f
--- /dev/null
+++ b/hw/xio3130_downstream.h
@@ -0,0 +1,11 @@
+#ifndef QEMU_XIO3130_DOWNSTREAM_H
+#define QEMU_XIO3130_DOWNSTREAM_H
+
+#include "pcie_port.h"
+
+PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction,
+ const char *bus_name, pci_map_irq_fn map_irq,
+ uint8_t port, uint8_t chassis,
+ uint16_t slot);
+
+#endif /* QEMU_XIO3130_DOWNSTREAM_H */
commit faf1e708d5b432757d88b7229fc3b5f2e71cfb2e
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Wed Oct 20 17:18:54 2010 +0900
x3130: pcie upstream port
Implement TI x3130 pcie upstream port switch.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/Makefile.objs b/Makefile.objs
index 3a05322..b1ef2bb 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -140,7 +140,7 @@ hw-obj-y =
hw-obj-y += vl.o loader.o
hw-obj-y += virtio.o virtio-console.o
hw-obj-y += fw_cfg.o pci.o pci_host.o pcie_host.o pci_bridge.o
-hw-obj-y += ioh3420.o
+hw-obj-y += ioh3420.o xio3130_upstream.o
hw-obj-y += watchdog.o
hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
hw-obj-$(CONFIG_ECC) += ecc.o
diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c
new file mode 100644
index 0000000..d9d637f
--- /dev/null
+++ b/hw/xio3130_upstream.c
@@ -0,0 +1,174 @@
+/*
+ * xio3130_upstream.c
+ * TI X3130 pci express upstream port switch
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci_ids.h"
+#include "msi.h"
+#include "pcie.h"
+#include "xio3130_upstream.h"
+
+#define PCI_DEVICE_ID_TI_XIO3130U 0x8232 /* upstream port */
+#define XIO3130_REVISION 0x2
+#define XIO3130_MSI_OFFSET 0x70
+#define XIO3130_MSI_SUPPORTED_FLAGS PCI_MSI_FLAGS_64BIT
+#define XIO3130_MSI_NR_VECTOR 1
+#define XIO3130_SSVID_OFFSET 0x80
+#define XIO3130_SSVID_SVID 0
+#define XIO3130_SSVID_SSID 0
+#define XIO3130_EXP_OFFSET 0x90
+#define XIO3130_AER_OFFSET 0x100
+
+static void xio3130_upstream_write_config(PCIDevice *d, uint32_t address,
+ uint32_t val, int len)
+{
+ pci_bridge_write_config(d, address, val, len);
+ pcie_cap_flr_write_config(d, address, val, len);
+ msi_write_config(d, address, val, len);
+ /* TODO: AER */
+}
+
+static void xio3130_upstream_reset(DeviceState *qdev)
+{
+ PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+ msi_reset(d);
+ pci_bridge_reset(qdev);
+ pcie_cap_deverr_reset(d);
+}
+
+static int xio3130_upstream_initfn(PCIDevice *d)
+{
+ PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+ PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+ int rc;
+
+ rc = pci_bridge_initfn(d);
+ if (rc < 0) {
+ return rc;
+ }
+
+ pcie_port_init_reg(d);
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_TI);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_TI_XIO3130U);
+ d->config[PCI_REVISION_ID] = XIO3130_REVISION;
+
+ rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
+ XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
+ XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+ if (rc < 0) {
+ return rc;
+ }
+ rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
+ XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
+ if (rc < 0) {
+ return rc;
+ }
+ rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM,
+ p->port);
+ if (rc < 0) {
+ return rc;
+ }
+
+ /* TODO: implement FLR */
+ pcie_cap_flr_init(d);
+
+ pcie_cap_deverr_init(d);
+ /* TODO: AER */
+
+ return 0;
+}
+
+static int xio3130_upstream_exitfn(PCIDevice *d)
+{
+ /* TODO: AER */
+ msi_uninit(d);
+ pcie_cap_exit(d);
+ return pci_bridge_exitfn(d);
+}
+
+PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction,
+ const char *bus_name, pci_map_irq_fn map_irq,
+ uint8_t port)
+{
+ PCIDevice *d;
+ PCIBridge *br;
+ DeviceState *qdev;
+
+ d = pci_create_multifunction(bus, devfn, multifunction, "x3130-upstream");
+ if (!d) {
+ return NULL;
+ }
+ br = DO_UPCAST(PCIBridge, dev, d);
+
+ qdev = &br->dev.qdev;
+ pci_bridge_map_irq(br, bus_name, map_irq);
+ qdev_prop_set_uint8(qdev, "port", port);
+ qdev_init_nofail(qdev);
+
+ return DO_UPCAST(PCIEPort, br, br);
+}
+
+static const VMStateDescription vmstate_xio3130_upstream = {
+ .name = "xio3130-express-upstream-port",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCIE_DEVICE(br.dev, PCIEPort),
+ /* TODO: AER */
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static PCIDeviceInfo xio3130_upstream_info = {
+ .qdev.name = "x3130-upstream",
+ .qdev.desc = "TI X3130 Upstream Port of PCI Express Switch",
+ .qdev.size = sizeof(PCIEPort),
+ .qdev.reset = xio3130_upstream_reset,
+ .qdev.vmsd = &vmstate_xio3130_upstream,
+
+ .is_express = 1,
+ .is_bridge = 1,
+ .config_write = xio3130_upstream_write_config,
+ .init = xio3130_upstream_initfn,
+ .exit = xio3130_upstream_exitfn,
+
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
+ /* TODO: AER */
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void xio3130_upstream_register(void)
+{
+ pci_qdev_register(&xio3130_upstream_info);
+}
+
+device_init(xio3130_upstream_register);
+
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tab-mode: nil
+ * End:
+ */
diff --git a/hw/xio3130_upstream.h b/hw/xio3130_upstream.h
new file mode 100644
index 0000000..e996997
--- /dev/null
+++ b/hw/xio3130_upstream.h
@@ -0,0 +1,10 @@
+#ifndef QEMU_XIO3130_UPSTREAM_H
+#define QEMU_XIO3130_UPSTREAM_H
+
+#include "pcie_port.h"
+
+PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction,
+ const char *bus_name, pci_map_irq_fn map_irq,
+ uint8_t port);
+
+#endif /* QEMU_XIO3130_H */
commit 8135aeed0f0b370a7978d06a49de20f50181e7b9
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Wed Oct 20 17:18:53 2010 +0900
ioh3420: pcie root port in X58 ioh
Implements pcie root port switch in intel X58 ioh
whose device id is 0x3420.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/Makefile.objs b/Makefile.objs
index c73d12b..3a05322 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -140,6 +140,7 @@ hw-obj-y =
hw-obj-y += vl.o loader.o
hw-obj-y += virtio.o virtio-console.o
hw-obj-y += fw_cfg.o pci.o pci_host.o pcie_host.o pci_bridge.o
+hw-obj-y += ioh3420.o
hw-obj-y += watchdog.o
hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
hw-obj-$(CONFIG_ECC) += ecc.o
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
new file mode 100644
index 0000000..1f340d3
--- /dev/null
+++ b/hw/ioh3420.c
@@ -0,0 +1,188 @@
+/*
+ * ioh3420.c
+ * Intel X58 north bridge IOH
+ * PCI Express root port device id 3420
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci_ids.h"
+#include "msi.h"
+#include "pcie.h"
+#include "ioh3420.h"
+
+#define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */
+#define PCI_DEVICE_ID_IOH_REV 0x2
+#define IOH_EP_SSVID_OFFSET 0x40
+#define IOH_EP_SSVID_SVID PCI_VENDOR_ID_INTEL
+#define IOH_EP_SSVID_SSID 0
+#define IOH_EP_MSI_OFFSET 0x60
+#define IOH_EP_MSI_SUPPORTED_FLAGS PCI_MSI_FLAGS_MASKBIT
+#define IOH_EP_MSI_NR_VECTOR 2
+#define IOH_EP_EXP_OFFSET 0x90
+#define IOH_EP_AER_OFFSET 0x100
+
+static void ioh3420_write_config(PCIDevice *d,
+ uint32_t address, uint32_t val, int len)
+{
+ uint16_t sltctl =
+ pci_get_word(d->config + d->exp.exp_cap + PCI_EXP_SLTCTL);
+
+ pci_bridge_write_config(d, address, val, len);
+ msi_write_config(d, address, val, len);
+ pcie_cap_slot_write_config(d, address, val, len, sltctl);
+ /* TODO: AER */
+}
+
+static void ioh3420_reset(DeviceState *qdev)
+{
+ PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+ msi_reset(d);
+ pcie_cap_root_reset(d);
+ pcie_cap_deverr_reset(d);
+ pcie_cap_slot_reset(d);
+ pci_bridge_reset(qdev);
+ pci_bridge_disable_base_limit(d);
+ /* TODO: AER */
+}
+
+static int ioh3420_initfn(PCIDevice *d)
+{
+ PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+ PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+ PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
+ int rc;
+
+ rc = pci_bridge_initfn(d);
+ if (rc < 0) {
+ return rc;
+ }
+
+ d->config[PCI_REVISION_ID] = PCI_DEVICE_ID_IOH_REV;
+ pcie_port_init_reg(d);
+
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_IOH_EPORT);
+
+ rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
+ IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID);
+ if (rc < 0) {
+ return rc;
+ }
+ rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
+ IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
+ IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+ if (rc < 0) {
+ return rc;
+ }
+ rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port);
+ if (rc < 0) {
+ return rc;
+ }
+ pcie_cap_deverr_init(d);
+ pcie_cap_slot_init(d, s->slot);
+ pcie_chassis_create(s->chassis);
+ rc = pcie_chassis_add_slot(s);
+ if (rc < 0) {
+ return rc;
+ }
+ pcie_cap_root_init(d);
+ /* TODO: AER */
+ return 0;
+}
+
+static int ioh3420_exitfn(PCIDevice *d)
+{
+ /* TODO: AER */
+ msi_uninit(d);
+ pcie_cap_exit(d);
+ return pci_bridge_exitfn(d);
+}
+
+PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction,
+ const char *bus_name, pci_map_irq_fn map_irq,
+ uint8_t port, uint8_t chassis, uint16_t slot)
+{
+ PCIDevice *d;
+ PCIBridge *br;
+ DeviceState *qdev;
+
+ d = pci_create_multifunction(bus, devfn, multifunction, "ioh3420");
+ if (!d) {
+ return NULL;
+ }
+ br = DO_UPCAST(PCIBridge, dev, d);
+
+ qdev = &br->dev.qdev;
+ pci_bridge_map_irq(br, bus_name, map_irq);
+ qdev_prop_set_uint8(qdev, "port", port);
+ qdev_prop_set_uint8(qdev, "chassis", chassis);
+ qdev_prop_set_uint16(qdev, "slot", slot);
+ qdev_init_nofail(qdev);
+
+ return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br));
+}
+
+static const VMStateDescription vmstate_ioh3420 = {
+ .name = "ioh-3240-express-root-port",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot),
+ /* TODO: AER */
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static PCIDeviceInfo ioh3420_info = {
+ .qdev.name = "ioh3420",
+ .qdev.desc = "Intel IOH device id 3420 PCIE Root Port",
+ .qdev.size = sizeof(PCIESlot),
+ .qdev.reset = ioh3420_reset,
+ .qdev.vmsd = &vmstate_ioh3420,
+
+ .is_express = 1,
+ .is_bridge = 1,
+ .config_write = ioh3420_write_config,
+ .init = ioh3420_initfn,
+ .exit = ioh3420_exitfn,
+
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
+ DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
+ DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
+ /* TODO: AER */
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void ioh3420_register(void)
+{
+ pci_qdev_register(&ioh3420_info);
+}
+
+device_init(ioh3420_register);
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tab-mode: nil
+ * End:
+ */
diff --git a/hw/ioh3420.h b/hw/ioh3420.h
new file mode 100644
index 0000000..68c523a
--- /dev/null
+++ b/hw/ioh3420.h
@@ -0,0 +1,10 @@
+#ifndef QEMU_IOH3420_H
+#define QEMU_IOH3420_H
+
+#include "pcie_port.h"
+
+PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction,
+ const char *bus_name, pci_map_irq_fn map_irq,
+ uint8_t port, uint8_t chassis, uint16_t slot);
+
+#endif /* QEMU_IOH3420_H */
commit bc20ba98b1a04c9e60de10f2a5626af2c528422b
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Wed Oct 20 17:18:52 2010 +0900
pcie port: define struct PCIEPort/PCIESlot and helper functions
define struct PCIEPort which represents common part
of pci express port.(root, upstream and downstream.)
add a helper function for pcie port which can be used commonly by
root/upstream/downstream port.
define struct PCIESlot which represents common part of
pcie slot.(root and downstream.) and helper functions for it.
helper functions for chassis, slot -> PCIESlot conversion.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/Makefile.objs b/Makefile.objs
index eeb5134..c73d12b 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -186,7 +186,7 @@ hw-obj-$(CONFIG_PIIX4) += piix4.o
# PCI watchdog devices
hw-obj-y += wdt_i6300esb.o
-hw-obj-y += pcie.o
+hw-obj-y += pcie.o pcie_port.o
hw-obj-y += msix.o msi.o
# PCI network cards
diff --git a/hw/pcie_port.c b/hw/pcie_port.c
new file mode 100644
index 0000000..117de61
--- /dev/null
+++ b/hw/pcie_port.c
@@ -0,0 +1,116 @@
+/*
+ * pcie_port.c
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pcie_port.h"
+
+void pcie_port_init_reg(PCIDevice *d)
+{
+ /* Unlike pci bridge,
+ 66MHz and fast back to back don't apply to pci express port. */
+ pci_set_word(d->config + PCI_STATUS, 0);
+ pci_set_word(d->config + PCI_SEC_STATUS, 0);
+
+ /* 7.5.3.5 Prefetchable Memory Base Limit
+ * The Prefetchable Memory Base and Prefetchable Memory Limit registers
+ * must indicate that 64-bit addresses are supported, as defined in
+ * PCI-to-PCI Bridge Architecture Specification, Revision 1.2.
+ */
+ pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE,
+ PCI_PREF_RANGE_TYPE_64);
+ pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT,
+ PCI_PREF_RANGE_TYPE_64);
+}
+
+/**************************************************************************
+ * (chassis number, pcie physical slot number) -> pcie slot conversion
+ */
+struct PCIEChassis {
+ uint8_t number;
+
+ QLIST_HEAD(, PCIESlot) slots;
+ QLIST_ENTRY(PCIEChassis) next;
+};
+
+static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis);
+
+static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number)
+{
+ struct PCIEChassis *c;
+ QLIST_FOREACH(c, &chassis, next) {
+ if (c->number == chassis_number) {
+ break;
+ }
+ }
+ return c;
+}
+
+void pcie_chassis_create(uint8_t chassis_number)
+{
+ struct PCIEChassis *c;
+ c = pcie_chassis_find(chassis_number);
+ if (c) {
+ return;
+ }
+ c = qemu_mallocz(sizeof(*c));
+ c->number = chassis_number;
+ QLIST_INIT(&c->slots);
+ QLIST_INSERT_HEAD(&chassis, c, next);
+}
+
+static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c,
+ uint8_t slot)
+{
+ PCIESlot *s;
+ QLIST_FOREACH(s, &c->slots, next) {
+ if (s->slot == slot) {
+ break;
+ }
+ }
+ return s;
+}
+
+PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot)
+{
+ struct PCIEChassis *c;
+ c = pcie_chassis_find(chassis_number);
+ if (!c) {
+ return NULL;
+ }
+ return pcie_chassis_find_slot_with_chassis(c, slot);
+}
+
+int pcie_chassis_add_slot(struct PCIESlot *slot)
+{
+ struct PCIEChassis *c;
+ c = pcie_chassis_find(slot->chassis);
+ if (!c) {
+ return -ENODEV;
+ }
+ if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) {
+ return -EBUSY;
+ }
+ QLIST_INSERT_HEAD(&c->slots, slot, next);
+ return 0;
+}
+
+void pcie_chassis_del_slot(PCIESlot *s)
+{
+ QLIST_REMOVE(s, next);
+}
diff --git a/hw/pcie_port.h b/hw/pcie_port.h
new file mode 100644
index 0000000..3709583
--- /dev/null
+++ b/hw/pcie_port.h
@@ -0,0 +1,51 @@
+/*
+ * pcie_port.h
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_PCIE_PORT_H
+#define QEMU_PCIE_PORT_H
+
+#include "pci_bridge.h"
+#include "pci_internals.h"
+
+struct PCIEPort {
+ PCIBridge br;
+
+ /* pci express switch port */
+ uint8_t port;
+};
+
+void pcie_port_init_reg(PCIDevice *d);
+
+struct PCIESlot {
+ PCIEPort port;
+
+ /* pci express switch port with slot */
+ uint8_t chassis;
+ uint16_t slot;
+ QLIST_ENTRY(PCIESlot) next;
+};
+
+void pcie_chassis_create(uint8_t chassis_number);
+void pcie_main_chassis_create(void);
+PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot);
+int pcie_chassis_add_slot(struct PCIESlot *slot);
+void pcie_chassis_del_slot(PCIESlot *s);
+
+#endif /* QEMU_PCIE_PORT_H */
diff --git a/qemu-common.h b/qemu-common.h
index 6d9ee26..b97b16e 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -221,6 +221,8 @@ typedef struct PCIBus PCIBus;
typedef struct PCIDevice PCIDevice;
typedef struct PCIExpressDevice PCIExpressDevice;
typedef struct PCIBridge PCIBridge;
+typedef struct PCIEPort PCIEPort;
+typedef struct PCIESlot PCIESlot;
typedef struct SerialState SerialState;
typedef struct IRQState *qemu_irq;
typedef struct PCMCIACardState PCMCIACardState;
commit 0208def1cadd4f72f862e62548c2af268a543b20
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Wed Oct 20 17:18:51 2010 +0900
pci/bridge: fix pci_bridge_reset()
The lower bits of base/limit registers is RO and shouldn't be zero
cleared on reset. This patch fixes it.
In fact, the default value of base/limit registers aren't specified
in the spec. And some bridges disable forwarding on reset instead of
zeroing base/limit registers.
So introduce one function to disable bridge forwarding so that
such bridges can use it. It will be used later.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 638e3b3..7e8488a 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -151,6 +151,26 @@ void pci_bridge_write_config(PCIDevice *d,
}
}
+void pci_bridge_disable_base_limit(PCIDevice *dev)
+{
+ uint8_t *conf = dev->config;
+
+ pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
+ PCI_IO_RANGE_MASK & 0xff);
+ pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
+ PCI_IO_RANGE_MASK & 0xff);
+ pci_word_test_and_set_mask(conf + PCI_MEMORY_BASE,
+ PCI_MEMORY_RANGE_MASK & 0xffff);
+ pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
+ PCI_MEMORY_RANGE_MASK & 0xffff);
+ pci_word_test_and_set_mask(conf + PCI_PREF_MEMORY_BASE,
+ PCI_PREF_RANGE_MASK & 0xffff);
+ pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
+ PCI_PREF_RANGE_MASK & 0xffff);
+ pci_set_word(conf + PCI_PREF_BASE_UPPER32, 0);
+ pci_set_word(conf + PCI_PREF_LIMIT_UPPER32, 0);
+}
+
/* reset bridge specific configuration registers */
void pci_bridge_reset_reg(PCIDevice *dev)
{
@@ -161,12 +181,28 @@ void pci_bridge_reset_reg(PCIDevice *dev)
conf[PCI_SUBORDINATE_BUS] = 0;
conf[PCI_SEC_LATENCY_TIMER] = 0;
- conf[PCI_IO_BASE] = 0;
- conf[PCI_IO_LIMIT] = 0;
- pci_set_word(conf + PCI_MEMORY_BASE, 0);
- pci_set_word(conf + PCI_MEMORY_LIMIT, 0);
- pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0);
- pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0);
+ /*
+ * the default values for base/limit registers aren't specified
+ * in the PCI-to-PCI-bridge spec. So we don't thouch them here.
+ * Each implementation can override it.
+ * typical implementation does
+ * zero base/limit registers or
+ * disable forwarding: pci_bridge_disable_base_limit()
+ * If disable forwarding is wanted, call pci_bridge_disable_base_limit()
+ * after this function.
+ */
+ pci_byte_test_and_clear_mask(conf + PCI_IO_BASE,
+ PCI_IO_RANGE_MASK & 0xff);
+ pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
+ PCI_IO_RANGE_MASK & 0xff);
+ pci_word_test_and_clear_mask(conf + PCI_MEMORY_BASE,
+ PCI_MEMORY_RANGE_MASK & 0xffff);
+ pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
+ PCI_MEMORY_RANGE_MASK & 0xffff);
+ pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_BASE,
+ PCI_PREF_RANGE_MASK & 0xffff);
+ pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
+ PCI_PREF_RANGE_MASK & 0xffff);
pci_set_word(conf + PCI_PREF_BASE_UPPER32, 0);
pci_set_word(conf + PCI_PREF_LIMIT_UPPER32, 0);
diff --git a/hw/pci_bridge.h b/hw/pci_bridge.h
index f6fade0..84411a6 100644
--- a/hw/pci_bridge.h
+++ b/hw/pci_bridge.h
@@ -39,6 +39,7 @@ pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type);
void pci_bridge_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len);
+void pci_bridge_disable_base_limit(PCIDevice *dev);
void pci_bridge_reset_reg(PCIDevice *dev);
void pci_bridge_reset(DeviceState *qdev);
commit 6da6d29fa63ab7adcc2959355497a44654f3703e
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Wed Oct 20 17:18:50 2010 +0900
pcie: comment on hpev_intx
document hpev_intx.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pcie.h b/hw/pcie.h
index 68327d8..2871e27 100644
--- a/hw/pcie.h
+++ b/hw/pcie.h
@@ -65,7 +65,15 @@ struct PCIExpressDevice {
/* TODO FLR */
/* SLOT */
- unsigned int hpev_intx; /* INTx for hot plug event */
+ unsigned int hpev_intx; /* INTx for hot plug event (0-3:INT[A-D]#)
+ * default is 0 = INTA#
+ * If the chip wants to use other interrupt
+ * line, initialize this member with the
+ * desired number.
+ * If the chip dynamically changes this member,
+ * also initialize it when loaded as
+ * appropreately.
+ */
};
/* PCI express capability helper functions */
commit 0428527c621c3edfd258b4d34fc178ef5df41071
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Tue Oct 19 18:06:34 2010 +0900
pcie: helper functions for pcie capability and extended capability
This patch implements helper functions for pci express capability
and pci express extended capability allocation.
NOTE: presence detection depends on pci_qdev_init() change.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/Makefile.objs b/Makefile.objs
index 5f5a4c5..eeb5134 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -186,6 +186,7 @@ hw-obj-$(CONFIG_PIIX4) += piix4.o
# PCI watchdog devices
hw-obj-y += wdt_i6300esb.o
+hw-obj-y += pcie.o
hw-obj-y += msix.o msi.o
# PCI network cards
diff --git a/hw/pci.h b/hw/pci.h
index 9e2f27d..d6c522b 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -9,6 +9,8 @@
/* PCI includes legacy ISA access. */
#include "isa.h"
+#include "pcie.h"
+
/* PCI bus */
#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
@@ -175,6 +177,9 @@ struct PCIDevice {
/* Offset of MSI capability in config space */
uint8_t msi_cap;
+ /* PCI Express */
+ PCIExpressDevice exp;
+
/* Location of option rom */
char *romfile;
ram_addr_t rom_offset;
diff --git a/hw/pcie.c b/hw/pcie.c
new file mode 100644
index 0000000..53d1fce
--- /dev/null
+++ b/hw/pcie.c
@@ -0,0 +1,540 @@
+/*
+ * pcie.c
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysemu.h"
+#include "pci_bridge.h"
+#include "pcie.h"
+#include "msix.h"
+#include "msi.h"
+#include "pci_internals.h"
+#include "pcie_regs.h"
+
+//#define DEBUG_PCIE
+#ifdef DEBUG_PCIE
+# define PCIE_DPRINTF(fmt, ...) \
+ fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
+#else
+# define PCIE_DPRINTF(fmt, ...) do {} while (0)
+#endif
+#define PCIE_DEV_PRINTF(dev, fmt, ...) \
+ PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
+
+
+/***************************************************************************
+ * pci express capability helper functions
+ */
+int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
+{
+ int pos;
+ uint8_t *exp_cap;
+
+ assert(pci_is_express(dev));
+
+ pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset,
+ PCI_EXP_VER2_SIZEOF);
+ if (pos < 0) {
+ return pos;
+ }
+ dev->exp.exp_cap = pos;
+ exp_cap = dev->config + pos;
+
+ /* capability register
+ interrupt message number defaults to 0 */
+ pci_set_word(exp_cap + PCI_EXP_FLAGS,
+ ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) |
+ PCI_EXP_FLAGS_VER2);
+
+ /* device capability register
+ * table 7-12:
+ * roll based error reporting bit must be set by all
+ * Functions conforming to the ECN, PCI Express Base
+ * Specification, Revision 1.1., or subsequent PCI Express Base
+ * Specification revisions.
+ */
+ pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER);
+
+ pci_set_long(exp_cap + PCI_EXP_LNKCAP,
+ (port << PCI_EXP_LNKCAP_PN_SHIFT) |
+ PCI_EXP_LNKCAP_ASPMS_0S |
+ PCI_EXP_LNK_MLW_1 |
+ PCI_EXP_LNK_LS_25);
+
+ pci_set_word(exp_cap + PCI_EXP_LNKSTA,
+ PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25);
+
+ pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
+ PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
+
+ pci_set_word(dev->wmask + pos, PCI_EXP_DEVCTL2_EETLPPB);
+ return pos;
+}
+
+void pcie_cap_exit(PCIDevice *dev)
+{
+ pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF);
+}
+
+uint8_t pcie_cap_get_type(const PCIDevice *dev)
+{
+ uint32_t pos = dev->exp.exp_cap;
+ assert(pos > 0);
+ return (pci_get_word(dev->config + pos + PCI_EXP_FLAGS) &
+ PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT;
+}
+
+/* MSI/MSI-X */
+/* pci express interrupt message number */
+/* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */
+void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector)
+{
+ uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
+ assert(vector < 32);
+ pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ);
+ pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS,
+ vector << PCI_EXP_FLAGS_IRQ_SHIFT);
+}
+
+uint8_t pcie_cap_flags_get_vector(PCIDevice *dev)
+{
+ return (pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) &
+ PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT;
+}
+
+void pcie_cap_deverr_init(PCIDevice *dev)
+{
+ uint32_t pos = dev->exp.exp_cap;
+ pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP,
+ PCI_EXP_DEVCAP_RBER);
+ pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL,
+ PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
+ PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
+ pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA,
+ PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED |
+ PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_URD);
+}
+
+void pcie_cap_deverr_reset(PCIDevice *dev)
+{
+ uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
+ pci_long_test_and_clear_mask(devctl,
+ PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
+ PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
+}
+
+/*
+ * A PCI Express Hot-Plug Event has occured, so update slot status register
+ * and notify OS of the event if necessary.
+ *
+ * 6.7.3 PCI Express Hot-Plug Events
+ * 6.7.3.4 Software Notification of Hot-Plug Events
+ */
+static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
+{
+ uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
+ uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
+ uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+
+ PCIE_DEV_PRINTF(dev,
+ "sltctl: 0x%02"PRIx16" sltsta: 0x%02"PRIx16" event: %x\n",
+ sltctl, sltsta, event);
+
+ if (pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, event)) {
+ return;
+ }
+ sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+ PCIE_DEV_PRINTF(dev, "sltsta -> %02"PRIx16"\n", sltsta);
+
+ if ((sltctl & PCI_EXP_SLTCTL_HPIE) &&
+ (sltctl & event & PCI_EXP_HP_EV_SUPPORTED)) {
+ if (pci_msi_enabled(dev)) {
+ pci_msi_notify(dev, pcie_cap_flags_get_vector(dev));
+ } else {
+ qemu_set_irq(dev->irq[dev->exp.hpev_intx], 1);
+ }
+ }
+}
+
+static int pcie_cap_slot_hotplug(DeviceState *qdev,
+ PCIDevice *pci_dev, int state)
+{
+ PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+ uint8_t *exp_cap = d->config + d->exp.exp_cap;
+ uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+
+ if (!pci_dev->qdev.hotplugged) {
+ assert(state); /* this case only happens at machine creation. */
+ pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
+ PCI_EXP_SLTSTA_PDS);
+ return 0;
+ }
+
+ PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state);
+ if (sltsta & PCI_EXP_SLTSTA_EIS) {
+ /* the slot is electromechanically locked.
+ * This error is propagated up to qdev and then to HMP/QMP.
+ */
+ return -EBUSY;
+ }
+
+ /* TODO: multifunction hot-plug.
+ * Right now, only a device of function = 0 is allowed to be
+ * hot plugged/unplugged.
+ */
+ assert(PCI_FUNC(pci_dev->devfn) == 0);
+
+ if (state) {
+ pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
+ PCI_EXP_SLTSTA_PDS);
+ pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
+ } else {
+ qdev_free(&pci_dev->qdev);
+ pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
+ PCI_EXP_SLTSTA_PDS);
+ pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
+ }
+ return 0;
+}
+
+/* pci express slot for pci express root/downstream port
+ PCI express capability slot registers */
+void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot)
+{
+ uint32_t pos = dev->exp.exp_cap;
+
+ pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS,
+ PCI_EXP_FLAGS_SLOT);
+
+ pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP,
+ ~PCI_EXP_SLTCAP_PSN);
+ pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP,
+ (slot << PCI_EXP_SLTCAP_PSN_SHIFT) |
+ PCI_EXP_SLTCAP_EIP |
+ PCI_EXP_SLTCAP_HPS |
+ PCI_EXP_SLTCAP_HPC |
+ PCI_EXP_SLTCAP_PIP |
+ PCI_EXP_SLTCAP_AIP |
+ PCI_EXP_SLTCAP_ABP);
+
+ pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL,
+ PCI_EXP_SLTCTL_PIC |
+ PCI_EXP_SLTCTL_AIC);
+ pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL,
+ PCI_EXP_SLTCTL_PIC_OFF |
+ PCI_EXP_SLTCTL_AIC_OFF);
+ pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
+ PCI_EXP_SLTCTL_PIC |
+ PCI_EXP_SLTCTL_AIC |
+ PCI_EXP_SLTCTL_HPIE |
+ PCI_EXP_SLTCTL_CCIE |
+ PCI_EXP_SLTCTL_PDCE |
+ PCI_EXP_SLTCTL_ABPE);
+ /* Although reading PCI_EXP_SLTCTL_EIC returns always 0,
+ * make the bit writable here in order to detect 1b is written.
+ * pcie_cap_slot_write_config() test-and-clear the bit, so
+ * this bit always returns 0 to the guest.
+ */
+ pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
+ PCI_EXP_SLTCTL_EIC);
+
+ pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA,
+ PCI_EXP_HP_EV_SUPPORTED);
+
+ pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)),
+ pcie_cap_slot_hotplug, &dev->qdev);
+}
+
+void pcie_cap_slot_reset(PCIDevice *dev)
+{
+ uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
+
+ PCIE_DEV_PRINTF(dev, "reset\n");
+
+ pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
+ PCI_EXP_SLTCTL_EIC |
+ PCI_EXP_SLTCTL_PIC |
+ PCI_EXP_SLTCTL_AIC |
+ PCI_EXP_SLTCTL_HPIE |
+ PCI_EXP_SLTCTL_CCIE |
+ PCI_EXP_SLTCTL_PDCE |
+ PCI_EXP_SLTCTL_ABPE);
+ pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL,
+ PCI_EXP_SLTCTL_PIC_OFF |
+ PCI_EXP_SLTCTL_AIC_OFF);
+
+ pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
+ PCI_EXP_SLTSTA_EIS |/* on reset,
+ the lock is released */
+ PCI_EXP_SLTSTA_CC |
+ PCI_EXP_SLTSTA_PDC |
+ PCI_EXP_SLTSTA_ABP);
+}
+
+void pcie_cap_slot_write_config(PCIDevice *dev,
+ uint32_t addr, uint32_t val, int len,
+ uint16_t sltctl_prev)
+{
+ uint32_t pos = dev->exp.exp_cap;
+ uint8_t *exp_cap = dev->config + pos;
+ uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
+ uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+
+ PCIE_DEV_PRINTF(dev,
+ "addr: 0x%"PRIx32" val: 0x%"PRIx32" len: %d\n"
+ "\tsltctl_prev: 0x%02"PRIx16" sltctl: 0x%02"PRIx16
+ " sltsta: 0x%02"PRIx16"\n",
+ addr, val, len, sltctl_prev, sltctl, sltsta);
+
+ /* SLTCTL */
+ if (ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
+ PCIE_DEV_PRINTF(dev, "sltctl: 0x%02"PRIx16" -> 0x%02"PRIx16"\n",
+ sltctl_prev, sltctl);
+ if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
+ PCI_EXP_SLTCTL_EIC)) {
+ sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */
+ pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
+ PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: "
+ "sltsta -> 0x%02"PRIx16"\n",
+ sltsta);
+ }
+
+ /*
+ * The events control bits might be enabled or disabled,
+ * Check if the software notificastion condition is satisfied
+ * or disatisfied.
+ *
+ * 6.7.3.4 Software Notification of Hot-plug events
+ */
+ if (pci_msi_enabled(dev)) {
+ bool msi_trigger =
+ (sltctl & PCI_EXP_SLTCTL_HPIE) &&
+ ((sltctl_prev ^ sltctl) & sltctl & /* stlctl: 0 -> 1 */
+ sltsta & PCI_EXP_HP_EV_SUPPORTED);
+ if (msi_trigger) {
+ pci_msi_notify(dev, pcie_cap_flags_get_vector(dev));
+ }
+ } else {
+ int int_level =
+ (sltctl & PCI_EXP_SLTCTL_HPIE) &&
+ (sltctl & sltsta & PCI_EXP_HP_EV_SUPPORTED);
+ qemu_set_irq(dev->irq[dev->exp.hpev_intx], int_level);
+ }
+
+ if (!((sltctl_prev ^ sltctl) & PCI_EXP_SLTCTL_SUPPORTED)) {
+ PCIE_DEV_PRINTF(dev,
+ "sprious command completion slctl "
+ "0x%"PRIx16" -> 0x%"PRIx16"\n",
+ sltctl_prev, sltctl);
+ }
+
+ /* command completion.
+ * Real hardware might take a while to complete
+ * requested command because physical movement would be involved
+ * like locking the electromechanical lock.
+ * However in our case, command is completed instantaneously above,
+ * so send a command completion event right now.
+ *
+ * 6.7.3.2 Command Completed Events
+ */
+ /* set command completed bit */
+ pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI);
+ }
+}
+
+void pcie_cap_slot_push_attention_button(PCIDevice *dev)
+{
+ pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP);
+}
+
+/* root control/capabilities/status. PME isn't emulated for now */
+void pcie_cap_root_init(PCIDevice *dev)
+{
+ pci_set_word(dev->wmask + dev->exp.exp_cap + PCI_EXP_RTCTL,
+ PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE |
+ PCI_EXP_RTCTL_SEFEE);
+}
+
+void pcie_cap_root_reset(PCIDevice *dev)
+{
+ pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0);
+}
+
+/*
+ * TODO: implement FLR:
+ * Right now sets the bit which indicates FLR is supported.
+ */
+/* function level reset(FLR) */
+void pcie_cap_flr_init(PCIDevice *dev)
+{
+ pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP,
+ PCI_EXP_DEVCAP_FLR);
+
+ /* Although reading BCR_FLR returns always 0,
+ * the bit is made writable here in order to detect the 1b is written
+ * pcie_cap_flr_write_config() test-and-clear the bit, so
+ * this bit always returns 0 to the guest.
+ */
+ pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap + PCI_EXP_DEVCTL,
+ PCI_EXP_DEVCTL_BCR_FLR);
+}
+
+void pcie_cap_flr_write_config(PCIDevice *dev,
+ uint32_t addr, uint32_t val, int len)
+{
+ uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
+ if (pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR)) {
+ /* TODO: implement FLR */
+ }
+}
+
+/* Alternative Routing-ID Interpretation (ARI) */
+/* ari forwarding support for down stream port */
+void pcie_cap_ari_init(PCIDevice *dev)
+{
+ uint32_t pos = dev->exp.exp_cap;
+ pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP2,
+ PCI_EXP_DEVCAP2_ARI);
+ pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL2,
+ PCI_EXP_DEVCTL2_ARI);
+}
+
+void pcie_cap_ari_reset(PCIDevice *dev)
+{
+ uint8_t *devctl2 = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2;
+ pci_long_test_and_clear_mask(devctl2, PCI_EXP_DEVCTL2_ARI);
+}
+
+bool pcie_cap_is_ari_enabled(const PCIDevice *dev)
+{
+ if (!pci_is_express(dev)) {
+ return false;
+ }
+ if (!dev->exp.exp_cap) {
+ return false;
+ }
+
+ return pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) &
+ PCI_EXP_DEVCTL2_ARI;
+}
+
+/**************************************************************************
+ * pci express extended capability allocation functions
+ * uint16_t ext_cap_id (16 bit)
+ * uint8_t cap_ver (4 bit)
+ * uint16_t cap_offset (12 bit)
+ * uint16_t ext_cap_size
+ */
+
+static uint16_t pcie_find_capability_list(PCIDevice *dev, uint16_t cap_id,
+ uint16_t *prev_p)
+{
+ uint16_t prev = 0;
+ uint16_t next;
+ uint32_t header = pci_get_long(dev->config + PCI_CONFIG_SPACE_SIZE);
+
+ if (!header) {
+ /* no extended capability */
+ next = 0;
+ goto out;
+ }
+ for (next = PCI_CONFIG_SPACE_SIZE; next;
+ prev = next, next = PCI_EXT_CAP_NEXT(header)) {
+
+ assert(next >= PCI_CONFIG_SPACE_SIZE);
+ assert(next <= PCIE_CONFIG_SPACE_SIZE - 8);
+
+ header = pci_get_long(dev->config + next);
+ if (PCI_EXT_CAP_ID(header) == cap_id) {
+ break;
+ }
+ }
+
+out:
+ if (prev_p) {
+ *prev_p = prev;
+ }
+ return next;
+}
+
+uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id)
+{
+ return pcie_find_capability_list(dev, cap_id, NULL);
+}
+
+static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next)
+{
+ uint16_t header = pci_get_long(dev->config + pos);
+ assert(!(next & (PCI_EXT_CAP_ALIGN - 1)));
+ header = (header & ~PCI_EXT_CAP_NEXT_MASK) |
+ ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK);
+ pci_set_long(dev->config + pos, header);
+}
+
+/*
+ * caller must supply valid (offset, size) * such that the range shouldn't
+ * overlap with other capability or other registers.
+ * This function doesn't check it.
+ */
+void pcie_add_capability(PCIDevice *dev,
+ uint16_t cap_id, uint8_t cap_ver,
+ uint16_t offset, uint16_t size)
+{
+ uint32_t header;
+ uint16_t next;
+
+ assert(offset >= PCI_CONFIG_SPACE_SIZE);
+ assert(offset < offset + size);
+ assert(offset + size < PCIE_CONFIG_SPACE_SIZE);
+ assert(size >= 8);
+ assert(pci_is_express(dev));
+
+ if (offset == PCI_CONFIG_SPACE_SIZE) {
+ header = pci_get_long(dev->config + offset);
+ next = PCI_EXT_CAP_NEXT(header);
+ } else {
+ uint16_t prev;
+
+ /* 0 is reserved cap id. use internally to find the last capability
+ in the linked list */
+ next = pcie_find_capability_list(dev, 0, &prev);
+
+ assert(prev >= PCI_CONFIG_SPACE_SIZE);
+ assert(next == 0);
+ pcie_ext_cap_set_next(dev, prev, offset);
+ }
+ pci_set_long(dev->config + offset, PCI_EXT_CAP(cap_id, cap_ver, next));
+
+ /* Make capability read-only by default */
+ memset(dev->wmask + offset, 0, size);
+ memset(dev->w1cmask + offset, 0, size);
+ /* Check capability by default */
+ memset(dev->cmask + offset, 0xFF, size);
+}
+
+/**************************************************************************
+ * pci express extended capability helper functions
+ */
+
+/* ARI */
+void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn)
+{
+ pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER,
+ offset, PCI_ARI_SIZEOF);
+ pci_set_long(dev->config + offset + PCI_ARI_CAP, PCI_ARI_CAP_NFN(nextfn));
+}
diff --git a/hw/pcie.h b/hw/pcie.h
new file mode 100644
index 0000000..68327d8
--- /dev/null
+++ b/hw/pcie.h
@@ -0,0 +1,107 @@
+/*
+ * pcie.h
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_PCIE_H
+#define QEMU_PCIE_H
+
+#include "hw.h"
+#include "pci_regs.h"
+#include "pcie_regs.h"
+
+typedef enum {
+ /* for attention and power indicator */
+ PCI_EXP_HP_IND_RESERVED = PCI_EXP_SLTCTL_IND_RESERVED,
+ PCI_EXP_HP_IND_ON = PCI_EXP_SLTCTL_IND_ON,
+ PCI_EXP_HP_IND_BLINK = PCI_EXP_SLTCTL_IND_BLINK,
+ PCI_EXP_HP_IND_OFF = PCI_EXP_SLTCTL_IND_OFF,
+} PCIExpressIndicator;
+
+typedef enum {
+ /* these bits must match the bits in Slot Control/Status registers.
+ * PCI_EXP_HP_EV_xxx = PCI_EXP_SLTCTL_xxxE = PCI_EXP_SLTSTA_xxx
+ *
+ * Not all the bits of slot control register match with the ones of
+ * slot status. Not some bits of slot status register is used to
+ * show status, not to report event occurence.
+ * So such bits must be masked out when checking the software
+ * notification condition.
+ */
+ PCI_EXP_HP_EV_ABP = PCI_EXP_SLTCTL_ABPE,
+ /* attention button pressed */
+ PCI_EXP_HP_EV_PDC = PCI_EXP_SLTCTL_PDCE,
+ /* presence detect changed */
+ PCI_EXP_HP_EV_CCI = PCI_EXP_SLTCTL_CCIE,
+ /* command completed */
+
+ PCI_EXP_HP_EV_SUPPORTED = PCI_EXP_HP_EV_ABP |
+ PCI_EXP_HP_EV_PDC |
+ PCI_EXP_HP_EV_CCI,
+ /* supported event mask */
+
+ /* events not listed aren't supported */
+} PCIExpressHotPlugEvent;
+
+struct PCIExpressDevice {
+ /* Offset of express capability in config space */
+ uint8_t exp_cap;
+
+ /* TODO FLR */
+
+ /* SLOT */
+ unsigned int hpev_intx; /* INTx for hot plug event */
+};
+
+/* PCI express capability helper functions */
+int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port);
+void pcie_cap_exit(PCIDevice *dev);
+uint8_t pcie_cap_get_type(const PCIDevice *dev);
+void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector);
+uint8_t pcie_cap_flags_get_vector(PCIDevice *dev);
+
+void pcie_cap_deverr_init(PCIDevice *dev);
+void pcie_cap_deverr_reset(PCIDevice *dev);
+
+void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot);
+void pcie_cap_slot_reset(PCIDevice *dev);
+void pcie_cap_slot_write_config(PCIDevice *dev,
+ uint32_t addr, uint32_t val, int len,
+ uint16_t sltctl_prev);
+void pcie_cap_slot_push_attention_button(PCIDevice *dev);
+
+void pcie_cap_root_init(PCIDevice *dev);
+void pcie_cap_root_reset(PCIDevice *dev);
+
+void pcie_cap_flr_init(PCIDevice *dev);
+void pcie_cap_flr_write_config(PCIDevice *dev,
+ uint32_t addr, uint32_t val, int len);
+
+void pcie_cap_ari_init(PCIDevice *dev);
+void pcie_cap_ari_reset(PCIDevice *dev);
+bool pcie_cap_is_ari_enabled(const PCIDevice *dev);
+
+/* PCI express extended capability helper functions */
+uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id);
+void pcie_add_capability(PCIDevice *dev,
+ uint16_t cap_id, uint8_t cap_ver,
+ uint16_t offset, uint16_t size);
+
+void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn);
+
+#endif /* QEMU_PCIE_H */
diff --git a/qemu-common.h b/qemu-common.h
index d735235..6d9ee26 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -219,6 +219,7 @@ typedef struct PCIHostState PCIHostState;
typedef struct PCIExpressHost PCIExpressHost;
typedef struct PCIBus PCIBus;
typedef struct PCIDevice PCIDevice;
+typedef struct PCIExpressDevice PCIExpressDevice;
typedef struct PCIBridge PCIBridge;
typedef struct SerialState SerialState;
typedef struct IRQState *qemu_irq;
commit 08f3dcf13f49dea3106b09c69bef9543e56fa629
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Tue Oct 19 18:06:33 2010 +0900
pcie: add pcie constants to pcie_regs.h
add pcie constants to pcie_regs.h.
Those constants should go to Linux pci_regs.h and then the file should
go away eventually.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pcie_regs.h b/hw/pcie_regs.h
new file mode 100644
index 0000000..3461a1b
--- /dev/null
+++ b/hw/pcie_regs.h
@@ -0,0 +1,154 @@
+/*
+ * constants for pcie configurations space from pci express spec.
+ *
+ * TODO:
+ * Those constants and macros should go to Linux pci_regs.h
+ * Once they're merged, they will go away.
+ */
+#ifndef QEMU_PCIE_REGS_H
+#define QEMU_PCIE_REGS_H
+
+
+/* express capability */
+
+#define PCI_EXP_VER2_SIZEOF 0x3c /* express capability of ver. 2 */
+#define PCI_EXT_CAP_VER_SHIFT 16
+#define PCI_EXT_CAP_NEXT_SHIFT 20
+#define PCI_EXT_CAP_NEXT_MASK (0xffc << PCI_EXT_CAP_NEXT_SHIFT)
+
+#define PCI_EXT_CAP(id, ver, next) \
+ ((id) | \
+ ((ver) << PCI_EXT_CAP_VER_SHIFT) | \
+ ((next) << PCI_EXT_CAP_NEXT_SHIFT))
+
+#define PCI_EXT_CAP_ALIGN 4
+#define PCI_EXT_CAP_ALIGNUP(x) \
+ (((x) + PCI_EXT_CAP_ALIGN - 1) & ~(PCI_EXT_CAP_ALIGN - 1))
+
+/* PCI_EXP_FLAGS */
+#define PCI_EXP_FLAGS_VER2 2 /* for now, supports only ver. 2 */
+#define PCI_EXP_FLAGS_IRQ_SHIFT (ffs(PCI_EXP_FLAGS_IRQ) - 1)
+#define PCI_EXP_FLAGS_TYPE_SHIFT (ffs(PCI_EXP_FLAGS_TYPE) - 1)
+
+
+/* PCI_EXP_LINK{CAP, STA} */
+/* link speed */
+#define PCI_EXP_LNK_LS_25 1
+
+#define PCI_EXP_LNK_MLW_SHIFT (ffs(PCI_EXP_LNKCAP_MLW) - 1)
+#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT)
+
+/* PCI_EXP_LINKCAP */
+#define PCI_EXP_LNKCAP_ASPMS_SHIFT (ffs(PCI_EXP_LNKCAP_ASPMS) - 1)
+#define PCI_EXP_LNKCAP_ASPMS_0S (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT)
+
+#define PCI_EXP_LNKCAP_PN_SHIFT (ffs(PCI_EXP_LNKCAP_PN) - 1)
+
+#define PCI_EXP_SLTCAP_PSN_SHIFT (ffs(PCI_EXP_SLTCAP_PSN) - 1)
+
+#define PCI_EXP_SLTCTL_IND_RESERVED 0x0
+#define PCI_EXP_SLTCTL_IND_ON 0x1
+#define PCI_EXP_SLTCTL_IND_BLINK 0x2
+#define PCI_EXP_SLTCTL_IND_OFF 0x3
+#define PCI_EXP_SLTCTL_AIC_SHIFT (ffs(PCI_EXP_SLTCTL_AIC) - 1)
+#define PCI_EXP_SLTCTL_AIC_OFF \
+ (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_AIC_SHIFT)
+
+#define PCI_EXP_SLTCTL_PIC_SHIFT (ffs(PCI_EXP_SLTCTL_PIC) - 1)
+#define PCI_EXP_SLTCTL_PIC_OFF \
+ (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_PIC_SHIFT)
+
+#define PCI_EXP_SLTCTL_SUPPORTED \
+ (PCI_EXP_SLTCTL_ABPE | \
+ PCI_EXP_SLTCTL_PDCE | \
+ PCI_EXP_SLTCTL_CCIE | \
+ PCI_EXP_SLTCTL_HPIE | \
+ PCI_EXP_SLTCTL_AIC | \
+ PCI_EXP_SLTCTL_PCC | \
+ PCI_EXP_SLTCTL_EIC)
+
+#define PCI_EXP_DEVCAP2_EFF 0x100000
+#define PCI_EXP_DEVCAP2_EETLPP 0x200000
+
+#define PCI_EXP_DEVCTL2_EETLPPB 0x80
+
+/* ARI */
+#define PCI_ARI_VER 1
+#define PCI_ARI_SIZEOF 8
+
+/* AER */
+#define PCI_ERR_VER 2
+#define PCI_ERR_SIZEOF 0x48
+
+#define PCI_ERR_UNC_SDN 0x00000020 /* surprise down */
+#define PCI_ERR_UNC_ACSV 0x00200000 /* ACS Violation */
+#define PCI_ERR_UNC_INTN 0x00400000 /* Internal Error */
+#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC Blcoked TLP */
+#define PCI_ERR_UNC_ATOP_EBLOCKED 0x01000000 /* atomic op egress blocked */
+#define PCI_ERR_UNC_TLP_PRF_BLOCKED 0x02000000 /* TLP Prefix Blocked */
+#define PCI_ERR_COR_ADV_NONFATAL 0x00002000 /* Advisory Non-Fatal */
+#define PCI_ERR_COR_INTERNAL 0x00004000 /* Corrected Internal */
+#define PCI_ERR_COR_HL_OVERFLOW 0x00008000 /* Header Long Overflow */
+#define PCI_ERR_CAP_FEP_MASK 0x0000001f
+#define PCI_ERR_CAP_MHRC 0x00000200
+#define PCI_ERR_CAP_MHRE 0x00000400
+#define PCI_ERR_CAP_TLP 0x00000800
+
+#define PCI_ERR_TLP_PREFIX_LOG 0x38
+
+#define PCI_SEC_STATUS_RCV_SYSTEM_ERROR 0x4000
+
+/* aer root error command/status */
+#define PCI_ERR_ROOT_CMD_EN_MASK (PCI_ERR_ROOT_CMD_COR_EN | \
+ PCI_ERR_ROOT_CMD_NONFATAL_EN | \
+ PCI_ERR_ROOT_CMD_FATAL_EN)
+
+#define PCI_ERR_ROOT_IRQ_MAX 32
+#define PCI_ERR_ROOT_IRQ 0xf8000000
+#define PCI_ERR_ROOT_IRQ_SHIFT (ffs(PCI_ERR_ROOT_IRQ) - 1)
+#define PCI_ERR_ROOT_STATUS_REPORT_MASK (PCI_ERR_ROOT_COR_RCV | \
+ PCI_ERR_ROOT_MULTI_COR_RCV | \
+ PCI_ERR_ROOT_UNCOR_RCV | \
+ PCI_ERR_ROOT_MULTI_UNCOR_RCV | \
+ PCI_ERR_ROOT_FIRST_FATAL | \
+ PCI_ERR_ROOT_NONFATAL_RCV | \
+ PCI_ERR_ROOT_FATAL_RCV)
+
+#define PCI_ERR_UNC_SUPPORTED (PCI_ERR_UNC_DLP | \
+ PCI_ERR_UNC_SDN | \
+ PCI_ERR_UNC_POISON_TLP | \
+ PCI_ERR_UNC_FCP | \
+ PCI_ERR_UNC_COMP_TIME | \
+ PCI_ERR_UNC_COMP_ABORT | \
+ PCI_ERR_UNC_UNX_COMP | \
+ PCI_ERR_UNC_RX_OVER | \
+ PCI_ERR_UNC_MALF_TLP | \
+ PCI_ERR_UNC_ECRC | \
+ PCI_ERR_UNC_UNSUP | \
+ PCI_ERR_UNC_ACSV | \
+ PCI_ERR_UNC_INTN | \
+ PCI_ERR_UNC_MCBTLP | \
+ PCI_ERR_UNC_ATOP_EBLOCKED | \
+ PCI_ERR_UNC_TLP_PRF_BLOCKED)
+
+#define PCI_ERR_UNC_SEVERITY_DEFAULT (PCI_ERR_UNC_DLP | \
+ PCI_ERR_UNC_SDN | \
+ PCI_ERR_UNC_FCP | \
+ PCI_ERR_UNC_RX_OVER | \
+ PCI_ERR_UNC_MALF_TLP | \
+ PCI_ERR_UNC_INTN)
+
+#define PCI_ERR_COR_SUPPORTED (PCI_ERR_COR_RCVR | \
+ PCI_ERR_COR_BAD_TLP | \
+ PCI_ERR_COR_BAD_DLLP | \
+ PCI_ERR_COR_REP_ROLL | \
+ PCI_ERR_COR_REP_TIMER | \
+ PCI_ERR_COR_ADV_NONFATAL | \
+ PCI_ERR_COR_INTERNAL | \
+ PCI_ERR_COR_HL_OVERFLOW)
+
+#define PCI_ERR_COR_MASK_DEFAULT (PCI_ERR_COR_ADV_NONFATAL | \
+ PCI_ERR_COR_INTERNAL | \
+ PCI_ERR_COR_HL_OVERFLOW)
+
+#endif /* QEMU_PCIE_REGS_H */
commit e4c7d2aef899780f9b9b86343bca4ac34c9e252f
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Tue Oct 19 18:06:32 2010 +0900
msi: implements msi
implements msi related functions.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/Makefile.objs b/Makefile.objs
index 594894b..5f5a4c5 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -186,7 +186,7 @@ hw-obj-$(CONFIG_PIIX4) += piix4.o
# PCI watchdog devices
hw-obj-y += wdt_i6300esb.o
-hw-obj-y += msix.o
+hw-obj-y += msix.o msi.o
# PCI network cards
hw-obj-y += ne2000.o
diff --git a/hw/msi.c b/hw/msi.c
new file mode 100644
index 0000000..a949d82
--- /dev/null
+++ b/hw/msi.c
@@ -0,0 +1,352 @@
+/*
+ * msi.c
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "msi.h"
+
+/* Eventually those constants should go to Linux pci_regs.h */
+#define PCI_MSI_PENDING_32 0x10
+#define PCI_MSI_PENDING_64 0x14
+
+/* PCI_MSI_ADDRESS_LO */
+#define PCI_MSI_ADDRESS_LO_MASK (~0x3)
+
+/* If we get rid of cap allocator, we won't need those. */
+#define PCI_MSI_32_SIZEOF 0x0a
+#define PCI_MSI_64_SIZEOF 0x0e
+#define PCI_MSI_32M_SIZEOF 0x14
+#define PCI_MSI_64M_SIZEOF 0x18
+
+#define PCI_MSI_VECTORS_MAX 32
+
+/* If we get rid of cap allocator, we won't need this. */
+static inline uint8_t msi_cap_sizeof(uint16_t flags)
+{
+ switch (flags & (PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT)) {
+ case PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT:
+ return PCI_MSI_64M_SIZEOF;
+ case PCI_MSI_FLAGS_64BIT:
+ return PCI_MSI_64_SIZEOF;
+ case PCI_MSI_FLAGS_MASKBIT:
+ return PCI_MSI_32M_SIZEOF;
+ case 0:
+ return PCI_MSI_32_SIZEOF;
+ default:
+ abort();
+ break;
+ }
+ return 0;
+}
+
+//#define MSI_DEBUG
+
+#ifdef MSI_DEBUG
+# define MSI_DPRINTF(fmt, ...) \
+ fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
+#else
+# define MSI_DPRINTF(fmt, ...) do { } while (0)
+#endif
+#define MSI_DEV_PRINTF(dev, fmt, ...) \
+ MSI_DPRINTF("%s:%x " fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
+
+static inline unsigned int msi_nr_vectors(uint16_t flags)
+{
+ return 1U <<
+ ((flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1));
+}
+
+static inline uint8_t msi_flags_off(const PCIDevice* dev)
+{
+ return dev->msi_cap + PCI_MSI_FLAGS;
+}
+
+static inline uint8_t msi_address_lo_off(const PCIDevice* dev)
+{
+ return dev->msi_cap + PCI_MSI_ADDRESS_LO;
+}
+
+static inline uint8_t msi_address_hi_off(const PCIDevice* dev)
+{
+ return dev->msi_cap + PCI_MSI_ADDRESS_HI;
+}
+
+static inline uint8_t msi_data_off(const PCIDevice* dev, bool msi64bit)
+{
+ return dev->msi_cap + (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32);
+}
+
+static inline uint8_t msi_mask_off(const PCIDevice* dev, bool msi64bit)
+{
+ return dev->msi_cap + (msi64bit ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32);
+}
+
+static inline uint8_t msi_pending_off(const PCIDevice* dev, bool msi64bit)
+{
+ return dev->msi_cap + (msi64bit ? PCI_MSI_PENDING_64 : PCI_MSI_PENDING_32);
+}
+
+bool msi_enabled(const PCIDevice *dev)
+{
+ return msi_present(dev) &&
+ (pci_get_word(dev->config + msi_flags_off(dev)) &
+ PCI_MSI_FLAGS_ENABLE);
+}
+
+int msi_init(struct PCIDevice *dev, uint8_t offset,
+ unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask)
+{
+ unsigned int vectors_order;
+ uint16_t flags;
+ uint8_t cap_size;
+ int config_offset;
+ MSI_DEV_PRINTF(dev,
+ "init offset: 0x%"PRIx8" vector: %"PRId8
+ " 64bit %d mask %d\n",
+ offset, nr_vectors, msi64bit, msi_per_vector_mask);
+
+ assert(!(nr_vectors & (nr_vectors - 1))); /* power of 2 */
+ assert(nr_vectors > 0);
+ assert(nr_vectors <= PCI_MSI_VECTORS_MAX);
+ /* the nr of MSI vectors is up to 32 */
+ vectors_order = ffs(nr_vectors) - 1;
+
+ flags = vectors_order << (ffs(PCI_MSI_FLAGS_QMASK) - 1);
+ if (msi64bit) {
+ flags |= PCI_MSI_FLAGS_64BIT;
+ }
+ if (msi_per_vector_mask) {
+ flags |= PCI_MSI_FLAGS_MASKBIT;
+ }
+
+ cap_size = msi_cap_sizeof(flags);
+ config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size);
+ if (config_offset < 0) {
+ return config_offset;
+ }
+
+ dev->msi_cap = config_offset;
+ dev->cap_present |= QEMU_PCI_CAP_MSI;
+
+ pci_set_word(dev->config + msi_flags_off(dev), flags);
+ pci_set_word(dev->wmask + msi_flags_off(dev),
+ PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
+ pci_set_long(dev->wmask + msi_address_lo_off(dev),
+ PCI_MSI_ADDRESS_LO_MASK);
+ if (msi64bit) {
+ pci_set_long(dev->wmask + msi_address_hi_off(dev), 0xffffffff);
+ }
+ pci_set_word(dev->wmask + msi_data_off(dev, msi64bit), 0xffff);
+
+ if (msi_per_vector_mask) {
+ pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit),
+ /* (1U << nr_vectors) - 1 is undefined
+ when nr_vectors = 32 */
+ 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors));
+ }
+ return config_offset;
+}
+
+void msi_uninit(struct PCIDevice *dev)
+{
+ uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
+ uint8_t cap_size = msi_cap_sizeof(flags);
+ pci_del_capability(dev, PCI_CAP_ID_MSIX, cap_size);
+ MSI_DEV_PRINTF(dev, "uninit\n");
+}
+
+void msi_reset(PCIDevice *dev)
+{
+ uint16_t flags;
+ bool msi64bit;
+
+ flags = pci_get_word(dev->config + msi_flags_off(dev));
+ flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
+ msi64bit = flags & PCI_MSI_FLAGS_64BIT;
+
+ pci_set_word(dev->config + msi_flags_off(dev), flags);
+ pci_set_long(dev->config + msi_address_lo_off(dev), 0);
+ if (msi64bit) {
+ pci_set_long(dev->config + msi_address_hi_off(dev), 0);
+ }
+ pci_set_word(dev->config + msi_data_off(dev, msi64bit), 0);
+ if (flags & PCI_MSI_FLAGS_MASKBIT) {
+ pci_set_long(dev->config + msi_mask_off(dev, msi64bit), 0);
+ pci_set_long(dev->config + msi_pending_off(dev, msi64bit), 0);
+ }
+ MSI_DEV_PRINTF(dev, "reset\n");
+}
+
+static bool msi_is_masked(const PCIDevice *dev, unsigned int vector)
+{
+ uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
+ uint32_t mask;
+ assert(vector < PCI_MSI_VECTORS_MAX);
+
+ if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
+ return false;
+ }
+
+ mask = pci_get_long(dev->config +
+ msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT));
+ return mask & (1U << vector);
+}
+
+void msi_notify(PCIDevice *dev, unsigned int vector)
+{
+ uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
+ bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
+ unsigned int nr_vectors = msi_nr_vectors(flags);
+ uint64_t address;
+ uint32_t data;
+
+ assert(vector < nr_vectors);
+ if (msi_is_masked(dev, vector)) {
+ assert(flags & PCI_MSI_FLAGS_MASKBIT);
+ pci_long_test_and_set_mask(
+ dev->config + msi_pending_off(dev, msi64bit), 1U << vector);
+ MSI_DEV_PRINTF(dev, "pending vector 0x%x\n", vector);
+ return;
+ }
+
+ if (msi64bit){
+ address = pci_get_quad(dev->config + msi_address_lo_off(dev));
+ } else {
+ address = pci_get_long(dev->config + msi_address_lo_off(dev));
+ }
+
+ /* upper bit 31:16 is zero */
+ data = pci_get_word(dev->config + msi_data_off(dev, msi64bit));
+ if (nr_vectors > 1) {
+ data &= ~(nr_vectors - 1);
+ data |= vector;
+ }
+
+ MSI_DEV_PRINTF(dev,
+ "notify vector 0x%x"
+ " address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
+ vector, address, data);
+ stl_phys(address, data);
+}
+
+/* call this function after updating configs by pci_default_write_config(). */
+void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
+{
+ uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
+ bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
+ bool msi_per_vector_mask = flags & PCI_MSI_FLAGS_MASKBIT;
+ unsigned int nr_vectors;
+ uint8_t log_num_vecs;
+ uint8_t log_max_vecs;
+ unsigned int vector;
+ uint32_t pending;
+ int i;
+
+#ifdef MSI_DEBUG
+ if (ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
+ MSI_DEV_PRINTF(dev, "addr 0x%"PRIx32" val 0x%"PRIx32" len %d\n",
+ addr, val, len);
+ MSI_DEV_PRINTF(dev, "ctrl: 0x%"PRIx16" address: 0x%"PRIx32,
+ flags,
+ pci_get_long(dev->config + msi_address_lo_off(dev)));
+ if (msi64bit) {
+ fprintf(stderr, " addrss-hi: 0x%"PRIx32,
+ pci_get_long(dev->config + msi_address_hi_off(dev)));
+ }
+ fprintf(stderr, " data: 0x%"PRIx16,
+ pci_get_word(dev->config + msi_data_off(dev, msi64bit)));
+ if (flags & PCI_MSI_FLAGS_MASKBIT) {
+ fprintf(stderr, " mask 0x%"PRIx32" pending 0x%"PRIx32,
+ pci_get_long(dev->config + msi_mask_off(dev, msi64bit)),
+ pci_get_long(dev->config + msi_pending_off(dev, msi64bit)));
+ }
+ fprintf(stderr, "\n");
+ }
+#endif
+
+ /* Are we modified? */
+ if (!(ranges_overlap(addr, len, msi_flags_off(dev), 2) ||
+ (msi_per_vector_mask &&
+ ranges_overlap(addr, len, msi_mask_off(dev, msi64bit), 4)))) {
+ return;
+ }
+
+ if (!(flags & PCI_MSI_FLAGS_ENABLE)) {
+ return;
+ }
+
+ /*
+ * Now MSI is enabled, clear INTx# interrupts.
+ * the driver is prohibited from writing enable bit to mask
+ * a service request. But the guest OS could do this.
+ * So we just discard the interrupts as moderate fallback.
+ *
+ * 6.8.3.3. Enabling Operation
+ * While enabled for MSI or MSI-X operation, a function is prohibited
+ * from using its INTx# pin (if implemented) to request
+ * service (MSI, MSI-X, and INTx# are mutually exclusive).
+ */
+ for (i = 0; i < PCI_NUM_PINS; ++i) {
+ qemu_set_irq(dev->irq[i], 0);
+ }
+
+ /*
+ * nr_vectors might be set bigger than capable. So clamp it.
+ * This is not legal by spec, so we can do anything we like,
+ * just don't crash the host
+ */
+ log_num_vecs =
+ (flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1);
+ log_max_vecs =
+ (flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) - 1);
+ if (log_num_vecs > log_max_vecs) {
+ flags &= ~PCI_MSI_FLAGS_QSIZE;
+ flags |= log_max_vecs << (ffs(PCI_MSI_FLAGS_QSIZE) - 1);
+ pci_set_word(dev->config + msi_flags_off(dev), flags);
+ }
+
+ if (!msi_per_vector_mask) {
+ /* if per vector masking isn't supported,
+ there is no pending interrupt. */
+ return;
+ }
+
+ nr_vectors = msi_nr_vectors(flags);
+
+ /* This will discard pending interrupts, if any. */
+ pending = pci_get_long(dev->config + msi_pending_off(dev, msi64bit));
+ pending &= 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors);
+ pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pending);
+
+ /* deliver pending interrupts which are unmasked */
+ for (vector = 0; vector < nr_vectors; ++vector) {
+ if (msi_is_masked(dev, vector) || !(pending & (1U << vector))) {
+ continue;
+ }
+
+ pci_long_test_and_clear_mask(
+ dev->config + msi_pending_off(dev, msi64bit), 1U << vector);
+ msi_notify(dev, vector);
+ }
+}
+
+unsigned int msi_nr_vectors_allocated(const PCIDevice *dev)
+{
+ uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
+ return msi_nr_vectors(flags);
+}
diff --git a/hw/msi.h b/hw/msi.h
new file mode 100644
index 0000000..5766018
--- /dev/null
+++ b/hw/msi.h
@@ -0,0 +1,41 @@
+/*
+ * msi.h
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_MSI_H
+#define QEMU_MSI_H
+
+#include "qemu-common.h"
+#include "pci.h"
+
+bool msi_enabled(const PCIDevice *dev);
+int msi_init(struct PCIDevice *dev, uint8_t offset,
+ unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask);
+void msi_uninit(struct PCIDevice *dev);
+void msi_reset(PCIDevice *dev);
+void msi_notify(PCIDevice *dev, unsigned int vector);
+void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len);
+unsigned int msi_nr_vectors_allocated(const PCIDevice *dev);
+
+static inline bool msi_present(const PCIDevice *dev)
+{
+ return dev->cap_present & QEMU_PCI_CAP_MSI;
+}
+
+#endif /* QEMU_MSI_H */
diff --git a/hw/pci.h b/hw/pci.h
index 3072a5f..9e2f27d 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -109,11 +109,12 @@ typedef struct PCIIORegion {
/* Bits in cap_present field. */
enum {
- QEMU_PCI_CAP_MSIX = 0x1,
- QEMU_PCI_CAP_EXPRESS = 0x2,
+ QEMU_PCI_CAP_MSI = 0x1,
+ QEMU_PCI_CAP_MSIX = 0x2,
+ QEMU_PCI_CAP_EXPRESS = 0x4,
/* multifunction capable device */
-#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR 2
+#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR 3
QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR),
};
@@ -171,6 +172,9 @@ struct PCIDevice {
/* Version id needed for VMState */
int32_t version_id;
+ /* Offset of MSI capability in config space */
+ uint8_t msi_cap;
+
/* Location of option rom */
char *romfile;
ram_addr_t rom_offset;
commit 99443c21b06aa433d74880f9d2a0e4320631b906
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Tue Oct 19 18:06:30 2010 +0900
pci: use pci_word_test_and_clear_mask() in pci_device_reset()
use pci_clear_bit_word() in pci_device_reset() where appropriate.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index 300079f..409e2c0 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -139,9 +139,8 @@ static void pci_device_reset(PCIDevice *dev)
dev->irq_state = 0;
pci_update_irq_status(dev);
/* Clear all writeable bits */
- pci_set_word(dev->config + PCI_COMMAND,
- pci_get_word(dev->config + PCI_COMMAND) &
- ~pci_get_word(dev->wmask + PCI_COMMAND));
+ pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
+ pci_get_word(dev->wmask + PCI_COMMAND));
dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
dev->config[PCI_INTERRUPT_LINE] = 0x0;
for (r = 0; r < PCI_NUM_REGIONS; ++r) {
commit a5d1fd20ccfd1fbe840729378e4adbc3eb0f8306
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Tue Oct 19 18:06:29 2010 +0900
pci: introduce helper function to handle msi-x and msi.
this patch implements helper functions to handle msi-x and msi
uniformly.
They will be used later.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index e3462a9..300079f 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -25,6 +25,8 @@
#include "pci.h"
#include "pci_bridge.h"
#include "pci_internals.h"
+#include "msix.h"
+#include "msi.h"
#include "monitor.h"
#include "net.h"
#include "sysemu.h"
@@ -1034,6 +1036,23 @@ static void pci_set_irq(void *opaque, int irq_num, int level)
pci_change_irq_level(pci_dev, irq_num, change);
}
+bool pci_msi_enabled(PCIDevice *dev)
+{
+ return msix_enabled(dev) || msi_enabled(dev);
+}
+
+void pci_msi_notify(PCIDevice *dev, unsigned int vector)
+{
+ if (msix_enabled(dev)) {
+ msix_notify(dev, vector);
+ } else if (msi_enabled(dev)) {
+ msi_notify(dev, vector);
+ } else {
+ /* MSI/MSI-X must be enabled */
+ abort();
+ }
+}
+
/***********************************************************/
/* monitor info on PCI */
diff --git a/hw/pci.h b/hw/pci.h
index 752e652..3072a5f 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -239,6 +239,9 @@ void do_pci_info_print(Monitor *mon, const QObject *data);
void do_pci_info(Monitor *mon, QObject **ret_data);
void pci_bridge_update_mappings(PCIBus *b);
+bool pci_msi_enabled(PCIDevice *dev);
+void pci_msi_notify(PCIDevice *dev, unsigned int vector);
+
static inline void
pci_set_byte(uint8_t *config, uint8_t val)
{
commit aabcf5266f94e637afd4c38d46d1fc1d1381d99e
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Tue Oct 19 18:06:28 2010 +0900
pci: introduce helper functions to test-and-{clear, set} mask in configuration space
This patch introduces helper functions to test-and-{clear, set} mask in configuration
space. pci_{byte, word, long, quad}_test_and_{clear, set}_mask().
They will be used later.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.h b/hw/pci.h
index d8b399f..752e652 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -323,6 +323,76 @@ pci_config_set_interrupt_pin(uint8_t *pci_config, uint8_t val)
pci_set_byte(&pci_config[PCI_INTERRUPT_PIN], val);
}
+/*
+ * helper functions to do bit mask operation on configuration space.
+ * Just to set bit, use test-and-set and discard returned value.
+ * Just to clear bit, use test-and-clear and discard returned value.
+ * NOTE: They aren't atomic.
+ */
+static inline uint8_t
+pci_byte_test_and_clear_mask(uint8_t *config, uint8_t mask)
+{
+ uint8_t val = pci_get_byte(config);
+ pci_set_byte(config, val & ~mask);
+ return val & mask;
+}
+
+static inline uint8_t
+pci_byte_test_and_set_mask(uint8_t *config, uint8_t mask)
+{
+ uint8_t val = pci_get_byte(config);
+ pci_set_byte(config, val | mask);
+ return val & mask;
+}
+
+static inline uint16_t
+pci_word_test_and_clear_mask(uint8_t *config, uint16_t mask)
+{
+ uint16_t val = pci_get_word(config);
+ pci_set_word(config, val & ~mask);
+ return val & mask;
+}
+
+static inline uint16_t
+pci_word_test_and_set_mask(uint8_t *config, uint16_t mask)
+{
+ uint16_t val = pci_get_word(config);
+ pci_set_word(config, val | mask);
+ return val & mask;
+}
+
+static inline uint32_t
+pci_long_test_and_clear_mask(uint8_t *config, uint32_t mask)
+{
+ uint32_t val = pci_get_long(config);
+ pci_set_long(config, val & ~mask);
+ return val & mask;
+}
+
+static inline uint32_t
+pci_long_test_and_set_mask(uint8_t *config, uint32_t mask)
+{
+ uint32_t val = pci_get_long(config);
+ pci_set_long(config, val | mask);
+ return val & mask;
+}
+
+static inline uint64_t
+pci_quad_test_and_clear_mask(uint8_t *config, uint64_t mask)
+{
+ uint64_t val = pci_get_quad(config);
+ pci_set_quad(config, val & ~mask);
+ return val & mask;
+}
+
+static inline uint64_t
+pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask)
+{
+ uint64_t val = pci_get_quad(config);
+ pci_set_quad(config, val | mask);
+ return val & mask;
+}
+
typedef int (*pci_qdev_initfn)(PCIDevice *dev);
typedef struct {
DeviceInfo qdev;
commit 1a4f5971b6f785db7cb2b964754d04103a0d2033
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Mon Oct 18 12:17:42 2010 +0900
pci: make pci_del_capability() update for w1cmask
Clear w1cmask when deleting a pci capability.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index abddc6d..e3462a9 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1745,6 +1745,7 @@ void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT];
/* Make capability writeable again */
memset(pdev->wmask + offset, 0xff, size);
+ memset(pdev->w1cmask + offset, 0, size);
/* Clear cmask as device-specific registers can't be checked */
memset(pdev->cmask + offset, 0, size);
memset(pdev->used + offset, 0, size);
commit 84a23f251fe85768338434040257bb96cf555de8
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon Aug 30 16:36:53 2010 +0200
spice: add misc config options
This patch adds a few more options to tweak spice server behavior.
The documentation update chunk has the details ;)
diff --git a/qemu-config.c b/qemu-config.c
index 5a62ae1..52f18be 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -415,6 +415,15 @@ QemuOptsList qemu_spice_opts = {
},{
.name = "zlib-glz-wan-compression",
.type = QEMU_OPT_STRING,
+ },{
+ .name = "streaming-video",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "agent-mouse",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "playback-compression",
+ .type = QEMU_OPT_BOOL,
},
{ /* end if list */ }
},
diff --git a/qemu-options.hx b/qemu-options.hx
index 0410b90..9e38dfb 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -728,6 +728,15 @@ Default is auto_glz.
Configure wan image compression (lossy for slow links).
Default is auto.
+ at item streaming-video=[off|all|filter]
+Configure video stream detection. Default is filter.
+
+ at item agent-mouse=[on|off]
+Enable/disable passing mouse events via vdagent. Default is on.
+
+ at item playback-compression=[on|off]
+Enable/disable audio stream compression (using celt 0.5.1). Default is on.
+
@end table
ETEXI
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 6f613c6..6a1cf17 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -169,6 +169,18 @@ static int parse_name(const char *string, const char *optname,
exit(1);
}
+#if SPICE_SERVER_VERSION >= 0x000600 /* 0.6.0 */
+
+static const char *stream_video_names[] = {
+ [ SPICE_STREAM_VIDEO_OFF ] = "off",
+ [ SPICE_STREAM_VIDEO_ALL ] = "all",
+ [ SPICE_STREAM_VIDEO_FILTER ] = "filter",
+};
+#define parse_stream_video(_name) \
+ name2enum(_name, stream_video_names, ARRAY_SIZE(stream_video_names))
+
+#endif /* >= 0.6.0 */
+
static const char *compression_names[] = {
[ SPICE_IMAGE_COMPRESS_OFF ] = "off",
[ SPICE_IMAGE_COMPRESS_AUTO_GLZ ] = "auto_glz",
@@ -228,7 +240,7 @@ void qemu_spice_init(void)
char *x509_key_file = NULL,
*x509_cert_file = NULL,
*x509_cacert_file = NULL;
- int port, tls_port, len, addr_flags;
+ int port, tls_port, len, addr_flags, streaming_video;
spice_image_compression_t compression;
spice_wan_compression_t wan_compr;
@@ -328,6 +340,21 @@ void qemu_spice_init(void)
}
spice_server_set_zlib_glz_compression(spice_server, wan_compr);
+#if SPICE_SERVER_VERSION >= 0x000600 /* 0.6.0 */
+
+ str = qemu_opt_get(opts, "streaming-video");
+ if (str) {
+ streaming_video = parse_stream_video(str);
+ spice_server_set_streaming_video(spice_server, streaming_video);
+ }
+
+ spice_server_set_agent_mouse
+ (spice_server, qemu_opt_get_bool(opts, "agent-mouse", 1));
+ spice_server_set_playback_compression
+ (spice_server, qemu_opt_get_bool(opts, "playback-compression", 1));
+
+#endif /* >= 0.6.0 */
+
qemu_opt_foreach(opts, add_channel, NULL, 0);
spice_server_init(spice_server, &core_interface);
commit 333b0eebcc8941b8453e837293eaa1191e967c25
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Fri Aug 27 14:29:16 2010 +0200
spice: add config options for the listening address
Make listening address configurable. Also add options to
force using IPv4 or IPv6.
diff --git a/qemu-config.c b/qemu-config.c
index f52e50c..5a62ae1 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -365,6 +365,15 @@ QemuOptsList qemu_spice_opts = {
.name = "tls-port",
.type = QEMU_OPT_NUMBER,
},{
+ .name = "addr",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "ipv4",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "ipv6",
+ .type = QEMU_OPT_BOOL,
+ },{
.name = "password",
.type = QEMU_OPT_STRING,
},{
diff --git a/qemu-options.hx b/qemu-options.hx
index 5a0d26b..0410b90 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -682,6 +682,13 @@ Enable the spice remote desktop protocol. Valid options are
@item port=<nr>
Set the TCP port spice is listening on for plaintext channels.
+ at item addr=<addr>
+Set the IP address spice is listening on. Default is any address.
+
+ at item ipv4
+ at item ipv6
+Force using the specified IP version.
+
@item password=<secret>
Set the password you need to authenticate.
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 7664ef7..6f613c6 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -221,14 +221,14 @@ static int add_channel(const char *name, const char *value, void *opaque)
void qemu_spice_init(void)
{
QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
- const char *password, *str, *x509_dir,
+ const char *password, *str, *x509_dir, *addr,
*x509_key_password = NULL,
*x509_dh_file = NULL,
*tls_ciphers = NULL;
char *x509_key_file = NULL,
*x509_cert_file = NULL,
*x509_cacert_file = NULL;
- int port, tls_port, len;
+ int port, tls_port, len, addr_flags;
spice_image_compression_t compression;
spice_wan_compression_t wan_compr;
@@ -278,7 +278,16 @@ void qemu_spice_init(void)
tls_ciphers = qemu_opt_get(opts, "tls-ciphers");
}
+ addr = qemu_opt_get(opts, "addr");
+ addr_flags = 0;
+ if (qemu_opt_get_bool(opts, "ipv4", 0)) {
+ addr_flags |= SPICE_ADDR_FLAG_IPV4_ONLY;
+ } else if (qemu_opt_get_bool(opts, "ipv6", 0)) {
+ addr_flags |= SPICE_ADDR_FLAG_IPV6_ONLY;
+ }
+
spice_server = spice_server_new();
+ spice_server_set_addr(spice_server, addr ? addr : "", addr_flags);
if (port) {
spice_server_set_port(spice_server, port);
}
commit 17b6dea08bd8c8484bc48dc67add236d2fe002b5
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Fri Aug 27 14:09:56 2010 +0200
spice: add config options for channel security.
This allows to enforce tls or plaintext usage for certain spice
channels.
[ v2: code style fixup ]
diff --git a/qemu-config.c b/qemu-config.c
index 8b545b1..f52e50c 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -392,6 +392,12 @@ QemuOptsList qemu_spice_opts = {
.name = "tls-ciphers",
.type = QEMU_OPT_STRING,
},{
+ .name = "tls-channel",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "plaintext-channel",
+ .type = QEMU_OPT_STRING,
+ },{
.name = "image-compression",
.type = QEMU_OPT_STRING,
},{
diff --git a/qemu-options.hx b/qemu-options.hx
index b9edaae..5a0d26b 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -704,6 +704,14 @@ The x509 file names can also be configured individually.
@item tls-ciphers=<list>
Specify which ciphers to use.
+ at item tls-channel=[main|display|inputs|record|playback|tunnel]
+ at item plaintext-channel=[main|display|inputs|record|playback|tunnel]
+Force specific channel to be used with or without TLS encryption. The
+options can be specified multiple times to configure multiple
+channels. The special name "default" can be used to set the default
+mode. For channels which are not explicitly forced into one mode the
+spice client is allowed to pick tls/plaintext as he pleases.
+
@item image-compression=[auto_glz|auto_lz|quic|glz|lz|off]
Configure image compression (lossless).
Default is auto_glz.
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 1567046..7664ef7 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -192,6 +192,32 @@ static const char *wan_compression_names[] = {
/* functions for the rest of qemu */
+static int add_channel(const char *name, const char *value, void *opaque)
+{
+ int security = 0;
+ int rc;
+
+ if (strcmp(name, "tls-channel") == 0) {
+ security = SPICE_CHANNEL_SECURITY_SSL;
+ }
+ if (strcmp(name, "plaintext-channel") == 0) {
+ security = SPICE_CHANNEL_SECURITY_NONE;
+ }
+ if (security == 0) {
+ return 0;
+ }
+ if (strcmp(value, "default") == 0) {
+ rc = spice_server_set_channel_security(spice_server, NULL, security);
+ } else {
+ rc = spice_server_set_channel_security(spice_server, value, security);
+ }
+ if (rc != 0) {
+ fprintf(stderr, "spice: failed to set channel security for %s\n", value);
+ exit(1);
+ }
+ return 0;
+}
+
void qemu_spice_init(void)
{
QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
@@ -293,6 +319,8 @@ void qemu_spice_init(void)
}
spice_server_set_zlib_glz_compression(spice_server, wan_compr);
+ qemu_opt_foreach(opts, add_channel, NULL, 0);
+
spice_server_init(spice_server, &core_interface);
using_spice = 1;
commit 9f04e09e36e430dd57c69c88b0532e9dc5061a47
Author: Yonit Halperin <yhalperi at redhat.com>
Date: Wed Jul 14 13:26:34 2010 +0300
spice: make compression configurable.
This patch adds options to the -spice command line switch to
configure image compression.
[ v2: speling fix in the documentation ]
diff --git a/qemu-config.c b/qemu-config.c
index 26748a5..8b545b1 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -391,6 +391,15 @@ QemuOptsList qemu_spice_opts = {
},{
.name = "tls-ciphers",
.type = QEMU_OPT_STRING,
+ },{
+ .name = "image-compression",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "jpeg-wan-compression",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "zlib-glz-wan-compression",
+ .type = QEMU_OPT_STRING,
},
{ /* end if list */ }
},
diff --git a/qemu-options.hx b/qemu-options.hx
index 9d3f8ef..b9edaae 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -704,6 +704,15 @@ The x509 file names can also be configured individually.
@item tls-ciphers=<list>
Specify which ciphers to use.
+ at item image-compression=[auto_glz|auto_lz|quic|glz|lz|off]
+Configure image compression (lossless).
+Default is auto_glz.
+
+ at item jpeg-wan-compression=[auto|never|always]
+ at item zlib-glz-wan-compression=[auto|never|always]
+Configure wan image compression (lossy for slow links).
+Default is auto.
+
@end table
ETEXI
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 51aa782..1567046 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -137,6 +137,59 @@ static SpiceCoreInterface core_interface = {
.watch_remove = watch_remove,
};
+/* config string parsing */
+
+static int name2enum(const char *string, const char *table[], int entries)
+{
+ int i;
+
+ if (string) {
+ for (i = 0; i < entries; i++) {
+ if (!table[i]) {
+ continue;
+ }
+ if (strcmp(string, table[i]) != 0) {
+ continue;
+ }
+ return i;
+ }
+ }
+ return -1;
+}
+
+static int parse_name(const char *string, const char *optname,
+ const char *table[], int entries)
+{
+ int value = name2enum(string, table, entries);
+
+ if (value != -1) {
+ return value;
+ }
+ fprintf(stderr, "spice: invalid %s: %s\n", optname, string);
+ exit(1);
+}
+
+static const char *compression_names[] = {
+ [ SPICE_IMAGE_COMPRESS_OFF ] = "off",
+ [ SPICE_IMAGE_COMPRESS_AUTO_GLZ ] = "auto_glz",
+ [ SPICE_IMAGE_COMPRESS_AUTO_LZ ] = "auto_lz",
+ [ SPICE_IMAGE_COMPRESS_QUIC ] = "quic",
+ [ SPICE_IMAGE_COMPRESS_GLZ ] = "glz",
+ [ SPICE_IMAGE_COMPRESS_LZ ] = "lz",
+};
+#define parse_compression(_name) \
+ parse_name(_name, "image compression", \
+ compression_names, ARRAY_SIZE(compression_names))
+
+static const char *wan_compression_names[] = {
+ [ SPICE_WAN_COMPRESSION_AUTO ] = "auto",
+ [ SPICE_WAN_COMPRESSION_NEVER ] = "never",
+ [ SPICE_WAN_COMPRESSION_ALWAYS ] = "always",
+};
+#define parse_wan_compression(_name) \
+ parse_name(_name, "wan compression", \
+ wan_compression_names, ARRAY_SIZE(wan_compression_names))
+
/* functions for the rest of qemu */
void qemu_spice_init(void)
@@ -150,6 +203,8 @@ void qemu_spice_init(void)
*x509_cert_file = NULL,
*x509_cacert_file = NULL;
int port, tls_port, len;
+ spice_image_compression_t compression;
+ spice_wan_compression_t wan_compr;
if (!opts) {
return;
@@ -217,8 +272,26 @@ void qemu_spice_init(void)
spice_server_set_noauth(spice_server);
}
- /* TODO: make configurable via cmdline */
- spice_server_set_image_compression(spice_server, SPICE_IMAGE_COMPRESS_AUTO_GLZ);
+ compression = SPICE_IMAGE_COMPRESS_AUTO_GLZ;
+ str = qemu_opt_get(opts, "image-compression");
+ if (str) {
+ compression = parse_compression(str);
+ }
+ spice_server_set_image_compression(spice_server, compression);
+
+ wan_compr = SPICE_WAN_COMPRESSION_AUTO;
+ str = qemu_opt_get(opts, "jpeg-wan-compression");
+ if (str) {
+ wan_compr = parse_wan_compression(str);
+ }
+ spice_server_set_jpeg_compression(spice_server, wan_compr);
+
+ wan_compr = SPICE_WAN_COMPRESSION_AUTO;
+ str = qemu_opt_get(opts, "zlib-glz-wan-compression");
+ if (str) {
+ wan_compr = parse_wan_compression(str);
+ }
+ spice_server_set_zlib_glz_compression(spice_server, wan_compr);
spice_server_init(spice_server, &core_interface);
using_spice = 1;
commit c448e8552b0f6135dabddf944a7110f929c08320
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Mar 11 11:13:32 2010 -0300
spice: tls support
Add options to the -spice command line switch to setup tls.
diff --git a/qemu-config.c b/qemu-config.c
index 32917cb..26748a5 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -362,11 +362,35 @@ QemuOptsList qemu_spice_opts = {
.name = "port",
.type = QEMU_OPT_NUMBER,
},{
+ .name = "tls-port",
+ .type = QEMU_OPT_NUMBER,
+ },{
.name = "password",
.type = QEMU_OPT_STRING,
},{
.name = "disable-ticketing",
.type = QEMU_OPT_BOOL,
+ },{
+ .name = "x509-dir",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "x509-key-file",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "x509-key-password",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "x509-cert-file",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "x509-cacert-file",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "x509-dh-key-file",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "tls-ciphers",
+ .type = QEMU_OPT_STRING,
},
{ /* end if list */ }
},
diff --git a/qemu-options.hx b/qemu-options.hx
index 718d47a..9d3f8ef 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -680,7 +680,7 @@ Enable the spice remote desktop protocol. Valid options are
@table @option
@item port=<nr>
-Set the TCP port spice is listening on.
+Set the TCP port spice is listening on for plaintext channels.
@item password=<secret>
Set the password you need to authenticate.
@@ -688,6 +688,22 @@ Set the password you need to authenticate.
@item disable-ticketing
Allow client connects without authentication.
+ at item tls-port=<nr>
+Set the TCP port spice is listening on for encrypted channels.
+
+ at item x509-dir=<dir>
+Set the x509 file directory. Expects same filenames as -vnc $display,x509=$dir
+
+ at item x509-key-file=<file>
+ at item x509-key-password=<file>
+ at item x509-cert-file=<file>
+ at item x509-cacert-file=<file>
+ at item x509-dh-key-file=<file>
+The x509 file names can also be configured individually.
+
+ at item tls-ciphers=<list>
+Specify which ciphers to use.
+
@end table
ETEXI
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 8b5e4a8..51aa782 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -22,6 +22,7 @@
#include "qemu-spice.h"
#include "qemu-timer.h"
#include "qemu-queue.h"
+#include "qemu-x509.h"
#include "monitor.h"
/* core bits */
@@ -141,20 +142,74 @@ static SpiceCoreInterface core_interface = {
void qemu_spice_init(void)
{
QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
- const char *password;
- int port;
+ const char *password, *str, *x509_dir,
+ *x509_key_password = NULL,
+ *x509_dh_file = NULL,
+ *tls_ciphers = NULL;
+ char *x509_key_file = NULL,
+ *x509_cert_file = NULL,
+ *x509_cacert_file = NULL;
+ int port, tls_port, len;
if (!opts) {
return;
}
port = qemu_opt_get_number(opts, "port", 0);
- if (!port) {
+ tls_port = qemu_opt_get_number(opts, "tls-port", 0);
+ if (!port && !tls_port) {
return;
}
password = qemu_opt_get(opts, "password");
+ if (tls_port) {
+ x509_dir = qemu_opt_get(opts, "x509-dir");
+ if (NULL == x509_dir) {
+ x509_dir = ".";
+ }
+ len = strlen(x509_dir) + 32;
+
+ str = qemu_opt_get(opts, "x509-key-file");
+ if (str) {
+ x509_key_file = qemu_strdup(str);
+ } else {
+ x509_key_file = qemu_malloc(len);
+ snprintf(x509_key_file, len, "%s/%s", x509_dir, X509_SERVER_KEY_FILE);
+ }
+
+ str = qemu_opt_get(opts, "x509-cert-file");
+ if (str) {
+ x509_cert_file = qemu_strdup(str);
+ } else {
+ x509_cert_file = qemu_malloc(len);
+ snprintf(x509_cert_file, len, "%s/%s", x509_dir, X509_SERVER_CERT_FILE);
+ }
+
+ str = qemu_opt_get(opts, "x509-cacert-file");
+ if (str) {
+ x509_cacert_file = qemu_strdup(str);
+ } else {
+ x509_cacert_file = qemu_malloc(len);
+ snprintf(x509_cacert_file, len, "%s/%s", x509_dir, X509_CA_CERT_FILE);
+ }
+
+ x509_key_password = qemu_opt_get(opts, "x509-key-password");
+ x509_dh_file = qemu_opt_get(opts, "x509-dh-file");
+ tls_ciphers = qemu_opt_get(opts, "tls-ciphers");
+ }
+
spice_server = spice_server_new();
- spice_server_set_port(spice_server, port);
+ if (port) {
+ spice_server_set_port(spice_server, port);
+ }
+ if (tls_port) {
+ spice_server_set_tls(spice_server, tls_port,
+ x509_cacert_file,
+ x509_cert_file,
+ x509_key_file,
+ x509_key_password,
+ x509_dh_file,
+ tls_ciphers);
+ }
if (password) {
spice_server_set_ticket(spice_server, password, 0, 0, 0);
}
@@ -169,6 +224,10 @@ void qemu_spice_init(void)
using_spice = 1;
qemu_spice_input_init();
+
+ qemu_free(x509_key_file);
+ qemu_free(x509_cert_file);
+ qemu_free(x509_cacert_file);
}
int qemu_spice_add_interface(SpiceBaseInstance *sin)
commit 57c6db2e2dec77a60bcfe6f93d756653f444a1f2
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Wed Sep 15 14:38:26 2010 +0900
msix: clear not only INTA, but all INTx when MSI-X is enabled.
clear not only INTA, but all INTx when MSI-X is enabled.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/msix.c b/hw/msix.c
index 7ce63eb..b202ff7 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -158,6 +158,7 @@ void msix_write_config(PCIDevice *dev, uint32_t addr,
{
unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET;
int vector;
+ int i;
if (!range_covers_byte(addr, len, enable_pos)) {
return;
@@ -167,7 +168,9 @@ void msix_write_config(PCIDevice *dev, uint32_t addr,
return;
}
- qemu_set_irq(dev->irq[0], 0);
+ for (i = 0; i < PCI_NUM_PINS; ++i) {
+ qemu_set_irq(dev->irq[i], 0);
+ }
if (msix_function_masked(dev)) {
return;
commit 92ba5f51c305911cbfc0fcff9f259b0604681222
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Wed Sep 15 14:38:15 2010 +0900
pci: implement RW1C register framework.
Implement RW1C register framework.
With this patch, it would be easy to implement
W1C(Write 1 to Clear) register by just setting w1cmask.
Later RW1C register will be used by pcie.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index 97a7b23..abddc6d 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -627,6 +627,7 @@ static void pci_config_alloc(PCIDevice *pci_dev)
pci_dev->config = qemu_mallocz(config_size);
pci_dev->cmask = qemu_mallocz(config_size);
pci_dev->wmask = qemu_mallocz(config_size);
+ pci_dev->w1cmask = qemu_mallocz(config_size);
pci_dev->used = qemu_mallocz(config_size);
}
@@ -635,6 +636,7 @@ static void pci_config_free(PCIDevice *pci_dev)
qemu_free(pci_dev->config);
qemu_free(pci_dev->cmask);
qemu_free(pci_dev->wmask);
+ qemu_free(pci_dev->w1cmask);
qemu_free(pci_dev->used);
}
@@ -997,7 +999,10 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) {
uint8_t wmask = d->wmask[addr + i];
+ uint8_t w1cmask = d->w1cmask[addr + i];
+ assert(!(wmask & w1cmask));
d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask);
+ d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
}
if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) ||
ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) ||
diff --git a/hw/pci.h b/hw/pci.h
index 1c6075e..d8b399f 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -129,6 +129,9 @@ struct PCIDevice {
/* Used to implement R/W bytes */
uint8_t *wmask;
+ /* Used to implement RW1C(Write 1 to Clear) bytes */
+ uint8_t *w1cmask;
+
/* Used to allocate config space for capabilities. */
uint8_t *used;
commit 0bb750ef9e897ba5f4d9899ddc7e222e809bcbbd
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Thu Sep 9 11:48:57 2010 +0900
pci: improve signature of pci_register_bar().
Make type uint8_t from int because PCIIORegion::type is uint8_t.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
diff --git a/hw/pci.c b/hw/pci.c
index 8f48d9b..97a7b23 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -758,7 +758,7 @@ static int pci_unregister_device(DeviceState *dev)
}
void pci_register_bar(PCIDevice *pci_dev, int region_num,
- pcibus_t size, int type,
+ pcibus_t size, uint8_t type,
PCIMapIORegionFunc *map_func)
{
PCIIORegion *r;
diff --git a/hw/pci.h b/hw/pci.h
index 2b4c318..1c6075e 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -180,7 +180,7 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
PCIConfigWriteFunc *config_write);
void pci_register_bar(PCIDevice *pci_dev, int region_num,
- pcibus_t size, int type,
+ pcibus_t size, uint8_t type,
PCIMapIORegionFunc *map_func);
int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
commit 2bbb9c2f7f36d0457cda5f27d7e4422219b3acd8
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Thu Sep 9 11:48:56 2010 +0900
pci: don't ignore invalid parameter for pci_register_bar().
Abort when invalid value for region_num is passed to pci_register_bar.
That is caller's bug. Abort instead of silently ignoring invalid value.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index c28b8a1..8f48d9b 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -765,9 +765,8 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
uint32_t addr;
uint64_t wmask;
- if ((unsigned int)region_num >= PCI_NUM_REGIONS)
- return;
-
+ assert(region_num >= 0);
+ assert(region_num < PCI_NUM_REGIONS);
if (size & (size-1)) {
fprintf(stderr, "ERROR: PCI region size must be pow2 "
"type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size);
commit 5a9ff3819a1023b63b94ad4fb82da973f93f65d0
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Thu Sep 9 11:48:55 2010 +0900
pci: sorting out type confusion in pci_register_bar().
This patch sorts out invalid use of pcibus_t.
In pci_register_bar(), pcibus_t wmask is used. It should,
however, be uint64_t because it is used to set
pci configuration space value(PCIDevice::wmask)
by pci_set_quad() or pci_set_long().
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index f03b83e..c28b8a1 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -763,7 +763,7 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
{
PCIIORegion *r;
uint32_t addr;
- pcibus_t wmask;
+ uint64_t wmask;
if ((unsigned int)region_num >= PCI_NUM_REGIONS)
return;
commit cf4c01fde264416dc8b1a1904bc9068a4af78cb7
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Mon Sep 6 16:46:20 2010 +0900
pci_ids.h: add vendor id of Texas Intesruments
add vendor id of Texas Intesruments.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index 39e9f1d..82cba7e 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -57,6 +57,8 @@
#define PCI_VENDOR_ID_AMD 0x1022
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
+#define PCI_VENDOR_ID_TI 0x104c
+
#define PCI_VENDOR_ID_MOTOROLA 0x1057
#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002
#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801
commit 43c945f16a172f07145ca1f30abb958070228690
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Mon Sep 6 16:46:19 2010 +0900
pci: make pci_parse_devfn() aware of func.
make pci_parse_devfn() aware of func. With func = NULL it behave as before.
This will be used later.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index bb9ddea..f03b83e 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -424,15 +424,18 @@ static void pci_set_default_subsystem_id(PCIDevice *pci_dev)
}
/*
- * Parse [[<domain>:]<bus>:]<slot>, return -1 on error
+ * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL
+ * [[<domain>:]<bus>:]<slot>.<func>, return -1 on error
*/
-static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)
+int pci_parse_devaddr(const char *addr, int *domp, int *busp,
+ unsigned int *slotp, unsigned int *funcp)
{
const char *p;
char *e;
unsigned long val;
unsigned long dom = 0, bus = 0;
- unsigned slot = 0;
+ unsigned int slot = 0;
+ unsigned int func = 0;
p = addr;
val = strtoul(p, &e, 16);
@@ -454,11 +457,24 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *s
}
}
- if (dom > 0xffff || bus > 0xff || val > 0x1f)
- return -1;
-
slot = val;
+ if (funcp != NULL) {
+ if (*e != '.')
+ return -1;
+
+ p = e + 1;
+ val = strtoul(p, &e, 16);
+ if (e == p)
+ return -1;
+
+ func = val;
+ }
+
+ /* if funcp == NULL func is 0 */
+ if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7)
+ return -1;
+
if (*e)
return -1;
@@ -469,6 +485,8 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *s
*domp = dom;
*busp = bus;
*slotp = slot;
+ if (funcp != NULL)
+ *funcp = func;
return 0;
}
@@ -479,7 +497,7 @@ int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
if (!strncmp(addr, "pci_addr=", 9)) {
addr += 9;
}
- if (pci_parse_devaddr(addr, domp, busp, slotp)) {
+ if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) {
monitor_printf(mon, "Invalid pci address\n");
return -1;
}
@@ -496,7 +514,7 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr)
return pci_find_bus(pci_find_root_bus(0), 0);
}
- if (pci_parse_devaddr(devaddr, &dom, &bus, &slot) < 0) {
+ if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) {
return NULL;
}
diff --git a/hw/pci.h b/hw/pci.h
index 2ddba59..2b4c318 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -227,6 +227,8 @@ PCIBus *pci_find_bus(PCIBus *bus, int bus_num);
PCIDevice *pci_find_device(PCIBus *bus, int bus_num, int slot, int function);
PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
+int pci_parse_devaddr(const char *addr, int *domp, int *busp,
+ unsigned int *slotp, unsigned int *funcp);
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
unsigned *slotp);
commit 5beb8ad503c88a76f2b8106c3b74b4ce485a60e1
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Mon Sep 6 16:46:18 2010 +0900
pci: call hotplug callback even when not hotplug case for later use.
call hotplug callback even when not hotplug case for later use.
And move hotplug check into hotplug callback.
PCIE slot needs this for card presence detection.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index bfa1d9a..24dfcf2 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -611,6 +611,9 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state)
PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev,
DO_UPCAST(PCIDevice, qdev, qdev));
+ if (!dev->qdev.hotplugged)
+ return 0;
+
s->pci0_status.up = 0;
s->pci0_status.down = 0;
if (state) {
diff --git a/hw/pci.c b/hw/pci.c
index 754ffb3..bb9ddea 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1514,7 +1514,8 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
pci_dev->romfile = qemu_strdup(info->romfile);
pci_add_option_rom(pci_dev);
- if (qdev->hotplugged) {
+ if (bus->hotplug) {
+ /* lower layer must check qdev->hotplugged */
rc = bus->hotplug(bus->hotplug_qdev, pci_dev, 1);
if (rc != 0) {
int r = pci_unregister_device(&pci_dev->qdev);
commit f4c817e000e50e9a0db8f95ce6496628bd70733d
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Mon Sep 6 16:46:17 2010 +0900
pci bridge: add helper function for ssvid capability.
helper function to add ssvid capability.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 198c3c7..638e3b3 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -32,6 +32,25 @@
#include "pci_bridge.h"
#include "pci_internals.h"
+/* PCI bridge subsystem vendor ID helper functions */
+#define PCI_SSVID_SIZEOF 8
+#define PCI_SSVID_SVID 4
+#define PCI_SSVID_SSID 6
+
+int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
+ uint16_t svid, uint16_t ssid)
+{
+ int pos;
+ pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SSVID_SIZEOF);
+ if (pos < 0) {
+ return pos;
+ }
+
+ pci_set_word(dev->config + pos + PCI_SSVID_SVID, svid);
+ pci_set_word(dev->config + pos + PCI_SSVID_SSID, ssid);
+ return pos;
+}
+
/* Accessor function to get parent bridge device from pci bus. */
PCIDevice *pci_bridge_get_device(PCIBus *bus)
{
diff --git a/hw/pci_bridge.h b/hw/pci_bridge.h
index 63ada19..f6fade0 100644
--- a/hw/pci_bridge.h
+++ b/hw/pci_bridge.h
@@ -28,6 +28,9 @@
#include "pci.h"
+int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
+ uint16_t svid, uint16_t ssid);
+
PCIDevice *pci_bridge_get_device(PCIBus *bus);
PCIBus *pci_bridge_get_sec_bus(PCIBridge *br);
commit ca77089d2d8e73283bfc73f03d954504561e1ce8
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Mon Sep 6 16:46:16 2010 +0900
pci: consolidate pci_add_capability_at_offset() into pci_add_capability().
By making pci_add_capability() the special case of
pci_add_capability_at_offset() of offset = 0,
consolidate pci_add_capability_at_offset() into pci_add_capability().
Cc: Stefan Weil <weil at mail.berlios.de>
Cc: Michael S. Tsirkin <mst at redhat.com>
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 2b75c8f..8cbc3aa 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -539,8 +539,8 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
if (e100_device->power_management) {
/* Power Management Capabilities */
int cfg_offset = 0xdc;
- int r = pci_add_capability_at_offset(&s->dev, PCI_CAP_ID_PM,
- cfg_offset, PCI_PM_SIZEOF);
+ int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM,
+ cfg_offset, PCI_PM_SIZEOF);
assert(r >= 0);
pci_set_word(pci_conf + cfg_offset + PCI_PM_PMC, 0x7e21);
#if 0 /* TODO: replace dummy code for power management emulation. */
diff --git a/hw/msix.c b/hw/msix.c
index d99403a..7ce63eb 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -73,7 +73,8 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries,
}
pdev->msix_bar_size = new_size;
- config_offset = pci_add_capability(pdev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH);
+ config_offset = pci_add_capability(pdev, PCI_CAP_ID_MSIX,
+ 0, MSIX_CAP_LENGTH);
if (config_offset < 0)
return config_offset;
config = pdev->config + config_offset;
diff --git a/hw/pci.c b/hw/pci.c
index 2dc1577..754ffb3 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1682,11 +1682,25 @@ static void pci_del_option_rom(PCIDevice *pdev)
pdev->rom_offset = 0;
}
-/* Reserve space and add capability to the linked list in pci config space */
-int pci_add_capability_at_offset(PCIDevice *pdev, uint8_t cap_id,
- uint8_t offset, uint8_t size)
+/*
+ * if !offset
+ * Reserve space and add capability to the linked list in pci config space
+ *
+ * if offset = 0,
+ * Find and reserve space and add capability to the linked list
+ * in pci config space */
+int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
+ uint8_t offset, uint8_t size)
{
- uint8_t *config = pdev->config + offset;
+ uint8_t *config;
+ if (!offset) {
+ offset = pci_find_space(pdev, size);
+ if (!offset) {
+ return -ENOSPC;
+ }
+ }
+
+ config = pdev->config + offset;
config[PCI_CAP_LIST_ID] = cap_id;
config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
pdev->config[PCI_CAPABILITY_LIST] = offset;
@@ -1699,17 +1713,6 @@ int pci_add_capability_at_offset(PCIDevice *pdev, uint8_t cap_id,
return offset;
}
-/* Find and reserve space and add capability to the linked list
- * in pci config space */
-int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
-{
- uint8_t offset = pci_find_space(pdev, size);
- if (!offset) {
- return -ENOSPC;
- }
- return pci_add_capability_at_offset(pdev, cap_id, offset, size);
-}
-
/* Unlink capability from the pci config space. */
void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
{
diff --git a/hw/pci.h b/hw/pci.h
index c551f96..2ddba59 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -183,9 +183,8 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
pcibus_t size, int type,
PCIMapIORegionFunc *map_func);
-int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
-int pci_add_capability_at_offset(PCIDevice *pci_dev, uint8_t cap_id,
- uint8_t cap_offset, uint8_t cap_size);
+int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
+ uint8_t offset, uint8_t size);
void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
commit 68f799944b72387c0ef9535612a212a5ea492059
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Tue Jul 13 13:01:42 2010 +0900
pci_bridge: introduce pci bridge library.
introduce pci bridge library.
convert apb bridge and dec p2p bridge to use new pci bridge library.
save/restore is supported as a side effect.
This is also preparation for pci express root/upstream/downstream port.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index 88ee4a9..c619112 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -30,6 +30,7 @@
#include "pci.h"
#include "pci_host.h"
#include "pci_bridge.h"
+#include "pci_internals.h"
#include "rwhandler.h"
#include "apb_pci.h"
#include "sysemu.h"
@@ -294,9 +295,17 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level)
}
}
-static void apb_pci_bridge_init(PCIBus *b)
+static int apb_pci_bridge_initfn(PCIDevice *dev)
{
- PCIDevice *dev = pci_bridge_get_device(b);
+ int rc;
+
+ rc = pci_bridge_initfn(dev);
+ if (rc < 0) {
+ return rc;
+ }
+
+ pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_SUN);
+ pci_config_set_device_id(dev->config, PCI_DEVICE_ID_SUN_SIMBA);
/*
* command register:
@@ -313,6 +322,7 @@ static void apb_pci_bridge_init(PCIBus *b)
PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
PCI_STATUS_DEVSEL_MEDIUM);
pci_set_byte(dev->config + PCI_REVISION_ID, 0x11);
+ return 0;
}
PCIBus *pci_apb_init(target_phys_addr_t special_base,
@@ -323,6 +333,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
SysBusDevice *s;
APBState *d;
unsigned int i;
+ PCIDevice *pci_dev;
+ PCIBridge *br;
/* Ultrasparc PBM main bus */
dev = qdev_create(NULL, "pbm");
@@ -348,17 +360,21 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
pci_create_simple(d->bus, 0, "pbm");
/* APB secondary busses */
- *bus2 = pci_bridge_init(d->bus, PCI_DEVFN(1, 0), true,
- PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
- pci_apb_map_irq,
- "Advanced PCI Bus secondary bridge 1");
- apb_pci_bridge_init(*bus2);
-
- *bus3 = pci_bridge_init(d->bus, PCI_DEVFN(1, 1), true,
- PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
- pci_apb_map_irq,
- "Advanced PCI Bus secondary bridge 2");
- apb_pci_bridge_init(*bus3);
+ pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true,
+ "pbm-bridge");
+ br = DO_UPCAST(PCIBridge, dev, pci_dev);
+ pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1",
+ pci_apb_map_irq);
+ qdev_init_nofail(&pci_dev->qdev);
+ *bus2 = pci_bridge_get_sec_bus(br);
+
+ pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 1), true,
+ "pbm-bridge");
+ br = DO_UPCAST(PCIBridge, dev, pci_dev);
+ pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2",
+ pci_apb_map_irq);
+ qdev_init_nofail(&pci_dev->qdev);
+ *bus3 = pci_bridge_get_sec_bus(br);
return d->bus;
}
@@ -441,10 +457,23 @@ static SysBusDeviceInfo pbm_host_info = {
.qdev.reset = pci_pbm_reset,
.init = pci_pbm_init_device,
};
+
+static PCIDeviceInfo pbm_pci_bridge_info = {
+ .qdev.name = "pbm-bridge",
+ .qdev.size = sizeof(PCIBridge),
+ .qdev.vmsd = &vmstate_pci_device,
+ .qdev.reset = pci_bridge_reset,
+ .init = apb_pci_bridge_initfn,
+ .exit = pci_bridge_exitfn,
+ .config_write = pci_bridge_write_config,
+ .is_bridge = 1,
+};
+
static void pbm_register_devices(void)
{
sysbus_register_withprop(&pbm_host_info);
pci_qdev_register(&pbm_pci_host_info);
+ pci_qdev_register(&pbm_pci_bridge_info);
}
device_init(pbm_register_devices)
diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index f7a9cdc..aa07ab7 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -28,6 +28,7 @@
#include "pci.h"
#include "pci_host.h"
#include "pci_bridge.h"
+#include "pci_internals.h"
/* debug DEC */
//#define DEBUG_DEC
@@ -49,18 +50,43 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
return irq_num;
}
-PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
+static int dec_21154_initfn(PCIDevice *dev)
{
- DeviceState *dev;
- PCIBus *ret;
+ int rc;
+
+ rc = pci_bridge_initfn(dev);
+ if (rc < 0) {
+ return rc;
+ }
+
+ pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_DEC);
+ pci_config_set_device_id(dev->config, PCI_DEVICE_ID_DEC_21154);
+ return 0;
+}
- dev = qdev_create(NULL, "dec-21154");
- qdev_init_nofail(dev);
- ret = pci_bridge_init(parent_bus, devfn, false,
- PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21154,
- dec_map_irq, "DEC 21154 PCI-PCI bridge");
+static PCIDeviceInfo dec_21154_pci_bridge_info = {
+ .qdev.name = "dec-21154-p2p-bridge",
+ .qdev.desc = "DEC 21154 PCI-PCI bridge",
+ .qdev.size = sizeof(PCIBridge),
+ .qdev.vmsd = &vmstate_pci_device,
+ .qdev.reset = pci_bridge_reset,
+ .init = dec_21154_initfn,
+ .exit = pci_bridge_exitfn,
+ .config_write = pci_bridge_write_config,
+ .is_bridge = 1,
+};
+
+PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
+{
+ PCIDevice *dev;
+ PCIBridge *br;
- return ret;
+ dev = pci_create_multifunction(parent_bus, devfn, false,
+ "dec-21154-p2p-bridge");
+ br = DO_UPCAST(PCIBridge, dev, dev);
+ pci_bridge_map_irq(br, "DEC 21154 PCI-PCI bridge", dec_map_irq);
+ qdev_init_nofail(&dev->qdev);
+ return pci_bridge_get_sec_bus(br);
}
static int pci_dec_21154_init_device(SysBusDevice *dev)
@@ -99,6 +125,7 @@ static void dec_register_devices(void)
sysbus_register_dev("dec-21154", sizeof(DECState),
pci_dec_21154_init_device);
pci_qdev_register(&dec_21154_pci_host_info);
+ pci_qdev_register(&dec_21154_pci_bridge_info);
}
device_init(dec_register_devices)
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 2f13c7d..198c3c7 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -32,12 +32,19 @@
#include "pci_bridge.h"
#include "pci_internals.h"
+/* Accessor function to get parent bridge device from pci bus. */
PCIDevice *pci_bridge_get_device(PCIBus *bus)
{
return bus->parent_dev;
}
-static uint32_t pci_config_get_io_base(PCIDevice *d,
+/* Accessor function to get secondary bus from pci-to-pci bridge device */
+PCIBus *pci_bridge_get_sec_bus(PCIBridge *br)
+{
+ return &br->sec_bus;
+}
+
+static uint32_t pci_config_get_io_base(const PCIDevice *d,
uint32_t base, uint32_t base_upper16)
{
uint32_t val;
@@ -49,13 +56,13 @@ static uint32_t pci_config_get_io_base(PCIDevice *d,
return val;
}
-static pcibus_t pci_config_get_memory_base(PCIDevice *d, uint32_t base)
+static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base)
{
return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)
<< 16;
}
-static pcibus_t pci_config_get_pref_base(PCIDevice *d,
+static pcibus_t pci_config_get_pref_base(const PCIDevice *d,
uint32_t base, uint32_t upper)
{
pcibus_t tmp;
@@ -69,7 +76,8 @@ static pcibus_t pci_config_get_pref_base(PCIDevice *d,
return val;
}
-pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type)
+/* accessor function to get bridge filtering base address */
+pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type)
{
pcibus_t base;
if (type & PCI_BASE_ADDRESS_SPACE_IO) {
@@ -87,7 +95,8 @@ pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type)
return base;
}
-pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type)
+/* accessor funciton to get bridge filtering limit */
+pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type)
{
pcibus_t limit;
if (type & PCI_BASE_ADDRESS_SPACE_IO) {
@@ -106,7 +115,8 @@ pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type)
return limit;
}
-static void pci_bridge_write_config(PCIDevice *d,
+/* default write_config function for PCI-to-PCI bridge */
+void pci_bridge_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len)
{
pci_default_write_config(d, address, val, len);
@@ -122,12 +132,41 @@ static void pci_bridge_write_config(PCIDevice *d,
}
}
-static int pci_bridge_initfn(PCIDevice *dev)
+/* reset bridge specific configuration registers */
+void pci_bridge_reset_reg(PCIDevice *dev)
+{
+ uint8_t *conf = dev->config;
+
+ conf[PCI_PRIMARY_BUS] = 0;
+ conf[PCI_SECONDARY_BUS] = 0;
+ conf[PCI_SUBORDINATE_BUS] = 0;
+ conf[PCI_SEC_LATENCY_TIMER] = 0;
+
+ conf[PCI_IO_BASE] = 0;
+ conf[PCI_IO_LIMIT] = 0;
+ pci_set_word(conf + PCI_MEMORY_BASE, 0);
+ pci_set_word(conf + PCI_MEMORY_LIMIT, 0);
+ pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0);
+ pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0);
+ pci_set_word(conf + PCI_PREF_BASE_UPPER32, 0);
+ pci_set_word(conf + PCI_PREF_LIMIT_UPPER32, 0);
+
+ pci_set_word(conf + PCI_BRIDGE_CONTROL, 0);
+}
+
+/* default reset function for PCI-to-PCI bridge */
+void pci_bridge_reset(DeviceState *qdev)
{
- PCIBridge *s = DO_UPCAST(PCIBridge, dev, dev);
+ PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+ pci_bridge_reset_reg(dev);
+}
- pci_config_set_vendor_id(s->dev.config, s->vid);
- pci_config_set_device_id(s->dev.config, s->did);
+/* default qdev initialization function for PCI-to-PCI bridge */
+int pci_bridge_initfn(PCIDevice *dev)
+{
+ PCIBus *parent = dev->bus;
+ PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
+ PCIBus *sec_bus = &br->sec_bus;
pci_set_word(dev->config + PCI_STATUS,
PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
@@ -137,58 +176,35 @@ static int pci_bridge_initfn(PCIDevice *dev)
PCI_HEADER_TYPE_BRIDGE;
pci_set_word(dev->config + PCI_SEC_STATUS,
PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
+
+ qbus_create_inplace(&sec_bus->qbus, &pci_bus_info, &dev->qdev,
+ br->bus_name);
+ sec_bus->parent_dev = dev;
+ sec_bus->map_irq = br->map_irq;
+
+ QLIST_INIT(&sec_bus->child);
+ QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
return 0;
}
-static int pci_bridge_exitfn(PCIDevice *pci_dev)
+/* default qdev clean up function for PCI-to-PCI bridge */
+int pci_bridge_exitfn(PCIDevice *pci_dev)
{
PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
assert(QLIST_EMPTY(&s->sec_bus.child));
QLIST_REMOVE(&s->sec_bus, sibling);
+ /* qbus_free() is called automatically by qdev_free() */
return 0;
}
-PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,
- uint16_t vid, uint16_t did,
- pci_map_irq_fn map_irq, const char *name)
-{
- PCIDevice *dev;
- PCIBridge *s;
- PCIBus *sec_bus;
-
- dev = pci_create_multifunction(bus, devfn, multifunction, "pci-bridge");
- qdev_prop_set_uint32(&dev->qdev, "vendorid", vid);
- qdev_prop_set_uint32(&dev->qdev, "deviceid", did);
- qdev_init_nofail(&dev->qdev);
-
- s = DO_UPCAST(PCIBridge, dev, dev);
- sec_bus = &s->sec_bus;
- qbus_create_inplace(&sec_bus->qbus, &pci_bus_info, &dev->qdev, name);
- sec_bus->parent_dev = dev;
- sec_bus->map_irq = map_irq;
-
- QLIST_INIT(&sec_bus->child);
- QLIST_INSERT_HEAD(&bus->child, sec_bus, sibling);
- return &s->sec_bus;
-}
-
-static PCIDeviceInfo bridge_info = {
- .qdev.name = "pci-bridge",
- .qdev.size = sizeof(PCIBridge),
- .init = pci_bridge_initfn,
- .exit = pci_bridge_exitfn,
- .config_write = pci_bridge_write_config,
- .is_bridge = 1,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("vendorid", PCIBridge, vid, 0),
- DEFINE_PROP_HEX32("deviceid", PCIBridge, did, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
-static void pci_register_devices(void)
+/*
+ * before qdev initialization(qdev_init()), this function sets bus_name and
+ * map_irq callback which are necessry for pci_bridge_initfn() to
+ * initialize bus.
+ */
+void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
+ pci_map_irq_fn map_irq)
{
- pci_qdev_register(&bridge_info);
+ br->map_irq = map_irq;
+ br->bus_name = bus_name;
}
-
-device_init(pci_register_devices)
diff --git a/hw/pci_bridge.h b/hw/pci_bridge.h
index ddb2c82..63ada19 100644
--- a/hw/pci_bridge.h
+++ b/hw/pci_bridge.h
@@ -29,13 +29,27 @@
#include "pci.h"
PCIDevice *pci_bridge_get_device(PCIBus *bus);
+PCIBus *pci_bridge_get_sec_bus(PCIBridge *br);
-pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type);
-pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type);
+pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type);
+pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type);
-PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,
- uint16_t vid, uint16_t did,
- pci_map_irq_fn map_irq, const char *name);
+void pci_bridge_write_config(PCIDevice *d,
+ uint32_t address, uint32_t val, int len);
+void pci_bridge_reset_reg(PCIDevice *dev);
+void pci_bridge_reset(DeviceState *qdev);
+
+int pci_bridge_initfn(PCIDevice *pci_dev);
+int pci_bridge_exitfn(PCIDevice *pci_dev);
+
+
+/*
+ * before qdev initialization(qdev_init()), this function sets bus_name and
+ * map_irq callback which are necessry for pci_bridge_initfn() to
+ * initialize bus.
+ */
+void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
+ pci_map_irq_fn map_irq);
#endif /* QEMU_PCI_BRIDGE_H */
/*
diff --git a/hw/pci_internals.h b/hw/pci_internals.h
index fa844ab..e3c93a3 100644
--- a/hw/pci_internals.h
+++ b/hw/pci_internals.h
@@ -5,6 +5,11 @@
* This header files is private to pci.c and pci_bridge.c
* So following structures are opaque to others and shouldn't be
* accessed.
+ *
+ * For pci-to-pci bridge needs to include this header file to embed
+ * PCIBridge in its structure or to get sizeof(PCIBridge),
+ * However, they shouldn't access those following members directly.
+ * Use accessor function in pci.h, pci_bridge.h
*/
extern struct BusInfo pci_bus_info;
@@ -30,11 +35,13 @@ struct PCIBus {
int *irq_count;
};
-typedef struct {
+struct PCIBridge {
PCIDevice dev;
+
+ /* private member */
PCIBus sec_bus;
- uint32_t vid;
- uint32_t did;
-} PCIBridge;
+ pci_map_irq_fn map_irq;
+ const char *bus_name;
+};
#endif /* QEMU_PCI_INTERNALS_H */
diff --git a/qemu-common.h b/qemu-common.h
index 3fb2f0b..d735235 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -219,6 +219,7 @@ typedef struct PCIHostState PCIHostState;
typedef struct PCIExpressHost PCIExpressHost;
typedef struct PCIBus PCIBus;
typedef struct PCIDevice PCIDevice;
+typedef struct PCIBridge PCIBridge;
typedef struct SerialState SerialState;
typedef struct IRQState *qemu_irq;
typedef struct PCMCIACardState PCMCIACardState;
commit 51a92333f8eb6d0fe685544f20ad56fc9af702f5
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Tue Jul 13 13:01:41 2010 +0900
pci_bridge: clean up: remove pci_{register, unregister}_secondary_bus()
Remove pci_{register, unregister}_secondary_bus() by open code.
They are old stype API and aren't used any more by others. So eliminate it.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 63052fe..2f13c7d 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -37,26 +37,6 @@ PCIDevice *pci_bridge_get_device(PCIBus *bus)
return bus->parent_dev;
}
-static void pci_register_secondary_bus(PCIBus *parent,
- PCIBus *bus,
- PCIDevice *dev,
- pci_map_irq_fn map_irq,
- const char *name)
-{
- qbus_create_inplace(&bus->qbus, &pci_bus_info, &dev->qdev, name);
- bus->map_irq = map_irq;
- bus->parent_dev = dev;
-
- QLIST_INIT(&bus->child);
- QLIST_INSERT_HEAD(&parent->child, bus, sibling);
-}
-
-static void pci_unregister_secondary_bus(PCIBus *bus)
-{
- assert(QLIST_EMPTY(&bus->child));
- QLIST_REMOVE(bus, sibling);
-}
-
static uint32_t pci_config_get_io_base(PCIDevice *d,
uint32_t base, uint32_t base_upper16)
{
@@ -163,7 +143,8 @@ static int pci_bridge_initfn(PCIDevice *dev)
static int pci_bridge_exitfn(PCIDevice *pci_dev)
{
PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
- pci_unregister_secondary_bus(&s->sec_bus);
+ assert(QLIST_EMPTY(&s->sec_bus.child));
+ QLIST_REMOVE(&s->sec_bus, sibling);
return 0;
}
@@ -173,6 +154,7 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,
{
PCIDevice *dev;
PCIBridge *s;
+ PCIBus *sec_bus;
dev = pci_create_multifunction(bus, devfn, multifunction, "pci-bridge");
qdev_prop_set_uint32(&dev->qdev, "vendorid", vid);
@@ -180,7 +162,13 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,
qdev_init_nofail(&dev->qdev);
s = DO_UPCAST(PCIBridge, dev, dev);
- pci_register_secondary_bus(bus, &s->sec_bus, &s->dev, map_irq, name);
+ sec_bus = &s->sec_bus;
+ qbus_create_inplace(&sec_bus->qbus, &pci_bus_info, &dev->qdev, name);
+ sec_bus->parent_dev = dev;
+ sec_bus->map_irq = map_irq;
+
+ QLIST_INIT(&sec_bus->child);
+ QLIST_INSERT_HEAD(&bus->child, sec_bus, sibling);
return &s->sec_bus;
}
commit 7e98e3af4e7454d53707b7b4d16b6e9bd5c21334
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Tue Jul 13 13:01:40 2010 +0900
pci_bridge: rename PCIBridge::bus -> PCIBridge::sec_bus.
To avoid confusion of primary bus with secondary bus,
rename PCIBridge::bus to PCIBridge::sec_bus.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 7f27870..63052fe 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -138,8 +138,7 @@ static void pci_bridge_write_config(PCIDevice *d,
io base/limit upper 16 */
ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
PCIBridge *s = container_of(d, PCIBridge, dev);
- PCIBus *secondary_bus = &s->bus;
- pci_bridge_update_mappings(secondary_bus);
+ pci_bridge_update_mappings(&s->sec_bus);
}
}
@@ -164,8 +163,7 @@ static int pci_bridge_initfn(PCIDevice *dev)
static int pci_bridge_exitfn(PCIDevice *pci_dev)
{
PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
- PCIBus *bus = &s->bus;
- pci_unregister_secondary_bus(bus);
+ pci_unregister_secondary_bus(&s->sec_bus);
return 0;
}
@@ -182,8 +180,8 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,
qdev_init_nofail(&dev->qdev);
s = DO_UPCAST(PCIBridge, dev, dev);
- pci_register_secondary_bus(bus, &s->bus, &s->dev, map_irq, name);
- return &s->bus;
+ pci_register_secondary_bus(bus, &s->sec_bus, &s->dev, map_irq, name);
+ return &s->sec_bus;
}
static PCIDeviceInfo bridge_info = {
diff --git a/hw/pci_internals.h b/hw/pci_internals.h
index 8a3026b..fa844ab 100644
--- a/hw/pci_internals.h
+++ b/hw/pci_internals.h
@@ -32,7 +32,7 @@ struct PCIBus {
typedef struct {
PCIDevice dev;
- PCIBus bus;
+ PCIBus sec_bus;
uint32_t vid;
uint32_t did;
} PCIBridge;
commit 783753fd53fe513d37fbbfe6694c0c1ab9701fd1
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Tue Jul 13 13:01:39 2010 +0900
pci/bridge: split out pci bridge code into pci_bridge.c from pci.c
Move pci bridge related code into pci_bridge.c from pci.c
for further enhancement. pci.c is big enough now, so split it out.
No code change but exporting some accesser functions.
In fact, few pci bridge functions stays in pci.c.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/Makefile.objs b/Makefile.objs
index 67f1b21..594894b 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -139,7 +139,7 @@ user-obj-y += cutils.o cache-utils.o
hw-obj-y =
hw-obj-y += vl.o loader.o
hw-obj-y += virtio.o virtio-console.o
-hw-obj-y += fw_cfg.o pci.o pci_host.o pcie_host.o
+hw-obj-y += fw_cfg.o pci.o pci_host.o pcie_host.o pci_bridge.o
hw-obj-y += watchdog.o
hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
hw-obj-$(CONFIG_ECC) += ecc.o
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index 0ecac55..88ee4a9 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -29,6 +29,7 @@
#include "sysbus.h"
#include "pci.h"
#include "pci_host.h"
+#include "pci_bridge.h"
#include "rwhandler.h"
#include "apb_pci.h"
#include "sysemu.h"
diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index ee49d5a..f7a9cdc 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -27,6 +27,7 @@
#include "sysbus.h"
#include "pci.h"
#include "pci_host.h"
+#include "pci_bridge.h"
/* debug DEC */
//#define DEBUG_DEC
diff --git a/hw/pci.c b/hw/pci.c
index 9c83d74..2dc1577 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -23,6 +23,7 @@
*/
#include "hw.h"
#include "pci.h"
+#include "pci_bridge.h"
#include "pci_internals.h"
#include "monitor.h"
#include "net.h"
@@ -272,26 +273,6 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
return bus;
}
-static void pci_register_secondary_bus(PCIBus *parent,
- PCIBus *bus,
- PCIDevice *dev,
- pci_map_irq_fn map_irq,
- const char *name)
-{
- qbus_create_inplace(&bus->qbus, &pci_bus_info, &dev->qdev, name);
- bus->map_irq = map_irq;
- bus->parent_dev = dev;
-
- QLIST_INIT(&bus->child);
- QLIST_INSERT_HEAD(&parent->child, bus, sibling);
-}
-
-static void pci_unregister_secondary_bus(PCIBus *bus)
-{
- assert(QLIST_EMPTY(&bus->child));
- QLIST_REMOVE(bus, sibling);
-}
-
int pci_bus_num(PCIBus *s)
{
if (!s->parent_dev)
@@ -799,75 +780,6 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
}
}
-static uint32_t pci_config_get_io_base(PCIDevice *d,
- uint32_t base, uint32_t base_upper16)
-{
- uint32_t val;
-
- val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8;
- if (d->config[base] & PCI_IO_RANGE_TYPE_32) {
- val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16;
- }
- return val;
-}
-
-static pcibus_t pci_config_get_memory_base(PCIDevice *d, uint32_t base)
-{
- return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)
- << 16;
-}
-
-static pcibus_t pci_config_get_pref_base(PCIDevice *d,
- uint32_t base, uint32_t upper)
-{
- pcibus_t tmp;
- pcibus_t val;
-
- tmp = (pcibus_t)pci_get_word(d->config + base);
- val = (tmp & PCI_PREF_RANGE_MASK) << 16;
- if (tmp & PCI_PREF_RANGE_TYPE_64) {
- val |= (pcibus_t)pci_get_long(d->config + upper) << 32;
- }
- return val;
-}
-
-static pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type)
-{
- pcibus_t base;
- if (type & PCI_BASE_ADDRESS_SPACE_IO) {
- base = pci_config_get_io_base(bridge,
- PCI_IO_BASE, PCI_IO_BASE_UPPER16);
- } else {
- if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
- base = pci_config_get_pref_base(
- bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32);
- } else {
- base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE);
- }
- }
-
- return base;
-}
-
-static pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type)
-{
- pcibus_t limit;
- if (type & PCI_BASE_ADDRESS_SPACE_IO) {
- limit = pci_config_get_io_base(bridge,
- PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16);
- limit |= 0xfff; /* PCI bridge spec 3.2.5.6. */
- } else {
- if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
- limit = pci_config_get_pref_base(
- bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32);
- } else {
- limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT);
- }
- limit |= 0xfffff; /* PCI bridge spec 3.2.5.{1, 8}. */
- }
- return limit;
-}
-
static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size,
uint8_t type)
{
@@ -1518,7 +1430,7 @@ static void pci_bridge_update_mappings_fn(PCIBus *b, PCIDevice *d)
pci_update_mappings(d);
}
-static void pci_bridge_update_mappings(PCIBus *b)
+void pci_bridge_update_mappings(PCIBus *b)
{
PCIBus *child;
@@ -1529,23 +1441,6 @@ static void pci_bridge_update_mappings(PCIBus *b)
}
}
-static void pci_bridge_write_config(PCIDevice *d,
- uint32_t address, uint32_t val, int len)
-{
- pci_default_write_config(d, address, val, len);
-
- if (/* io base/limit */
- ranges_overlap(address, len, PCI_IO_BASE, 2) ||
-
- /* memory base/limit, prefetchable base/limit and
- io base/limit upper 16 */
- ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
- PCIBridge *s = container_of(d, PCIBridge, dev);
- PCIBus *secondary_bus = &s->bus;
- pci_bridge_update_mappings(secondary_bus);
- }
-}
-
PCIBus *pci_find_bus(PCIBus *bus, int bus_num)
{
PCIBus *sec;
@@ -1589,54 +1484,6 @@ PCIDevice *pci_find_device(PCIBus *bus, int bus_num, int slot, int function)
return bus->devices[PCI_DEVFN(slot, function)];
}
-static int pci_bridge_initfn(PCIDevice *dev)
-{
- PCIBridge *s = DO_UPCAST(PCIBridge, dev, dev);
-
- pci_config_set_vendor_id(s->dev.config, s->vid);
- pci_config_set_device_id(s->dev.config, s->did);
-
- pci_set_word(dev->config + PCI_STATUS,
- PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
- pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
- dev->config[PCI_HEADER_TYPE] =
- (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
- PCI_HEADER_TYPE_BRIDGE;
- pci_set_word(dev->config + PCI_SEC_STATUS,
- PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
- return 0;
-}
-
-static int pci_bridge_exitfn(PCIDevice *pci_dev)
-{
- PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
- PCIBus *bus = &s->bus;
- pci_unregister_secondary_bus(bus);
- return 0;
-}
-
-PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,
- uint16_t vid, uint16_t did,
- pci_map_irq_fn map_irq, const char *name)
-{
- PCIDevice *dev;
- PCIBridge *s;
-
- dev = pci_create_multifunction(bus, devfn, multifunction, "pci-bridge");
- qdev_prop_set_uint32(&dev->qdev, "vendorid", vid);
- qdev_prop_set_uint32(&dev->qdev, "deviceid", did);
- qdev_init_nofail(&dev->qdev);
-
- s = DO_UPCAST(PCIBridge, dev, dev);
- pci_register_secondary_bus(bus, &s->bus, &s->dev, map_irq, name);
- return &s->bus;
-}
-
-PCIDevice *pci_bridge_get_device(PCIBus *bus)
-{
- return bus->parent_dev;
-}
-
static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
{
PCIDevice *pci_dev = (PCIDevice *)qdev;
@@ -1942,23 +1789,3 @@ static char *pcibus_get_dev_path(DeviceState *dev)
return strdup(path);
}
-static PCIDeviceInfo bridge_info = {
- .qdev.name = "pci-bridge",
- .qdev.size = sizeof(PCIBridge),
- .init = pci_bridge_initfn,
- .exit = pci_bridge_exitfn,
- .config_write = pci_bridge_write_config,
- .is_bridge = 1,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("vendorid", PCIBridge, vid, 0),
- DEFINE_PROP_HEX32("deviceid", PCIBridge, did, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
-static void pci_register_devices(void)
-{
- pci_qdev_register(&bridge_info);
-}
-
-device_init(pci_register_devices)
diff --git a/hw/pci.h b/hw/pci.h
index 1eab7e7..c551f96 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -233,10 +233,7 @@ int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
void do_pci_info_print(Monitor *mon, const QObject *data);
void do_pci_info(Monitor *mon, QObject **ret_data);
-PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,
- uint16_t vid, uint16_t did,
- pci_map_irq_fn map_irq, const char *name);
-PCIDevice *pci_bridge_get_device(PCIBus *bus);
+void pci_bridge_update_mappings(PCIBus *b);
static inline void
pci_set_byte(uint8_t *config, uint8_t val)
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
new file mode 100644
index 0000000..7f27870
--- /dev/null
+++ b/hw/pci_bridge.c
@@ -0,0 +1,208 @@
+/*
+ * QEMU PCI bus manager
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to dea
+
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM
+
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+/*
+ * split out from pci.c
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ */
+
+#include "pci_bridge.h"
+#include "pci_internals.h"
+
+PCIDevice *pci_bridge_get_device(PCIBus *bus)
+{
+ return bus->parent_dev;
+}
+
+static void pci_register_secondary_bus(PCIBus *parent,
+ PCIBus *bus,
+ PCIDevice *dev,
+ pci_map_irq_fn map_irq,
+ const char *name)
+{
+ qbus_create_inplace(&bus->qbus, &pci_bus_info, &dev->qdev, name);
+ bus->map_irq = map_irq;
+ bus->parent_dev = dev;
+
+ QLIST_INIT(&bus->child);
+ QLIST_INSERT_HEAD(&parent->child, bus, sibling);
+}
+
+static void pci_unregister_secondary_bus(PCIBus *bus)
+{
+ assert(QLIST_EMPTY(&bus->child));
+ QLIST_REMOVE(bus, sibling);
+}
+
+static uint32_t pci_config_get_io_base(PCIDevice *d,
+ uint32_t base, uint32_t base_upper16)
+{
+ uint32_t val;
+
+ val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8;
+ if (d->config[base] & PCI_IO_RANGE_TYPE_32) {
+ val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16;
+ }
+ return val;
+}
+
+static pcibus_t pci_config_get_memory_base(PCIDevice *d, uint32_t base)
+{
+ return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)
+ << 16;
+}
+
+static pcibus_t pci_config_get_pref_base(PCIDevice *d,
+ uint32_t base, uint32_t upper)
+{
+ pcibus_t tmp;
+ pcibus_t val;
+
+ tmp = (pcibus_t)pci_get_word(d->config + base);
+ val = (tmp & PCI_PREF_RANGE_MASK) << 16;
+ if (tmp & PCI_PREF_RANGE_TYPE_64) {
+ val |= (pcibus_t)pci_get_long(d->config + upper) << 32;
+ }
+ return val;
+}
+
+pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type)
+{
+ pcibus_t base;
+ if (type & PCI_BASE_ADDRESS_SPACE_IO) {
+ base = pci_config_get_io_base(bridge,
+ PCI_IO_BASE, PCI_IO_BASE_UPPER16);
+ } else {
+ if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+ base = pci_config_get_pref_base(
+ bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32);
+ } else {
+ base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE);
+ }
+ }
+
+ return base;
+}
+
+pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type)
+{
+ pcibus_t limit;
+ if (type & PCI_BASE_ADDRESS_SPACE_IO) {
+ limit = pci_config_get_io_base(bridge,
+ PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16);
+ limit |= 0xfff; /* PCI bridge spec 3.2.5.6. */
+ } else {
+ if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+ limit = pci_config_get_pref_base(
+ bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32);
+ } else {
+ limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT);
+ }
+ limit |= 0xfffff; /* PCI bridge spec 3.2.5.{1, 8}. */
+ }
+ return limit;
+}
+
+static void pci_bridge_write_config(PCIDevice *d,
+ uint32_t address, uint32_t val, int len)
+{
+ pci_default_write_config(d, address, val, len);
+
+ if (/* io base/limit */
+ ranges_overlap(address, len, PCI_IO_BASE, 2) ||
+
+ /* memory base/limit, prefetchable base/limit and
+ io base/limit upper 16 */
+ ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
+ PCIBridge *s = container_of(d, PCIBridge, dev);
+ PCIBus *secondary_bus = &s->bus;
+ pci_bridge_update_mappings(secondary_bus);
+ }
+}
+
+static int pci_bridge_initfn(PCIDevice *dev)
+{
+ PCIBridge *s = DO_UPCAST(PCIBridge, dev, dev);
+
+ pci_config_set_vendor_id(s->dev.config, s->vid);
+ pci_config_set_device_id(s->dev.config, s->did);
+
+ pci_set_word(dev->config + PCI_STATUS,
+ PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
+ pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
+ dev->config[PCI_HEADER_TYPE] =
+ (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
+ PCI_HEADER_TYPE_BRIDGE;
+ pci_set_word(dev->config + PCI_SEC_STATUS,
+ PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
+ return 0;
+}
+
+static int pci_bridge_exitfn(PCIDevice *pci_dev)
+{
+ PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
+ PCIBus *bus = &s->bus;
+ pci_unregister_secondary_bus(bus);
+ return 0;
+}
+
+PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,
+ uint16_t vid, uint16_t did,
+ pci_map_irq_fn map_irq, const char *name)
+{
+ PCIDevice *dev;
+ PCIBridge *s;
+
+ dev = pci_create_multifunction(bus, devfn, multifunction, "pci-bridge");
+ qdev_prop_set_uint32(&dev->qdev, "vendorid", vid);
+ qdev_prop_set_uint32(&dev->qdev, "deviceid", did);
+ qdev_init_nofail(&dev->qdev);
+
+ s = DO_UPCAST(PCIBridge, dev, dev);
+ pci_register_secondary_bus(bus, &s->bus, &s->dev, map_irq, name);
+ return &s->bus;
+}
+
+static PCIDeviceInfo bridge_info = {
+ .qdev.name = "pci-bridge",
+ .qdev.size = sizeof(PCIBridge),
+ .init = pci_bridge_initfn,
+ .exit = pci_bridge_exitfn,
+ .config_write = pci_bridge_write_config,
+ .is_bridge = 1,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_HEX32("vendorid", PCIBridge, vid, 0),
+ DEFINE_PROP_HEX32("deviceid", PCIBridge, did, 0),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void pci_register_devices(void)
+{
+ pci_qdev_register(&bridge_info);
+}
+
+device_init(pci_register_devices)
diff --git a/hw/pci_bridge.h b/hw/pci_bridge.h
new file mode 100644
index 0000000..ddb2c82
--- /dev/null
+++ b/hw/pci_bridge.h
@@ -0,0 +1,48 @@
+/*
+ * QEMU PCI bridge
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc]
+ * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ */
+
+#ifndef QEMU_PCI_BRIDGE_H
+#define QEMU_PCI_BRIDGE_H
+
+#include "pci.h"
+
+PCIDevice *pci_bridge_get_device(PCIBus *bus);
+
+pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type);
+pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type);
+
+PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,
+ uint16_t vid, uint16_t did,
+ pci_map_irq_fn map_irq, const char *name);
+
+#endif /* QEMU_PCI_BRIDGE_H */
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tab-mode: nil
+ * End:
+ */
commit cfb0a50a06825a0bee349cae3fa94f96242e83a5
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date: Mon Jul 12 19:36:40 2010 +0900
pci: move out pci internal structures, PCIBus, PCIBridge, and pci_bus_info.
move out pci internal structures, PCIBus, PCIBridge and pci_bus_info into
private header file, pci_internals.h.
This is a preparation. Later pci bridge implementation will be
split out form pci.c into pci_bridge.c.
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index a98d6f3..9c83d74 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -23,6 +23,7 @@
*/
#include "hw.h"
#include "pci.h"
+#include "pci_internals.h"
#include "monitor.h"
#include "net.h"
#include "sysemu.h"
@@ -36,31 +37,10 @@
# define PCI_DPRINTF(format, ...) do { } while (0)
#endif
-struct PCIBus {
- BusState qbus;
- int devfn_min;
- pci_set_irq_fn set_irq;
- pci_map_irq_fn map_irq;
- pci_hotplug_fn hotplug;
- DeviceState *hotplug_qdev;
- void *irq_opaque;
- PCIDevice *devices[256];
- PCIDevice *parent_dev;
- target_phys_addr_t mem_base;
-
- QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */
- QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */
-
- /* The bus IRQ state is the logical OR of the connected devices.
- Keep a count of the number of devices with raised IRQs. */
- int nirq;
- int *irq_count;
-};
-
static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent);
static char *pcibus_get_dev_path(DeviceState *dev);
-static struct BusInfo pci_bus_info = {
+struct BusInfo pci_bus_info = {
.name = "PCI",
.size = sizeof(PCIBus),
.print_dev = pcibus_dev_print,
@@ -1533,14 +1513,6 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
return res;
}
-typedef struct {
- PCIDevice dev;
- PCIBus bus;
- uint32_t vid;
- uint32_t did;
-} PCIBridge;
-
-
static void pci_bridge_update_mappings_fn(PCIBus *b, PCIDevice *d)
{
pci_update_mappings(d);
diff --git a/hw/pci_internals.h b/hw/pci_internals.h
new file mode 100644
index 0000000..8a3026b
--- /dev/null
+++ b/hw/pci_internals.h
@@ -0,0 +1,40 @@
+#ifndef QEMU_PCI_INTERNALS_H
+#define QEMU_PCI_INTERNALS_H
+
+/*
+ * This header files is private to pci.c and pci_bridge.c
+ * So following structures are opaque to others and shouldn't be
+ * accessed.
+ */
+
+extern struct BusInfo pci_bus_info;
+
+struct PCIBus {
+ BusState qbus;
+ int devfn_min;
+ pci_set_irq_fn set_irq;
+ pci_map_irq_fn map_irq;
+ pci_hotplug_fn hotplug;
+ DeviceState *hotplug_qdev;
+ void *irq_opaque;
+ PCIDevice *devices[256];
+ PCIDevice *parent_dev;
+ target_phys_addr_t mem_base;
+
+ QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */
+ QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */
+
+ /* The bus IRQ state is the logical OR of the connected devices.
+ Keep a count of the number of devices with raised IRQs. */
+ int nirq;
+ int *irq_count;
+};
+
+typedef struct {
+ PCIDevice dev;
+ PCIBus bus;
+ uint32_t vid;
+ uint32_t did;
+} PCIBridge;
+
+#endif /* QEMU_PCI_INTERNALS_H */
More information about the Spice-commits
mailing list