summaryrefslogtreecommitdiffstats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/9pfs/9p-handle.c6
-rw-r--r--hw/9pfs/9p-local.c4
-rw-r--r--hw/9pfs/xen-9p-backend.c7
-rw-r--r--hw/Makefile.objs3
-rw-r--r--hw/alpha/dp264.c3
-rw-r--r--hw/alpha/typhoon.c13
-rw-r--r--hw/arm/boot.c18
-rw-r--r--hw/arm/musicpal.c5
-rw-r--r--hw/arm/sysbus-fdt.c61
-rw-r--r--hw/arm/virt.c7
-rw-r--r--hw/audio/ac97.c12
-rw-r--r--hw/audio/es1370.c20
-rw-r--r--hw/audio/marvell_88w8618.c14
-rw-r--r--hw/char/serial.c4
-rw-r--r--hw/char/sh_serial.c20
-rw-r--r--hw/char/virtio-serial-bus.c6
-rw-r--r--hw/char/xen_console.c6
-rw-r--r--hw/core/Makefile.objs5
-rw-r--r--hw/core/generic-loader.c7
-rw-r--r--hw/core/hotplug.c10
-rw-r--r--hw/core/loader.c5
-rw-r--r--hw/core/machine.c2
-rw-r--r--hw/core/null-machine.c2
-rw-r--r--hw/core/qdev.c16
-rw-r--r--hw/display/Makefile.objs4
-rw-r--r--hw/display/bcm2835_fb.c2
-rw-r--r--hw/display/bochs-display.c13
-rw-r--r--hw/display/cg3.c2
-rw-r--r--hw/display/cirrus_vga.c143
-rw-r--r--hw/display/cirrus_vga_internal.h103
-rw-r--r--hw/display/cirrus_vga_isa.c98
-rw-r--r--hw/display/edid-generate.c10
-rw-r--r--hw/display/qxl.c47
-rw-r--r--hw/display/qxl.h1
-rw-r--r--hw/display/tcx.c2
-rw-r--r--hw/display/vga-pci.c8
-rw-r--r--hw/display/vga_int.h1
-rw-r--r--hw/hppa/dino.c7
-rw-r--r--hw/hppa/machine.c2
-rw-r--r--hw/hyperv/Makefile.objs2
-rw-r--r--hw/hyperv/hyperv.c654
-rw-r--r--hw/hyperv/hyperv_testdev.c327
-rw-r--r--hw/i2c/i2c-ddc.c200
-rw-r--r--hw/i386/kvm/clock.c17
-rw-r--r--hw/i386/pc.c18
-rw-r--r--hw/ide/core.c3
-rw-r--r--hw/input/ps2.c8
-rw-r--r--hw/intc/armv7m_nvic.c12
-rw-r--r--hw/intc/ioapic.c8
-rw-r--r--hw/intc/xics.c15
-rw-r--r--hw/intc/xics_kvm.c7
-rw-r--r--hw/isa/Makefile.objs3
-rw-r--r--hw/mem/Makefile.objs4
-rw-r--r--hw/mem/memory-device.c103
-rw-r--r--hw/mem/nvdimm.c9
-rw-r--r--hw/mem/pc-dimm.c84
-rw-r--r--hw/mem/trace-events5
-rw-r--r--hw/mips/gt64xxx_pci.c18
-rw-r--r--hw/mips/mips_fulong2e.c6
-rw-r--r--hw/mips/mips_malta.c19
-rw-r--r--hw/mips/mips_mipssim.c3
-rw-r--r--hw/mips/mips_r4k.c6
-rw-r--r--hw/misc/Makefile.objs1
-rw-r--r--hw/misc/debugexit.c6
-rw-r--r--hw/misc/edu.c9
-rw-r--r--hw/misc/hyperv_testdev.c168
-rw-r--r--hw/misc/ivshmem.c18
-rw-r--r--hw/misc/pc-testdev.c20
-rw-r--r--hw/moxie/moxiesim.c2
-rw-r--r--hw/net/cadence_gem.c194
-rw-r--r--hw/net/e1000.c16
-rw-r--r--hw/net/etraxfs_eth.c44
-rw-r--r--hw/net/lan9118.c9
-rw-r--r--hw/net/lance.c8
-rw-r--r--hw/net/milkymist-minimac2.c24
-rw-r--r--hw/net/mipsnet.c9
-rw-r--r--hw/net/ne2000.c4
-rw-r--r--hw/net/opencores_eth.c8
-rw-r--r--hw/net/pcnet.c4
-rw-r--r--hw/net/rtl8139.c8
-rw-r--r--hw/net/smc91c111.c8
-rw-r--r--hw/net/stellaris_enet.c15
-rw-r--r--hw/net/trace-events3
-rw-r--r--hw/net/virtio-net.c8
-rw-r--r--hw/net/xgmac.c9
-rw-r--r--hw/nvram/Makefile.objs2
-rw-r--r--hw/nvram/fw_cfg.c13
-rw-r--r--hw/pci-host/bonito.c9
-rw-r--r--hw/pci-host/piix.c6
-rw-r--r--hw/pci-host/q35.c6
-rw-r--r--hw/pci/pci.c13
-rw-r--r--hw/ppc/pnv_core.c4
-rw-r--r--hw/ppc/spapr.c29
-rw-r--r--hw/ppc/spapr_pci.c7
-rw-r--r--hw/riscv/sifive_clint.c8
-rw-r--r--hw/riscv/sifive_plic.c4
-rw-r--r--hw/riscv/sifive_u.c4
-rw-r--r--hw/riscv/spike.c6
-rw-r--r--hw/riscv/virt.c6
-rw-r--r--hw/s390x/Makefile.objs4
-rw-r--r--hw/s390x/ap-bridge.c78
-rw-r--r--hw/s390x/ap-device.c38
-rw-r--r--hw/s390x/css.c38
-rw-r--r--hw/s390x/ipl.h5
-rw-r--r--hw/s390x/s390-pci-bus.c34
-rw-r--r--hw/s390x/s390-virtio-ccw.c14
-rw-r--r--hw/scsi/lsi53c895a.c214
-rw-r--r--hw/scsi/mptendian.c163
-rw-r--r--hw/scsi/scsi-disk.c35
-rw-r--r--hw/scsi/trace-events62
-rw-r--r--hw/scsi/virtio-scsi.c11
-rw-r--r--hw/sd/ssi-sd.c2
-rw-r--r--hw/sh4/sh_pci.c20
-rw-r--r--hw/smbios/smbios.c90
-rw-r--r--hw/sparc64/niagara.c4
-rw-r--r--hw/ssi/xilinx_spi.c9
-rw-r--r--hw/timer/aspeed_timer.c3
-rw-r--r--hw/timer/mc146818rtc.c9
-rw-r--r--hw/timer/sun4v-rtc.c23
-rw-r--r--hw/timer/trace-events6
-rw-r--r--hw/usb/bus.c5
-rw-r--r--hw/usb/ccid-card-emulated.c27
-rw-r--r--hw/usb/hcd-ohci.c6
-rw-r--r--hw/vfio/Makefile.objs1
-rw-r--r--hw/vfio/amd-xgbe.c1
-rw-r--r--hw/vfio/ap.c181
-rw-r--r--hw/vfio/calxeda-xgmac.c1
-rw-r--r--hw/vfio/display.c12
-rw-r--r--hw/vfio/pci-quirks.c4
-rw-r--r--hw/vfio/pci.c79
-rw-r--r--hw/vfio/pci.h1
-rw-r--r--hw/vfio/platform.c31
-rw-r--r--hw/virtio/vhost-user.c20
-rw-r--r--hw/virtio/virtio-pci.c4
-rw-r--r--hw/virtio/virtio.c11
-rw-r--r--hw/xen/xen_pt.c2
-rw-r--r--hw/xen/xen_pt_config_init.c8
137 files changed, 2840 insertions, 1358 deletions
diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c
index f3641dbe4a..3465b1ef30 100644
--- a/hw/9pfs/9p-handle.c
+++ b/hw/9pfs/9p-handle.c
@@ -19,6 +19,7 @@
#include <grp.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include "qapi/error.h"
#include "qemu/xattr.h"
#include "qemu/cutils.h"
#include "qemu/error-report.h"
@@ -655,12 +656,13 @@ static int handle_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
warn_report("handle backend is deprecated");
if (sec_model) {
- error_report("Invalid argument security_model specified with handle fsdriver");
+ error_setg(errp,
+ "Invalid argument security_model specified with handle fsdriver");
return -1;
}
if (!path) {
- error_report("fsdev: No path specified");
+ error_setg(errp, "fsdev: No path specified");
return -1;
}
fse->path = g_strdup(path);
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index c30f4f26bd..08e673a79c 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -1509,8 +1509,8 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
fsdev_throttle_parse_opts(opts, &fse->fst, &local_err);
if (local_err) {
- error_propagate(errp, local_err);
- error_prepend(errp, "invalid throttle configuration: ");
+ error_propagate_prepend(errp, local_err,
+ "invalid throttle configuration: ");
return -1;
}
diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c
index 6026780f95..3f54a21c76 100644
--- a/hw/9pfs/xen-9p-backend.c
+++ b/hw/9pfs/xen-9p-backend.c
@@ -14,6 +14,7 @@
#include "hw/9pfs/9p.h"
#include "hw/xen/xen_backend.h"
#include "hw/9pfs/xen-9pfs.h"
+#include "qapi/error.h"
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "fsdev/qemu-fsdev.h"
@@ -355,6 +356,7 @@ static int xen_9pfs_free(struct XenDevice *xendev)
static int xen_9pfs_connect(struct XenDevice *xendev)
{
+ Error *err = NULL;
int i;
Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
V9fsState *s = &xen_9pdev->state;
@@ -452,7 +454,10 @@ static int xen_9pfs_connect(struct XenDevice *xendev)
qemu_opt_set(fsdev, "path", xen_9pdev->path, NULL);
qemu_opt_set(fsdev, "security_model", xen_9pdev->security_model, NULL);
qemu_opts_set_id(fsdev, s->fsconf.fsdev_id);
- qemu_fsdev_add(fsdev);
+ qemu_fsdev_add(fsdev, &err);
+ if (err) {
+ error_report_err(err);
+ }
v9fs_device_realize_common(s, &xen_9p_transport, NULL);
return 0;
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index a19c1417ed..39d882af6f 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -9,6 +9,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += cpu/
devices-dirs-$(CONFIG_SOFTMMU) += display/
devices-dirs-$(CONFIG_SOFTMMU) += dma/
devices-dirs-$(CONFIG_SOFTMMU) += gpio/
+devices-dirs-$(CONFIG_HYPERV) += hyperv/
devices-dirs-$(CONFIG_SOFTMMU) += i2c/
devices-dirs-$(CONFIG_SOFTMMU) += ide/
devices-dirs-$(CONFIG_SOFTMMU) += input/
@@ -33,7 +34,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += vfio/
devices-dirs-$(CONFIG_SOFTMMU) += virtio/
devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
devices-dirs-$(CONFIG_SOFTMMU) += xen/
-devices-dirs-$(CONFIG_MEM_HOTPLUG) += mem/
+devices-dirs-$(CONFIG_MEM_DEVICE) += mem/
devices-dirs-$(CONFIG_SOFTMMU) += smbios/
devices-dirs-y += core/
common-obj-y += $(devices-dirs-y)
diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c
index 80b987f7fb..dd62f2a405 100644
--- a/hw/alpha/dp264.c
+++ b/hw/alpha/dp264.c
@@ -150,7 +150,8 @@ static void clipper_init(MachineState *machine)
}
if (initrd_filename) {
- long initrd_base, initrd_size;
+ long initrd_base;
+ int64_t initrd_size;
initrd_size = get_image_size(initrd_filename);
if (initrd_size < 0) {
diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c
index d74b5b55e1..8004afe45b 100644
--- a/hw/alpha/typhoon.c
+++ b/hw/alpha/typhoon.c
@@ -932,23 +932,10 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
return b;
}
-static int typhoon_pcihost_init(SysBusDevice *dev)
-{
- return 0;
-}
-
-static void typhoon_pcihost_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = typhoon_pcihost_init;
-}
-
static const TypeInfo typhoon_pcihost_info = {
.name = TYPE_TYPHOON_PCI_HOST_BRIDGE,
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(TyphoonState),
- .class_init = typhoon_pcihost_class_init,
};
static void typhoon_iommu_memory_region_class_init(ObjectClass *klass,
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 20c71d7d96..586baa9b64 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -24,6 +24,7 @@
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "exec/address-spaces.h"
+#include "qemu/units.h"
/* Kernel boot protocol is specified in the kernel docs
* Documentation/arm/Booting and Documentation/arm64/booting.txt
@@ -36,6 +37,8 @@
#define ARM64_TEXT_OFFSET_OFFSET 8
#define ARM64_MAGIC_OFFSET 56
+#define BOOTLOADER_MAX_SIZE (4 * KiB)
+
AddressSpace *arm_boot_address_space(ARMCPU *cpu,
const struct arm_boot_info *info)
{
@@ -184,6 +187,8 @@ static void write_bootloader(const char *name, hwaddr addr,
code[i] = tswap32(insn);
}
+ assert((len * sizeof(uint32_t)) < BOOTLOADER_MAX_SIZE);
+
rom_add_blob_fixed_as(name, code, len * sizeof(uint32_t), addr, as);
g_free(code);
@@ -919,6 +924,19 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base,
memcpy(&hdrvals, buffer + ARM64_TEXT_OFFSET_OFFSET, sizeof(hdrvals));
if (hdrvals[1] != 0) {
kernel_load_offset = le64_to_cpu(hdrvals[0]);
+
+ /*
+ * We write our startup "bootloader" at the very bottom of RAM,
+ * so that bit can't be used for the image. Luckily the Image
+ * format specification is that the image requests only an offset
+ * from a 2MB boundary, not an absolute load address. So if the
+ * image requests an offset that might mean it overlaps with the
+ * bootloader, we can just load it starting at 2MB+offset rather
+ * than 0MB + offset.
+ */
+ if (kernel_load_offset < BOOTLOADER_MAX_SIZE) {
+ kernel_load_offset += 2 * MiB;
+ }
}
}
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index c807010e83..9648b3af44 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -1693,9 +1693,10 @@ static void musicpal_init(MachineState *machine)
}
wm8750_dev = i2c_create_slave(i2c, TYPE_WM8750, MP_WM_ADDR);
- dev = qdev_create(NULL, "mv88w8618_audio");
+ dev = qdev_create(NULL, TYPE_MV88W8618_AUDIO);
s = SYS_BUS_DEVICE(dev);
- qdev_prop_set_ptr(dev, "wm8750", wm8750_dev);
+ object_property_set_link(OBJECT(dev), OBJECT(wm8750_dev),
+ TYPE_WM8750, NULL);
qdev_init_nofail(dev);
sysbus_mmio_map(s, 0, MP_AUDIO_BASE);
sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]);
diff --git a/hw/arm/sysbus-fdt.c b/hw/arm/sysbus-fdt.c
index 43d6a7bb48..0e24c803a1 100644
--- a/hw/arm/sysbus-fdt.c
+++ b/hw/arm/sysbus-fdt.c
@@ -50,11 +50,13 @@ typedef struct PlatformBusFDTData {
PlatformBusDevice *pbus;
} PlatformBusFDTData;
-/* struct that associates a device type name and a node creation function */
-typedef struct NodeCreationPair {
+/* struct that allows to match a device and create its FDT node */
+typedef struct BindingEntry {
const char *typename;
- int (*add_fdt_node_fn)(SysBusDevice *sbdev, void *opaque);
-} NodeCreationPair;
+ const char *compat;
+ int (*add_fn)(SysBusDevice *sbdev, void *opaque);
+ bool (*match_fn)(SysBusDevice *sbdev, const struct BindingEntry *combo);
+} BindingEntry;
/* helpers */
@@ -413,6 +415,27 @@ static int add_amd_xgbe_fdt_node(SysBusDevice *sbdev, void *opaque)
return 0;
}
+/* DT compatible matching */
+static bool vfio_platform_match(SysBusDevice *sbdev,
+ const BindingEntry *entry)
+{
+ VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
+ const char *compat;
+ unsigned int n;
+
+ for (n = vdev->num_compat, compat = vdev->compat; n > 0;
+ n--, compat += strlen(compat) + 1) {
+ if (!strcmp(entry->compat, compat)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+#define VFIO_PLATFORM_BINDING(compat, add_fn) \
+ {TYPE_VFIO_PLATFORM, (compat), (add_fn), vfio_platform_match}
+
#endif /* CONFIG_LINUX */
static int no_fdt_node(SysBusDevice *sbdev, void *opaque)
@@ -420,14 +443,23 @@ static int no_fdt_node(SysBusDevice *sbdev, void *opaque)
return 0;
}
-/* list of supported dynamic sysbus devices */
-static const NodeCreationPair add_fdt_node_functions[] = {
+/* Device type based matching */
+static bool type_match(SysBusDevice *sbdev, const BindingEntry *entry)
+{
+ return !strcmp(object_get_typename(OBJECT(sbdev)), entry->typename);
+}
+
+#define TYPE_BINDING(type, add_fn) {(type), NULL, (add_fn), type_match}
+
+/* list of supported dynamic sysbus bindings */
+static const BindingEntry bindings[] = {
#ifdef CONFIG_LINUX
- {TYPE_VFIO_CALXEDA_XGMAC, add_calxeda_midway_xgmac_fdt_node},
- {TYPE_VFIO_AMD_XGBE, add_amd_xgbe_fdt_node},
+ TYPE_BINDING(TYPE_VFIO_CALXEDA_XGMAC, add_calxeda_midway_xgmac_fdt_node),
+ TYPE_BINDING(TYPE_VFIO_AMD_XGBE, add_amd_xgbe_fdt_node),
+ VFIO_PLATFORM_BINDING("amd,xgbe-seattle-v1a", add_amd_xgbe_fdt_node),
#endif
- {TYPE_RAMFB_DEVICE, no_fdt_node},
- {"", NULL}, /* last element */
+ TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node),
+ TYPE_BINDING("", NULL), /* last element */
};
/* Generic Code */
@@ -446,10 +478,11 @@ static void add_fdt_node(SysBusDevice *sbdev, void *opaque)
{
int i, ret;
- for (i = 0; i < ARRAY_SIZE(add_fdt_node_functions); i++) {
- if (!strcmp(object_get_typename(OBJECT(sbdev)),
- add_fdt_node_functions[i].typename)) {
- ret = add_fdt_node_functions[i].add_fdt_node_fn(sbdev, opaque);
+ for (i = 0; i < ARRAY_SIZE(bindings); i++) {
+ const BindingEntry *iter = &bindings[i];
+
+ if (iter->match_fn(sbdev, iter)) {
+ ret = iter->add_fn(sbdev, opaque);
assert(!ret);
return;
}
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 0b57f87abc..9f677825f9 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -712,6 +712,10 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart,
/* Mark as not usable by the normal world */
qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled");
qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay");
+
+ qemu_fdt_add_subnode(vms->fdt, "/secure-chosen");
+ qemu_fdt_setprop_string(vms->fdt, "/secure-chosen", "stdout-path",
+ nodename);
}
g_free(nodename);
@@ -1758,6 +1762,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_CALXEDA_XGMAC);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_AMD_XGBE);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_PLATFORM);
mc->block_default_type = IF_VIRTIO;
mc->no_cdrom = 1;
mc->pci_allow_0_address = true;
@@ -1926,6 +1931,8 @@ static void virt_machine_2_10_options(MachineClass *mc)
{
virt_machine_2_11_options(mc);
SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_10);
+ /* before 2.11 we never faulted accesses to bad addresses */
+ mc->ignore_memory_transaction_failures = true;
}
DEFINE_VIRT_MACHINE(2, 10)
diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c
index 337402e9c6..d799533aa9 100644
--- a/hw/audio/ac97.c
+++ b/hw/audio/ac97.c
@@ -123,6 +123,10 @@ enum {
#define MUTE_SHIFT 15
+#define TYPE_AC97 "AC97"
+#define AC97(obj) \
+ OBJECT_CHECK(AC97LinkState, (obj), TYPE_AC97)
+
#define REC_MASK 7
enum {
REC_MIC = 0,
@@ -1340,7 +1344,7 @@ static void ac97_on_reset (DeviceState *dev)
static void ac97_realize(PCIDevice *dev, Error **errp)
{
- AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
+ AC97LinkState *s = AC97(dev);
uint8_t *c = s->dev.config;
/* TODO: no need to override */
@@ -1389,7 +1393,7 @@ static void ac97_realize(PCIDevice *dev, Error **errp)
static void ac97_exit(PCIDevice *dev)
{
- AC97LinkState *s = DO_UPCAST(AC97LinkState, dev, dev);
+ AC97LinkState *s = AC97(dev);
AUD_close_in(&s->card, s->voice_pi);
AUD_close_out(&s->card, s->voice_po);
@@ -1399,7 +1403,7 @@ static void ac97_exit(PCIDevice *dev)
static int ac97_init (PCIBus *bus)
{
- pci_create_simple (bus, -1, "AC97");
+ pci_create_simple(bus, -1, TYPE_AC97);
return 0;
}
@@ -1427,7 +1431,7 @@ static void ac97_class_init (ObjectClass *klass, void *data)
}
static const TypeInfo ac97_info = {
- .name = "AC97",
+ .name = TYPE_AC97,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof (AC97LinkState),
.class_init = ac97_class_init,
diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index dd75c9e8f5..97789a0771 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -506,10 +506,13 @@ static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
d - &s->chan[0], val >> 16, (val & 0xffff));
break;
+ case ES1370_REG_ADC_FRAMEADR:
+ d += 2;
+ goto frameadr;
case ES1370_REG_DAC1_FRAMEADR:
case ES1370_REG_DAC2_FRAMEADR:
- case ES1370_REG_ADC_FRAMEADR:
d += (addr - ES1370_REG_DAC1_FRAMEADR) >> 3;
+ frameadr:
d->frame_addr = val;
ldebug ("chan %td frame address %#x\n", d - &s->chan[0], val);
break;
@@ -521,10 +524,13 @@ static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
lwarn ("writing to phantom frame address %#x\n", val);
break;
+ case ES1370_REG_ADC_FRAMECNT:
+ d += 2;
+ goto framecnt;
case ES1370_REG_DAC1_FRAMECNT:
case ES1370_REG_DAC2_FRAMECNT:
- case ES1370_REG_ADC_FRAMECNT:
d += (addr - ES1370_REG_DAC1_FRAMECNT) >> 3;
+ framecnt:
d->frame_cnt = val;
d->leftover = 0;
ldebug ("chan %td frame count %d, buffer size %d\n",
@@ -579,10 +585,13 @@ static uint64_t es1370_read(void *opaque, hwaddr addr, unsigned size)
#endif
break;
+ case ES1370_REG_ADC_FRAMECNT:
+ d += 2;
+ goto framecnt;
case ES1370_REG_DAC1_FRAMECNT:
case ES1370_REG_DAC2_FRAMECNT:
- case ES1370_REG_ADC_FRAMECNT:
d += (addr - ES1370_REG_DAC1_FRAMECNT) >> 3;
+ framecnt:
val = d->frame_cnt;
#ifdef DEBUG_ES1370
{
@@ -596,10 +605,13 @@ static uint64_t es1370_read(void *opaque, hwaddr addr, unsigned size)
#endif
break;
+ case ES1370_REG_ADC_FRAMEADR:
+ d += 2;
+ goto frameadr;
case ES1370_REG_DAC1_FRAMEADR:
case ES1370_REG_DAC2_FRAMEADR:
- case ES1370_REG_ADC_FRAMEADR:
d += (addr - ES1370_REG_DAC1_FRAMEADR) >> 3;
+ frameadr:
val = d->frame_addr;
break;
diff --git a/hw/audio/marvell_88w8618.c b/hw/audio/marvell_88w8618.c
index e546892d3c..6600ab4851 100644
--- a/hw/audio/marvell_88w8618.c
+++ b/hw/audio/marvell_88w8618.c
@@ -15,6 +15,7 @@
#include "hw/i2c/i2c.h"
#include "hw/audio/wm8750.h"
#include "audio/audio.h"
+#include "qapi/error.h"
#define MP_AUDIO_SIZE 0x00001000
@@ -38,7 +39,6 @@
#define MP_AUDIO_CLOCK_24MHZ (1 << 9)
#define MP_AUDIO_MONO (1 << 14)
-#define TYPE_MV88W8618_AUDIO "mv88w8618_audio"
#define MV88W8618_AUDIO(obj) \
OBJECT_CHECK(mv88w8618_audio_state, (obj), TYPE_MV88W8618_AUDIO)
@@ -252,6 +252,11 @@ static void mv88w8618_audio_init(Object *obj)
memory_region_init_io(&s->iomem, obj, &mv88w8618_audio_ops, s,
"audio", MP_AUDIO_SIZE);
sysbus_init_mmio(dev, &s->iomem);
+
+ object_property_add_link(OBJECT(dev), "wm8750", TYPE_WM8750,
+ (Object **) &s->wm,
+ qdev_prop_allow_set_link_before_realize,
+ 0, &error_abort);
}
static void mv88w8618_audio_realize(DeviceState *dev, Error **errp)
@@ -279,11 +284,6 @@ static const VMStateDescription mv88w8618_audio_vmsd = {
}
};
-static Property mv88w8618_audio_properties[] = {
- DEFINE_PROP_PTR("wm8750", mv88w8618_audio_state, wm),
- {/* end of list */},
-};
-
static void mv88w8618_audio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -291,8 +291,6 @@ static void mv88w8618_audio_class_init(ObjectClass *klass, void *data)
dc->realize = mv88w8618_audio_realize;
dc->reset = mv88w8618_audio_reset;
dc->vmsd = &mv88w8618_audio_vmsd;
- dc->props = mv88w8618_audio_properties;
- /* Reason: pointer property "wm8750" */
dc->user_creatable = false;
}
diff --git a/hw/char/serial.c b/hw/char/serial.c
index 251f40fdac..02463e3388 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -345,9 +345,9 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
default:
case 0:
if (s->lcr & UART_LCR_DLAB) {
- if (size == 2) {
+ if (size == 1) {
s->divider = (s->divider & 0xff00) | val;
- } else if (size == 4) {
+ } else {
s->divider = val;
}
serial_update_parameters(s);
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
index 373a40595f..12831561a6 100644
--- a/hw/char/sh_serial.c
+++ b/hw/char/sh_serial.c
@@ -29,6 +29,7 @@
#include "hw/sh4/sh.h"
#include "chardev/char-fe.h"
#include "qapi/error.h"
+#include "qemu/timer.h"
//#define DEBUG_SERIAL
@@ -63,6 +64,8 @@ typedef struct {
int rtrg;
CharBackend chr;
+ QEMUTimer *fifo_timeout_timer;
+ uint64_t etu; /* Elementary Time Unit (ns) */
qemu_irq eri;
qemu_irq rxi;
@@ -314,6 +317,16 @@ static int sh_serial_can_receive1(void *opaque)
return sh_serial_can_receive(s);
}
+static void sh_serial_timeout_int(void *opaque)
+{
+ sh_serial_state *s = opaque;
+
+ s->flags |= SH_SERIAL_FLAG_RDF;
+ if (s->scr & (1 << 6) && s->rxi) {
+ qemu_set_irq(s->rxi, 1);
+ }
+}
+
static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
{
sh_serial_state *s = opaque;
@@ -330,8 +343,12 @@ static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
if (s->rx_cnt >= s->rtrg) {
s->flags |= SH_SERIAL_FLAG_RDF;
if (s->scr & (1 << 6) && s->rxi) {
+ timer_del(s->fifo_timeout_timer);
qemu_set_irq(s->rxi, 1);
}
+ } else {
+ timer_mod(s->fifo_timeout_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
}
}
}
@@ -402,6 +419,9 @@ void sh_serial_init(MemoryRegion *sysmem,
sh_serial_event, NULL, s, NULL, true);
}
+ s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ sh_serial_timeout_int, s);
+ s->etu = NANOSECONDS_PER_SECOND / 9600;
s->eri = eri_source;
s->rxi = rxi_source;
s->txi = txi_source;
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index d2dd8ab502..04e3ebe352 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -667,9 +667,9 @@ static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f)
/* The config space (ignored on the far end in current versions) */
get_config(vdev, (uint8_t *)&config);
- qemu_put_be16s(f, &config.cols);
- qemu_put_be16s(f, &config.rows);
- qemu_put_be32s(f, &config.max_nr_ports);
+ qemu_put_be16(f, config.cols);
+ qemu_put_be16(f, config.rows);
+ qemu_put_be32(f, config.max_nr_ports);
/* The ports map */
max_nr_ports = s->serial.max_virtserial_ports;
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index 8b4b4bf523..44f7236382 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -207,7 +207,11 @@ static int con_init(struct XenDevice *xendev)
} else {
snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
qemu_chr_fe_init(&con->chr,
- qemu_chr_new(label, output), &error_abort);
+ /*
+ * FIXME: sure we want to support implicit
+ * muxed monitors here?
+ */
+ qemu_chr_new_mux_mon(label, output), &error_abort);
}
xenstore_store_pv_console_info(con->xendev.dev,
diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index eb88ca979e..a799c83815 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -20,6 +20,5 @@ common-obj-$(CONFIG_SOFTMMU) += register.o
common-obj-$(CONFIG_SOFTMMU) += or-irq.o
common-obj-$(CONFIG_SOFTMMU) += split-irq.o
common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o
-
-obj-$(CONFIG_SOFTMMU) += generic-loader.o
-obj-$(CONFIG_SOFTMMU) += null-machine.o
+common-obj-$(CONFIG_SOFTMMU) += generic-loader.o
+common-obj-$(CONFIG_SOFTMMU) += null-machine.o
diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c
index fde32cbda1..fbae05fb3b 100644
--- a/hw/core/generic-loader.c
+++ b/hw/core/generic-loader.c
@@ -130,11 +130,7 @@ static void generic_loader_realize(DeviceState *dev, Error **errp)
s->cpu = first_cpu;
}
-#ifdef TARGET_WORDS_BIGENDIAN
- big_endian = 1;
-#else
- big_endian = 0;
-#endif
+ big_endian = target_words_bigendian();
if (s->file) {
AddressSpace *as = s->cpu ? s->cpu->as : NULL;
@@ -204,6 +200,7 @@ static void generic_loader_class_init(ObjectClass *klass, void *data)
dc->unrealize = generic_loader_unrealize;
dc->props = generic_loader_props;
dc->desc = "Generic Loader";
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
static TypeInfo generic_loader_info = {
diff --git a/hw/core/hotplug.c b/hw/core/hotplug.c
index 2253072d0e..17ac986685 100644
--- a/hw/core/hotplug.c
+++ b/hw/core/hotplug.c
@@ -35,16 +35,6 @@ void hotplug_handler_plug(HotplugHandler *plug_handler,
}
}
-void hotplug_handler_post_plug(HotplugHandler *plug_handler,
- DeviceState *plugged_dev)
-{
- HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
-
- if (hdc->post_plug) {
- hdc->post_plug(plug_handler, plugged_dev);
- }
-}
-
void hotplug_handler_unplug_request(HotplugHandler *plug_handler,
DeviceState *plugged_dev,
Error **errp)
diff --git a/hw/core/loader.c b/hw/core/loader.c
index 390987a05c..aa0b3fc867 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -61,9 +61,10 @@
static int roms_loaded;
/* return the size or -1 if error */
-int get_image_size(const char *filename)
+int64_t get_image_size(const char *filename)
{
- int fd, size;
+ int fd;
+ int64_t size;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 1987557833..da50ad6de7 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -636,7 +636,7 @@ static void machine_class_init(ObjectClass *oc, void *data)
machine_get_memory_encryption, machine_set_memory_encryption,
&error_abort);
object_class_property_set_description(oc, "memory-encryption",
- "Set memory encyption object to use", &error_abort);
+ "Set memory encryption object to use", &error_abort);
}
static void machine_class_base_init(ObjectClass *oc, void *data)
diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
index cde4d3eb57..76d3f8e39c 100644
--- a/hw/core/null-machine.c
+++ b/hw/core/null-machine.c
@@ -18,7 +18,7 @@
#include "hw/boards.h"
#include "sysemu/sysemu.h"
#include "exec/address-spaces.h"
-#include "cpu.h"
+#include "qom/cpu.h"
static void machine_none_init(MachineState *mch)
{
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 046d8f1f76..6b3cc55b27 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -832,14 +832,6 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
DEVICE_LISTENER_CALL(realize, Forward, dev);
- if (hotplug_ctrl) {
- hotplug_handler_plug(hotplug_ctrl, dev, &local_err);
- }
-
- if (local_err != NULL) {
- goto post_realize_fail;
- }
-
/*
* always free/re-initialize here since the value cannot be cleaned up
* in device_unrealize due to its usage later on in the unplug path
@@ -869,8 +861,12 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
dev->pending_deleted_event = false;
if (hotplug_ctrl) {
- hotplug_handler_post_plug(hotplug_ctrl, dev);
- }
+ hotplug_handler_plug(hotplug_ctrl, dev, &local_err);
+ if (local_err != NULL) {
+ goto child_realize_fail;
+ }
+ }
+
} else if (!value && dev->realized) {
Error **local_errp = NULL;
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index 780a76b9f0..97acd5b6cb 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -5,6 +5,7 @@ common-obj-$(CONFIG_FW_CFG_DMA) += ramfb-standalone.o
common-obj-$(CONFIG_ADS7846) += ads7846.o
common-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o
+common-obj-$(call land,$(CONFIG_VGA_CIRRUS),$(CONFIG_VGA_ISA))+=cirrus_vga_isa.o
common-obj-$(CONFIG_G364FB) += g364fb.o
common-obj-$(CONFIG_JAZZ_LED) += jazz_led.o
common-obj-$(CONFIG_PL110) += pl110.o
@@ -14,11 +15,12 @@ common-obj-$(CONFIG_SSD0323) += ssd0323.o
common-obj-$(CONFIG_XEN) += xenfb.o
common-obj-$(CONFIG_VGA_PCI) += vga-pci.o
-common-obj-$(CONFIG_VGA_PCI) += bochs-display.o
common-obj-$(CONFIG_VGA_PCI) += edid-region.o
common-obj-$(CONFIG_VGA_ISA) += vga-isa.o
common-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
common-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
+common-obj-$(CONFIG_BOCHS_DISPLAY) += bochs-display.o
+common-obj-$(CONFIG_BOCHS_DISPLAY) += edid-region.o
common-obj-$(CONFIG_BLIZZARD) += blizzard.o
common-obj-$(CONFIG_EXYNOS4) += exynos4210_fimd.o
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
index d534d00a65..599863e4e1 100644
--- a/hw/display/bcm2835_fb.c
+++ b/hw/display/bcm2835_fb.c
@@ -190,7 +190,7 @@ static void fb_update_display(void *opaque)
}
if (s->invalidate) {
- hwaddr base = s->config.base + xoff + yoff * src_width;
+ hwaddr base = s->config.base + xoff + (hwaddr)yoff * src_width;
framebuffer_update_memory_section(&s->fbsection, s->dma_mr,
base,
s->config.yres, src_width);
diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c
index 09d8944a1b..3d439eb240 100644
--- a/hw/display/bochs-display.c
+++ b/hw/display/bochs-display.c
@@ -9,6 +9,7 @@
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "hw/display/bochs-vbe.h"
+#include "hw/display/edid.h"
#include "qapi/error.h"
@@ -35,9 +36,13 @@ typedef struct BochsDisplayState {
MemoryRegion mmio;
MemoryRegion vbe;
MemoryRegion qext;
+ MemoryRegion edid;
/* device config */
uint64_t vgamem;
+ bool enable_edid;
+ qemu_edid_info edid_info;
+ uint8_t edid_blob[256];
/* device registers */
uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
@@ -283,6 +288,12 @@ static void bochs_display_realize(PCIDevice *dev, Error **errp)
pci_register_bar(&s->pci, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
pci_register_bar(&s->pci, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
+ if (s->enable_edid) {
+ qemu_edid_generate(s->edid_blob, sizeof(s->edid_blob), &s->edid_info);
+ qemu_edid_region_io(&s->edid, obj, s->edid_blob, sizeof(s->edid_blob));
+ memory_region_add_subregion(&s->mmio, 0, &s->edid);
+ }
+
if (pci_bus_is_express(pci_get_bus(dev))) {
dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
ret = pcie_endpoint_cap_init(dev, 0x80);
@@ -325,6 +336,8 @@ static void bochs_display_exit(PCIDevice *dev)
static Property bochs_display_properties[] = {
DEFINE_PROP_SIZE("vgamem", BochsDisplayState, vgamem, 16 * MiB),
+ DEFINE_PROP_BOOL("edid", BochsDisplayState, enable_edid, false),
+ DEFINE_EDID_PROPERTIES(BochsDisplayState, edid_info),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
index 1c199ab369..e50d97e48c 100644
--- a/hw/display/cg3.c
+++ b/hw/display/cg3.c
@@ -307,7 +307,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp)
ret = load_image_mr(fcode_filename, &s->rom);
g_free(fcode_filename);
if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) {
- error_report("cg3: could not load prom '%s'", CG3_ROM_FILE);
+ warn_report("cg3: could not load prom '%s'", CG3_ROM_FILE);
}
}
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 04c87c8e8d..d9b854d74d 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -33,8 +33,8 @@
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "ui/pixel_ops.h"
-#include "vga_int.h"
#include "hw/loader.h"
+#include "cirrus_vga_internal.h"
/*
* TODO:
@@ -52,16 +52,6 @@
*
***************************************/
-// ID
-#define CIRRUS_ID_CLGD5422 (0x23<<2)
-#define CIRRUS_ID_CLGD5426 (0x24<<2)
-#define CIRRUS_ID_CLGD5424 (0x25<<2)
-#define CIRRUS_ID_CLGD5428 (0x26<<2)
-#define CIRRUS_ID_CLGD5430 (0x28<<2)
-#define CIRRUS_ID_CLGD5434 (0x2A<<2)
-#define CIRRUS_ID_CLGD5436 (0x2B<<2)
-#define CIRRUS_ID_CLGD5446 (0x2E<<2)
-
// sequencer 0x07
#define CIRRUS_SR7_BPP_VGA 0x00
#define CIRRUS_SR7_BPP_SVGA 0x01
@@ -176,65 +166,10 @@
#define CIRRUS_PNPMMIO_SIZE 0x1000
-struct CirrusVGAState;
-typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
- uint32_t dstaddr, uint32_t srcaddr,
- int dstpitch, int srcpitch,
- int bltwidth, int bltheight);
typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
uint32_t dstaddr, int dst_pitch,
int width, int height);
-typedef struct CirrusVGAState {
- VGACommonState vga;
-
- MemoryRegion cirrus_vga_io;
- MemoryRegion cirrus_linear_io;
- MemoryRegion cirrus_linear_bitblt_io;
- MemoryRegion cirrus_mmio_io;
- MemoryRegion pci_bar;
- bool linear_vram; /* vga.vram mapped over cirrus_linear_io */
- MemoryRegion low_mem_container; /* container for 0xa0000-0xc0000 */
- MemoryRegion low_mem; /* always mapped, overridden by: */
- MemoryRegion cirrus_bank[2]; /* aliases at 0xa0000-0xb0000 */
- uint32_t cirrus_addr_mask;
- uint32_t linear_mmio_mask;
- uint8_t cirrus_shadow_gr0;
- uint8_t cirrus_shadow_gr1;
- uint8_t cirrus_hidden_dac_lockindex;
- uint8_t cirrus_hidden_dac_data;
- uint32_t cirrus_bank_base[2];
- uint32_t cirrus_bank_limit[2];
- uint8_t cirrus_hidden_palette[48];
- bool enable_blitter;
- int cirrus_blt_pixelwidth;
- int cirrus_blt_width;
- int cirrus_blt_height;
- int cirrus_blt_dstpitch;
- int cirrus_blt_srcpitch;
- uint32_t cirrus_blt_fgcol;
- uint32_t cirrus_blt_bgcol;
- uint32_t cirrus_blt_dstaddr;
- uint32_t cirrus_blt_srcaddr;
- uint8_t cirrus_blt_mode;
- uint8_t cirrus_blt_modeext;
- cirrus_bitblt_rop_t cirrus_rop;
-#define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */
- uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE];
- uint8_t *cirrus_srcptr;
- uint8_t *cirrus_srcptr_end;
- uint32_t cirrus_srccounter;
- /* hwcursor display state */
- int last_hw_cursor_size;
- int last_hw_cursor_x;
- int last_hw_cursor_y;
- int last_hw_cursor_y_start;
- int last_hw_cursor_y_end;
- int real_vram_size; /* XXX: suppress that */
- int device_id;
- int bustype;
-} CirrusVGAState;
-
typedef struct PCICirrusVGAState {
PCIDevice dev;
CirrusVGAState cirrus_vga;
@@ -244,16 +179,6 @@ typedef struct PCICirrusVGAState {
#define PCI_CIRRUS_VGA(obj) \
OBJECT_CHECK(PCICirrusVGAState, (obj), TYPE_PCI_CIRRUS_VGA)
-#define TYPE_ISA_CIRRUS_VGA "isa-cirrus-vga"
-#define ISA_CIRRUS_VGA(obj) \
- OBJECT_CHECK(ISACirrusVGAState, (obj), TYPE_ISA_CIRRUS_VGA)
-
-typedef struct ISACirrusVGAState {
- ISADevice parent_obj;
-
- CirrusVGAState cirrus_vga;
-} ISACirrusVGAState;
-
static uint8_t rop_to_index[256];
/***************************************
@@ -2829,7 +2754,7 @@ static int cirrus_post_load(void *opaque, int version_id)
return 0;
}
-static const VMStateDescription vmstate_cirrus_vga = {
+const VMStateDescription vmstate_cirrus_vga = {
.name = "cirrus_vga",
.version_id = 2,
.minimum_version_id = 1,
@@ -2932,10 +2857,9 @@ static const MemoryRegionOps cirrus_vga_io_ops = {
},
};
-static void cirrus_init_common(CirrusVGAState *s, Object *owner,
- int device_id, int is_pci,
- MemoryRegion *system_memory,
- MemoryRegion *system_io)
+void cirrus_init_common(CirrusVGAState *s, Object *owner,
+ int device_id, int is_pci,
+ MemoryRegion *system_memory, MemoryRegion *system_io)
{
int i;
static int inited;
@@ -3031,62 +2955,6 @@ static void cirrus_init_common(CirrusVGAState *s, Object *owner,
/***************************************
*
- * ISA bus support
- *
- ***************************************/
-
-static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
-{
- ISADevice *isadev = ISA_DEVICE(dev);
- ISACirrusVGAState *d = ISA_CIRRUS_VGA(dev);
- VGACommonState *s = &d->cirrus_vga.vga;
-
- /* follow real hardware, cirrus card emulated has 4 MB video memory.
- Also accept 8 MB/16 MB for backward compatibility. */
- if (s->vram_size_mb != 4 && s->vram_size_mb != 8 &&
- s->vram_size_mb != 16) {
- error_setg(errp, "Invalid cirrus_vga ram size '%u'",
- s->vram_size_mb);
- return;
- }
- s->global_vmstate = true;
- vga_common_init(s, OBJECT(dev));
- cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
- isa_address_space(isadev),
- isa_address_space_io(isadev));
- s->con = graphic_console_init(dev, 0, s->hw_ops, s);
- rom_add_vga(VGABIOS_CIRRUS_FILENAME);
- /* XXX ISA-LFB support */
- /* FIXME not qdev yet */
-}
-
-static Property isa_cirrus_vga_properties[] = {
- DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState,
- cirrus_vga.vga.vram_size_mb, 4),
- DEFINE_PROP_BOOL("blitter", struct ISACirrusVGAState,
- cirrus_vga.enable_blitter, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_cirrus_vga;
- dc->realize = isa_cirrus_vga_realizefn;
- dc->props = isa_cirrus_vga_properties;
- set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
-}
-
-static const TypeInfo isa_cirrus_vga_info = {
- .name = TYPE_ISA_CIRRUS_VGA,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISACirrusVGAState),
- .class_init = isa_cirrus_vga_class_init,
-};
-
-/***************************************
- *
* PCI bus support
*
***************************************/
@@ -3171,7 +3039,6 @@ static const TypeInfo cirrus_vga_info = {
static void cirrus_vga_register_types(void)
{
- type_register_static(&isa_cirrus_vga_info);
type_register_static(&cirrus_vga_info);
}
diff --git a/hw/display/cirrus_vga_internal.h b/hw/display/cirrus_vga_internal.h
new file mode 100644
index 0000000000..a78ebbd920
--- /dev/null
+++ b/hw/display/cirrus_vga_internal.h
@@ -0,0 +1,103 @@
+/*
+ * QEMU Cirrus CLGD 54xx VGA Emulator, ISA bus support
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ * Copyright (c) 2004 Makoto Suzuki (suzu)
+ *
+ * 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.
+ */
+
+#ifndef CIRRUS_VGA_INTERNAL_H
+#define CIRRUS_VGA_INTERNAL_H
+
+#include "vga_int.h"
+
+/* IDs */
+#define CIRRUS_ID_CLGD5422 (0x23 << 2)
+#define CIRRUS_ID_CLGD5426 (0x24 << 2)
+#define CIRRUS_ID_CLGD5424 (0x25 << 2)
+#define CIRRUS_ID_CLGD5428 (0x26 << 2)
+#define CIRRUS_ID_CLGD5430 (0x28 << 2)
+#define CIRRUS_ID_CLGD5434 (0x2A << 2)
+#define CIRRUS_ID_CLGD5436 (0x2B << 2)
+#define CIRRUS_ID_CLGD5446 (0x2E << 2)
+
+extern const VMStateDescription vmstate_cirrus_vga;
+
+struct CirrusVGAState;
+typedef void (*cirrus_bitblt_rop_t)(struct CirrusVGAState *s,
+ uint32_t dstaddr, uint32_t srcaddr,
+ int dstpitch, int srcpitch,
+ int bltwidth, int bltheight);
+
+typedef struct CirrusVGAState {
+ VGACommonState vga;
+
+ MemoryRegion cirrus_vga_io;
+ MemoryRegion cirrus_linear_io;
+ MemoryRegion cirrus_linear_bitblt_io;
+ MemoryRegion cirrus_mmio_io;
+ MemoryRegion pci_bar;
+ bool linear_vram; /* vga.vram mapped over cirrus_linear_io */
+ MemoryRegion low_mem_container; /* container for 0xa0000-0xc0000 */
+ MemoryRegion low_mem; /* always mapped, overridden by: */
+ MemoryRegion cirrus_bank[2]; /* aliases at 0xa0000-0xb0000 */
+ uint32_t cirrus_addr_mask;
+ uint32_t linear_mmio_mask;
+ uint8_t cirrus_shadow_gr0;
+ uint8_t cirrus_shadow_gr1;
+ uint8_t cirrus_hidden_dac_lockindex;
+ uint8_t cirrus_hidden_dac_data;
+ uint32_t cirrus_bank_base[2];
+ uint32_t cirrus_bank_limit[2];
+ uint8_t cirrus_hidden_palette[48];
+ bool enable_blitter;
+ int cirrus_blt_pixelwidth;
+ int cirrus_blt_width;
+ int cirrus_blt_height;
+ int cirrus_blt_dstpitch;
+ int cirrus_blt_srcpitch;
+ uint32_t cirrus_blt_fgcol;
+ uint32_t cirrus_blt_bgcol;
+ uint32_t cirrus_blt_dstaddr;
+ uint32_t cirrus_blt_srcaddr;
+ uint8_t cirrus_blt_mode;
+ uint8_t cirrus_blt_modeext;
+ cirrus_bitblt_rop_t cirrus_rop;
+#define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */
+ uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE];
+ uint8_t *cirrus_srcptr;
+ uint8_t *cirrus_srcptr_end;
+ uint32_t cirrus_srccounter;
+ /* hwcursor display state */
+ int last_hw_cursor_size;
+ int last_hw_cursor_x;
+ int last_hw_cursor_y;
+ int last_hw_cursor_y_start;
+ int last_hw_cursor_y_end;
+ int real_vram_size; /* XXX: suppress that */
+ int device_id;
+ int bustype;
+} CirrusVGAState;
+
+void cirrus_init_common(CirrusVGAState *s, Object *owner,
+ int device_id, int is_pci,
+ MemoryRegion *system_memory, MemoryRegion *system_io);
+
+#endif
diff --git a/hw/display/cirrus_vga_isa.c b/hw/display/cirrus_vga_isa.c
new file mode 100644
index 0000000000..fa10b74230
--- /dev/null
+++ b/hw/display/cirrus_vga_isa.c
@@ -0,0 +1,98 @@
+/*
+ * QEMU Cirrus CLGD 54xx VGA Emulator, ISA bus support
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ * Copyright (c) 2004 Makoto Suzuki (suzu)
+ *
+ * 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.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "hw/loader.h"
+#include "hw/isa/isa.h"
+#include "cirrus_vga_internal.h"
+
+#define TYPE_ISA_CIRRUS_VGA "isa-cirrus-vga"
+#define ISA_CIRRUS_VGA(obj) \
+ OBJECT_CHECK(ISACirrusVGAState, (obj), TYPE_ISA_CIRRUS_VGA)
+
+typedef struct ISACirrusVGAState {
+ ISADevice parent_obj;
+
+ CirrusVGAState cirrus_vga;
+} ISACirrusVGAState;
+
+static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
+{
+ ISADevice *isadev = ISA_DEVICE(dev);
+ ISACirrusVGAState *d = ISA_CIRRUS_VGA(dev);
+ VGACommonState *s = &d->cirrus_vga.vga;
+
+ /* follow real hardware, cirrus card emulated has 4 MB video memory.
+ Also accept 8 MB/16 MB for backward compatibility. */
+ if (s->vram_size_mb != 4 && s->vram_size_mb != 8 &&
+ s->vram_size_mb != 16) {
+ error_setg(errp, "Invalid cirrus_vga ram size '%u'",
+ s->vram_size_mb);
+ return;
+ }
+ s->global_vmstate = true;
+ vga_common_init(s, OBJECT(dev));
+ cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
+ isa_address_space(isadev),
+ isa_address_space_io(isadev));
+ s->con = graphic_console_init(dev, 0, s->hw_ops, s);
+ rom_add_vga(VGABIOS_CIRRUS_FILENAME);
+ /* XXX ISA-LFB support */
+ /* FIXME not qdev yet */
+}
+
+static Property isa_cirrus_vga_properties[] = {
+ DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState,
+ cirrus_vga.vga.vram_size_mb, 4),
+ DEFINE_PROP_BOOL("blitter", struct ISACirrusVGAState,
+ cirrus_vga.enable_blitter, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_cirrus_vga;
+ dc->realize = isa_cirrus_vga_realizefn;
+ dc->props = isa_cirrus_vga_properties;
+ set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
+}
+
+static const TypeInfo isa_cirrus_vga_info = {
+ .name = TYPE_ISA_CIRRUS_VGA,
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISACirrusVGAState),
+ .class_init = isa_cirrus_vga_class_init,
+};
+
+static void cirrus_vga_isa_register_types(void)
+{
+ type_register_static(&isa_cirrus_vga_info);
+}
+
+type_init(cirrus_vga_isa_register_types)
diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c
index c80397ea96..bdf5e1d4d4 100644
--- a/hw/display/edid-generate.c
+++ b/hw/display/edid-generate.c
@@ -223,7 +223,7 @@ static void edid_desc_timing(uint8_t *desc,
uint32_t clock = 75 * (xres + xblank) * (yres + yblank);
- *(uint32_t *)(desc) = cpu_to_le32(clock / 10000);
+ stl_le_p(desc, clock / 10000);
desc[2] = xres & 0xff;
desc[3] = xblank & 0xff;
@@ -301,7 +301,7 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
/* =============== set defaults =============== */
if (!info->vendor || strlen(info->vendor) != 3) {
- info->vendor = "EMU";
+ info->vendor = "RHT";
}
if (!info->name) {
info->name = "QEMU Monitor";
@@ -342,9 +342,9 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
(((info->vendor[2] - '@') & 0x1f) << 0));
uint16_t model_nr = 0x1234;
uint32_t serial_nr = info->serial ? atoi(info->serial) : 0;
- *(uint16_t *)(edid + 8) = cpu_to_be16(vendor_id);
- *(uint16_t *)(edid + 10) = cpu_to_le16(model_nr);
- *(uint32_t *)(edid + 12) = cpu_to_le32(serial_nr);
+ stw_be_p(edid + 8, vendor_id);
+ stw_le_p(edid + 10, model_nr);
+ stl_le_p(edid + 12, serial_nr);
/* manufacture week and year */
edid[16] = 42;
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 747986478f..9087db5dee 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -290,7 +290,7 @@ static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay)
}
cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST);
- if (cfg->count == 1) {
+ if (cfg != NULL && cfg->count == 1) {
qxl->guest_primary.resized = 1;
qxl->guest_head0_width = cfg->heads[0].width;
qxl->guest_head0_height = cfg->heads[0].height;
@@ -848,7 +848,7 @@ static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *
qxl->guest_primary.commands++;
qxl_track_command(qxl, ext);
qxl_log_command(qxl, "csr", ext);
- if (qxl->id == 0) {
+ if (qxl->have_vga) {
qxl_render_cursor(qxl, ext);
}
trace_qxl_ring_cursor_get(qxl->id, qxl_mode_to_string(qxl->mode));
@@ -1255,7 +1255,7 @@ static void qxl_soft_reset(PCIQXLDevice *d)
d->current_async = QXL_UNDEFINED_IO;
qemu_mutex_unlock(&d->async_lock);
- if (d->id == 0) {
+ if (d->have_vga) {
qxl_enter_vga_mode(d);
} else {
d->mode = QXL_MODE_UNDEFINED;
@@ -1893,7 +1893,31 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
trace_qxl_send_events_vm_stopped(d->id, events);
return;
}
- old_pending = atomic_fetch_or(&d->ram->int_pending, le_events);
+ /*
+ * Older versions of Spice forgot to define the QXLRam struct
+ * with the '__aligned__(4)' attribute. clang 7 and newer will
+ * thus warn that atomic_fetch_or(&d->ram->int_pending, ...)
+ * might be a misaligned atomic access, and will generate an
+ * out-of-line call for it, which results in a link error since
+ * we don't currently link against libatomic.
+ *
+ * In fact we set up d->ram in init_qxl_ram() so it always starts
+ * at a 4K boundary, so we know that &d->ram->int_pending is
+ * naturally aligned for a uint32_t. Newer Spice versions
+ * (with Spice commit beda5ec7a6848be20c0cac2a9a8ef2a41e8069c1)
+ * will fix the bug directly. To deal with older versions,
+ * we tell the compiler to assume the address really is aligned.
+ * Any compiler which cares about the misalignment will have
+ * __builtin_assume_aligned.
+ */
+#ifdef HAS_ASSUME_ALIGNED
+#define ALIGNED_UINT32_PTR(P) ((uint32_t *)__builtin_assume_aligned(P, 4))
+#else
+#define ALIGNED_UINT32_PTR(P) ((uint32_t *)P)
+#endif
+
+ old_pending = atomic_fetch_or(ALIGNED_UINT32_PTR(&d->ram->int_pending),
+ le_events);
if ((old_pending & le_events) == le_events) {
return;
}
@@ -2115,7 +2139,7 @@ static void qxl_realize_common(PCIQXLDevice *qxl, Error **errp)
memory_region_init_io(&qxl->io_bar, OBJECT(qxl), &qxl_io_ops, qxl,
"qxl-ioports", io_size);
- if (qxl->id == 0) {
+ if (qxl->have_vga) {
vga_dirty_log_start(&qxl->vga);
}
memory_region_set_flush_coalesced(&qxl->io_bar);
@@ -2147,7 +2171,7 @@ static void qxl_realize_common(PCIQXLDevice *qxl, Error **errp)
/* print pci bar details */
dprint(qxl, 1, "ram/%s: %" PRId64 " MB [region 0]\n",
- qxl->id == 0 ? "pri" : "sec", qxl->vga.vram_size / MiB);
+ qxl->have_vga ? "pri" : "sec", qxl->vga.vram_size / MiB);
dprint(qxl, 1, "vram/32: %" PRIx64 " MB [region 1]\n",
qxl->vram32_size / MiB);
dprint(qxl, 1, "vram/64: %" PRIx64 " MB %s\n",
@@ -2175,7 +2199,6 @@ static void qxl_realize_primary(PCIDevice *dev, Error **errp)
VGACommonState *vga = &qxl->vga;
Error *local_err = NULL;
- qxl->id = 0;
qxl_init_ramsize(qxl);
vga->vbe_size = qxl->vgamem_size;
vga->vram_size_mb = qxl->vga.vram_size / MiB;
@@ -2186,8 +2209,15 @@ static void qxl_realize_primary(PCIDevice *dev, Error **errp)
vga, "vga");
portio_list_set_flush_coalesced(&qxl->vga_port_list);
portio_list_add(&qxl->vga_port_list, pci_address_space_io(dev), 0x3b0);
+ qxl->have_vga = true;
vga->con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
+ qxl->id = qemu_console_get_index(vga->con); /* == channel_id */
+ if (qxl->id != 0) {
+ error_setg(errp, "primary qxl-vga device must be console 0 "
+ "(first display device on the command line)");
+ return;
+ }
qxl_realize_common(qxl, &local_err);
if (local_err) {
@@ -2202,15 +2232,14 @@ static void qxl_realize_primary(PCIDevice *dev, Error **errp)
static void qxl_realize_secondary(PCIDevice *dev, Error **errp)
{
- static int device_id = 1;
PCIQXLDevice *qxl = PCI_QXL(dev);
- qxl->id = device_id++;
qxl_init_ramsize(qxl);
memory_region_init_ram(&qxl->vga.vram, OBJECT(dev), "qxl.vgavram",
qxl->vga.vram_size, &error_fatal);
qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
+ qxl->id = qemu_console_get_index(qxl->vga.con); /* == channel_id */
qxl_realize_common(qxl, errp);
}
diff --git a/hw/display/qxl.h b/hw/display/qxl.h
index dd9c0522b7..6f9d1f21fa 100644
--- a/hw/display/qxl.h
+++ b/hw/display/qxl.h
@@ -34,6 +34,7 @@ typedef struct PCIQXLDevice {
PortioList vga_port_list;
SimpleSpiceDisplay ssd;
int id;
+ bool have_vga;
uint32_t debug;
uint32_t guestdebug;
uint32_t cmdlog;
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index b2786ee8d0..66f2459226 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -823,7 +823,7 @@ static void tcx_realizefn(DeviceState *dev, Error **errp)
ret = load_image_mr(fcode_filename, &s->rom);
g_free(fcode_filename);
if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) {
- error_report("tcx: could not load prom '%s'", TCX_ROM_FILE);
+ warn_report("tcx: could not load prom '%s'", TCX_ROM_FILE);
}
}
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index 24ca1b3e1f..a17c96e703 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -309,6 +309,14 @@ static void pci_secondary_vga_exit(PCIDevice *dev)
VGACommonState *s = &d->vga;
graphic_console_close(s->con);
+ memory_region_del_subregion(&d->mmio, &d->mrs[0]);
+ memory_region_del_subregion(&d->mmio, &d->mrs[1]);
+ if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_QEXT)) {
+ memory_region_del_subregion(&d->mmio, &d->mrs[2]);
+ }
+ if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_EDID)) {
+ memory_region_del_subregion(&d->mmio, &d->mrs[3]);
+ }
}
static void pci_secondary_vga_init(Object *obj)
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
index 6e4fa48a79..55c418eab5 100644
--- a/hw/display/vga_int.h
+++ b/hw/display/vga_int.h
@@ -166,7 +166,6 @@ MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
const MemoryRegionPortio **vbe_ports);
void vga_common_reset(VGACommonState *s);
-void vga_sync_dirty_bitmap(VGACommonState *s);
void vga_dirty_log_start(VGACommonState *s);
void vga_dirty_log_stop(VGACommonState *s);
diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c
index 564b938e3a..31e09942b5 100644
--- a/hw/hppa/dino.c
+++ b/hw/hppa/dino.c
@@ -488,17 +488,10 @@ PCIBus *dino_init(MemoryRegion *addr_space,
return b;
}
-static int dino_pcihost_init(SysBusDevice *dev)
-{
- return 0;
-}
-
static void dino_pcihost_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- k->init = dino_pcihost_init;
dc->vmsd = &vmstate_dino;
}
diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c
index 0fb8fb877e..ac6dd7f6ab 100644
--- a/hw/hppa/machine.c
+++ b/hw/hppa/machine.c
@@ -191,7 +191,7 @@ static void machine_hppa_init(MachineState *machine)
if (initrd_filename) {
ram_addr_t initrd_base;
- long initrd_size;
+ int64_t initrd_size;
initrd_size = get_image_size(initrd_filename);
if (initrd_size < 0) {
diff --git a/hw/hyperv/Makefile.objs b/hw/hyperv/Makefile.objs
new file mode 100644
index 0000000000..edaca2f763
--- /dev/null
+++ b/hw/hyperv/Makefile.objs
@@ -0,0 +1,2 @@
+obj-y += hyperv.o
+obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
new file mode 100644
index 0000000000..a28e7249d8
--- /dev/null
+++ b/hw/hyperv/hyperv.c
@@ -0,0 +1,654 @@
+/*
+ * Hyper-V guest/hypervisor interaction
+ *
+ * Copyright (c) 2015-2018 Virtuozzo International GmbH.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qapi/error.h"
+#include "exec/address-spaces.h"
+#include "sysemu/kvm.h"
+#include "qemu/bitops.h"
+#include "qemu/error-report.h"
+#include "qemu/queue.h"
+#include "qemu/rcu.h"
+#include "qemu/rcu_queue.h"
+#include "hw/hyperv/hyperv.h"
+
+typedef struct SynICState {
+ DeviceState parent_obj;
+
+ CPUState *cs;
+
+ bool enabled;
+ hwaddr msg_page_addr;
+ hwaddr event_page_addr;
+ MemoryRegion msg_page_mr;
+ MemoryRegion event_page_mr;
+ struct hyperv_message_page *msg_page;
+ struct hyperv_event_flags_page *event_page;
+} SynICState;
+
+#define TYPE_SYNIC "hyperv-synic"
+#define SYNIC(obj) OBJECT_CHECK(SynICState, (obj), TYPE_SYNIC)
+
+static SynICState *get_synic(CPUState *cs)
+{
+ return SYNIC(object_resolve_path_component(OBJECT(cs), "synic"));
+}
+
+static void synic_update(SynICState *synic, bool enable,
+ hwaddr msg_page_addr, hwaddr event_page_addr)
+{
+
+ synic->enabled = enable;
+ if (synic->msg_page_addr != msg_page_addr) {
+ if (synic->msg_page_addr) {
+ memory_region_del_subregion(get_system_memory(),
+ &synic->msg_page_mr);
+ }
+ if (msg_page_addr) {
+ memory_region_add_subregion(get_system_memory(), msg_page_addr,
+ &synic->msg_page_mr);
+ }
+ synic->msg_page_addr = msg_page_addr;
+ }
+ if (synic->event_page_addr != event_page_addr) {
+ if (synic->event_page_addr) {
+ memory_region_del_subregion(get_system_memory(),
+ &synic->event_page_mr);
+ }
+ if (event_page_addr) {
+ memory_region_add_subregion(get_system_memory(), event_page_addr,
+ &synic->event_page_mr);
+ }
+ synic->event_page_addr = event_page_addr;
+ }
+}
+
+void hyperv_synic_update(CPUState *cs, bool enable,
+ hwaddr msg_page_addr, hwaddr event_page_addr)
+{
+ SynICState *synic = get_synic(cs);
+
+ if (!synic) {
+ return;
+ }
+
+ synic_update(synic, enable, msg_page_addr, event_page_addr);
+}
+
+static void synic_realize(DeviceState *dev, Error **errp)
+{
+ Object *obj = OBJECT(dev);
+ SynICState *synic = SYNIC(dev);
+ char *msgp_name, *eventp_name;
+ uint32_t vp_index;
+
+ /* memory region names have to be globally unique */
+ vp_index = hyperv_vp_index(synic->cs);
+ msgp_name = g_strdup_printf("synic-%u-msg-page", vp_index);
+ eventp_name = g_strdup_printf("synic-%u-event-page", vp_index);
+
+ memory_region_init_ram(&synic->msg_page_mr, obj, msgp_name,
+ sizeof(*synic->msg_page), &error_abort);
+ memory_region_init_ram(&synic->event_page_mr, obj, eventp_name,
+ sizeof(*synic->event_page), &error_abort);
+ synic->msg_page = memory_region_get_ram_ptr(&synic->msg_page_mr);
+ synic->event_page = memory_region_get_ram_ptr(&synic->event_page_mr);
+
+ g_free(msgp_name);
+ g_free(eventp_name);
+}
+static void synic_reset(DeviceState *dev)
+{
+ SynICState *synic = SYNIC(dev);
+ memset(synic->msg_page, 0, sizeof(*synic->msg_page));
+ memset(synic->event_page, 0, sizeof(*synic->event_page));
+ synic_update(synic, false, 0, 0);
+}
+
+static void synic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = synic_realize;
+ dc->reset = synic_reset;
+ dc->user_creatable = false;
+}
+
+void hyperv_synic_add(CPUState *cs)
+{
+ Object *obj;
+ SynICState *synic;
+
+ obj = object_new(TYPE_SYNIC);
+ synic = SYNIC(obj);
+ synic->cs = cs;
+ object_property_add_child(OBJECT(cs), "synic", obj, &error_abort);
+ object_unref(obj);
+ object_property_set_bool(obj, true, "realized", &error_abort);
+}
+
+void hyperv_synic_reset(CPUState *cs)
+{
+ device_reset(DEVICE(get_synic(cs)));
+}
+
+static const TypeInfo synic_type_info = {
+ .name = TYPE_SYNIC,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SynICState),
+ .class_init = synic_class_init,
+};
+
+static void synic_register_types(void)
+{
+ type_register_static(&synic_type_info);
+}
+
+type_init(synic_register_types)
+
+/*
+ * KVM has its own message producers (SynIC timers). To guarantee
+ * serialization with both KVM vcpu and the guest cpu, the messages are first
+ * staged in an intermediate area and then posted to the SynIC message page in
+ * the vcpu thread.
+ */
+typedef struct HvSintStagedMessage {
+ /* message content staged by hyperv_post_msg */
+ struct hyperv_message msg;
+ /* callback + data (r/o) to complete the processing in a BH */
+ HvSintMsgCb cb;
+ void *cb_data;
+ /* message posting status filled by cpu_post_msg */
+ int status;
+ /* passing the buck: */
+ enum {
+ /* initial state */
+ HV_STAGED_MSG_FREE,
+ /*
+ * hyperv_post_msg (e.g. in main loop) grabs the staged area (FREE ->
+ * BUSY), copies msg, and schedules cpu_post_msg on the assigned cpu
+ */
+ HV_STAGED_MSG_BUSY,
+ /*
+ * cpu_post_msg (vcpu thread) tries to copy staged msg to msg slot,
+ * notify the guest, records the status, marks the posting done (BUSY
+ * -> POSTED), and schedules sint_msg_bh BH
+ */
+ HV_STAGED_MSG_POSTED,
+ /*
+ * sint_msg_bh (BH) verifies that the posting is done, runs the
+ * callback, and starts over (POSTED -> FREE)
+ */
+ } state;
+} HvSintStagedMessage;
+
+struct HvSintRoute {
+ uint32_t sint;
+ SynICState *synic;
+ int gsi;
+ EventNotifier sint_set_notifier;
+ EventNotifier sint_ack_notifier;
+
+ HvSintStagedMessage *staged_msg;
+
+ unsigned refcount;
+};
+
+static CPUState *hyperv_find_vcpu(uint32_t vp_index)
+{
+ CPUState *cs = qemu_get_cpu(vp_index);
+ assert(hyperv_vp_index(cs) == vp_index);
+ return cs;
+}
+
+/*
+ * BH to complete the processing of a staged message.
+ */
+static void sint_msg_bh(void *opaque)
+{
+ HvSintRoute *sint_route = opaque;
+ HvSintStagedMessage *staged_msg = sint_route->staged_msg;
+
+ if (atomic_read(&staged_msg->state) != HV_STAGED_MSG_POSTED) {
+ /* status nor ready yet (spurious ack from guest?), ignore */
+ return;
+ }
+
+ staged_msg->cb(staged_msg->cb_data, staged_msg->status);
+ staged_msg->status = 0;
+
+ /* staged message processing finished, ready to start over */
+ atomic_set(&staged_msg->state, HV_STAGED_MSG_FREE);
+ /* drop the reference taken in hyperv_post_msg */
+ hyperv_sint_route_unref(sint_route);
+}
+
+/*
+ * Worker to transfer the message from the staging area into the SynIC message
+ * page in vcpu context.
+ */
+static void cpu_post_msg(CPUState *cs, run_on_cpu_data data)
+{
+ HvSintRoute *sint_route = data.host_ptr;
+ HvSintStagedMessage *staged_msg = sint_route->staged_msg;
+ SynICState *synic = sint_route->synic;
+ struct hyperv_message *dst_msg;
+ bool wait_for_sint_ack = false;
+
+ assert(staged_msg->state == HV_STAGED_MSG_BUSY);
+
+ if (!synic->enabled || !synic->msg_page_addr) {
+ staged_msg->status = -ENXIO;
+ goto posted;
+ }
+
+ dst_msg = &synic->msg_page->slot[sint_route->sint];
+
+ if (dst_msg->header.message_type != HV_MESSAGE_NONE) {
+ dst_msg->header.message_flags |= HV_MESSAGE_FLAG_PENDING;
+ staged_msg->status = -EAGAIN;
+ wait_for_sint_ack = true;
+ } else {
+ memcpy(dst_msg, &staged_msg->msg, sizeof(*dst_msg));
+ staged_msg->status = hyperv_sint_route_set_sint(sint_route);
+ }
+
+ memory_region_set_dirty(&synic->msg_page_mr, 0, sizeof(*synic->msg_page));
+
+posted:
+ atomic_set(&staged_msg->state, HV_STAGED_MSG_POSTED);
+ /*
+ * Notify the msg originator of the progress made; if the slot was busy we
+ * set msg_pending flag in it so it will be the guest who will do EOM and
+ * trigger the notification from KVM via sint_ack_notifier
+ */
+ if (!wait_for_sint_ack) {
+ aio_bh_schedule_oneshot(qemu_get_aio_context(), sint_msg_bh,
+ sint_route);
+ }
+}
+
+/*
+ * Post a Hyper-V message to the staging area, for delivery to guest in the
+ * vcpu thread.
+ */
+int hyperv_post_msg(HvSintRoute *sint_route, struct hyperv_message *src_msg)
+{
+ HvSintStagedMessage *staged_msg = sint_route->staged_msg;
+
+ assert(staged_msg);
+
+ /* grab the staging area */
+ if (atomic_cmpxchg(&staged_msg->state, HV_STAGED_MSG_FREE,
+ HV_STAGED_MSG_BUSY) != HV_STAGED_MSG_FREE) {
+ return -EAGAIN;
+ }
+
+ memcpy(&staged_msg->msg, src_msg, sizeof(*src_msg));
+
+ /* hold a reference on sint_route until the callback is finished */
+ hyperv_sint_route_ref(sint_route);
+
+ /* schedule message posting attempt in vcpu thread */
+ async_run_on_cpu(sint_route->synic->cs, cpu_post_msg,
+ RUN_ON_CPU_HOST_PTR(sint_route));
+ return 0;
+}
+
+static void sint_ack_handler(EventNotifier *notifier)
+{
+ HvSintRoute *sint_route = container_of(notifier, HvSintRoute,
+ sint_ack_notifier);
+ event_notifier_test_and_clear(notifier);
+
+ /*
+ * the guest consumed the previous message so complete the current one with
+ * -EAGAIN and let the msg originator retry
+ */
+ aio_bh_schedule_oneshot(qemu_get_aio_context(), sint_msg_bh, sint_route);
+}
+
+/*
+ * Set given event flag for a given sint on a given vcpu, and signal the sint.
+ */
+int hyperv_set_event_flag(HvSintRoute *sint_route, unsigned eventno)
+{
+ int ret;
+ SynICState *synic = sint_route->synic;
+ unsigned long *flags, set_mask;
+ unsigned set_idx;
+
+ if (eventno > HV_EVENT_FLAGS_COUNT) {
+ return -EINVAL;
+ }
+ if (!synic->enabled || !synic->event_page_addr) {
+ return -ENXIO;
+ }
+
+ set_idx = BIT_WORD(eventno);
+ set_mask = BIT_MASK(eventno);
+ flags = synic->event_page->slot[sint_route->sint].flags;
+
+ if ((atomic_fetch_or(&flags[set_idx], set_mask) & set_mask) != set_mask) {
+ memory_region_set_dirty(&synic->event_page_mr, 0,
+ sizeof(*synic->event_page));
+ ret = hyperv_sint_route_set_sint(sint_route);
+ } else {
+ ret = 0;
+ }
+ return ret;
+}
+
+HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint,
+ HvSintMsgCb cb, void *cb_data)
+{
+ HvSintRoute *sint_route;
+ EventNotifier *ack_notifier;
+ int r, gsi;
+ CPUState *cs;
+ SynICState *synic;
+
+ cs = hyperv_find_vcpu(vp_index);
+ if (!cs) {
+ return NULL;
+ }
+
+ synic = get_synic(cs);
+ if (!synic) {
+ return NULL;
+ }
+
+ sint_route = g_new0(HvSintRoute, 1);
+ r = event_notifier_init(&sint_route->sint_set_notifier, false);
+ if (r) {
+ goto err;
+ }
+
+
+ ack_notifier = cb ? &sint_route->sint_ack_notifier : NULL;
+ if (ack_notifier) {
+ sint_route->staged_msg = g_new0(HvSintStagedMessage, 1);
+ sint_route->staged_msg->cb = cb;
+ sint_route->staged_msg->cb_data = cb_data;
+
+ r = event_notifier_init(ack_notifier, false);
+ if (r) {
+ goto err_sint_set_notifier;
+ }
+
+ event_notifier_set_handler(ack_notifier, sint_ack_handler);
+ }
+
+ gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vp_index, sint);
+ if (gsi < 0) {
+ goto err_gsi;
+ }
+
+ r = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state,
+ &sint_route->sint_set_notifier,
+ ack_notifier, gsi);
+ if (r) {
+ goto err_irqfd;
+ }
+ sint_route->gsi = gsi;
+ sint_route->synic = synic;
+ sint_route->sint = sint;
+ sint_route->refcount = 1;
+
+ return sint_route;
+
+err_irqfd:
+ kvm_irqchip_release_virq(kvm_state, gsi);
+err_gsi:
+ if (ack_notifier) {
+ event_notifier_set_handler(ack_notifier, NULL);
+ event_notifier_cleanup(ack_notifier);
+ g_free(sint_route->staged_msg);
+ }
+err_sint_set_notifier:
+ event_notifier_cleanup(&sint_route->sint_set_notifier);
+err:
+ g_free(sint_route);
+
+ return NULL;
+}
+
+void hyperv_sint_route_ref(HvSintRoute *sint_route)
+{
+ sint_route->refcount++;
+}
+
+void hyperv_sint_route_unref(HvSintRoute *sint_route)
+{
+ if (!sint_route) {
+ return;
+ }
+
+ assert(sint_route->refcount > 0);
+
+ if (--sint_route->refcount) {
+ return;
+ }
+
+ kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state,
+ &sint_route->sint_set_notifier,
+ sint_route->gsi);
+ kvm_irqchip_release_virq(kvm_state, sint_route->gsi);
+ if (sint_route->staged_msg) {
+ event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL);
+ event_notifier_cleanup(&sint_route->sint_ack_notifier);
+ g_free(sint_route->staged_msg);
+ }
+ event_notifier_cleanup(&sint_route->sint_set_notifier);
+ g_free(sint_route);
+}
+
+int hyperv_sint_route_set_sint(HvSintRoute *sint_route)
+{
+ return event_notifier_set(&sint_route->sint_set_notifier);
+}
+
+typedef struct MsgHandler {
+ struct rcu_head rcu;
+ QLIST_ENTRY(MsgHandler) link;
+ uint32_t conn_id;
+ HvMsgHandler handler;
+ void *data;
+} MsgHandler;
+
+typedef struct EventFlagHandler {
+ struct rcu_head rcu;
+ QLIST_ENTRY(EventFlagHandler) link;
+ uint32_t conn_id;
+ EventNotifier *notifier;
+} EventFlagHandler;
+
+static QLIST_HEAD(, MsgHandler) msg_handlers;
+static QLIST_HEAD(, EventFlagHandler) event_flag_handlers;
+static QemuMutex handlers_mutex;
+
+static void __attribute__((constructor)) hv_init(void)
+{
+ QLIST_INIT(&msg_handlers);
+ QLIST_INIT(&event_flag_handlers);
+ qemu_mutex_init(&handlers_mutex);
+}
+
+int hyperv_set_msg_handler(uint32_t conn_id, HvMsgHandler handler, void *data)
+{
+ int ret;
+ MsgHandler *mh;
+
+ qemu_mutex_lock(&handlers_mutex);
+ QLIST_FOREACH(mh, &msg_handlers, link) {
+ if (mh->conn_id == conn_id) {
+ if (handler) {
+ ret = -EEXIST;
+ } else {
+ QLIST_REMOVE_RCU(mh, link);
+ g_free_rcu(mh, rcu);
+ ret = 0;
+ }
+ goto unlock;
+ }
+ }
+
+ if (handler) {
+ mh = g_new(MsgHandler, 1);
+ mh->conn_id = conn_id;
+ mh->handler = handler;
+ mh->data = data;
+ QLIST_INSERT_HEAD_RCU(&msg_handlers, mh, link);
+ ret = 0;
+ } else {
+ ret = -ENOENT;
+ }
+unlock:
+ qemu_mutex_unlock(&handlers_mutex);
+ return ret;
+}
+
+uint16_t hyperv_hcall_post_message(uint64_t param, bool fast)
+{
+ uint16_t ret;
+ hwaddr len;
+ struct hyperv_post_message_input *msg;
+ MsgHandler *mh;
+
+ if (fast) {
+ return HV_STATUS_INVALID_HYPERCALL_CODE;
+ }
+ if (param & (__alignof__(*msg) - 1)) {
+ return HV_STATUS_INVALID_ALIGNMENT;
+ }
+
+ len = sizeof(*msg);
+ msg = cpu_physical_memory_map(param, &len, 0);
+ if (len < sizeof(*msg)) {
+ ret = HV_STATUS_INSUFFICIENT_MEMORY;
+ goto unmap;
+ }
+ if (msg->payload_size > sizeof(msg->payload)) {
+ ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
+ goto unmap;
+ }
+
+ ret = HV_STATUS_INVALID_CONNECTION_ID;
+ rcu_read_lock();
+ QLIST_FOREACH_RCU(mh, &msg_handlers, link) {
+ if (mh->conn_id == (msg->connection_id & HV_CONNECTION_ID_MASK)) {
+ ret = mh->handler(msg, mh->data);
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+unmap:
+ cpu_physical_memory_unmap(msg, len, 0, 0);
+ return ret;
+}
+
+static int set_event_flag_handler(uint32_t conn_id, EventNotifier *notifier)
+{
+ int ret;
+ EventFlagHandler *handler;
+
+ qemu_mutex_lock(&handlers_mutex);
+ QLIST_FOREACH(handler, &event_flag_handlers, link) {
+ if (handler->conn_id == conn_id) {
+ if (notifier) {
+ ret = -EEXIST;
+ } else {
+ QLIST_REMOVE_RCU(handler, link);
+ g_free_rcu(handler, rcu);
+ ret = 0;
+ }
+ goto unlock;
+ }
+ }
+
+ if (notifier) {
+ handler = g_new(EventFlagHandler, 1);
+ handler->conn_id = conn_id;
+ handler->notifier = notifier;
+ QLIST_INSERT_HEAD_RCU(&event_flag_handlers, handler, link);
+ ret = 0;
+ } else {
+ ret = -ENOENT;
+ }
+unlock:
+ qemu_mutex_unlock(&handlers_mutex);
+ return ret;
+}
+
+static bool process_event_flags_userspace;
+
+int hyperv_set_event_flag_handler(uint32_t conn_id, EventNotifier *notifier)
+{
+ if (!process_event_flags_userspace &&
+ !kvm_check_extension(kvm_state, KVM_CAP_HYPERV_EVENTFD)) {
+ process_event_flags_userspace = true;
+
+ warn_report("Hyper-V event signaling is not supported by this kernel; "
+ "using slower userspace hypercall processing");
+ }
+
+ if (!process_event_flags_userspace) {
+ struct kvm_hyperv_eventfd hvevfd = {
+ .conn_id = conn_id,
+ .fd = notifier ? event_notifier_get_fd(notifier) : -1,
+ .flags = notifier ? 0 : KVM_HYPERV_EVENTFD_DEASSIGN,
+ };
+
+ return kvm_vm_ioctl(kvm_state, KVM_HYPERV_EVENTFD, &hvevfd);
+ }
+ return set_event_flag_handler(conn_id, notifier);
+}
+
+uint16_t hyperv_hcall_signal_event(uint64_t param, bool fast)
+{
+ uint16_t ret;
+ EventFlagHandler *handler;
+
+ if (unlikely(!fast)) {
+ hwaddr addr = param;
+
+ if (addr & (__alignof__(addr) - 1)) {
+ return HV_STATUS_INVALID_ALIGNMENT;
+ }
+
+ param = ldq_phys(&address_space_memory, addr);
+ }
+
+ /*
+ * Per spec, bits 32-47 contain the extra "flag number". However, we
+ * have no use for it, and in all known usecases it is zero, so just
+ * report lookup failure if it isn't.
+ */
+ if (param & 0xffff00000000ULL) {
+ return HV_STATUS_INVALID_PORT_ID;
+ }
+ /* remaining bits are reserved-zero */
+ if (param & ~HV_CONNECTION_ID_MASK) {
+ return HV_STATUS_INVALID_HYPERCALL_INPUT;
+ }
+
+ ret = HV_STATUS_INVALID_CONNECTION_ID;
+ rcu_read_lock();
+ QLIST_FOREACH_RCU(handler, &event_flag_handlers, link) {
+ if (handler->conn_id == param) {
+ event_notifier_set(handler->notifier);
+ ret = 0;
+ break;
+ }
+ }
+ rcu_read_unlock();
+ return ret;
+}
diff --git a/hw/hyperv/hyperv_testdev.c b/hw/hyperv/hyperv_testdev.c
new file mode 100644
index 0000000000..4880333cf5
--- /dev/null
+++ b/hw/hyperv/hyperv_testdev.c
@@ -0,0 +1,327 @@
+/*
+ * QEMU KVM Hyper-V test device to support Hyper-V kvm-unit-tests
+ *
+ * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
+ *
+ * Authors:
+ * Andrey Smetanin <asmetanin@virtuozzo.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu/queue.h"
+#include "hw/qdev.h"
+#include "hw/isa/isa.h"
+#include "hw/hyperv/hyperv.h"
+
+typedef struct TestSintRoute {
+ QLIST_ENTRY(TestSintRoute) le;
+ uint8_t vp_index;
+ uint8_t sint;
+ HvSintRoute *sint_route;
+} TestSintRoute;
+
+typedef struct TestMsgConn {
+ QLIST_ENTRY(TestMsgConn) le;
+ uint8_t conn_id;
+ HvSintRoute *sint_route;
+ struct hyperv_message msg;
+} TestMsgConn;
+
+typedef struct TestEvtConn {
+ QLIST_ENTRY(TestEvtConn) le;
+ uint8_t conn_id;
+ HvSintRoute *sint_route;
+ EventNotifier notifier;
+} TestEvtConn;
+
+struct HypervTestDev {
+ ISADevice parent_obj;
+ MemoryRegion sint_control;
+ QLIST_HEAD(, TestSintRoute) sint_routes;
+ QLIST_HEAD(, TestMsgConn) msg_conns;
+ QLIST_HEAD(, TestEvtConn) evt_conns;
+};
+typedef struct HypervTestDev HypervTestDev;
+
+#define TYPE_HYPERV_TEST_DEV "hyperv-testdev"
+#define HYPERV_TEST_DEV(obj) \
+ OBJECT_CHECK(HypervTestDev, (obj), TYPE_HYPERV_TEST_DEV)
+
+enum {
+ HV_TEST_DEV_SINT_ROUTE_CREATE = 1,
+ HV_TEST_DEV_SINT_ROUTE_DESTROY,
+ HV_TEST_DEV_SINT_ROUTE_SET_SINT,
+ HV_TEST_DEV_MSG_CONN_CREATE,
+ HV_TEST_DEV_MSG_CONN_DESTROY,
+ HV_TEST_DEV_EVT_CONN_CREATE,
+ HV_TEST_DEV_EVT_CONN_DESTROY,
+};
+
+static void sint_route_create(HypervTestDev *dev,
+ uint8_t vp_index, uint8_t sint)
+{
+ TestSintRoute *sint_route;
+
+ sint_route = g_new0(TestSintRoute, 1);
+ assert(sint_route);
+
+ sint_route->vp_index = vp_index;
+ sint_route->sint = sint;
+
+ sint_route->sint_route = hyperv_sint_route_new(vp_index, sint, NULL, NULL);
+ assert(sint_route->sint_route);
+
+ QLIST_INSERT_HEAD(&dev->sint_routes, sint_route, le);
+}
+
+static TestSintRoute *sint_route_find(HypervTestDev *dev,
+ uint8_t vp_index, uint8_t sint)
+{
+ TestSintRoute *sint_route;
+
+ QLIST_FOREACH(sint_route, &dev->sint_routes, le) {
+ if (sint_route->vp_index == vp_index && sint_route->sint == sint) {
+ return sint_route;
+ }
+ }
+ assert(false);
+ return NULL;
+}
+
+static void sint_route_destroy(HypervTestDev *dev,
+ uint8_t vp_index, uint8_t sint)
+{
+ TestSintRoute *sint_route;
+
+ sint_route = sint_route_find(dev, vp_index, sint);
+ QLIST_REMOVE(sint_route, le);
+ hyperv_sint_route_unref(sint_route->sint_route);
+ g_free(sint_route);
+}
+
+static void sint_route_set_sint(HypervTestDev *dev,
+ uint8_t vp_index, uint8_t sint)
+{
+ TestSintRoute *sint_route;
+
+ sint_route = sint_route_find(dev, vp_index, sint);
+
+ hyperv_sint_route_set_sint(sint_route->sint_route);
+}
+
+static void msg_retry(void *opaque)
+{
+ TestMsgConn *conn = opaque;
+ assert(!hyperv_post_msg(conn->sint_route, &conn->msg));
+}
+
+static void msg_cb(void *data, int status)
+{
+ TestMsgConn *conn = data;
+
+ if (!status) {
+ return;
+ }
+
+ assert(status == -EAGAIN);
+
+ aio_bh_schedule_oneshot(qemu_get_aio_context(), msg_retry, conn);
+}
+
+static uint16_t msg_handler(const struct hyperv_post_message_input *msg,
+ void *data)
+{
+ int ret;
+ TestMsgConn *conn = data;
+
+ /* post the same message we've got */
+ conn->msg.header.message_type = msg->message_type;
+ assert(msg->payload_size < sizeof(conn->msg.payload));
+ conn->msg.header.payload_size = msg->payload_size;
+ memcpy(&conn->msg.payload, msg->payload, msg->payload_size);
+
+ ret = hyperv_post_msg(conn->sint_route, &conn->msg);
+
+ switch (ret) {
+ case 0:
+ return HV_STATUS_SUCCESS;
+ case -EAGAIN:
+ return HV_STATUS_INSUFFICIENT_BUFFERS;
+ default:
+ return HV_STATUS_INVALID_HYPERCALL_INPUT;
+ }
+}
+
+static void msg_conn_create(HypervTestDev *dev, uint8_t vp_index,
+ uint8_t sint, uint8_t conn_id)
+{
+ TestMsgConn *conn;
+
+ conn = g_new0(TestMsgConn, 1);
+ assert(conn);
+
+ conn->conn_id = conn_id;
+
+ conn->sint_route = hyperv_sint_route_new(vp_index, sint, msg_cb, conn);
+ assert(conn->sint_route);
+
+ assert(!hyperv_set_msg_handler(conn->conn_id, msg_handler, conn));
+
+ QLIST_INSERT_HEAD(&dev->msg_conns, conn, le);
+}
+
+static void msg_conn_destroy(HypervTestDev *dev, uint8_t conn_id)
+{
+ TestMsgConn *conn;
+
+ QLIST_FOREACH(conn, &dev->msg_conns, le) {
+ if (conn->conn_id == conn_id) {
+ QLIST_REMOVE(conn, le);
+ hyperv_set_msg_handler(conn->conn_id, NULL, NULL);
+ hyperv_sint_route_unref(conn->sint_route);
+ g_free(conn);
+ return;
+ }
+ }
+ assert(false);
+}
+
+static void evt_conn_handler(EventNotifier *notifier)
+{
+ TestEvtConn *conn = container_of(notifier, TestEvtConn, notifier);
+
+ event_notifier_test_and_clear(notifier);
+
+ /* signal the same event flag we've got */
+ assert(!hyperv_set_event_flag(conn->sint_route, conn->conn_id));
+}
+
+static void evt_conn_create(HypervTestDev *dev, uint8_t vp_index,
+ uint8_t sint, uint8_t conn_id)
+{
+ TestEvtConn *conn;
+
+ conn = g_new0(TestEvtConn, 1);
+ assert(conn);
+
+ conn->conn_id = conn_id;
+
+ conn->sint_route = hyperv_sint_route_new(vp_index, sint, NULL, NULL);
+ assert(conn->sint_route);
+
+ assert(!event_notifier_init(&conn->notifier, false));
+
+ event_notifier_set_handler(&conn->notifier, evt_conn_handler);
+
+ assert(!hyperv_set_event_flag_handler(conn_id, &conn->notifier));
+
+ QLIST_INSERT_HEAD(&dev->evt_conns, conn, le);
+}
+
+static void evt_conn_destroy(HypervTestDev *dev, uint8_t conn_id)
+{
+ TestEvtConn *conn;
+
+ QLIST_FOREACH(conn, &dev->evt_conns, le) {
+ if (conn->conn_id == conn_id) {
+ QLIST_REMOVE(conn, le);
+ hyperv_set_event_flag_handler(conn->conn_id, NULL);
+ event_notifier_set_handler(&conn->notifier, NULL);
+ event_notifier_cleanup(&conn->notifier);
+ hyperv_sint_route_unref(conn->sint_route);
+ g_free(conn);
+ return;
+ }
+ }
+ assert(false);
+}
+
+static uint64_t hv_test_dev_read(void *opaque, hwaddr addr, unsigned size)
+{
+ return 0;
+}
+
+static void hv_test_dev_write(void *opaque, hwaddr addr, uint64_t data,
+ uint32_t len)
+{
+ HypervTestDev *dev = HYPERV_TEST_DEV(opaque);
+ uint8_t sint = data & 0xFF;
+ uint8_t vp_index = (data >> 8ULL) & 0xFF;
+ uint8_t ctl = (data >> 16ULL) & 0xFF;
+ uint8_t conn_id = (data >> 24ULL) & 0xFF;
+
+ switch (ctl) {
+ case HV_TEST_DEV_SINT_ROUTE_CREATE:
+ sint_route_create(dev, vp_index, sint);
+ break;
+ case HV_TEST_DEV_SINT_ROUTE_DESTROY:
+ sint_route_destroy(dev, vp_index, sint);
+ break;
+ case HV_TEST_DEV_SINT_ROUTE_SET_SINT:
+ sint_route_set_sint(dev, vp_index, sint);
+ break;
+ case HV_TEST_DEV_MSG_CONN_CREATE:
+ msg_conn_create(dev, vp_index, sint, conn_id);
+ break;
+ case HV_TEST_DEV_MSG_CONN_DESTROY:
+ msg_conn_destroy(dev, conn_id);
+ break;
+ case HV_TEST_DEV_EVT_CONN_CREATE:
+ evt_conn_create(dev, vp_index, sint, conn_id);
+ break;
+ case HV_TEST_DEV_EVT_CONN_DESTROY:
+ evt_conn_destroy(dev, conn_id);
+ break;
+ default:
+ break;
+ }
+}
+
+static const MemoryRegionOps synic_test_sint_ops = {
+ .read = hv_test_dev_read,
+ .write = hv_test_dev_write,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void hv_test_dev_realizefn(DeviceState *d, Error **errp)
+{
+ ISADevice *isa = ISA_DEVICE(d);
+ HypervTestDev *dev = HYPERV_TEST_DEV(d);
+ MemoryRegion *io = isa_address_space_io(isa);
+
+ QLIST_INIT(&dev->sint_routes);
+ QLIST_INIT(&dev->msg_conns);
+ QLIST_INIT(&dev->evt_conns);
+ memory_region_init_io(&dev->sint_control, OBJECT(dev),
+ &synic_test_sint_ops, dev,
+ "hyperv-testdev-ctl", 4);
+ memory_region_add_subregion(io, 0x3000, &dev->sint_control);
+}
+
+static void hv_test_dev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ dc->realize = hv_test_dev_realizefn;
+}
+
+static const TypeInfo hv_test_dev_info = {
+ .name = TYPE_HYPERV_TEST_DEV,
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(HypervTestDev),
+ .class_init = hv_test_dev_class_init,
+};
+
+static void hv_test_dev_register_types(void)
+{
+ type_register_static(&hv_test_dev_info);
+}
+type_init(hv_test_dev_register_types);
diff --git a/hw/i2c/i2c-ddc.c b/hw/i2c/i2c-ddc.c
index bec0c91e2d..be34fe072c 100644
--- a/hw/i2c/i2c-ddc.c
+++ b/hw/i2c/i2c-ddc.c
@@ -32,197 +32,6 @@
} \
} while (0)
-/* Structure defining a monitor's characteristics in a
- * readable format: this should be passed to build_edid_blob()
- * to convert it into the 128 byte binary EDID blob.
- * Not all bits of the EDID are customisable here.
- */
-struct EDIDData {
- char manuf_id[3]; /* three upper case letters */
- uint16_t product_id;
- uint32_t serial_no;
- uint8_t manuf_week;
- int manuf_year;
- uint8_t h_cm;
- uint8_t v_cm;
- uint8_t gamma;
- char monitor_name[14];
- char serial_no_string[14];
- /* Range limits */
- uint8_t vmin; /* Hz */
- uint8_t vmax; /* Hz */
- uint8_t hmin; /* kHz */
- uint8_t hmax; /* kHz */
- uint8_t pixclock; /* MHz / 10 */
- uint8_t timing_data[18];
-};
-
-typedef struct EDIDData EDIDData;
-
-/* EDID data for a simple LCD monitor */
-static const EDIDData lcd_edid = {
- /* The manuf_id ought really to be an assigned EISA ID */
- .manuf_id = "QMU",
- .product_id = 0,
- .serial_no = 1,
- .manuf_week = 1,
- .manuf_year = 2011,
- .h_cm = 40,
- .v_cm = 30,
- .gamma = 0x78,
- .monitor_name = "QEMU monitor",
- .serial_no_string = "1",
- .vmin = 40,
- .vmax = 120,
- .hmin = 30,
- .hmax = 100,
- .pixclock = 18,
- .timing_data = {
- /* Borrowed from a 21" LCD */
- 0x48, 0x3f, 0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40,
- 0xc0, 0x13, 0x00, 0x98, 0x32, 0x11, 0x00, 0x00, 0x1e
- }
-};
-
-static uint8_t manuf_char_to_int(char c)
-{
- return (c - 'A') & 0x1f;
-}
-
-static void write_ascii_descriptor_block(uint8_t *descblob, uint8_t blocktype,
- const char *string)
-{
- /* Write an EDID Descriptor Block of the "ascii string" type */
- int i;
- descblob[0] = descblob[1] = descblob[2] = descblob[4] = 0;
- descblob[3] = blocktype;
- /* The rest is 13 bytes of ASCII; if less then the rest must
- * be filled with newline then spaces
- */
- for (i = 5; i < 19; i++) {
- descblob[i] = string[i - 5];
- if (!descblob[i]) {
- break;
- }
- }
- if (i < 19) {
- descblob[i++] = '\n';
- }
- for ( ; i < 19; i++) {
- descblob[i] = ' ';
- }
-}
-
-static void write_range_limits_descriptor(const EDIDData *edid,
- uint8_t *descblob)
-{
- int i;
- descblob[0] = descblob[1] = descblob[2] = descblob[4] = 0;
- descblob[3] = 0xfd;
- descblob[5] = edid->vmin;
- descblob[6] = edid->vmax;
- descblob[7] = edid->hmin;
- descblob[8] = edid->hmax;
- descblob[9] = edid->pixclock;
- descblob[10] = 0;
- descblob[11] = 0xa;
- for (i = 12; i < 19; i++) {
- descblob[i] = 0x20;
- }
-}
-
-static void build_edid_blob(const EDIDData *edid, uint8_t *blob)
-{
- /* Write an EDID 1.3 format blob (128 bytes) based
- * on the EDIDData structure.
- */
- int i;
- uint8_t cksum;
-
- /* 00-07 : header */
- blob[0] = blob[7] = 0;
- for (i = 1 ; i < 7; i++) {
- blob[i] = 0xff;
- }
- /* 08-09 : manufacturer ID */
- blob[8] = (manuf_char_to_int(edid->manuf_id[0]) << 2)
- | (manuf_char_to_int(edid->manuf_id[1]) >> 3);
- blob[9] = (manuf_char_to_int(edid->manuf_id[1]) << 5)
- | manuf_char_to_int(edid->manuf_id[2]);
- /* 10-11 : product ID code */
- blob[10] = edid->product_id;
- blob[11] = edid->product_id >> 8;
- blob[12] = edid->serial_no;
- blob[13] = edid->serial_no >> 8;
- blob[14] = edid->serial_no >> 16;
- blob[15] = edid->serial_no >> 24;
- /* 16 : week of manufacture */
- blob[16] = edid->manuf_week;
- /* 17 : year of manufacture - 1990 */
- blob[17] = edid->manuf_year - 1990;
- /* 18, 19 : EDID version and revision */
- blob[18] = 1;
- blob[19] = 3;
- /* 20 - 24 : basic display parameters */
- /* We are always a digital display */
- blob[20] = 0x80;
- /* 21, 22 : max h/v size in cm */
- blob[21] = edid->h_cm;
- blob[22] = edid->v_cm;
- /* 23 : gamma (divide by 100 then add 1 for actual value) */
- blob[23] = edid->gamma;
- /* 24 feature support: no power management, RGB, preferred timing mode,
- * standard colour space
- */
- blob[24] = 0x0e;
- /* 25 - 34 : chromaticity coordinates. These are the
- * standard sRGB chromaticity values
- */
- blob[25] = 0xee;
- blob[26] = 0x91;
- blob[27] = 0xa3;
- blob[28] = 0x54;
- blob[29] = 0x4c;
- blob[30] = 0x99;
- blob[31] = 0x26;
- blob[32] = 0x0f;
- blob[33] = 0x50;
- blob[34] = 0x54;
- /* 35, 36 : Established timings: claim to support everything */
- blob[35] = blob[36] = 0xff;
- /* 37 : manufacturer's reserved timing: none */
- blob[37] = 0;
- /* 38 - 53 : standard timing identification
- * don't claim anything beyond what the 'established timings'
- * already provide. Unused slots must be (0x1, 0x1)
- */
- for (i = 38; i < 54; i++) {
- blob[i] = 0x1;
- }
- /* 54 - 71 : descriptor block 1 : must be preferred timing data */
- memcpy(blob + 54, edid->timing_data, 18);
- /* 72 - 89, 90 - 107, 108 - 125 : descriptor block 2, 3, 4
- * Order not important, but we must have a monitor name and a
- * range limits descriptor.
- */
- write_range_limits_descriptor(edid, blob + 72);
- write_ascii_descriptor_block(blob + 90, 0xfc, edid->monitor_name);
- write_ascii_descriptor_block(blob + 108, 0xff, edid->serial_no_string);
-
- /* 126 : extension flag */
- blob[126] = 0;
-
- cksum = 0;
- for (i = 0; i < 127; i++) {
- cksum += blob[i];
- }
- /* 127 : checksum */
- blob[127] = -cksum;
- if (DEBUG_I2CDDC) {
- qemu_hexdump((char *)blob, stdout, "", 128);
- }
-}
-
static void i2c_ddc_reset(DeviceState *ds)
{
I2CDDCState *s = I2CDDC(ds);
@@ -270,7 +79,8 @@ static int i2c_ddc_tx(I2CSlave *i2c, uint8_t data)
static void i2c_ddc_init(Object *obj)
{
I2CDDCState *s = I2CDDC(obj);
- build_edid_blob(&lcd_edid, s->edid_blob);
+
+ qemu_edid_generate(s->edid_blob, sizeof(s->edid_blob), &s->edid_info);
}
static const VMStateDescription vmstate_i2c_ddc = {
@@ -283,6 +93,11 @@ static const VMStateDescription vmstate_i2c_ddc = {
}
};
+static Property i2c_ddc_properties[] = {
+ DEFINE_EDID_PROPERTIES(I2CDDCState, edid_info),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void i2c_ddc_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -290,6 +105,7 @@ static void i2c_ddc_class_init(ObjectClass *oc, void *data)
dc->reset = i2c_ddc_reset;
dc->vmsd = &vmstate_i2c_ddc;
+ dc->props = i2c_ddc_properties;
isc->event = i2c_ddc_event;
isc->recv = i2c_ddc_rx;
isc->send = i2c_ddc_tx;
diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c
index 0bf1c60a06..25ea783bec 100644
--- a/hw/i386/kvm/clock.c
+++ b/hw/i386/kvm/clock.c
@@ -147,6 +147,15 @@ static void kvm_update_clock(KVMClockState *s)
s->clock_is_reliable = kvm_has_adjust_clock_stable();
}
+static void do_kvmclock_ctrl(CPUState *cpu, run_on_cpu_data data)
+{
+ int ret = kvm_vcpu_ioctl(cpu, KVM_KVMCLOCK_CTRL, 0);
+
+ if (ret && ret != -EINVAL) {
+ fprintf(stderr, "%s: %s\n", __func__, strerror(-ret));
+ }
+}
+
static void kvmclock_vm_state_change(void *opaque, int running,
RunState state)
{
@@ -183,13 +192,7 @@ static void kvmclock_vm_state_change(void *opaque, int running,
return;
}
CPU_FOREACH(cpu) {
- ret = kvm_vcpu_ioctl(cpu, KVM_KVMCLOCK_CTRL, 0);
- if (ret) {
- if (ret != -EINVAL) {
- fprintf(stderr, "%s: %s\n", __func__, strerror(-ret));
- }
- return;
- }
+ run_on_cpu(cpu, do_kvmclock_ctrl, RUN_ON_CPU_NULL);
}
} else {
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 03148450c8..f095725dba 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -838,7 +838,8 @@ static void load_linux(PCMachineState *pcms,
FWCfgState *fw_cfg)
{
uint16_t protocol;
- int setup_size, kernel_size, initrd_size = 0, cmdline_size;
+ int setup_size, kernel_size, cmdline_size;
+ int64_t initrd_size = 0;
int dtb_size, setup_data_offset;
uint32_t initrd_max;
uint8_t header[8192], *setup, *kernel, *initrd_data;
@@ -974,6 +975,10 @@ static void load_linux(PCMachineState *pcms,
fprintf(stderr, "qemu: error reading initrd %s: %s\n",
initrd_filename, strerror(errno));
exit(1);
+ } else if (initrd_size >= initrd_max) {
+ fprintf(stderr, "qemu: initrd is too large, cannot support."
+ "(max: %"PRIu32", need %"PRId64")\n", initrd_max, initrd_size);
+ exit(1);
}
initrd_addr = (initrd_max-initrd_size) & ~4095;
@@ -1699,7 +1704,7 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
return;
}
- pc_dimm_pre_plug(dev, MACHINE(hotplug_dev),
+ pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev),
pcmc->enforce_aligned_dimm ? NULL : &legacy_align, errp);
}
@@ -1711,7 +1716,7 @@ static void pc_memory_plug(HotplugHandler *hotplug_dev,
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
- pc_dimm_plug(dev, MACHINE(pcms), &local_err);
+ pc_dimm_plug(PC_DIMM(dev), MACHINE(pcms), &local_err);
if (local_err) {
goto out;
}
@@ -1771,7 +1776,7 @@ static void pc_memory_unplug(HotplugHandler *hotplug_dev,
goto out;
}
- pc_dimm_unplug(dev, MACHINE(pcms));
+ pc_dimm_unplug(PC_DIMM(dev), MACHINE(pcms));
object_unparent(OBJECT(dev));
out:
@@ -2204,8 +2209,9 @@ static void pc_machine_set_nvdimm_persistence(Object *obj, const char *value,
else if (strcmp(value, "mem-ctrl") == 0)
nvdimm_state->persistence = 2;
else {
- error_report("-machine nvdimm-persistence=%s: unsupported option", value);
- exit(EXIT_FAILURE);
+ error_setg(errp, "-machine nvdimm-persistence=%s: unsupported option",
+ value);
+ return;
}
g_free(nvdimm_state->persistence_string);
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 2c62efc536..04e22e751d 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -35,6 +35,7 @@
#include "sysemu/block-backend.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
+#include "sysemu/replay.h"
#include "hw/ide/internal.h"
#include "trace.h"
@@ -479,7 +480,7 @@ static void ide_issue_trim_cb(void *opaque, int ret)
done:
iocb->aiocb = NULL;
if (iocb->bh) {
- qemu_bh_schedule(iocb->bh);
+ replay_bh_schedule_event(iocb->bh);
}
}
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index fdfcadf9a1..6c43fc2912 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -914,7 +914,12 @@ static void ps2_common_post_load(PS2State *s)
uint8_t tmp_data[PS2_QUEUE_SIZE];
/* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
- size = (q->count < 0 || q->count > PS2_QUEUE_SIZE) ? 0 : q->count;
+ size = q->count;
+ if (q->count < 0) {
+ size = 0;
+ } else if (q->count > PS2_QUEUE_SIZE) {
+ size = PS2_QUEUE_SIZE;
+ }
/* move the queue elements to the start of data array */
for (i = 0; i < size; i++) {
@@ -929,7 +934,6 @@ static void ps2_common_post_load(PS2State *s)
q->rptr = 0;
q->wptr = (size == PS2_QUEUE_SIZE) ? 0 : size;
q->count = size;
- s->update_irq(s->update_arg, q->count != 0);
}
static void ps2_kbd_reset(void *opaque)
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 0d816fdd2c..0beefb05d4 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -1055,17 +1055,17 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
case 0xd5c: /* MMFR3. */
return cpu->id_mmfr3;
case 0xd60: /* ISAR0. */
- return cpu->id_isar0;
+ return cpu->isar.id_isar0;
case 0xd64: /* ISAR1. */
- return cpu->id_isar1;
+ return cpu->isar.id_isar1;
case 0xd68: /* ISAR2. */
- return cpu->id_isar2;
+ return cpu->isar.id_isar2;
case 0xd6c: /* ISAR3. */
- return cpu->id_isar3;
+ return cpu->isar.id_isar3;
case 0xd70: /* ISAR4. */
- return cpu->id_isar4;
+ return cpu->isar.id_isar4;
case 0xd74: /* ISAR5. */
- return cpu->id_isar5;
+ return cpu->isar.id_isar5;
case 0xd78: /* CLIDR */
return cpu->clidr;
case 0xd7c: /* CTR */
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index b6896ac4ce..4e529729b4 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -21,7 +21,7 @@
*/
#include "qemu/osdep.h"
-#include "qemu/error-report.h"
+#include "qapi/error.h"
#include "monitor/monitor.h"
#include "hw/hw.h"
#include "hw/i386/pc.h"
@@ -393,9 +393,9 @@ static void ioapic_realize(DeviceState *dev, Error **errp)
IOAPICCommonState *s = IOAPIC_COMMON(dev);
if (s->version != 0x11 && s->version != 0x20) {
- error_report("IOAPIC only supports version 0x11 or 0x20 "
- "(default: 0x%x).", IOAPIC_VER_DEF);
- exit(1);
+ error_setg(errp, "IOAPIC only supports version 0x11 or 0x20 "
+ "(default: 0x%x).", IOAPIC_VER_DEF);
+ return;
}
memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s,
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index c90c893228..406efee064 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -320,8 +320,9 @@ static void icp_realize(DeviceState *dev, Error **errp)
obj = object_property_get_link(OBJECT(dev), ICP_PROP_XICS, &err);
if (!obj) {
- error_propagate(errp, err);
- error_prepend(errp, "required link '" ICP_PROP_XICS "' not found: ");
+ error_propagate_prepend(errp, err,
+ "required link '" ICP_PROP_XICS
+ "' not found: ");
return;
}
@@ -329,8 +330,9 @@ static void icp_realize(DeviceState *dev, Error **errp)
obj = object_property_get_link(OBJECT(dev), ICP_PROP_CPU, &err);
if (!obj) {
- error_propagate(errp, err);
- error_prepend(errp, "required link '" ICP_PROP_CPU "' not found: ");
+ error_propagate_prepend(errp, err,
+ "required link '" ICP_PROP_CPU
+ "' not found: ");
return;
}
@@ -624,8 +626,9 @@ static void ics_base_realize(DeviceState *dev, Error **errp)
obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &err);
if (!obj) {
- error_propagate(errp, err);
- error_prepend(errp, "required link '" ICS_PROP_XICS "' not found: ");
+ error_propagate_prepend(errp, err,
+ "required link '" ICS_PROP_XICS
+ "' not found: ");
return;
}
ics->xics = XICS_FABRIC(obj);
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index 30c3769a20..e8fa9a53ae 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -198,17 +198,12 @@ static void ics_get_kvm_state(ICSState *ics)
{
uint64_t state;
int i;
- Error *local_err = NULL;
for (i = 0; i < ics->nr_irqs; i++) {
ICSIRQState *irq = &ics->irqs[i];
kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES,
- i + ics->offset, &state, false, &local_err);
- if (local_err) {
- error_report_err(local_err);
- exit(1);
- }
+ i + ics->offset, &state, false, &error_fatal);
irq->server = state & KVM_XICS_DESTINATION_MASK;
irq->saved_priority = (state >> KVM_XICS_PRIORITY_SHIFT)
diff --git a/hw/isa/Makefile.objs b/hw/isa/Makefile.objs
index 83e06f6c04..9e106df186 100644
--- a/hw/isa/Makefile.objs
+++ b/hw/isa/Makefile.objs
@@ -1,9 +1,10 @@
common-obj-$(CONFIG_ISA_BUS) += isa-bus.o
-common-obj-$(CONFIG_ISA_BUS) += isa-superio.o smc37c669-superio.o
+common-obj-$(CONFIG_ISA_BUS) += isa-superio.o
common-obj-$(CONFIG_APM) += apm.o
common-obj-$(CONFIG_I82378) += i82378.o
common-obj-$(CONFIG_PC87312) += pc87312.o
common-obj-$(CONFIG_PIIX4) += piix4.o
common-obj-$(CONFIG_VT82C686) += vt82c686.o
+common-obj-$(CONFIG_SMC37C669) += smc37c669-superio.o
obj-$(CONFIG_LPC_ICH9) += lpc_ich9.o
diff --git a/hw/mem/Makefile.objs b/hw/mem/Makefile.objs
index 10be4df2a2..3e2f7c5ca2 100644
--- a/hw/mem/Makefile.objs
+++ b/hw/mem/Makefile.objs
@@ -1,3 +1,3 @@
-common-obj-$(CONFIG_MEM_HOTPLUG) += pc-dimm.o
-common-obj-$(CONFIG_MEM_HOTPLUG) += memory-device.o
+common-obj-$(CONFIG_DIMM) += pc-dimm.o
+common-obj-$(CONFIG_MEM_DEVICE) += memory-device.o
common-obj-$(CONFIG_NVDIMM) += nvdimm.o
diff --git a/hw/mem/memory-device.c b/hw/mem/memory-device.c
index 6de4f70bb4..7de1ccd497 100644
--- a/hw/mem/memory-device.c
+++ b/hw/mem/memory-device.c
@@ -17,6 +17,7 @@
#include "qemu/range.h"
#include "hw/virtio/vhost.h"
#include "sysemu/kvm.h"
+#include "trace.h"
static gint memory_device_addr_sort(gconstpointer a, gconstpointer b)
{
@@ -57,10 +58,9 @@ static int memory_device_used_region_size(Object *obj, void *opaque)
if (object_dynamic_cast(obj, TYPE_MEMORY_DEVICE)) {
const DeviceState *dev = DEVICE(obj);
const MemoryDeviceState *md = MEMORY_DEVICE(obj);
- const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(obj);
if (dev->realized) {
- *size += mdc->get_region_size(md);
+ *size += memory_device_get_region_size(md, &error_abort);
}
}
@@ -87,16 +87,17 @@ static void memory_device_check_addable(MachineState *ms, uint64_t size,
memory_device_used_region_size(OBJECT(ms), &used_region_size);
if (used_region_size + size > ms->maxram_size - ms->ram_size) {
error_setg(errp, "not enough space, currently 0x%" PRIx64
- " in use of total hot pluggable 0x" RAM_ADDR_FMT,
+ " in use of total space for memory devices 0x" RAM_ADDR_FMT,
used_region_size, ms->maxram_size - ms->ram_size);
return;
}
}
-uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
- uint64_t align, uint64_t size,
- Error **errp)
+static uint64_t memory_device_get_free_addr(MachineState *ms,
+ const uint64_t *hint,
+ uint64_t align, uint64_t size,
+ Error **errp)
{
uint64_t address_space_start, address_space_end;
GSList *list = NULL, *item;
@@ -120,7 +121,7 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
/* address_space_start indicates the maximum alignment we expect */
if (QEMU_ALIGN_UP(address_space_start, align) != address_space_start) {
- error_setg(errp, "the alignment (0%" PRIx64 ") is not supported",
+ error_setg(errp, "the alignment (0x%" PRIx64 ") is not supported",
align);
return 0;
}
@@ -145,11 +146,12 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
if (hint) {
new_addr = *hint;
if (new_addr < address_space_start) {
- error_setg(errp, "can't add memory [0x%" PRIx64 ":0x%" PRIx64
- "] at 0x%" PRIx64, new_addr, size, address_space_start);
+ error_setg(errp, "can't add memory device [0x%" PRIx64 ":0x%" PRIx64
+ "] before 0x%" PRIx64, new_addr, size,
+ address_space_start);
return 0;
} else if ((new_addr + size) > address_space_end) {
- error_setg(errp, "can't add memory [0x%" PRIx64 ":0x%" PRIx64
+ error_setg(errp, "can't add memory device [0x%" PRIx64 ":0x%" PRIx64
"] beyond 0x%" PRIx64, new_addr, size,
address_space_end);
return 0;
@@ -166,15 +168,13 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
uint64_t md_size, md_addr;
md_addr = mdc->get_addr(md);
- md_size = mdc->get_region_size(md);
- if (*errp) {
- goto out;
- }
+ md_size = memory_device_get_region_size(md, &error_abort);
if (ranges_overlap(md_addr, md_size, new_addr, size)) {
if (hint) {
const DeviceState *d = DEVICE(md);
- error_setg(errp, "address range conflicts with '%s'", d->id);
+ error_setg(errp, "address range conflicts with memory device"
+ " id='%s'", d->id ? d->id : "(unnamed)");
goto out;
}
new_addr = QEMU_ALIGN_UP(md_addr + md_size, align);
@@ -232,7 +232,7 @@ static int memory_device_plugged_size(Object *obj, void *opaque)
const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(obj);
if (dev->realized) {
- *size += mdc->get_plugged_size(md);
+ *size += mdc->get_plugged_size(md, &error_abort);
}
}
@@ -249,22 +249,83 @@ uint64_t get_plugged_memory_size(void)
return size;
}
-void memory_device_plug_region(MachineState *ms, MemoryRegion *mr,
- uint64_t addr)
+void memory_device_pre_plug(MemoryDeviceState *md, MachineState *ms,
+ const uint64_t *legacy_align, Error **errp)
+{
+ const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md);
+ Error *local_err = NULL;
+ uint64_t addr, align;
+ MemoryRegion *mr;
+
+ mr = mdc->get_memory_region(md, &local_err);
+ if (local_err) {
+ goto out;
+ }
+
+ align = legacy_align ? *legacy_align : memory_region_get_alignment(mr);
+ addr = mdc->get_addr(md);
+ addr = memory_device_get_free_addr(ms, !addr ? NULL : &addr, align,
+ memory_region_size(mr), &local_err);
+ if (local_err) {
+ goto out;
+ }
+ mdc->set_addr(md, addr, &local_err);
+ if (!local_err) {
+ trace_memory_device_pre_plug(DEVICE(md)->id ? DEVICE(md)->id : "",
+ addr);
+ }
+out:
+ error_propagate(errp, local_err);
+}
+
+void memory_device_plug(MemoryDeviceState *md, MachineState *ms)
{
- /* we expect a previous call to memory_device_get_free_addr() */
+ const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md);
+ const uint64_t addr = mdc->get_addr(md);
+ MemoryRegion *mr;
+
+ /*
+ * We expect that a previous call to memory_device_pre_plug() succeeded, so
+ * it can't fail at this point.
+ */
+ mr = mdc->get_memory_region(md, &error_abort);
g_assert(ms->device_memory);
memory_region_add_subregion(&ms->device_memory->mr,
addr - ms->device_memory->base, mr);
+ trace_memory_device_plug(DEVICE(md)->id ? DEVICE(md)->id : "", addr);
}
-void memory_device_unplug_region(MachineState *ms, MemoryRegion *mr)
+void memory_device_unplug(MemoryDeviceState *md, MachineState *ms)
{
- /* we expect a previous call to memory_device_get_free_addr() */
+ const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md);
+ MemoryRegion *mr;
+
+ /*
+ * We expect that a previous call to memory_device_pre_plug() succeeded, so
+ * it can't fail at this point.
+ */
+ mr = mdc->get_memory_region(md, &error_abort);
g_assert(ms->device_memory);
memory_region_del_subregion(&ms->device_memory->mr, mr);
+ trace_memory_device_unplug(DEVICE(md)->id ? DEVICE(md)->id : "",
+ mdc->get_addr(md));
+}
+
+uint64_t memory_device_get_region_size(const MemoryDeviceState *md,
+ Error **errp)
+{
+ const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md);
+ MemoryRegion *mr;
+
+ /* dropping const here is fine as we don't touch the memory region */
+ mr = mdc->get_memory_region((MemoryDeviceState *)md, errp);
+ if (!mr) {
+ return 0;
+ }
+
+ return memory_region_size(mr);
}
static const TypeInfo memory_device_info = {
diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c
index 1c6674c4ed..49324f3fae 100644
--- a/hw/mem/nvdimm.c
+++ b/hw/mem/nvdimm.c
@@ -27,6 +27,7 @@
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "hw/mem/nvdimm.h"
+#include "hw/mem/memory-device.h"
static void nvdimm_get_label_size(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
@@ -118,9 +119,10 @@ static void nvdimm_prepare_memory_region(NVDIMMDevice *nvdimm, Error **errp)
nvdimm->nvdimm_mr->align = align;
}
-static MemoryRegion *nvdimm_get_memory_region(PCDIMMDevice *dimm, Error **errp)
+static MemoryRegion *nvdimm_md_get_memory_region(MemoryDeviceState *md,
+ Error **errp)
{
- NVDIMMDevice *nvdimm = NVDIMM(dimm);
+ NVDIMMDevice *nvdimm = NVDIMM(md);
Error *local_err = NULL;
if (!nvdimm->nvdimm_mr) {
@@ -190,11 +192,12 @@ static Property nvdimm_properties[] = {
static void nvdimm_class_init(ObjectClass *oc, void *data)
{
PCDIMMDeviceClass *ddc = PC_DIMM_CLASS(oc);
+ MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc);
NVDIMMClass *nvc = NVDIMM_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
ddc->realize = nvdimm_realize;
- ddc->get_memory_region = nvdimm_get_memory_region;
+ mdc->get_memory_region = nvdimm_md_get_memory_region;
dc->props = nvdimm_properties;
nvc->read_label_data = nvdimm_read_label_data;
diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c
index fb6bcaedc4..0c9b9e8292 100644
--- a/hw/mem/pc-dimm.c
+++ b/hw/mem/pc-dimm.c
@@ -29,72 +29,47 @@
static int pc_dimm_get_free_slot(const int *hint, int max_slots, Error **errp);
-void pc_dimm_pre_plug(DeviceState *dev, MachineState *machine,
+void pc_dimm_pre_plug(PCDIMMDevice *dimm, MachineState *machine,
const uint64_t *legacy_align, Error **errp)
{
- PCDIMMDevice *dimm = PC_DIMM(dev);
- PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
Error *local_err = NULL;
- MemoryRegion *mr;
- uint64_t addr, align;
int slot;
- slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP,
+ slot = object_property_get_int(OBJECT(dimm), PC_DIMM_SLOT_PROP,
&error_abort);
slot = pc_dimm_get_free_slot(slot == PC_DIMM_UNASSIGNED_SLOT ? NULL : &slot,
machine->ram_slots, &local_err);
if (local_err) {
goto out;
}
- object_property_set_int(OBJECT(dev), slot, PC_DIMM_SLOT_PROP, &error_abort);
+ object_property_set_int(OBJECT(dimm), slot, PC_DIMM_SLOT_PROP,
+ &error_abort);
trace_mhp_pc_dimm_assigned_slot(slot);
- mr = ddc->get_memory_region(dimm, &local_err);
- if (local_err) {
- goto out;
- }
-
- align = legacy_align ? *legacy_align : memory_region_get_alignment(mr);
- addr = object_property_get_uint(OBJECT(dev), PC_DIMM_ADDR_PROP,
- &error_abort);
- addr = memory_device_get_free_addr(machine, !addr ? NULL : &addr, align,
- memory_region_size(mr), &local_err);
- if (local_err) {
- goto out;
- }
- trace_mhp_pc_dimm_assigned_address(addr);
- object_property_set_uint(OBJECT(dev), addr, PC_DIMM_ADDR_PROP,
- &error_abort);
+ memory_device_pre_plug(MEMORY_DEVICE(dimm), machine, legacy_align,
+ &local_err);
out:
error_propagate(errp, local_err);
}
-void pc_dimm_plug(DeviceState *dev, MachineState *machine, Error **errp)
+void pc_dimm_plug(PCDIMMDevice *dimm, MachineState *machine, Error **errp)
{
- PCDIMMDevice *dimm = PC_DIMM(dev);
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm,
&error_abort);
- MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort);
- uint64_t addr;
-
- addr = object_property_get_uint(OBJECT(dev), PC_DIMM_ADDR_PROP,
- &error_abort);
- memory_device_plug_region(machine, mr, addr);
- vmstate_register_ram(vmstate_mr, dev);
+ memory_device_plug(MEMORY_DEVICE(dimm), machine);
+ vmstate_register_ram(vmstate_mr, DEVICE(dimm));
}
-void pc_dimm_unplug(DeviceState *dev, MachineState *machine)
+void pc_dimm_unplug(PCDIMMDevice *dimm, MachineState *machine)
{
- PCDIMMDevice *dimm = PC_DIMM(dev);
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm,
&error_abort);
- MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort);
- memory_device_unplug_region(machine, mr);
- vmstate_unregister_ram(vmstate_mr, dev);
+ memory_device_unplug(MEMORY_DEVICE(dimm), machine);
+ vmstate_unregister_ram(vmstate_mr, DEVICE(dimm));
}
static int pc_dimm_slot2bitmap(Object *obj, void *opaque)
@@ -163,16 +138,14 @@ static Property pc_dimm_properties[] = {
static void pc_dimm_get_size(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
+ Error *local_err = NULL;
uint64_t value;
- MemoryRegion *mr;
- PCDIMMDevice *dimm = PC_DIMM(obj);
- PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(obj);
- mr = ddc->get_memory_region(dimm, errp);
- if (!mr) {
+ value = memory_device_get_region_size(MEMORY_DEVICE(obj), &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
- value = memory_region_size(mr);
visit_type_uint64(v, name, &value, errp);
}
@@ -236,19 +209,16 @@ static uint64_t pc_dimm_md_get_addr(const MemoryDeviceState *md)
return dimm->addr;
}
-static uint64_t pc_dimm_md_get_region_size(const MemoryDeviceState *md)
+static void pc_dimm_md_set_addr(MemoryDeviceState *md, uint64_t addr,
+ Error **errp)
{
- /* dropping const here is fine as we don't touch the memory region */
- PCDIMMDevice *dimm = PC_DIMM(md);
- const PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(md);
- MemoryRegion *mr;
-
- mr = ddc->get_memory_region(dimm, &error_abort);
- if (!mr) {
- return 0;
- }
+ object_property_set_uint(OBJECT(md), addr, PC_DIMM_ADDR_PROP, errp);
+}
- return memory_region_size(mr);
+static MemoryRegion *pc_dimm_md_get_memory_region(MemoryDeviceState *md,
+ Error **errp)
+{
+ return pc_dimm_get_memory_region(PC_DIMM(md), errp);
}
static void pc_dimm_md_fill_device_info(const MemoryDeviceState *md,
@@ -292,13 +262,13 @@ static void pc_dimm_class_init(ObjectClass *oc, void *data)
dc->props = pc_dimm_properties;
dc->desc = "DIMM memory module";
- ddc->get_memory_region = pc_dimm_get_memory_region;
ddc->get_vmstate_memory_region = pc_dimm_get_memory_region;
mdc->get_addr = pc_dimm_md_get_addr;
+ mdc->set_addr = pc_dimm_md_set_addr;
/* for a dimm plugged_size == region_size */
- mdc->get_plugged_size = pc_dimm_md_get_region_size;
- mdc->get_region_size = pc_dimm_md_get_region_size;
+ mdc->get_plugged_size = memory_device_get_region_size;
+ mdc->get_memory_region = pc_dimm_md_get_memory_region;
mdc->fill_device_info = pc_dimm_md_fill_device_info;
}
diff --git a/hw/mem/trace-events b/hw/mem/trace-events
index e150dcc497..0f2f278ff2 100644
--- a/hw/mem/trace-events
+++ b/hw/mem/trace-events
@@ -2,4 +2,7 @@
# hw/mem/pc-dimm.c
mhp_pc_dimm_assigned_slot(int slot) "%d"
-mhp_pc_dimm_assigned_address(uint64_t addr) "0x%"PRIx64
+# hw/mem/memory-device.c
+memory_device_pre_plug(const char *id, uint64_t addr) "id=%s addr=0x%"PRIx64
+memory_device_plug(const char *id, uint64_t addr) "id=%s addr=0x%"PRIx64
+memory_device_unplug(const char *id, uint64_t addr) "id=%s addr=0x%"PRIx64
diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c
index 24ad0ad024..1cd8aac658 100644
--- a/hw/mips/gt64xxx_pci.c
+++ b/hw/mips/gt64xxx_pci.c
@@ -992,9 +992,9 @@ static void gt64120_pci_set_irq(void *opaque, int irq_num, int level)
}
-static void gt64120_reset(void *opaque)
+static void gt64120_reset(DeviceState *dev)
{
- GT64120State *s = opaque;
+ GT64120State *s = GT64120_PCI_HOST_BRIDGE(dev);
/* FIXME: Malta specific hw assumptions ahead */
@@ -1184,16 +1184,6 @@ PCIBus *gt64120_register(qemu_irq *pic)
return phb->bus;
}
-static int gt64120_init(SysBusDevice *dev)
-{
- GT64120State *s;
-
- s = GT64120_PCI_HOST_BRIDGE(dev);
-
- qemu_register_reset(gt64120_reset, s);
- return 0;
-}
-
static void gt64120_pci_realize(PCIDevice *d, Error **errp)
{
/* FIXME: Malta specific hw assumptions ahead */
@@ -1241,9 +1231,9 @@ static const TypeInfo gt64120_pci_info = {
static void gt64120_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
- sdc->init = gt64120_init;
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->reset = gt64120_reset;
dc->vmsd = &vmstate_gt64120;
}
diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c
index c1694c8254..2fbba32c48 100644
--- a/hw/mips/mips_fulong2e.c
+++ b/hw/mips/mips_fulong2e.c
@@ -104,9 +104,9 @@ static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
static int64_t load_kernel (CPUMIPSState *env)
{
- int64_t kernel_entry, kernel_low, kernel_high;
+ int64_t kernel_entry, kernel_low, kernel_high, initrd_size;
int index = 0;
- long kernel_size, initrd_size;
+ long kernel_size;
ram_addr_t initrd_offset;
uint32_t *prom_buf;
long prom_size;
@@ -150,7 +150,7 @@ static int64_t load_kernel (CPUMIPSState *env)
prom_set(prom_buf, index++, "%s", loaderparams.kernel_filename);
if (initrd_size > 0) {
- prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
+ prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%" PRId64 " %s",
cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
loaderparams.kernel_cmdline);
} else {
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index 40041d5ec0..c1cf0fe12e 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -995,8 +995,8 @@ static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
/* Kernel */
static int64_t load_kernel (void)
{
- int64_t kernel_entry, kernel_high;
- long kernel_size, initrd_size;
+ int64_t kernel_entry, kernel_high, initrd_size;
+ long kernel_size;
ram_addr_t initrd_offset;
int big_endian;
uint32_t *prom_buf;
@@ -1070,7 +1070,7 @@ static int64_t load_kernel (void)
prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename);
if (initrd_size > 0) {
- prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
+ prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%" PRId64 " %s",
xlate_to_kseg0(NULL, initrd_offset), initrd_size,
loaderparams.kernel_cmdline);
} else {
@@ -1422,23 +1422,10 @@ void mips_malta_init(MachineState *machine)
pci_vga_init(pci_bus);
}
-static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev)
-{
- return 0;
-}
-
-static void mips_malta_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = mips_malta_sysbus_device_init;
-}
-
static const TypeInfo mips_malta_device = {
.name = TYPE_MIPS_MALTA,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(MaltaState),
- .class_init = mips_malta_class_init,
};
static void mips_malta_machine_init(MachineClass *mc)
diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mips_mipssim.c
index 241faa1d0f..f665752a2f 100644
--- a/hw/mips/mips_mipssim.c
+++ b/hw/mips/mips_mipssim.c
@@ -58,9 +58,8 @@ typedef struct ResetData {
static int64_t load_kernel(void)
{
- int64_t entry, kernel_high;
+ int64_t entry, kernel_high, initrd_size;
long kernel_size;
- long initrd_size;
ram_addr_t initrd_offset;
int big_endian;
diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c
index d5725d0555..3e852e98cf 100644
--- a/hw/mips/mips_r4k.c
+++ b/hw/mips/mips_r4k.c
@@ -81,8 +81,8 @@ typedef struct ResetData {
static int64_t load_kernel(void)
{
const size_t params_size = 264;
- int64_t entry, kernel_high;
- long kernel_size, initrd_size;
+ int64_t entry, kernel_high, initrd_size;
+ long kernel_size;
ram_addr_t initrd_offset;
uint32_t *params_buf;
int big_endian;
@@ -136,7 +136,7 @@ static int64_t load_kernel(void)
params_buf[1] = tswap32(0x12345678);
if (initrd_size > 0) {
- snprintf((char *)params_buf + 8, 256, "rd_start=0x%" PRIx64 " rd_size=%li %s",
+ snprintf((char *)params_buf + 8, 256, "rd_start=0x%" PRIx64 " rd_size=%" PRId64 " %s",
cpu_mips_phys_to_kseg0(NULL, initrd_offset),
initrd_size, loaderparams.kernel_cmdline);
} else {
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 6d50b03cfd..680350b3c3 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -71,7 +71,6 @@ obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o
obj-$(CONFIG_IOTKIT_SYSINFO) += iotkit-sysinfo.o
obj-$(CONFIG_PVPANIC) += pvpanic.o
-obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
obj-$(CONFIG_AUX) += auxbus.o
obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
obj-$(CONFIG_MSF2) += msf2-sysreg.o
diff --git a/hw/misc/debugexit.c b/hw/misc/debugexit.c
index 84fa1a5b9d..bed293247e 100644
--- a/hw/misc/debugexit.c
+++ b/hw/misc/debugexit.c
@@ -23,6 +23,11 @@ typedef struct ISADebugExitState {
MemoryRegion io;
} ISADebugExitState;
+static uint64_t debug_exit_read(void *opaque, hwaddr addr, unsigned size)
+{
+ return 0;
+}
+
static void debug_exit_write(void *opaque, hwaddr addr, uint64_t val,
unsigned width)
{
@@ -30,6 +35,7 @@ static void debug_exit_write(void *opaque, hwaddr addr, uint64_t val,
}
static const MemoryRegionOps debug_exit_ops = {
+ .read = debug_exit_read,
.write = debug_exit_write,
.valid.min_access_size = 1,
.valid.max_access_size = 4,
diff --git a/hw/misc/edu.c b/hw/misc/edu.c
index df26a4d046..cdcf550dd7 100644
--- a/hw/misc/edu.c
+++ b/hw/misc/edu.c
@@ -30,7 +30,8 @@
#include "qemu/main-loop.h" /* iothread mutex */
#include "qapi/visitor.h"
-#define EDU(obj) OBJECT_CHECK(EduState, obj, "edu")
+#define TYPE_PCI_EDU_DEVICE "edu"
+#define EDU(obj) OBJECT_CHECK(EduState, obj, TYPE_PCI_EDU_DEVICE)
#define FACT_IRQ 0x00000001
#define DMA_IRQ 0x00000100
@@ -341,7 +342,7 @@ static void *edu_fact_thread(void *opaque)
static void pci_edu_realize(PCIDevice *pdev, Error **errp)
{
- EduState *edu = DO_UPCAST(EduState, pdev, pdev);
+ EduState *edu = EDU(pdev);
uint8_t *pci_conf = pdev->config;
pci_config_set_interrupt_pin(pci_conf, 1);
@@ -364,7 +365,7 @@ static void pci_edu_realize(PCIDevice *pdev, Error **errp)
static void pci_edu_uninit(PCIDevice *pdev)
{
- EduState *edu = DO_UPCAST(EduState, pdev, pdev);
+ EduState *edu = EDU(pdev);
qemu_mutex_lock(&edu->thr_mutex);
edu->stopping = true;
@@ -414,7 +415,7 @@ static void pci_edu_register_types(void)
{ },
};
static const TypeInfo edu_info = {
- .name = "edu",
+ .name = TYPE_PCI_EDU_DEVICE,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(EduState),
.instance_init = edu_instance_init,
diff --git a/hw/misc/hyperv_testdev.c b/hw/misc/hyperv_testdev.c
deleted file mode 100644
index bf6bbfa8cf..0000000000
--- a/hw/misc/hyperv_testdev.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * QEMU KVM Hyper-V test device to support Hyper-V kvm-unit-tests
- *
- * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
- *
- * Authors:
- * Andrey Smetanin <asmetanin@virtuozzo.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include <linux/kvm.h>
-#include "hw/hw.h"
-#include "hw/qdev.h"
-#include "hw/isa/isa.h"
-#include "sysemu/kvm.h"
-#include "target/i386/hyperv.h"
-#include "kvm_i386.h"
-
-#define HV_TEST_DEV_MAX_SINT_ROUTES 64
-
-struct HypervTestDev {
- ISADevice parent_obj;
- MemoryRegion sint_control;
- HvSintRoute *sint_route[HV_TEST_DEV_MAX_SINT_ROUTES];
-};
-typedef struct HypervTestDev HypervTestDev;
-
-#define TYPE_HYPERV_TEST_DEV "hyperv-testdev"
-#define HYPERV_TEST_DEV(obj) \
- OBJECT_CHECK(HypervTestDev, (obj), TYPE_HYPERV_TEST_DEV)
-
-enum {
- HV_TEST_DEV_SINT_ROUTE_CREATE = 1,
- HV_TEST_DEV_SINT_ROUTE_DESTROY,
- HV_TEST_DEV_SINT_ROUTE_SET_SINT
-};
-
-static int alloc_sint_route_index(HypervTestDev *dev)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) {
- if (dev->sint_route[i] == NULL) {
- return i;
- }
- }
- return -1;
-}
-
-static void free_sint_route_index(HypervTestDev *dev, int i)
-{
- assert(i >= 0 && i < ARRAY_SIZE(dev->sint_route));
- dev->sint_route[i] = NULL;
-}
-
-static int find_sint_route_index(HypervTestDev *dev, uint32_t vp_index,
- uint32_t sint)
-{
- HvSintRoute *sint_route;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) {
- sint_route = dev->sint_route[i];
- if (sint_route && sint_route->vp_index == vp_index &&
- sint_route->sint == sint) {
- return i;
- }
- }
- return -1;
-}
-
-static void hv_synic_test_dev_control(HypervTestDev *dev, uint32_t ctl,
- uint32_t vp_index, uint32_t sint)
-{
- int i;
- HvSintRoute *sint_route;
-
- switch (ctl) {
- case HV_TEST_DEV_SINT_ROUTE_CREATE:
- i = alloc_sint_route_index(dev);
- assert(i >= 0);
- sint_route = kvm_hv_sint_route_create(vp_index, sint, NULL);
- assert(sint_route);
- dev->sint_route[i] = sint_route;
- break;
- case HV_TEST_DEV_SINT_ROUTE_DESTROY:
- i = find_sint_route_index(dev, vp_index, sint);
- assert(i >= 0);
- sint_route = dev->sint_route[i];
- kvm_hv_sint_route_destroy(sint_route);
- free_sint_route_index(dev, i);
- break;
- case HV_TEST_DEV_SINT_ROUTE_SET_SINT:
- i = find_sint_route_index(dev, vp_index, sint);
- assert(i >= 0);
- sint_route = dev->sint_route[i];
- kvm_hv_sint_route_set_sint(sint_route);
- break;
- default:
- break;
- }
-}
-
-static void hv_test_dev_control(void *opaque, hwaddr addr, uint64_t data,
- uint32_t len)
-{
- HypervTestDev *dev = HYPERV_TEST_DEV(opaque);
- uint8_t ctl;
-
- ctl = (data >> 16ULL) & 0xFF;
- switch (ctl) {
- case HV_TEST_DEV_SINT_ROUTE_CREATE:
- case HV_TEST_DEV_SINT_ROUTE_DESTROY:
- case HV_TEST_DEV_SINT_ROUTE_SET_SINT: {
- uint8_t sint = data & 0xFF;
- uint8_t vp_index = (data >> 8ULL) & 0xFF;
- hv_synic_test_dev_control(dev, ctl, vp_index, sint);
- break;
- }
- default:
- break;
- }
-}
-
-static const MemoryRegionOps synic_test_sint_ops = {
- .write = hv_test_dev_control,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void hv_test_dev_realizefn(DeviceState *d, Error **errp)
-{
- ISADevice *isa = ISA_DEVICE(d);
- HypervTestDev *dev = HYPERV_TEST_DEV(d);
- MemoryRegion *io = isa_address_space_io(isa);
-
- memset(dev->sint_route, 0, sizeof(dev->sint_route));
- memory_region_init_io(&dev->sint_control, OBJECT(dev),
- &synic_test_sint_ops, dev,
- "hyperv-testdev-ctl", 4);
- memory_region_add_subregion(io, 0x3000, &dev->sint_control);
-}
-
-static void hv_test_dev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->realize = hv_test_dev_realizefn;
-}
-
-static const TypeInfo hv_test_dev_info = {
- .name = TYPE_HYPERV_TEST_DEV,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(HypervTestDev),
- .class_init = hv_test_dev_class_init,
-};
-
-static void hv_test_dev_register_types(void)
-{
- type_register_static(&hv_test_dev_info);
-}
-type_init(hv_test_dev_register_types);
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 6febbabcaa..f88910e55c 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -911,6 +911,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
IVSHMEM_DPRINTF("using hostmem\n");
s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem);
+ host_memory_backend_set_mapped(s->hostmem, true);
} else {
Chardev *chr = qemu_chr_fe_get_driver(&s->server_chr);
assert(chr);
@@ -993,6 +994,10 @@ static void ivshmem_exit(PCIDevice *dev)
vmstate_unregister_ram(s->ivshmem_bar2, DEVICE(dev));
}
+ if (s->hostmem) {
+ host_memory_backend_set_mapped(s->hostmem, false);
+ }
+
if (s->peers) {
for (i = 0; i < s->nb_peers; i++) {
close_peer_eventfds(s, i);
@@ -1101,14 +1106,6 @@ static void ivshmem_plain_realize(PCIDevice *dev, Error **errp)
}
ivshmem_common_realize(dev, errp);
- host_memory_backend_set_mapped(s->hostmem, true);
-}
-
-static void ivshmem_plain_exit(PCIDevice *pci_dev)
-{
- IVShmemState *s = IVSHMEM_COMMON(pci_dev);
-
- host_memory_backend_set_mapped(s->hostmem, false);
}
static void ivshmem_plain_class_init(ObjectClass *klass, void *data)
@@ -1117,7 +1114,6 @@ static void ivshmem_plain_class_init(ObjectClass *klass, void *data)
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->realize = ivshmem_plain_realize;
- k->exit = ivshmem_plain_exit;
dc->props = ivshmem_plain_properties;
dc->vmsd = &ivshmem_plain_vmsd;
}
@@ -1292,8 +1288,8 @@ static void ivshmem_realize(PCIDevice *dev, Error **errp)
IVShmemState *s = IVSHMEM_COMMON(dev);
if (!qtest_enabled()) {
- error_report("ivshmem is deprecated, please use ivshmem-plain"
- " or ivshmem-doorbell instead");
+ warn_report("ivshmem is deprecated, please use ivshmem-plain"
+ " or ivshmem-doorbell instead");
}
if (qemu_chr_fe_backend_connected(&s->server_chr) + !!s->shmobj != 1) {
diff --git a/hw/misc/pc-testdev.c b/hw/misc/pc-testdev.c
index b81d820084..697eb88c97 100644
--- a/hw/misc/pc-testdev.c
+++ b/hw/misc/pc-testdev.c
@@ -58,7 +58,12 @@ typedef struct PCTestdev {
#define TESTDEV(obj) \
OBJECT_CHECK(PCTestdev, (obj), TYPE_TESTDEV)
-static void test_irq_line(void *opaque, hwaddr addr, uint64_t data,
+static uint64_t test_irq_line_read(void *opaque, hwaddr addr, unsigned size)
+{
+ return 0;
+}
+
+static void test_irq_line_write(void *opaque, hwaddr addr, uint64_t data,
unsigned len)
{
PCTestdev *dev = opaque;
@@ -68,7 +73,8 @@ static void test_irq_line(void *opaque, hwaddr addr, uint64_t data,
}
static const MemoryRegionOps test_irq_ops = {
- .write = test_irq_line,
+ .read = test_irq_line_read,
+ .write = test_irq_line_write,
.valid.min_access_size = 1,
.valid.max_access_size = 1,
.endianness = DEVICE_LITTLE_ENDIAN,
@@ -110,7 +116,12 @@ static const MemoryRegionOps test_ioport_byte_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static void test_flush_page(void *opaque, hwaddr addr, uint64_t data,
+static uint64_t test_flush_page_read(void *opaque, hwaddr addr, unsigned size)
+{
+ return 0;
+}
+
+static void test_flush_page_write(void *opaque, hwaddr addr, uint64_t data,
unsigned len)
{
hwaddr page = 4096;
@@ -126,7 +137,8 @@ static void test_flush_page(void *opaque, hwaddr addr, uint64_t data,
}
static const MemoryRegionOps test_flush_ops = {
- .write = test_flush_page,
+ .read = test_flush_page_read,
+ .write = test_flush_page_write,
.valid.min_access_size = 4,
.valid.max_access_size = 4,
.endianness = DEVICE_LITTLE_ENDIAN,
diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c
index d41247dbdc..4b0ce09c5e 100644
--- a/hw/moxie/moxiesim.c
+++ b/hw/moxie/moxiesim.c
@@ -54,8 +54,8 @@ typedef struct {
static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params)
{
uint64_t entry, kernel_low, kernel_high;
+ int64_t initrd_size;
long kernel_size;
- long initrd_size;
ram_addr_t initrd_offset;
kernel_size = load_elf(loader_params->kernel_filename, NULL, NULL,
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 0fa4b0dc44..d95cc27f58 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -28,6 +28,7 @@
#include "hw/net/cadence_gem.h"
#include "qapi/error.h"
#include "qemu/log.h"
+#include "sysemu/dma.h"
#include "net/checksum.h"
#ifdef CADENCE_GEM_ERR_DEBUG
@@ -141,6 +142,7 @@
#define GEM_DESCONF4 (0x0000028C/4)
#define GEM_DESCONF5 (0x00000290/4)
#define GEM_DESCONF6 (0x00000294/4)
+#define GEM_DESCONF6_64B_MASK (1U << 23)
#define GEM_DESCONF7 (0x00000298/4)
#define GEM_INT_Q1_STATUS (0x00000400 / 4)
@@ -152,6 +154,9 @@
#define GEM_RECEIVE_Q1_PTR (0x00000480 / 4)
#define GEM_RECEIVE_Q7_PTR (GEM_RECEIVE_Q1_PTR + 6)
+#define GEM_TBQPH (0x000004C8 / 4)
+#define GEM_RBQPH (0x000004D4 / 4)
+
#define GEM_INT_Q1_ENABLE (0x00000600 / 4)
#define GEM_INT_Q7_ENABLE (GEM_INT_Q1_ENABLE + 6)
@@ -207,6 +212,9 @@
#define GEM_NWCFG_BCAST_REJ 0x00000020 /* Reject broadcast packets */
#define GEM_NWCFG_PROMISC 0x00000010 /* Accept all packets */
+#define GEM_DMACFG_ADDR_64B (1U << 30)
+#define GEM_DMACFG_TX_BD_EXT (1U << 29)
+#define GEM_DMACFG_RX_BD_EXT (1U << 28)
#define GEM_DMACFG_RBUFSZ_M 0x00FF0000 /* DMA RX Buffer Size mask */
#define GEM_DMACFG_RBUFSZ_S 16 /* DMA RX Buffer Size shift */
#define GEM_DMACFG_RBUFSZ_MUL 64 /* DMA RX Buffer Size multiplier */
@@ -302,42 +310,47 @@
#define GEM_MODID_VALUE 0x00020118
-static inline unsigned tx_desc_get_buffer(unsigned *desc)
+static inline uint64_t tx_desc_get_buffer(CadenceGEMState *s, uint32_t *desc)
{
- return desc[0];
+ uint64_t ret = desc[0];
+
+ if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) {
+ ret |= (uint64_t)desc[2] << 32;
+ }
+ return ret;
}
-static inline unsigned tx_desc_get_used(unsigned *desc)
+static inline unsigned tx_desc_get_used(uint32_t *desc)
{
return (desc[1] & DESC_1_USED) ? 1 : 0;
}
-static inline void tx_desc_set_used(unsigned *desc)
+static inline void tx_desc_set_used(uint32_t *desc)
{
desc[1] |= DESC_1_USED;
}
-static inline unsigned tx_desc_get_wrap(unsigned *desc)
+static inline unsigned tx_desc_get_wrap(uint32_t *desc)
{
return (desc[1] & DESC_1_TX_WRAP) ? 1 : 0;
}
-static inline unsigned tx_desc_get_last(unsigned *desc)
+static inline unsigned tx_desc_get_last(uint32_t *desc)
{
return (desc[1] & DESC_1_TX_LAST) ? 1 : 0;
}
-static inline void tx_desc_set_last(unsigned *desc)
+static inline void tx_desc_set_last(uint32_t *desc)
{
desc[1] |= DESC_1_TX_LAST;
}
-static inline unsigned tx_desc_get_length(unsigned *desc)
+static inline unsigned tx_desc_get_length(uint32_t *desc)
{
return desc[1] & DESC_1_LENGTH;
}
-static inline void print_gem_tx_desc(unsigned *desc, uint8_t queue)
+static inline void print_gem_tx_desc(uint32_t *desc, uint8_t queue)
{
DB_PRINT("TXDESC (queue %" PRId8 "):\n", queue);
DB_PRINT("bufaddr: 0x%08x\n", *desc);
@@ -347,58 +360,79 @@ static inline void print_gem_tx_desc(unsigned *desc, uint8_t queue)
DB_PRINT("length: %d\n", tx_desc_get_length(desc));
}
-static inline unsigned rx_desc_get_buffer(unsigned *desc)
+static inline uint64_t rx_desc_get_buffer(CadenceGEMState *s, uint32_t *desc)
{
- return desc[0] & ~0x3UL;
+ uint64_t ret = desc[0] & ~0x3UL;
+
+ if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) {
+ ret |= (uint64_t)desc[2] << 32;
+ }
+ return ret;
}
-static inline unsigned rx_desc_get_wrap(unsigned *desc)
+static inline int gem_get_desc_len(CadenceGEMState *s, bool rx_n_tx)
+{
+ int ret = 2;
+
+ if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) {
+ ret += 2;
+ }
+ if (s->regs[GEM_DMACFG] & (rx_n_tx ? GEM_DMACFG_RX_BD_EXT
+ : GEM_DMACFG_TX_BD_EXT)) {
+ ret += 2;
+ }
+
+ assert(ret <= DESC_MAX_NUM_WORDS);
+ return ret;
+}
+
+static inline unsigned rx_desc_get_wrap(uint32_t *desc)
{
return desc[0] & DESC_0_RX_WRAP ? 1 : 0;
}
-static inline unsigned rx_desc_get_ownership(unsigned *desc)
+static inline unsigned rx_desc_get_ownership(uint32_t *desc)
{
return desc[0] & DESC_0_RX_OWNERSHIP ? 1 : 0;
}
-static inline void rx_desc_set_ownership(unsigned *desc)
+static inline void rx_desc_set_ownership(uint32_t *desc)
{
desc[0] |= DESC_0_RX_OWNERSHIP;
}
-static inline void rx_desc_set_sof(unsigned *desc)
+static inline void rx_desc_set_sof(uint32_t *desc)
{
desc[1] |= DESC_1_RX_SOF;
}
-static inline void rx_desc_set_eof(unsigned *desc)
+static inline void rx_desc_set_eof(uint32_t *desc)
{
desc[1] |= DESC_1_RX_EOF;
}
-static inline void rx_desc_set_length(unsigned *desc, unsigned len)
+static inline void rx_desc_set_length(uint32_t *desc, unsigned len)
{
desc[1] &= ~DESC_1_LENGTH;
desc[1] |= len;
}
-static inline void rx_desc_set_broadcast(unsigned *desc)
+static inline void rx_desc_set_broadcast(uint32_t *desc)
{
desc[1] |= R_DESC_1_RX_BROADCAST;
}
-static inline void rx_desc_set_unicast_hash(unsigned *desc)
+static inline void rx_desc_set_unicast_hash(uint32_t *desc)
{
desc[1] |= R_DESC_1_RX_UNICAST_HASH;
}
-static inline void rx_desc_set_multicast_hash(unsigned *desc)
+static inline void rx_desc_set_multicast_hash(uint32_t *desc)
{
desc[1] |= R_DESC_1_RX_MULTICAST_HASH;
}
-static inline void rx_desc_set_sar(unsigned *desc, int sar_idx)
+static inline void rx_desc_set_sar(uint32_t *desc, int sar_idx)
{
desc[1] = deposit32(desc[1], R_DESC_1_RX_SAR_SHIFT, R_DESC_1_RX_SAR_LENGTH,
sar_idx);
@@ -419,7 +453,7 @@ static void gem_init_register_masks(CadenceGEMState *s)
memset(&s->regs_ro[0], 0, sizeof(s->regs_ro));
s->regs_ro[GEM_NWCTRL] = 0xFFF80000;
s->regs_ro[GEM_NWSTATUS] = 0xFFFFFFFF;
- s->regs_ro[GEM_DMACFG] = 0xFE00F000;
+ s->regs_ro[GEM_DMACFG] = 0x8E00F000;
s->regs_ro[GEM_TXSTATUS] = 0xFFFFFE08;
s->regs_ro[GEM_RXQBASE] = 0x00000003;
s->regs_ro[GEM_TXQBASE] = 0x00000003;
@@ -802,17 +836,42 @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr,
return 0;
}
+static hwaddr gem_get_desc_addr(CadenceGEMState *s, bool tx, int q)
+{
+ hwaddr desc_addr = 0;
+
+ if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) {
+ desc_addr = s->regs[tx ? GEM_TBQPH : GEM_RBQPH];
+ }
+ desc_addr <<= 32;
+ desc_addr |= tx ? s->tx_desc_addr[q] : s->rx_desc_addr[q];
+ return desc_addr;
+}
+
+static hwaddr gem_get_tx_desc_addr(CadenceGEMState *s, int q)
+{
+ return gem_get_desc_addr(s, true, q);
+}
+
+static hwaddr gem_get_rx_desc_addr(CadenceGEMState *s, int q)
+{
+ return gem_get_desc_addr(s, false, q);
+}
+
static void gem_get_rx_desc(CadenceGEMState *s, int q)
{
- DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[q]);
+ hwaddr desc_addr = gem_get_rx_desc_addr(s, q);
+
+ DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", desc_addr);
+
/* read current descriptor */
- cpu_physical_memory_read(s->rx_desc_addr[q],
- (uint8_t *)s->rx_desc[q], sizeof(s->rx_desc[q]));
+ address_space_read(&s->dma_as, desc_addr, MEMTXATTRS_UNSPECIFIED,
+ (uint8_t *)s->rx_desc[q],
+ sizeof(uint32_t) * gem_get_desc_len(s, true));
/* Descriptor owned by software ? */
if (rx_desc_get_ownership(s->rx_desc[q]) == 1) {
- DB_PRINT("descriptor 0x%x owned by sw.\n",
- (unsigned)s->rx_desc_addr[q]);
+ DB_PRINT("descriptor 0x%" HWADDR_PRIx " owned by sw.\n", desc_addr);
s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;
s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]);
/* Handle interrupt consequences */
@@ -916,6 +975,8 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize);
while (bytes_to_copy) {
+ hwaddr desc_addr;
+
/* Do nothing if receive is not enabled. */
if (!gem_can_receive(nc)) {
assert(!first_desc);
@@ -926,9 +987,10 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
rx_desc_get_buffer(s->rx_desc[q]));
/* Copy packet data to emulated DMA buffer */
- cpu_physical_memory_write(rx_desc_get_buffer(s->rx_desc[q]) +
- rxbuf_offset,
- rxbuf_ptr, MIN(bytes_to_copy, rxbufsize));
+ address_space_write(&s->dma_as, rx_desc_get_buffer(s, s->rx_desc[q]) +
+ rxbuf_offset,
+ MEMTXATTRS_UNSPECIFIED, rxbuf_ptr,
+ MIN(bytes_to_copy, rxbufsize));
rxbuf_ptr += MIN(bytes_to_copy, rxbufsize);
bytes_to_copy -= MIN(bytes_to_copy, rxbufsize);
@@ -962,9 +1024,11 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
}
/* Descriptor write-back. */
- cpu_physical_memory_write(s->rx_desc_addr[q],
- (uint8_t *)s->rx_desc[q],
- sizeof(s->rx_desc[q]));
+ desc_addr = gem_get_rx_desc_addr(s, q);
+ address_space_write(&s->dma_as, desc_addr,
+ MEMTXATTRS_UNSPECIFIED,
+ (uint8_t *)s->rx_desc[q],
+ sizeof(uint32_t) * gem_get_desc_len(s, true));
/* Next descriptor */
if (rx_desc_get_wrap(s->rx_desc[q])) {
@@ -972,7 +1036,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
s->rx_desc_addr[q] = s->regs[GEM_RXQBASE];
} else {
DB_PRINT("incrementing RX descriptor list\n");
- s->rx_desc_addr[q] += 8;
+ s->rx_desc_addr[q] += 4 * gem_get_desc_len(s, true);
}
gem_get_rx_desc(s, q);
@@ -1042,7 +1106,7 @@ static void gem_transmit_updatestats(CadenceGEMState *s, const uint8_t *packet,
*/
static void gem_transmit(CadenceGEMState *s)
{
- unsigned desc[2];
+ uint32_t desc[DESC_MAX_NUM_WORDS];
hwaddr packet_desc_addr;
uint8_t tx_packet[2048];
uint8_t *p;
@@ -1065,11 +1129,12 @@ static void gem_transmit(CadenceGEMState *s)
for (q = s->num_priority_queues - 1; q >= 0; q--) {
/* read current descriptor */
- packet_desc_addr = s->tx_desc_addr[q];
+ packet_desc_addr = gem_get_tx_desc_addr(s, q);
DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr);
- cpu_physical_memory_read(packet_desc_addr,
- (uint8_t *)desc, sizeof(desc));
+ address_space_read(&s->dma_as, packet_desc_addr,
+ MEMTXATTRS_UNSPECIFIED, (uint8_t *)desc,
+ sizeof(uint32_t) * gem_get_desc_len(s, false));
/* Handle all descriptors owned by hardware */
while (tx_desc_get_used(desc) == 0) {
@@ -1082,7 +1147,7 @@ static void gem_transmit(CadenceGEMState *s)
/* The real hardware would eat this (and possibly crash).
* For QEMU let's lend a helping hand.
*/
- if ((tx_desc_get_buffer(desc) == 0) ||
+ if ((tx_desc_get_buffer(s, desc) == 0) ||
(tx_desc_get_length(desc) == 0)) {
DB_PRINT("Invalid TX descriptor @ 0x%x\n",
(unsigned)packet_desc_addr);
@@ -1101,30 +1166,35 @@ static void gem_transmit(CadenceGEMState *s)
/* Gather this fragment of the packet from "dma memory" to our
* contig buffer.
*/
- cpu_physical_memory_read(tx_desc_get_buffer(desc), p,
- tx_desc_get_length(desc));
+ address_space_read(&s->dma_as, tx_desc_get_buffer(s, desc),
+ MEMTXATTRS_UNSPECIFIED,
+ p, tx_desc_get_length(desc));
p += tx_desc_get_length(desc);
total_bytes += tx_desc_get_length(desc);
/* Last descriptor for this packet; hand the whole thing off */
if (tx_desc_get_last(desc)) {
- unsigned desc_first[2];
+ uint32_t desc_first[DESC_MAX_NUM_WORDS];
+ hwaddr desc_addr = gem_get_tx_desc_addr(s, q);
/* Modify the 1st descriptor of this packet to be owned by
* the processor.
*/
- cpu_physical_memory_read(s->tx_desc_addr[q],
- (uint8_t *)desc_first,
- sizeof(desc_first));
+ address_space_read(&s->dma_as, desc_addr,
+ MEMTXATTRS_UNSPECIFIED,
+ (uint8_t *)desc_first,
+ sizeof(desc_first));
tx_desc_set_used(desc_first);
- cpu_physical_memory_write(s->tx_desc_addr[q],
- (uint8_t *)desc_first,
- sizeof(desc_first));
+ address_space_write(&s->dma_as, desc_addr,
+ MEMTXATTRS_UNSPECIFIED,
+ (uint8_t *)desc_first,
+ sizeof(desc_first));
/* Advance the hardware current descriptor past this packet */
if (tx_desc_get_wrap(desc)) {
s->tx_desc_addr[q] = s->regs[GEM_TXQBASE];
} else {
- s->tx_desc_addr[q] = packet_desc_addr + 8;
+ s->tx_desc_addr[q] = packet_desc_addr +
+ 4 * gem_get_desc_len(s, false);
}
DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr[q]);
@@ -1168,11 +1238,12 @@ static void gem_transmit(CadenceGEMState *s)
tx_desc_set_last(desc);
packet_desc_addr = s->regs[GEM_TXQBASE];
} else {
- packet_desc_addr += 8;
+ packet_desc_addr += 4 * gem_get_desc_len(s, false);
}
DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr);
- cpu_physical_memory_read(packet_desc_addr,
- (uint8_t *)desc, sizeof(desc));
+ address_space_read(&s->dma_as, packet_desc_addr,
+ MEMTXATTRS_UNSPECIFIED, (uint8_t *)desc,
+ sizeof(uint32_t) * gem_get_desc_len(s, false));
}
if (tx_desc_get_used(desc)) {
@@ -1213,6 +1284,7 @@ static void gem_reset(DeviceState *d)
int i;
CadenceGEMState *s = CADENCE_GEM(d);
const uint8_t *a;
+ uint32_t queues_mask = 0;
DB_PRINT("\n");
@@ -1228,8 +1300,13 @@ static void gem_reset(DeviceState *d)
s->regs[GEM_MODID] = s->revision;
s->regs[GEM_DESCONF] = 0x02500111;
s->regs[GEM_DESCONF2] = 0x2ab13fff;
- s->regs[GEM_DESCONF5] = 0x002f2145;
- s->regs[GEM_DESCONF6] = 0x00000200;
+ s->regs[GEM_DESCONF5] = 0x002f2045;
+ s->regs[GEM_DESCONF6] = GEM_DESCONF6_64B_MASK;
+
+ if (s->num_priority_queues > 1) {
+ queues_mask = MAKE_64BIT_MASK(1, s->num_priority_queues - 1);
+ s->regs[GEM_DESCONF6] |= queues_mask;
+ }
/* Set MAC address */
a = &s->conf.macaddr.a[0];
@@ -1463,6 +1540,9 @@ static void gem_realize(DeviceState *dev, Error **errp)
CadenceGEMState *s = CADENCE_GEM(dev);
int i;
+ address_space_init(&s->dma_as,
+ s->dma_mr ? s->dma_mr : get_system_memory(), "dma");
+
if (s->num_priority_queues == 0 ||
s->num_priority_queues > MAX_PRIORITY_QUEUES) {
error_setg(errp, "Invalid num-priority-queues value: %" PRIx8,
@@ -1500,6 +1580,12 @@ static void gem_init(Object *obj)
"enet", sizeof(s->regs));
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+
+ object_property_add_link(obj, "dma", TYPE_MEMORY_REGION,
+ (Object **)&s->dma_mr,
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_STRONG,
+ &error_abort);
}
static const VMStateDescription vmstate_cadence_gem = {
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index 13a9494a8d..5e144cb4e4 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -36,6 +36,7 @@
#include "qemu/range.h"
#include "e1000x_common.h"
+#include "trace.h"
static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
@@ -847,6 +848,15 @@ static uint64_t rx_desc_base(E1000State *s)
return (bah << 32) + bal;
}
+static void
+e1000_receiver_overrun(E1000State *s, size_t size)
+{
+ trace_e1000_receiver_overrun(size, s->mac_reg[RDH], s->mac_reg[RDT]);
+ e1000x_inc_reg_if_not_full(s->mac_reg, RNBC);
+ e1000x_inc_reg_if_not_full(s->mac_reg, MPC);
+ set_ics(s, 0, E1000_ICS_RXO);
+}
+
static ssize_t
e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
{
@@ -916,8 +926,8 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
desc_offset = 0;
total_size = size + e1000x_fcs_len(s->mac_reg);
if (!e1000_has_rxbufs(s, total_size)) {
- set_ics(s, 0, E1000_ICS_RXO);
- return -1;
+ e1000_receiver_overrun(s, total_size);
+ return -1;
}
do {
desc_size = total_size - desc_offset;
@@ -969,7 +979,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
rdh_start >= s->mac_reg[RDLEN] / sizeof(desc)) {
DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
- set_ics(s, 0, E1000_ICS_RXO);
+ e1000_receiver_overrun(s, total_size);
return -1;
}
} while (desc_offset < total_size);
diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c
index a6932432b1..36855804db 100644
--- a/hw/net/etraxfs_eth.c
+++ b/hw/net/etraxfs_eth.c
@@ -23,6 +23,7 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "hw/sysbus.h"
#include "net/net.h"
#include "hw/cris/etraxfs.h"
@@ -126,7 +127,7 @@ tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
}
static void
-tdk_init(struct qemu_phy *phy)
+tdk_reset(struct qemu_phy *phy)
{
phy->regs[0] = 0x3100;
/* PHY Id. */
@@ -135,9 +136,6 @@ tdk_init(struct qemu_phy *phy)
/* Autonegotiation advertisement reg. */
phy->regs[4] = 0x01E1;
phy->link = 1;
-
- phy->read = tdk_read;
- phy->write = tdk_write;
}
struct qemu_mdio
@@ -584,14 +582,35 @@ static NetClientInfo net_etraxfs_info = {
.link_status_changed = eth_set_link,
};
-static int fs_eth_init(SysBusDevice *sbd)
+static void etraxfs_eth_reset(DeviceState *dev)
+{
+ ETRAXFSEthState *s = ETRAX_FS_ETH(dev);
+
+ memset(s->regs, 0, sizeof(s->regs));
+ memset(s->macaddr, 0, sizeof(s->macaddr));
+ s->duplex_mismatch = 0;
+
+ s->mdio_bus.mdc = 0;
+ s->mdio_bus.mdio = 0;
+ s->mdio_bus.state = 0;
+ s->mdio_bus.drive = 0;
+ s->mdio_bus.cnt = 0;
+ s->mdio_bus.addr = 0;
+ s->mdio_bus.opc = 0;
+ s->mdio_bus.req = 0;
+ s->mdio_bus.data = 0;
+
+ tdk_reset(&s->phy);
+}
+
+static void etraxfs_eth_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
ETRAXFSEthState *s = ETRAX_FS_ETH(dev);
if (!s->dma_out || !s->dma_in) {
- error_report("Unconnected ETRAX-FS Ethernet MAC");
- return -1;
+ error_setg(errp, "Unconnected ETRAX-FS Ethernet MAC");
+ return;
}
s->dma_out->client.push = eth_tx_push;
@@ -608,10 +627,9 @@ static int fs_eth_init(SysBusDevice *sbd)
object_get_typename(OBJECT(s)), dev->id, s);
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- tdk_init(&s->phy);
+ s->phy.read = tdk_read;
+ s->phy.write = tdk_write;
mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
- return 0;
}
static Property etraxfs_eth_properties[] = {
@@ -625,9 +643,9 @@ static Property etraxfs_eth_properties[] = {
static void etraxfs_eth_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = fs_eth_init;
+ dc->realize = etraxfs_eth_realize;
+ dc->reset = etraxfs_eth_reset;
dc->props = etraxfs_eth_properties;
/* Reason: pointer properties "dma_out", "dma_in" */
dc->user_creatable = false;
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
index b9032dac59..a6269d9463 100644
--- a/hw/net/lan9118.c
+++ b/hw/net/lan9118.c
@@ -1320,9 +1320,9 @@ static NetClientInfo net_lan9118_info = {
.link_status_changed = lan9118_set_link,
};
-static int lan9118_init1(SysBusDevice *sbd)
+static void lan9118_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
lan9118_state *s = LAN9118(dev);
QEMUBH *bh;
int i;
@@ -1349,8 +1349,6 @@ static int lan9118_init1(SysBusDevice *sbd)
s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
ptimer_set_freq(s->timer, 10000);
ptimer_set_limit(s->timer, 0xffff, 1);
-
- return 0;
}
static Property lan9118_properties[] = {
@@ -1362,12 +1360,11 @@ static Property lan9118_properties[] = {
static void lan9118_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = lan9118_init1;
dc->reset = lan9118_reset;
dc->props = lan9118_properties;
dc->vmsd = &vmstate_lan9118;
+ dc->realize = lan9118_realize;
}
static const TypeInfo lan9118_info = {
diff --git a/hw/net/lance.c b/hw/net/lance.c
index a08d5ac6a8..f987b2fd18 100644
--- a/hw/net/lance.c
+++ b/hw/net/lance.c
@@ -97,9 +97,9 @@ static const VMStateDescription vmstate_lance = {
}
};
-static int lance_init(SysBusDevice *sbd)
+static void lance_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
SysBusPCNetState *d = SYSBUS_PCNET(dev);
PCNetState *s = &d->state;
@@ -115,7 +115,6 @@ static int lance_init(SysBusDevice *sbd)
s->phys_mem_read = ledma_memory_read;
s->phys_mem_write = ledma_memory_write;
pcnet_common_init(dev, s, &net_lance_info);
- return 0;
}
static void lance_reset(DeviceState *dev)
@@ -144,9 +143,8 @@ static Property lance_properties[] = {
static void lance_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = lance_init;
+ dc->realize = lance_realize;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->fw_name = "ethernet";
dc->reset = lance_reset;
diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c
index 3eaa19dfde..85c9fc0b65 100644
--- a/hw/net/milkymist-minimac2.c
+++ b/hw/net/milkymist-minimac2.c
@@ -30,6 +30,7 @@
#include "hw/sysbus.h"
#include "trace.h"
#include "net/net.h"
+#include "qemu/log.h"
#include "qemu/error-report.h"
#include <zlib.h>
@@ -214,7 +215,8 @@ static size_t assemble_frame(uint8_t *buf, size_t size,
uint32_t crc;
if (size < payload_size + 12) {
- error_report("milkymist_minimac2: received too big ethernet frame");
+ qemu_log_mask(LOG_GUEST_ERROR, "milkymist_minimac2: frame too big "
+ "(%zd bytes)\n", payload_size);
return 0;
}
@@ -347,8 +349,9 @@ minimac2_read(void *opaque, hwaddr addr, unsigned size)
break;
default:
- error_report("milkymist_minimac2: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "milkymist_minimac2_rd%d: 0x%" HWADDR_PRIx "\n",
+ size, addr << 2);
break;
}
@@ -413,8 +416,10 @@ minimac2_write(void *opaque, hwaddr addr, uint64_t value,
break;
default:
- error_report("milkymist_minimac2: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "milkymist_minimac2_wr%d: 0x%" HWADDR_PRIx
+ " = 0x%" PRIx64 "\n",
+ size, addr << 2, value);
break;
}
}
@@ -452,9 +457,9 @@ static NetClientInfo net_milkymist_minimac2_info = {
.receive = minimac2_rx,
};
-static int milkymist_minimac2_init(SysBusDevice *sbd)
+static void milkymist_minimac2_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(dev);
size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE);
@@ -479,8 +484,6 @@ static int milkymist_minimac2_init(SysBusDevice *sbd)
s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf,
object_get_typename(OBJECT(dev)), dev->id, s);
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- return 0;
}
static const VMStateDescription vmstate_milkymist_minimac2_mdio = {
@@ -521,9 +524,8 @@ static Property milkymist_minimac2_properties[] = {
static void milkymist_minimac2_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = milkymist_minimac2_init;
+ dc->realize = milkymist_minimac2_realize;
dc->reset = milkymist_minimac2_reset;
dc->vmsd = &vmstate_milkymist_minimac2;
dc->props = milkymist_minimac2_properties;
diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c
index 5a63df7ccb..03b3104278 100644
--- a/hw/net/mipsnet.c
+++ b/hw/net/mipsnet.c
@@ -236,9 +236,9 @@ static const MemoryRegionOps mipsnet_ioport_ops = {
.impl.max_access_size = 4,
};
-static int mipsnet_sysbus_init(SysBusDevice *sbd)
+static void mipsnet_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
MIPSnetState *s = MIPS_NET(dev);
memory_region_init_io(&s->io, OBJECT(dev), &mipsnet_ioport_ops, s,
@@ -249,8 +249,6 @@ static int mipsnet_sysbus_init(SysBusDevice *sbd)
s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
object_get_typename(OBJECT(dev)), dev->id, s);
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- return 0;
}
static void mipsnet_sysbus_reset(DeviceState *dev)
@@ -267,9 +265,8 @@ static Property mipsnet_properties[] = {
static void mipsnet_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = mipsnet_sysbus_init;
+ dc->realize = mipsnet_realize;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->desc = "MIPS Simulator network device";
dc->reset = mipsnet_sysbus_reset;
diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c
index 07d79e317f..869518ee06 100644
--- a/hw/net/ne2000.c
+++ b/hw/net/ne2000.c
@@ -174,7 +174,7 @@ static int ne2000_buffer_full(NE2000State *s)
ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
{
NE2000State *s = qemu_get_nic_opaque(nc);
- int size = size_;
+ size_t size = size_;
uint8_t *p;
unsigned int total_len, next, avail, len, index, mcast_idx;
uint8_t buf1[60];
@@ -182,7 +182,7 @@ ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
#if defined(DEBUG_NE2000)
- printf("NE2000: received len=%d\n", size);
+ printf("NE2000: received len=%zu\n", size);
#endif
if (s->cmd & E8390_STOP || ne2000_buffer_full(s))
diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c
index d42b79c08c..d6f54f8d82 100644
--- a/hw/net/opencores_eth.c
+++ b/hw/net/opencores_eth.c
@@ -715,9 +715,9 @@ static const MemoryRegionOps open_eth_desc_ops = {
.write = open_eth_desc_write,
};
-static int sysbus_open_eth_init(SysBusDevice *sbd)
+static void sysbus_open_eth_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
OpenEthState *s = OPEN_ETH(dev);
memory_region_init_io(&s->reg_io, OBJECT(dev), &open_eth_reg_ops, s,
@@ -732,7 +732,6 @@ static int sysbus_open_eth_init(SysBusDevice *sbd)
s->nic = qemu_new_nic(&net_open_eth_info, &s->conf,
object_get_typename(OBJECT(s)), dev->id, s);
- return 0;
}
static void qdev_open_eth_reset(DeviceState *dev)
@@ -750,9 +749,8 @@ static Property open_eth_properties[] = {
static void open_eth_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = sysbus_open_eth_init;
+ dc->realize = sysbus_open_eth_realize;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->desc = "Opencores 10/100 Mbit Ethernet";
dc->reset = qdev_open_eth_reset;
diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c
index 0c44554168..d9ba04bdfc 100644
--- a/hw/net/pcnet.c
+++ b/hw/net/pcnet.c
@@ -988,14 +988,14 @@ ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
uint8_t buf1[60];
int remaining;
int crc_err = 0;
- int size = size_;
+ size_t size = 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);
+ printf("pcnet_receive size=%zu\n", size);
#endif
/* if too small buffer, then expand it */
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index 46daa16202..2342a095e3 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -817,7 +817,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
RTL8139State *s = qemu_get_nic_opaque(nc);
PCIDevice *d = PCI_DEVICE(s);
/* size is the length of the buffer passed to the driver */
- int size = size_;
+ size_t size = size_;
const uint8_t *dot1q_buf = NULL;
uint32_t packet_header = 0;
@@ -826,7 +826,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
static const uint8_t broadcast_macaddr[6] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- DPRINTF(">>> received len=%d\n", size);
+ DPRINTF(">>> received len=%zu\n", size);
/* test if board clock is stopped */
if (!s->clock_enabled)
@@ -1035,7 +1035,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
if (size+4 > rx_space)
{
- DPRINTF("C+ Rx mode : descriptor %d size %d received %d + 4\n",
+ DPRINTF("C+ Rx mode : descriptor %d size %d received %zu + 4\n",
descriptor, rx_space, size);
s->IntrStatus |= RxOverflow;
@@ -1148,7 +1148,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
if (avail != 0 && RX_ALIGN(size + 8) >= avail)
{
DPRINTF("rx overflow: rx buffer length %d head 0x%04x "
- "read 0x%04x === available 0x%04x need 0x%04x\n",
+ "read 0x%04x === available 0x%04x need 0x%04zx\n",
s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8);
s->IntrStatus |= RxOverflow;
diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c
index d2fd2040e8..99da2d9297 100644
--- a/hw/net/smc91c111.c
+++ b/hw/net/smc91c111.c
@@ -766,9 +766,9 @@ static NetClientInfo net_smc91c111_info = {
.receive = smc91c111_receive,
};
-static int smc91c111_init1(SysBusDevice *sbd)
+static void smc91c111_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
smc91c111_state *s = SMC91C111(dev);
memory_region_init_io(&s->mmio, OBJECT(s), &smc91c111_mem_ops, s,
@@ -780,7 +780,6 @@ static int smc91c111_init1(SysBusDevice *sbd)
object_get_typename(OBJECT(dev)), dev->id, s);
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
/* ??? Save/restore. */
- return 0;
}
static Property smc91c111_properties[] = {
@@ -791,9 +790,8 @@ static Property smc91c111_properties[] = {
static void smc91c111_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = smc91c111_init1;
+ dc->realize = smc91c111_realize;
dc->reset = smc91c111_reset;
dc->vmsd = &vmstate_smc91c111;
dc->props = smc91c111_properties;
diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c
index 165562d788..b3375ebb45 100644
--- a/hw/net/stellaris_enet.c
+++ b/hw/net/stellaris_enet.c
@@ -457,8 +457,10 @@ static const MemoryRegionOps stellaris_enet_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void stellaris_enet_reset(stellaris_enet_state *s)
+static void stellaris_enet_reset(DeviceState *dev)
{
+ stellaris_enet_state *s = STELLARIS_ENET(dev);
+
s->mdv = 0x80;
s->rctl = SE_RCTL_BADCRC;
s->im = SE_INT_PHY | SE_INT_MD | SE_INT_RXER | SE_INT_FOV | SE_INT_TXEMP
@@ -473,9 +475,9 @@ static NetClientInfo net_stellaris_enet_info = {
.receive = stellaris_enet_receive,
};
-static int stellaris_enet_init(SysBusDevice *sbd)
+static void stellaris_enet_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
stellaris_enet_state *s = STELLARIS_ENET(dev);
memory_region_init_io(&s->mmio, OBJECT(s), &stellaris_enet_ops, s,
@@ -487,9 +489,6 @@ static int stellaris_enet_init(SysBusDevice *sbd)
s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf,
object_get_typename(OBJECT(dev)), dev->id, s);
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- stellaris_enet_reset(s);
- return 0;
}
static Property stellaris_enet_properties[] = {
@@ -500,9 +499,9 @@ static Property stellaris_enet_properties[] = {
static void stellaris_enet_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = stellaris_enet_init;
+ dc->realize = stellaris_enet_realize;
+ dc->reset = stellaris_enet_reset;
dc->props = stellaris_enet_properties;
dc->vmsd = &vmstate_stellaris_enet;
}
diff --git a/hw/net/trace-events b/hw/net/trace-events
index c1dea4b156..9d49f62fa1 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -98,6 +98,9 @@ net_rx_pkt_rss_ip6_ex(void) "Calculating IPv6/EX RSS hash"
net_rx_pkt_rss_hash(size_t rss_length, uint32_t rss_hash) "RSS hash for %zu bytes: 0x%X"
net_rx_pkt_rss_add_chunk(void* ptr, size_t size, size_t input_offset) "Add RSS chunk %p, %zu bytes, RSS input offset %zu bytes"
+# hw/net/e1000.c
+e1000_receiver_overrun(size_t s, uint32_t rdh, uint32_t rdt) "Receiver overrun: dropped packet of %zu bytes, RDH=%u, RDT=%u"
+
# hw/net/e1000x_common.c
e1000x_rx_can_recv_disabled(bool link_up, bool rx_enabled, bool pci_master) "link_up: %d, rx_enabled %d, pci_master %d"
e1000x_vlan_is_vlan_pkt(bool is_vlan_pkt, uint16_t eth_proto, uint16_t vet) "Is VLAN packet: %d, ETH proto: 0x%X, VET: 0x%X"
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 4bdd5b8532..385b1a03e9 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -2020,10 +2020,10 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
if (n->net_conf.tx && strcmp(n->net_conf.tx, "timer")
&& strcmp(n->net_conf.tx, "bh")) {
- error_report("virtio-net: "
- "Unknown option tx=%s, valid options: \"timer\" \"bh\"",
- n->net_conf.tx);
- error_report("Defaulting to \"bh\"");
+ warn_report("virtio-net: "
+ "Unknown option tx=%s, valid options: \"timer\" \"bh\"",
+ n->net_conf.tx);
+ error_printf("Defaulting to \"bh\"");
}
n->net_conf.tx_queue_size = MIN(virtio_net_max_tx_queue_size(n),
diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c
index fa001563d3..63f5a62ebf 100644
--- a/hw/net/xgmac.c
+++ b/hw/net/xgmac.c
@@ -374,9 +374,9 @@ static NetClientInfo net_xgmac_enet_info = {
.receive = eth_rx,
};
-static int xgmac_enet_init(SysBusDevice *sbd)
+static void xgmac_enet_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
XgmacState *s = XGMAC(dev);
memory_region_init_io(&s->iomem, OBJECT(s), &enet_mem_ops, s,
@@ -397,8 +397,6 @@ static int xgmac_enet_init(SysBusDevice *sbd)
(s->conf.macaddr.a[2] << 16) |
(s->conf.macaddr.a[1] << 8) |
s->conf.macaddr.a[0];
-
- return 0;
}
static Property xgmac_properties[] = {
@@ -408,10 +406,9 @@ static Property xgmac_properties[] = {
static void xgmac_enet_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- sbc->init = xgmac_enet_init;
+ dc->realize = xgmac_enet_realize;
dc->vmsd = &vmstate_xgmac;
dc->props = xgmac_properties;
}
diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs
index a912d25391..b318e53a43 100644
--- a/hw/nvram/Makefile.objs
+++ b/hw/nvram/Makefile.objs
@@ -1,6 +1,6 @@
common-obj-$(CONFIG_DS1225Y) += ds1225y.o
common-obj-y += eeprom93xx.o
-common-obj-$(CONFIG_I2C) += eeprom_at24c.o
+common-obj-$(CONFIG_AT24C) += eeprom_at24c.o
common-obj-y += fw_cfg.o
common-obj-y += chrp_nvram.o
common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index d79a568f54..946f765f7f 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -434,6 +434,11 @@ static bool fw_cfg_data_mem_valid(void *opaque, hwaddr addr,
return addr == 0;
}
+static uint64_t fw_cfg_ctl_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+ return 0;
+}
+
static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
@@ -468,6 +473,7 @@ static bool fw_cfg_comb_valid(void *opaque, hwaddr addr,
}
static const MemoryRegionOps fw_cfg_ctl_mem_ops = {
+ .read = fw_cfg_ctl_mem_read,
.write = fw_cfg_ctl_mem_write,
.endianness = DEVICE_BIG_ENDIAN,
.valid.accepts = fw_cfg_ctl_mem_valid,
@@ -1109,12 +1115,7 @@ static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->ctl_iomem);
if (s->data_width > data_ops->valid.max_access_size) {
- /* memberwise copy because the "old_mmio" member is const */
- s->wide_data_ops.read = data_ops->read;
- s->wide_data_ops.write = data_ops->write;
- s->wide_data_ops.endianness = data_ops->endianness;
- s->wide_data_ops.valid = data_ops->valid;
- s->wide_data_ops.impl = data_ops->impl;
+ s->wide_data_ops = *data_ops;
s->wide_data_ops.valid.max_access_size = s->data_width;
s->wide_data_ops.impl.max_access_size = s->data_width;
diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c
index 9868e2eccc..9f33582706 100644
--- a/hw/pci-host/bonito.c
+++ b/hw/pci-host/bonito.c
@@ -595,7 +595,7 @@ static const VMStateDescription vmstate_bonito = {
}
};
-static int bonito_pcihost_initfn(SysBusDevice *dev)
+static void bonito_pcihost_realize(DeviceState *dev, Error **errp)
{
PCIHostState *phb = PCI_HOST_BRIDGE(dev);
@@ -603,8 +603,6 @@ static int bonito_pcihost_initfn(SysBusDevice *dev)
pci_bonito_set_irq, pci_bonito_map_irq,
dev, get_system_memory(), get_system_io(),
0x28, 32, TYPE_PCI_BUS);
-
- return 0;
}
static void bonito_realize(PCIDevice *dev, Error **errp)
@@ -684,7 +682,6 @@ PCIBus *bonito_init(qemu_irq *pic)
pcihost->pic = pic;
qdev_init_nofail(dev);
- /* set the pcihost pointer before bonito_initfn is called */
d = pci_create(phb->bus, PCI_DEVFN(0, 0), TYPE_PCI_BONITO);
s = PCI_BONITO(d);
s->pcihost = pcihost;
@@ -726,9 +723,9 @@ static const TypeInfo bonito_info = {
static void bonito_pcihost_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- k->init = bonito_pcihost_initfn;
+ dc->realize = bonito_pcihost_realize;
}
static const TypeInfo bonito_pcihost_info = {
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index 0e608347c1..47293a3915 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -144,7 +144,7 @@ static void i440fx_update_memory_mappings(PCII440FXState *d)
memory_region_transaction_begin();
for (i = 0; i < 13; i++) {
pam_update(&d->pam_regions[i], i,
- pd->config[I440FX_PAM + (DIV_ROUND_UP(i, 2))]);
+ pd->config[I440FX_PAM + DIV_ROUND_UP(i, 2)]);
}
memory_region_set_enabled(&d->smram_region,
!(pd->config[I440FX_SMRAM] & SMRAM_D_OPEN));
@@ -327,6 +327,10 @@ static void i440fx_pcihost_realize(DeviceState *dev, Error **errp)
sysbus_add_io(sbd, 0xcfc, &s->data_mem);
sysbus_init_ioports(sbd, 0xcfc, 4);
+
+ /* register i440fx 0xcf8 port as coalesced pio */
+ memory_region_set_flush_coalesced(&s->data_mem);
+ memory_region_add_coalescing(&s->conf_mem, 0, 4);
}
static void i440fx_realize(PCIDevice *dev, Error **errp)
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 02f9576588..966a7cf92d 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -51,6 +51,10 @@ static void q35_host_realize(DeviceState *dev, Error **errp)
sysbus_add_io(sbd, MCH_HOST_BRIDGE_CONFIG_DATA, &pci->data_mem);
sysbus_init_ioports(sbd, MCH_HOST_BRIDGE_CONFIG_DATA, 4);
+ /* register q35 0xcf8 port as coalesced pio */
+ memory_region_set_flush_coalesced(&pci->data_mem);
+ memory_region_add_coalescing(&pci->conf_mem, 0, 4);
+
pci->bus = pci_root_bus_new(DEVICE(s), "pcie.0",
s->mch.pci_address_space,
s->mch.address_space_io,
@@ -352,7 +356,7 @@ static void mch_update_pam(MCHPCIState *mch)
memory_region_transaction_begin();
for (i = 0; i < 13; i++) {
pam_update(&mch->pam_regions[i], i,
- pd->config[MCH_HOST_BRIDGE_PAM0 + (DIV_ROUND_UP(i, 2))]);
+ pd->config[MCH_HOST_BRIDGE_PAM0 + DIV_ROUND_UP(i, 2)]);
}
memory_region_transaction_commit();
}
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 51d0dec466..b937f0dc0a 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -1737,9 +1737,6 @@ static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
info->id = g_new0(PciDeviceId, 1);
info->id->vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
info->id->device = pci_get_word(dev->config + PCI_DEVICE_ID);
- info->id->subsystem = pci_get_word(dev->config + PCI_SUBSYSTEM_ID);
- info->id->subsystem_vendor =
- pci_get_word(dev->config + PCI_SUBSYSTEM_VENDOR_ID);
info->regions = qmp_query_pci_regions(dev);
info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");
@@ -1752,6 +1749,16 @@ static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
if (type == PCI_HEADER_TYPE_BRIDGE) {
info->has_pci_bridge = true;
info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num);
+ } else if (type == PCI_HEADER_TYPE_NORMAL) {
+ info->id->has_subsystem = info->id->has_subsystem_vendor = true;
+ info->id->subsystem = pci_get_word(dev->config + PCI_SUBSYSTEM_ID);
+ info->id->subsystem_vendor =
+ pci_get_word(dev->config + PCI_SUBSYSTEM_VENDOR_ID);
+ } else if (type == PCI_HEADER_TYPE_CARDBUS) {
+ info->id->has_subsystem = info->id->has_subsystem_vendor = true;
+ info->id->subsystem = pci_get_word(dev->config + PCI_CB_SUBSYSTEM_ID);
+ info->id->subsystem_vendor =
+ pci_get_word(dev->config + PCI_CB_SUBSYSTEM_VENDOR_ID);
}
return info;
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 9750464bf4..ad1bcc7990 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -148,8 +148,8 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
chip = object_property_get_link(OBJECT(dev), "chip", &local_err);
if (!chip) {
- error_propagate(errp, local_err);
- error_prepend(errp, "required link 'chip' not found: ");
+ error_propagate_prepend(errp, local_err,
+ "required link 'chip' not found: ");
return;
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 98868d893a..c08130facb 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -3128,14 +3128,12 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error *local_err = NULL;
sPAPRMachineState *ms = SPAPR_MACHINE(hotplug_dev);
PCDIMMDevice *dimm = PC_DIMM(dev);
- PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
- MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort);
uint64_t size, addr;
uint32_t node;
- size = memory_region_size(mr);
+ size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort);
- pc_dimm_plug(dev, MACHINE(ms), &local_err);
+ pc_dimm_plug(dimm, MACHINE(ms), &local_err);
if (local_err) {
goto out;
}
@@ -3158,7 +3156,7 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
return;
out_unplug:
- pc_dimm_unplug(dev, MACHINE(ms));
+ pc_dimm_unplug(dimm, MACHINE(ms));
out:
error_propagate(errp, local_err);
}
@@ -3169,9 +3167,7 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
const sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
PCDIMMDevice *dimm = PC_DIMM(dev);
- PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
Error *local_err = NULL;
- MemoryRegion *mr;
uint64_t size;
Object *memdev;
hwaddr pagesize;
@@ -3181,11 +3177,11 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
return;
}
- mr = ddc->get_memory_region(dimm, errp);
- if (!mr) {
+ size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
- size = memory_region_size(mr);
if (size % SPAPR_MEMORY_BLOCK_SIZE) {
error_setg(errp, "Hotplugged memory size must be a multiple of "
@@ -3202,7 +3198,7 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
return;
}
- pc_dimm_pre_plug(dev, MACHINE(hotplug_dev), NULL, errp);
+ pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp);
}
struct sPAPRDIMMState {
@@ -3257,9 +3253,8 @@ static sPAPRDIMMState *spapr_recover_pending_dimm_state(sPAPRMachineState *ms,
PCDIMMDevice *dimm)
{
sPAPRDRConnector *drc;
- PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
- MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort);
- uint64_t size = memory_region_size(mr);
+ uint64_t size = memory_device_get_region_size(MEMORY_DEVICE(dimm),
+ &error_abort);
uint32_t nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
uint32_t avail_lmbs = 0;
uint64_t addr_start, addr;
@@ -3314,7 +3309,7 @@ static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
sPAPRDIMMState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
- pc_dimm_unplug(dev, MACHINE(hotplug_dev));
+ pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev));
object_unparent(OBJECT(dev));
spapr_pending_dimm_unplugs_remove(spapr, ds);
}
@@ -3325,14 +3320,12 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
Error *local_err = NULL;
PCDIMMDevice *dimm = PC_DIMM(dev);
- PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
- MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort);
uint32_t nr_lmbs;
uint64_t size, addr_start, addr;
int i;
sPAPRDRConnector *drc;
- size = memory_region_size(mr);
+ size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index c2271e6ed4..58afa46204 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1724,16 +1724,15 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
if (smc->legacy_irq_allocation) {
irq = spapr_irq_findone(spapr, &local_err);
if (local_err) {
- error_propagate(errp, local_err);
- error_prepend(errp, "can't allocate LSIs: ");
+ error_propagate_prepend(errp, local_err,
+ "can't allocate LSIs: ");
return;
}
}
spapr_irq_claim(spapr, irq, true, &local_err);
if (local_err) {
- error_propagate(errp, local_err);
- error_prepend(errp, "can't allocate LSIs: ");
+ error_propagate_prepend(errp, local_err, "can't allocate LSIs: ");
return;
}
diff --git a/hw/riscv/sifive_clint.c b/hw/riscv/sifive_clint.c
index 7cc606e065..0d2fd52487 100644
--- a/hw/riscv/sifive_clint.c
+++ b/hw/riscv/sifive_clint.c
@@ -47,12 +47,12 @@ static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value)
if (cpu->env.timecmp <= rtc_r) {
/* if we're setting an MTIMECMP value in the "past",
immediately raise the timer interrupt */
- riscv_set_local_interrupt(cpu, MIP_MTIP, 1);
+ riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
return;
}
/* otherwise, set up the future timer interrupt */
- riscv_set_local_interrupt(cpu, MIP_MTIP, 0);
+ riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
diff = cpu->env.timecmp - rtc_r;
/* back to ns (note args switched in muldiv64) */
next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
@@ -67,7 +67,7 @@ static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value)
static void sifive_clint_timer_cb(void *opaque)
{
RISCVCPU *cpu = opaque;
- riscv_set_local_interrupt(cpu, MIP_MTIP, 1);
+ riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
}
/* CPU wants to read rtc or timecmp register */
@@ -132,7 +132,7 @@ static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
if (!env) {
error_report("clint: invalid timecmp hartid: %zu", hartid);
} else if ((addr & 0x3) == 0) {
- riscv_set_local_interrupt(RISCV_CPU(cpu), MIP_MSIP, value != 0);
+ riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value));
} else {
error_report("clint: invalid sip write: %08x", (uint32_t)addr);
}
diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c
index f635e6ff67..9cf9a1f986 100644
--- a/hw/riscv/sifive_plic.c
+++ b/hw/riscv/sifive_plic.c
@@ -142,10 +142,10 @@ static void sifive_plic_update(SiFivePLICState *plic)
int level = sifive_plic_irqs_pending(plic, addrid);
switch (mode) {
case PLICMode_M:
- riscv_set_local_interrupt(RISCV_CPU(cpu), MIP_MEIP, level);
+ riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, BOOL_TO_MASK(level));
break;
case PLICMode_S:
- riscv_set_local_interrupt(RISCV_CPU(cpu), MIP_SEIP, level);
+ riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_SEIP, BOOL_TO_MASK(level));
break;
default:
break;
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 862f8ff5f7..ef07df2442 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -230,7 +230,9 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
qemu_fdt_add_subnode(fdt, "/chosen");
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename);
- qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
+ if (cmdline) {
+ qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
+ }
g_free(nodename);
}
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index be5ef85e81..8a712ed490 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -156,8 +156,10 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap,
g_free(cells);
g_free(nodename);
- qemu_fdt_add_subnode(fdt, "/chosen");
- qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
+ if (cmdline) {
+ qemu_fdt_add_subnode(fdt, "/chosen");
+ qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
+ }
}
static void spike_v1_10_0_board_init(MachineState *machine)
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 005169eabc..4a137a503c 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -254,7 +254,9 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
qemu_fdt_add_subnode(fdt, "/chosen");
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename);
- qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
+ if (cmdline) {
+ qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
+ }
g_free(nodename);
return fdt;
@@ -385,6 +387,8 @@ static void riscv_virt_board_init(MachineState *machine)
serial_mm_init(system_memory, memmap[VIRT_UART0].base,
0, qdev_get_gpio_in(DEVICE(s->plic), UART0_IRQ), 399193,
serial_hd(0), DEVICE_LITTLE_ENDIAN);
+
+ g_free(plic_hart_config);
}
static void riscv_virt_board_machine_init(MachineClass *mc)
diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
index 5dbc00ce9b..ca68806e44 100644
--- a/hw/s390x/Makefile.objs
+++ b/hw/s390x/Makefile.objs
@@ -26,8 +26,10 @@ obj-$(call lnot,$(CONFIG_PCI)) += s390-pci-stub.o
obj-y += s390-skeys.o
obj-y += s390-stattrib.o
obj-y += tod.o
+obj-y += tod-qemu.o
obj-$(CONFIG_KVM) += tod-kvm.o
-obj-$(CONFIG_TCG) += tod-qemu.o
obj-$(CONFIG_KVM) += s390-skeys-kvm.o
obj-$(CONFIG_KVM) += s390-stattrib-kvm.o
obj-y += s390-ccw.o
+obj-y += ap-device.o
+obj-y += ap-bridge.o
diff --git a/hw/s390x/ap-bridge.c b/hw/s390x/ap-bridge.c
new file mode 100644
index 0000000000..3795d30dd7
--- /dev/null
+++ b/hw/s390x/ap-bridge.c
@@ -0,0 +1,78 @@
+/*
+ * ap bridge
+ *
+ * Copyright 2018 IBM Corp.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/sysbus.h"
+#include "qemu/bitops.h"
+#include "hw/s390x/ap-bridge.h"
+#include "cpu.h"
+
+static char *ap_bus_get_dev_path(DeviceState *dev)
+{
+ /* at most one */
+ return g_strdup_printf("/1");
+}
+
+static void ap_bus_class_init(ObjectClass *oc, void *data)
+{
+ BusClass *k = BUS_CLASS(oc);
+
+ k->get_dev_path = ap_bus_get_dev_path;
+ /* More than one ap device does not make sense */
+ k->max_dev = 1;
+}
+
+static const TypeInfo ap_bus_info = {
+ .name = TYPE_AP_BUS,
+ .parent = TYPE_BUS,
+ .instance_size = 0,
+ .class_init = ap_bus_class_init,
+};
+
+void s390_init_ap(void)
+{
+ DeviceState *dev;
+
+ /* If no AP instructions then no need for AP bridge */
+ if (!s390_has_feat(S390_FEAT_AP)) {
+ return;
+ }
+
+ /* Create bridge device */
+ dev = qdev_create(NULL, TYPE_AP_BRIDGE);
+ object_property_add_child(qdev_get_machine(), TYPE_AP_BRIDGE,
+ OBJECT(dev), NULL);
+ qdev_init_nofail(dev);
+
+ /* Create bus on bridge device */
+ qbus_create(TYPE_AP_BUS, dev, TYPE_AP_BUS);
+ }
+
+static void ap_bridge_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+}
+
+static const TypeInfo ap_bridge_info = {
+ .name = TYPE_AP_BRIDGE,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = 0,
+ .class_init = ap_bridge_class_init,
+};
+
+static void ap_register(void)
+{
+ type_register_static(&ap_bridge_info);
+ type_register_static(&ap_bus_info);
+}
+
+type_init(ap_register)
diff --git a/hw/s390x/ap-device.c b/hw/s390x/ap-device.c
new file mode 100644
index 0000000000..f5ac8db968
--- /dev/null
+++ b/hw/s390x/ap-device.c
@@ -0,0 +1,38 @@
+/*
+ * Adjunct Processor (AP) matrix device
+ *
+ * Copyright 2018 IBM Corp.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "qapi/error.h"
+#include "hw/qdev.h"
+#include "hw/s390x/ap-device.h"
+
+static void ap_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "AP device class";
+ dc->hotpluggable = false;
+}
+
+static const TypeInfo ap_device_info = {
+ .name = AP_DEVICE_TYPE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(APDevice),
+ .class_size = sizeof(DeviceClass),
+ .class_init = ap_class_init,
+ .abstract = true,
+};
+
+static void ap_device_register(void)
+{
+ type_register_static(&ap_device_info);
+}
+
+type_init(ap_device_register)
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 5a9fe45ce8..04ec5cc970 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -750,20 +750,25 @@ static void sch_handle_halt_func(SubchDev *sch)
}
-static void copy_sense_id_to_guest(SenseId *dest, SenseId *src)
+/*
+ * As the SenseId struct cannot be packed (would cause unaligned accesses), we
+ * have to copy the individual fields to an unstructured area using the correct
+ * layout (see SA22-7204-01 "Common I/O-Device Commands").
+ */
+static void copy_sense_id_to_guest(uint8_t *dest, SenseId *src)
{
int i;
- dest->reserved = src->reserved;
- dest->cu_type = cpu_to_be16(src->cu_type);
- dest->cu_model = src->cu_model;
- dest->dev_type = cpu_to_be16(src->dev_type);
- dest->dev_model = src->dev_model;
- dest->unused = src->unused;
- for (i = 0; i < ARRAY_SIZE(dest->ciw); i++) {
- dest->ciw[i].type = src->ciw[i].type;
- dest->ciw[i].command = src->ciw[i].command;
- dest->ciw[i].count = cpu_to_be16(src->ciw[i].count);
+ dest[0] = src->reserved;
+ stw_be_p(dest + 1, src->cu_type);
+ dest[3] = src->cu_model;
+ stw_be_p(dest + 4, src->dev_type);
+ dest[6] = src->dev_model;
+ dest[7] = src->unused;
+ for (i = 0; i < ARRAY_SIZE(src->ciw); i++) {
+ dest[8 + i * 4] = src->ciw[i].type;
+ dest[9 + i * 4] = src->ciw[i].command;
+ stw_be_p(dest + 10 + i * 4, src->ciw[i].count);
}
}
@@ -1044,9 +1049,10 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
break;
case CCW_CMD_SENSE_ID:
{
- SenseId sense_id;
+ /* According to SA22-7204-01, Sense-ID can store up to 256 bytes */
+ uint8_t sense_id[256];
- copy_sense_id_to_guest(&sense_id, &sch->id);
+ copy_sense_id_to_guest(sense_id, &sch->id);
/* Sense ID information is device specific. */
if (check_len) {
if (ccw.count != sizeof(sense_id)) {
@@ -1060,11 +1066,11 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
* have enough place to store at least bytes 0-3.
*/
if (len >= 4) {
- sense_id.reserved = 0xff;
+ sense_id[0] = 0xff;
} else {
- sense_id.reserved = 0;
+ sense_id[0] = 0;
}
- ccw_dstream_write_buf(&sch->cds, &sense_id, len);
+ ccw_dstream_write_buf(&sch->cds, sense_id, len);
sch->curr_status.scsw.count = ccw_dstream_residual_count(&sch->cds);
ret = 0;
break;
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 4e87b89418..b3a07a12d8 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -132,15 +132,15 @@ typedef struct QemuIplParameters QemuIplParameters;
struct S390IPLState {
/*< private >*/
DeviceState parent_obj;
+ IplParameterBlock iplb;
+ QemuIplParameters qipl;
uint64_t start_addr;
uint64_t compat_start_addr;
uint64_t bios_start_addr;
uint64_t compat_bios_start_addr;
bool enforce_bios;
- IplParameterBlock iplb;
bool iplb_valid;
bool netboot;
- QemuIplParameters qipl;
/* reset related properties don't have to be migrated or reset */
enum s390_reset reset_type;
int reset_cpu_index;
@@ -157,6 +157,7 @@ struct S390IPLState {
bool iplbext_migration;
};
typedef struct S390IPLState S390IPLState;
+QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong");
#define S390_IPL_TYPE_FCP 0x00
#define S390_IPL_TYPE_CCW 0x02
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index e3e0ebb7f6..e42e1b80d6 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -692,27 +692,35 @@ static void s390_pci_iommu_free(S390pciState *s, PCIBus *bus, int32_t devfn)
object_unref(OBJECT(iommu));
}
-static int s390_pcihost_init(SysBusDevice *dev)
+static void s390_pcihost_realize(DeviceState *dev, Error **errp)
{
PCIBus *b;
BusState *bus;
PCIHostState *phb = PCI_HOST_BRIDGE(dev);
S390pciState *s = S390_PCI_HOST_BRIDGE(dev);
+ Error *local_err = NULL;
DPRINTF("host_init\n");
- b = pci_register_root_bus(DEVICE(dev), NULL,
- s390_pci_set_irq, s390_pci_map_irq, NULL,
- get_system_memory(), get_system_io(), 0, 64,
- TYPE_PCI_BUS);
+ b = pci_register_root_bus(dev, NULL, s390_pci_set_irq, s390_pci_map_irq,
+ NULL, get_system_memory(), get_system_io(), 0,
+ 64, TYPE_PCI_BUS);
pci_setup_iommu(b, s390_pci_dma_iommu, s);
bus = BUS(b);
- qbus_set_hotplug_handler(bus, DEVICE(dev), NULL);
+ qbus_set_hotplug_handler(bus, dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
phb->bus = b;
- s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, DEVICE(s), NULL));
- qbus_set_hotplug_handler(BUS(s->bus), DEVICE(s), NULL);
+ s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, dev, NULL));
+ qbus_set_hotplug_handler(BUS(s->bus), dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
s->iommu_table = g_hash_table_new_full(g_int64_hash, g_int64_equal,
NULL, g_free);
@@ -722,9 +730,10 @@ static int s390_pcihost_init(SysBusDevice *dev)
QTAILQ_INIT(&s->zpci_devs);
css_register_io_adapters(CSS_IO_ADAPTER_PCI, true, false,
- S390_ADAPTER_SUPPRESSIBLE, &error_abort);
-
- return 0;
+ S390_ADAPTER_SUPPRESSIBLE, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ }
}
static int s390_pci_msix_init(S390PCIBusDevice *pbdev)
@@ -1018,12 +1027,11 @@ static void s390_pcihost_reset(DeviceState *dev)
static void s390_pcihost_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
dc->reset = s390_pcihost_reset;
- k->init = s390_pcihost_init;
+ dc->realize = s390_pcihost_realize;
hc->plug = s390_pcihost_hot_plug;
hc->unplug = s390_pcihost_hot_unplug;
msi_nonbroken = true;
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index f0f7fdcadd..a0615a8b35 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -32,6 +32,7 @@
#include "ipl.h"
#include "hw/s390x/s390-virtio-ccw.h"
#include "hw/s390x/css-bridge.h"
+#include "hw/s390x/ap-bridge.h"
#include "migration/register.h"
#include "cpu_models.h"
#include "hw/nmi.h"
@@ -263,6 +264,9 @@ static void ccw_init(MachineState *machine)
/* init the SIGP facility */
s390_init_sigp();
+ /* create AP bridge and bus(es) */
+ s390_init_ap();
+
/* get a BUS */
css_bus = virtual_css_bus_init();
s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
@@ -456,6 +460,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
s390mc->ri_allowed = true;
s390mc->cpu_model_allowed = true;
s390mc->css_migration_enabled = true;
+ s390mc->hpage_1m_allowed = true;
mc->init = ccw_init;
mc->reset = s390_machine_reset;
mc->hot_add_cpu = s390_hot_add_cpu;
@@ -535,6 +540,12 @@ bool cpu_model_allowed(void)
return get_machine_class()->cpu_model_allowed;
}
+bool hpage_1m_allowed(void)
+{
+ /* for "none" machine this results in true */
+ return get_machine_class()->hpage_1m_allowed;
+}
+
static char *machine_get_loadparm(Object *obj, Error **errp)
{
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
@@ -747,6 +758,9 @@ static void ccw_machine_3_0_instance_options(MachineState *machine)
static void ccw_machine_3_0_class_options(MachineClass *mc)
{
+ S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
+
+ s390mc->hpage_1m_allowed = false;
ccw_machine_3_1_class_options(mc);
SET_MACHINE_COMPAT(mc, CCW_COMPAT_3_0);
}
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index 996b40650d..d1e6534311 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -20,20 +20,7 @@
#include "hw/scsi/scsi.h"
#include "sysemu/dma.h"
#include "qemu/log.h"
-
-//#define DEBUG_LSI
-//#define DEBUG_LSI_REG
-
-#ifdef DEBUG_LSI
-#define DPRINTF(fmt, ...) \
-do { printf("lsi_scsi: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
+#include "trace.h"
static const char *names[] = {
"SCNTL0", "SCNTL1", "SCNTL2", "SCNTL3", "SCID", "SXFER", "SDID", "GPREG",
@@ -313,7 +300,7 @@ static inline int lsi_irq_on_rsl(LSIState *s)
static void lsi_soft_reset(LSIState *s)
{
- DPRINTF("Reset\n");
+ trace_lsi_reset();
s->carry = 0;
s->msg_action = 0;
@@ -484,15 +471,13 @@ static void lsi_update_irq(LSIState *s)
level = 1;
if (level != last_level) {
- DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n",
- level, s->dstat, s->sist1, s->sist0);
+ trace_lsi_update_irq(level, s->dstat, s->sist1, s->sist0);
last_level = level;
}
lsi_set_irq(s, level);
if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) {
- DPRINTF("Handled IRQs & disconnected, looking for pending "
- "processes\n");
+ trace_lsi_update_irq_disconnected();
QTAILQ_FOREACH(p, &s->queue, next) {
if (p->pending) {
lsi_reselect(s, p);
@@ -508,8 +493,7 @@ static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1)
uint32_t mask0;
uint32_t mask1;
- DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n",
- stat1, stat0, s->sist1, s->sist0);
+ trace_lsi_script_scsi_interrupt(stat1, stat0, s->sist1, s->sist0);
s->sist0 |= stat0;
s->sist1 |= stat1;
/* Stop processor on fatal or unmasked interrupt. As a special hack
@@ -527,7 +511,7 @@ static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1)
/* Stop SCRIPTS execution and raise a DMA interrupt. */
static void lsi_script_dma_interrupt(LSIState *s, int stat)
{
- DPRINTF("DMA Interrupt 0x%x prev 0x%x\n", stat, s->dstat);
+ trace_lsi_script_dma_interrupt(stat, s->dstat);
s->dstat |= stat;
lsi_update_irq(s);
lsi_stop_script(s);
@@ -547,9 +531,9 @@ static void lsi_bad_phase(LSIState *s, int out, int new_phase)
} else {
s->dsp = (s->scntl2 & LSI_SCNTL2_WSR ? s->pmjad2 : s->pmjad1);
}
- DPRINTF("Data phase mismatch jump to %08x\n", s->dsp);
+ trace_lsi_bad_phase_jump(s->dsp);
} else {
- DPRINTF("Phase mismatch interrupt\n");
+ trace_lsi_bad_phase_interrupt();
lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
lsi_stop_script(s);
}
@@ -576,7 +560,7 @@ static void lsi_disconnect(LSIState *s)
static void lsi_bad_selection(LSIState *s, uint32_t id)
{
- DPRINTF("Selected absent target %d\n", id);
+ trace_lsi_bad_selection(id);
lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
lsi_disconnect(s);
}
@@ -591,7 +575,7 @@ static void lsi_do_dma(LSIState *s, int out)
assert(s->current);
if (!s->current->dma_len) {
/* Wait until data is available. */
- DPRINTF("DMA no data available\n");
+ trace_lsi_do_dma_unavailable();
return;
}
@@ -611,7 +595,7 @@ static void lsi_do_dma(LSIState *s, int out)
else if (s->sbms)
addr |= ((uint64_t)s->sbms << 32);
- DPRINTF("DMA addr=0x" DMA_ADDR_FMT " len=%d\n", addr, count);
+ trace_lsi_do_dma(addr, count);
s->csbc += count;
s->dnad += count;
s->dbc -= count;
@@ -640,7 +624,7 @@ static void lsi_queue_command(LSIState *s)
{
lsi_request *p = s->current;
- DPRINTF("Queueing tag=0x%x\n", p->tag);
+ trace_lsi_queue_command(p->tag);
assert(s->current != NULL);
assert(s->current->dma_len == 0);
QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
@@ -654,9 +638,9 @@ static void lsi_queue_command(LSIState *s)
static void lsi_add_msg_byte(LSIState *s, uint8_t data)
{
if (s->msg_len >= LSI_MAX_MSGIN_LEN) {
- BADF("MSG IN data too long\n");
+ trace_lsi_add_msg_byte_error();
} else {
- DPRINTF("MSG IN 0x%02x\n", data);
+ trace_lsi_add_msg_byte(data);
s->msg[s->msg_len++] = data;
}
}
@@ -676,7 +660,7 @@ static void lsi_reselect(LSIState *s, lsi_request *p)
if (!(s->dcntl & LSI_DCNTL_COM)) {
s->sfbr = 1 << (id & 0x7);
}
- DPRINTF("Reselected target %d\n", id);
+ trace_lsi_reselect(id);
s->scntl1 |= LSI_SCNTL1_CON;
lsi_set_phase(s, PHASE_MI);
s->msg_action = p->out ? 2 : 3;
@@ -732,7 +716,7 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
lsi_request *p = req->hba_private;
if (p->pending) {
- BADF("Multiple IO pending for request %p\n", p);
+ trace_lsi_queue_req_error(p);
}
p->pending = len;
/* Reselect if waiting for it, or if reselection triggers an IRQ
@@ -747,7 +731,7 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
lsi_reselect(s, p);
return 0;
} else {
- DPRINTF("Queueing IO tag=0x%x\n", p->tag);
+ trace_lsi_queue_req(p->tag);
p->pending = len;
return 1;
}
@@ -760,7 +744,7 @@ static void lsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid
int out;
out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
- DPRINTF("Command complete status=%d\n", (int)status);
+ trace_lsi_command_complete(status);
s->status = status;
s->command_complete = 2;
if (s->waiting && s->dbc != 0) {
@@ -795,7 +779,7 @@ static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
/* host adapter (re)connected */
- DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, len);
+ trace_lsi_transfer_data(req->tag, len);
s->current->dma_len = len;
s->command_complete = 1;
if (s->waiting) {
@@ -814,7 +798,7 @@ static void lsi_do_command(LSIState *s)
uint32_t id;
int n;
- DPRINTF("Send command len=%d\n", s->dbc);
+ trace_lsi_do_command(s->dbc);
if (s->dbc > 16)
s->dbc = 16;
pci_dma_read(PCI_DEVICE(s), s->dnad, buf, s->dbc);
@@ -862,9 +846,10 @@ static void lsi_do_command(LSIState *s)
static void lsi_do_status(LSIState *s)
{
uint8_t status;
- DPRINTF("Get status len=%d status=%d\n", s->dbc, s->status);
- if (s->dbc != 1)
- BADF("Bad Status move\n");
+ trace_lsi_do_status(s->dbc, s->status);
+ if (s->dbc != 1) {
+ trace_lsi_do_status_error();
+ }
s->dbc = 1;
status = s->status;
s->sfbr = status;
@@ -877,7 +862,7 @@ static void lsi_do_status(LSIState *s)
static void lsi_do_msgin(LSIState *s)
{
int len;
- DPRINTF("Message in len=%d/%d\n", s->dbc, s->msg_len);
+ trace_lsi_do_msgin(s->dbc, s->msg_len);
s->sfbr = s->msg[0];
len = s->msg_len;
if (len > s->dbc)
@@ -942,36 +927,36 @@ static void lsi_do_msgout(LSIState *s)
current_req = lsi_find_by_tag(s, current_tag);
}
- DPRINTF("MSG out len=%d\n", s->dbc);
+ trace_lsi_do_msgout(s->dbc);
while (s->dbc) {
msg = lsi_get_msgbyte(s);
s->sfbr = msg;
switch (msg) {
case 0x04:
- DPRINTF("MSG: Disconnect\n");
+ trace_lsi_do_msgout_disconnect();
lsi_disconnect(s);
break;
case 0x08:
- DPRINTF("MSG: No Operation\n");
+ trace_lsi_do_msgout_noop();
lsi_set_phase(s, PHASE_CMD);
break;
case 0x01:
len = lsi_get_msgbyte(s);
msg = lsi_get_msgbyte(s);
(void)len; /* avoid a warning about unused variable*/
- DPRINTF("Extended message 0x%x (len %d)\n", msg, len);
+ trace_lsi_do_msgout_extended(msg, len);
switch (msg) {
case 1:
- DPRINTF("SDTR (ignored)\n");
+ trace_lsi_do_msgout_ignored("SDTR");
lsi_skip_msgbytes(s, 2);
break;
case 3:
- DPRINTF("WDTR (ignored)\n");
+ trace_lsi_do_msgout_ignored("WDTR");
lsi_skip_msgbytes(s, 1);
break;
case 4:
- DPRINTF("PPR (ignored)\n");
+ trace_lsi_do_msgout_ignored("PPR");
lsi_skip_msgbytes(s, 5);
break;
default:
@@ -980,19 +965,20 @@ static void lsi_do_msgout(LSIState *s)
break;
case 0x20: /* SIMPLE queue */
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
- DPRINTF("SIMPLE queue tag=0x%x\n", s->select_tag & 0xff);
+ trace_lsi_do_msgout_simplequeue(s->select_tag & 0xff);
break;
case 0x21: /* HEAD of queue */
- BADF("HEAD queue not implemented\n");
+ qemu_log_mask(LOG_UNIMP, "lsi_scsi: HEAD queue not implemented\n");
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
break;
case 0x22: /* ORDERED queue */
- BADF("ORDERED queue not implemented\n");
+ qemu_log_mask(LOG_UNIMP,
+ "lsi_scsi: ORDERED queue not implemented\n");
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
break;
case 0x0d:
/* The ABORT TAG message clears the current I/O process only. */
- DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag);
+ trace_lsi_do_msgout_abort(current_tag);
if (current_req) {
scsi_req_cancel(current_req->req);
}
@@ -1004,17 +990,17 @@ static void lsi_do_msgout(LSIState *s)
/* The ABORT message clears all I/O processes for the selecting
initiator on the specified logical unit of the target. */
if (msg == 0x06) {
- DPRINTF("MSG: ABORT tag=0x%x\n", current_tag);
+ trace_lsi_do_msgout_abort(current_tag);
}
/* The CLEAR QUEUE message clears all I/O processes for all
initiators on the specified logical unit of the target. */
if (msg == 0x0e) {
- DPRINTF("MSG: CLEAR QUEUE tag=0x%x\n", current_tag);
+ trace_lsi_do_msgout_clearqueue(current_tag);
}
/* The BUS DEVICE RESET message clears all I/O processes for all
initiators on all logical units of the target. */
if (msg == 0x0c) {
- DPRINTF("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag);
+ trace_lsi_do_msgout_busdevicereset(current_tag);
}
/* clear the current I/O process */
@@ -1042,14 +1028,14 @@ static void lsi_do_msgout(LSIState *s)
goto bad;
}
s->current_lun = msg & 7;
- DPRINTF("Select LUN %d\n", s->current_lun);
+ trace_lsi_do_msgout_select(s->current_lun);
lsi_set_phase(s, PHASE_CMD);
break;
}
}
return;
bad:
- BADF("Unimplemented message 0x%02x\n", msg);
+ qemu_log_mask(LOG_UNIMP, "Unimplemented message 0x%02x\n", msg);
lsi_set_phase(s, PHASE_MI);
lsi_add_msg_byte(s, 7); /* MESSAGE REJECT */
s->msg_action = 0;
@@ -1061,7 +1047,7 @@ static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
int n;
uint8_t buf[LSI_BUF_SIZE];
- DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count);
+ trace_lsi_memcpy(dest, src, count);
while (count) {
n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count;
lsi_mem_read(s, src, buf, n);
@@ -1076,7 +1062,7 @@ static void lsi_wait_reselect(LSIState *s)
{
lsi_request *p;
- DPRINTF("Wait Reselect\n");
+ trace_lsi_wait_reselect();
QTAILQ_FOREACH(p, &s->queue, next) {
if (p->pending) {
@@ -1109,14 +1095,14 @@ again:
}
addr = read_dword(s, s->dsp + 4);
addr_high = 0;
- DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr);
+ trace_lsi_execute_script(s->dsp, insn, addr);
s->dsps = addr;
s->dcmd = insn >> 24;
s->dsp += 8;
switch (insn >> 30) {
case 0: /* Block move. */
if (s->sist1 & LSI_SIST1_STO) {
- DPRINTF("Delayed select timeout\n");
+ trace_lsi_execute_script_blockmove_delayed();
lsi_stop_script(s);
break;
}
@@ -1171,8 +1157,9 @@ again:
addr_high = s->dbms;
break;
default:
- BADF("Illegal selector specified (0x%x > 0x15)"
- " for 64-bit DMA block move", selector);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "lsi_scsi: Illegal selector specified (0x%x > 0x15) "
+ "for 64-bit DMA block move", selector);
break;
}
}
@@ -1184,8 +1171,8 @@ again:
s->ia = s->dsp - 12;
}
if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
- DPRINTF("Wrong phase got %d expected %d\n",
- s->sstat1 & PHASE_MASK, (insn >> 24) & 7);
+ trace_lsi_execute_script_blockmove_badphase(s->sstat1 & PHASE_MASK,
+ (insn >> 24) & 7);
lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
break;
}
@@ -1217,8 +1204,8 @@ again:
lsi_do_msgin(s);
break;
default:
- BADF("Unimplemented phase %d\n", s->sstat1 & PHASE_MASK);
- exit(1);
+ qemu_log_mask(LOG_UNIMP, "lsi_scsi: Unimplemented phase %d\n",
+ s->sstat1 & PHASE_MASK);
}
s->dfifo = s->dbc & 0xff;
s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3);
@@ -1246,7 +1233,7 @@ again:
case 0: /* Select */
s->sdid = id;
if (s->scntl1 & LSI_SCNTL1_CON) {
- DPRINTF("Already reselected, jumping to alternative address\n");
+ trace_lsi_execute_script_io_alreadyreselected();
s->dsp = s->dnad;
break;
}
@@ -1256,8 +1243,8 @@ again:
lsi_bad_selection(s, id);
break;
}
- DPRINTF("Selected target %d%s\n",
- id, insn & (1 << 3) ? " ATN" : "");
+ trace_lsi_execute_script_io_selected(id,
+ insn & (1 << 3) ? " ATN" : "");
/* ??? Linux drivers compain when this is set. Maybe
it only applies in low-level mode (unimplemented).
lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
@@ -1269,7 +1256,7 @@ again:
lsi_set_phase(s, PHASE_MO);
break;
case 1: /* Disconnect */
- DPRINTF("Wait Disconnect\n");
+ trace_lsi_execute_script_io_disconnect();
s->scntl1 &= ~LSI_SCNTL1_CON;
break;
case 2: /* Wait Reselect */
@@ -1278,7 +1265,7 @@ again:
}
break;
case 3: /* Set */
- DPRINTF("Set%s%s%s%s\n",
+ trace_lsi_execute_script_io_set(
insn & (1 << 3) ? " ATN" : "",
insn & (1 << 6) ? " ACK" : "",
insn & (1 << 9) ? " TM" : "",
@@ -1288,14 +1275,14 @@ again:
lsi_set_phase(s, PHASE_MO);
}
if (insn & (1 << 9)) {
- BADF("Target mode not implemented\n");
- exit(1);
+ qemu_log_mask(LOG_UNIMP,
+ "lsi_scsi: Target mode not implemented\n");
}
if (insn & (1 << 10))
s->carry = 1;
break;
case 4: /* Clear */
- DPRINTF("Clear%s%s%s%s\n",
+ trace_lsi_execute_script_io_clear(
insn & (1 << 3) ? " ATN" : "",
insn & (1 << 6) ? " ACK" : "",
insn & (1 << 9) ? " TM" : "",
@@ -1313,18 +1300,17 @@ again:
uint8_t data8;
int reg;
int operator;
-#ifdef DEBUG_LSI
+
static const char *opcode_names[3] =
{"Write", "Read", "Read-Modify-Write"};
static const char *operator_names[8] =
{"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"};
-#endif
reg = ((insn >> 16) & 0x7f) | (insn & 0x80);
data8 = (insn >> 8) & 0xff;
opcode = (insn >> 27) & 7;
operator = (insn >> 24) & 7;
- DPRINTF("%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s\n",
+ trace_lsi_execute_script_io_opcode(
opcode_names[opcode - 5], reg,
operator_names[operator], data8, s->sfbr,
(insn & (1 << 23)) ? " SFBR" : "");
@@ -1404,21 +1390,21 @@ again:
int jmp;
if ((insn & 0x002e0000) == 0) {
- DPRINTF("NOP\n");
+ trace_lsi_execute_script_tc_nop();
break;
}
if (s->sist1 & LSI_SIST1_STO) {
- DPRINTF("Delayed select timeout\n");
+ trace_lsi_execute_script_tc_delayedselect_timeout();
lsi_stop_script(s);
break;
}
cond = jmp = (insn & (1 << 19)) != 0;
if (cond == jmp && (insn & (1 << 21))) {
- DPRINTF("Compare carry %d\n", s->carry == jmp);
+ trace_lsi_execute_script_tc_compc(s->carry == jmp);
cond = s->carry != 0;
}
if (cond == jmp && (insn & (1 << 17))) {
- DPRINTF("Compare phase %d %c= %d\n",
+ trace_lsi_execute_script_tc_compp(
(s->sstat1 & PHASE_MASK),
jmp ? '=' : '!',
((insn >> 24) & 7));
@@ -1428,7 +1414,7 @@ again:
uint8_t mask;
mask = (~insn >> 8) & 0xff;
- DPRINTF("Compare data 0x%x & 0x%x %c= 0x%x\n",
+ trace_lsi_execute_script_tc_compd(
s->sfbr, mask, jmp ? '=' : '!', insn & mask);
cond = (s->sfbr & mask) == (insn & mask);
}
@@ -1439,21 +1425,21 @@ again:
}
switch ((insn >> 27) & 7) {
case 0: /* Jump */
- DPRINTF("Jump to 0x%08x\n", addr);
+ trace_lsi_execute_script_tc_jump(addr);
s->adder = addr;
s->dsp = addr;
break;
case 1: /* Call */
- DPRINTF("Call 0x%08x\n", addr);
+ trace_lsi_execute_script_tc_call(addr);
s->temp = s->dsp;
s->dsp = addr;
break;
case 2: /* Return */
- DPRINTF("Return to 0x%08x\n", s->temp);
+ trace_lsi_execute_script_tc_return(s->temp);
s->dsp = s->temp;
break;
case 3: /* Interrupt */
- DPRINTF("Interrupt 0x%08x\n", s->dsps);
+ trace_lsi_execute_script_tc_interrupt(s->dsps);
if ((insn & (1 << 20)) != 0) {
s->istat0 |= LSI_ISTAT0_INTF;
lsi_update_irq(s);
@@ -1462,12 +1448,12 @@ again:
}
break;
default:
- DPRINTF("Illegal transfer control\n");
+ trace_lsi_execute_script_tc_illegal();
lsi_script_dma_interrupt(s, LSI_DSTAT_IID);
break;
}
} else {
- DPRINTF("Control condition failed\n");
+ trace_lsi_execute_script_tc_cc_failed();
}
}
break;
@@ -1495,13 +1481,12 @@ again:
reg = (insn >> 16) & 0xff;
if (insn & (1 << 24)) {
pci_dma_read(pci_dev, addr, data, n);
- DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n,
- addr, *(int *)data);
+ trace_lsi_execute_script_mm_load(reg, n, addr, *(int *)data);
for (i = 0; i < n; i++) {
lsi_reg_writeb(s, reg + i, data[i]);
}
} else {
- DPRINTF("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr);
+ trace_lsi_execute_script_mm_store(reg, n, addr);
for (i = 0; i < n; i++) {
data[i] = lsi_reg_readb(s, reg + i);
}
@@ -1515,8 +1500,10 @@ again:
assume this is the case and force an unexpected device disconnect.
This is apparently sufficient to beat the drivers into submission.
*/
- if (!(s->sien0 & LSI_SIST0_UDC))
- fprintf(stderr, "inf. loop with UDC masked\n");
+ if (!(s->sien0 & LSI_SIST0_UDC)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "lsi_scsi: inf. loop with UDC masked");
+ }
lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0);
lsi_disconnect(s);
} else if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) {
@@ -1526,7 +1513,7 @@ again:
goto again;
}
}
- DPRINTF("SCRIPTS execution stopped\n");
+ trace_lsi_execute_script_stop();
}
static uint8_t lsi_reg_readb(LSIState *s, int offset)
@@ -1761,10 +1748,8 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset)
#undef CASE_GET_REG24
#undef CASE_GET_REG32
-#ifdef DEBUG_LSI_REG
- DPRINTF("Read reg %s %x = %02x\n",
- offset < ARRAY_SIZE(names) ? names[offset] : "???", offset, ret);
-#endif
+ trace_lsi_reg_read(offset < ARRAY_SIZE(names) ? names[offset] : "???",
+ offset, ret);
return ret;
}
@@ -1782,21 +1767,22 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \
case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break;
-#ifdef DEBUG_LSI_REG
- DPRINTF("Write reg %s %x = %02x\n",
- offset < ARRAY_SIZE(names) ? names[offset] : "???", offset, val);
-#endif
+ trace_lsi_reg_write(offset < ARRAY_SIZE(names) ? names[offset] : "???",
+ offset, val);
+
switch (offset) {
case 0x00: /* SCNTL0 */
s->scntl0 = val;
if (val & LSI_SCNTL0_START) {
- BADF("Start sequence not implemented\n");
+ qemu_log_mask(LOG_UNIMP,
+ "lsi_scsi: Start sequence not implemented\n");
}
break;
case 0x01: /* SCNTL1 */
s->scntl1 = val & ~LSI_SCNTL1_SST;
if (val & LSI_SCNTL1_IARB) {
- BADF("Immediate Arbritration not implemented\n");
+ qemu_log_mask(LOG_UNIMP,
+ "lsi_scsi: Immediate Arbritration not implemented\n");
}
if (val & LSI_SCNTL1_RST) {
if (!(s->sstat0 & LSI_SSTAT0_RST)) {
@@ -1823,7 +1809,8 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
break;
case 0x06: /* SDID */
if ((s->ssid & 0x80) && (val & 0xf) != (s->ssid & 0xf)) {
- BADF("Destination ID does not match SSID\n");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "lsi_scsi: Destination ID does not match SSID\n");
}
s->sdid = val & 0xf;
break;
@@ -1851,7 +1838,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
lsi_update_irq(s);
}
if (s->waiting == 1 && val & LSI_ISTAT0_SIGP) {
- DPRINTF("Woken by SIGP\n");
+ trace_lsi_awoken();
s->waiting = 0;
s->dsp = s->dnad;
lsi_execute_script(s);
@@ -1878,13 +1865,15 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
CASE_SET_REG32(temp, 0x1c)
case 0x21: /* CTEST4 */
if (val & 7) {
- BADF("Unimplemented CTEST4-FBL 0x%x\n", val);
+ qemu_log_mask(LOG_UNIMP,
+ "lsi_scsi: Unimplemented CTEST4-FBL 0x%x\n", val);
}
s->ctest4 = val;
break;
case 0x22: /* CTEST5 */
if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) {
- BADF("CTEST5 DMA increment not implemented\n");
+ qemu_log_mask(LOG_UNIMP,
+ "lsi_scsi: CTEST5 DMA increment not implemented\n");
}
s->ctest5 = val;
break;
@@ -1941,7 +1930,8 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
break;
case 0x49: /* STIME1 */
if (val & 0xf) {
- DPRINTF("General purpose timer not implemented\n");
+ qemu_log_mask(LOG_UNIMP,
+ "lsi_scsi: General purpose timer not implemented\n");
/* ??? Raising the interrupt immediately seems to be sufficient
to keep the FreeBSD driver happy. */
lsi_script_scsi_interrupt(s, 0, LSI_SIST1_GEN);
@@ -1958,13 +1948,15 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
break;
case 0x4e: /* STEST2 */
if (val & 1) {
- BADF("Low level mode not implemented\n");
+ qemu_log_mask(LOG_UNIMP,
+ "lsi_scsi: Low level mode not implemented\n");
}
s->stest2 = val;
break;
case 0x4f: /* STEST3 */
if (val & 0x41) {
- BADF("SCSI FIFO test mode not implemented\n");
+ qemu_log_mask(LOG_UNIMP,
+ "lsi_scsi: SCSI FIFO test mode not implemented\n");
}
s->stest3 = val;
break;
diff --git a/hw/scsi/mptendian.c b/hw/scsi/mptendian.c
index 8ae39a76f4..79f99734d2 100644
--- a/hw/scsi/mptendian.c
+++ b/hw/scsi/mptendian.c
@@ -35,152 +35,155 @@
static void mptsas_fix_sgentry_endianness(MPISGEntry *sge)
{
- le32_to_cpus(&sge->FlagsLength);
+ sge->FlagsLength = le32_to_cpu(sge->FlagsLength);
if (sge->FlagsLength & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
- le64_to_cpus(&sge->u.Address64);
+ sge->u.Address64 = le64_to_cpu(sge->u.Address64);
} else {
- le32_to_cpus(&sge->u.Address32);
+ sge->u.Address32 = le32_to_cpu(sge->u.Address32);
}
}
static void mptsas_fix_sgentry_endianness_reply(MPISGEntry *sge)
{
if (sge->FlagsLength & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
- cpu_to_le64s(&sge->u.Address64);
+ sge->u.Address64 = cpu_to_le64(sge->u.Address64);
} else {
- cpu_to_le32s(&sge->u.Address32);
+ sge->u.Address32 = cpu_to_le32(sge->u.Address32);
}
- cpu_to_le32s(&sge->FlagsLength);
+ sge->FlagsLength = cpu_to_le32(sge->FlagsLength);
}
void mptsas_fix_scsi_io_endianness(MPIMsgSCSIIORequest *req)
{
- le32_to_cpus(&req->MsgContext);
- le32_to_cpus(&req->Control);
- le32_to_cpus(&req->DataLength);
- le32_to_cpus(&req->SenseBufferLowAddr);
+ req->MsgContext = le32_to_cpu(req->MsgContext);
+ req->Control = le32_to_cpu(req->Control);
+ req->DataLength = le32_to_cpu(req->DataLength);
+ req->SenseBufferLowAddr = le32_to_cpu(req->SenseBufferLowAddr);
}
void mptsas_fix_scsi_io_reply_endianness(MPIMsgSCSIIOReply *reply)
{
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
- cpu_to_le32s(&reply->TransferCount);
- cpu_to_le32s(&reply->SenseCount);
- cpu_to_le32s(&reply->ResponseInfo);
- cpu_to_le16s(&reply->TaskTag);
+ reply->MsgContext = cpu_to_le32(reply->MsgContext);
+ reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
+ reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
+ reply->TransferCount = cpu_to_le32(reply->TransferCount);
+ reply->SenseCount = cpu_to_le32(reply->SenseCount);
+ reply->ResponseInfo = cpu_to_le32(reply->ResponseInfo);
+ reply->TaskTag = cpu_to_le16(reply->TaskTag);
}
void mptsas_fix_scsi_task_mgmt_endianness(MPIMsgSCSITaskMgmt *req)
{
- le32_to_cpus(&req->MsgContext);
- le32_to_cpus(&req->TaskMsgContext);
+ req->MsgContext = le32_to_cpu(req->MsgContext);
+ req->TaskMsgContext = le32_to_cpu(req->TaskMsgContext);
}
void mptsas_fix_scsi_task_mgmt_reply_endianness(MPIMsgSCSITaskMgmtReply *reply)
{
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
- cpu_to_le32s(&reply->TerminationCount);
+ reply->MsgContext = cpu_to_le32(reply->MsgContext);
+ reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
+ reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
+ reply->TerminationCount = cpu_to_le32(reply->TerminationCount);
}
void mptsas_fix_ioc_init_endianness(MPIMsgIOCInit *req)
{
- le32_to_cpus(&req->MsgContext);
- le16_to_cpus(&req->ReplyFrameSize);
- le32_to_cpus(&req->HostMfaHighAddr);
- le32_to_cpus(&req->SenseBufferHighAddr);
- le32_to_cpus(&req->ReplyFifoHostSignalingAddr);
+ req->MsgContext = le32_to_cpu(req->MsgContext);
+ req->ReplyFrameSize = le16_to_cpu(req->ReplyFrameSize);
+ req->HostMfaHighAddr = le32_to_cpu(req->HostMfaHighAddr);
+ req->SenseBufferHighAddr = le32_to_cpu(req->SenseBufferHighAddr);
+ req->ReplyFifoHostSignalingAddr =
+ le32_to_cpu(req->ReplyFifoHostSignalingAddr);
mptsas_fix_sgentry_endianness(&req->HostPageBufferSGE);
- le16_to_cpus(&req->MsgVersion);
- le16_to_cpus(&req->HeaderVersion);
+ req->MsgVersion = le16_to_cpu(req->MsgVersion);
+ req->HeaderVersion = le16_to_cpu(req->HeaderVersion);
}
void mptsas_fix_ioc_init_reply_endianness(MPIMsgIOCInitReply *reply)
{
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
+ reply->MsgContext = cpu_to_le32(reply->MsgContext);
+ reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
+ reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
}
void mptsas_fix_ioc_facts_endianness(MPIMsgIOCFacts *req)
{
- le32_to_cpus(&req->MsgContext);
+ req->MsgContext = le32_to_cpu(req->MsgContext);
}
void mptsas_fix_ioc_facts_reply_endianness(MPIMsgIOCFactsReply *reply)
{
- cpu_to_le16s(&reply->MsgVersion);
- cpu_to_le16s(&reply->HeaderVersion);
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCExceptions);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
- cpu_to_le16s(&reply->ReplyQueueDepth);
- cpu_to_le16s(&reply->RequestFrameSize);
- cpu_to_le16s(&reply->ProductID);
- cpu_to_le32s(&reply->CurrentHostMfaHighAddr);
- cpu_to_le16s(&reply->GlobalCredits);
- cpu_to_le32s(&reply->CurrentSenseBufferHighAddr);
- cpu_to_le16s(&reply->CurReplyFrameSize);
- cpu_to_le32s(&reply->FWImageSize);
- cpu_to_le32s(&reply->IOCCapabilities);
- cpu_to_le16s(&reply->HighPriorityQueueDepth);
+ reply->MsgVersion = cpu_to_le16(reply->MsgVersion);
+ reply->HeaderVersion = cpu_to_le16(reply->HeaderVersion);
+ reply->MsgContext = cpu_to_le32(reply->MsgContext);
+ reply->IOCExceptions = cpu_to_le16(reply->IOCExceptions);
+ reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
+ reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
+ reply->ReplyQueueDepth = cpu_to_le16(reply->ReplyQueueDepth);
+ reply->RequestFrameSize = cpu_to_le16(reply->RequestFrameSize);
+ reply->ProductID = cpu_to_le16(reply->ProductID);
+ reply->CurrentHostMfaHighAddr = cpu_to_le32(reply->CurrentHostMfaHighAddr);
+ reply->GlobalCredits = cpu_to_le16(reply->GlobalCredits);
+ reply->CurrentSenseBufferHighAddr =
+ cpu_to_le32(reply->CurrentSenseBufferHighAddr);
+ reply->CurReplyFrameSize = cpu_to_le16(reply->CurReplyFrameSize);
+ reply->FWImageSize = cpu_to_le32(reply->FWImageSize);
+ reply->IOCCapabilities = cpu_to_le32(reply->IOCCapabilities);
+ reply->HighPriorityQueueDepth = cpu_to_le16(reply->HighPriorityQueueDepth);
mptsas_fix_sgentry_endianness_reply(&reply->HostPageBufferSGE);
- cpu_to_le32s(&reply->ReplyFifoHostSignalingAddr);
+ reply->ReplyFifoHostSignalingAddr =
+ cpu_to_le32(reply->ReplyFifoHostSignalingAddr);
}
void mptsas_fix_config_endianness(MPIMsgConfig *req)
{
- le16_to_cpus(&req->ExtPageLength);
- le32_to_cpus(&req->MsgContext);
- le32_to_cpus(&req->PageAddress);
+ req->ExtPageLength = le16_to_cpu(req->ExtPageLength);
+ req->MsgContext = le32_to_cpu(req->MsgContext);
+ req->PageAddress = le32_to_cpu(req->PageAddress);
mptsas_fix_sgentry_endianness(&req->PageBufferSGE);
}
void mptsas_fix_config_reply_endianness(MPIMsgConfigReply *reply)
{
- cpu_to_le16s(&reply->ExtPageLength);
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
+ reply->ExtPageLength = cpu_to_le16(reply->ExtPageLength);
+ reply->MsgContext = cpu_to_le32(reply->MsgContext);
+ reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
+ reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
}
void mptsas_fix_port_facts_endianness(MPIMsgPortFacts *req)
{
- le32_to_cpus(&req->MsgContext);
+ req->MsgContext = le32_to_cpu(req->MsgContext);
}
void mptsas_fix_port_facts_reply_endianness(MPIMsgPortFactsReply *reply)
{
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
- cpu_to_le16s(&reply->MaxDevices);
- cpu_to_le16s(&reply->PortSCSIID);
- cpu_to_le16s(&reply->ProtocolFlags);
- cpu_to_le16s(&reply->MaxPostedCmdBuffers);
- cpu_to_le16s(&reply->MaxPersistentIDs);
- cpu_to_le16s(&reply->MaxLanBuckets);
+ reply->MsgContext = cpu_to_le32(reply->MsgContext);
+ reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
+ reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
+ reply->MaxDevices = cpu_to_le16(reply->MaxDevices);
+ reply->PortSCSIID = cpu_to_le16(reply->PortSCSIID);
+ reply->ProtocolFlags = cpu_to_le16(reply->ProtocolFlags);
+ reply->MaxPostedCmdBuffers = cpu_to_le16(reply->MaxPostedCmdBuffers);
+ reply->MaxPersistentIDs = cpu_to_le16(reply->MaxPersistentIDs);
+ reply->MaxLanBuckets = cpu_to_le16(reply->MaxLanBuckets);
}
void mptsas_fix_port_enable_endianness(MPIMsgPortEnable *req)
{
- le32_to_cpus(&req->MsgContext);
+ req->MsgContext = le32_to_cpu(req->MsgContext);
}
void mptsas_fix_port_enable_reply_endianness(MPIMsgPortEnableReply *reply)
{
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
+ reply->MsgContext = cpu_to_le32(reply->MsgContext);
+ reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
+ reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
}
void mptsas_fix_event_notification_endianness(MPIMsgEventNotify *req)
{
- le32_to_cpus(&req->MsgContext);
+ req->MsgContext = le32_to_cpu(req->MsgContext);
}
void mptsas_fix_event_notification_reply_endianness(MPIMsgEventNotifyReply *reply)
@@ -188,16 +191,16 @@ void mptsas_fix_event_notification_reply_endianness(MPIMsgEventNotifyReply *repl
int length = reply->EventDataLength;
int i;
- cpu_to_le16s(&reply->EventDataLength);
- cpu_to_le32s(&reply->MsgContext);
- cpu_to_le16s(&reply->IOCStatus);
- cpu_to_le32s(&reply->IOCLogInfo);
- cpu_to_le32s(&reply->Event);
- cpu_to_le32s(&reply->EventContext);
+ reply->EventDataLength = cpu_to_le16(reply->EventDataLength);
+ reply->MsgContext = cpu_to_le32(reply->MsgContext);
+ reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
+ reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
+ reply->Event = cpu_to_le32(reply->Event);
+ reply->EventContext = cpu_to_le32(reply->EventContext);
/* Really depends on the event kind. This will do for now. */
for (i = 0; i < length; i++) {
- cpu_to_le32s(&reply->Data[i]);
+ reply->Data[i] = cpu_to_le32(reply->Data[i]);
}
}
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 5ae7baa082..e2c5408aa2 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -441,9 +441,18 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
}
switch (error) {
case 0:
- /* The command has run, no need to fake sense. */
+ /* A passthrough command has run and has produced sense data; check
+ * whether the error has to be handled by the guest or should rather
+ * pause the host.
+ */
assert(r->status && *r->status);
- scsi_req_complete(&r->req, *r->status);
+ error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense));
+ if (error == ECANCELED || error == EAGAIN || error == ENOTCONN ||
+ error == 0) {
+ /* These errors are handled by guest. */
+ scsi_req_complete(&r->req, *r->status);
+ return true;
+ }
break;
case ENOMEDIUM:
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
@@ -462,23 +471,17 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
break;
}
}
- if (!error) {
- assert(r->status && *r->status);
- error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense));
- if (error == ECANCELED || error == EAGAIN || error == ENOTCONN ||
- error == 0) {
- /* These errors are handled by guest. */
- scsi_req_complete(&r->req, *r->status);
- return true;
- }
+ blk_error_action(s->qdev.conf.blk, action, is_read, error);
+ if (action == BLOCK_ERROR_ACTION_IGNORE) {
+ scsi_req_complete(&r->req, 0);
+ return true;
}
- blk_error_action(s->qdev.conf.blk, action, is_read, error);
if (action == BLOCK_ERROR_ACTION_STOP) {
scsi_req_retry(&r->req);
}
- return action != BLOCK_ERROR_ACTION_IGNORE;
+ return false;
}
static void scsi_write_complete_noio(SCSIDiskReq *r, int ret)
@@ -2610,6 +2613,12 @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp)
return;
}
+ if (s->rotation_rate) {
+ error_report_once("rotation_rate is specified for scsi-block but is "
+ "not implemented. This option is deprecated and will "
+ "be removed in a future version");
+ }
+
/* check we are using a driver managing SG_IO (version 3 and after) */
rc = blk_ioctl(s->qdev.conf.blk, SG_GET_VERSION_NUM, &sg_version);
if (rc < 0) {
diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
index 6e299d0338..0fb6a99616 100644
--- a/hw/scsi/trace-events
+++ b/hw/scsi/trace-events
@@ -229,3 +229,65 @@ spapr_vscsi_process_login(void) "Got login, sending response !"
spapr_vscsi_queue_cmd_no_drive(uint64_t lun) "Command for lun 0x%08" PRIx64 " with no drive"
spapr_vscsi_queue_cmd(uint32_t qtag, unsigned cdb, const char *cmd, int lun, int ret) "Queued command tag 0x%"PRIx32" CMD 0x%x=%s LUN %d ret: %d"
spapr_vscsi_do_crq(unsigned c0, unsigned c1) "crq: %02x %02x ..."
+
+# hw/scsi/lsi53c895a.c
+lsi_reset(void) "Reset"
+lsi_update_irq(int level, uint8_t dstat, uint8_t sist1, uint8_t sist0) "Update IRQ level %d dstat 0x%02x sist 0x%02x0x%02x"
+lsi_update_irq_disconnected(void) "Handled IRQs & disconnected, looking for pending processes"
+lsi_script_scsi_interrupt(uint8_t stat1, uint8_t stat0, uint8_t sist1, uint8_t sist0) "SCSI Interrupt 0x%02x0x%02x prev 0x%02x0x%02x"
+lsi_script_dma_interrupt(uint8_t stat, uint8_t dstat) "DMA Interrupt 0x%x prev 0x%x"
+lsi_bad_phase_jump(uint32_t dsp) "Data phase mismatch jump to 0x%"PRIX32
+lsi_bad_phase_interrupt(void) "Phase mismatch interrupt"
+lsi_bad_selection(uint32_t id) "Selected absent target %"PRIu32
+lsi_do_dma_unavailable(void) "DMA no data available"
+lsi_do_dma(uint64_t addr, int len) "DMA addr=0x%"PRIx64" len=%d"
+lsi_queue_command(uint32_t tag) "Queueing tag=0x%"PRId32
+lsi_add_msg_byte_error(void) "MSG IN data too long"
+lsi_add_msg_byte(uint8_t data) "MSG IN 0x%02x"
+lsi_reselect(int id) "Reselected target %d"
+lsi_queue_req_error(void *p) "Multiple IO pending for request %p"
+lsi_queue_req(uint32_t tag) "Queueing IO tag=0x%"PRIx32
+lsi_command_complete(uint32_t status) "Command complete status=%"PRId32
+lsi_transfer_data(uint32_t tag, uint32_t len) "Data ready tag=0x%"PRIx32" len=%"PRId32
+lsi_do_command(uint32_t dbc) "Send command len=%"PRId32
+lsi_do_status(uint32_t dbc, uint8_t status) "Get status len=%"PRId32" status=%d"
+lsi_do_status_error(void) "Bad Status move"
+lsi_do_msgin(uint32_t dbc, int len) "Message in len=%"PRId32" %d"
+lsi_do_msgout(uint32_t dbc) "MSG out len=%"PRId32
+lsi_do_msgout_disconnect(void) "MSG: Disconnect"
+lsi_do_msgout_noop(void) "MSG: No Operation"
+lsi_do_msgout_extended(uint8_t msg, uint8_t len) "Extended message 0x%x (len %d)"
+lsi_do_msgout_ignored(const char *msg) "%s (ignored)"
+lsi_do_msgout_simplequeue(uint8_t select_tag) "SIMPLE queue tag=0x%x"
+lsi_do_msgout_abort(uint32_t tag) "MSG: ABORT TAG tag=0x%"PRId32
+lsi_do_msgout_clearqueue(uint32_t tag) "MSG: CLEAR QUEUE tag=0x%"PRIx32
+lsi_do_msgout_busdevicereset(uint32_t tag) "MSG: BUS DEVICE RESET tag=0x%"PRIx32
+lsi_do_msgout_select(int id) "Select LUN %d"
+lsi_memcpy(uint32_t dest, uint32_t src, int count) "memcpy dest 0x%"PRIx32" src 0x%"PRIx32" count %d"
+lsi_wait_reselect(void) "Wait Reselect"
+lsi_execute_script(uint32_t dsp, uint32_t insn, uint32_t addr) "SCRIPTS dsp=0x%"PRIx32" opcode 0x%"PRIx32" arg 0x%"PRIx32
+lsi_execute_script_blockmove_delayed(void) "Delayed select timeout"
+lsi_execute_script_blockmove_badphase(uint8_t phase, uint8_t expected) "Wrong phase got %d expected %d"
+lsi_execute_script_io_alreadyreselected(void) "Already reselected, jumping to alternative address"
+lsi_execute_script_io_selected(uint8_t id, const char *atn) "Selected target %d%s"
+lsi_execute_script_io_disconnect(void) "Wait Disconnect"
+lsi_execute_script_io_set(const char *atn, const char *ack, const char *tm, const char *cc) "Set%s%s%s%s"
+lsi_execute_script_io_clear(const char *atn, const char *ack, const char *tm, const char *cc) "Clear%s%s%s%s"
+lsi_execute_script_io_opcode(const char *opcode, int reg, const char *opname, uint8_t data8, uint32_t sfbr, const char *ssfbr) "%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s"
+lsi_execute_script_tc_nop(void) "NOP"
+lsi_execute_script_tc_delayedselect_timeout(void) "Delayed select timeout"
+lsi_execute_script_tc_compc(int result) "Compare carry %d"
+lsi_execute_script_tc_compp(uint8_t phase, int op, uint8_t insn_phase) "Compare phase %d %c= %d"
+lsi_execute_script_tc_compd(uint32_t sfbr, uint8_t mask, int op, int result) "Compare data 0x%"PRIx32" & 0x%x %c= 0x%x"
+lsi_execute_script_tc_jump(uint32_t addr) "Jump to 0x%"PRIx32
+lsi_execute_script_tc_call(uint32_t addr) "Call 0x%"PRIx32
+lsi_execute_script_tc_return(uint32_t addr) "Return to 0x%"PRIx32
+lsi_execute_script_tc_interrupt(uint32_t addr) "Interrupt 0x%"PRIx32
+lsi_execute_script_tc_illegal(void) "Illegal transfer control"
+lsi_execute_script_tc_cc_failed(void) "Control condition failed"
+lsi_execute_script_mm_load(int reg, int n, uint32_t addr, int data) "Load reg 0x%x size %d addr 0x%"PRIx32" = 0x%08x"
+lsi_execute_script_mm_store(int reg, int n, uint32_t addr) "Store reg 0x%x size %d addr 0x%"PRIx32
+lsi_execute_script_stop(void) "SCRIPTS execution stopped"
+lsi_awoken(void) "Woken by SIGP"
+lsi_reg_read(const char *name, int offset, uint8_t ret) "Read reg %s 0x%x = 0x%02x"
+lsi_reg_write(const char *name, int offset, uint8_t val) "Write reg %s 0x%x = 0x%02x"
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 5a3057d1f8..3aa99717e2 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -797,16 +797,8 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
virtio_scsi_acquire(s);
blk_set_aio_context(sd->conf.blk, s->ctx);
virtio_scsi_release(s);
- }
-}
-/* Announce the new device after it has been plugged */
-static void virtio_scsi_post_hotplug(HotplugHandler *hotplug_dev,
- DeviceState *dev)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
- VirtIOSCSI *s = VIRTIO_SCSI(vdev);
- SCSIDevice *sd = SCSI_DEVICE(dev);
+ }
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
virtio_scsi_acquire(s);
@@ -976,7 +968,6 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data)
vdc->start_ioeventfd = virtio_scsi_dataplane_start;
vdc->stop_ioeventfd = virtio_scsi_dataplane_stop;
hc->plug = virtio_scsi_hotplug;
- hc->post_plug = virtio_scsi_post_hotplug;
hc->unplug = virtio_scsi_hotunplug;
}
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index 95a143bfba..623d0333e8 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -284,6 +284,8 @@ static void ssi_sd_class_init(ObjectClass *klass, void *data)
k->cs_polarity = SSI_CS_LOW;
dc->vmsd = &vmstate_ssi_sd;
dc->reset = ssi_sd_reset;
+ /* Reason: init() method uses drive_get_next() */
+ dc->user_creatable = false;
}
static const TypeInfo ssi_sd_info = {
diff --git a/hw/sh4/sh_pci.c b/hw/sh4/sh_pci.c
index 4ec2e35500..379d0685ed 100644
--- a/hw/sh4/sh_pci.c
+++ b/hw/sh4/sh_pci.c
@@ -120,16 +120,15 @@ static void sh_pci_set_irq(void *opaque, int irq_num, int level)
qemu_set_irq(pic[irq_num], level);
}
-static int sh_pci_device_init(SysBusDevice *dev)
+static void sh_pci_device_realize(DeviceState *dev, Error **errp)
{
- PCIHostState *phb;
- SHPCIState *s;
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ SHPCIState *s = SH_PCI_HOST_BRIDGE(dev);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
int i;
- s = SH_PCI_HOST_BRIDGE(dev);
- phb = PCI_HOST_BRIDGE(s);
for (i = 0; i < 4; i++) {
- sysbus_init_irq(dev, &s->irq[i]);
+ sysbus_init_irq(sbd, &s->irq[i]);
}
phb->bus = pci_register_root_bus(DEVICE(dev), "pci",
sh_pci_set_irq, sh_pci_map_irq,
@@ -143,13 +142,12 @@ static int sh_pci_device_init(SysBusDevice *dev)
&s->memconfig_p4, 0, 0x224);
memory_region_init_alias(&s->isa, OBJECT(s), "sh_pci.isa",
get_system_io(), 0, 0x40000);
- sysbus_init_mmio(dev, &s->memconfig_p4);
- sysbus_init_mmio(dev, &s->memconfig_a7);
+ sysbus_init_mmio(sbd, &s->memconfig_p4);
+ sysbus_init_mmio(sbd, &s->memconfig_a7);
s->iobr = 0xfe240000;
memory_region_add_subregion(get_system_memory(), s->iobr, &s->isa);
s->dev = pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "sh_pci_host");
- return 0;
}
static void sh_pci_host_realize(PCIDevice *d, Error **errp)
@@ -187,9 +185,9 @@ static const TypeInfo sh_pci_host_info = {
static void sh_pci_device_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- sdc->init = sh_pci_device_init;
+ dc->realize = sh_pci_device_realize;
}
static const TypeInfo sh_pci_device_info = {
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index a27e54b2fa..920939454e 100644
--- a/hw/smbios/smbios.c
+++ b/hw/smbios/smbios.c
@@ -950,6 +950,7 @@ static void save_opt_list(size_t *ndest, const char ***dest,
void smbios_entry_add(QemuOpts *opts, Error **errp)
{
+ Error *err = NULL;
const char *val;
assert(!smbios_immutable);
@@ -960,12 +961,16 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
int size;
struct smbios_table *table; /* legacy mode only */
- qemu_opts_validate(opts, qemu_smbios_file_opts, &error_fatal);
+ qemu_opts_validate(opts, qemu_smbios_file_opts, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
size = get_image_size(val);
if (size == -1 || size < sizeof(struct smbios_structure_header)) {
- error_report("Cannot read SMBIOS file %s", val);
- exit(1);
+ error_setg(errp, "Cannot read SMBIOS file %s", val);
+ return;
}
/*
@@ -978,14 +983,15 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
smbios_tables_len);
if (load_image(val, (uint8_t *)header) != size) {
- error_report("Failed to load SMBIOS file %s", val);
- exit(1);
+ error_setg(errp, "Failed to load SMBIOS file %s", val);
+ return;
}
if (test_bit(header->type, have_fields_bitmap)) {
- error_report("can't load type %d struct, fields already specified!",
- header->type);
- exit(1);
+ error_setg(errp,
+ "can't load type %d struct, fields already specified!",
+ header->type);
+ return;
}
set_bit(header->type, have_binfile_bitmap);
@@ -1030,19 +1036,23 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
unsigned long type = strtoul(val, NULL, 0);
if (type > SMBIOS_MAX_TYPE) {
- error_report("out of range!");
- exit(1);
+ error_setg(errp, "out of range!");
+ return;
}
if (test_bit(type, have_binfile_bitmap)) {
- error_report("can't add fields, binary file already loaded!");
- exit(1);
+ error_setg(errp, "can't add fields, binary file already loaded!");
+ return;
}
set_bit(type, have_fields_bitmap);
switch (type) {
case 0:
- qemu_opts_validate(opts, qemu_smbios_type0_opts, &error_fatal);
+ qemu_opts_validate(opts, qemu_smbios_type0_opts, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
save_opt(&type0.vendor, opts, "vendor");
save_opt(&type0.version, opts, "version");
save_opt(&type0.date, opts, "date");
@@ -1051,14 +1061,18 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
val = qemu_opt_get(opts, "release");
if (val) {
if (sscanf(val, "%hhu.%hhu", &type0.major, &type0.minor) != 2) {
- error_report("Invalid release");
- exit(1);
+ error_setg(errp, "Invalid release");
+ return;
}
type0.have_major_minor = true;
}
return;
case 1:
- qemu_opts_validate(opts, qemu_smbios_type1_opts, &error_fatal);
+ qemu_opts_validate(opts, qemu_smbios_type1_opts, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
save_opt(&type1.manufacturer, opts, "manufacturer");
save_opt(&type1.product, opts, "product");
save_opt(&type1.version, opts, "version");
@@ -1069,14 +1083,18 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
val = qemu_opt_get(opts, "uuid");
if (val) {
if (qemu_uuid_parse(val, &qemu_uuid) != 0) {
- error_report("Invalid UUID");
- exit(1);
+ error_setg(errp, "Invalid UUID");
+ return;
}
qemu_uuid_set = true;
}
return;
case 2:
- qemu_opts_validate(opts, qemu_smbios_type2_opts, &error_fatal);
+ qemu_opts_validate(opts, qemu_smbios_type2_opts, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
save_opt(&type2.manufacturer, opts, "manufacturer");
save_opt(&type2.product, opts, "product");
save_opt(&type2.version, opts, "version");
@@ -1085,7 +1103,11 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
save_opt(&type2.location, opts, "location");
return;
case 3:
- qemu_opts_validate(opts, qemu_smbios_type3_opts, &error_fatal);
+ qemu_opts_validate(opts, qemu_smbios_type3_opts, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
save_opt(&type3.manufacturer, opts, "manufacturer");
save_opt(&type3.version, opts, "version");
save_opt(&type3.serial, opts, "serial");
@@ -1093,7 +1115,11 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
save_opt(&type3.sku, opts, "sku");
return;
case 4:
- qemu_opts_validate(opts, qemu_smbios_type4_opts, &error_fatal);
+ qemu_opts_validate(opts, qemu_smbios_type4_opts, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
save_opt(&type4.sock_pfx, opts, "sock_pfx");
save_opt(&type4.manufacturer, opts, "manufacturer");
save_opt(&type4.version, opts, "version");
@@ -1102,11 +1128,19 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
save_opt(&type4.part, opts, "part");
return;
case 11:
- qemu_opts_validate(opts, qemu_smbios_type11_opts, &error_fatal);
+ qemu_opts_validate(opts, qemu_smbios_type11_opts, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
save_opt_list(&type11.nvalues, &type11.values, opts, "value");
return;
case 17:
- qemu_opts_validate(opts, qemu_smbios_type17_opts, &error_fatal);
+ qemu_opts_validate(opts, qemu_smbios_type17_opts, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
save_opt(&type17.loc_pfx, opts, "loc_pfx");
save_opt(&type17.bank, opts, "bank");
save_opt(&type17.manufacturer, opts, "manufacturer");
@@ -1116,12 +1150,12 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
type17.speed = qemu_opt_get_number(opts, "speed", 0);
return;
default:
- error_report("Don't know how to build fields for SMBIOS type %ld",
- type);
- exit(1);
+ error_setg(errp,
+ "Don't know how to build fields for SMBIOS type %ld",
+ type);
+ return;
}
}
- error_report("Must specify type= or file=");
- exit(1);
+ error_setg(errp, "Must specify type= or file=");
}
diff --git a/hw/sparc64/niagara.c b/hw/sparc64/niagara.c
index 4fa8cb2904..f8a856f611 100644
--- a/hw/sparc64/niagara.c
+++ b/hw/sparc64/niagara.c
@@ -29,7 +29,7 @@
#include "hw/hw.h"
#include "hw/boards.h"
#include "hw/char/serial.h"
-#include "hw/empty_slot.h"
+#include "hw/misc/unimp.h"
#include "hw/loader.h"
#include "hw/sparc/sparc64.h"
#include "hw/timer/sun4v-rtc.h"
@@ -161,7 +161,7 @@ static void niagara_init(MachineState *machine)
serial_mm_init(sysmem, NIAGARA_UART_BASE, 0, NULL, 115200,
serial_hd(0), DEVICE_BIG_ENDIAN);
}
- empty_slot_init(NIAGARA_IOBBASE, NIAGARA_IOBSIZE);
+ create_unimplemented_device("sun4v-iob", NIAGARA_IOBBASE, NIAGARA_IOBSIZE);
sun4v_rtc_init(NIAGARA_RTC_BASE);
}
diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c
index 83585bc8b2..3dae303d5b 100644
--- a/hw/ssi/xilinx_spi.c
+++ b/hw/ssi/xilinx_spi.c
@@ -319,9 +319,9 @@ static const MemoryRegionOps spi_ops = {
}
};
-static int xilinx_spi_init(SysBusDevice *sbd)
+static void xilinx_spi_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
XilinxSPI *s = XILINX_SPI(dev);
int i;
@@ -344,8 +344,6 @@ static int xilinx_spi_init(SysBusDevice *sbd)
fifo8_create(&s->tx_fifo, FIFO_CAPACITY);
fifo8_create(&s->rx_fifo, FIFO_CAPACITY);
-
- return 0;
}
static const VMStateDescription vmstate_xilinx_spi = {
@@ -368,9 +366,8 @@ static Property xilinx_spi_properties[] = {
static void xilinx_spi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = xilinx_spi_init;
+ dc->realize = xilinx_spi_realize;
dc->reset = xlx_spi_reset;
dc->props = xilinx_spi_properties;
dc->vmsd = &vmstate_xilinx_spi;
diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
index 54b400b94a..5c786e5128 100644
--- a/hw/timer/aspeed_timer.c
+++ b/hw/timer/aspeed_timer.c
@@ -454,8 +454,7 @@ static void aspeed_timer_realize(DeviceState *dev, Error **errp)
obj = object_property_get_link(OBJECT(dev), "scu", &err);
if (!obj) {
- error_propagate(errp, err);
- error_prepend(errp, "required link 'scu' not found: ");
+ error_propagate_prepend(errp, err, "required link 'scu' not found: ");
return;
}
s->scu = ASPEED_SCU(obj);
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index acee47da0e..e4e4de8b8a 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -34,6 +34,7 @@
#include "qapi/qapi-commands-misc.h"
#include "qapi/qapi-events-misc.h"
#include "qapi/visitor.h"
+#include "exec/address-spaces.h"
#ifdef TARGET_I386
#include "hw/i386/apic.h"
@@ -70,6 +71,7 @@ typedef struct RTCState {
ISADevice parent_obj;
MemoryRegion io;
+ MemoryRegion coalesced_io;
uint8_t cmos_data[128];
uint8_t cmos_index;
int32_t base_year;
@@ -990,6 +992,13 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
memory_region_init_io(&s->io, OBJECT(s), &cmos_ops, s, "rtc", 2);
isa_register_ioport(isadev, &s->io, base);
+ /* register rtc 0x70 port for coalesced_pio */
+ memory_region_set_flush_coalesced(&s->io);
+ memory_region_init_io(&s->coalesced_io, OBJECT(s), &cmos_ops,
+ s, "rtc-index", 1);
+ memory_region_add_subregion(&s->io, 0, &s->coalesced_io);
+ memory_region_add_coalescing(&s->coalesced_io, 0, 1);
+
qdev_set_legacy_instance_id(dev, base, 3);
qemu_register_reset(rtc_reset, s);
diff --git a/hw/timer/sun4v-rtc.c b/hw/timer/sun4v-rtc.c
index 310523225f..4e7f6a1eff 100644
--- a/hw/timer/sun4v-rtc.c
+++ b/hw/timer/sun4v-rtc.c
@@ -14,15 +14,8 @@
#include "hw/sysbus.h"
#include "qemu/timer.h"
#include "hw/timer/sun4v-rtc.h"
+#include "trace.h"
-//#define DEBUG_SUN4V_RTC
-
-#ifdef DEBUG_SUN4V_RTC
-#define DPRINTF(fmt, ...) \
- do { printf("sun4v_rtc: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
#define TYPE_SUN4V_RTC "sun4v_rtc"
#define SUN4V_RTC(obj) OBJECT_CHECK(Sun4vRtc, (obj), TYPE_SUN4V_RTC)
@@ -41,14 +34,14 @@ static uint64_t sun4v_rtc_read(void *opaque, hwaddr addr,
/* accessing the high 32 bits */
val >>= 32;
}
- DPRINTF("read from " TARGET_FMT_plx " val %lx\n", addr, val);
+ trace_sun4v_rtc_read(addr, val);
return val;
}
static void sun4v_rtc_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
- DPRINTF("write 0x%x to " TARGET_FMT_plx "\n", (unsigned)val, addr);
+ trace_sun4v_rtc_read(addr, val);
}
static const MemoryRegionOps sun4v_rtc_ops = {
@@ -70,21 +63,21 @@ void sun4v_rtc_init(hwaddr addr)
sysbus_mmio_map(s, 0, addr);
}
-static int sun4v_rtc_init1(SysBusDevice *dev)
+static void sun4v_rtc_realize(DeviceState *dev, Error **errp)
{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
Sun4vRtc *s = SUN4V_RTC(dev);
memory_region_init_io(&s->iomem, OBJECT(s), &sun4v_rtc_ops, s,
"sun4v-rtc", 0x08ULL);
- sysbus_init_mmio(dev, &s->iomem);
- return 0;
+ sysbus_init_mmio(sbd, &s->iomem);
}
static void sun4v_rtc_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- k->init = sun4v_rtc_init1;
+ dc->realize = sun4v_rtc_realize;
}
static const TypeInfo sun4v_rtc_info = {
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
index fa4213df5b..75bd3b1042 100644
--- a/hw/timer/trace-events
+++ b/hw/timer/trace-events
@@ -56,7 +56,7 @@ systick_timer_tick(void) "systick reload"
systick_read(uint64_t addr, uint32_t value, unsigned size) "systick read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
systick_write(uint64_t addr, uint32_t value, unsigned size) "systick write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
-# hw/char/cmsdk_apb_timer.c
+# hw/timer/cmsdk_apb_timer.c
cmsdk_apb_timer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB timer read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
cmsdk_apb_timer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB timer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
cmsdk_apb_timer_reset(void) "CMSDK APB timer: reset"
@@ -66,5 +66,9 @@ cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK A
cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset"
+# hw/timer/sun4v-rtc.c
+sun4v_rtc_read(uint64_t addr, uint64_t value) "read: addr 0x%" PRIx64 " value 0x%" PRIx64
+sun4v_rtc_write(uint64_t addr, uint64_t value) "write: addr 0x%" PRIx64 " value 0x%" PRIx64
+
# hw/timer/xlnx-zynqmp-rtc.c
xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec) "Get time from host: %d-%d-%d %2d:%02d:%02d"
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index 11f7720d71..bf796d67e6 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -340,8 +340,9 @@ static USBDevice *usb_try_create_simple(USBBus *bus, const char *name,
}
object_property_set_bool(OBJECT(dev), true, "realized", &err);
if (err) {
- error_propagate(errp, err);
- error_prepend(errp, "Failed to initialize USB device '%s': ", name);
+ error_propagate_prepend(errp, err,
+ "Failed to initialize USB device '%s': ",
+ name);
return NULL;
}
return dev;
diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c
index 5c8b3c9907..25976ed84f 100644
--- a/hw/usb/ccid-card-emulated.c
+++ b/hw/usb/ccid-card-emulated.c
@@ -409,6 +409,12 @@ static int init_event_notifier(EmulatedState *card, Error **errp)
return 0;
}
+static void clean_event_notifier(EmulatedState *card)
+{
+ event_notifier_set_handler(&card->notifier, NULL);
+ event_notifier_cleanup(&card->notifier);
+}
+
#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
#define CERTIFICATES_ARGS_TEMPLATE\
"db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)"
@@ -493,7 +499,7 @@ static void emulated_realize(CCIDCardState *base, Error **errp)
card->reader = NULL;
card->quit_apdu_thread = 0;
if (init_event_notifier(card, errp) < 0) {
- return;
+ goto out1;
}
card->backend = 0;
@@ -507,7 +513,7 @@ static void emulated_realize(CCIDCardState *base, Error **errp)
for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) {
error_append_hint(errp, "%s\n", ptable->name);
}
- return;
+ goto out2;
}
/* TODO: a passthru backened that works on local machine. third card type?*/
@@ -517,31 +523,39 @@ static void emulated_realize(CCIDCardState *base, Error **errp)
} else {
error_setg(errp, "%s: you must provide all three certs for"
" certificates backend", TYPE_EMULATED_CCID);
- return;
+ goto out2;
}
} else {
if (card->backend != BACKEND_NSS_EMULATED) {
error_setg(errp, "%s: bad backend specified. The options are:%s"
" (default), %s.", TYPE_EMULATED_CCID,
BACKEND_NSS_EMULATED_NAME, BACKEND_CERTIFICATES_NAME);
- return;
+ goto out2;
}
if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) {
error_setg(errp, "%s: unexpected cert parameters to nss emulated "
"backend", TYPE_EMULATED_CCID);
- return;
+ goto out2;
}
/* default to mirroring the local hardware readers */
ret = wrap_vcard_emul_init(NULL);
}
if (ret != VCARD_EMUL_OK) {
error_setg(errp, "%s: failed to initialize vcard", TYPE_EMULATED_CCID);
- return;
+ goto out2;
}
qemu_thread_create(&card->event_thread_id, "ccid/event", event_thread,
card, QEMU_THREAD_JOINABLE);
qemu_thread_create(&card->apdu_thread_id, "ccid/apdu", handle_apdu_thread,
card, QEMU_THREAD_JOINABLE);
+
+out2:
+ clean_event_notifier(card);
+out1:
+ qemu_cond_destroy(&card->handle_apdu_cond);
+ qemu_mutex_destroy(&card->handle_apdu_mutex);
+ qemu_mutex_destroy(&card->vreader_mutex);
+ qemu_mutex_destroy(&card->event_list_mutex);
}
static void emulated_unrealize(CCIDCardState *base, Error **errp)
@@ -556,6 +570,7 @@ static void emulated_unrealize(CCIDCardState *base, Error **errp)
qemu_cond_signal(&card->handle_apdu_cond);
qemu_thread_join(&card->apdu_thread_id);
+ clean_event_notifier(card);
/* threads exited, can destroy all condvars/mutexes */
qemu_cond_destroy(&card->handle_apdu_cond);
qemu_mutex_destroy(&card->handle_apdu_mutex);
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index 66656a1133..c34cf5b73a 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -57,7 +57,7 @@ typedef struct {
qemu_irq irq;
MemoryRegion mem;
AddressSpace *as;
- int num_ports;
+ uint32_t num_ports;
const char *name;
QEMUTimer *eof_timer;
@@ -1850,7 +1850,7 @@ static USBBusOps ohci_bus_ops = {
};
static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
- int num_ports, dma_addr_t localmem_base,
+ uint32_t num_ports, dma_addr_t localmem_base,
char *masterbus, uint32_t firstport,
AddressSpace *as, Error **errp)
{
@@ -1860,7 +1860,7 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
ohci->as = as;
if (num_ports > OHCI_MAX_PORTS) {
- error_setg(errp, "OHCI num-ports=%d is too big (limit is %d ports)",
+ error_setg(errp, "OHCI num-ports=%u is too big (limit is %u ports)",
num_ports, OHCI_MAX_PORTS);
return;
}
diff --git a/hw/vfio/Makefile.objs b/hw/vfio/Makefile.objs
index a2e7a0a7cf..8b3f664d85 100644
--- a/hw/vfio/Makefile.objs
+++ b/hw/vfio/Makefile.objs
@@ -6,4 +6,5 @@ obj-$(CONFIG_SOFTMMU) += platform.o
obj-$(CONFIG_VFIO_XGMAC) += calxeda-xgmac.o
obj-$(CONFIG_VFIO_AMD_XGBE) += amd-xgbe.o
obj-$(CONFIG_SOFTMMU) += spapr.o
+obj-$(CONFIG_VFIO_AP) += ap.o
endif
diff --git a/hw/vfio/amd-xgbe.c b/hw/vfio/amd-xgbe.c
index 0c4ec4ba25..ee64a3b4a2 100644
--- a/hw/vfio/amd-xgbe.c
+++ b/hw/vfio/amd-xgbe.c
@@ -20,6 +20,7 @@ static void amd_xgbe_realize(DeviceState *dev, Error **errp)
VFIOAmdXgbeDeviceClass *k = VFIO_AMD_XGBE_DEVICE_GET_CLASS(dev);
vdev->compat = g_strdup("amd,xgbe-seattle-v1a");
+ vdev->num_compat = 1;
k->parent_realize(dev, errp);
}
diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c
new file mode 100644
index 0000000000..3962bb74e5
--- /dev/null
+++ b/hw/vfio/ap.c
@@ -0,0 +1,181 @@
+/*
+ * VFIO based AP matrix device assignment
+ *
+ * Copyright 2018 IBM Corp.
+ * Author(s): Tony Krowiak <akrowiak@linux.ibm.com>
+ * Halil Pasic <pasic@linux.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include <linux/vfio.h>
+#include <sys/ioctl.h>
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/sysbus.h"
+#include "hw/vfio/vfio.h"
+#include "hw/vfio/vfio-common.h"
+#include "hw/s390x/ap-device.h"
+#include "qemu/error-report.h"
+#include "qemu/queue.h"
+#include "qemu/option.h"
+#include "qemu/config-file.h"
+#include "cpu.h"
+#include "kvm_s390x.h"
+#include "sysemu/sysemu.h"
+#include "hw/s390x/ap-bridge.h"
+#include "exec/address-spaces.h"
+
+#define VFIO_AP_DEVICE_TYPE "vfio-ap"
+
+typedef struct VFIOAPDevice {
+ APDevice apdev;
+ VFIODevice vdev;
+} VFIOAPDevice;
+
+#define VFIO_AP_DEVICE(obj) \
+ OBJECT_CHECK(VFIOAPDevice, (obj), VFIO_AP_DEVICE_TYPE)
+
+static void vfio_ap_compute_needs_reset(VFIODevice *vdev)
+{
+ vdev->needs_reset = false;
+}
+
+/*
+ * We don't need vfio_hot_reset_multi and vfio_eoi operations for
+ * vfio-ap device now.
+ */
+struct VFIODeviceOps vfio_ap_ops = {
+ .vfio_compute_needs_reset = vfio_ap_compute_needs_reset,
+};
+
+static void vfio_ap_put_device(VFIOAPDevice *vapdev)
+{
+ g_free(vapdev->vdev.name);
+ vfio_put_base_device(&vapdev->vdev);
+}
+
+static VFIOGroup *vfio_ap_get_group(VFIOAPDevice *vapdev, Error **errp)
+{
+ GError *gerror = NULL;
+ char *symlink, *group_path;
+ int groupid;
+
+ symlink = g_strdup_printf("%s/iommu_group", vapdev->vdev.sysfsdev);
+ group_path = g_file_read_link(symlink, &gerror);
+ g_free(symlink);
+
+ if (!group_path) {
+ error_setg(errp, "%s: no iommu_group found for %s: %s",
+ VFIO_AP_DEVICE_TYPE, vapdev->vdev.sysfsdev, gerror->message);
+ return NULL;
+ }
+
+ if (sscanf(basename(group_path), "%d", &groupid) != 1) {
+ error_setg(errp, "vfio: failed to read %s", group_path);
+ g_free(group_path);
+ return NULL;
+ }
+
+ g_free(group_path);
+
+ return vfio_get_group(groupid, &address_space_memory, errp);
+}
+
+static void vfio_ap_realize(DeviceState *dev, Error **errp)
+{
+ int ret;
+ char *mdevid;
+ Error *local_err = NULL;
+ VFIOGroup *vfio_group;
+ APDevice *apdev = AP_DEVICE(dev);
+ VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev);
+
+ vfio_group = vfio_ap_get_group(vapdev, &local_err);
+ if (!vfio_group) {
+ goto out_err;
+ }
+
+ vapdev->vdev.ops = &vfio_ap_ops;
+ vapdev->vdev.type = VFIO_DEVICE_TYPE_AP;
+ mdevid = basename(vapdev->vdev.sysfsdev);
+ vapdev->vdev.name = g_strdup_printf("%s", mdevid);
+ vapdev->vdev.dev = dev;
+
+ ret = vfio_get_device(vfio_group, mdevid, &vapdev->vdev, &local_err);
+ if (ret) {
+ goto out_get_dev_err;
+ }
+
+ return;
+
+out_get_dev_err:
+ vfio_ap_put_device(vapdev);
+ vfio_put_group(vfio_group);
+out_err:
+ error_propagate(errp, local_err);
+}
+
+static void vfio_ap_unrealize(DeviceState *dev, Error **errp)
+{
+ APDevice *apdev = AP_DEVICE(dev);
+ VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev);
+ VFIOGroup *group = vapdev->vdev.group;
+
+ vfio_ap_put_device(vapdev);
+ vfio_put_group(group);
+}
+
+static Property vfio_ap_properties[] = {
+ DEFINE_PROP_STRING("sysfsdev", VFIOAPDevice, vdev.sysfsdev),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vfio_ap_reset(DeviceState *dev)
+{
+ int ret;
+ APDevice *apdev = AP_DEVICE(dev);
+ VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev);
+
+ ret = ioctl(vapdev->vdev.fd, VFIO_DEVICE_RESET);
+ if (ret) {
+ error_report("%s: failed to reset %s device: %s", __func__,
+ vapdev->vdev.name, strerror(ret));
+ }
+}
+
+static const VMStateDescription vfio_ap_vmstate = {
+ .name = VFIO_AP_DEVICE_TYPE,
+ .unmigratable = 1,
+};
+
+static void vfio_ap_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->props = vfio_ap_properties;
+ dc->vmsd = &vfio_ap_vmstate;
+ dc->desc = "VFIO-based AP device assignment";
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ dc->realize = vfio_ap_realize;
+ dc->unrealize = vfio_ap_unrealize;
+ dc->hotpluggable = false;
+ dc->reset = vfio_ap_reset;
+ dc->bus_type = TYPE_AP_BUS;
+}
+
+static const TypeInfo vfio_ap_info = {
+ .name = VFIO_AP_DEVICE_TYPE,
+ .parent = AP_DEVICE_TYPE,
+ .instance_size = sizeof(VFIOAPDevice),
+ .class_init = vfio_ap_class_init,
+};
+
+static void vfio_ap_type_init(void)
+{
+ type_register_static(&vfio_ap_info);
+}
+
+type_init(vfio_ap_type_init)
diff --git a/hw/vfio/calxeda-xgmac.c b/hw/vfio/calxeda-xgmac.c
index 24cee6d065..e7767c4b02 100644
--- a/hw/vfio/calxeda-xgmac.c
+++ b/hw/vfio/calxeda-xgmac.c
@@ -20,6 +20,7 @@ static void calxeda_xgmac_realize(DeviceState *dev, Error **errp)
VFIOCalxedaXgmacDeviceClass *k = VFIO_CALXEDA_XGMAC_DEVICE_GET_CLASS(dev);
vdev->compat = g_strdup("calxeda,hb-xgmac");
+ vdev->num_compat = 1;
k->parent_realize(dev, errp);
}
diff --git a/hw/vfio/display.c b/hw/vfio/display.c
index 59c0e5d1d7..dead30e626 100644
--- a/hw/vfio/display.c
+++ b/hw/vfio/display.c
@@ -124,6 +124,9 @@ static void vfio_display_dmabuf_update(void *opaque)
primary = vfio_display_get_dmabuf(vdev, DRM_PLANE_TYPE_PRIMARY);
if (primary == NULL) {
+ if (dpy->ramfb) {
+ ramfb_display_update(dpy->con, dpy->ramfb);
+ }
return;
}
@@ -181,6 +184,9 @@ static int vfio_display_dmabuf_init(VFIOPCIDevice *vdev, Error **errp)
vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0,
&vfio_display_dmabuf_ops,
vdev);
+ if (vdev->enable_ramfb) {
+ vdev->dpy->ramfb = ramfb_setup(errp);
+ }
return 0;
}
@@ -228,6 +234,9 @@ static void vfio_display_region_update(void *opaque)
return;
}
if (!plane.drm_format || !plane.size) {
+ if (dpy->ramfb) {
+ ramfb_display_update(dpy->con, dpy->ramfb);
+ }
return;
}
format = qemu_drm_format_to_pixman(plane.drm_format);
@@ -300,6 +309,9 @@ static int vfio_display_region_init(VFIOPCIDevice *vdev, Error **errp)
vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0,
&vfio_display_region_ops,
vdev);
+ if (vdev->enable_ramfb) {
+ vdev->dpy->ramfb = ramfb_setup(errp);
+ }
return 0;
}
diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
index 481fd08df7..eae31c74d6 100644
--- a/hw/vfio/pci-quirks.c
+++ b/hw/vfio/pci-quirks.c
@@ -1670,7 +1670,7 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
* but also no point in us enabling VGA if disabled in hardware.
*/
if (!(gmch & 0x2) && !vdev->vga && vfio_populate_vga(vdev, &err)) {
- error_reportf_err(err, ERR_PREFIX, vdev->vbasedev.name);
+ error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
error_report("IGD device %s failed to enable VGA access, "
"legacy mode disabled", vdev->vbasedev.name);
goto out;
@@ -1696,7 +1696,7 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
ret = vfio_pci_igd_opregion_init(vdev, opregion, &err);
if (ret) {
error_append_hint(&err, "IGD legacy mode disabled\n");
- error_reportf_err(err, ERR_PREFIX, vdev->vbasedev.name);
+ error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
goto out;
}
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 866f0deeb7..5c7bd96984 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -37,6 +37,9 @@
#define MSIX_CAP_LENGTH 12
+#define TYPE_VFIO_PCI "vfio-pci"
+#define PCI_VFIO(obj) OBJECT_CHECK(VFIOPCIDevice, obj, TYPE_VFIO_PCI)
+
static void vfio_disable_interrupts(VFIOPCIDevice *vdev);
static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled);
@@ -222,7 +225,7 @@ static void vfio_intx_disable_kvm(VFIOPCIDevice *vdev)
static void vfio_intx_update(PCIDevice *pdev)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
PCIINTxRoute route;
Error *err = NULL;
@@ -249,7 +252,7 @@ static void vfio_intx_update(PCIDevice *pdev)
vfio_intx_enable_kvm(vdev, &err);
if (err) {
- error_reportf_err(err, WARN_PREFIX, vdev->vbasedev.name);
+ warn_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
/* Re-enable the interrupt in cased we missed an EOI */
@@ -314,7 +317,7 @@ static int vfio_intx_enable(VFIOPCIDevice *vdev, Error **errp)
vfio_intx_enable_kvm(vdev, &err);
if (err) {
- error_reportf_err(err, WARN_PREFIX, vdev->vbasedev.name);
+ warn_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
vdev->interrupt = VFIO_INT_INTx;
@@ -477,7 +480,7 @@ static void vfio_update_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage msg,
static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
MSIMessage *msg, IOHandler *handler)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
VFIOMSIVector *vector;
int ret;
@@ -574,7 +577,7 @@ static int vfio_msix_vector_use(PCIDevice *pdev,
static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
VFIOMSIVector *vector = &vdev->msi_vectors[nr];
trace_vfio_msix_vector_release(vdev->vbasedev.name, nr);
@@ -742,7 +745,7 @@ static void vfio_msi_disable_common(VFIOPCIDevice *vdev)
vfio_intx_enable(vdev, &err);
if (err) {
- error_reportf_err(err, ERR_PREFIX, vdev->vbasedev.name);
+ error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
}
@@ -1086,7 +1089,7 @@ static const MemoryRegionOps vfio_vga_ops = {
*/
static void vfio_sub_page_bar_update_mapping(PCIDevice *pdev, int bar)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
VFIORegion *region = &vdev->bars[bar].region;
MemoryRegion *mmap_mr, *region_mr, *base_mr;
PCIIORegion *r;
@@ -1132,7 +1135,7 @@ static void vfio_sub_page_bar_update_mapping(PCIDevice *pdev, int bar)
*/
uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
uint32_t emu_bits = 0, emu_val = 0, phys_val = 0, val;
memcpy(&emu_bits, vdev->emulated_config_bits + addr, len);
@@ -1165,7 +1168,7 @@ uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
void vfio_pci_write_config(PCIDevice *pdev,
uint32_t addr, uint32_t val, int len)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
uint32_t val_le = cpu_to_le32(val);
trace_vfio_pci_write_config(vdev->vbasedev.name, addr, val, len);
@@ -1280,8 +1283,7 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
if (ret == -ENOTSUP) {
return 0;
}
- error_prepend(&err, "msi_init failed: ");
- error_propagate(errp, err);
+ error_propagate_prepend(errp, err, "msi_init failed: ");
return ret;
}
vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0);
@@ -1555,7 +1557,7 @@ static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
&err);
if (ret < 0) {
if (ret == -ENOTSUP) {
- error_report_err(err);
+ warn_report_err(err);
return 0;
}
@@ -2194,7 +2196,7 @@ static void vfio_pci_post_reset(VFIOPCIDevice *vdev)
vfio_intx_enable(vdev, &err);
if (err) {
- error_reportf_err(err, ERR_PREFIX, vdev->vbasedev.name);
+ error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
for (nr = 0; nr < PCI_NUM_REGIONS - 1; ++nr) {
@@ -2588,9 +2590,9 @@ static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp)
} else if (irq_info.count == 1) {
vdev->pci_aer = true;
} else {
- error_report(WARN_PREFIX
- "Could not enable error recovery for the device",
- vbasedev->name);
+ warn_report(VFIO_MSG_PREFIX
+ "Could not enable error recovery for the device",
+ vbasedev->name);
}
}
@@ -2715,7 +2717,7 @@ static void vfio_req_notifier_handler(void *opaque)
qdev_unplug(&vdev->pdev.qdev, &err);
if (err) {
- error_reportf_err(err, WARN_PREFIX, vdev->vbasedev.name);
+ warn_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
}
@@ -2801,7 +2803,7 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev)
static void vfio_realize(PCIDevice *pdev, Error **errp)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
VFIODevice *vbasedev_iter;
VFIOGroup *group;
char *tmp, *subsys, group_path[PATH_MAX], *group_name;
@@ -2828,7 +2830,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
if (stat(vdev->vbasedev.sysfsdev, &st) < 0) {
error_setg_errno(errp, errno, "no such host device");
- error_prepend(errp, ERR_PREFIX, vdev->vbasedev.sysfsdev);
+ error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.sysfsdev);
return;
}
@@ -3067,6 +3069,10 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
goto out_teardown;
}
}
+ if (vdev->enable_ramfb && vdev->dpy == NULL) {
+ error_setg(errp, "ramfb=on requires display=on");
+ goto out_teardown;
+ }
vfio_register_err_notifier(vdev);
vfio_register_req_notifier(vdev);
@@ -3079,13 +3085,12 @@ out_teardown:
vfio_teardown_msi(vdev);
vfio_bars_exit(vdev);
error:
- error_prepend(errp, ERR_PREFIX, vdev->vbasedev.name);
+ error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
static void vfio_instance_finalize(Object *obj)
{
- PCIDevice *pci_dev = PCI_DEVICE(obj);
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pci_dev);
+ VFIOPCIDevice *vdev = PCI_VFIO(obj);
VFIOGroup *group = vdev->vbasedev.group;
vfio_display_finalize(vdev);
@@ -3105,7 +3110,7 @@ static void vfio_instance_finalize(Object *obj)
static void vfio_exitfn(PCIDevice *pdev)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
vfio_unregister_req_notifier(vdev);
vfio_unregister_err_notifier(vdev);
@@ -3120,8 +3125,7 @@ static void vfio_exitfn(PCIDevice *pdev)
static void vfio_pci_reset(DeviceState *dev)
{
- PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev);
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(dev);
trace_vfio_pci_reset(vdev->vbasedev.name);
@@ -3161,7 +3165,7 @@ post_reset:
static void vfio_instance_init(Object *obj)
{
PCIDevice *pci_dev = PCI_DEVICE(obj);
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, PCI_DEVICE(obj));
+ VFIOPCIDevice *vdev = PCI_VFIO(obj);
device_add_bootindex_property(obj, &vdev->bootindex,
"bootindex", NULL,
@@ -3245,7 +3249,7 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo vfio_pci_dev_info = {
- .name = "vfio-pci",
+ .name = TYPE_VFIO_PCI,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(VFIOPCIDevice),
.class_init = vfio_pci_dev_class_init,
@@ -3258,9 +3262,30 @@ static const TypeInfo vfio_pci_dev_info = {
},
};
+static Property vfio_pci_dev_nohotplug_properties[] = {
+ DEFINE_PROP_BOOL("ramfb", VFIOPCIDevice, enable_ramfb, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vfio_pci_nohotplug_dev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->props = vfio_pci_dev_nohotplug_properties;
+ dc->hotpluggable = false;
+}
+
+static const TypeInfo vfio_pci_nohotplug_dev_info = {
+ .name = "vfio-pci-nohotplug",
+ .parent = "vfio-pci",
+ .instance_size = sizeof(VFIOPCIDevice),
+ .class_init = vfio_pci_nohotplug_dev_class_init,
+};
+
static void register_vfio_pci_dev_type(void)
{
type_register_static(&vfio_pci_dev_info);
+ type_register_static(&vfio_pci_nohotplug_dev_info);
}
type_init(register_vfio_pci_dev_type)
diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
index 52b065421a..b1ae4c0754 100644
--- a/hw/vfio/pci.h
+++ b/hw/vfio/pci.h
@@ -165,6 +165,7 @@ typedef struct VFIOPCIDevice {
bool no_geforce_quirks;
bool no_kvm_ioeventfd;
bool no_vfio_ioeventfd;
+ bool enable_ramfb;
VFIODisplay *dpy;
} VFIOPCIDevice;
diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c
index 57c4a0ee2b..398db38f14 100644
--- a/hw/vfio/platform.c
+++ b/hw/vfio/platform.c
@@ -655,10 +655,32 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp)
goto out;
}
+ if (!vdev->compat) {
+ GError *gerr = NULL;
+ gchar *contents;
+ gsize length;
+ char *path;
+
+ path = g_strdup_printf("%s/of_node/compatible", vbasedev->sysfsdev);
+ if (!g_file_get_contents(path, &contents, &length, &gerr)) {
+ error_setg(errp, "%s", gerr->message);
+ g_error_free(gerr);
+ g_free(path);
+ return;
+ }
+ g_free(path);
+ vdev->compat = contents;
+ for (vdev->num_compat = 0; length; vdev->num_compat++) {
+ size_t skip = strlen(contents) + 1;
+ contents += skip;
+ length -= skip;
+ }
+ }
+
for (i = 0; i < vbasedev->num_regions; i++) {
if (vfio_region_mmap(vdev->regions[i])) {
- error_report("%s mmap unsupported. Performance may be slow",
- memory_region_name(vdev->regions[i]->mem));
+ warn_report("%s mmap unsupported, performance may be slow",
+ memory_region_name(vdev->regions[i]->mem));
}
sysbus_init_mmio(sbdev, vdev->regions[i]->mem);
}
@@ -668,7 +690,7 @@ out:
}
if (vdev->vbasedev.name) {
- error_prepend(errp, ERR_PREFIX, vdev->vbasedev.name);
+ error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name);
} else {
error_prepend(errp, "vfio error: ");
}
@@ -700,6 +722,8 @@ static void vfio_platform_class_init(ObjectClass *klass, void *data)
dc->desc = "VFIO-based platform device assignment";
sbc->connect_irq_notifier = vfio_start_irqfd_injection;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ /* Supported by TYPE_VIRT_MACHINE */
+ dc->user_creatable = true;
}
static const TypeInfo vfio_platform_dev_info = {
@@ -708,7 +732,6 @@ static const TypeInfo vfio_platform_dev_info = {
.instance_size = sizeof(VFIOPlatformDevice),
.class_init = vfio_platform_class_init,
.class_size = sizeof(VFIOPlatformDeviceClass),
- .abstract = true,
};
static void register_vfio_platform_dev_type(void)
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index b041343632..e09bed0e4a 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -374,8 +374,6 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev,
int fds[VHOST_MEMORY_MAX_NREGIONS];
int i, fd;
size_t fd_num = 0;
- bool reply_supported = virtio_has_feature(dev->protocol_features,
- VHOST_USER_PROTOCOL_F_REPLY_ACK);
VhostUserMsg msg_reply;
int region_i, msg_i;
@@ -384,10 +382,6 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev,
.hdr.flags = VHOST_USER_VERSION,
};
- if (reply_supported) {
- msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK;
- }
-
if (u->region_rb_len < dev->mem->nregions) {
u->region_rb = g_renew(RAMBlock*, u->region_rb, dev->mem->nregions);
u->region_rb_offset = g_renew(ram_addr_t, u->region_rb_offset,
@@ -503,10 +497,6 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev,
return -1;
}
- if (reply_supported) {
- return process_message_reply(dev, &msg);
- }
-
return 0;
}
@@ -519,8 +509,7 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,
size_t fd_num = 0;
bool do_postcopy = u->postcopy_listen && u->postcopy_fd.handler;
bool reply_supported = virtio_has_feature(dev->protocol_features,
- VHOST_USER_PROTOCOL_F_REPLY_ACK) &&
- !do_postcopy;
+ VHOST_USER_PROTOCOL_F_REPLY_ACK);
if (do_postcopy) {
/* Postcopy has enough differences that it's best done in it's own
@@ -1291,6 +1280,7 @@ static int vhost_user_postcopy_end(struct vhost_dev *dev, Error **errp)
return ret;
}
postcopy_unregister_shared_ufd(&u->postcopy_fd);
+ close(u->postcopy_fd.fd);
u->postcopy_fd.handler = NULL;
trace_vhost_user_postcopy_end_exit();
@@ -1430,6 +1420,12 @@ static int vhost_user_backend_cleanup(struct vhost_dev *dev)
postcopy_remove_notifier(&u->postcopy_notifier);
u->postcopy_notifier.notify = NULL;
}
+ u->postcopy_listen = false;
+ if (u->postcopy_fd.handler) {
+ postcopy_unregister_shared_ufd(&u->postcopy_fd);
+ close(u->postcopy_fd.fd);
+ u->postcopy_fd.handler = NULL;
+ }
if (u->slave_fd >= 0) {
qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL);
close(u->slave_fd);
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 3a01fe90f0..a954799267 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1683,8 +1683,8 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
if (err) {
/* Notice when a system that supports MSIx can't initialize it */
if (err != -ENOTSUP) {
- error_report("unable to init msix vectors to %" PRIu32,
- proxy->nvectors);
+ warn_report("unable to init msix vectors to %" PRIu32,
+ proxy->nvectors);
}
proxy->nvectors = 0;
}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index f6a588ab57..4136d239dd 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -358,6 +358,10 @@ int virtio_queue_ready(VirtQueue *vq)
* Called within rcu_read_lock(). */
static int virtio_queue_empty_rcu(VirtQueue *vq)
{
+ if (unlikely(vq->vdev->broken)) {
+ return 1;
+ }
+
if (unlikely(!vq->vring.avail)) {
return 1;
}
@@ -373,6 +377,10 @@ int virtio_queue_empty(VirtQueue *vq)
{
bool empty;
+ if (unlikely(vq->vdev->broken)) {
+ return 1;
+ }
+
if (unlikely(!vq->vring.avail)) {
return 1;
}
@@ -1161,7 +1169,6 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val)
return 0;
}
-bool target_words_bigendian(void);
static enum virtio_device_endian virtio_default_endian(void)
{
if (target_words_bigendian()) {
@@ -1604,6 +1611,8 @@ void virtio_del_queue(VirtIODevice *vdev, int n)
vdev->vq[n].vring.num = 0;
vdev->vq[n].vring.num_default = 0;
+ vdev->vq[n].handle_output = NULL;
+ vdev->vq[n].handle_aio_output = NULL;
}
static void virtio_set_isr(VirtIODevice *vdev, int value)
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index e5a6eff44f..f1f3a3727c 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -830,7 +830,7 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
xen_pt_config_init(s, &err);
if (err) {
error_append_hint(&err, "PCI Config space initialisation failed");
- error_report_err(err);
+ error_propagate(errp, err);
rc = -1;
goto err_out;
}
diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c
index aee31c62bb..47f9010c75 100644
--- a/hw/xen/xen_pt_config_init.c
+++ b/hw/xen/xen_pt_config_init.c
@@ -358,7 +358,7 @@ static uint64_t xen_pt_get_bar_size(PCIIORegion *r)
static XenPTBarFlag xen_pt_bar_reg_parse(XenPCIPassthroughState *s,
int index)
{
- PCIDevice *d = &s->dev;
+ PCIDevice *d = PCI_DEVICE(s);
XenPTRegion *region = NULL;
PCIIORegion *r;
@@ -469,7 +469,7 @@ static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
{
XenPTRegInfo *reg = cfg_entry->reg;
XenPTRegion *base = NULL;
- PCIDevice *d = &s->dev;
+ PCIDevice *d = PCI_DEVICE(s);
const PCIIORegion *r;
uint32_t writable_mask = 0;
uint32_t bar_emu_mask = 0;
@@ -543,7 +543,7 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
{
XenPTRegInfo *reg = cfg_entry->reg;
XenPTRegion *base = NULL;
- PCIDevice *d = (PCIDevice *)&s->dev;
+ PCIDevice *d = PCI_DEVICE(s);
uint32_t writable_mask = 0;
uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
pcibus_t r_size = 0;
@@ -1587,7 +1587,7 @@ static int xen_pt_pcie_size_init(XenPCIPassthroughState *s,
const XenPTRegGroupInfo *grp_reg,
uint32_t base_offset, uint8_t *size)
{
- PCIDevice *d = &s->dev;
+ PCIDevice *d = PCI_DEVICE(s);
uint8_t version = get_capability_version(s, base_offset);
uint8_t type = get_device_type(s, base_offset);
uint8_t pcie_size = 0;