aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/9pfs/9p-local.c7
-rw-r--r--hw/9pfs/9p-xattr.c1
-rw-r--r--hw/9pfs/9p.c25
-rw-r--r--hw/acpi/tco.c2
-rw-r--r--hw/acpi/vmgenid.c22
-rw-r--r--hw/arm/allwinner-a10.c6
-rw-r--r--hw/arm/aspeed_soc.c21
-rw-r--r--hw/arm/bcm2836.c6
-rw-r--r--hw/arm/boot.c64
-rw-r--r--hw/arm/digic.c6
-rw-r--r--hw/arm/exynos4210.c29
-rw-r--r--hw/arm/exynos4_boards.c7
-rw-r--r--hw/arm/fsl-imx25.c5
-rw-r--r--hw/arm/fsl-imx31.c5
-rw-r--r--hw/arm/fsl-imx6.c5
-rw-r--r--hw/arm/pxa2xx.c14
-rw-r--r--hw/arm/stellaris.c60
-rw-r--r--hw/arm/xlnx-zynqmp.c12
-rw-r--r--hw/block/fdc.c6
-rw-r--r--hw/char/exynos4210_uart.c8
-rw-r--r--hw/core/machine.c5
-rw-r--r--hw/core/null-machine.c6
-rw-r--r--hw/core/qdev-properties-system.c6
-rw-r--r--hw/core/qdev-properties.c3
-rw-r--r--hw/core/qdev.c49
-rw-r--r--hw/display/cg3.c12
-rw-r--r--hw/display/cirrus_vga_rop2.h4
-rw-r--r--hw/display/exynos4210_fimd.c11
-rw-r--r--hw/display/framebuffer.c11
-rw-r--r--hw/display/g364fb.c28
-rw-r--r--hw/display/qxl.c66
-rw-r--r--hw/display/qxl.h3
-rw-r--r--hw/display/sm501.c1784
-rw-r--r--hw/display/sm501_template.h90
-rw-r--r--hw/display/tcx.c298
-rw-r--r--hw/display/vga.c50
-rw-r--r--hw/display/virtio-gpu.c41
-rw-r--r--hw/display/vmware_vga.c21
-rw-r--r--hw/i386/amd_iommu.c3
-rw-r--r--hw/i386/intel_iommu.c442
-rw-r--r--hw/i386/intel_iommu_internal.h1
-rw-r--r--hw/i386/pc.c4
-rw-r--r--hw/i386/trace-events11
-rw-r--r--hw/input/virtio-input.c33
-rw-r--r--hw/intc/apic_common.c33
-rw-r--r--hw/intc/arm_gicv3_kvm.c17
-rw-r--r--hw/intc/s390_flic.c9
-rw-r--r--hw/ipmi/isa_ipmi_bt.c34
-rw-r--r--hw/isa/lpc_ich9.c5
-rw-r--r--hw/misc/exynos4210_pmu.c4
-rw-r--r--hw/net/Makefile.objs1
-rw-r--r--hw/net/cadence_gem.c45
-rw-r--r--hw/net/e1000.c2
-rw-r--r--hw/net/ftgmac100.c1016
-rw-r--r--hw/net/virtio-net.c4
-rw-r--r--hw/pci-host/versatile.c35
-rw-r--r--hw/pci/pci.c4
-rw-r--r--hw/ppc/spapr.c16
-rw-r--r--hw/ppc/spapr_drc.c20
-rw-r--r--hw/s390x/ccw-device.c40
-rw-r--r--hw/s390x/ccw-device.h9
-rw-r--r--hw/s390x/css-bridge.c3
-rw-r--r--hw/s390x/css.c92
-rw-r--r--hw/s390x/s390-pci-bus.c19
-rw-r--r--hw/s390x/s390-pci-bus.h1
-rw-r--r--hw/s390x/s390-pci-inst.c26
-rw-r--r--hw/s390x/s390-virtio-ccw.c20
-rw-r--r--hw/s390x/virtio-ccw.c58
-rw-r--r--hw/scsi/megasas.c6
-rw-r--r--hw/scsi/scsi-generic.c5
-rw-r--r--hw/scsi/vhost-scsi.c6
-rw-r--r--hw/scsi/virtio-scsi-dataplane.c20
-rw-r--r--hw/scsi/virtio-scsi.c52
-rw-r--r--hw/sh4/r2d.c11
-rw-r--r--hw/sparc/sun4m.c2
-rw-r--r--hw/timer/exynos4210_mct.c6
-rw-r--r--hw/timer/exynos4210_pwm.c13
-rw-r--r--hw/timer/exynos4210_rtc.c19
-rw-r--r--hw/usb/bus.c4
-rw-r--r--hw/usb/hcd-xhci.c4
-rw-r--r--hw/usb/host-libusb.c7
-rw-r--r--hw/vfio/common.c12
-rw-r--r--hw/vfio/pci-quirks.c67
-rw-r--r--hw/virtio/trace-events3
-rw-r--r--hw/virtio/vhost.c91
-rw-r--r--hw/virtio/virtio-bus.c20
-rw-r--r--hw/virtio/virtio-rng.c29
-rw-r--r--hw/virtio/virtio.c13
88 files changed, 3568 insertions, 1628 deletions
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index 45e9a1f9b0..f3ebca4f7a 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -1098,8 +1098,13 @@ static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
{
if (dir_path) {
v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
- } else {
+ } else if (strcmp(name, "/")) {
v9fs_path_sprintf(target, "%s", name);
+ } else {
+ /* We want the path of the export root to be relative, otherwise
+ * "*at()" syscalls would treat it as "/" in the host.
+ */
+ v9fs_path_sprintf(target, "%s", ".");
}
return 0;
}
diff --git a/hw/9pfs/9p-xattr.c b/hw/9pfs/9p-xattr.c
index eec160b3c2..d05c1a1c1d 100644
--- a/hw/9pfs/9p-xattr.c
+++ b/hw/9pfs/9p-xattr.c
@@ -108,6 +108,7 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
g_free(name);
close_preserve_errno(dirfd);
if (xattr_len < 0) {
+ g_free(orig_value);
return -1;
}
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index b8c0b99358..c80ba67389 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -539,14 +539,15 @@ static void coroutine_fn virtfs_reset(V9fsPDU *pdu)
/* Free all fids */
while (s->fid_list) {
+ /* Get fid */
fidp = s->fid_list;
+ fidp->ref++;
+
+ /* Clunk fid */
s->fid_list = fidp->next;
+ fidp->clunked = 1;
- if (fidp->ref) {
- fidp->clunked = 1;
- } else {
- free_fid(pdu, fidp);
- }
+ put_fid(pdu, fidp);
}
}
@@ -1550,6 +1551,10 @@ static void coroutine_fn v9fs_lcreate(void *opaque)
err = -ENOENT;
goto out_nofid;
}
+ if (fidp->fid_type != P9_FID_NONE) {
+ err = -EINVAL;
+ goto out;
+ }
flags = get_dotl_openflags(pdu->s, flags);
err = v9fs_co_open2(pdu, fidp, &name, gid,
@@ -2153,6 +2158,10 @@ static void coroutine_fn v9fs_create(void *opaque)
err = -EINVAL;
goto out_nofid;
}
+ if (fidp->fid_type != P9_FID_NONE) {
+ err = -EINVAL;
+ goto out;
+ }
if (perm & P9_STAT_MODE_DIR) {
err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777,
fidp->uid, -1, &stbuf);
@@ -2379,8 +2388,10 @@ static void coroutine_fn v9fs_flush(void *opaque)
* Wait for pdu to complete.
*/
qemu_co_queue_wait(&cancel_pdu->complete, NULL);
- cancel_pdu->cancelled = 0;
- pdu_free(cancel_pdu);
+ if (!qemu_co_queue_next(&cancel_pdu->complete)) {
+ cancel_pdu->cancelled = 0;
+ pdu_free(cancel_pdu);
+ }
}
pdu_complete(pdu, 7);
}
diff --git a/hw/acpi/tco.c b/hw/acpi/tco.c
index b4adac88cd..05b9d7ba36 100644
--- a/hw/acpi/tco.c
+++ b/hw/acpi/tco.c
@@ -75,8 +75,6 @@ static void tco_timer_expired(void *opaque)
if (pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN) {
ich9_generate_smi();
- } else {
- ich9_generate_nmi();
}
tr->tco.rld = tr->tco.tmr;
tco_timer_reload(tr);
diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
index 7a3ad17d66..a32b847fe0 100644
--- a/hw/acpi/vmgenid.c
+++ b/hw/acpi/vmgenid.c
@@ -205,9 +205,30 @@ static void vmgenid_handle_reset(void *opaque)
memset(vms->vmgenid_addr_le, 0, ARRAY_SIZE(vms->vmgenid_addr_le));
}
+static Property vmgenid_properties[] = {
+ DEFINE_PROP_BOOL("x-write-pointer-available", VmGenIdState,
+ write_pointer_available, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void vmgenid_realize(DeviceState *dev, Error **errp)
{
VmGenIdState *vms = VMGENID(dev);
+
+ if (!vms->write_pointer_available) {
+ error_setg(errp, "%s requires DMA write support in fw_cfg, "
+ "which this machine type does not provide", VMGENID_DEVICE);
+ return;
+ }
+
+ /* Given that this function is executing, there is at least one VMGENID
+ * device. Check if there are several.
+ */
+ if (!find_vmgenid_dev()) {
+ error_setg(errp, "at most one %s device is permitted", VMGENID_DEVICE);
+ return;
+ }
+
qemu_register_reset(vmgenid_handle_reset, vms);
}
@@ -218,6 +239,7 @@ static void vmgenid_device_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_vmgenid;
dc->realize = vmgenid_realize;
dc->hotpluggable = false;
+ dc->props = vmgenid_properties;
object_class_property_add_str(klass, VMGENID_GUID, NULL,
vmgenid_set_guid, NULL);
diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c
index ca15d1c8cc..f62a9a3541 100644
--- a/hw/arm/allwinner-a10.c
+++ b/hw/arm/allwinner-a10.c
@@ -118,12 +118,6 @@ static void aw_a10_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = aw_a10_realize;
-
- /*
- * Reason: creates an ARM CPU, thus use after free(), see
- * arm_cpu_class_init()
- */
- dc->cannot_destroy_with_object_finalize_yet = true;
}
static const TypeInfo aw_a10_type_info = {
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
index 571e4f097b..4937e2bc83 100644
--- a/hw/arm/aspeed_soc.c
+++ b/hw/arm/aspeed_soc.c
@@ -19,6 +19,7 @@
#include "hw/char/serial.h"
#include "qemu/log.h"
#include "hw/i2c/aspeed_i2c.h"
+#include "net/net.h"
#define ASPEED_SOC_UART_5_BASE 0x00184000
#define ASPEED_SOC_IOMEM_SIZE 0x00200000
@@ -33,6 +34,8 @@
#define ASPEED_SOC_TIMER_BASE 0x1E782000
#define ASPEED_SOC_WDT_BASE 0x1E785000
#define ASPEED_SOC_I2C_BASE 0x1E78A000
+#define ASPEED_SOC_ETH1_BASE 0x1E660000
+#define ASPEED_SOC_ETH2_BASE 0x1E680000
static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, };
@@ -175,6 +178,10 @@ static void aspeed_soc_init(Object *obj)
object_initialize(&s->wdt, sizeof(s->wdt), TYPE_ASPEED_WDT);
object_property_add_child(obj, "wdt", OBJECT(&s->wdt), NULL);
qdev_set_parent_bus(DEVICE(&s->wdt), sysbus_get_default());
+
+ object_initialize(&s->ftgmac100, sizeof(s->ftgmac100), TYPE_FTGMAC100);
+ object_property_add_child(obj, "ftgmac100", OBJECT(&s->ftgmac100), NULL);
+ qdev_set_parent_bus(DEVICE(&s->ftgmac100), sysbus_get_default());
}
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
@@ -299,6 +306,20 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, ASPEED_SOC_WDT_BASE);
+
+ /* Net */
+ qdev_set_nic_properties(DEVICE(&s->ftgmac100), &nd_table[0]);
+ object_property_set_bool(OBJECT(&s->ftgmac100), true, "aspeed", &err);
+ object_property_set_bool(OBJECT(&s->ftgmac100), true, "realized",
+ &local_err);
+ error_propagate(&err, local_err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100), 0, ASPEED_SOC_ETH1_BASE);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100), 0,
+ qdev_get_gpio_in(DEVICE(&s->vic), 2));
}
static void aspeed_soc_class_init(ObjectClass *oc, void *data)
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
index 8451190a19..8c43291112 100644
--- a/hw/arm/bcm2836.c
+++ b/hw/arm/bcm2836.c
@@ -160,12 +160,6 @@ static void bcm2836_class_init(ObjectClass *oc, void *data)
dc->props = bcm2836_props;
dc->realize = bcm2836_realize;
-
- /*
- * Reason: creates an ARM CPU, thus use after free(), see
- * arm_cpu_class_init()
- */
- dc->cannot_destroy_with_object_finalize_yet = true;
}
static const TypeInfo bcm2836_type_info = {
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index ff621e4b6a..c2720c8046 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -31,6 +31,9 @@
#define KERNEL_LOAD_ADDR 0x00010000
#define KERNEL64_LOAD_ADDR 0x00080000
+#define ARM64_TEXT_OFFSET_OFFSET 8
+#define ARM64_MAGIC_OFFSET 56
+
typedef enum {
FIXUP_NONE = 0, /* do nothing */
FIXUP_TERMINATOR, /* end of insns */
@@ -768,6 +771,49 @@ static uint64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry,
return ret;
}
+static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base,
+ hwaddr *entry)
+{
+ hwaddr kernel_load_offset = KERNEL64_LOAD_ADDR;
+ uint8_t *buffer;
+ int size;
+
+ /* On aarch64, it's the bootloader's job to uncompress the kernel. */
+ size = load_image_gzipped_buffer(filename, LOAD_IMAGE_MAX_GUNZIP_BYTES,
+ &buffer);
+
+ if (size < 0) {
+ gsize len;
+
+ /* Load as raw file otherwise */
+ if (!g_file_get_contents(filename, (char **)&buffer, &len, NULL)) {
+ return -1;
+ }
+ size = len;
+ }
+
+ /* check the arm64 magic header value -- very old kernels may not have it */
+ if (memcmp(buffer + ARM64_MAGIC_OFFSET, "ARM\x64", 4) == 0) {
+ uint64_t hdrvals[2];
+
+ /* The arm64 Image header has text_offset and image_size fields at 8 and
+ * 16 bytes into the Image header, respectively. The text_offset field
+ * is only valid if the image_size is non-zero.
+ */
+ memcpy(&hdrvals, buffer + ARM64_TEXT_OFFSET_OFFSET, sizeof(hdrvals));
+ if (hdrvals[1] != 0) {
+ kernel_load_offset = le64_to_cpu(hdrvals[0]);
+ }
+ }
+
+ *entry = mem_base + kernel_load_offset;
+ rom_add_blob_fixed(filename, buffer, size, *entry);
+
+ g_free(buffer);
+
+ return size;
+}
+
static void arm_load_kernel_notify(Notifier *notifier, void *data)
{
CPUState *cs;
@@ -776,7 +822,7 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
int is_linux = 0;
uint64_t elf_entry, elf_low_addr, elf_high_addr;
int elf_machine;
- hwaddr entry, kernel_load_offset;
+ hwaddr entry;
static const ARMInsnFixup *primary_loader;
ArmLoadKernelNotifier *n = DO_UPCAST(ArmLoadKernelNotifier,
notifier, notifier);
@@ -841,14 +887,12 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
primary_loader = bootloader_aarch64;
- kernel_load_offset = KERNEL64_LOAD_ADDR;
elf_machine = EM_AARCH64;
} else {
primary_loader = bootloader;
if (!info->write_board_setup) {
primary_loader += BOOTLOADER_NO_BOARD_SETUP_OFFSET;
}
- kernel_load_offset = KERNEL_LOAD_ADDR;
elf_machine = EM_ARM;
}
@@ -900,17 +944,15 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
&is_linux, NULL, NULL);
}
- /* On aarch64, it's the bootloader's job to uncompress the kernel. */
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && kernel_size < 0) {
- entry = info->loader_start + kernel_load_offset;
- kernel_size = load_image_gzipped(info->kernel_filename, entry,
- info->ram_size - kernel_load_offset);
+ kernel_size = load_aarch64_image(info->kernel_filename,
+ info->loader_start, &entry);
is_linux = 1;
- }
- if (kernel_size < 0) {
- entry = info->loader_start + kernel_load_offset;
+ } else if (kernel_size < 0) {
+ /* 32-bit ARM */
+ entry = info->loader_start + KERNEL_LOAD_ADDR;
kernel_size = load_image_targphys(info->kernel_filename, entry,
- info->ram_size - kernel_load_offset);
+ info->ram_size - KERNEL_LOAD_ADDR);
is_linux = 1;
}
if (kernel_size < 0) {
diff --git a/hw/arm/digic.c b/hw/arm/digic.c
index d60ea395f4..94f32637f0 100644
--- a/hw/arm/digic.c
+++ b/hw/arm/digic.c
@@ -101,12 +101,6 @@ static void digic_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = digic_realize;
-
- /*
- * Reason: creates an ARM CPU, thus use after free(), see
- * arm_cpu_class_init()
- */
- dc->cannot_destroy_with_object_finalize_yet = true;
}
static const TypeInfo digic_type_info = {
diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c
index 1d2b50cc4e..960f27e45a 100644
--- a/hw/arm/exynos4210.c
+++ b/hw/arm/exynos4210.c
@@ -32,6 +32,7 @@
#include "hw/arm/arm.h"
#include "hw/loader.h"
#include "hw/arm/exynos4210.h"
+#include "hw/sd/sd.h"
#include "hw/usb/hcd-ehci.h"
#define EXYNOS4210_CHIPID_ADDR 0x10000000
@@ -72,6 +73,13 @@
#define EXYNOS4210_EXT_COMBINER_BASE_ADDR 0x10440000
#define EXYNOS4210_INT_COMBINER_BASE_ADDR 0x10448000
+/* SD/MMC host controllers */
+#define EXYNOS4210_SDHCI_CAPABILITIES 0x05E80080
+#define EXYNOS4210_SDHCI_BASE_ADDR 0x12510000
+#define EXYNOS4210_SDHCI_ADDR(n) (EXYNOS4210_SDHCI_BASE_ADDR + \
+ 0x00010000 * (n))
+#define EXYNOS4210_SDHCI_NUMBER 4
+
/* PMU SFR base address */
#define EXYNOS4210_PMU_BASE_ADDR 0x10020000
@@ -382,6 +390,27 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
EXYNOS4210_UART3_FIFO_SIZE, 3, NULL,
s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]);
+ /*** SD/MMC host controllers ***/
+ for (n = 0; n < EXYNOS4210_SDHCI_NUMBER; n++) {
+ DeviceState *carddev;
+ BlockBackend *blk;
+ DriveInfo *di;
+
+ dev = qdev_create(NULL, "generic-sdhci");
+ qdev_prop_set_uint32(dev, "capareg", EXYNOS4210_SDHCI_CAPABILITIES);
+ qdev_init_nofail(dev);
+
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(busdev, 0, EXYNOS4210_SDHCI_ADDR(n));
+ sysbus_connect_irq(busdev, 0, s->irq_table[exynos4210_get_irq(29, n)]);
+
+ di = drive_get(IF_SD, 0, n);
+ blk = di ? blk_by_legacy_dinfo(di) : NULL;
+ carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD);
+ qdev_prop_set_drive(carddev, "drive", blk, &error_abort);
+ qdev_init_nofail(carddev);
+ }
+
/*** Display controller (FIMD) ***/
sysbus_create_varargs("exynos4210.fimd", EXYNOS4210_FIMD0_BASE_ADDR,
s->irq_table[exynos4210_get_irq(11, 0)],
diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c
index 0efa194054..4853c31802 100644
--- a/hw/arm/exynos4_boards.c
+++ b/hw/arm/exynos4_boards.c
@@ -22,6 +22,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/error-report.h"
#include "qemu-common.h"
#include "cpu.h"
#include "sysemu/sysemu.h"
@@ -101,9 +102,9 @@ static Exynos4210State *exynos4_boards_init_common(MachineState *machine,
MachineClass *mc = MACHINE_GET_CLASS(machine);
if (smp_cpus != EXYNOS4210_NCPUS && !qtest_enabled()) {
- fprintf(stderr, "%s board supports only %d CPU cores. Ignoring smp_cpus"
- " value.\n",
- mc->name, EXYNOS4210_NCPUS);
+ error_report("%s board supports only %d CPU cores, ignoring smp_cpus"
+ " value",
+ mc->name, EXYNOS4210_NCPUS);
}
exynos4_board_binfo.ram_size = exynos4_board_ram_size[board_type];
diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c
index 2126f73ca0..9056f27bf8 100644
--- a/hw/arm/fsl-imx25.c
+++ b/hw/arm/fsl-imx25.c
@@ -290,11 +290,6 @@ static void fsl_imx25_class_init(ObjectClass *oc, void *data)
dc->realize = fsl_imx25_realize;
- /*
- * Reason: creates an ARM CPU, thus use after free(), see
- * arm_cpu_class_init()
- */
- dc->cannot_destroy_with_object_finalize_yet = true;
dc->desc = "i.MX25 SOC";
}
diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c
index dd1c713ae3..d7e2d832b2 100644
--- a/hw/arm/fsl-imx31.c
+++ b/hw/arm/fsl-imx31.c
@@ -262,11 +262,6 @@ static void fsl_imx31_class_init(ObjectClass *oc, void *data)
dc->realize = fsl_imx31_realize;
- /*
- * Reason: creates an ARM CPU, thus use after free(), see
- * arm_cpu_class_init()
- */
- dc->cannot_destroy_with_object_finalize_yet = true;
dc->desc = "i.MX31 SOC";
}
diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c
index 76dd8a48ca..6969e734ad 100644
--- a/hw/arm/fsl-imx6.c
+++ b/hw/arm/fsl-imx6.c
@@ -442,11 +442,6 @@ static void fsl_imx6_class_init(ObjectClass *oc, void *data)
dc->realize = fsl_imx6_realize;
- /*
- * Reason: creates an ARM CPU, thus use after free(), see
- * arm_cpu_class_init()
- */
- dc->cannot_destroy_with_object_finalize_yet = true;
dc->desc = "i.MX6 SOC";
}
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index cfee3929d9..eea551dc16 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -755,19 +755,18 @@ static void pxa2xx_ssp_reset(DeviceState *d)
s->rx_start = s->rx_level = 0;
}
-static int pxa2xx_ssp_init(SysBusDevice *sbd)
+static void pxa2xx_ssp_init(Object *obj)
{
- DeviceState *dev = DEVICE(sbd);
- PXA2xxSSPState *s = PXA2XX_SSP(dev);
-
+ DeviceState *dev = DEVICE(obj);
+ PXA2xxSSPState *s = PXA2XX_SSP(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
sysbus_init_irq(sbd, &s->irq);
- memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_ssp_ops, s,
+ memory_region_init_io(&s->iomem, obj, &pxa2xx_ssp_ops, s,
"pxa2xx-ssp", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
s->bus = ssi_create_bus(dev, "ssi");
- return 0;
}
/* Real-Time Clock */
@@ -2321,10 +2320,8 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- sdc->init = pxa2xx_ssp_init;
dc->reset = pxa2xx_ssp_reset;
dc->vmsd = &vmstate_pxa2xx_ssp;
}
@@ -2333,6 +2330,7 @@ static const TypeInfo pxa2xx_ssp_info = {
.name = TYPE_PXA2XX_SSP,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(PXA2xxSSPState),
+ .instance_init = pxa2xx_ssp_init,
.class_init = pxa2xx_ssp_class_init,
};
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index 9edcd49740..ea7a8094e1 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -108,7 +108,10 @@ static void gptm_reload(gptm_state *s, int n, int reset)
} else if (s->mode[n] == 0xa) {
/* PWM mode. Not implemented. */
} else {
- hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
+ qemu_log_mask(LOG_UNIMP,
+ "GPTM: 16-bit timer mode unimplemented: 0x%x\n",
+ s->mode[n]);
+ return;
}
s->tick[n] = tick;
timer_mod(s->timer[n], tick);
@@ -149,7 +152,9 @@ static void gptm_tick(void *opaque)
} else if (s->mode[n] == 0xa) {
/* PWM mode. Not implemented. */
} else {
- hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
+ qemu_log_mask(LOG_UNIMP,
+ "GPTM: 16-bit timer mode unimplemented: 0x%x\n",
+ s->mode[n]);
}
gptm_update_irq(s);
}
@@ -286,7 +291,8 @@ static void gptm_write(void *opaque, hwaddr offset,
s->match_prescale[0] = value;
break;
default:
- hw_error("gptm_write: Bad offset 0x%x\n", (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "GPTM: read at bad offset 0x%x\n", (int)offset);
}
gptm_update_irq(s);
}
@@ -425,7 +431,10 @@ static int ssys_board_class(const ssys_state *s)
}
/* for unknown classes, fall through */
default:
- hw_error("ssys_board_class: Unknown class 0x%08x\n", did0);
+ /* This can only happen if the hardwired constant did0 value
+ * in this board's stellaris_board_info struct is wrong.
+ */
+ g_assert_not_reached();
}
}
@@ -479,8 +488,7 @@ static uint64_t ssys_read(void *opaque, hwaddr offset,
case DID0_CLASS_SANDSTORM:
return pllcfg_sandstorm[xtal];
default:
- hw_error("ssys_read: Unhandled class for PLLCFG read.\n");
- return 0;
+ g_assert_not_reached();
}
}
case 0x070: /* RCC2 */
@@ -512,7 +520,8 @@ static uint64_t ssys_read(void *opaque, hwaddr offset,
case 0x1e4: /* USER1 */
return s->user1;
default:
- hw_error("ssys_read: Bad offset 0x%x\n", (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "SSYS: read at bad offset 0x%x\n", (int)offset);
return 0;
}
}
@@ -614,7 +623,8 @@ static void ssys_write(void *opaque, hwaddr offset,
s->ldoarst = value;
break;
default:
- hw_error("ssys_write: Bad offset 0x%x\n", (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "SSYS: write at bad offset 0x%x\n", (int)offset);
}
ssys_update(s);
}
@@ -748,7 +758,8 @@ static uint64_t stellaris_i2c_read(void *opaque, hwaddr offset,
case 0x20: /* MCR */
return s->mcr;
default:
- hw_error("strllaris_i2c_read: Bad offset 0x%x\n", (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "stellaris_i2c: read at bad offset 0x%x\n", (int)offset);
return 0;
}
}
@@ -823,17 +834,18 @@ static void stellaris_i2c_write(void *opaque, hwaddr offset,
s->mris &= ~value;
break;
case 0x20: /* MCR */
- if (value & 1)
- hw_error(
- "stellaris_i2c_write: Loopback not implemented\n");
- if (value & 0x20)
- hw_error(
- "stellaris_i2c_write: Slave mode not implemented\n");
+ if (value & 1) {
+ qemu_log_mask(LOG_UNIMP, "stellaris_i2c: Loopback not implemented");
+ }
+ if (value & 0x20) {
+ qemu_log_mask(LOG_UNIMP,
+ "stellaris_i2c: Slave mode not implemented");
+ }
s->mcr = value & 0x31;
break;
default:
- hw_error("stellaris_i2c_write: Bad offset 0x%x\n",
- (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "stellaris_i2c: write at bad offset 0x%x\n", (int)offset);
}
stellaris_i2c_update(s);
}
@@ -1057,8 +1069,8 @@ static uint64_t stellaris_adc_read(void *opaque, hwaddr offset,
case 0x30: /* SAC */
return s->sac;
default:
- hw_error("strllaris_adc_read: Bad offset 0x%x\n",
- (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "stellaris_adc: read at bad offset 0x%x\n", (int)offset);
return 0;
}
}
@@ -1078,8 +1090,9 @@ static void stellaris_adc_write(void *opaque, hwaddr offset,
return;
case 0x04: /* SSCTL */
if (value != 6) {
- hw_error("ADC: Unimplemented sequence %" PRIx64 "\n",
- value);
+ qemu_log_mask(LOG_UNIMP,
+ "ADC: Unimplemented sequence %" PRIx64 "\n",
+ value);
}
s->ssctl[n] = value;
return;
@@ -1110,13 +1123,14 @@ static void stellaris_adc_write(void *opaque, hwaddr offset,
s->sspri = value;
break;
case 0x28: /* PSSI */
- hw_error("Not implemented: ADC sample initiate\n");
+ qemu_log_mask(LOG_UNIMP, "ADC: sample initiate unimplemented");
break;
case 0x30: /* SAC */
s->sac = value;
break;
default:
- hw_error("stellaris_adc_write: Bad offset 0x%x\n", (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "stellaris_adc: write at bad offset 0x%x\n", (int)offset);
}
stellaris_adc_update(s);
}
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index bc4e66b862..64f52f80a5 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -30,6 +30,8 @@
#define ARM_PHYS_TIMER_PPI 30
#define ARM_VIRT_TIMER_PPI 27
+#define GEM_REVISION 0x40070106
+
#define GIC_BASE_ADDR 0xf9000000
#define GIC_DIST_ADDR 0xf9010000
#define GIC_CPU_ADDR 0xf9020000
@@ -334,8 +336,10 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
qdev_set_nic_properties(DEVICE(&s->gem[i]), nd);
}
+ object_property_set_int(OBJECT(&s->gem[i]), GEM_REVISION, "revision",
+ &error_abort);
object_property_set_int(OBJECT(&s->gem[i]), 2, "num-priority-queues",
- &error_abort);
+ &error_abort);
object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err);
if (err) {
error_propagate(errp, err);
@@ -439,12 +443,6 @@ static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data)
dc->props = xlnx_zynqmp_props;
dc->realize = xlnx_zynqmp_realize;
-
- /*
- * Reason: creates an ARM CPU, thus use after free(), see
- * arm_cpu_class_init()
- */
- dc->cannot_destroy_with_object_finalize_yet = true;
}
static const TypeInfo xlnx_zynqmp_type_info = {
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index a328693d15..2e629b398b 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -2521,8 +2521,8 @@ static void fdctrl_result_timer(void *opaque)
}
/* Init functions */
-static void fdctrl_connect_drives(FDCtrl *fdctrl, Error **errp,
- DeviceState *fdc_dev)
+static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev,
+ Error **errp)
{
unsigned int i;
FDrive *drive;
@@ -2675,7 +2675,7 @@ static void fdctrl_realize_common(DeviceState *dev, FDCtrl *fdctrl,
}
floppy_bus_create(fdctrl, &fdctrl->bus, dev);
- fdctrl_connect_drives(fdctrl, errp, dev);
+ fdctrl_connect_drives(fdctrl, dev, errp);
}
static const MemoryRegionPortio fdc_portio_list[] = {
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index b75f28d473..bff706ab3a 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -102,7 +102,7 @@ typedef struct Exynos4210UartReg {
uint32_t reset_value;
} Exynos4210UartReg;
-static Exynos4210UartReg exynos4210_uart_regs[] = {
+static const Exynos4210UartReg exynos4210_uart_regs[] = {
{"ULCON", ULCON, 0x00000000},
{"UCON", UCON, 0x00003000},
{"UFCON", UFCON, 0x00000000},
@@ -220,7 +220,7 @@ static uint8_t fifo_retrieve(Exynos4210UartFIFO *q)
return ret;
}
-static int fifo_elements_number(Exynos4210UartFIFO *q)
+static int fifo_elements_number(const Exynos4210UartFIFO *q)
{
if (q->sp < q->rp) {
return q->size - q->rp + q->sp;
@@ -229,7 +229,7 @@ static int fifo_elements_number(Exynos4210UartFIFO *q)
return q->sp - q->rp;
}
-static int fifo_empty_elements_number(Exynos4210UartFIFO *q)
+static int fifo_empty_elements_number(const Exynos4210UartFIFO *q)
{
return q->size - fifo_elements_number(q);
}
@@ -245,7 +245,7 @@ static void fifo_reset(Exynos4210UartFIFO *q)
q->rp = 0;
}
-static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(Exynos4210UartState *s)
+static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(const Exynos4210UartState *s)
{
uint32_t level = 0;
uint32_t reg;
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 0d92672203..ada9eea483 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -396,6 +396,11 @@ static void machine_class_init(ObjectClass *oc, void *data)
mc->default_ram_size = 128 * M_BYTE;
mc->rom_file_has_mr = true;
+ /* numa node memory size aligned on 8MB by default.
+ * On Linux, each node's border has to be 8MB aligned
+ */
+ mc->numa_mem_align_shift = 23;
+
object_class_property_add_str(oc, "accel",
machine_get_accel, machine_set_accel, &error_abort);
object_class_property_set_description(oc, "accel",
diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
index 27c8369b57..864832db34 100644
--- a/hw/core/null-machine.c
+++ b/hw/core/null-machine.c
@@ -40,6 +40,12 @@ static void machine_none_init(MachineState *mch)
memory_region_allocate_system_memory(ram, NULL, "ram", mch->ram_size);
memory_region_add_subregion(get_system_memory(), 0, ram);
}
+
+ if (mch->kernel_filename) {
+ error_report("The -kernel parameter is not supported "
+ "(use the generic 'loader' device instead).");
+ exit(1);
+ }
}
static void machine_none_machine_init(MachineClass *mc)
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index c34be1c1ba..79c2014135 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -124,8 +124,12 @@ static void release_drive(Object *obj, const char *name, void *opaque)
BlockBackend **ptr = qdev_get_prop_ptr(dev, prop);
if (*ptr) {
+ AioContext *ctx = blk_get_aio_context(*ptr);
+
+ aio_context_acquire(ctx);
blockdev_auto_del(*ptr);
blk_detach_dev(*ptr, dev);
+ aio_context_release(ctx);
}
}
@@ -405,7 +409,7 @@ void qdev_prop_set_drive(DeviceState *dev, const char *name,
if (value) {
ref = blk_name(value);
if (!*ref) {
- BlockDriverState *bs = blk_bs(value);
+ const BlockDriverState *bs = blk_bs(value);
if (bs) {
ref = bdrv_get_node_name(bs);
}
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 6ab4265eb4..fa3617db2d 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -1010,7 +1010,8 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value)
object_property_set_str(OBJECT(dev), value, name, &error_abort);
}
-void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
+void qdev_prop_set_macaddr(DeviceState *dev, const char *name,
+ const uint8_t *value)
{
char str[2 * 6 + 5 + 1];
snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x",
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 1e7fb33246..02b632f6b3 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -39,9 +39,9 @@
#include "qapi-event.h"
#include "migration/migration.h"
-int qdev_hotplug = 0;
+bool qdev_hotplug = false;
static bool qdev_hot_added = false;
-static bool qdev_hot_removed = false;
+bool qdev_hot_removed = false;
const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
{
@@ -271,40 +271,6 @@ HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
return hotplug_ctrl;
}
-void qdev_unplug(DeviceState *dev, Error **errp)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(dev);
- HotplugHandler *hotplug_ctrl;
- HotplugHandlerClass *hdc;
-
- if (dev->parent_bus && !qbus_is_hotpluggable(dev->parent_bus)) {
- error_setg(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
- return;
- }
-
- if (!dc->hotpluggable) {
- error_setg(errp, QERR_DEVICE_NO_HOTPLUG,
- object_get_typename(OBJECT(dev)));
- return;
- }
-
- qdev_hot_removed = true;
-
- hotplug_ctrl = qdev_get_hotplug_handler(dev);
- /* hotpluggable device MUST have HotplugHandler, if it doesn't
- * then something is very wrong with it */
- g_assert(hotplug_ctrl);
-
- /* If device supports async unplug just request it to be done,
- * otherwise just remove it synchronously */
- hdc = HOTPLUG_HANDLER_GET_CLASS(hotplug_ctrl);
- if (hdc->unplug_request) {
- hotplug_handler_unplug_request(hotplug_ctrl, dev, errp);
- } else {
- hotplug_handler_unplug(hotplug_ctrl, dev, errp);
- }
-}
-
static int qdev_reset_one(DeviceState *dev, void *opaque)
{
device_reset(dev);
@@ -385,7 +351,7 @@ void qdev_machine_creation_done(void)
* ok, initial machine setup is done, starting from now we can
* only create hotpluggable devices
*/
- qdev_hotplug = 1;
+ qdev_hotplug = true;
}
bool qdev_machine_modified(void)
@@ -1037,13 +1003,6 @@ static bool device_get_hotplugged(Object *obj, Error **err)
return dev->hotplugged;
}
-static void device_set_hotplugged(Object *obj, bool value, Error **err)
-{
- DeviceState *dev = DEVICE(obj);
-
- dev->hotplugged = value;
-}
-
static void device_initfn(Object *obj)
{
DeviceState *dev = DEVICE(obj);
@@ -1063,7 +1022,7 @@ static void device_initfn(Object *obj)
object_property_add_bool(obj, "hotpluggable",
device_get_hotpluggable, NULL, NULL);
object_property_add_bool(obj, "hotplugged",
- device_get_hotplugged, device_set_hotplugged,
+ device_get_hotplugged, NULL,
&error_abort);
class = object_get_class(OBJECT(dev));
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
index 1174220394..03d9197f71 100644
--- a/hw/display/cg3.c
+++ b/hw/display/cg3.c
@@ -26,7 +26,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu-common.h"
-#include "cpu.h"
#include "qemu/error-report.h"
#include "ui/console.h"
#include "hw/sysbus.h"
@@ -114,8 +113,8 @@ static void cg3_update_display(void *opaque)
for (y = 0; y < height; y++) {
int update = s->full_update;
- page = (y * width) & TARGET_PAGE_MASK;
- update |= memory_region_get_dirty(&s->vram_mem, page, page + width,
+ page = y * width;
+ update |= memory_region_get_dirty(&s->vram_mem, page, width,
DIRTY_MEMORY_VGA);
if (update) {
if (y_start < 0) {
@@ -148,8 +147,7 @@ static void cg3_update_display(void *opaque)
}
if (page_max >= page_min) {
memory_region_reset_dirty(&s->vram_mem,
- page_min, page_max - page_min + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
+ page_min, page_max - page_min, DIRTY_MEMORY_VGA);
}
/* vsync interrupt? */
if (s->regs[0] & CG3_CR_ENABLE_INTS) {
@@ -305,8 +303,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp)
vmstate_register_ram_global(&s->rom);
fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, CG3_ROM_FILE);
if (fcode_filename) {
- ret = load_image_targphys(fcode_filename, s->prom_addr,
- FCODE_MAX_ROM_SIZE);
+ 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);
@@ -371,7 +368,6 @@ static Property cg3_properties[] = {
DEFINE_PROP_UINT16("width", CG3State, width, -1),
DEFINE_PROP_UINT16("height", CG3State, height, -1),
DEFINE_PROP_UINT16("depth", CG3State, depth, -1),
- DEFINE_PROP_UINT64("prom-addr", CG3State, prom_addr, -1),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/display/cirrus_vga_rop2.h b/hw/display/cirrus_vga_rop2.h
index b86bcd6e09..b208b7348a 100644
--- a/hw/display/cirrus_vga_rop2.h
+++ b/hw/display/cirrus_vga_rop2.h
@@ -29,8 +29,8 @@
#elif DEPTH == 24
#define PUTPIXEL(s, a, c) do { \
ROP_OP(s, a, c); \
- ROP_OP(s, a + 1, (col >> 8)); \
- ROP_OP(s, a + 2, (col >> 16)); \
+ ROP_OP(s, a + 1, (c >> 8)); \
+ ROP_OP(s, a + 2, (c >> 16)); \
} while (0)
#elif DEPTH == 32
#define PUTPIXEL(s, a, c) ROP_OP_32(s, a, c)
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
index e5be713406..fd0b2bec65 100644
--- a/hw/display/exynos4210_fimd.c
+++ b/hw/display/exynos4210_fimd.c
@@ -1263,6 +1263,7 @@ static void exynos4210_fimd_update(void *opaque)
Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
DisplaySurface *surface;
Exynos4210fimdWindow *w;
+ DirtyBitmapSnapshot *snap;
int i, line;
hwaddr fb_line_addr, inc_size;
int scrn_height;
@@ -1291,10 +1292,12 @@ static void exynos4210_fimd_update(void *opaque)
memory_region_sync_dirty_bitmap(w->mem_section.mr);
host_fb_addr = w->host_fb_addr;
fb_line_addr = w->mem_section.offset_within_region;
+ snap = memory_region_snapshot_and_clear_dirty(w->mem_section.mr,
+ fb_line_addr, inc_size * scrn_height, DIRTY_MEMORY_VGA);
for (line = 0; line < scrn_height; line++) {
- is_dirty = memory_region_get_dirty(w->mem_section.mr,
- fb_line_addr, scrn_width, DIRTY_MEMORY_VGA);
+ is_dirty = memory_region_snapshot_get_dirty(w->mem_section.mr,
+ snap, fb_line_addr, scrn_width);
if (s->invalidate || is_dirty) {
if (first_line == -1) {
@@ -1309,9 +1312,7 @@ static void exynos4210_fimd_update(void *opaque)
fb_line_addr += inc_size;
is_dirty = false;
}
- memory_region_reset_dirty(w->mem_section.mr,
- w->mem_section.offset_within_region,
- w->fb_len, DIRTY_MEMORY_VGA);
+ g_free(snap);
blend = true;
}
}
diff --git a/hw/display/framebuffer.c b/hw/display/framebuffer.c
index 25aa46c8c7..d7310d25f2 100644
--- a/hw/display/framebuffer.c
+++ b/hw/display/framebuffer.c
@@ -67,7 +67,7 @@ void framebuffer_update_display(
int *first_row, /* Input and output. */
int *last_row /* Output only */)
{
- hwaddr src_len;
+ DirtyBitmapSnapshot *snap;
uint8_t *dest;
uint8_t *src;
int first, last = 0;
@@ -78,7 +78,6 @@ void framebuffer_update_display(
i = *first_row;
*first_row = -1;
- src_len = (hwaddr)src_width * rows;
mem = mem_section->mr;
if (!mem) {
@@ -102,9 +101,10 @@ void framebuffer_update_display(
src += i * src_width;
dest += i * dest_row_pitch;
+ snap = memory_region_snapshot_and_clear_dirty(mem, addr, src_width * rows,
+ DIRTY_MEMORY_VGA);
for (; i < rows; i++) {
- dirty = memory_region_get_dirty(mem, addr, src_width,
- DIRTY_MEMORY_VGA);
+ dirty = memory_region_snapshot_get_dirty(mem, snap, addr, src_width);
if (dirty || invalidate) {
fn(opaque, dest, src, cols, dest_col_pitch);
if (first == -1)
@@ -115,11 +115,10 @@ void framebuffer_update_display(
src += src_width;
dest += dest_row_pitch;
}
+ g_free(snap);
if (first < 0) {
return;
}
- memory_region_reset_dirty(mem, mem_section->offset_within_region, src_len,
- DIRTY_MEMORY_VGA);
*first_row = first;
*last_row = last;
}
diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c
index 8cdc205dd9..86557d14a9 100644
--- a/hw/display/g364fb.c
+++ b/hw/display/g364fb.c
@@ -64,17 +64,8 @@ typedef struct G364State {
static inline int check_dirty(G364State *s, ram_addr_t page)
{
- return memory_region_get_dirty(&s->mem_vram, page, G364_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
-}
-
-static inline void reset_dirty(G364State *s,
- ram_addr_t page_min, ram_addr_t page_max)
-{
- memory_region_reset_dirty(&s->mem_vram,
- page_min,
- page_max + G364_PAGE_SIZE - page_min - 1,
- DIRTY_MEMORY_VGA);
+ return memory_region_test_and_clear_dirty(&s->mem_vram, page, G364_PAGE_SIZE,
+ DIRTY_MEMORY_VGA);
}
static void g364fb_draw_graphic8(G364State *s)
@@ -83,7 +74,7 @@ static void g364fb_draw_graphic8(G364State *s)
int i, w;
uint8_t *vram;
uint8_t *data_display, *dd;
- ram_addr_t page, page_min, page_max;
+ ram_addr_t page;
int x, y;
int xmin, xmax;
int ymin, ymax;
@@ -114,8 +105,6 @@ static void g364fb_draw_graphic8(G364State *s)
}
page = 0;
- page_min = (ram_addr_t)-1;
- page_max = 0;
x = y = 0;
xmin = s->width;
@@ -137,9 +126,6 @@ static void g364fb_draw_graphic8(G364State *s)
if (check_dirty(s, page)) {
if (y < ymin)
ymin = ymax = y;
- if (page_min == (ram_addr_t)-1)
- page_min = page;
- page_max = page;
if (x < xmin)
xmin = x;
for (i = 0; i < G364_PAGE_SIZE; i++) {
@@ -196,10 +182,7 @@ static void g364fb_draw_graphic8(G364State *s)
ymax = y;
} else {
int dy;
- if (page_min != (ram_addr_t)-1) {
- reset_dirty(s, page_min, page_max);
- page_min = (ram_addr_t)-1;
- page_max = 0;
+ if (xmax || ymax) {
dpy_gfx_update(s->con, xmin, ymin,
xmax - xmin + 1, ymax - ymin + 1);
xmin = s->width;
@@ -219,9 +202,8 @@ static void g364fb_draw_graphic8(G364State *s)
}
done:
- if (page_min != (ram_addr_t)-1) {
+ if (xmax || ymax) {
dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
- reset_dirty(s, page_min, page_max);
}
}
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 0d02f0efe6..4d94cecd72 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -26,6 +26,7 @@
#include "qemu/queue.h"
#include "qemu/atomic.h"
#include "sysemu/sysemu.h"
+#include "migration/migration.h"
#include "trace.h"
#include "qxl.h"
@@ -304,6 +305,16 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
qxl->ssd.cursor = cursor_builtin_hidden();
}
+static uint32_t qxl_crc32(const uint8_t *p, unsigned len)
+{
+ /*
+ * zlib xors the seed with 0xffffffff, and xors the result
+ * again with 0xffffffff; Both are not done with linux's crc32,
+ * which we want to be compatible with, so undo that.
+ */
+ return crc32(0xffffffff, p, len) ^ 0xffffffff;
+}
+
static ram_addr_t qxl_rom_size(void)
{
#define QXL_REQUIRED_SZ (sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes))
@@ -368,6 +379,18 @@ static void init_qxl_rom(PCIQXLDevice *d)
rom->num_pages = cpu_to_le32(num_pages);
rom->ram_header_offset = cpu_to_le32(d->vga.vram_size - ram_header_size);
+ if (d->xres && d->yres) {
+ /* needs linux kernel 4.12+ to work */
+ rom->client_monitors_config.count = 1;
+ rom->client_monitors_config.heads[0].left = 0;
+ rom->client_monitors_config.heads[0].top = 0;
+ rom->client_monitors_config.heads[0].right = cpu_to_le32(d->xres);
+ rom->client_monitors_config.heads[0].bottom = cpu_to_le32(d->yres);
+ rom->client_monitors_config_crc = qxl_crc32(
+ (const uint8_t *)&rom->client_monitors_config,
+ sizeof(rom->client_monitors_config));
+ }
+
d->shadow_rom = *rom;
d->rom = rom;
d->modes = modes;
@@ -639,6 +662,30 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
qxl->guest_primary.commands++;
qxl_track_command(qxl, ext);
qxl_log_command(qxl, "cmd", ext);
+ {
+ /*
+ * Windows 8 drivers place qxl commands in the vram
+ * (instead of the ram) bar. We can't live migrate such a
+ * guest, so add a migration blocker in case we detect
+ * this, to avoid triggering the assert in pre_save().
+ *
+ * https://cgit.freedesktop.org/spice/win32/qxl-wddm-dod/commit/?id=f6e099db39e7d0787f294d5fd0dce328b5210faa
+ */
+ void *msg = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+ if (msg != NULL && (
+ msg < (void *)qxl->vga.vram_ptr ||
+ msg > ((void *)qxl->vga.vram_ptr + qxl->vga.vram_size))) {
+ if (!qxl->migration_blocker) {
+ Error *local_err = NULL;
+ error_setg(&qxl->migration_blocker,
+ "qxl: guest bug: command not in ram bar");
+ migrate_add_blocker(qxl->migration_blocker, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ }
+ }
+ }
+ }
trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode));
return true;
default:
@@ -986,16 +1033,6 @@ static void interface_set_client_capabilities(QXLInstance *sin,
qxl_send_events(qxl, QXL_INTERRUPT_CLIENT);
}
-static uint32_t qxl_crc32(const uint8_t *p, unsigned len)
-{
- /*
- * zlib xors the seed with 0xffffffff, and xors the result
- * again with 0xffffffff; Both are not done with linux's crc32,
- * which we want to be compatible with, so undo that.
- */
- return crc32(0xffffffff, p, len) ^ 0xffffffff;
-}
-
static bool qxl_rom_monitors_config_changed(QXLRom *rom,
VDAgentMonitorsConfig *monitors_config,
unsigned int max_outputs)
@@ -1146,6 +1183,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d)
update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_DEFAULT);
qemu_spice_create_host_primary(&d->ssd);
d->mode = QXL_MODE_VGA;
+ qemu_spice_display_switch(&d->ssd, d->ssd.ds);
vga_dirty_log_start(&d->vga);
graphic_hw_update(d->vga.con);
}
@@ -1235,6 +1273,12 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
qemu_spice_create_host_memslot(&d->ssd);
qxl_soft_reset(d);
+ if (d->migration_blocker) {
+ migrate_del_blocker(d->migration_blocker);
+ error_free(d->migration_blocker);
+ d->migration_blocker = NULL;
+ }
+
if (startstop) {
qemu_spice_display_start();
}
@@ -2365,6 +2409,8 @@ static Property qxl_properties[] = {
#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */
DEFINE_PROP_UINT16("max_outputs", PCIQXLDevice, max_outputs, 0),
#endif
+ DEFINE_PROP_UINT32("xres", PCIQXLDevice, xres, 0),
+ DEFINE_PROP_UINT32("yres", PCIQXLDevice, yres, 0),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/display/qxl.h b/hw/display/qxl.h
index d2d49dd933..f6556adb73 100644
--- a/hw/display/qxl.h
+++ b/hw/display/qxl.h
@@ -40,6 +40,7 @@ typedef struct PCIQXLDevice {
uint32_t cmdlog;
uint32_t guest_bug;
+ Error *migration_blocker;
enum qxl_mode mode;
uint32_t cmdflags;
@@ -118,6 +119,8 @@ typedef struct PCIQXLDevice {
uint32_t vram_size_mb;
uint32_t vram32_size_mb;
uint32_t vgamem_size_mb;
+ uint32_t xres;
+ uint32_t yres;
/* qxl_render_update state */
int render_update_cookie_num;
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 040a0b93f2..2094adbc9c 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -2,6 +2,7 @@
* QEMU SM501 Device
*
* Copyright (c) 2008 Shin-ichiro KAWASAKI
+ * Copyright (c) 2016 BALATON Zoltan
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,6 +24,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/cutils.h"
#include "qapi/error.h"
#include "qemu-common.h"
#include "cpu.h"
@@ -31,6 +33,7 @@
#include "ui/console.h"
#include "hw/devices.h"
#include "hw/sysbus.h"
+#include "hw/pci/pci.h"
#include "qemu/range.h"
#include "ui/pixel_ops.h"
#include "exec/address-spaces.h"
@@ -38,10 +41,13 @@
/*
* Status: 2010/05/07
* - Minimum implementation for Linux console : mmio regs and CRT layer.
- * - 2D grapihcs acceleration partially supported : only fill rectangle.
+ * - 2D graphics acceleration partially supported : only fill rectangle.
*
- * TODO:
+ * Status: 2016/12/04
+ * - Misc fixes: endianness, hardware cursor
* - Panel support
+ *
+ * TODO:
* - Touch panel support
* - USB support
* - UART support
@@ -49,395 +55,396 @@
* - Performance tuning
*/
-//#define DEBUG_SM501
-//#define DEBUG_BITBLT
+/*#define DEBUG_SM501*/
+/*#define DEBUG_BITBLT*/
#ifdef DEBUG_SM501
#define SM501_DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
#else
-#define SM501_DPRINTF(fmt, ...) do {} while(0)
+#define SM501_DPRINTF(fmt, ...) do {} while (0)
#endif
-
#define MMIO_BASE_OFFSET 0x3e00000
+#define MMIO_SIZE 0x200000
+#define DC_PALETTE_ENTRIES (0x400 * 3)
/* SM501 register definitions taken from "linux/include/linux/sm501-regs.h" */
/* System Configuration area */
/* System config base */
-#define SM501_SYS_CONFIG (0x000000)
+#define SM501_SYS_CONFIG (0x000000)
/* config 1 */
-#define SM501_SYSTEM_CONTROL (0x000000)
+#define SM501_SYSTEM_CONTROL (0x000000)
-#define SM501_SYSCTRL_PANEL_TRISTATE (1<<0)
-#define SM501_SYSCTRL_MEM_TRISTATE (1<<1)
-#define SM501_SYSCTRL_CRT_TRISTATE (1<<2)
+#define SM501_SYSCTRL_PANEL_TRISTATE (1 << 0)
+#define SM501_SYSCTRL_MEM_TRISTATE (1 << 1)
+#define SM501_SYSCTRL_CRT_TRISTATE (1 << 2)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_MASK (3<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_1 (0<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_2 (1<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_4 (2<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_8 (3<<4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_MASK (3 << 4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_1 (0 << 4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_2 (1 << 4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_4 (2 << 4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_8 (3 << 4)
-#define SM501_SYSCTRL_PCI_CLOCK_RUN_EN (1<<6)
-#define SM501_SYSCTRL_PCI_RETRY_DISABLE (1<<7)
-#define SM501_SYSCTRL_PCI_SUBSYS_LOCK (1<<11)
-#define SM501_SYSCTRL_PCI_BURST_READ_EN (1<<15)
+#define SM501_SYSCTRL_PCI_CLOCK_RUN_EN (1 << 6)
+#define SM501_SYSCTRL_PCI_RETRY_DISABLE (1 << 7)
+#define SM501_SYSCTRL_PCI_SUBSYS_LOCK (1 << 11)
+#define SM501_SYSCTRL_PCI_BURST_READ_EN (1 << 15)
/* miscellaneous control */
-#define SM501_MISC_CONTROL (0x000004)
+#define SM501_MISC_CONTROL (0x000004)
-#define SM501_MISC_BUS_SH (0x0)
-#define SM501_MISC_BUS_PCI (0x1)
-#define SM501_MISC_BUS_XSCALE (0x2)
-#define SM501_MISC_BUS_NEC (0x6)
-#define SM501_MISC_BUS_MASK (0x7)
+#define SM501_MISC_BUS_SH (0x0)
+#define SM501_MISC_BUS_PCI (0x1)
+#define SM501_MISC_BUS_XSCALE (0x2)
+#define SM501_MISC_BUS_NEC (0x6)
+#define SM501_MISC_BUS_MASK (0x7)
-#define SM501_MISC_VR_62MB (1<<3)
-#define SM501_MISC_CDR_RESET (1<<7)
-#define SM501_MISC_USB_LB (1<<8)
-#define SM501_MISC_USB_SLAVE (1<<9)
-#define SM501_MISC_BL_1 (1<<10)
-#define SM501_MISC_MC (1<<11)
-#define SM501_MISC_DAC_POWER (1<<12)
-#define SM501_MISC_IRQ_INVERT (1<<16)
-#define SM501_MISC_SH (1<<17)
+#define SM501_MISC_VR_62MB (1 << 3)
+#define SM501_MISC_CDR_RESET (1 << 7)
+#define SM501_MISC_USB_LB (1 << 8)
+#define SM501_MISC_USB_SLAVE (1 << 9)
+#define SM501_MISC_BL_1 (1 << 10)
+#define SM501_MISC_MC (1 << 11)
+#define SM501_MISC_DAC_POWER (1 << 12)
+#define SM501_MISC_IRQ_INVERT (1 << 16)
+#define SM501_MISC_SH (1 << 17)
-#define SM501_MISC_HOLD_EMPTY (0<<18)
-#define SM501_MISC_HOLD_8 (1<<18)
-#define SM501_MISC_HOLD_16 (2<<18)
-#define SM501_MISC_HOLD_24 (3<<18)
-#define SM501_MISC_HOLD_32 (4<<18)
-#define SM501_MISC_HOLD_MASK (7<<18)
+#define SM501_MISC_HOLD_EMPTY (0 << 18)
+#define SM501_MISC_HOLD_8 (1 << 18)
+#define SM501_MISC_HOLD_16 (2 << 18)
+#define SM501_MISC_HOLD_24 (3 << 18)
+#define SM501_MISC_HOLD_32 (4 << 18)
+#define SM501_MISC_HOLD_MASK (7 << 18)
-#define SM501_MISC_FREQ_12 (1<<24)
-#define SM501_MISC_PNL_24BIT (1<<25)
-#define SM501_MISC_8051_LE (1<<26)
+#define SM501_MISC_FREQ_12 (1 << 24)
+#define SM501_MISC_PNL_24BIT (1 << 25)
+#define SM501_MISC_8051_LE (1 << 26)
-#define SM501_GPIO31_0_CONTROL (0x000008)
-#define SM501_GPIO63_32_CONTROL (0x00000C)
-#define SM501_DRAM_CONTROL (0x000010)
+#define SM501_GPIO31_0_CONTROL (0x000008)
+#define SM501_GPIO63_32_CONTROL (0x00000C)
+#define SM501_DRAM_CONTROL (0x000010)
/* command list */
-#define SM501_ARBTRTN_CONTROL (0x000014)
+#define SM501_ARBTRTN_CONTROL (0x000014)
/* command list */
-#define SM501_COMMAND_LIST_STATUS (0x000024)
+#define SM501_COMMAND_LIST_STATUS (0x000024)
/* interrupt debug */
-#define SM501_RAW_IRQ_STATUS (0x000028)
-#define SM501_RAW_IRQ_CLEAR (0x000028)
-#define SM501_IRQ_STATUS (0x00002C)
-#define SM501_IRQ_MASK (0x000030)
-#define SM501_DEBUG_CONTROL (0x000034)
+#define SM501_RAW_IRQ_STATUS (0x000028)
+#define SM501_RAW_IRQ_CLEAR (0x000028)
+#define SM501_IRQ_STATUS (0x00002C)
+#define SM501_IRQ_MASK (0x000030)
+#define SM501_DEBUG_CONTROL (0x000034)
/* power management */
-#define SM501_POWERMODE_P2X_SRC (1<<29)
-#define SM501_POWERMODE_V2X_SRC (1<<20)
-#define SM501_POWERMODE_M_SRC (1<<12)
-#define SM501_POWERMODE_M1_SRC (1<<4)
-
-#define SM501_CURRENT_GATE (0x000038)
-#define SM501_CURRENT_CLOCK (0x00003C)
-#define SM501_POWER_MODE_0_GATE (0x000040)
-#define SM501_POWER_MODE_0_CLOCK (0x000044)
-#define SM501_POWER_MODE_1_GATE (0x000048)
-#define SM501_POWER_MODE_1_CLOCK (0x00004C)
-#define SM501_SLEEP_MODE_GATE (0x000050)
-#define SM501_POWER_MODE_CONTROL (0x000054)
+#define SM501_POWERMODE_P2X_SRC (1 << 29)
+#define SM501_POWERMODE_V2X_SRC (1 << 20)
+#define SM501_POWERMODE_M_SRC (1 << 12)
+#define SM501_POWERMODE_M1_SRC (1 << 4)
+
+#define SM501_CURRENT_GATE (0x000038)
+#define SM501_CURRENT_CLOCK (0x00003C)
+#define SM501_POWER_MODE_0_GATE (0x000040)
+#define SM501_POWER_MODE_0_CLOCK (0x000044)
+#define SM501_POWER_MODE_1_GATE (0x000048)
+#define SM501_POWER_MODE_1_CLOCK (0x00004C)
+#define SM501_SLEEP_MODE_GATE (0x000050)
+#define SM501_POWER_MODE_CONTROL (0x000054)
/* power gates for units within the 501 */
-#define SM501_GATE_HOST (0)
-#define SM501_GATE_MEMORY (1)
-#define SM501_GATE_DISPLAY (2)
-#define SM501_GATE_2D_ENGINE (3)
-#define SM501_GATE_CSC (4)
-#define SM501_GATE_ZVPORT (5)
-#define SM501_GATE_GPIO (6)
-#define SM501_GATE_UART0 (7)
-#define SM501_GATE_UART1 (8)
-#define SM501_GATE_SSP (10)
-#define SM501_GATE_USB_HOST (11)
-#define SM501_GATE_USB_GADGET (12)
-#define SM501_GATE_UCONTROLLER (17)
-#define SM501_GATE_AC97 (18)
+#define SM501_GATE_HOST (0)
+#define SM501_GATE_MEMORY (1)
+#define SM501_GATE_DISPLAY (2)
+#define SM501_GATE_2D_ENGINE (3)
+#define SM501_GATE_CSC (4)
+#define SM501_GATE_ZVPORT (5)
+#define SM501_GATE_GPIO (6)
+#define SM501_GATE_UART0 (7)
+#define SM501_GATE_UART1 (8)
+#define SM501_GATE_SSP (10)
+#define SM501_GATE_USB_HOST (11)
+#define SM501_GATE_USB_GADGET (12)
+#define SM501_GATE_UCONTROLLER (17)
+#define SM501_GATE_AC97 (18)
/* panel clock */
-#define SM501_CLOCK_P2XCLK (24)
+#define SM501_CLOCK_P2XCLK (24)
/* crt clock */
-#define SM501_CLOCK_V2XCLK (16)
+#define SM501_CLOCK_V2XCLK (16)
/* main clock */
-#define SM501_CLOCK_MCLK (8)
+#define SM501_CLOCK_MCLK (8)
/* SDRAM controller clock */
-#define SM501_CLOCK_M1XCLK (0)
+#define SM501_CLOCK_M1XCLK (0)
/* config 2 */
-#define SM501_PCI_MASTER_BASE (0x000058)
-#define SM501_ENDIAN_CONTROL (0x00005C)
-#define SM501_DEVICEID (0x000060)
+#define SM501_PCI_MASTER_BASE (0x000058)
+#define SM501_ENDIAN_CONTROL (0x00005C)
+#define SM501_DEVICEID (0x000060)
/* 0x050100A0 */
-#define SM501_DEVICEID_SM501 (0x05010000)
-#define SM501_DEVICEID_IDMASK (0xffff0000)
-#define SM501_DEVICEID_REVMASK (0x000000ff)
+#define SM501_DEVICEID_SM501 (0x05010000)
+#define SM501_DEVICEID_IDMASK (0xffff0000)
+#define SM501_DEVICEID_REVMASK (0x000000ff)
-#define SM501_PLLCLOCK_COUNT (0x000064)
-#define SM501_MISC_TIMING (0x000068)
-#define SM501_CURRENT_SDRAM_CLOCK (0x00006C)
+#define SM501_PLLCLOCK_COUNT (0x000064)
+#define SM501_MISC_TIMING (0x000068)
+#define SM501_CURRENT_SDRAM_CLOCK (0x00006C)
-#define SM501_PROGRAMMABLE_PLL_CONTROL (0x000074)
+#define SM501_PROGRAMMABLE_PLL_CONTROL (0x000074)
/* GPIO base */
-#define SM501_GPIO (0x010000)
-#define SM501_GPIO_DATA_LOW (0x00)
-#define SM501_GPIO_DATA_HIGH (0x04)
-#define SM501_GPIO_DDR_LOW (0x08)
-#define SM501_GPIO_DDR_HIGH (0x0C)
-#define SM501_GPIO_IRQ_SETUP (0x10)
-#define SM501_GPIO_IRQ_STATUS (0x14)
-#define SM501_GPIO_IRQ_RESET (0x14)
+#define SM501_GPIO (0x010000)
+#define SM501_GPIO_DATA_LOW (0x00)
+#define SM501_GPIO_DATA_HIGH (0x04)
+#define SM501_GPIO_DDR_LOW (0x08)
+#define SM501_GPIO_DDR_HIGH (0x0C)
+#define SM501_GPIO_IRQ_SETUP (0x10)
+#define SM501_GPIO_IRQ_STATUS (0x14)
+#define SM501_GPIO_IRQ_RESET (0x14)
/* I2C controller base */
-#define SM501_I2C (0x010040)
-#define SM501_I2C_BYTE_COUNT (0x00)
-#define SM501_I2C_CONTROL (0x01)
-#define SM501_I2C_STATUS (0x02)
-#define SM501_I2C_RESET (0x02)
-#define SM501_I2C_SLAVE_ADDRESS (0x03)
-#define SM501_I2C_DATA (0x04)
+#define SM501_I2C (0x010040)
+#define SM501_I2C_BYTE_COUNT (0x00)
+#define SM501_I2C_CONTROL (0x01)
+#define SM501_I2C_STATUS (0x02)
+#define SM501_I2C_RESET (0x02)
+#define SM501_I2C_SLAVE_ADDRESS (0x03)
+#define SM501_I2C_DATA (0x04)
/* SSP base */
-#define SM501_SSP (0x020000)
+#define SM501_SSP (0x020000)
/* Uart 0 base */
-#define SM501_UART0 (0x030000)
+#define SM501_UART0 (0x030000)
/* Uart 1 base */
-#define SM501_UART1 (0x030020)
+#define SM501_UART1 (0x030020)
/* USB host port base */
-#define SM501_USB_HOST (0x040000)
+#define SM501_USB_HOST (0x040000)
/* USB slave/gadget base */
-#define SM501_USB_GADGET (0x060000)
+#define SM501_USB_GADGET (0x060000)
/* USB slave/gadget data port base */
-#define SM501_USB_GADGET_DATA (0x070000)
+#define SM501_USB_GADGET_DATA (0x070000)
/* Display controller/video engine base */
-#define SM501_DC (0x080000)
+#define SM501_DC (0x080000)
/* common defines for the SM501 address registers */
-#define SM501_ADDR_FLIP (1<<31)
-#define SM501_ADDR_EXT (1<<27)
-#define SM501_ADDR_CS1 (1<<26)
-#define SM501_ADDR_MASK (0x3f << 26)
+#define SM501_ADDR_FLIP (1 << 31)
+#define SM501_ADDR_EXT (1 << 27)
+#define SM501_ADDR_CS1 (1 << 26)
+#define SM501_ADDR_MASK (0x3f << 26)
-#define SM501_FIFO_MASK (0x3 << 16)
-#define SM501_FIFO_1 (0x0 << 16)
-#define SM501_FIFO_3 (0x1 << 16)
-#define SM501_FIFO_7 (0x2 << 16)
-#define SM501_FIFO_11 (0x3 << 16)
+#define SM501_FIFO_MASK (0x3 << 16)
+#define SM501_FIFO_1 (0x0 << 16)
+#define SM501_FIFO_3 (0x1 << 16)
+#define SM501_FIFO_7 (0x2 << 16)
+#define SM501_FIFO_11 (0x3 << 16)
/* common registers for panel and the crt */
-#define SM501_OFF_DC_H_TOT (0x000)
-#define SM501_OFF_DC_V_TOT (0x008)
-#define SM501_OFF_DC_H_SYNC (0x004)
-#define SM501_OFF_DC_V_SYNC (0x00C)
-
-#define SM501_DC_PANEL_CONTROL (0x000)
-
-#define SM501_DC_PANEL_CONTROL_FPEN (1<<27)
-#define SM501_DC_PANEL_CONTROL_BIAS (1<<26)
-#define SM501_DC_PANEL_CONTROL_DATA (1<<25)
-#define SM501_DC_PANEL_CONTROL_VDD (1<<24)
-#define SM501_DC_PANEL_CONTROL_DP (1<<23)
-
-#define SM501_DC_PANEL_CONTROL_TFT_888 (0<<21)
-#define SM501_DC_PANEL_CONTROL_TFT_333 (1<<21)
-#define SM501_DC_PANEL_CONTROL_TFT_444 (2<<21)
-
-#define SM501_DC_PANEL_CONTROL_DE (1<<20)
-
-#define SM501_DC_PANEL_CONTROL_LCD_TFT (0<<18)
-#define SM501_DC_PANEL_CONTROL_LCD_STN8 (1<<18)
-#define SM501_DC_PANEL_CONTROL_LCD_STN12 (2<<18)
-
-#define SM501_DC_PANEL_CONTROL_CP (1<<14)
-#define SM501_DC_PANEL_CONTROL_VSP (1<<13)
-#define SM501_DC_PANEL_CONTROL_HSP (1<<12)
-#define SM501_DC_PANEL_CONTROL_CK (1<<9)
-#define SM501_DC_PANEL_CONTROL_TE (1<<8)
-#define SM501_DC_PANEL_CONTROL_VPD (1<<7)
-#define SM501_DC_PANEL_CONTROL_VP (1<<6)
-#define SM501_DC_PANEL_CONTROL_HPD (1<<5)
-#define SM501_DC_PANEL_CONTROL_HP (1<<4)
-#define SM501_DC_PANEL_CONTROL_GAMMA (1<<3)
-#define SM501_DC_PANEL_CONTROL_EN (1<<2)
-
-#define SM501_DC_PANEL_CONTROL_8BPP (0<<0)
-#define SM501_DC_PANEL_CONTROL_16BPP (1<<0)
-#define SM501_DC_PANEL_CONTROL_32BPP (2<<0)
-
-
-#define SM501_DC_PANEL_PANNING_CONTROL (0x004)
-#define SM501_DC_PANEL_COLOR_KEY (0x008)
-#define SM501_DC_PANEL_FB_ADDR (0x00C)
-#define SM501_DC_PANEL_FB_OFFSET (0x010)
-#define SM501_DC_PANEL_FB_WIDTH (0x014)
-#define SM501_DC_PANEL_FB_HEIGHT (0x018)
-#define SM501_DC_PANEL_TL_LOC (0x01C)
-#define SM501_DC_PANEL_BR_LOC (0x020)
-#define SM501_DC_PANEL_H_TOT (0x024)
-#define SM501_DC_PANEL_H_SYNC (0x028)
-#define SM501_DC_PANEL_V_TOT (0x02C)
-#define SM501_DC_PANEL_V_SYNC (0x030)
-#define SM501_DC_PANEL_CUR_LINE (0x034)
-
-#define SM501_DC_VIDEO_CONTROL (0x040)
-#define SM501_DC_VIDEO_FB0_ADDR (0x044)
-#define SM501_DC_VIDEO_FB_WIDTH (0x048)
-#define SM501_DC_VIDEO_FB0_LAST_ADDR (0x04C)
-#define SM501_DC_VIDEO_TL_LOC (0x050)
-#define SM501_DC_VIDEO_BR_LOC (0x054)
-#define SM501_DC_VIDEO_SCALE (0x058)
-#define SM501_DC_VIDEO_INIT_SCALE (0x05C)
-#define SM501_DC_VIDEO_YUV_CONSTANTS (0x060)
-#define SM501_DC_VIDEO_FB1_ADDR (0x064)
-#define SM501_DC_VIDEO_FB1_LAST_ADDR (0x068)
-
-#define SM501_DC_VIDEO_ALPHA_CONTROL (0x080)
-#define SM501_DC_VIDEO_ALPHA_FB_ADDR (0x084)
-#define SM501_DC_VIDEO_ALPHA_FB_OFFSET (0x088)
-#define SM501_DC_VIDEO_ALPHA_FB_LAST_ADDR (0x08C)
-#define SM501_DC_VIDEO_ALPHA_TL_LOC (0x090)
-#define SM501_DC_VIDEO_ALPHA_BR_LOC (0x094)
-#define SM501_DC_VIDEO_ALPHA_SCALE (0x098)
-#define SM501_DC_VIDEO_ALPHA_INIT_SCALE (0x09C)
-#define SM501_DC_VIDEO_ALPHA_CHROMA_KEY (0x0A0)
-#define SM501_DC_VIDEO_ALPHA_COLOR_LOOKUP (0x0A4)
-
-#define SM501_DC_PANEL_HWC_BASE (0x0F0)
-#define SM501_DC_PANEL_HWC_ADDR (0x0F0)
-#define SM501_DC_PANEL_HWC_LOC (0x0F4)
-#define SM501_DC_PANEL_HWC_COLOR_1_2 (0x0F8)
-#define SM501_DC_PANEL_HWC_COLOR_3 (0x0FC)
-
-#define SM501_HWC_EN (1<<31)
-
-#define SM501_OFF_HWC_ADDR (0x00)
-#define SM501_OFF_HWC_LOC (0x04)
-#define SM501_OFF_HWC_COLOR_1_2 (0x08)
-#define SM501_OFF_HWC_COLOR_3 (0x0C)
-
-#define SM501_DC_ALPHA_CONTROL (0x100)
-#define SM501_DC_ALPHA_FB_ADDR (0x104)
-#define SM501_DC_ALPHA_FB_OFFSET (0x108)
-#define SM501_DC_ALPHA_TL_LOC (0x10C)
-#define SM501_DC_ALPHA_BR_LOC (0x110)
-#define SM501_DC_ALPHA_CHROMA_KEY (0x114)
-#define SM501_DC_ALPHA_COLOR_LOOKUP (0x118)
-
-#define SM501_DC_CRT_CONTROL (0x200)
-
-#define SM501_DC_CRT_CONTROL_TVP (1<<15)
-#define SM501_DC_CRT_CONTROL_CP (1<<14)
-#define SM501_DC_CRT_CONTROL_VSP (1<<13)
-#define SM501_DC_CRT_CONTROL_HSP (1<<12)
-#define SM501_DC_CRT_CONTROL_VS (1<<11)
-#define SM501_DC_CRT_CONTROL_BLANK (1<<10)
-#define SM501_DC_CRT_CONTROL_SEL (1<<9)
-#define SM501_DC_CRT_CONTROL_TE (1<<8)
+#define SM501_OFF_DC_H_TOT (0x000)
+#define SM501_OFF_DC_V_TOT (0x008)
+#define SM501_OFF_DC_H_SYNC (0x004)
+#define SM501_OFF_DC_V_SYNC (0x00C)
+
+#define SM501_DC_PANEL_CONTROL (0x000)
+
+#define SM501_DC_PANEL_CONTROL_FPEN (1 << 27)
+#define SM501_DC_PANEL_CONTROL_BIAS (1 << 26)
+#define SM501_DC_PANEL_CONTROL_DATA (1 << 25)
+#define SM501_DC_PANEL_CONTROL_VDD (1 << 24)
+#define SM501_DC_PANEL_CONTROL_DP (1 << 23)
+
+#define SM501_DC_PANEL_CONTROL_TFT_888 (0 << 21)
+#define SM501_DC_PANEL_CONTROL_TFT_333 (1 << 21)
+#define SM501_DC_PANEL_CONTROL_TFT_444 (2 << 21)
+
+#define SM501_DC_PANEL_CONTROL_DE (1 << 20)
+
+#define SM501_DC_PANEL_CONTROL_LCD_TFT (0 << 18)
+#define SM501_DC_PANEL_CONTROL_LCD_STN8 (1 << 18)
+#define SM501_DC_PANEL_CONTROL_LCD_STN12 (2 << 18)
+
+#define SM501_DC_PANEL_CONTROL_CP (1 << 14)
+#define SM501_DC_PANEL_CONTROL_VSP (1 << 13)
+#define SM501_DC_PANEL_CONTROL_HSP (1 << 12)
+#define SM501_DC_PANEL_CONTROL_CK (1 << 9)
+#define SM501_DC_PANEL_CONTROL_TE (1 << 8)
+#define SM501_DC_PANEL_CONTROL_VPD (1 << 7)
+#define SM501_DC_PANEL_CONTROL_VP (1 << 6)
+#define SM501_DC_PANEL_CONTROL_HPD (1 << 5)
+#define SM501_DC_PANEL_CONTROL_HP (1 << 4)
+#define SM501_DC_PANEL_CONTROL_GAMMA (1 << 3)
+#define SM501_DC_PANEL_CONTROL_EN (1 << 2)
+
+#define SM501_DC_PANEL_CONTROL_8BPP (0 << 0)
+#define SM501_DC_PANEL_CONTROL_16BPP (1 << 0)
+#define SM501_DC_PANEL_CONTROL_32BPP (2 << 0)
+
+
+#define SM501_DC_PANEL_PANNING_CONTROL (0x004)
+#define SM501_DC_PANEL_COLOR_KEY (0x008)
+#define SM501_DC_PANEL_FB_ADDR (0x00C)
+#define SM501_DC_PANEL_FB_OFFSET (0x010)
+#define SM501_DC_PANEL_FB_WIDTH (0x014)
+#define SM501_DC_PANEL_FB_HEIGHT (0x018)
+#define SM501_DC_PANEL_TL_LOC (0x01C)
+#define SM501_DC_PANEL_BR_LOC (0x020)
+#define SM501_DC_PANEL_H_TOT (0x024)
+#define SM501_DC_PANEL_H_SYNC (0x028)
+#define SM501_DC_PANEL_V_TOT (0x02C)
+#define SM501_DC_PANEL_V_SYNC (0x030)
+#define SM501_DC_PANEL_CUR_LINE (0x034)
+
+#define SM501_DC_VIDEO_CONTROL (0x040)
+#define SM501_DC_VIDEO_FB0_ADDR (0x044)
+#define SM501_DC_VIDEO_FB_WIDTH (0x048)
+#define SM501_DC_VIDEO_FB0_LAST_ADDR (0x04C)
+#define SM501_DC_VIDEO_TL_LOC (0x050)
+#define SM501_DC_VIDEO_BR_LOC (0x054)
+#define SM501_DC_VIDEO_SCALE (0x058)
+#define SM501_DC_VIDEO_INIT_SCALE (0x05C)
+#define SM501_DC_VIDEO_YUV_CONSTANTS (0x060)
+#define SM501_DC_VIDEO_FB1_ADDR (0x064)
+#define SM501_DC_VIDEO_FB1_LAST_ADDR (0x068)
+
+#define SM501_DC_VIDEO_ALPHA_CONTROL (0x080)
+#define SM501_DC_VIDEO_ALPHA_FB_ADDR (0x084)
+#define SM501_DC_VIDEO_ALPHA_FB_OFFSET (0x088)
+#define SM501_DC_VIDEO_ALPHA_FB_LAST_ADDR (0x08C)
+#define SM501_DC_VIDEO_ALPHA_TL_LOC (0x090)
+#define SM501_DC_VIDEO_ALPHA_BR_LOC (0x094)
+#define SM501_DC_VIDEO_ALPHA_SCALE (0x098)
+#define SM501_DC_VIDEO_ALPHA_INIT_SCALE (0x09C)
+#define SM501_DC_VIDEO_ALPHA_CHROMA_KEY (0x0A0)
+#define SM501_DC_VIDEO_ALPHA_COLOR_LOOKUP (0x0A4)
+
+#define SM501_DC_PANEL_HWC_BASE (0x0F0)
+#define SM501_DC_PANEL_HWC_ADDR (0x0F0)
+#define SM501_DC_PANEL_HWC_LOC (0x0F4)
+#define SM501_DC_PANEL_HWC_COLOR_1_2 (0x0F8)
+#define SM501_DC_PANEL_HWC_COLOR_3 (0x0FC)
+
+#define SM501_HWC_EN (1 << 31)
+
+#define SM501_OFF_HWC_ADDR (0x00)
+#define SM501_OFF_HWC_LOC (0x04)
+#define SM501_OFF_HWC_COLOR_1_2 (0x08)
+#define SM501_OFF_HWC_COLOR_3 (0x0C)
+
+#define SM501_DC_ALPHA_CONTROL (0x100)
+#define SM501_DC_ALPHA_FB_ADDR (0x104)
+#define SM501_DC_ALPHA_FB_OFFSET (0x108)
+#define SM501_DC_ALPHA_TL_LOC (0x10C)
+#define SM501_DC_ALPHA_BR_LOC (0x110)
+#define SM501_DC_ALPHA_CHROMA_KEY (0x114)
+#define SM501_DC_ALPHA_COLOR_LOOKUP (0x118)
+
+#define SM501_DC_CRT_CONTROL (0x200)
+
+#define SM501_DC_CRT_CONTROL_TVP (1 << 15)
+#define SM501_DC_CRT_CONTROL_CP (1 << 14)
+#define SM501_DC_CRT_CONTROL_VSP (1 << 13)
+#define SM501_DC_CRT_CONTROL_HSP (1 << 12)
+#define SM501_DC_CRT_CONTROL_VS (1 << 11)
+#define SM501_DC_CRT_CONTROL_BLANK (1 << 10)
+#define SM501_DC_CRT_CONTROL_SEL (1 << 9)
+#define SM501_DC_CRT_CONTROL_TE (1 << 8)
#define SM501_DC_CRT_CONTROL_PIXEL_MASK (0xF << 4)
-#define SM501_DC_CRT_CONTROL_GAMMA (1<<3)
-#define SM501_DC_CRT_CONTROL_ENABLE (1<<2)
+#define SM501_DC_CRT_CONTROL_GAMMA (1 << 3)
+#define SM501_DC_CRT_CONTROL_ENABLE (1 << 2)
-#define SM501_DC_CRT_CONTROL_8BPP (0<<0)
-#define SM501_DC_CRT_CONTROL_16BPP (1<<0)
-#define SM501_DC_CRT_CONTROL_32BPP (2<<0)
+#define SM501_DC_CRT_CONTROL_8BPP (0 << 0)
+#define SM501_DC_CRT_CONTROL_16BPP (1 << 0)
+#define SM501_DC_CRT_CONTROL_32BPP (2 << 0)
-#define SM501_DC_CRT_FB_ADDR (0x204)
-#define SM501_DC_CRT_FB_OFFSET (0x208)
-#define SM501_DC_CRT_H_TOT (0x20C)
-#define SM501_DC_CRT_H_SYNC (0x210)
-#define SM501_DC_CRT_V_TOT (0x214)
-#define SM501_DC_CRT_V_SYNC (0x218)
-#define SM501_DC_CRT_SIGNATURE_ANALYZER (0x21C)
-#define SM501_DC_CRT_CUR_LINE (0x220)
-#define SM501_DC_CRT_MONITOR_DETECT (0x224)
+#define SM501_DC_CRT_FB_ADDR (0x204)
+#define SM501_DC_CRT_FB_OFFSET (0x208)
+#define SM501_DC_CRT_H_TOT (0x20C)
+#define SM501_DC_CRT_H_SYNC (0x210)
+#define SM501_DC_CRT_V_TOT (0x214)
+#define SM501_DC_CRT_V_SYNC (0x218)
+#define SM501_DC_CRT_SIGNATURE_ANALYZER (0x21C)
+#define SM501_DC_CRT_CUR_LINE (0x220)
+#define SM501_DC_CRT_MONITOR_DETECT (0x224)
-#define SM501_DC_CRT_HWC_BASE (0x230)
-#define SM501_DC_CRT_HWC_ADDR (0x230)
-#define SM501_DC_CRT_HWC_LOC (0x234)
-#define SM501_DC_CRT_HWC_COLOR_1_2 (0x238)
-#define SM501_DC_CRT_HWC_COLOR_3 (0x23C)
+#define SM501_DC_CRT_HWC_BASE (0x230)
+#define SM501_DC_CRT_HWC_ADDR (0x230)
+#define SM501_DC_CRT_HWC_LOC (0x234)
+#define SM501_DC_CRT_HWC_COLOR_1_2 (0x238)
+#define SM501_DC_CRT_HWC_COLOR_3 (0x23C)
-#define SM501_DC_PANEL_PALETTE (0x400)
+#define SM501_DC_PANEL_PALETTE (0x400)
-#define SM501_DC_VIDEO_PALETTE (0x800)
+#define SM501_DC_VIDEO_PALETTE (0x800)
-#define SM501_DC_CRT_PALETTE (0xC00)
+#define SM501_DC_CRT_PALETTE (0xC00)
/* Zoom Video port base */
-#define SM501_ZVPORT (0x090000)
+#define SM501_ZVPORT (0x090000)
/* AC97/I2S base */
-#define SM501_AC97 (0x0A0000)
+#define SM501_AC97 (0x0A0000)
/* 8051 micro controller base */
-#define SM501_UCONTROLLER (0x0B0000)
+#define SM501_UCONTROLLER (0x0B0000)
/* 8051 micro controller SRAM base */
-#define SM501_UCONTROLLER_SRAM (0x0C0000)
+#define SM501_UCONTROLLER_SRAM (0x0C0000)
/* DMA base */
-#define SM501_DMA (0x0D0000)
+#define SM501_DMA (0x0D0000)
/* 2d engine base */
-#define SM501_2D_ENGINE (0x100000)
-#define SM501_2D_SOURCE (0x00)
-#define SM501_2D_DESTINATION (0x04)
-#define SM501_2D_DIMENSION (0x08)
-#define SM501_2D_CONTROL (0x0C)
-#define SM501_2D_PITCH (0x10)
-#define SM501_2D_FOREGROUND (0x14)
-#define SM501_2D_BACKGROUND (0x18)
-#define SM501_2D_STRETCH (0x1C)
-#define SM501_2D_COLOR_COMPARE (0x20)
-#define SM501_2D_COLOR_COMPARE_MASK (0x24)
-#define SM501_2D_MASK (0x28)
-#define SM501_2D_CLIP_TL (0x2C)
-#define SM501_2D_CLIP_BR (0x30)
-#define SM501_2D_MONO_PATTERN_LOW (0x34)
-#define SM501_2D_MONO_PATTERN_HIGH (0x38)
-#define SM501_2D_WINDOW_WIDTH (0x3C)
-#define SM501_2D_SOURCE_BASE (0x40)
-#define SM501_2D_DESTINATION_BASE (0x44)
-#define SM501_2D_ALPHA (0x48)
-#define SM501_2D_WRAP (0x4C)
-#define SM501_2D_STATUS (0x50)
-
-#define SM501_CSC_Y_SOURCE_BASE (0xC8)
-#define SM501_CSC_CONSTANTS (0xCC)
-#define SM501_CSC_Y_SOURCE_X (0xD0)
-#define SM501_CSC_Y_SOURCE_Y (0xD4)
-#define SM501_CSC_U_SOURCE_BASE (0xD8)
-#define SM501_CSC_V_SOURCE_BASE (0xDC)
-#define SM501_CSC_SOURCE_DIMENSION (0xE0)
-#define SM501_CSC_SOURCE_PITCH (0xE4)
-#define SM501_CSC_DESTINATION (0xE8)
-#define SM501_CSC_DESTINATION_DIMENSION (0xEC)
-#define SM501_CSC_DESTINATION_PITCH (0xF0)
-#define SM501_CSC_SCALE_FACTOR (0xF4)
-#define SM501_CSC_DESTINATION_BASE (0xF8)
-#define SM501_CSC_CONTROL (0xFC)
+#define SM501_2D_ENGINE (0x100000)
+#define SM501_2D_SOURCE (0x00)
+#define SM501_2D_DESTINATION (0x04)
+#define SM501_2D_DIMENSION (0x08)
+#define SM501_2D_CONTROL (0x0C)
+#define SM501_2D_PITCH (0x10)
+#define SM501_2D_FOREGROUND (0x14)
+#define SM501_2D_BACKGROUND (0x18)
+#define SM501_2D_STRETCH (0x1C)
+#define SM501_2D_COLOR_COMPARE (0x20)
+#define SM501_2D_COLOR_COMPARE_MASK (0x24)
+#define SM501_2D_MASK (0x28)
+#define SM501_2D_CLIP_TL (0x2C)
+#define SM501_2D_CLIP_BR (0x30)
+#define SM501_2D_MONO_PATTERN_LOW (0x34)
+#define SM501_2D_MONO_PATTERN_HIGH (0x38)
+#define SM501_2D_WINDOW_WIDTH (0x3C)
+#define SM501_2D_SOURCE_BASE (0x40)
+#define SM501_2D_DESTINATION_BASE (0x44)
+#define SM501_2D_ALPHA (0x48)
+#define SM501_2D_WRAP (0x4C)
+#define SM501_2D_STATUS (0x50)
+
+#define SM501_CSC_Y_SOURCE_BASE (0xC8)
+#define SM501_CSC_CONSTANTS (0xCC)
+#define SM501_CSC_Y_SOURCE_X (0xD0)
+#define SM501_CSC_Y_SOURCE_Y (0xD4)
+#define SM501_CSC_U_SOURCE_BASE (0xD8)
+#define SM501_CSC_V_SOURCE_BASE (0xDC)
+#define SM501_CSC_SOURCE_DIMENSION (0xE0)
+#define SM501_CSC_SOURCE_PITCH (0xE4)
+#define SM501_CSC_DESTINATION (0xE8)
+#define SM501_CSC_DESTINATION_DIMENSION (0xEC)
+#define SM501_CSC_DESTINATION_PITCH (0xF0)
+#define SM501_CSC_SCALE_FACTOR (0xF4)
+#define SM501_CSC_DESTINATION_BASE (0xF8)
+#define SM501_CSC_CONTROL (0xFC)
/* 2d engine data port base */
-#define SM501_2D_ENGINE_DATA (0x110000)
+#define SM501_2D_ENGINE_DATA (0x110000)
/* end of register definitions */
@@ -446,12 +453,12 @@
/* SM501 local memory size taken from "linux/drivers/mfd/sm501.c" */
static const uint32_t sm501_mem_local_size[] = {
- [0] = 4*1024*1024,
- [1] = 8*1024*1024,
- [2] = 16*1024*1024,
- [3] = 32*1024*1024,
- [4] = 64*1024*1024,
- [5] = 2*1024*1024,
+ [0] = 4 * M_BYTE,
+ [1] = 8 * M_BYTE,
+ [2] = 16 * M_BYTE,
+ [3] = 32 * M_BYTE,
+ [4] = 64 * M_BYTE,
+ [5] = 2 * M_BYTE,
};
#define get_local_mem_size(s) sm501_mem_local_size[(s)->local_mem_size_index]
@@ -460,10 +467,13 @@ typedef struct SM501State {
QemuConsole *con;
/* status & internal resources */
- hwaddr base;
uint32_t local_mem_size_index;
- uint8_t * local_mem;
+ uint8_t *local_mem;
MemoryRegion local_mem_region;
+ MemoryRegion mmio_region;
+ MemoryRegion system_config_region;
+ MemoryRegion disp_ctrl_region;
+ MemoryRegion twoD_engine_region;
uint32_t last_width;
uint32_t last_height;
@@ -473,6 +483,7 @@ typedef struct SM501State {
uint32_t gpio_31_0_control;
uint32_t gpio_63_32_control;
uint32_t dram_control;
+ uint32_t arbitration_control;
uint32_t irq_mask;
uint32_t misc_timing;
uint32_t power_mode_control;
@@ -482,7 +493,7 @@ typedef struct SM501State {
uint32_t uart0_mcr;
uint32_t uart0_scr;
- uint8_t dc_palette[0x400 * 3];
+ uint8_t dc_palette[DC_PALETTE_ENTRIES];
uint32_t dc_panel_control;
uint32_t dc_panel_panning_control;
@@ -502,6 +513,8 @@ typedef struct SM501State {
uint32_t dc_panel_hwc_color_1_2;
uint32_t dc_panel_hwc_color_3;
+ uint32_t dc_video_control;
+
uint32_t dc_crt_control;
uint32_t dc_crt_fb_addr;
uint32_t dc_crt_fb_offset;
@@ -521,13 +534,20 @@ typedef struct SM501State {
uint32_t twoD_control;
uint32_t twoD_pitch;
uint32_t twoD_foreground;
+ uint32_t twoD_background;
uint32_t twoD_stretch;
+ uint32_t twoD_color_compare;
uint32_t twoD_color_compare_mask;
uint32_t twoD_mask;
+ uint32_t twoD_clip_tl;
+ uint32_t twoD_clip_br;
+ uint32_t twoD_mono_pattern_low;
+ uint32_t twoD_mono_pattern_high;
uint32_t twoD_window_width;
uint32_t twoD_source_base;
uint32_t twoD_destination_base;
-
+ uint32_t twoD_alpha;
+ uint32_t twoD_wrap;
} SM501State;
static uint32_t get_local_mem_size_index(uint32_t size)
@@ -536,18 +556,36 @@ static uint32_t get_local_mem_size_index(uint32_t size)
int i, index = 0;
for (i = 0; i < ARRAY_SIZE(sm501_mem_local_size); i++) {
- uint32_t new_size = sm501_mem_local_size[i];
- if (new_size >= size) {
- if (norm_size == 0 || norm_size > new_size) {
- norm_size = new_size;
- index = i;
- }
- }
+ uint32_t new_size = sm501_mem_local_size[i];
+ if (new_size >= size) {
+ if (norm_size == 0 || norm_size > new_size) {
+ norm_size = new_size;
+ index = i;
+ }
+ }
}
return index;
}
+static inline int get_width(SM501State *s, int crt)
+{
+ int width = crt ? s->dc_crt_h_total : s->dc_panel_h_total;
+ return (width & 0x00000FFF) + 1;
+}
+
+static inline int get_height(SM501State *s, int crt)
+{
+ int height = crt ? s->dc_crt_v_total : s->dc_panel_v_total;
+ return (height & 0x00000FFF) + 1;
+}
+
+static inline int get_bpp(SM501State *s, int crt)
+{
+ int bpp = crt ? s->dc_crt_control : s->dc_panel_control;
+ return 1 << (bpp & 3);
+}
+
/**
* Check the availability of hardware cursor.
* @param crt 0 for PANEL, 1 for CRT.
@@ -555,17 +593,17 @@ static uint32_t get_local_mem_size_index(uint32_t size)
static inline int is_hwc_enabled(SM501State *state, int crt)
{
uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
- return addr & 0x80000000;
+ return addr & SM501_HWC_EN;
}
/**
* Get the address which holds cursor pattern data.
* @param crt 0 for PANEL, 1 for CRT.
*/
-static inline uint32_t get_hwc_address(SM501State *state, int crt)
+static inline uint8_t *get_hwc_address(SM501State *state, int crt)
{
uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
- return (addr & 0x03FFFFF0)/* >> 4*/;
+ return state->local_mem + (addr & 0x03FFFFF0);
}
/**
@@ -591,53 +629,51 @@ static inline uint32_t get_hwc_x(SM501State *state, int crt)
}
/**
- * Get the cursor position in x coordinate.
+ * Get the hardware cursor palette.
* @param crt 0 for PANEL, 1 for CRT.
- * @param index 0, 1, 2 or 3 which specifies color of corsor dot.
+ * @param palette pointer to a [3 * 3] array to store color values in
*/
-static inline uint16_t get_hwc_color(SM501State *state, int crt, int index)
+static inline void get_hwc_palette(SM501State *state, int crt, uint8_t *palette)
{
- uint32_t color_reg = 0;
- uint16_t color_565 = 0;
-
- if (index == 0) {
- return 0;
- }
-
- switch (index) {
- case 1:
- case 2:
- color_reg = crt ? state->dc_crt_hwc_color_1_2
- : state->dc_panel_hwc_color_1_2;
- break;
- case 3:
- color_reg = crt ? state->dc_crt_hwc_color_3
- : state->dc_panel_hwc_color_3;
- break;
- default:
- printf("invalid hw cursor color.\n");
- abort();
- }
+ int i;
+ uint32_t color_reg;
+ uint16_t rgb565;
+
+ for (i = 0; i < 3; i++) {
+ if (i + 1 == 3) {
+ color_reg = crt ? state->dc_crt_hwc_color_3
+ : state->dc_panel_hwc_color_3;
+ } else {
+ color_reg = crt ? state->dc_crt_hwc_color_1_2
+ : state->dc_panel_hwc_color_1_2;
+ }
- switch (index) {
- case 1:
- case 3:
- color_565 = (uint16_t)(color_reg & 0xFFFF);
- break;
- case 2:
- color_565 = (uint16_t)((color_reg >> 16) & 0xFFFF);
- break;
+ if (i + 1 == 2) {
+ rgb565 = (color_reg >> 16) & 0xFFFF;
+ } else {
+ rgb565 = color_reg & 0xFFFF;
+ }
+ palette[i * 3 + 0] = (rgb565 << 3) & 0xf8; /* red */
+ palette[i * 3 + 1] = (rgb565 >> 3) & 0xfc; /* green */
+ palette[i * 3 + 2] = (rgb565 >> 8) & 0xf8; /* blue */
}
- return color_565;
}
-static int within_hwc_y_range(SM501State *state, int y, int crt)
+static inline void hwc_invalidate(SM501State *s, int crt)
{
- int hwc_y = get_hwc_y(state, crt);
- return (hwc_y <= y && y < hwc_y + SM501_HWC_HEIGHT);
+ int w = get_width(s, crt);
+ int h = get_height(s, crt);
+ int bpp = get_bpp(s, crt);
+ int start = get_hwc_y(s, crt);
+ int end = MIN(h, start + SM501_HWC_HEIGHT) + 1;
+
+ start *= w * bpp;
+ end *= w * bpp;
+
+ memory_region_set_dirty(&s->local_mem_region, start, end - start);
}
-static void sm501_2d_operation(SM501State * s)
+static void sm501_2d_operation(SM501State *s)
{
/* obtain operation parameters */
int operation = (s->twoD_control >> 16) & 0x1f;
@@ -653,8 +689,8 @@ static void sm501_2d_operation(SM501State * s)
int addressing = (s->twoD_stretch >> 16) & 0xF;
/* get frame buffer info */
- uint8_t * src = s->local_mem + (s->twoD_source_base & 0x03FFFFFF);
- uint8_t * dst = s->local_mem + (s->twoD_destination_base & 0x03FFFFFF);
+ uint8_t *src = s->local_mem + (s->twoD_source_base & 0x03FFFFFF);
+ uint8_t *dst = s->local_mem + (s->twoD_destination_base & 0x03FFFFFF);
int src_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
int dst_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
@@ -671,20 +707,20 @@ static void sm501_2d_operation(SM501State * s)
switch (operation) {
case 0x00: /* copy area */
-#define COPY_AREA(_bpp, _pixel_type, rtl) { \
- int y, x, index_d, index_s; \
- for (y = 0; y < operation_height; y++) { \
- for (x = 0; x < operation_width; x++) { \
- if (rtl) { \
- index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \
- index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \
- } else { \
- index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \
- index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
- } \
- *(_pixel_type*)&dst[index_d] = *(_pixel_type*)&src[index_s];\
- } \
- } \
+#define COPY_AREA(_bpp, _pixel_type, rtl) { \
+ int y, x, index_d, index_s; \
+ for (y = 0; y < operation_height; y++) { \
+ for (x = 0; x < operation_width; x++) { \
+ if (rtl) { \
+ index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \
+ index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \
+ } else { \
+ index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \
+ index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
+ } \
+ *(_pixel_type *)&dst[index_d] = *(_pixel_type *)&src[index_s];\
+ } \
+ } \
}
switch (format_flags) {
case 0:
@@ -705,7 +741,7 @@ static void sm501_2d_operation(SM501State * s)
for (y = 0; y < operation_height; y++) { \
for (x = 0; x < operation_width; x++) { \
int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
- *(_pixel_type*)&dst[index] = (_pixel_type)color; \
+ *(_pixel_type *)&dst[index] = (_pixel_type)color; \
} \
} \
}
@@ -733,50 +769,53 @@ static void sm501_2d_operation(SM501State * s)
static uint64_t sm501_system_config_read(void *opaque, hwaddr addr,
unsigned size)
{
- SM501State * s = (SM501State *)opaque;
+ SM501State *s = (SM501State *)opaque;
uint32_t ret = 0;
SM501_DPRINTF("sm501 system config regs : read addr=%x\n", (int)addr);
- switch(addr) {
+ switch (addr) {
case SM501_SYSTEM_CONTROL:
- ret = s->system_control;
- break;
+ ret = s->system_control;
+ break;
case SM501_MISC_CONTROL:
- ret = s->misc_control;
- break;
+ ret = s->misc_control;
+ break;
case SM501_GPIO31_0_CONTROL:
- ret = s->gpio_31_0_control;
- break;
+ ret = s->gpio_31_0_control;
+ break;
case SM501_GPIO63_32_CONTROL:
- ret = s->gpio_63_32_control;
- break;
+ ret = s->gpio_63_32_control;
+ break;
case SM501_DEVICEID:
- ret = 0x050100A0;
- break;
+ ret = 0x050100A0;
+ break;
case SM501_DRAM_CONTROL:
- ret = (s->dram_control & 0x07F107C0) | s->local_mem_size_index << 13;
- break;
+ ret = (s->dram_control & 0x07F107C0) | s->local_mem_size_index << 13;
+ break;
+ case SM501_ARBTRTN_CONTROL:
+ ret = s->arbitration_control;
+ break;
case SM501_IRQ_MASK:
- ret = s->irq_mask;
- break;
+ ret = s->irq_mask;
+ break;
case SM501_MISC_TIMING:
- /* TODO : simulate gate control */
- ret = s->misc_timing;
- break;
+ /* TODO : simulate gate control */
+ ret = s->misc_timing;
+ break;
case SM501_CURRENT_GATE:
- /* TODO : simulate gate control */
- ret = 0x00021807;
- break;
+ /* TODO : simulate gate control */
+ ret = 0x00021807;
+ break;
case SM501_CURRENT_CLOCK:
- ret = 0x2A1A0A09;
- break;
+ ret = 0x2A1A0A09;
+ break;
case SM501_POWER_MODE_CONTROL:
- ret = s->power_mode_control;
- break;
+ ret = s->power_mode_control;
+ break;
default:
- printf("sm501 system config : not implemented register read."
- " addr=%x\n", (int)addr);
+ printf("sm501 system config : not implemented register read."
+ " addr=%x\n", (int)addr);
abort();
}
@@ -786,47 +825,50 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr,
static void sm501_system_config_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
- SM501State * s = (SM501State *)opaque;
+ SM501State *s = (SM501State *)opaque;
SM501_DPRINTF("sm501 system config regs : write addr=%x, val=%x\n",
- (uint32_t)addr, (uint32_t)value);
+ (uint32_t)addr, (uint32_t)value);
- switch(addr) {
+ switch (addr) {
case SM501_SYSTEM_CONTROL:
- s->system_control = value & 0xE300B8F7;
- break;
+ s->system_control = value & 0xE300B8F7;
+ break;
case SM501_MISC_CONTROL:
- s->misc_control = value & 0xFF7FFF20;
- break;
+ s->misc_control = value & 0xFF7FFF20;
+ break;
case SM501_GPIO31_0_CONTROL:
- s->gpio_31_0_control = value;
- break;
+ s->gpio_31_0_control = value;
+ break;
case SM501_GPIO63_32_CONTROL:
- s->gpio_63_32_control = value;
- break;
+ s->gpio_63_32_control = value;
+ break;
case SM501_DRAM_CONTROL:
- s->local_mem_size_index = (value >> 13) & 0x7;
- /* rODO : check validity of size change */
- s->dram_control |= value & 0x7FFFFFC3;
- break;
+ s->local_mem_size_index = (value >> 13) & 0x7;
+ /* TODO : check validity of size change */
+ s->dram_control |= value & 0x7FFFFFC3;
+ break;
+ case SM501_ARBTRTN_CONTROL:
+ s->arbitration_control = value & 0x37777777;
+ break;
case SM501_IRQ_MASK:
- s->irq_mask = value;
- break;
+ s->irq_mask = value;
+ break;
case SM501_MISC_TIMING:
- s->misc_timing = value & 0xF31F1FFF;
- break;
+ s->misc_timing = value & 0xF31F1FFF;
+ break;
case SM501_POWER_MODE_0_GATE:
case SM501_POWER_MODE_1_GATE:
case SM501_POWER_MODE_0_CLOCK:
case SM501_POWER_MODE_1_CLOCK:
- /* TODO : simulate gate & clock control */
- break;
+ /* TODO : simulate gate & clock control */
+ break;
case SM501_POWER_MODE_CONTROL:
- s->power_mode_control = value & 0x00000003;
- break;
+ s->power_mode_control = value & 0x00000003;
+ break;
default:
- printf("sm501 system config : not implemented register write."
- " addr=%x, val=%x\n", (int)addr, (uint32_t)value);
+ printf("sm501 system config : not implemented register write."
+ " addr=%x, val=%x\n", (int)addr, (uint32_t)value);
abort();
}
}
@@ -838,124 +880,128 @@ static const MemoryRegionOps sm501_system_config_ops = {
.min_access_size = 4,
.max_access_size = 4,
},
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static uint32_t sm501_palette_read(void *opaque, hwaddr addr)
{
- SM501State * s = (SM501State *)opaque;
+ SM501State *s = (SM501State *)opaque;
SM501_DPRINTF("sm501 palette read addr=%x\n", (int)addr);
/* TODO : consider BYTE/WORD access */
/* TODO : consider endian */
assert(range_covers_byte(0, 0x400 * 3, addr));
- return *(uint32_t*)&s->dc_palette[addr];
+ return *(uint32_t *)&s->dc_palette[addr];
}
-static void sm501_palette_write(void *opaque,
- hwaddr addr, uint32_t value)
+static void sm501_palette_write(void *opaque, hwaddr addr,
+ uint32_t value)
{
- SM501State * s = (SM501State *)opaque;
+ SM501State *s = (SM501State *)opaque;
SM501_DPRINTF("sm501 palette write addr=%x, val=%x\n",
- (int)addr, value);
+ (int)addr, value);
/* TODO : consider BYTE/WORD access */
/* TODO : consider endian */
assert(range_covers_byte(0, 0x400 * 3, addr));
- *(uint32_t*)&s->dc_palette[addr] = value;
+ *(uint32_t *)&s->dc_palette[addr] = value;
}
static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr,
unsigned size)
{
- SM501State * s = (SM501State *)opaque;
+ SM501State *s = (SM501State *)opaque;
uint32_t ret = 0;
SM501_DPRINTF("sm501 disp ctrl regs : read addr=%x\n", (int)addr);
- switch(addr) {
+ switch (addr) {
case SM501_DC_PANEL_CONTROL:
- ret = s->dc_panel_control;
- break;
+ ret = s->dc_panel_control;
+ break;
case SM501_DC_PANEL_PANNING_CONTROL:
- ret = s->dc_panel_panning_control;
- break;
+ ret = s->dc_panel_panning_control;
+ break;
case SM501_DC_PANEL_FB_ADDR:
- ret = s->dc_panel_fb_addr;
- break;
+ ret = s->dc_panel_fb_addr;
+ break;
case SM501_DC_PANEL_FB_OFFSET:
- ret = s->dc_panel_fb_offset;
- break;
+ ret = s->dc_panel_fb_offset;
+ break;
case SM501_DC_PANEL_FB_WIDTH:
- ret = s->dc_panel_fb_width;
- break;
+ ret = s->dc_panel_fb_width;
+ break;
case SM501_DC_PANEL_FB_HEIGHT:
- ret = s->dc_panel_fb_height;
- break;
+ ret = s->dc_panel_fb_height;
+ break;
case SM501_DC_PANEL_TL_LOC:
- ret = s->dc_panel_tl_location;
- break;
+ ret = s->dc_panel_tl_location;
+ break;
case SM501_DC_PANEL_BR_LOC:
- ret = s->dc_panel_br_location;
- break;
+ ret = s->dc_panel_br_location;
+ break;
case SM501_DC_PANEL_H_TOT:
- ret = s->dc_panel_h_total;
- break;
+ ret = s->dc_panel_h_total;
+ break;
case SM501_DC_PANEL_H_SYNC:
- ret = s->dc_panel_h_sync;
- break;
+ ret = s->dc_panel_h_sync;
+ break;
case SM501_DC_PANEL_V_TOT:
- ret = s->dc_panel_v_total;
- break;
+ ret = s->dc_panel_v_total;
+ break;
case SM501_DC_PANEL_V_SYNC:
- ret = s->dc_panel_v_sync;
- break;
+ ret = s->dc_panel_v_sync;
+ break;
+
+ case SM501_DC_VIDEO_CONTROL:
+ ret = s->dc_video_control;
+ break;
case SM501_DC_CRT_CONTROL:
- ret = s->dc_crt_control;
- break;
+ ret = s->dc_crt_control;
+ break;
case SM501_DC_CRT_FB_ADDR:
- ret = s->dc_crt_fb_addr;
- break;
+ ret = s->dc_crt_fb_addr;
+ break;
case SM501_DC_CRT_FB_OFFSET:
- ret = s->dc_crt_fb_offset;
- break;
+ ret = s->dc_crt_fb_offset;
+ break;
case SM501_DC_CRT_H_TOT:
- ret = s->dc_crt_h_total;
- break;
+ ret = s->dc_crt_h_total;
+ break;
case SM501_DC_CRT_H_SYNC:
- ret = s->dc_crt_h_sync;
- break;
+ ret = s->dc_crt_h_sync;
+ break;
case SM501_DC_CRT_V_TOT:
- ret = s->dc_crt_v_total;
- break;
+ ret = s->dc_crt_v_total;
+ break;
case SM501_DC_CRT_V_SYNC:
- ret = s->dc_crt_v_sync;
- break;
+ ret = s->dc_crt_v_sync;
+ break;
case SM501_DC_CRT_HWC_ADDR:
- ret = s->dc_crt_hwc_addr;
- break;
+ ret = s->dc_crt_hwc_addr;
+ break;
case SM501_DC_CRT_HWC_LOC:
- ret = s->dc_crt_hwc_location;
- break;
+ ret = s->dc_crt_hwc_location;
+ break;
case SM501_DC_CRT_HWC_COLOR_1_2:
- ret = s->dc_crt_hwc_color_1_2;
- break;
+ ret = s->dc_crt_hwc_color_1_2;
+ break;
case SM501_DC_CRT_HWC_COLOR_3:
- ret = s->dc_crt_hwc_color_3;
- break;
+ ret = s->dc_crt_hwc_color_3;
+ break;
- case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
+ case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400 * 3 - 4:
ret = sm501_palette_read(opaque, addr - SM501_DC_PANEL_PALETTE);
break;
default:
- printf("sm501 disp ctrl : not implemented register read."
- " addr=%x\n", (int)addr);
+ printf("sm501 disp ctrl : not implemented register read."
+ " addr=%x\n", (int)addr);
abort();
}
@@ -965,104 +1011,124 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr,
static void sm501_disp_ctrl_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
- SM501State * s = (SM501State *)opaque;
+ SM501State *s = (SM501State *)opaque;
SM501_DPRINTF("sm501 disp ctrl regs : write addr=%x, val=%x\n",
- (unsigned)addr, (unsigned)value);
+ (unsigned)addr, (unsigned)value);
- switch(addr) {
+ switch (addr) {
case SM501_DC_PANEL_CONTROL:
- s->dc_panel_control = value & 0x0FFF73FF;
- break;
+ s->dc_panel_control = value & 0x0FFF73FF;
+ break;
case SM501_DC_PANEL_PANNING_CONTROL:
- s->dc_panel_panning_control = value & 0xFF3FFF3F;
- break;
+ s->dc_panel_panning_control = value & 0xFF3FFF3F;
+ break;
case SM501_DC_PANEL_FB_ADDR:
- s->dc_panel_fb_addr = value & 0x8FFFFFF0;
- break;
+ s->dc_panel_fb_addr = value & 0x8FFFFFF0;
+ break;
case SM501_DC_PANEL_FB_OFFSET:
- s->dc_panel_fb_offset = value & 0x3FF03FF0;
- break;
+ s->dc_panel_fb_offset = value & 0x3FF03FF0;
+ break;
case SM501_DC_PANEL_FB_WIDTH:
- s->dc_panel_fb_width = value & 0x0FFF0FFF;
- break;
+ s->dc_panel_fb_width = value & 0x0FFF0FFF;
+ break;
case SM501_DC_PANEL_FB_HEIGHT:
- s->dc_panel_fb_height = value & 0x0FFF0FFF;
- break;
+ s->dc_panel_fb_height = value & 0x0FFF0FFF;
+ break;
case SM501_DC_PANEL_TL_LOC:
- s->dc_panel_tl_location = value & 0x07FF07FF;
- break;
+ s->dc_panel_tl_location = value & 0x07FF07FF;
+ break;
case SM501_DC_PANEL_BR_LOC:
- s->dc_panel_br_location = value & 0x07FF07FF;
- break;
+ s->dc_panel_br_location = value & 0x07FF07FF;
+ break;
case SM501_DC_PANEL_H_TOT:
- s->dc_panel_h_total = value & 0x0FFF0FFF;
- break;
+ s->dc_panel_h_total = value & 0x0FFF0FFF;
+ break;
case SM501_DC_PANEL_H_SYNC:
- s->dc_panel_h_sync = value & 0x00FF0FFF;
- break;
+ s->dc_panel_h_sync = value & 0x00FF0FFF;
+ break;
case SM501_DC_PANEL_V_TOT:
- s->dc_panel_v_total = value & 0x0FFF0FFF;
- break;
+ s->dc_panel_v_total = value & 0x0FFF0FFF;
+ break;
case SM501_DC_PANEL_V_SYNC:
- s->dc_panel_v_sync = value & 0x003F0FFF;
- break;
+ s->dc_panel_v_sync = value & 0x003F0FFF;
+ break;
case SM501_DC_PANEL_HWC_ADDR:
- s->dc_panel_hwc_addr = value & 0x8FFFFFF0;
- break;
+ value &= 0x8FFFFFF0;
+ if (value != s->dc_panel_hwc_addr) {
+ hwc_invalidate(s, 0);
+ s->dc_panel_hwc_addr = value;
+ }
+ break;
case SM501_DC_PANEL_HWC_LOC:
- s->dc_panel_hwc_location = value & 0x0FFF0FFF;
- break;
+ value &= 0x0FFF0FFF;
+ if (value != s->dc_panel_hwc_location) {
+ hwc_invalidate(s, 0);
+ s->dc_panel_hwc_location = value;
+ }
+ break;
case SM501_DC_PANEL_HWC_COLOR_1_2:
- s->dc_panel_hwc_color_1_2 = value;
- break;
+ s->dc_panel_hwc_color_1_2 = value;
+ break;
case SM501_DC_PANEL_HWC_COLOR_3:
- s->dc_panel_hwc_color_3 = value & 0x0000FFFF;
- break;
+ s->dc_panel_hwc_color_3 = value & 0x0000FFFF;
+ break;
+
+ case SM501_DC_VIDEO_CONTROL:
+ s->dc_video_control = value & 0x00037FFF;
+ break;
case SM501_DC_CRT_CONTROL:
- s->dc_crt_control = value & 0x0003FFFF;
- break;
+ s->dc_crt_control = value & 0x0003FFFF;
+ break;
case SM501_DC_CRT_FB_ADDR:
- s->dc_crt_fb_addr = value & 0x8FFFFFF0;
- break;
+ s->dc_crt_fb_addr = value & 0x8FFFFFF0;
+ break;
case SM501_DC_CRT_FB_OFFSET:
- s->dc_crt_fb_offset = value & 0x3FF03FF0;
- break;
+ s->dc_crt_fb_offset = value & 0x3FF03FF0;
+ break;
case SM501_DC_CRT_H_TOT:
- s->dc_crt_h_total = value & 0x0FFF0FFF;
- break;
+ s->dc_crt_h_total = value & 0x0FFF0FFF;
+ break;
case SM501_DC_CRT_H_SYNC:
- s->dc_crt_h_sync = value & 0x00FF0FFF;
- break;
+ s->dc_crt_h_sync = value & 0x00FF0FFF;
+ break;
case SM501_DC_CRT_V_TOT:
- s->dc_crt_v_total = value & 0x0FFF0FFF;
- break;
+ s->dc_crt_v_total = value & 0x0FFF0FFF;
+ break;
case SM501_DC_CRT_V_SYNC:
- s->dc_crt_v_sync = value & 0x003F0FFF;
- break;
+ s->dc_crt_v_sync = value & 0x003F0FFF;
+ break;
case SM501_DC_CRT_HWC_ADDR:
- s->dc_crt_hwc_addr = value & 0x8FFFFFF0;
- break;
+ value &= 0x8FFFFFF0;
+ if (value != s->dc_crt_hwc_addr) {
+ hwc_invalidate(s, 1);
+ s->dc_crt_hwc_addr = value;
+ }
+ break;
case SM501_DC_CRT_HWC_LOC:
- s->dc_crt_hwc_location = value & 0x0FFF0FFF;
- break;
+ value &= 0x0FFF0FFF;
+ if (value != s->dc_crt_hwc_location) {
+ hwc_invalidate(s, 1);
+ s->dc_crt_hwc_location = value;
+ }
+ break;
case SM501_DC_CRT_HWC_COLOR_1_2:
- s->dc_crt_hwc_color_1_2 = value;
- break;
+ s->dc_crt_hwc_color_1_2 = value;
+ break;
case SM501_DC_CRT_HWC_COLOR_3:
- s->dc_crt_hwc_color_3 = value & 0x0000FFFF;
- break;
+ s->dc_crt_hwc_color_3 = value & 0x0000FFFF;
+ break;
- case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
+ case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400 * 3 - 4:
sm501_palette_write(opaque, addr - SM501_DC_PANEL_PALETTE, value);
break;
default:
- printf("sm501 disp ctrl : not implemented register write."
- " addr=%x, val=%x\n", (int)addr, (unsigned)value);
+ printf("sm501 disp ctrl : not implemented register write."
+ " addr=%x, val=%x\n", (int)addr, (unsigned)value);
abort();
}
}
@@ -1074,20 +1140,80 @@ static const MemoryRegionOps sm501_disp_ctrl_ops = {
.min_access_size = 4,
.max_access_size = 4,
},
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr,
unsigned size)
{
- SM501State * s = (SM501State *)opaque;
+ SM501State *s = (SM501State *)opaque;
uint32_t ret = 0;
SM501_DPRINTF("sm501 2d engine regs : read addr=%x\n", (int)addr);
- switch(addr) {
+ switch (addr) {
+ case SM501_2D_SOURCE:
+ ret = s->twoD_source;
+ break;
+ case SM501_2D_DESTINATION:
+ ret = s->twoD_destination;
+ break;
+ case SM501_2D_DIMENSION:
+ ret = s->twoD_dimension;
+ break;
+ case SM501_2D_CONTROL:
+ ret = s->twoD_control;
+ break;
+ case SM501_2D_PITCH:
+ ret = s->twoD_pitch;
+ break;
+ case SM501_2D_FOREGROUND:
+ ret = s->twoD_foreground;
+ break;
+ case SM501_2D_BACKGROUND:
+ ret = s->twoD_background;
+ break;
+ case SM501_2D_STRETCH:
+ ret = s->twoD_stretch;
+ break;
+ case SM501_2D_COLOR_COMPARE:
+ ret = s->twoD_color_compare;
+ break;
+ case SM501_2D_COLOR_COMPARE_MASK:
+ ret = s->twoD_color_compare_mask;
+ break;
+ case SM501_2D_MASK:
+ ret = s->twoD_mask;
+ break;
+ case SM501_2D_CLIP_TL:
+ ret = s->twoD_clip_tl;
+ break;
+ case SM501_2D_CLIP_BR:
+ ret = s->twoD_clip_br;
+ break;
+ case SM501_2D_MONO_PATTERN_LOW:
+ ret = s->twoD_mono_pattern_low;
+ break;
+ case SM501_2D_MONO_PATTERN_HIGH:
+ ret = s->twoD_mono_pattern_high;
+ break;
+ case SM501_2D_WINDOW_WIDTH:
+ ret = s->twoD_window_width;
+ break;
case SM501_2D_SOURCE_BASE:
ret = s->twoD_source_base;
break;
+ case SM501_2D_DESTINATION_BASE:
+ ret = s->twoD_destination_base;
+ break;
+ case SM501_2D_ALPHA:
+ ret = s->twoD_alpha;
+ break;
+ case SM501_2D_WRAP:
+ ret = s->twoD_wrap;
+ break;
+ case SM501_2D_STATUS:
+ ret = 0; /* Should return interrupt status */
+ break;
default:
printf("sm501 disp ctrl : not implemented register read."
" addr=%x\n", (int)addr);
@@ -1100,11 +1226,11 @@ static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr,
static void sm501_2d_engine_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
- SM501State * s = (SM501State *)opaque;
+ SM501State *s = (SM501State *)opaque;
SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n",
(unsigned)addr, (unsigned)value);
- switch(addr) {
+ switch (addr) {
case SM501_2D_SOURCE:
s->twoD_source = value;
break;
@@ -1130,15 +1256,33 @@ static void sm501_2d_engine_write(void *opaque, hwaddr addr,
case SM501_2D_FOREGROUND:
s->twoD_foreground = value;
break;
+ case SM501_2D_BACKGROUND:
+ s->twoD_background = value;
+ break;
case SM501_2D_STRETCH:
s->twoD_stretch = value;
break;
+ case SM501_2D_COLOR_COMPARE:
+ s->twoD_color_compare = value;
+ break;
case SM501_2D_COLOR_COMPARE_MASK:
s->twoD_color_compare_mask = value;
break;
case SM501_2D_MASK:
s->twoD_mask = value;
break;
+ case SM501_2D_CLIP_TL:
+ s->twoD_clip_tl = value;
+ break;
+ case SM501_2D_CLIP_BR:
+ s->twoD_clip_br = value;
+ break;
+ case SM501_2D_MONO_PATTERN_LOW:
+ s->twoD_mono_pattern_low = value;
+ break;
+ case SM501_2D_MONO_PATTERN_HIGH:
+ s->twoD_mono_pattern_high = value;
+ break;
case SM501_2D_WINDOW_WIDTH:
s->twoD_window_width = value;
break;
@@ -1148,6 +1292,15 @@ static void sm501_2d_engine_write(void *opaque, hwaddr addr,
case SM501_2D_DESTINATION_BASE:
s->twoD_destination_base = value;
break;
+ case SM501_2D_ALPHA:
+ s->twoD_alpha = value;
+ break;
+ case SM501_2D_WRAP:
+ s->twoD_wrap = value;
+ break;
+ case SM501_2D_STATUS:
+ /* ignored, writing 0 should clear interrupt status */
+ break;
default:
printf("sm501 2d engine : not implemented register write."
" addr=%x, val=%x\n", (int)addr, (unsigned)value);
@@ -1162,16 +1315,17 @@ static const MemoryRegionOps sm501_2d_engine_ops = {
.min_access_size = 4,
.max_access_size = 4,
},
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
/* draw line functions for all console modes */
typedef void draw_line_func(uint8_t *d, const uint8_t *s,
- int width, const uint32_t *pal);
+ int width, const uint32_t *pal);
-typedef void draw_hwc_line_func(SM501State * s, int crt, uint8_t * palette,
- int c_y, uint8_t *d, int width);
+typedef void draw_hwc_line_func(uint8_t *d, const uint8_t *s,
+ int width, const uint8_t *palette,
+ int c_x, int c_y);
#define DEPTH 8
#include "sm501_template.h"
@@ -1197,7 +1351,7 @@ typedef void draw_hwc_line_func(SM501State * s, int crt, uint8_t * palette,
#define DEPTH 32
#include "sm501_template.h"
-static draw_line_func * draw_line8_funcs[] = {
+static draw_line_func *draw_line8_funcs[] = {
draw_line8_8,
draw_line8_15,
draw_line8_16,
@@ -1207,7 +1361,7 @@ static draw_line_func * draw_line8_funcs[] = {
draw_line8_16bgr,
};
-static draw_line_func * draw_line16_funcs[] = {
+static draw_line_func *draw_line16_funcs[] = {
draw_line16_8,
draw_line16_15,
draw_line16_16,
@@ -1217,7 +1371,7 @@ static draw_line_func * draw_line16_funcs[] = {
draw_line16_16bgr,
};
-static draw_line_func * draw_line32_funcs[] = {
+static draw_line_func *draw_line32_funcs[] = {
draw_line32_8,
draw_line32_15,
draw_line32_16,
@@ -1227,7 +1381,7 @@ static draw_line_func * draw_line32_funcs[] = {
draw_line32_16bgr,
};
-static draw_hwc_line_func * draw_hwc_line_funcs[] = {
+static draw_hwc_line_func *draw_hwc_line_funcs[] = {
draw_hwc_line_8,
draw_hwc_line_15,
draw_hwc_line_16,
@@ -1242,7 +1396,7 @@ static inline int get_depth_index(DisplaySurface *surface)
switch (surface_bits_per_pixel(surface)) {
default:
case 8:
- return 0;
+ return 0;
case 15:
return 1;
case 16:
@@ -1256,203 +1410,459 @@ static inline int get_depth_index(DisplaySurface *surface)
}
}
-static void sm501_draw_crt(SM501State * s)
+static void sm501_update_display(void *opaque)
{
+ SM501State *s = (SM501State *)opaque;
DisplaySurface *surface = qemu_console_surface(s->con);
- int y;
- int width = (s->dc_crt_h_total & 0x00000FFF) + 1;
- int height = (s->dc_crt_v_total & 0x00000FFF) + 1;
-
- uint8_t * src = s->local_mem;
- int src_bpp = 0;
+ int y, c_x = 0, c_y = 0;
+ int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0;
+ int width = get_width(s, crt);
+ int height = get_height(s, crt);
+ int src_bpp = get_bpp(s, crt);
int dst_bpp = surface_bytes_per_pixel(surface);
- uint32_t * palette = (uint32_t *)&s->dc_palette[SM501_DC_CRT_PALETTE
- - SM501_DC_PANEL_PALETTE];
- uint8_t hwc_palette[3 * 3];
- int ds_depth_index = get_depth_index(surface);
- draw_line_func * draw_line = NULL;
- draw_hwc_line_func * draw_hwc_line = NULL;
+ int dst_depth_index = get_depth_index(surface);
+ draw_line_func *draw_line = NULL;
+ draw_hwc_line_func *draw_hwc_line = NULL;
int full_update = 0;
int y_start = -1;
ram_addr_t page_min = ~0l;
ram_addr_t page_max = 0l;
- ram_addr_t offset = 0;
+ ram_addr_t offset;
+ uint32_t *palette;
+ uint8_t hwc_palette[3 * 3];
+ uint8_t *hwc_src = NULL;
+
+ if (!((crt ? s->dc_crt_control : s->dc_panel_control)
+ & SM501_DC_CRT_CONTROL_ENABLE)) {
+ return;
+ }
+
+ palette = (uint32_t *)(crt ? &s->dc_palette[SM501_DC_CRT_PALETTE -
+ SM501_DC_PANEL_PALETTE]
+ : &s->dc_palette[0]);
/* choose draw_line function */
- switch (s->dc_crt_control & 3) {
- case SM501_DC_CRT_CONTROL_8BPP:
- src_bpp = 1;
- draw_line = draw_line8_funcs[ds_depth_index];
- break;
- case SM501_DC_CRT_CONTROL_16BPP:
- src_bpp = 2;
- draw_line = draw_line16_funcs[ds_depth_index];
- break;
- case SM501_DC_CRT_CONTROL_32BPP:
- src_bpp = 4;
- draw_line = draw_line32_funcs[ds_depth_index];
- break;
+ switch (src_bpp) {
+ case 1:
+ draw_line = draw_line8_funcs[dst_depth_index];
+ break;
+ case 2:
+ draw_line = draw_line16_funcs[dst_depth_index];
+ break;
+ case 4:
+ draw_line = draw_line32_funcs[dst_depth_index];
+ break;
default:
- printf("sm501 draw crt : invalid DC_CRT_CONTROL=%x.\n",
- s->dc_crt_control);
+ printf("sm501 update display : invalid control register value.\n");
abort();
- break;
+ break;
}
/* set up to draw hardware cursor */
- if (is_hwc_enabled(s, 1)) {
- int i;
-
- /* get cursor palette */
- for (i = 0; i < 3; i++) {
- uint16_t rgb565 = get_hwc_color(s, 1, i + 1);
- hwc_palette[i * 3 + 0] = (rgb565 & 0xf800) >> 8; /* red */
- hwc_palette[i * 3 + 1] = (rgb565 & 0x07e0) >> 3; /* green */
- hwc_palette[i * 3 + 2] = (rgb565 & 0x001f) << 3; /* blue */
- }
-
+ if (is_hwc_enabled(s, crt)) {
/* choose cursor draw line function */
- draw_hwc_line = draw_hwc_line_funcs[ds_depth_index];
+ draw_hwc_line = draw_hwc_line_funcs[dst_depth_index];
+ hwc_src = get_hwc_address(s, crt);
+ c_x = get_hwc_x(s, crt);
+ c_y = get_hwc_y(s, crt);
+ get_hwc_palette(s, crt, hwc_palette);
}
/* adjust console size */
if (s->last_width != width || s->last_height != height) {
qemu_console_resize(s->con, width, height);
surface = qemu_console_surface(s->con);
- s->last_width = width;
- s->last_height = height;
- full_update = 1;
+ s->last_width = width;
+ s->last_height = height;
+ full_update = 1;
}
/* draw each line according to conditions */
memory_region_sync_dirty_bitmap(&s->local_mem_region);
- for (y = 0; y < height; y++) {
- int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0;
- int update = full_update || update_hwc;
+ for (y = 0, offset = 0; y < height; y++, offset += width * src_bpp) {
+ int update, update_hwc;
ram_addr_t page0 = offset;
ram_addr_t page1 = offset + width * src_bpp - 1;
- /* check dirty flags for each line */
- update = memory_region_get_dirty(&s->local_mem_region, page0,
- page1 - page0, DIRTY_MEMORY_VGA);
+ /* check if hardware cursor is enabled and we're within its range */
+ update_hwc = draw_hwc_line && c_y <= y && y < c_y + SM501_HWC_HEIGHT;
+ update = full_update || update_hwc;
+ /* check dirty flags for each line */
+ update |= memory_region_get_dirty(&s->local_mem_region, page0,
+ page1 - page0, DIRTY_MEMORY_VGA);
- /* draw line and change status */
- if (update) {
+ /* draw line and change status */
+ if (update) {
uint8_t *d = surface_data(surface);
d += y * width * dst_bpp;
/* draw graphics layer */
- draw_line(d, src, width, palette);
+ draw_line(d, s->local_mem + offset, width, palette);
- /* draw haredware cursor */
+ /* draw hardware cursor */
if (update_hwc) {
- draw_hwc_line(s, 1, hwc_palette, y - get_hwc_y(s, 1), d, width);
+ draw_hwc_line(d, hwc_src, width, hwc_palette, c_x, y - c_y);
}
- if (y_start < 0)
- y_start = y;
- if (page0 < page_min)
- page_min = page0;
- if (page1 > page_max)
- page_max = page1;
- } else {
- if (y_start >= 0) {
- /* flush to display */
+ if (y_start < 0) {
+ y_start = y;
+ }
+ if (page0 < page_min) {
+ page_min = page0;
+ }
+ if (page1 > page_max) {
+ page_max = page1;
+ }
+ } else {
+ if (y_start >= 0) {
+ /* flush to display */
dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
- y_start = -1;
- }
- }
-
- src += width * src_bpp;
- offset += width * src_bpp;
+ y_start = -1;
+ }
+ }
}
/* complete flush to display */
- if (y_start >= 0)
+ if (y_start >= 0) {
dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
+ }
/* clear dirty flags */
if (page_min != ~0l) {
- memory_region_reset_dirty(&s->local_mem_region,
+ memory_region_reset_dirty(&s->local_mem_region,
page_min, page_max + TARGET_PAGE_SIZE,
DIRTY_MEMORY_VGA);
}
}
-static void sm501_update_display(void *opaque)
-{
- SM501State * s = (SM501State *)opaque;
-
- if (s->dc_crt_control & SM501_DC_CRT_CONTROL_ENABLE)
- sm501_draw_crt(s);
-}
-
static const GraphicHwOps sm501_ops = {
.gfx_update = sm501_update_display,
};
-void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
- uint32_t local_mem_bytes, qemu_irq irq, Chardev *chr)
+static void sm501_reset(SM501State *s)
{
- SM501State * s;
- DeviceState *dev;
- MemoryRegion *sm501_system_config = g_new(MemoryRegion, 1);
- MemoryRegion *sm501_disp_ctrl = g_new(MemoryRegion, 1);
- MemoryRegion *sm501_2d_engine = g_new(MemoryRegion, 1);
-
- /* allocate management data region */
- s = (SM501State *)g_malloc0(sizeof(SM501State));
- s->base = base;
- s->local_mem_size_index
- = get_local_mem_size_index(local_mem_bytes);
- SM501_DPRINTF("local mem size=%x. index=%d\n", get_local_mem_size(s),
- s->local_mem_size_index);
- s->system_control = 0x00100000;
- s->misc_control = 0x00001000; /* assumes SH, active=low */
- s->dc_panel_control = 0x00010000;
+ s->system_control = 0x00100000; /* 2D engine FIFO empty */
+ /* Bits 17 (SH), 7 (CDR), 6:5 (Test), 2:0 (Bus) are all supposed
+ * to be determined at reset by GPIO lines which set config bits.
+ * We hardwire them:
+ * SH = 0 : Hitachi Ready Polarity == Active Low
+ * CDR = 0 : do not reset clock divider
+ * TEST = 0 : Normal mode (not testing the silicon)
+ * BUS = 0 : Hitachi SH3/SH4
+ */
+ s->misc_control = SM501_MISC_DAC_POWER;
+ s->gpio_31_0_control = 0;
+ s->gpio_63_32_control = 0;
+ s->dram_control = 0;
+ s->arbitration_control = 0x05146732;
+ s->irq_mask = 0;
+ s->misc_timing = 0;
+ s->power_mode_control = 0;
+ s->dc_panel_control = 0x00010000; /* FIFO level 3 */
+ s->dc_video_control = 0;
s->dc_crt_control = 0x00010000;
+ s->twoD_source = 0;
+ s->twoD_destination = 0;
+ s->twoD_dimension = 0;
+ s->twoD_control = 0;
+ s->twoD_pitch = 0;
+ s->twoD_foreground = 0;
+ s->twoD_background = 0;
+ s->twoD_stretch = 0;
+ s->twoD_color_compare = 0;
+ s->twoD_color_compare_mask = 0;
+ s->twoD_mask = 0;
+ s->twoD_clip_tl = 0;
+ s->twoD_clip_br = 0;
+ s->twoD_mono_pattern_low = 0;
+ s->twoD_mono_pattern_high = 0;
+ s->twoD_window_width = 0;
+ s->twoD_source_base = 0;
+ s->twoD_destination_base = 0;
+ s->twoD_alpha = 0;
+ s->twoD_wrap = 0;
+}
+
+static void sm501_init(SM501State *s, DeviceState *dev,
+ uint32_t local_mem_bytes)
+{
+ s->local_mem_size_index = get_local_mem_size_index(local_mem_bytes);
+ SM501_DPRINTF("sm501 local mem size=%x. index=%d\n", get_local_mem_size(s),
+ s->local_mem_size_index);
- /* allocate local memory */
- memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local",
- local_mem_bytes, &error_fatal);
+ /* local memory */
+ memory_region_init_ram(&s->local_mem_region, OBJECT(dev), "sm501.local",
+ get_local_mem_size(s), &error_fatal);
vmstate_register_ram_global(&s->local_mem_region);
memory_region_set_log(&s->local_mem_region, true, DIRTY_MEMORY_VGA);
s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region);
- memory_region_add_subregion(address_space_mem, base, &s->local_mem_region);
- /* map mmio */
- memory_region_init_io(sm501_system_config, NULL, &sm501_system_config_ops, s,
+ /* mmio */
+ memory_region_init(&s->mmio_region, OBJECT(dev), "sm501.mmio", MMIO_SIZE);
+ memory_region_init_io(&s->system_config_region, OBJECT(dev),
+ &sm501_system_config_ops, s,
"sm501-system-config", 0x6c);
- memory_region_add_subregion(address_space_mem, base + MMIO_BASE_OFFSET,
- sm501_system_config);
- memory_region_init_io(sm501_disp_ctrl, NULL, &sm501_disp_ctrl_ops, s,
+ memory_region_add_subregion(&s->mmio_region, SM501_SYS_CONFIG,
+ &s->system_config_region);
+ memory_region_init_io(&s->disp_ctrl_region, OBJECT(dev),
+ &sm501_disp_ctrl_ops, s,
"sm501-disp-ctrl", 0x1000);
- memory_region_add_subregion(address_space_mem,
- base + MMIO_BASE_OFFSET + SM501_DC,
- sm501_disp_ctrl);
- memory_region_init_io(sm501_2d_engine, NULL, &sm501_2d_engine_ops, s,
+ memory_region_add_subregion(&s->mmio_region, SM501_DC,
+ &s->disp_ctrl_region);
+ memory_region_init_io(&s->twoD_engine_region, OBJECT(dev),
+ &sm501_2d_engine_ops, s,
"sm501-2d-engine", 0x54);
- memory_region_add_subregion(address_space_mem,
- base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
- sm501_2d_engine);
+ memory_region_add_subregion(&s->mmio_region, SM501_2D_ENGINE,
+ &s->twoD_engine_region);
+
+ /* create qemu graphic console */
+ s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s);
+}
+
+static const VMStateDescription vmstate_sm501_state = {
+ .name = "sm501-state",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(local_mem_size_index, SM501State),
+ VMSTATE_UINT32(system_control, SM501State),
+ VMSTATE_UINT32(misc_control, SM501State),
+ VMSTATE_UINT32(gpio_31_0_control, SM501State),
+ VMSTATE_UINT32(gpio_63_32_control, SM501State),
+ VMSTATE_UINT32(dram_control, SM501State),
+ VMSTATE_UINT32(arbitration_control, SM501State),
+ VMSTATE_UINT32(irq_mask, SM501State),
+ VMSTATE_UINT32(misc_timing, SM501State),
+ VMSTATE_UINT32(power_mode_control, SM501State),
+ VMSTATE_UINT32(uart0_ier, SM501State),
+ VMSTATE_UINT32(uart0_lcr, SM501State),
+ VMSTATE_UINT32(uart0_mcr, SM501State),
+ VMSTATE_UINT32(uart0_scr, SM501State),
+ VMSTATE_UINT8_ARRAY(dc_palette, SM501State, DC_PALETTE_ENTRIES),
+ VMSTATE_UINT32(dc_panel_control, SM501State),
+ VMSTATE_UINT32(dc_panel_panning_control, SM501State),
+ VMSTATE_UINT32(dc_panel_fb_addr, SM501State),
+ VMSTATE_UINT32(dc_panel_fb_offset, SM501State),
+ VMSTATE_UINT32(dc_panel_fb_width, SM501State),
+ VMSTATE_UINT32(dc_panel_fb_height, SM501State),
+ VMSTATE_UINT32(dc_panel_tl_location, SM501State),
+ VMSTATE_UINT32(dc_panel_br_location, SM501State),
+ VMSTATE_UINT32(dc_panel_h_total, SM501State),
+ VMSTATE_UINT32(dc_panel_h_sync, SM501State),
+ VMSTATE_UINT32(dc_panel_v_total, SM501State),
+ VMSTATE_UINT32(dc_panel_v_sync, SM501State),
+ VMSTATE_UINT32(dc_panel_hwc_addr, SM501State),
+ VMSTATE_UINT32(dc_panel_hwc_location, SM501State),
+ VMSTATE_UINT32(dc_panel_hwc_color_1_2, SM501State),
+ VMSTATE_UINT32(dc_panel_hwc_color_3, SM501State),
+ VMSTATE_UINT32(dc_video_control, SM501State),
+ VMSTATE_UINT32(dc_crt_control, SM501State),
+ VMSTATE_UINT32(dc_crt_fb_addr, SM501State),
+ VMSTATE_UINT32(dc_crt_fb_offset, SM501State),
+ VMSTATE_UINT32(dc_crt_h_total, SM501State),
+ VMSTATE_UINT32(dc_crt_h_sync, SM501State),
+ VMSTATE_UINT32(dc_crt_v_total, SM501State),
+ VMSTATE_UINT32(dc_crt_v_sync, SM501State),
+ VMSTATE_UINT32(dc_crt_hwc_addr, SM501State),
+ VMSTATE_UINT32(dc_crt_hwc_location, SM501State),
+ VMSTATE_UINT32(dc_crt_hwc_color_1_2, SM501State),
+ VMSTATE_UINT32(dc_crt_hwc_color_3, SM501State),
+ VMSTATE_UINT32(twoD_source, SM501State),
+ VMSTATE_UINT32(twoD_destination, SM501State),
+ VMSTATE_UINT32(twoD_dimension, SM501State),
+ VMSTATE_UINT32(twoD_control, SM501State),
+ VMSTATE_UINT32(twoD_pitch, SM501State),
+ VMSTATE_UINT32(twoD_foreground, SM501State),
+ VMSTATE_UINT32(twoD_background, SM501State),
+ VMSTATE_UINT32(twoD_stretch, SM501State),
+ VMSTATE_UINT32(twoD_color_compare, SM501State),
+ VMSTATE_UINT32(twoD_color_compare_mask, SM501State),
+ VMSTATE_UINT32(twoD_mask, SM501State),
+ VMSTATE_UINT32(twoD_clip_tl, SM501State),
+ VMSTATE_UINT32(twoD_clip_br, SM501State),
+ VMSTATE_UINT32(twoD_mono_pattern_low, SM501State),
+ VMSTATE_UINT32(twoD_mono_pattern_high, SM501State),
+ VMSTATE_UINT32(twoD_window_width, SM501State),
+ VMSTATE_UINT32(twoD_source_base, SM501State),
+ VMSTATE_UINT32(twoD_destination_base, SM501State),
+ VMSTATE_UINT32(twoD_alpha, SM501State),
+ VMSTATE_UINT32(twoD_wrap, SM501State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+#define TYPE_SYSBUS_SM501 "sysbus-sm501"
+#define SYSBUS_SM501(obj) \
+ OBJECT_CHECK(SM501SysBusState, (obj), TYPE_SYSBUS_SM501)
+
+typedef struct {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+ SM501State state;
+ uint32_t vram_size;
+ uint32_t base;
+ void *chr_state;
+} SM501SysBusState;
+
+static void sm501_realize_sysbus(DeviceState *dev, Error **errp)
+{
+ SM501SysBusState *s = SYSBUS_SM501(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ DeviceState *usb_dev;
+
+ sm501_init(&s->state, dev, s->vram_size);
+ if (get_local_mem_size(&s->state) != s->vram_size) {
+ error_setg(errp, "Invalid VRAM size, nearest valid size is %" PRIu32,
+ get_local_mem_size(&s->state));
+ return;
+ }
+ sysbus_init_mmio(sbd, &s->state.local_mem_region);
+ sysbus_init_mmio(sbd, &s->state.mmio_region);
/* bridge to usb host emulation module */
- dev = qdev_create(NULL, "sysbus-ohci");
- qdev_prop_set_uint32(dev, "num-ports", 2);
- qdev_prop_set_uint64(dev, "dma-offset", base);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0,
- base + MMIO_BASE_OFFSET + SM501_USB_HOST);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+ usb_dev = qdev_create(NULL, "sysbus-ohci");
+ qdev_prop_set_uint32(usb_dev, "num-ports", 2);
+ qdev_prop_set_uint64(usb_dev, "dma-offset", s->base);
+ qdev_init_nofail(usb_dev);
+ memory_region_add_subregion(&s->state.mmio_region, SM501_USB_HOST,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(usb_dev), 0));
+ sysbus_pass_irq(sbd, SYS_BUS_DEVICE(usb_dev));
/* bridge to serial emulation module */
- if (chr) {
- serial_mm_init(address_space_mem,
- base + MMIO_BASE_OFFSET + SM501_UART0, 2,
+ if (s->chr_state) {
+ serial_mm_init(&s->state.mmio_region, SM501_UART0, 2,
NULL, /* TODO : chain irq to IRL */
- 115200, chr, DEVICE_NATIVE_ENDIAN);
+ 115200, s->chr_state, DEVICE_LITTLE_ENDIAN);
}
+}
- /* create qemu graphic console */
- s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s);
+static Property sm501_sysbus_properties[] = {
+ DEFINE_PROP_UINT32("vram-size", SM501SysBusState, vram_size, 0),
+ DEFINE_PROP_UINT32("base", SM501SysBusState, base, 0),
+ DEFINE_PROP_PTR("chr-state", SM501SysBusState, chr_state),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sm501_reset_sysbus(DeviceState *dev)
+{
+ SM501SysBusState *s = SYSBUS_SM501(dev);
+ sm501_reset(&s->state);
}
+
+static const VMStateDescription vmstate_sm501_sysbus = {
+ .name = TYPE_SYSBUS_SM501,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(state, SM501SysBusState, 1,
+ vmstate_sm501_state, SM501State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void sm501_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = sm501_realize_sysbus;
+ set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
+ dc->desc = "SM501 Multimedia Companion";
+ dc->props = sm501_sysbus_properties;
+ dc->reset = sm501_reset_sysbus;
+ dc->vmsd = &vmstate_sm501_sysbus;
+ /* Note: pointer property "chr-state" may remain null, thus
+ * no need for dc->cannot_instantiate_with_device_add_yet = true;
+ */
+}
+
+static const TypeInfo sm501_sysbus_info = {
+ .name = TYPE_SYSBUS_SM501,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SM501SysBusState),
+ .class_init = sm501_sysbus_class_init,
+};
+
+#define TYPE_PCI_SM501 "sm501"
+#define PCI_SM501(obj) OBJECT_CHECK(SM501PCIState, (obj), TYPE_PCI_SM501)
+
+typedef struct {
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+ SM501State state;
+ uint32_t vram_size;
+} SM501PCIState;
+
+static void sm501_realize_pci(PCIDevice *dev, Error **errp)
+{
+ SM501PCIState *s = PCI_SM501(dev);
+
+ sm501_init(&s->state, DEVICE(dev), s->vram_size);
+ if (get_local_mem_size(&s->state) != s->vram_size) {
+ error_setg(errp, "Invalid VRAM size, nearest valid size is %" PRIu32,
+ get_local_mem_size(&s->state));
+ return;
+ }
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
+ &s->state.local_mem_region);
+ pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
+ &s->state.mmio_region);
+}
+
+static Property sm501_pci_properties[] = {
+ DEFINE_PROP_UINT32("vram-size", SM501PCIState, vram_size, 64 * M_BYTE),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sm501_reset_pci(DeviceState *dev)
+{
+ SM501PCIState *s = PCI_SM501(dev);
+ sm501_reset(&s->state);
+ /* Bits 2:0 of misc_control register is 001 for PCI */
+ s->state.misc_control |= 1;
+}
+
+static const VMStateDescription vmstate_sm501_pci = {
+ .name = TYPE_PCI_SM501,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(parent_obj, SM501PCIState),
+ VMSTATE_STRUCT(state, SM501PCIState, 1,
+ vmstate_sm501_state, SM501State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void sm501_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->realize = sm501_realize_pci;
+ k->vendor_id = PCI_VENDOR_ID_SILICON_MOTION;
+ k->device_id = PCI_DEVICE_ID_SM501;
+ k->class_id = PCI_CLASS_DISPLAY_OTHER;
+ set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
+ dc->desc = "SM501 Display Controller";
+ dc->props = sm501_pci_properties;
+ dc->reset = sm501_reset_pci;
+ dc->hotpluggable = false;
+ dc->vmsd = &vmstate_sm501_pci;
+}
+
+static const TypeInfo sm501_pci_info = {
+ .name = TYPE_PCI_SM501,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(SM501PCIState),
+ .class_init = sm501_pci_class_init,
+};
+
+static void sm501_register_types(void)
+{
+ type_register_static(&sm501_sysbus_info);
+ type_register_static(&sm501_pci_info);
+}
+
+type_init(sm501_register_types)
diff --git a/hw/display/sm501_template.h b/hw/display/sm501_template.h
index f33e499be4..a60abad019 100644
--- a/hw/display/sm501_template.h
+++ b/hw/display/sm501_template.h
@@ -47,81 +47,67 @@ static void glue(draw_line8_, PIXEL_NAME)(
{
uint8_t v, r, g, b;
do {
- v = ldub_p(s);
- r = (pal[v] >> 16) & 0xff;
- g = (pal[v] >> 8) & 0xff;
- b = (pal[v] >> 0) & 0xff;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- s ++;
- d += BPP;
- } while (-- width != 0);
+ v = ldub_p(s);
+ r = (pal[v] >> 16) & 0xff;
+ g = (pal[v] >> 8) & 0xff;
+ b = (pal[v] >> 0) & 0xff;
+ *(PIXEL_TYPE *)d = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+ s++;
+ d += BPP;
+ } while (--width != 0);
}
static void glue(draw_line16_, PIXEL_NAME)(
- uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
+ uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
{
uint16_t rgb565;
uint8_t r, g, b;
do {
- rgb565 = lduw_p(s);
- r = ((rgb565 >> 11) & 0x1f) << 3;
- g = ((rgb565 >> 5) & 0x3f) << 2;
- b = ((rgb565 >> 0) & 0x1f) << 3;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- s += 2;
- d += BPP;
- } while (-- width != 0);
+ rgb565 = lduw_le_p(s);
+ r = (rgb565 >> 8) & 0xf8;
+ g = (rgb565 >> 3) & 0xfc;
+ b = (rgb565 << 3) & 0xf8;
+ *(PIXEL_TYPE *)d = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+ s += 2;
+ d += BPP;
+ } while (--width != 0);
}
static void glue(draw_line32_, PIXEL_NAME)(
- uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
+ uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
{
uint8_t r, g, b;
do {
- ldub_p(s);
-#if defined(TARGET_WORDS_BIGENDIAN)
- r = s[1];
- g = s[2];
- b = s[3];
-#else
- b = s[0];
- g = s[1];
r = s[2];
-#endif
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- s += 4;
- d += BPP;
- } while (-- width != 0);
+ g = s[1];
+ b = s[0];
+ *(PIXEL_TYPE *)d = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+ s += 4;
+ d += BPP;
+ } while (--width != 0);
}
/**
* Draw hardware cursor image on the given line.
*/
-static void glue(draw_hwc_line_, PIXEL_NAME)(SM501State * s, int crt,
- uint8_t * palette, int c_y, uint8_t *d, int width)
+static void glue(draw_hwc_line_, PIXEL_NAME)(uint8_t *d, const uint8_t *s,
+ int width, const uint8_t *palette, int c_x, int c_y)
{
- int x, i;
- uint8_t bitset = 0;
-
- /* get hardware cursor pattern */
- uint32_t cursor_addr = get_hwc_address(s, crt);
- assert(0 <= c_y && c_y < SM501_HWC_HEIGHT);
- cursor_addr += 64 * c_y / 4; /* 4 pixels per byte */
- cursor_addr += s->base;
+ int i;
+ uint8_t r, g, b, v, bitset = 0;
/* get cursor position */
- x = get_hwc_x(s, crt);
- d += x * BPP;
-
- for (i = 0; i < SM501_HWC_WIDTH && x + i < width; i++) {
- uint8_t v;
+ assert(0 <= c_y && c_y < SM501_HWC_HEIGHT);
+ s += SM501_HWC_WIDTH * c_y / 4; /* 4 pixels per byte */
+ d += c_x * BPP;
+ for (i = 0; i < SM501_HWC_WIDTH && c_x + i < width; i++) {
/* get pixel value */
if (i % 4 == 0) {
- bitset = ldub_phys(&address_space_memory, cursor_addr);
- cursor_addr++;
+ bitset = ldub_p(s);
+ s++;
}
v = bitset & 3;
bitset >>= 2;
@@ -129,10 +115,10 @@ static void glue(draw_hwc_line_, PIXEL_NAME)(SM501State * s, int crt,
/* write pixel */
if (v) {
v--;
- uint8_t r = palette[v * 3 + 0];
- uint8_t g = palette[v * 3 + 1];
- uint8_t b = palette[v * 3 + 2];
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+ r = palette[v * 3 + 0];
+ g = palette[v * 3 + 1];
+ b = palette[v * 3 + 2];
+ *(PIXEL_TYPE *)d = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
}
d += BPP;
}
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index 8e26aae801..5a1115cc65 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -25,7 +25,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu-common.h"
-#include "cpu.h" /* FIXME shouldn't use TARGET_PAGE_SIZE */
#include "ui/console.h"
#include "ui/pixel_ops.h"
#include "hw/loader.h"
@@ -93,41 +92,46 @@ typedef struct TCXState {
uint16_t cursy;
} TCXState;
-static void tcx_set_dirty(TCXState *s)
+static void tcx_set_dirty(TCXState *s, ram_addr_t addr, int len)
{
- memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY);
+ memory_region_set_dirty(&s->vram_mem, addr, len);
+
+ if (s->depth == 24) {
+ memory_region_set_dirty(&s->vram_mem, s->vram24_offset + addr * 4,
+ len * 4);
+ memory_region_set_dirty(&s->vram_mem, s->cplane_offset + addr * 4,
+ len * 4);
+ }
}
-static inline int tcx24_check_dirty(TCXState *s, ram_addr_t page,
- ram_addr_t page24, ram_addr_t cpage)
+static int tcx_check_dirty(TCXState *s, ram_addr_t addr, int len)
{
int ret;
- ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
- ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4,
- DIRTY_MEMORY_VGA);
- ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4,
- DIRTY_MEMORY_VGA);
+ ret = memory_region_get_dirty(&s->vram_mem, addr, len, DIRTY_MEMORY_VGA);
+
+ if (s->depth == 24) {
+ ret |= memory_region_get_dirty(&s->vram_mem,
+ s->vram24_offset + addr * 4, len * 4,
+ DIRTY_MEMORY_VGA);
+ ret |= memory_region_get_dirty(&s->vram_mem,
+ s->cplane_offset + addr * 4, len * 4,
+ DIRTY_MEMORY_VGA);
+ }
+
return ret;
}
-static inline void tcx24_reset_dirty(TCXState *ts, ram_addr_t page_min,
- ram_addr_t page_max, ram_addr_t page24,
- ram_addr_t cpage)
+static void tcx_reset_dirty(TCXState *s, ram_addr_t addr, int len)
{
- memory_region_reset_dirty(&ts->vram_mem,
- page_min,
- (page_max - page_min) + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
- memory_region_reset_dirty(&ts->vram_mem,
- page24 + page_min * 4,
- (page_max - page_min) * 4 + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
- memory_region_reset_dirty(&ts->vram_mem,
- cpage + page_min * 4,
- (page_max - page_min) * 4 + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
+ memory_region_reset_dirty(&s->vram_mem, addr, len, DIRTY_MEMORY_VGA);
+
+ if (s->depth == 24) {
+ memory_region_reset_dirty(&s->vram_mem, s->vram24_offset + addr * 4,
+ len * 4, DIRTY_MEMORY_VGA);
+ memory_region_reset_dirty(&s->vram_mem, s->cplane_offset + addr * 4,
+ len * 4, DIRTY_MEMORY_VGA);
+ }
}
static void update_palette_entries(TCXState *s, int start, int end)
@@ -136,27 +140,14 @@ static void update_palette_entries(TCXState *s, int start, int end)
int i;
for (i = start; i < end; i++) {
- switch (surface_bits_per_pixel(surface)) {
- default:
- case 8:
- s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
- break;
- case 15:
- s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
- break;
- case 16:
- s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
- break;
- case 32:
- if (is_surface_bgr(surface)) {
- s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
- } else {
- s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
- }
- break;
+ if (is_surface_bgr(surface)) {
+ s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
+ } else {
+ s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
}
+ break;
}
- tcx_set_dirty(s);
+ tcx_set_dirty(s, 0, memory_region_size(&s->vram_mem));
}
static void tcx_draw_line32(TCXState *s1, uint8_t *d,
@@ -172,31 +163,6 @@ static void tcx_draw_line32(TCXState *s1, uint8_t *d,
}
}
-static void tcx_draw_line16(TCXState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int x;
- uint8_t val;
- uint16_t *p = (uint16_t *)d;
-
- for (x = 0; x < width; x++) {
- val = *s++;
- *p++ = s1->palette[val];
- }
-}
-
-static void tcx_draw_line8(TCXState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int x;
- uint8_t val;
-
- for(x = 0; x < width; x++) {
- val = *s++;
- *d++ = s1->palette[val];
- }
-}
-
static void tcx_draw_cursor32(TCXState *s1, uint8_t *d,
int y, int width)
{
@@ -223,57 +189,6 @@ static void tcx_draw_cursor32(TCXState *s1, uint8_t *d,
}
}
-static void tcx_draw_cursor16(TCXState *s1, uint8_t *d,
- int y, int width)
-{
- int x, len;
- uint32_t mask, bits;
- uint16_t *p = (uint16_t *)d;
-
- y = y - s1->cursy;
- mask = s1->cursmask[y];
- bits = s1->cursbits[y];
- len = MIN(width - s1->cursx, 32);
- p = &p[s1->cursx];
- for (x = 0; x < len; x++) {
- if (mask & 0x80000000) {
- if (bits & 0x80000000) {
- *p = s1->palette[259];
- } else {
- *p = s1->palette[258];
- }
- }
- p++;
- mask <<= 1;
- bits <<= 1;
- }
-}
-
-static void tcx_draw_cursor8(TCXState *s1, uint8_t *d,
- int y, int width)
-{
- int x, len;
- uint32_t mask, bits;
-
- y = y - s1->cursy;
- mask = s1->cursmask[y];
- bits = s1->cursbits[y];
- len = MIN(width - s1->cursx, 32);
- d = &d[s1->cursx];
- for (x = 0; x < len; x++) {
- if (mask & 0x80000000) {
- if (bits & 0x80000000) {
- *d = s1->palette[259];
- } else {
- *d = s1->palette[258];
- }
- }
- d++;
- mask <<= 1;
- bits <<= 1;
- }
-}
-
/*
XXX Could be much more optimal:
* detect if line/page/whole screen is in 24 bit mode
@@ -322,10 +237,8 @@ static void tcx_update_display(void *opaque)
ram_addr_t page, page_min, page_max;
int y, y_start, dd, ds;
uint8_t *d, *s;
- void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
- void (*fc)(TCXState *s1, uint8_t *dst, int y, int width);
- if (surface_bits_per_pixel(surface) == 0) {
+ if (surface_bits_per_pixel(surface) != 32) {
return;
}
@@ -338,29 +251,9 @@ static void tcx_update_display(void *opaque)
dd = surface_stride(surface);
ds = 1024;
- switch (surface_bits_per_pixel(surface)) {
- case 32:
- f = tcx_draw_line32;
- fc = tcx_draw_cursor32;
- break;
- case 15:
- case 16:
- f = tcx_draw_line16;
- fc = tcx_draw_cursor16;
- break;
- default:
- case 8:
- f = tcx_draw_line8;
- fc = tcx_draw_cursor8;
- break;
- case 0:
- return;
- }
-
memory_region_sync_dirty_bitmap(&ts->vram_mem);
- for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE) {
- if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA)) {
+ for (y = 0; y < ts->height; y++, page += ds) {
+ if (tcx_check_dirty(ts, page, ds)) {
if (y_start < 0)
y_start = y;
if (page < page_min)
@@ -368,37 +261,10 @@ static void tcx_update_display(void *opaque)
if (page > page_max)
page_max = page;
- f(ts, d, s, ts->width);
- if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) {
- fc(ts, d, y, ts->width);
- }
- d += dd;
- s += ds;
- y++;
-
- f(ts, d, s, ts->width);
- if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) {
- fc(ts, d, y, ts->width);
- }
- d += dd;
- s += ds;
- y++;
-
- f(ts, d, s, ts->width);
- if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) {
- fc(ts, d, y, ts->width);
- }
- d += dd;
- s += ds;
- y++;
-
- f(ts, d, s, ts->width);
+ tcx_draw_line32(ts, d, s, ts->width);
if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) {
- fc(ts, d, y, ts->width);
+ tcx_draw_cursor32(ts, d, y, ts->width);
}
- d += dd;
- s += ds;
- y++;
} else {
if (y_start >= 0) {
/* flush to display */
@@ -406,10 +272,9 @@ static void tcx_update_display(void *opaque)
ts->width, y - y_start);
y_start = -1;
}
- d += dd * 4;
- s += ds * 4;
- y += 4;
}
+ s += ds;
+ d += dd;
}
if (y_start >= 0) {
/* flush to display */
@@ -418,10 +283,7 @@ static void tcx_update_display(void *opaque)
}
/* reset modified pages */
if (page_max >= page_min) {
- memory_region_reset_dirty(&ts->vram_mem,
- page_min,
- (page_max - page_min) + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
+ tcx_reset_dirty(ts, page_min, page_max - page_min);
}
}
@@ -429,7 +291,7 @@ static void tcx24_update_display(void *opaque)
{
TCXState *ts = opaque;
DisplaySurface *surface = qemu_console_surface(ts->con);
- ram_addr_t page, page_min, page_max, cpage, page24;
+ ram_addr_t page, page_min, page_max;
int y, y_start, dd, ds;
uint8_t *d, *s;
uint32_t *cptr, *s24;
@@ -439,8 +301,6 @@ static void tcx24_update_display(void *opaque)
}
page = 0;
- page24 = ts->vram24_offset;
- cpage = ts->cplane_offset;
y_start = -1;
page_min = -1;
page_max = 0;
@@ -452,9 +312,8 @@ static void tcx24_update_display(void *opaque)
ds = 1024;
memory_region_sync_dirty_bitmap(&ts->vram_mem);
- for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE,
- page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
- if (tcx24_check_dirty(ts, page, page24, cpage)) {
+ for (y = 0; y < ts->height; y++, page += ds) {
+ if (tcx_check_dirty(ts, page, ds)) {
if (y_start < 0)
y_start = y;
if (page < page_min)
@@ -465,38 +324,6 @@ static void tcx24_update_display(void *opaque)
if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) {
tcx_draw_cursor32(ts, d, y, ts->width);
}
- d += dd;
- s += ds;
- cptr += ds;
- s24 += ds;
- y++;
- tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
- if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) {
- tcx_draw_cursor32(ts, d, y, ts->width);
- }
- d += dd;
- s += ds;
- cptr += ds;
- s24 += ds;
- y++;
- tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
- if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) {
- tcx_draw_cursor32(ts, d, y, ts->width);
- }
- d += dd;
- s += ds;
- cptr += ds;
- s24 += ds;
- y++;
- tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
- if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) {
- tcx_draw_cursor32(ts, d, y, ts->width);
- }
- d += dd;
- s += ds;
- cptr += ds;
- s24 += ds;
- y++;
} else {
if (y_start >= 0) {
/* flush to display */
@@ -504,12 +331,11 @@ static void tcx24_update_display(void *opaque)
ts->width, y - y_start);
y_start = -1;
}
- d += dd * 4;
- s += ds * 4;
- cptr += ds * 4;
- s24 += ds * 4;
- y += 4;
}
+ d += dd;
+ s += ds;
+ cptr += ds;
+ s24 += ds;
}
if (y_start >= 0) {
/* flush to display */
@@ -518,7 +344,7 @@ static void tcx24_update_display(void *opaque)
}
/* reset modified pages */
if (page_max >= page_min) {
- tcx24_reset_dirty(ts, page_min, page_max, page24, cpage);
+ tcx_reset_dirty(ts, page_min, page_max - page_min);
}
}
@@ -526,7 +352,7 @@ static void tcx_invalidate_display(void *opaque)
{
TCXState *s = opaque;
- tcx_set_dirty(s);
+ tcx_set_dirty(s, 0, memory_region_size(&s->vram_mem));
qemu_console_resize(s->con, s->width, s->height);
}
@@ -534,7 +360,7 @@ static void tcx24_invalidate_display(void *opaque)
{
TCXState *s = opaque;
- tcx_set_dirty(s);
+ tcx_set_dirty(s, 0, memory_region_size(&s->vram_mem));
qemu_console_resize(s->con, s->width, s->height);
}
@@ -543,7 +369,7 @@ static int vmstate_tcx_post_load(void *opaque, int version_id)
TCXState *s = opaque;
update_palette_entries(s, 0, 256);
- tcx_set_dirty(s);
+ tcx_set_dirty(s, 0, memory_region_size(&s->vram_mem));
return 0;
}
@@ -699,7 +525,7 @@ static void tcx_stip_writel(void *opaque, hwaddr addr,
val <<= 1;
}
}
- memory_region_set_dirty(&s->vram_mem, addr, 32);
+ tcx_set_dirty(s, addr, 32);
}
}
@@ -732,7 +558,7 @@ static void tcx_rstip_writel(void *opaque, hwaddr addr,
val <<= 1;
}
}
- memory_region_set_dirty(&s->vram_mem, addr, 32);
+ tcx_set_dirty(s, addr, 32);
}
}
@@ -790,7 +616,7 @@ static void tcx_blit_writel(void *opaque, hwaddr addr,
memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4);
}
}
- memory_region_set_dirty(&s->vram_mem, addr, len);
+ tcx_set_dirty(s, addr, len);
}
}
@@ -824,7 +650,7 @@ static void tcx_rblit_writel(void *opaque, hwaddr addr,
memcpy(&s->cplane[addr], &s->cplane[adsr], len * 4);
}
}
- memory_region_set_dirty(&s->vram_mem, addr, len);
+ tcx_set_dirty(s, addr, len);
}
}
@@ -861,7 +687,7 @@ static void tcx_invalidate_cursor_position(TCXState *s)
start = ymin * 1024;
end = ymax * 1024;
- memory_region_set_dirty(&s->vram_mem, start, end-start);
+ tcx_set_dirty(s, start, end - start);
}
static uint64_t tcx_thc_readl(void *opaque, hwaddr addr,
@@ -1017,8 +843,7 @@ static void tcx_realizefn(DeviceState *dev, Error **errp)
vmstate_register_ram_global(&s->rom);
fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, TCX_ROM_FILE);
if (fcode_filename) {
- ret = load_image_targphys(fcode_filename, s->prom_addr,
- FCODE_MAX_ROM_SIZE);
+ 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);
@@ -1076,7 +901,6 @@ static Property tcx_properties[] = {
DEFINE_PROP_UINT16("width", TCXState, width, -1),
DEFINE_PROP_UINT16("height", TCXState, height, -1),
DEFINE_PROP_UINT16("depth", TCXState, depth, -1),
- DEFINE_PROP_UINT64("prom_addr", TCXState, prom_addr, -1),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 69c3e1d674..b2516c8d21 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1434,6 +1434,14 @@ void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
}
}
+static bool vga_scanline_invalidated(VGACommonState *s, int y)
+{
+ if (y >= VGA_MAX_HEIGHT) {
+ return false;
+ }
+ return s->invalidated_y_table[y >> 5] & (1 << (y & 0x1f));
+}
+
void vga_sync_dirty_bitmap(VGACommonState *s)
{
memory_region_sync_dirty_bitmap(&s->vram);
@@ -1457,7 +1465,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
DisplaySurface *surface = qemu_console_surface(s->con);
int y1, y, update, linesize, y_start, double_scan, mask, depth;
int width, height, shift_control, line_offset, bwidth, bits;
- ram_addr_t page0, page1, page_min, page_max;
+ ram_addr_t page0, page1;
+ DirtyBitmapSnapshot *snap = NULL;
int disp_width, multi_scan, multi_run;
uint8_t *d;
uint32_t v, addr1, addr;
@@ -1472,9 +1481,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
full_update |= update_basic_params(s);
- if (!full_update)
- vga_sync_dirty_bitmap(s);
-
s->get_resolution(s, &width, &height);
disp_width = width;
@@ -1617,11 +1623,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
addr1 = (s->start_addr * 4);
bwidth = (width * bits + 7) / 8;
y_start = -1;
- page_min = -1;
- page_max = 0;
d = surface_data(surface);
linesize = surface_stride(surface);
y1 = 0;
+
+ if (!full_update) {
+ vga_sync_dirty_bitmap(s);
+ snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1,
+ bwidth * height,
+ DIRTY_MEMORY_VGA);
+ }
+
for(y = 0; y < height; y++) {
addr = addr1;
if (!(s->cr[VGA_CRTC_MODE] & 1)) {
@@ -1636,17 +1648,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
update = full_update;
page0 = addr;
page1 = addr + bwidth - 1;
- update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
- DIRTY_MEMORY_VGA);
- /* explicit invalidation for the hardware cursor */
- update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
+ if (full_update) {
+ update = 1;
+ } else {
+ update = memory_region_snapshot_get_dirty(&s->vram, snap,
+ page0, page1 - page0);
+ }
+ /* explicit invalidation for the hardware cursor (cirrus only) */
+ update |= vga_scanline_invalidated(s, y);
if (update) {
if (y_start < 0)
y_start = y;
- if (page0 < page_min)
- page_min = page0;
- if (page1 > page_max)
- page_max = page1;
if (!(is_buffer_shared(surface))) {
vga_draw_line(s, d, s->vram_ptr + addr, width);
if (s->cursor_draw_line)
@@ -1679,14 +1691,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
dpy_gfx_update(s->con, 0, y_start,
disp_width, y - y_start);
}
- /* reset modified pages */
- if (page_max >= page_min) {
- memory_region_reset_dirty(&s->vram,
- page_min,
- page_max - page_min,
- DIRTY_MEMORY_VGA);
- }
- memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
+ g_free(snap);
+ memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table));
}
static void vga_draw_blank(VGACommonState *s, int full_update)
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 9b530ab5b0..e1056f34df 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -258,41 +258,22 @@ void virtio_gpu_get_display_info(VirtIOGPU *g,
static pixman_format_code_t get_pixman_format(uint32_t virtio_gpu_format)
{
switch (virtio_gpu_format) {
-#ifdef HOST_WORDS_BIGENDIAN
case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM:
- return PIXMAN_b8g8r8x8;
+ return PIXMAN_BE_b8g8r8x8;
case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM:
- return PIXMAN_b8g8r8a8;
+ return PIXMAN_BE_b8g8r8a8;
case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM:
- return PIXMAN_x8r8g8b8;
+ return PIXMAN_BE_x8r8g8b8;
case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
- return PIXMAN_a8r8g8b8;
+ return PIXMAN_BE_a8r8g8b8;
case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
- return PIXMAN_r8g8b8x8;
+ return PIXMAN_BE_r8g8b8x8;
case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM:
- return PIXMAN_r8g8b8a8;
+ return PIXMAN_BE_r8g8b8a8;
case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM:
- return PIXMAN_x8b8g8r8;
+ return PIXMAN_BE_x8b8g8r8;
case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
- return PIXMAN_a8b8g8r8;
-#else
- case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM:
- return PIXMAN_x8r8g8b8;
- case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM:
- return PIXMAN_a8r8g8b8;
- case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM:
- return PIXMAN_b8g8r8x8;
- case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
- return PIXMAN_b8g8r8a8;
- case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
- return PIXMAN_x8b8g8r8;
- case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM:
- return PIXMAN_a8b8g8r8;
- case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM:
- return PIXMAN_r8g8b8x8;
- case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
- return PIXMAN_r8g8b8a8;
-#endif
+ return PIXMAN_BE_a8b8g8r8;
default:
return 0;
}
@@ -1170,8 +1151,8 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
g->config_size);
- g->req_state[0].width = 1024;
- g->req_state[0].height = 768;
+ g->req_state[0].width = g->conf.xres;
+ g->req_state[0].height = g->conf.yres;
if (virtio_gpu_virgl_enabled(g->conf)) {
/* use larger control queue in 3d mode */
@@ -1291,6 +1272,8 @@ static Property virtio_gpu_properties[] = {
DEFINE_PROP_BIT("stats", VirtIOGPU, conf.flags,
VIRTIO_GPU_FLAG_STATS_ENABLED, false),
#endif
+ DEFINE_PROP_UINT32("xres", VirtIOGPU, conf.xres, 1024),
+ DEFINE_PROP_UINT32("yres", VirtIOGPU, conf.yres, 768),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 6599cf078d..ec5f27d67e 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -1118,9 +1118,9 @@ static void vmsvga_update_display(void *opaque)
{
struct vmsvga_state_s *s = opaque;
DisplaySurface *surface;
- bool dirty = false;
- if (!s->enable) {
+ if (!s->enable || !s->config) {
+ /* in standard vga mode */
s->vga.hw_ops->gfx_update(&s->vga);
return;
}
@@ -1131,26 +1131,11 @@ static void vmsvga_update_display(void *opaque)
vmsvga_fifo_run(s);
vmsvga_update_rect_flush(s);
- /*
- * Is it more efficient to look at vram VGA-dirty bits or wait
- * for the driver to issue SVGA_CMD_UPDATE?
- */
- if (memory_region_is_logging(&s->vga.vram, DIRTY_MEMORY_VGA)) {
- vga_sync_dirty_bitmap(&s->vga);
- dirty = memory_region_get_dirty(&s->vga.vram, 0,
- surface_stride(surface) * surface_height(surface),
- DIRTY_MEMORY_VGA);
- }
- if (s->invalidated || dirty) {
+ if (s->invalidated) {
s->invalidated = 0;
dpy_gfx_update(s->vga.con, 0, 0,
surface_width(surface), surface_height(surface));
}
- if (dirty) {
- memory_region_reset_dirty(&s->vga.vram, 0,
- surface_stride(surface) * surface_height(surface),
- DIRTY_MEMORY_VGA);
- }
}
static void vmsvga_reset(DeviceState *dev)
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index e0732ccaf1..f86a40aa30 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -572,8 +572,7 @@ static uint64_t amdvi_mmio_read(void *opaque, hwaddr addr, unsigned size)
uint64_t val = -1;
if (addr + size > AMDVI_MMIO_SIZE) {
- trace_amdvi_mmio_read("error: addr outside region: max ",
- (uint64_t)AMDVI_MMIO_SIZE, addr, size);
+ trace_amdvi_mmio_read_invalid(AMDVI_MMIO_SIZE, addr, size);
return (uint64_t)-1;
}
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 22d8226e43..02f047c8e3 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -595,6 +595,22 @@ static inline uint32_t vtd_get_agaw_from_context_entry(VTDContextEntry *ce)
return 30 + (ce->hi & VTD_CONTEXT_ENTRY_AW) * 9;
}
+static inline uint64_t vtd_iova_limit(VTDContextEntry *ce)
+{
+ uint32_t ce_agaw = vtd_get_agaw_from_context_entry(ce);
+ return 1ULL << MIN(ce_agaw, VTD_MGAW);
+}
+
+/* Return true if IOVA passes range check, otherwise false. */
+static inline bool vtd_iova_range_check(uint64_t iova, VTDContextEntry *ce)
+{
+ /*
+ * Check if @iova is above 2^X-1, where X is the minimum of MGAW
+ * in CAP_REG and AW in context-entry.
+ */
+ return !(iova & ~(vtd_iova_limit(ce) - 1));
+}
+
static const uint64_t vtd_paging_entry_rsvd_field[] = {
[0] = ~0ULL,
/* For not large page */
@@ -630,13 +646,9 @@ static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write,
uint32_t level = vtd_get_level_from_context_entry(ce);
uint32_t offset;
uint64_t slpte;
- uint32_t ce_agaw = vtd_get_agaw_from_context_entry(ce);
uint64_t access_right_check;
- /* Check if @iova is above 2^X-1, where X is the minimum of MGAW
- * in CAP_REG and AW in context-entry.
- */
- if (iova & ~((1ULL << MIN(ce_agaw, VTD_MGAW)) - 1)) {
+ if (!vtd_iova_range_check(iova, ce)) {
VTD_DPRINTF(GENERAL, "error: iova 0x%"PRIx64 " exceeds limits", iova);
return -VTD_FR_ADDR_BEYOND_MGAW;
}
@@ -684,6 +696,135 @@ static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write,
}
}
+typedef int (*vtd_page_walk_hook)(IOMMUTLBEntry *entry, void *private);
+
+/**
+ * vtd_page_walk_level - walk over specific level for IOVA range
+ *
+ * @addr: base GPA addr to start the walk
+ * @start: IOVA range start address
+ * @end: IOVA range end address (start <= addr < end)
+ * @hook_fn: hook func to be called when detected page
+ * @private: private data to be passed into hook func
+ * @read: whether parent level has read permission
+ * @write: whether parent level has write permission
+ * @notify_unmap: whether we should notify invalid entries
+ */
+static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
+ uint64_t end, vtd_page_walk_hook hook_fn,
+ void *private, uint32_t level,
+ bool read, bool write, bool notify_unmap)
+{
+ bool read_cur, write_cur, entry_valid;
+ uint32_t offset;
+ uint64_t slpte;
+ uint64_t subpage_size, subpage_mask;
+ IOMMUTLBEntry entry;
+ uint64_t iova = start;
+ uint64_t iova_next;
+ int ret = 0;
+
+ trace_vtd_page_walk_level(addr, level, start, end);
+
+ subpage_size = 1ULL << vtd_slpt_level_shift(level);
+ subpage_mask = vtd_slpt_level_page_mask(level);
+
+ while (iova < end) {
+ iova_next = (iova & subpage_mask) + subpage_size;
+
+ offset = vtd_iova_level_offset(iova, level);
+ slpte = vtd_get_slpte(addr, offset);
+
+ if (slpte == (uint64_t)-1) {
+ trace_vtd_page_walk_skip_read(iova, iova_next);
+ goto next;
+ }
+
+ if (vtd_slpte_nonzero_rsvd(slpte, level)) {
+ trace_vtd_page_walk_skip_reserve(iova, iova_next);
+ goto next;
+ }
+
+ /* Permissions are stacked with parents' */
+ read_cur = read && (slpte & VTD_SL_R);
+ write_cur = write && (slpte & VTD_SL_W);
+
+ /*
+ * As long as we have either read/write permission, this is a
+ * valid entry. The rule works for both page entries and page
+ * table entries.
+ */
+ entry_valid = read_cur | write_cur;
+
+ if (vtd_is_last_slpte(slpte, level)) {
+ entry.target_as = &address_space_memory;
+ entry.iova = iova & subpage_mask;
+ /* NOTE: this is only meaningful if entry_valid == true */
+ entry.translated_addr = vtd_get_slpte_addr(slpte);
+ entry.addr_mask = ~subpage_mask;
+ entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur);
+ if (!entry_valid && !notify_unmap) {
+ trace_vtd_page_walk_skip_perm(iova, iova_next);
+ goto next;
+ }
+ trace_vtd_page_walk_one(level, entry.iova, entry.translated_addr,
+ entry.addr_mask, entry.perm);
+ if (hook_fn) {
+ ret = hook_fn(&entry, private);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ } else {
+ if (!entry_valid) {
+ trace_vtd_page_walk_skip_perm(iova, iova_next);
+ goto next;
+ }
+ ret = vtd_page_walk_level(vtd_get_slpte_addr(slpte), iova,
+ MIN(iova_next, end), hook_fn, private,
+ level - 1, read_cur, write_cur,
+ notify_unmap);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+next:
+ iova = iova_next;
+ }
+
+ return 0;
+}
+
+/**
+ * vtd_page_walk - walk specific IOVA range, and call the hook
+ *
+ * @ce: context entry to walk upon
+ * @start: IOVA address to start the walk
+ * @end: IOVA range end address (start <= addr < end)
+ * @hook_fn: the hook that to be called for each detected area
+ * @private: private data for the hook function
+ */
+static int vtd_page_walk(VTDContextEntry *ce, uint64_t start, uint64_t end,
+ vtd_page_walk_hook hook_fn, void *private,
+ bool notify_unmap)
+{
+ dma_addr_t addr = vtd_get_slpt_base_from_context(ce);
+ uint32_t level = vtd_get_level_from_context_entry(ce);
+
+ if (!vtd_iova_range_check(start, ce)) {
+ return -VTD_FR_ADDR_BEYOND_MGAW;
+ }
+
+ if (!vtd_iova_range_check(end, ce)) {
+ /* Fix end so that it reaches the maximum */
+ end = vtd_iova_limit(ce);
+ }
+
+ return vtd_page_walk_level(addr, start, end, hook_fn, private,
+ level, true, true, notify_unmap);
+}
+
/* Map a device to its corresponding domain (context-entry) */
static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
uint8_t devfn, VTDContextEntry *ce)
@@ -898,6 +1039,15 @@ static void vtd_interrupt_remap_table_setup(IntelIOMMUState *s)
s->intr_root, s->intr_size);
}
+static void vtd_iommu_replay_all(IntelIOMMUState *s)
+{
+ IntelIOMMUNotifierNode *node;
+
+ QLIST_FOREACH(node, &s->notifiers_list, next) {
+ memory_region_iommu_replay_all(&node->vtd_as->iommu);
+ }
+}
+
static void vtd_context_global_invalidate(IntelIOMMUState *s)
{
trace_vtd_inv_desc_cc_global();
@@ -905,6 +1055,14 @@ static void vtd_context_global_invalidate(IntelIOMMUState *s)
if (s->context_cache_gen == VTD_CONTEXT_CACHE_GEN_MAX) {
vtd_reset_context_cache(s);
}
+ /*
+ * From VT-d spec 6.5.2.1, a global context entry invalidation
+ * should be followed by a IOTLB global invalidation, so we should
+ * be safe even without this. Hoewever, let's replay the region as
+ * well to be safer, and go back here when we need finer tunes for
+ * VT-d emulation codes.
+ */
+ vtd_iommu_replay_all(s);
}
@@ -971,6 +1129,16 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s,
trace_vtd_inv_desc_cc_device(bus_n, VTD_PCI_SLOT(devfn_it),
VTD_PCI_FUNC(devfn_it));
vtd_as->context_cache_entry.context_cache_gen = 0;
+ /*
+ * So a device is moving out of (or moving into) a
+ * domain, a replay() suites here to notify all the
+ * IOMMU_NOTIFIER_MAP registers about this change.
+ * This won't bring bad even if we have no such
+ * notifier registered - the IOMMU notification
+ * framework will skip MAP notifications if that
+ * happened.
+ */
+ memory_region_iommu_replay_all(&vtd_as->iommu);
}
}
}
@@ -1012,12 +1180,53 @@ static void vtd_iotlb_global_invalidate(IntelIOMMUState *s)
{
trace_vtd_iotlb_reset("global invalidation recved");
vtd_reset_iotlb(s);
+ vtd_iommu_replay_all(s);
}
static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id)
{
+ IntelIOMMUNotifierNode *node;
+ VTDContextEntry ce;
+ VTDAddressSpace *vtd_as;
+
g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_domain,
&domain_id);
+
+ QLIST_FOREACH(node, &s->notifiers_list, next) {
+ vtd_as = node->vtd_as;
+ if (!vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus),
+ vtd_as->devfn, &ce) &&
+ domain_id == VTD_CONTEXT_ENTRY_DID(ce.hi)) {
+ memory_region_iommu_replay_all(&vtd_as->iommu);
+ }
+ }
+}
+
+static int vtd_page_invalidate_notify_hook(IOMMUTLBEntry *entry,
+ void *private)
+{
+ memory_region_notify_iommu((MemoryRegion *)private, *entry);
+ return 0;
+}
+
+static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s,
+ uint16_t domain_id, hwaddr addr,
+ uint8_t am)
+{
+ IntelIOMMUNotifierNode *node;
+ VTDContextEntry ce;
+ int ret;
+
+ QLIST_FOREACH(node, &(s->notifiers_list), next) {
+ VTDAddressSpace *vtd_as = node->vtd_as;
+ ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus),
+ vtd_as->devfn, &ce);
+ if (!ret && domain_id == VTD_CONTEXT_ENTRY_DID(ce.hi)) {
+ vtd_page_walk(&ce, addr, addr + (1 << am) * VTD_PAGE_SIZE,
+ vtd_page_invalidate_notify_hook,
+ (void *)&vtd_as->iommu, true);
+ }
+ }
}
static void vtd_iotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id,
@@ -1030,6 +1239,7 @@ static void vtd_iotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id,
info.addr = addr;
info.mask = ~((1 << am) - 1);
g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_page, &info);
+ vtd_iotlb_page_invalidate_notify(s, domain_id, addr, am);
}
/* Flush IOTLB
@@ -1151,9 +1361,49 @@ static void vtd_handle_gcmd_sirtp(IntelIOMMUState *s)
vtd_set_clear_mask_long(s, DMAR_GSTS_REG, 0, VTD_GSTS_IRTPS);
}
+static void vtd_switch_address_space(VTDAddressSpace *as)
+{
+ assert(as);
+
+ trace_vtd_switch_address_space(pci_bus_num(as->bus),
+ VTD_PCI_SLOT(as->devfn),
+ VTD_PCI_FUNC(as->devfn),
+ as->iommu_state->dmar_enabled);
+
+ /* Turn off first then on the other */
+ if (as->iommu_state->dmar_enabled) {
+ memory_region_set_enabled(&as->sys_alias, false);
+ memory_region_set_enabled(&as->iommu, true);
+ } else {
+ memory_region_set_enabled(&as->iommu, false);
+ memory_region_set_enabled(&as->sys_alias, true);
+ }
+}
+
+static void vtd_switch_address_space_all(IntelIOMMUState *s)
+{
+ GHashTableIter iter;
+ VTDBus *vtd_bus;
+ int i;
+
+ g_hash_table_iter_init(&iter, s->vtd_as_by_busptr);
+ while (g_hash_table_iter_next(&iter, NULL, (void **)&vtd_bus)) {
+ for (i = 0; i < X86_IOMMU_PCI_DEVFN_MAX; i++) {
+ if (!vtd_bus->dev_as[i]) {
+ continue;
+ }
+ vtd_switch_address_space(vtd_bus->dev_as[i]);
+ }
+ }
+}
+
/* Handle Translation Enable/Disable */
static void vtd_handle_gcmd_te(IntelIOMMUState *s, bool en)
{
+ if (s->dmar_enabled == en) {
+ return;
+ }
+
VTD_DPRINTF(CSR, "Translation Enable %s", (en ? "on" : "off"));
if (en) {
@@ -1168,6 +1418,8 @@ static void vtd_handle_gcmd_te(IntelIOMMUState *s, bool en)
/* Ok - report back to driver */
vtd_set_clear_mask_long(s, DMAR_GSTS_REG, VTD_GSTS_TES, 0);
}
+
+ vtd_switch_address_space_all(s);
}
/* Handle Interrupt Remap Enable/Disable */
@@ -1457,7 +1709,7 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
entry.iova = addr;
entry.perm = IOMMU_NONE;
entry.translated_addr = 0;
- memory_region_notify_iommu(entry.target_as->root, entry);
+ memory_region_notify_iommu(&vtd_dev_as->iommu, entry);
done:
return true;
@@ -2005,15 +2257,33 @@ static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu,
IOMMUNotifierFlag new)
{
VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
+ IntelIOMMUState *s = vtd_as->iommu_state;
+ IntelIOMMUNotifierNode *node = NULL;
+ IntelIOMMUNotifierNode *next_node = NULL;
- if (new & IOMMU_NOTIFIER_MAP) {
- error_report("Device at bus %s addr %02x.%d requires iommu "
- "notifier which is currently not supported by "
- "intel-iommu emulation",
- vtd_as->bus->qbus.name, PCI_SLOT(vtd_as->devfn),
- PCI_FUNC(vtd_as->devfn));
+ if (!s->caching_mode && new & IOMMU_NOTIFIER_MAP) {
+ error_report("We need to set cache_mode=1 for intel-iommu to enable "
+ "device assignment with IOMMU protection.");
exit(1);
}
+
+ if (old == IOMMU_NOTIFIER_NONE) {
+ node = g_malloc0(sizeof(*node));
+ node->vtd_as = vtd_as;
+ QLIST_INSERT_HEAD(&s->notifiers_list, node, next);
+ return;
+ }
+
+ /* update notifier node with new flags */
+ QLIST_FOREACH_SAFE(node, &s->notifiers_list, next, next_node) {
+ if (node->vtd_as == vtd_as) {
+ if (new == IOMMU_NOTIFIER_NONE) {
+ QLIST_REMOVE(node, next);
+ g_free(node);
+ }
+ return;
+ }
+ }
}
static const VMStateDescription vtd_vmstate = {
@@ -2389,19 +2659,150 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
vtd_dev_as->devfn = (uint8_t)devfn;
vtd_dev_as->iommu_state = s;
vtd_dev_as->context_cache_entry.context_cache_gen = 0;
+
+ /*
+ * Memory region relationships looks like (Address range shows
+ * only lower 32 bits to make it short in length...):
+ *
+ * |-----------------+-------------------+----------|
+ * | Name | Address range | Priority |
+ * |-----------------+-------------------+----------+
+ * | vtd_root | 00000000-ffffffff | 0 |
+ * | intel_iommu | 00000000-ffffffff | 1 |
+ * | vtd_sys_alias | 00000000-ffffffff | 1 |
+ * | intel_iommu_ir | fee00000-feefffff | 64 |
+ * |-----------------+-------------------+----------|
+ *
+ * We enable/disable DMAR by switching enablement for
+ * vtd_sys_alias and intel_iommu regions. IR region is always
+ * enabled.
+ */
memory_region_init_iommu(&vtd_dev_as->iommu, OBJECT(s),
- &s->iommu_ops, "intel_iommu", UINT64_MAX);
+ &s->iommu_ops, "intel_iommu_dmar",
+ UINT64_MAX);
+ memory_region_init_alias(&vtd_dev_as->sys_alias, OBJECT(s),
+ "vtd_sys_alias", get_system_memory(),
+ 0, memory_region_size(get_system_memory()));
memory_region_init_io(&vtd_dev_as->iommu_ir, OBJECT(s),
&vtd_mem_ir_ops, s, "intel_iommu_ir",
VTD_INTERRUPT_ADDR_SIZE);
- memory_region_add_subregion(&vtd_dev_as->iommu, VTD_INTERRUPT_ADDR_FIRST,
- &vtd_dev_as->iommu_ir);
- address_space_init(&vtd_dev_as->as,
- &vtd_dev_as->iommu, name);
+ memory_region_init(&vtd_dev_as->root, OBJECT(s),
+ "vtd_root", UINT64_MAX);
+ memory_region_add_subregion_overlap(&vtd_dev_as->root,
+ VTD_INTERRUPT_ADDR_FIRST,
+ &vtd_dev_as->iommu_ir, 64);
+ address_space_init(&vtd_dev_as->as, &vtd_dev_as->root, name);
+ memory_region_add_subregion_overlap(&vtd_dev_as->root, 0,
+ &vtd_dev_as->sys_alias, 1);
+ memory_region_add_subregion_overlap(&vtd_dev_as->root, 0,
+ &vtd_dev_as->iommu, 1);
+ vtd_switch_address_space(vtd_dev_as);
}
return vtd_dev_as;
}
+/* Unmap the whole range in the notifier's scope. */
+static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n)
+{
+ IOMMUTLBEntry entry;
+ hwaddr size;
+ hwaddr start = n->start;
+ hwaddr end = n->end;
+
+ /*
+ * Note: all the codes in this function has a assumption that IOVA
+ * bits are no more than VTD_MGAW bits (which is restricted by
+ * VT-d spec), otherwise we need to consider overflow of 64 bits.
+ */
+
+ if (end > VTD_ADDRESS_SIZE) {
+ /*
+ * Don't need to unmap regions that is bigger than the whole
+ * VT-d supported address space size
+ */
+ end = VTD_ADDRESS_SIZE;
+ }
+
+ assert(start <= end);
+ size = end - start;
+
+ if (ctpop64(size) != 1) {
+ /*
+ * This size cannot format a correct mask. Let's enlarge it to
+ * suite the minimum available mask.
+ */
+ int n = 64 - clz64(size);
+ if (n > VTD_MGAW) {
+ /* should not happen, but in case it happens, limit it */
+ n = VTD_MGAW;
+ }
+ size = 1ULL << n;
+ }
+
+ entry.target_as = &address_space_memory;
+ /* Adjust iova for the size */
+ entry.iova = n->start & ~(size - 1);
+ /* This field is meaningless for unmap */
+ entry.translated_addr = 0;
+ entry.perm = IOMMU_NONE;
+ entry.addr_mask = size - 1;
+
+ trace_vtd_as_unmap_whole(pci_bus_num(as->bus),
+ VTD_PCI_SLOT(as->devfn),
+ VTD_PCI_FUNC(as->devfn),
+ entry.iova, size);
+
+ memory_region_notify_one(n, &entry);
+}
+
+static void vtd_address_space_unmap_all(IntelIOMMUState *s)
+{
+ IntelIOMMUNotifierNode *node;
+ VTDAddressSpace *vtd_as;
+ IOMMUNotifier *n;
+
+ QLIST_FOREACH(node, &s->notifiers_list, next) {
+ vtd_as = node->vtd_as;
+ IOMMU_NOTIFIER_FOREACH(n, &vtd_as->iommu) {
+ vtd_address_space_unmap(vtd_as, n);
+ }
+ }
+}
+
+static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private)
+{
+ memory_region_notify_one((IOMMUNotifier *)private, entry);
+ return 0;
+}
+
+static void vtd_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n)
+{
+ VTDAddressSpace *vtd_as = container_of(mr, VTDAddressSpace, iommu);
+ IntelIOMMUState *s = vtd_as->iommu_state;
+ uint8_t bus_n = pci_bus_num(vtd_as->bus);
+ VTDContextEntry ce;
+
+ /*
+ * The replay can be triggered by either a invalidation or a newly
+ * created entry. No matter what, we release existing mappings
+ * (it means flushing caches for UNMAP-only registers).
+ */
+ vtd_address_space_unmap(vtd_as, n);
+
+ if (vtd_dev_to_context_entry(s, bus_n, vtd_as->devfn, &ce) == 0) {
+ trace_vtd_replay_ce_valid(bus_n, PCI_SLOT(vtd_as->devfn),
+ PCI_FUNC(vtd_as->devfn),
+ VTD_CONTEXT_ENTRY_DID(ce.hi),
+ ce.hi, ce.lo);
+ vtd_page_walk(&ce, 0, ~0ULL, vtd_replay_hook, (void *)n, false);
+ } else {
+ trace_vtd_replay_ce_invalid(bus_n, PCI_SLOT(vtd_as->devfn),
+ PCI_FUNC(vtd_as->devfn));
+ }
+
+ return;
+}
+
/* Do the initialization. It will also be called when reset, so pay
* attention when adding new initialization stuff.
*/
@@ -2416,6 +2817,7 @@ static void vtd_init(IntelIOMMUState *s)
s->iommu_ops.translate = vtd_iommu_translate;
s->iommu_ops.notify_flag_changed = vtd_iommu_notify_flag_changed;
+ s->iommu_ops.replay = vtd_iommu_replay;
s->root = 0;
s->root_extended = false;
s->dmar_enabled = false;
@@ -2511,6 +2913,11 @@ static void vtd_reset(DeviceState *dev)
VTD_DPRINTF(GENERAL, "");
vtd_init(s);
+
+ /*
+ * When device reset, throw away all mappings and external caches
+ */
+ vtd_address_space_unmap_all(s);
}
static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
@@ -2574,6 +2981,7 @@ static void vtd_realize(DeviceState *dev, Error **errp)
return;
}
+ QLIST_INIT(&s->notifiers_list);
memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num));
memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s,
"intel_iommu", DMAR_REG_SIZE);
diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h
index 41041219ba..29d67075f4 100644
--- a/hw/i386/intel_iommu_internal.h
+++ b/hw/i386/intel_iommu_internal.h
@@ -197,6 +197,7 @@
#define VTD_DOMAIN_ID_MASK ((1UL << VTD_DOMAIN_ID_SHIFT) - 1)
#define VTD_CAP_ND (((VTD_DOMAIN_ID_SHIFT - 4) / 2) & 7ULL)
#define VTD_MGAW 39 /* Maximum Guest Address Width */
+#define VTD_ADDRESS_SIZE (1ULL << VTD_MGAW)
#define VTD_CAP_MGAW (((VTD_MGAW - 1) & 0x3fULL) << 16)
#define VTD_MAMV 18ULL
#define VTD_CAP_MAMV (VTD_MAMV << 48)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index d24388e05f..f3b372a18f 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1104,9 +1104,7 @@ static void pc_new_cpu(const char *typename, int64_t apic_id, Error **errp)
object_property_set_bool(cpu, true, "realized", &local_err);
object_unref(cpu);
- if (local_err) {
- error_propagate(errp, local_err);
- }
+ error_propagate(errp, local_err);
}
void pc_hot_add_cpu(const int64_t id, Error **errp)
diff --git a/hw/i386/trace-events b/hw/i386/trace-events
index 88ad5e4c43..04a6980800 100644
--- a/hw/i386/trace-events
+++ b/hw/i386/trace-events
@@ -4,7 +4,6 @@
x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC invalidation: global=%d index=%" PRIu32 " mask=%" PRIu32
# hw/i386/intel_iommu.c
-vtd_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device %02x:%02x.%x switching address space (iommu enabled=%d)"
vtd_inv_desc(const char *type, uint64_t hi, uint64_t lo) "invalidate desc type %s high 0x%"PRIx64" low 0x%"PRIx64
vtd_inv_desc_invalid(uint64_t hi, uint64_t lo) "invalid inv desc hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_inv_desc_cc_domain(uint16_t domain) "context invalidate domain 0x%"PRIx16
@@ -30,6 +29,15 @@ vtd_iotlb_cc_hit(uint8_t bus, uint8_t devfn, uint64_t high, uint64_t low, uint32
vtd_iotlb_cc_update(uint8_t bus, uint8_t devfn, uint64_t high, uint64_t low, uint32_t gen1, uint32_t gen2) "IOTLB context update bus 0x%"PRIx8" devfn 0x%"PRIx8" high 0x%"PRIx64" low 0x%"PRIx64" gen %"PRIu32" -> gen %"PRIu32
vtd_iotlb_reset(const char *reason) "IOTLB reset (reason: %s)"
vtd_fault_disabled(void) "Fault processing disabled for context entry"
+vtd_replay_ce_valid(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t domain, uint64_t hi, uint64_t lo) "replay valid context device %02"PRIx8":%02"PRIx8".%02"PRIx8" domain 0x%"PRIx16" hi 0x%"PRIx64" lo 0x%"PRIx64
+vtd_replay_ce_invalid(uint8_t bus, uint8_t dev, uint8_t fn) "replay invalid context device %02"PRIx8":%02"PRIx8".%02"PRIx8
+vtd_page_walk_level(uint64_t addr, uint32_t level, uint64_t start, uint64_t end) "walk (base=0x%"PRIx64", level=%"PRIu32") iova range 0x%"PRIx64" - 0x%"PRIx64
+vtd_page_walk_one(uint32_t level, uint64_t iova, uint64_t gpa, uint64_t mask, int perm) "detected page level 0x%"PRIx32" iova 0x%"PRIx64" -> gpa 0x%"PRIx64" mask 0x%"PRIx64" perm %d"
+vtd_page_walk_skip_read(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to unable to read"
+vtd_page_walk_skip_perm(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to perm empty"
+vtd_page_walk_skip_reserve(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to rsrv set"
+vtd_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device %02x:%02x.%x switching address space (iommu enabled=%d)"
+vtd_as_unmap_whole(uint8_t bus, uint8_t slot, uint8_t fn, uint64_t iova, uint64_t size) "Device %02x:%02x.%x start 0x%"PRIx64" size 0x%"PRIx64
# hw/i386/amd_iommu.c
amdvi_evntlog_fail(uint64_t addr, uint32_t head) "error: fail to write at addr 0x%"PRIx64" + offset 0x%"PRIx32
@@ -37,6 +45,7 @@ amdvi_cache_update(uint16_t domid, uint8_t bus, uint8_t slot, uint8_t func, uint
amdvi_completion_wait_fail(uint64_t addr) "error: fail to write at address 0x%"PRIx64
amdvi_mmio_write(const char *reg, uint64_t addr, unsigned size, uint64_t val, uint64_t offset) "%s write addr 0x%"PRIx64", size %u, val 0x%"PRIx64", offset 0x%"PRIx64
amdvi_mmio_read(const char *reg, uint64_t addr, unsigned size, uint64_t offset) "%s read addr 0x%"PRIx64", size %u offset 0x%"PRIx64
+amdvi_mmio_read_invalid(int max, uint64_t addr, unsigned size) "error: addr outside region (max 0x%x): read addr 0x%" PRIx64 ", size %u"
amdvi_command_error(uint64_t status) "error: Executing commands with command buffer disabled 0x%"PRIx64
amdvi_command_read_fail(uint64_t addr, uint32_t head) "error: fail to access memory at 0x%"PRIx64" + 0x%"PRIx32
amdvi_command_exec(uint32_t head, uint32_t tail, uint64_t buf) "command buffer head at 0x%"PRIx32" command buffer tail at 0x%"PRIx32" command buffer base at 0x%"PRIx64
diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
index b678ee9f20..0e42f0d02c 100644
--- a/hw/input/virtio-input.c
+++ b/hw/input/virtio-input.c
@@ -22,7 +22,6 @@
void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
{
VirtQueueElement *elem;
- unsigned have, need;
int i, len;
if (!vinput->active) {
@@ -32,10 +31,10 @@ void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
/* queue up events ... */
if (vinput->qindex == vinput->qsize) {
vinput->qsize++;
- vinput->queue = realloc(vinput->queue, vinput->qsize *
- sizeof(virtio_input_event));
+ vinput->queue = g_realloc(vinput->queue, vinput->qsize *
+ sizeof(vinput->queue[0]));
}
- vinput->queue[vinput->qindex++] = *event;
+ vinput->queue[vinput->qindex++].event = *event;
/* ... until we see a report sync ... */
if (event->type != cpu_to_le16(EV_SYN) ||
@@ -44,24 +43,24 @@ void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
}
/* ... then check available space ... */
- need = sizeof(virtio_input_event) * vinput->qindex;
- virtqueue_get_avail_bytes(vinput->evt, &have, NULL, need, 0);
- if (have < need) {
- vinput->qindex = 0;
- trace_virtio_input_queue_full();
- return;
- }
-
- /* ... and finally pass them to the guest */
for (i = 0; i < vinput->qindex; i++) {
elem = virtqueue_pop(vinput->evt, sizeof(VirtQueueElement));
if (!elem) {
- /* should not happen, we've checked for space beforehand */
- fprintf(stderr, "%s: Huh? No vq elem available ...\n", __func__);
+ while (--i >= 0) {
+ virtqueue_unpop(vinput->evt, vinput->queue[i].elem, 0);
+ }
+ vinput->qindex = 0;
+ trace_virtio_input_queue_full();
return;
}
+ vinput->queue[i].elem = elem;
+ }
+
+ /* ... and finally pass them to the guest */
+ for (i = 0; i < vinput->qindex; i++) {
+ elem = vinput->queue[i].elem;
len = iov_from_buf(elem->in_sg, elem->in_num,
- 0, vinput->queue+i, sizeof(virtio_input_event));
+ 0, &vinput->queue[i].event, sizeof(virtio_input_event));
virtqueue_push(vinput->evt, elem, len);
g_free(elem);
}
@@ -272,6 +271,8 @@ static void virtio_input_finalize(Object *obj)
QTAILQ_REMOVE(&vinput->cfg_list, cfg, node);
g_free(cfg);
}
+
+ g_free(vinput->queue);
}
static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
{
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
index 7a6e771ed1..c3829e31b5 100644
--- a/hw/intc/apic_common.c
+++ b/hw/intc/apic_common.c
@@ -387,25 +387,6 @@ static bool apic_common_sipi_needed(void *opaque)
return s->wait_for_sipi != 0;
}
-static bool apic_irq_delivered_needed(void *opaque)
-{
- APICCommonState *s = APIC_COMMON(opaque);
- return s->cpu == X86_CPU(first_cpu) && apic_irq_delivered != 0;
-}
-
-static void apic_irq_delivered_pre_save(void *opaque)
-{
- APICCommonState *s = APIC_COMMON(opaque);
- s->apic_irq_delivered = apic_irq_delivered;
-}
-
-static int apic_irq_delivered_post_load(void *opaque, int version_id)
-{
- APICCommonState *s = APIC_COMMON(opaque);
- apic_irq_delivered = s->apic_irq_delivered;
- return 0;
-}
-
static const VMStateDescription vmstate_apic_common_sipi = {
.name = "apic_sipi",
.version_id = 1,
@@ -418,19 +399,6 @@ static const VMStateDescription vmstate_apic_common_sipi = {
}
};
-static const VMStateDescription vmstate_apic_irq_delivered = {
- .name = "apic_irq_delivered",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = apic_irq_delivered_needed,
- .pre_save = apic_irq_delivered_pre_save,
- .post_load = apic_irq_delivered_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(apic_irq_delivered, APICCommonState),
- VMSTATE_END_OF_LIST()
- }
-};
-
static const VMStateDescription vmstate_apic_common = {
.name = "apic",
.version_id = 3,
@@ -465,7 +433,6 @@ static const VMStateDescription vmstate_apic_common = {
},
.subsections = (const VMStateDescription*[]) {
&vmstate_apic_common_sipi,
- &vmstate_apic_irq_delivered,
NULL
}
};
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index 81f0403117..19aab56072 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -614,12 +614,6 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
s = c->gic;
cpu = ARM_CPU(c->cpu);
- /* Initialize to actual HW supported configuration */
- kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
- KVM_VGIC_ATTR(ICC_CTLR_EL1, cpu->mp_affinity),
- &c->icc_ctlr_el1[GICV3_NS], false);
-
- c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS];
c->icc_pmr_el1 = 0;
c->icc_bpr[GICV3_G0] = GIC_MIN_BPR;
c->icc_bpr[GICV3_G1] = GIC_MIN_BPR;
@@ -628,6 +622,17 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
c->icc_sre_el1 = 0x7;
memset(c->icc_apr, 0, sizeof(c->icc_apr));
memset(c->icc_igrpen, 0, sizeof(c->icc_igrpen));
+
+ if (s->migration_blocker) {
+ return;
+ }
+
+ /* Initialize to actual HW supported configuration */
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+ KVM_VGIC_ATTR(ICC_CTLR_EL1, cpu->mp_affinity),
+ &c->icc_ctlr_el1[GICV3_NS], false);
+
+ c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS];
}
static void kvm_arm_gicv3_reset(DeviceState *dev)
diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c
index bef4caf980..711c11454f 100644
--- a/hw/intc/s390_flic.c
+++ b/hw/intc/s390_flic.c
@@ -21,11 +21,14 @@
S390FLICState *s390_get_flic(void)
{
- S390FLICState *fs;
+ static S390FLICState *fs;
- fs = S390_FLIC_COMMON(object_resolve_path(TYPE_KVM_S390_FLIC, NULL));
if (!fs) {
- fs = S390_FLIC_COMMON(object_resolve_path(TYPE_QEMU_S390_FLIC, NULL));
+ fs = S390_FLIC_COMMON(object_resolve_path(TYPE_KVM_S390_FLIC, NULL));
+ if (!fs) {
+ fs = S390_FLIC_COMMON(object_resolve_path(TYPE_QEMU_S390_FLIC,
+ NULL));
+ }
}
return fs;
}
diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c
index 1c69cb33f8..2fcc3d2e7c 100644
--- a/hw/ipmi/isa_ipmi_bt.c
+++ b/hw/ipmi/isa_ipmi_bt.c
@@ -37,40 +37,30 @@
#define IPMI_BT_HBUSY_BIT 6
#define IPMI_BT_BBUSY_BIT 7
-#define IPMI_BT_CLR_WR_MASK (1 << IPMI_BT_CLR_WR_BIT)
#define IPMI_BT_GET_CLR_WR(d) (((d) >> IPMI_BT_CLR_WR_BIT) & 0x1)
-#define IPMI_BT_SET_CLR_WR(d, v) (d) = (((d) & ~IPMI_BT_CLR_WR_MASK) | \
- (((v & 1) << IPMI_BT_CLR_WR_BIT)))
-#define IPMI_BT_CLR_RD_MASK (1 << IPMI_BT_CLR_RD_BIT)
#define IPMI_BT_GET_CLR_RD(d) (((d) >> IPMI_BT_CLR_RD_BIT) & 0x1)
-#define IPMI_BT_SET_CLR_RD(d, v) (d) = (((d) & ~IPMI_BT_CLR_RD_MASK) | \
- (((v & 1) << IPMI_BT_CLR_RD_BIT)))
-#define IPMI_BT_H2B_ATN_MASK (1 << IPMI_BT_H2B_ATN_BIT)
#define IPMI_BT_GET_H2B_ATN(d) (((d) >> IPMI_BT_H2B_ATN_BIT) & 0x1)
-#define IPMI_BT_SET_H2B_ATN(d, v) (d) = (((d) & ~IPMI_BT_H2B_ATN_MASK) | \
- (((v & 1) << IPMI_BT_H2B_ATN_BIT)))
#define IPMI_BT_B2H_ATN_MASK (1 << IPMI_BT_B2H_ATN_BIT)
#define IPMI_BT_GET_B2H_ATN(d) (((d) >> IPMI_BT_B2H_ATN_BIT) & 0x1)
-#define IPMI_BT_SET_B2H_ATN(d, v) (d) = (((d) & ~IPMI_BT_B2H_ATN_MASK) | \
- (((v & 1) << IPMI_BT_B2H_ATN_BIT)))
+#define IPMI_BT_SET_B2H_ATN(d, v) ((d) = (((d) & ~IPMI_BT_B2H_ATN_MASK) | \
+ (((v) & 1) << IPMI_BT_B2H_ATN_BIT)))
#define IPMI_BT_SMS_ATN_MASK (1 << IPMI_BT_SMS_ATN_BIT)
#define IPMI_BT_GET_SMS_ATN(d) (((d) >> IPMI_BT_SMS_ATN_BIT) & 0x1)
-#define IPMI_BT_SET_SMS_ATN(d, v) (d) = (((d) & ~IPMI_BT_SMS_ATN_MASK) | \
- (((v & 1) << IPMI_BT_SMS_ATN_BIT)))
+#define IPMI_BT_SET_SMS_ATN(d, v) ((d) = (((d) & ~IPMI_BT_SMS_ATN_MASK) | \
+ (((v) & 1) << IPMI_BT_SMS_ATN_BIT)))
#define IPMI_BT_HBUSY_MASK (1 << IPMI_BT_HBUSY_BIT)
#define IPMI_BT_GET_HBUSY(d) (((d) >> IPMI_BT_HBUSY_BIT) & 0x1)
-#define IPMI_BT_SET_HBUSY(d, v) (d) = (((d) & ~IPMI_BT_HBUSY_MASK) | \
- (((v & 1) << IPMI_BT_HBUSY_BIT)))
+#define IPMI_BT_SET_HBUSY(d, v) ((d) = (((d) & ~IPMI_BT_HBUSY_MASK) | \
+ (((v) & 1) << IPMI_BT_HBUSY_BIT)))
#define IPMI_BT_BBUSY_MASK (1 << IPMI_BT_BBUSY_BIT)
-#define IPMI_BT_GET_BBUSY(d) (((d) >> IPMI_BT_BBUSY_BIT) & 0x1)
-#define IPMI_BT_SET_BBUSY(d, v) (d) = (((d) & ~IPMI_BT_BBUSY_MASK) | \
- (((v & 1) << IPMI_BT_BBUSY_BIT)))
+#define IPMI_BT_SET_BBUSY(d, v) ((d) = (((d) & ~IPMI_BT_BBUSY_MASK) | \
+ (((v) & 1) << IPMI_BT_BBUSY_BIT)))
/* Mask register */
@@ -79,13 +69,13 @@
#define IPMI_BT_B2H_IRQ_EN_MASK (1 << IPMI_BT_B2H_IRQ_EN_BIT)
#define IPMI_BT_GET_B2H_IRQ_EN(d) (((d) >> IPMI_BT_B2H_IRQ_EN_BIT) & 0x1)
-#define IPMI_BT_SET_B2H_IRQ_EN(d, v) (d) = (((d) & ~IPMI_BT_B2H_IRQ_EN_MASK) | \
- (((v & 1) << IPMI_BT_B2H_IRQ_EN_BIT)))
+#define IPMI_BT_SET_B2H_IRQ_EN(d, v) ((d) = (((d) & ~IPMI_BT_B2H_IRQ_EN_MASK) |\
+ (((v) & 1) << IPMI_BT_B2H_IRQ_EN_BIT)))
#define IPMI_BT_B2H_IRQ_MASK (1 << IPMI_BT_B2H_IRQ_BIT)
#define IPMI_BT_GET_B2H_IRQ(d) (((d) >> IPMI_BT_B2H_IRQ_BIT) & 0x1)
-#define IPMI_BT_SET_B2H_IRQ(d, v) (d) = (((d) & ~IPMI_BT_B2H_IRQ_MASK) | \
- (((v & 1) << IPMI_BT_B2H_IRQ_BIT)))
+#define IPMI_BT_SET_B2H_IRQ(d, v) ((d) = (((d) & ~IPMI_BT_B2H_IRQ_MASK) | \
+ (((v) & 1) << IPMI_BT_B2H_IRQ_BIT)))
typedef struct IPMIBT {
IPMIBmc *bmc;
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index 59930dd9d0..a0866c3856 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -312,11 +312,6 @@ void ich9_generate_smi(void)
cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
}
-void ich9_generate_nmi(void)
-{
- cpu_interrupt(first_cpu, CPU_INTERRUPT_NMI);
-}
-
static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
{
switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
diff --git a/hw/misc/exynos4210_pmu.c b/hw/misc/exynos4210_pmu.c
index e30dbc7d3d..63a8ccd355 100644
--- a/hw/misc/exynos4210_pmu.c
+++ b/hw/misc/exynos4210_pmu.c
@@ -401,8 +401,8 @@ static uint64_t exynos4210_pmu_read(void *opaque, hwaddr offset,
unsigned size)
{
Exynos4210PmuState *s = (Exynos4210PmuState *)opaque;
- unsigned i;
const Exynos4210PmuReg *reg_p = exynos4210_pmu_regs;
+ unsigned int i;
for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) {
if (reg_p->offset == offset) {
@@ -420,8 +420,8 @@ static void exynos4210_pmu_write(void *opaque, hwaddr offset,
uint64_t val, unsigned size)
{
Exynos4210PmuState *s = (Exynos4210PmuState *)opaque;
- unsigned i;
const Exynos4210PmuReg *reg_p = exynos4210_pmu_regs;
+ unsigned int i;
for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) {
if (reg_p->offset == offset) {
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index 6a95d92d37..5ddaffe63a 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -26,6 +26,7 @@ common-obj-$(CONFIG_IMX_FEC) += imx_fec.o
common-obj-$(CONFIG_CADENCE) += cadence_gem.o
common-obj-$(CONFIG_STELLARIS_ENET) += stellaris_enet.o
common-obj-$(CONFIG_LANCE) += lance.o
+common-obj-$(CONFIG_FTGMAC100) += ftgmac100.o
obj-$(CONFIG_ETRAXFS) += etraxfs_eth.o
obj-$(CONFIG_COLDFIRE) += mcf_fec.o
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index d4de8ad9f1..3943187572 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -300,6 +300,8 @@
#define DESC_1_RX_SOF 0x00004000
#define DESC_1_RX_EOF 0x00008000
+#define GEM_MODID_VALUE 0x00020118
+
static inline unsigned tx_desc_get_buffer(unsigned *desc)
{
return desc[0];
@@ -481,14 +483,17 @@ static int gem_can_receive(NetClientState *nc)
}
for (i = 0; i < s->num_priority_queues; i++) {
- if (rx_desc_get_ownership(s->rx_desc[i]) == 1) {
- if (s->can_rx_state != 2) {
- s->can_rx_state = 2;
- DB_PRINT("can't receive - busy buffer descriptor (q%d) 0x%x\n",
- i, s->rx_desc_addr[i]);
- }
- return 0;
+ if (rx_desc_get_ownership(s->rx_desc[i]) != 1) {
+ break;
+ }
+ };
+
+ if (i == s->num_priority_queues) {
+ if (s->can_rx_state != 2) {
+ s->can_rx_state = 2;
+ DB_PRINT("can't receive - all the buffer descriptors are busy\n");
}
+ return 0;
}
if (s->can_rx_state != 0) {
@@ -506,7 +511,18 @@ static void gem_update_int_status(CadenceGEMState *s)
{
int i;
- if ((s->num_priority_queues == 1) && s->regs[GEM_ISR]) {
+ if (!s->regs[GEM_ISR]) {
+ /* ISR isn't set, clear all the interrupts */
+ for (i = 0; i < s->num_priority_queues; ++i) {
+ qemu_set_irq(s->irq[i], 0);
+ }
+ return;
+ }
+
+ /* If we get here we know s->regs[GEM_ISR] is set, so we don't need to
+ * check it again.
+ */
+ if (s->num_priority_queues == 1) {
/* No priority queues, just trigger the interrupt */
DB_PRINT("asserting int.\n");
qemu_set_irq(s->irq[0], 1);
@@ -790,8 +806,8 @@ static void gem_get_rx_desc(CadenceGEMState *s, int q)
{
DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[q]);
/* read current descriptor */
- cpu_physical_memory_read(s->rx_desc_addr[0],
- (uint8_t *)s->rx_desc[0], sizeof(s->rx_desc[0]));
+ cpu_physical_memory_read(s->rx_desc_addr[q],
+ (uint8_t *)s->rx_desc[q], sizeof(s->rx_desc[q]));
/* Descriptor owned by software ? */
if (rx_desc_get_ownership(s->rx_desc[q]) == 1) {
@@ -1209,7 +1225,7 @@ static void gem_reset(DeviceState *d)
s->regs[GEM_TXPAUSE] = 0x0000ffff;
s->regs[GEM_TXPARTIALSF] = 0x000003ff;
s->regs[GEM_RXPARTIALSF] = 0x000003ff;
- s->regs[GEM_MODID] = 0x00020118;
+ s->regs[GEM_MODID] = s->revision;
s->regs[GEM_DESCONF] = 0x02500111;
s->regs[GEM_DESCONF2] = 0x2ab13fff;
s->regs[GEM_DESCONF5] = 0x002f2145;
@@ -1271,7 +1287,6 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
{
CadenceGEMState *s;
uint32_t retval;
- int i;
s = (CadenceGEMState *)opaque;
offset >>= 2;
@@ -1282,9 +1297,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
switch (offset) {
case GEM_ISR:
DB_PRINT("lowering irqs on ISR read\n");
- for (i = 0; i < s->num_priority_queues; ++i) {
- qemu_set_irq(s->irq[i], 0);
- }
+ /* The interrupts get updated at the end of the function. */
break;
case GEM_PHYMNTNC:
if (retval & GEM_PHYMNTNC_OP_R) {
@@ -1508,6 +1521,8 @@ static const VMStateDescription vmstate_cadence_gem = {
static Property gem_properties[] = {
DEFINE_NIC_PROPERTIES(CadenceGEMState, conf),
+ DEFINE_PROP_UINT32("revision", CadenceGEMState, revision,
+ GEM_MODID_VALUE),
DEFINE_PROP_UINT8("num-priority-queues", CadenceGEMState,
num_priority_queues, 1),
DEFINE_PROP_UINT8("num-type1-screeners", CadenceGEMState,
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index 93249497f4..f2e5072d27 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -40,7 +40,7 @@
static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-#define E1000_DEBUG
+/* #define E1000_DEBUG */
#ifdef E1000_DEBUG
enum {
diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c
new file mode 100644
index 0000000000..3c36ab9cec
--- /dev/null
+++ b/hw/net/ftgmac100.c
@@ -0,0 +1,1016 @@
+/*
+ * Faraday FTGMAC100 Gigabit Ethernet
+ *
+ * Copyright (C) 2016-2017, IBM Corporation.
+ *
+ * Based on Coldfire Fast Ethernet Controller emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/net/ftgmac100.h"
+#include "sysemu/dma.h"
+#include "qemu/log.h"
+#include "net/checksum.h"
+#include "net/eth.h"
+#include "hw/net/mii.h"
+
+/* For crc32 */
+#include <zlib.h>
+
+/*
+ * FTGMAC100 registers
+ */
+#define FTGMAC100_ISR 0x00
+#define FTGMAC100_IER 0x04
+#define FTGMAC100_MAC_MADR 0x08
+#define FTGMAC100_MAC_LADR 0x0c
+#define FTGMAC100_MATH0 0x10
+#define FTGMAC100_MATH1 0x14
+#define FTGMAC100_NPTXPD 0x18
+#define FTGMAC100_RXPD 0x1C
+#define FTGMAC100_NPTXR_BADR 0x20
+#define FTGMAC100_RXR_BADR 0x24
+#define FTGMAC100_HPTXPD 0x28
+#define FTGMAC100_HPTXR_BADR 0x2c
+#define FTGMAC100_ITC 0x30
+#define FTGMAC100_APTC 0x34
+#define FTGMAC100_DBLAC 0x38
+#define FTGMAC100_REVR 0x40
+#define FTGMAC100_FEAR1 0x44
+#define FTGMAC100_RBSR 0x4c
+#define FTGMAC100_TPAFCR 0x48
+
+#define FTGMAC100_MACCR 0x50
+#define FTGMAC100_MACSR 0x54
+#define FTGMAC100_PHYCR 0x60
+#define FTGMAC100_PHYDATA 0x64
+#define FTGMAC100_FCR 0x68
+
+/*
+ * Interrupt status register & interrupt enable register
+ */
+#define FTGMAC100_INT_RPKT_BUF (1 << 0)
+#define FTGMAC100_INT_RPKT_FIFO (1 << 1)
+#define FTGMAC100_INT_NO_RXBUF (1 << 2)
+#define FTGMAC100_INT_RPKT_LOST (1 << 3)
+#define FTGMAC100_INT_XPKT_ETH (1 << 4)
+#define FTGMAC100_INT_XPKT_FIFO (1 << 5)
+#define FTGMAC100_INT_NO_NPTXBUF (1 << 6)
+#define FTGMAC100_INT_XPKT_LOST (1 << 7)
+#define FTGMAC100_INT_AHB_ERR (1 << 8)
+#define FTGMAC100_INT_PHYSTS_CHG (1 << 9)
+#define FTGMAC100_INT_NO_HPTXBUF (1 << 10)
+
+/*
+ * Automatic polling timer control register
+ */
+#define FTGMAC100_APTC_RXPOLL_CNT(x) ((x) & 0xf)
+#define FTGMAC100_APTC_RXPOLL_TIME_SEL (1 << 4)
+#define FTGMAC100_APTC_TXPOLL_CNT(x) (((x) >> 8) & 0xf)
+#define FTGMAC100_APTC_TXPOLL_TIME_SEL (1 << 12)
+
+/*
+ * PHY control register
+ */
+#define FTGMAC100_PHYCR_MIIRD (1 << 26)
+#define FTGMAC100_PHYCR_MIIWR (1 << 27)
+
+#define FTGMAC100_PHYCR_DEV(x) (((x) >> 16) & 0x1f)
+#define FTGMAC100_PHYCR_REG(x) (((x) >> 21) & 0x1f)
+
+/*
+ * PHY data register
+ */
+#define FTGMAC100_PHYDATA_MIIWDATA(x) ((x) & 0xffff)
+#define FTGMAC100_PHYDATA_MIIRDATA(x) (((x) >> 16) & 0xffff)
+
+/*
+ * Feature Register
+ */
+#define FTGMAC100_REVR_NEW_MDIO_INTERFACE (1 << 31)
+
+/*
+ * MAC control register
+ */
+#define FTGMAC100_MACCR_TXDMA_EN (1 << 0)
+#define FTGMAC100_MACCR_RXDMA_EN (1 << 1)
+#define FTGMAC100_MACCR_TXMAC_EN (1 << 2)
+#define FTGMAC100_MACCR_RXMAC_EN (1 << 3)
+#define FTGMAC100_MACCR_RM_VLAN (1 << 4)
+#define FTGMAC100_MACCR_HPTXR_EN (1 << 5)
+#define FTGMAC100_MACCR_LOOP_EN (1 << 6)
+#define FTGMAC100_MACCR_ENRX_IN_HALFTX (1 << 7)
+#define FTGMAC100_MACCR_FULLDUP (1 << 8)
+#define FTGMAC100_MACCR_GIGA_MODE (1 << 9)
+#define FTGMAC100_MACCR_CRC_APD (1 << 10) /* not needed */
+#define FTGMAC100_MACCR_RX_RUNT (1 << 12)
+#define FTGMAC100_MACCR_JUMBO_LF (1 << 13)
+#define FTGMAC100_MACCR_RX_ALL (1 << 14)
+#define FTGMAC100_MACCR_HT_MULTI_EN (1 << 15)
+#define FTGMAC100_MACCR_RX_MULTIPKT (1 << 16)
+#define FTGMAC100_MACCR_RX_BROADPKT (1 << 17)
+#define FTGMAC100_MACCR_DISCARD_CRCERR (1 << 18)
+#define FTGMAC100_MACCR_FAST_MODE (1 << 19)
+#define FTGMAC100_MACCR_SW_RST (1 << 31)
+
+/*
+ * Transmit descriptor
+ */
+#define FTGMAC100_TXDES0_TXBUF_SIZE(x) ((x) & 0x3fff)
+#define FTGMAC100_TXDES0_EDOTR (1 << 15)
+#define FTGMAC100_TXDES0_CRC_ERR (1 << 19)
+#define FTGMAC100_TXDES0_LTS (1 << 28)
+#define FTGMAC100_TXDES0_FTS (1 << 29)
+#define FTGMAC100_TXDES0_EDOTR_ASPEED (1 << 30)
+#define FTGMAC100_TXDES0_TXDMA_OWN (1 << 31)
+
+#define FTGMAC100_TXDES1_VLANTAG_CI(x) ((x) & 0xffff)
+#define FTGMAC100_TXDES1_INS_VLANTAG (1 << 16)
+#define FTGMAC100_TXDES1_TCP_CHKSUM (1 << 17)
+#define FTGMAC100_TXDES1_UDP_CHKSUM (1 << 18)
+#define FTGMAC100_TXDES1_IP_CHKSUM (1 << 19)
+#define FTGMAC100_TXDES1_LLC (1 << 22)
+#define FTGMAC100_TXDES1_TX2FIC (1 << 30)
+#define FTGMAC100_TXDES1_TXIC (1 << 31)
+
+/*
+ * Receive descriptor
+ */
+#define FTGMAC100_RXDES0_VDBC 0x3fff
+#define FTGMAC100_RXDES0_EDORR (1 << 15)
+#define FTGMAC100_RXDES0_MULTICAST (1 << 16)
+#define FTGMAC100_RXDES0_BROADCAST (1 << 17)
+#define FTGMAC100_RXDES0_RX_ERR (1 << 18)
+#define FTGMAC100_RXDES0_CRC_ERR (1 << 19)
+#define FTGMAC100_RXDES0_FTL (1 << 20)
+#define FTGMAC100_RXDES0_RUNT (1 << 21)
+#define FTGMAC100_RXDES0_RX_ODD_NB (1 << 22)
+#define FTGMAC100_RXDES0_FIFO_FULL (1 << 23)
+#define FTGMAC100_RXDES0_PAUSE_OPCODE (1 << 24)
+#define FTGMAC100_RXDES0_PAUSE_FRAME (1 << 25)
+#define FTGMAC100_RXDES0_LRS (1 << 28)
+#define FTGMAC100_RXDES0_FRS (1 << 29)
+#define FTGMAC100_RXDES0_EDORR_ASPEED (1 << 30)
+#define FTGMAC100_RXDES0_RXPKT_RDY (1 << 31)
+
+#define FTGMAC100_RXDES1_VLANTAG_CI 0xffff
+#define FTGMAC100_RXDES1_PROT_MASK (0x3 << 20)
+#define FTGMAC100_RXDES1_PROT_NONIP (0x0 << 20)
+#define FTGMAC100_RXDES1_PROT_IP (0x1 << 20)
+#define FTGMAC100_RXDES1_PROT_TCPIP (0x2 << 20)
+#define FTGMAC100_RXDES1_PROT_UDPIP (0x3 << 20)
+#define FTGMAC100_RXDES1_LLC (1 << 22)
+#define FTGMAC100_RXDES1_DF (1 << 23)
+#define FTGMAC100_RXDES1_VLANTAG_AVAIL (1 << 24)
+#define FTGMAC100_RXDES1_TCP_CHKSUM_ERR (1 << 25)
+#define FTGMAC100_RXDES1_UDP_CHKSUM_ERR (1 << 26)
+#define FTGMAC100_RXDES1_IP_CHKSUM_ERR (1 << 27)
+
+/*
+ * Receive and transmit Buffer Descriptor
+ */
+typedef struct {
+ uint32_t des0;
+ uint32_t des1;
+ uint32_t des2; /* not used by HW */
+ uint32_t des3;
+} FTGMAC100Desc;
+
+/*
+ * Specific RTL8211E MII Registers
+ */
+#define RTL8211E_MII_PHYCR 16 /* PHY Specific Control */
+#define RTL8211E_MII_PHYSR 17 /* PHY Specific Status */
+#define RTL8211E_MII_INER 18 /* Interrupt Enable */
+#define RTL8211E_MII_INSR 19 /* Interrupt Status */
+#define RTL8211E_MII_RXERC 24 /* Receive Error Counter */
+#define RTL8211E_MII_LDPSR 27 /* Link Down Power Saving */
+#define RTL8211E_MII_EPAGSR 30 /* Extension Page Select */
+#define RTL8211E_MII_PAGSEL 31 /* Page Select */
+
+/*
+ * RTL8211E Interrupt Status
+ */
+#define PHY_INT_AUTONEG_ERROR (1 << 15)
+#define PHY_INT_PAGE_RECV (1 << 12)
+#define PHY_INT_AUTONEG_COMPLETE (1 << 11)
+#define PHY_INT_LINK_STATUS (1 << 10)
+#define PHY_INT_ERROR (1 << 9)
+#define PHY_INT_DOWN (1 << 8)
+#define PHY_INT_JABBER (1 << 0)
+
+/*
+ * Max frame size for the receiving buffer
+ */
+#define FTGMAC100_MAX_FRAME_SIZE 10240
+
+/* Limits depending on the type of the frame
+ *
+ * 9216 for Jumbo frames (+ 4 for VLAN)
+ * 1518 for other frames (+ 4 for VLAN)
+ */
+static int ftgmac100_max_frame_size(FTGMAC100State *s)
+{
+ return (s->maccr & FTGMAC100_MACCR_JUMBO_LF ? 9216 : 1518) + 4;
+}
+
+static void ftgmac100_update_irq(FTGMAC100State *s)
+{
+ qemu_set_irq(s->irq, s->isr & s->ier);
+}
+
+/*
+ * The MII phy could raise a GPIO to the processor which in turn
+ * could be handled as an interrpt by the OS.
+ * For now we don't handle any GPIO/interrupt line, so the OS will
+ * have to poll for the PHY status.
+ */
+static void phy_update_irq(FTGMAC100State *s)
+{
+ ftgmac100_update_irq(s);
+}
+
+static void phy_update_link(FTGMAC100State *s)
+{
+ /* Autonegotiation status mirrors link status. */
+ if (qemu_get_queue(s->nic)->link_down) {
+ s->phy_status &= ~(MII_BMSR_LINK_ST | MII_BMSR_AN_COMP);
+ s->phy_int |= PHY_INT_DOWN;
+ } else {
+ s->phy_status |= (MII_BMSR_LINK_ST | MII_BMSR_AN_COMP);
+ s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
+ }
+ phy_update_irq(s);
+}
+
+static void ftgmac100_set_link(NetClientState *nc)
+{
+ phy_update_link(FTGMAC100(qemu_get_nic_opaque(nc)));
+}
+
+static void phy_reset(FTGMAC100State *s)
+{
+ s->phy_status = (MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | MII_BMSR_10T_FD |
+ MII_BMSR_10T_HD | MII_BMSR_EXTSTAT | MII_BMSR_MFPS |
+ MII_BMSR_AN_COMP | MII_BMSR_AUTONEG | MII_BMSR_LINK_ST |
+ MII_BMSR_EXTCAP);
+ s->phy_control = (MII_BMCR_AUTOEN | MII_BMCR_FD | MII_BMCR_SPEED1000);
+ s->phy_advertise = (MII_ANAR_PAUSE_ASYM | MII_ANAR_PAUSE | MII_ANAR_TXFD |
+ MII_ANAR_TX | MII_ANAR_10FD | MII_ANAR_10 |
+ MII_ANAR_CSMACD);
+ s->phy_int_mask = 0;
+ s->phy_int = 0;
+}
+
+static uint32_t do_phy_read(FTGMAC100State *s, int reg)
+{
+ uint32_t val;
+
+ switch (reg) {
+ case MII_BMCR: /* Basic Control */
+ val = s->phy_control;
+ break;
+ case MII_BMSR: /* Basic Status */
+ val = s->phy_status;
+ break;
+ case MII_PHYID1: /* ID1 */
+ val = RTL8211E_PHYID1;
+ break;
+ case MII_PHYID2: /* ID2 */
+ val = RTL8211E_PHYID2;
+ break;
+ case MII_ANAR: /* Auto-neg advertisement */
+ val = s->phy_advertise;
+ break;
+ case MII_ANLPAR: /* Auto-neg Link Partner Ability */
+ val = (MII_ANLPAR_ACK | MII_ANLPAR_PAUSE | MII_ANLPAR_TXFD |
+ MII_ANLPAR_TX | MII_ANLPAR_10FD | MII_ANLPAR_10 |
+ MII_ANLPAR_CSMACD);
+ break;
+ case MII_ANER: /* Auto-neg Expansion */
+ val = MII_ANER_NWAY;
+ break;
+ case MII_CTRL1000: /* 1000BASE-T control */
+ val = (MII_CTRL1000_HALF | MII_CTRL1000_FULL);
+ break;
+ case MII_STAT1000: /* 1000BASE-T status */
+ val = MII_STAT1000_FULL;
+ break;
+ case RTL8211E_MII_INSR: /* Interrupt status. */
+ val = s->phy_int;
+ s->phy_int = 0;
+ phy_update_irq(s);
+ break;
+ case RTL8211E_MII_INER: /* Interrupt enable */
+ val = s->phy_int_mask;
+ break;
+ case RTL8211E_MII_PHYCR:
+ case RTL8211E_MII_PHYSR:
+ case RTL8211E_MII_RXERC:
+ case RTL8211E_MII_LDPSR:
+ case RTL8211E_MII_EPAGSR:
+ case RTL8211E_MII_PAGSEL:
+ qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n",
+ __func__, reg);
+ val = 0;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n",
+ __func__, reg);
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+#define MII_BMCR_MASK (MII_BMCR_LOOPBACK | MII_BMCR_SPEED100 | \
+ MII_BMCR_SPEED | MII_BMCR_AUTOEN | MII_BMCR_PDOWN | \
+ MII_BMCR_FD | MII_BMCR_CTST)
+#define MII_ANAR_MASK 0x2d7f
+
+static void do_phy_write(FTGMAC100State *s, int reg, uint32_t val)
+{
+ switch (reg) {
+ case MII_BMCR: /* Basic Control */
+ if (val & MII_BMCR_RESET) {
+ phy_reset(s);
+ } else {
+ s->phy_control = val & MII_BMCR_MASK;
+ /* Complete autonegotiation immediately. */
+ if (val & MII_BMCR_AUTOEN) {
+ s->phy_status |= MII_BMSR_AN_COMP;
+ }
+ }
+ break;
+ case MII_ANAR: /* Auto-neg advertisement */
+ s->phy_advertise = (val & MII_ANAR_MASK) | MII_ANAR_TX;
+ break;
+ case RTL8211E_MII_INER: /* Interrupt enable */
+ s->phy_int_mask = val & 0xff;
+ phy_update_irq(s);
+ break;
+ case RTL8211E_MII_PHYCR:
+ case RTL8211E_MII_PHYSR:
+ case RTL8211E_MII_RXERC:
+ case RTL8211E_MII_LDPSR:
+ case RTL8211E_MII_EPAGSR:
+ case RTL8211E_MII_PAGSEL:
+ qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n",
+ __func__, reg);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n",
+ __func__, reg);
+ break;
+ }
+}
+
+static int ftgmac100_read_bd(FTGMAC100Desc *bd, dma_addr_t addr)
+{
+ if (dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd))) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to read descriptor @ 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ return -1;
+ }
+ bd->des0 = le32_to_cpu(bd->des0);
+ bd->des1 = le32_to_cpu(bd->des1);
+ bd->des2 = le32_to_cpu(bd->des2);
+ bd->des3 = le32_to_cpu(bd->des3);
+ return 0;
+}
+
+static int ftgmac100_write_bd(FTGMAC100Desc *bd, dma_addr_t addr)
+{
+ FTGMAC100Desc lebd;
+
+ lebd.des0 = cpu_to_le32(bd->des0);
+ lebd.des1 = cpu_to_le32(bd->des1);
+ lebd.des2 = cpu_to_le32(bd->des2);
+ lebd.des3 = cpu_to_le32(bd->des3);
+ if (dma_memory_write(&address_space_memory, addr, &lebd, sizeof(lebd))) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to write descriptor @ 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ return -1;
+ }
+ return 0;
+}
+
+static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
+ uint32_t tx_descriptor)
+{
+ int frame_size = 0;
+ uint8_t *ptr = s->frame;
+ uint32_t addr = tx_descriptor;
+ uint32_t flags = 0;
+ int max_frame_size = ftgmac100_max_frame_size(s);
+
+ while (1) {
+ FTGMAC100Desc bd;
+ int len;
+
+ if (ftgmac100_read_bd(&bd, addr) ||
+ ((bd.des0 & FTGMAC100_TXDES0_TXDMA_OWN) == 0)) {
+ /* Run out of descriptors to transmit. */
+ s->isr |= FTGMAC100_INT_NO_NPTXBUF;
+ break;
+ }
+
+ /* record transmit flags as they are valid only on the first
+ * segment */
+ if (bd.des0 & FTGMAC100_TXDES0_FTS) {
+ flags = bd.des1;
+ }
+
+ len = bd.des0 & 0x3FFF;
+ if (frame_size + len > max_frame_size) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: frame too big : %d bytes\n",
+ __func__, len);
+ len = max_frame_size - frame_size;
+ }
+
+ if (dma_memory_read(&address_space_memory, bd.des3, ptr, len)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to read packet @ 0x%x\n",
+ __func__, bd.des3);
+ s->isr |= FTGMAC100_INT_NO_NPTXBUF;
+ break;
+ }
+
+ ptr += len;
+ frame_size += len;
+ if (bd.des0 & FTGMAC100_TXDES0_LTS) {
+ if (flags & FTGMAC100_TXDES1_IP_CHKSUM) {
+ net_checksum_calculate(s->frame, frame_size);
+ }
+ /* Last buffer in frame. */
+ qemu_send_packet(qemu_get_queue(s->nic), s->frame, frame_size);
+ ptr = s->frame;
+ frame_size = 0;
+ if (flags & FTGMAC100_TXDES1_TXIC) {
+ s->isr |= FTGMAC100_INT_XPKT_ETH;
+ }
+ }
+
+ if (flags & FTGMAC100_TXDES1_TX2FIC) {
+ s->isr |= FTGMAC100_INT_XPKT_FIFO;
+ }
+ bd.des0 &= ~FTGMAC100_TXDES0_TXDMA_OWN;
+
+ /* Write back the modified descriptor. */
+ ftgmac100_write_bd(&bd, addr);
+ /* Advance to the next descriptor. */
+ if (bd.des0 & s->txdes0_edotr) {
+ addr = tx_ring;
+ } else {
+ addr += sizeof(FTGMAC100Desc);
+ }
+ }
+
+ s->tx_descriptor = addr;
+
+ ftgmac100_update_irq(s);
+}
+
+static int ftgmac100_can_receive(NetClientState *nc)
+{
+ FTGMAC100State *s = FTGMAC100(qemu_get_nic_opaque(nc));
+ FTGMAC100Desc bd;
+
+ if ((s->maccr & (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN))
+ != (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN)) {
+ return 0;
+ }
+
+ if (ftgmac100_read_bd(&bd, s->rx_descriptor)) {
+ return 0;
+ }
+ return !(bd.des0 & FTGMAC100_RXDES0_RXPKT_RDY);
+}
+
+/*
+ * This is purely informative. The HW can poll the RW (and RX) ring
+ * buffers for available descriptors but we don't need to trigger a
+ * timer for that in qemu.
+ */
+static uint32_t ftgmac100_rxpoll(FTGMAC100State *s)
+{
+ /* Polling times :
+ *
+ * Speed TIME_SEL=0 TIME_SEL=1
+ *
+ * 10 51.2 ms 819.2 ms
+ * 100 5.12 ms 81.92 ms
+ * 1000 1.024 ms 16.384 ms
+ */
+ static const int div[] = { 20, 200, 1000 };
+
+ uint32_t cnt = 1024 * FTGMAC100_APTC_RXPOLL_CNT(s->aptcr);
+ uint32_t speed = (s->maccr & FTGMAC100_MACCR_FAST_MODE) ? 1 : 0;
+ uint32_t period;
+
+ if (s->aptcr & FTGMAC100_APTC_RXPOLL_TIME_SEL) {
+ cnt <<= 4;
+ }
+
+ if (s->maccr & FTGMAC100_MACCR_GIGA_MODE) {
+ speed = 2;
+ }
+
+ period = cnt / div[speed];
+
+ return period;
+}
+
+static void ftgmac100_reset(DeviceState *d)
+{
+ FTGMAC100State *s = FTGMAC100(d);
+
+ /* Reset the FTGMAC100 */
+ s->isr = 0;
+ s->ier = 0;
+ s->rx_enabled = 0;
+ s->rx_ring = 0;
+ s->rbsr = 0x640;
+ s->rx_descriptor = 0;
+ s->tx_ring = 0;
+ s->tx_descriptor = 0;
+ s->math[0] = 0;
+ s->math[1] = 0;
+ s->itc = 0;
+ s->aptcr = 1;
+ s->dblac = 0x00022f00;
+ s->revr = 0;
+ s->fear1 = 0;
+ s->tpafcr = 0xf1;
+
+ s->maccr = 0;
+ s->phycr = 0;
+ s->phydata = 0;
+ s->fcr = 0x400;
+
+ /* and the PHY */
+ phy_reset(s);
+}
+
+static uint64_t ftgmac100_read(void *opaque, hwaddr addr, unsigned size)
+{
+ FTGMAC100State *s = FTGMAC100(opaque);
+
+ switch (addr & 0xff) {
+ case FTGMAC100_ISR:
+ return s->isr;
+ case FTGMAC100_IER:
+ return s->ier;
+ case FTGMAC100_MAC_MADR:
+ return (s->conf.macaddr.a[0] << 8) | s->conf.macaddr.a[1];
+ case FTGMAC100_MAC_LADR:
+ return ((uint32_t) s->conf.macaddr.a[2] << 24) |
+ (s->conf.macaddr.a[3] << 16) | (s->conf.macaddr.a[4] << 8) |
+ s->conf.macaddr.a[5];
+ case FTGMAC100_MATH0:
+ return s->math[0];
+ case FTGMAC100_MATH1:
+ return s->math[1];
+ case FTGMAC100_ITC:
+ return s->itc;
+ case FTGMAC100_DBLAC:
+ return s->dblac;
+ case FTGMAC100_REVR:
+ return s->revr;
+ case FTGMAC100_FEAR1:
+ return s->fear1;
+ case FTGMAC100_TPAFCR:
+ return s->tpafcr;
+ case FTGMAC100_FCR:
+ return s->fcr;
+ case FTGMAC100_MACCR:
+ return s->maccr;
+ case FTGMAC100_PHYCR:
+ return s->phycr;
+ case FTGMAC100_PHYDATA:
+ return s->phydata;
+
+ /* We might want to support these one day */
+ case FTGMAC100_HPTXPD: /* High Priority Transmit Poll Demand */
+ case FTGMAC100_HPTXR_BADR: /* High Priority Transmit Ring Base Address */
+ case FTGMAC100_MACSR: /* MAC Status Register (MACSR) */
+ qemu_log_mask(LOG_UNIMP, "%s: read to unimplemented register 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ return 0;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ return 0;
+ }
+}
+
+static void ftgmac100_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ FTGMAC100State *s = FTGMAC100(opaque);
+ int reg;
+
+ switch (addr & 0xff) {
+ case FTGMAC100_ISR: /* Interrupt status */
+ s->isr &= ~value;
+ break;
+ case FTGMAC100_IER: /* Interrupt control */
+ s->ier = value;
+ break;
+ case FTGMAC100_MAC_MADR: /* MAC */
+ s->conf.macaddr.a[0] = value >> 8;
+ s->conf.macaddr.a[1] = value;
+ break;
+ case FTGMAC100_MAC_LADR:
+ s->conf.macaddr.a[2] = value >> 24;
+ s->conf.macaddr.a[3] = value >> 16;
+ s->conf.macaddr.a[4] = value >> 8;
+ s->conf.macaddr.a[5] = value;
+ break;
+ case FTGMAC100_MATH0: /* Multicast Address Hash Table 0 */
+ s->math[0] = value;
+ break;
+ case FTGMAC100_MATH1: /* Multicast Address Hash Table 1 */
+ s->math[1] = value;
+ break;
+ case FTGMAC100_ITC: /* TODO: Interrupt Timer Control */
+ s->itc = value;
+ break;
+ case FTGMAC100_RXR_BADR: /* Ring buffer address */
+ s->rx_ring = value;
+ s->rx_descriptor = s->rx_ring;
+ break;
+
+ case FTGMAC100_RBSR: /* DMA buffer size */
+ s->rbsr = value;
+ break;
+
+ case FTGMAC100_NPTXR_BADR: /* Transmit buffer address */
+ s->tx_ring = value;
+ s->tx_descriptor = s->tx_ring;
+ break;
+
+ case FTGMAC100_NPTXPD: /* Trigger transmit */
+ if ((s->maccr & (FTGMAC100_MACCR_TXDMA_EN | FTGMAC100_MACCR_TXMAC_EN))
+ == (FTGMAC100_MACCR_TXDMA_EN | FTGMAC100_MACCR_TXMAC_EN)) {
+ /* TODO: high priority tx ring */
+ ftgmac100_do_tx(s, s->tx_ring, s->tx_descriptor);
+ }
+ if (ftgmac100_can_receive(qemu_get_queue(s->nic))) {
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
+ }
+ break;
+
+ case FTGMAC100_RXPD: /* Receive Poll Demand Register */
+ if (ftgmac100_can_receive(qemu_get_queue(s->nic))) {
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
+ }
+ break;
+
+ case FTGMAC100_APTC: /* Automatic polling */
+ s->aptcr = value;
+
+ if (FTGMAC100_APTC_RXPOLL_CNT(s->aptcr)) {
+ ftgmac100_rxpoll(s);
+ }
+
+ if (FTGMAC100_APTC_TXPOLL_CNT(s->aptcr)) {
+ qemu_log_mask(LOG_UNIMP, "%s: no transmit polling\n", __func__);
+ }
+ break;
+
+ case FTGMAC100_MACCR: /* MAC Device control */
+ s->maccr = value;
+ if (value & FTGMAC100_MACCR_SW_RST) {
+ ftgmac100_reset(DEVICE(s));
+ }
+
+ if (ftgmac100_can_receive(qemu_get_queue(s->nic))) {
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
+ }
+ break;
+
+ case FTGMAC100_PHYCR: /* PHY Device control */
+ reg = FTGMAC100_PHYCR_REG(value);
+ s->phycr = value;
+ if (value & FTGMAC100_PHYCR_MIIWR) {
+ do_phy_write(s, reg, s->phydata & 0xffff);
+ s->phycr &= ~FTGMAC100_PHYCR_MIIWR;
+ } else {
+ s->phydata = do_phy_read(s, reg) << 16;
+ s->phycr &= ~FTGMAC100_PHYCR_MIIRD;
+ }
+ break;
+ case FTGMAC100_PHYDATA:
+ s->phydata = value & 0xffff;
+ break;
+ case FTGMAC100_DBLAC: /* DMA Burst Length and Arbitration Control */
+ s->dblac = value;
+ break;
+ case FTGMAC100_REVR: /* Feature Register */
+ /* TODO: Only Old MDIO interface is supported */
+ s->revr = value & ~FTGMAC100_REVR_NEW_MDIO_INTERFACE;
+ break;
+ case FTGMAC100_FEAR1: /* Feature Register 1 */
+ s->fear1 = value;
+ break;
+ case FTGMAC100_TPAFCR: /* Transmit Priority Arbitration and FIFO Control */
+ s->tpafcr = value;
+ break;
+ case FTGMAC100_FCR: /* Flow Control */
+ s->fcr = value;
+ break;
+
+ case FTGMAC100_HPTXPD: /* High Priority Transmit Poll Demand */
+ case FTGMAC100_HPTXR_BADR: /* High Priority Transmit Ring Base Address */
+ case FTGMAC100_MACSR: /* MAC Status Register (MACSR) */
+ qemu_log_mask(LOG_UNIMP, "%s: write to unimplemented register 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ break;
+ }
+
+ ftgmac100_update_irq(s);
+}
+
+static int ftgmac100_filter(FTGMAC100State *s, const uint8_t *buf, size_t len)
+{
+ unsigned mcast_idx;
+
+ if (s->maccr & FTGMAC100_MACCR_RX_ALL) {
+ return 1;
+ }
+
+ switch (get_eth_packet_type(PKT_GET_ETH_HDR(buf))) {
+ case ETH_PKT_BCAST:
+ if (!(s->maccr & FTGMAC100_MACCR_RX_BROADPKT)) {
+ return 0;
+ }
+ break;
+ case ETH_PKT_MCAST:
+ if (!(s->maccr & FTGMAC100_MACCR_RX_MULTIPKT)) {
+ if (!(s->maccr & FTGMAC100_MACCR_HT_MULTI_EN)) {
+ return 0;
+ }
+
+ /* TODO: this does not seem to work for ftgmac100 */
+ mcast_idx = compute_mcast_idx(buf);
+ if (!(s->math[mcast_idx / 32] & (1 << (mcast_idx % 32)))) {
+ return 0;
+ }
+ }
+ break;
+ case ETH_PKT_UCAST:
+ if (memcmp(s->conf.macaddr.a, buf, 6)) {
+ return 0;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf,
+ size_t len)
+{
+ FTGMAC100State *s = FTGMAC100(qemu_get_nic_opaque(nc));
+ FTGMAC100Desc bd;
+ uint32_t flags = 0;
+ uint32_t addr;
+ uint32_t crc;
+ uint32_t buf_addr;
+ uint8_t *crc_ptr;
+ uint32_t buf_len;
+ size_t size = len;
+ uint32_t first = FTGMAC100_RXDES0_FRS;
+ int max_frame_size = ftgmac100_max_frame_size(s);
+
+ if ((s->maccr & (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN))
+ != (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN)) {
+ return -1;
+ }
+
+ /* TODO : Pad to minimum Ethernet frame length */
+ /* handle small packets. */
+ if (size < 10) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: dropped frame of %zd bytes\n",
+ __func__, size);
+ return size;
+ }
+
+ if (size < 64 && !(s->maccr & FTGMAC100_MACCR_RX_RUNT)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: dropped runt frame of %zd bytes\n",
+ __func__, size);
+ return size;
+ }
+
+ if (!ftgmac100_filter(s, buf, size)) {
+ return size;
+ }
+
+ /* 4 bytes for the CRC. */
+ size += 4;
+ crc = cpu_to_be32(crc32(~0, buf, size));
+ crc_ptr = (uint8_t *) &crc;
+
+ /* Huge frames are truncated. */
+ if (size > max_frame_size) {
+ size = max_frame_size;
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: frame too big : %zd bytes\n",
+ __func__, size);
+ flags |= FTGMAC100_RXDES0_FTL;
+ }
+
+ switch (get_eth_packet_type(PKT_GET_ETH_HDR(buf))) {
+ case ETH_PKT_BCAST:
+ flags |= FTGMAC100_RXDES0_BROADCAST;
+ break;
+ case ETH_PKT_MCAST:
+ flags |= FTGMAC100_RXDES0_MULTICAST;
+ break;
+ case ETH_PKT_UCAST:
+ break;
+ }
+
+ addr = s->rx_descriptor;
+ while (size > 0) {
+ if (!ftgmac100_can_receive(nc)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Unexpected packet\n", __func__);
+ return -1;
+ }
+
+ if (ftgmac100_read_bd(&bd, addr) ||
+ (bd.des0 & FTGMAC100_RXDES0_RXPKT_RDY)) {
+ /* No descriptors available. Bail out. */
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Lost end of frame\n",
+ __func__);
+ s->isr |= FTGMAC100_INT_NO_RXBUF;
+ break;
+ }
+ buf_len = (size <= s->rbsr) ? size : s->rbsr;
+ bd.des0 |= buf_len & 0x3fff;
+ size -= buf_len;
+
+ /* The last 4 bytes are the CRC. */
+ if (size < 4) {
+ buf_len += size - 4;
+ }
+ buf_addr = bd.des3;
+ dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
+ buf += buf_len;
+ if (size < 4) {
+ dma_memory_write(&address_space_memory, buf_addr + buf_len,
+ crc_ptr, 4 - size);
+ crc_ptr += 4 - size;
+ }
+
+ bd.des0 |= first | FTGMAC100_RXDES0_RXPKT_RDY;
+ first = 0;
+ if (size == 0) {
+ /* Last buffer in frame. */
+ bd.des0 |= flags | FTGMAC100_RXDES0_LRS;
+ s->isr |= FTGMAC100_INT_RPKT_BUF;
+ } else {
+ s->isr |= FTGMAC100_INT_RPKT_FIFO;
+ }
+ ftgmac100_write_bd(&bd, addr);
+ if (bd.des0 & s->rxdes0_edorr) {
+ addr = s->rx_ring;
+ } else {
+ addr += sizeof(FTGMAC100Desc);
+ }
+ }
+ s->rx_descriptor = addr;
+
+ ftgmac100_update_irq(s);
+ return len;
+}
+
+static const MemoryRegionOps ftgmac100_ops = {
+ .read = ftgmac100_read,
+ .write = ftgmac100_write,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ftgmac100_cleanup(NetClientState *nc)
+{
+ FTGMAC100State *s = FTGMAC100(qemu_get_nic_opaque(nc));
+
+ s->nic = NULL;
+}
+
+static NetClientInfo net_ftgmac100_info = {
+ .type = NET_CLIENT_DRIVER_NIC,
+ .size = sizeof(NICState),
+ .can_receive = ftgmac100_can_receive,
+ .receive = ftgmac100_receive,
+ .cleanup = ftgmac100_cleanup,
+ .link_status_changed = ftgmac100_set_link,
+};
+
+static void ftgmac100_realize(DeviceState *dev, Error **errp)
+{
+ FTGMAC100State *s = FTGMAC100(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ if (s->aspeed) {
+ s->txdes0_edotr = FTGMAC100_TXDES0_EDOTR_ASPEED;
+ s->rxdes0_edorr = FTGMAC100_RXDES0_EDORR_ASPEED;
+ } else {
+ s->txdes0_edotr = FTGMAC100_TXDES0_EDOTR;
+ s->rxdes0_edorr = FTGMAC100_RXDES0_EDORR;
+ }
+
+ memory_region_init_io(&s->iomem, OBJECT(dev), &ftgmac100_ops, s,
+ TYPE_FTGMAC100, 0x2000);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_init_irq(sbd, &s->irq);
+ qemu_macaddr_default_if_unset(&s->conf.macaddr);
+
+ s->conf.peers.ncs[0] = nd_table[0].netdev;
+
+ s->nic = qemu_new_nic(&net_ftgmac100_info, &s->conf,
+ object_get_typename(OBJECT(dev)), DEVICE(dev)->id,
+ s);
+ qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+
+ s->frame = g_malloc(FTGMAC100_MAX_FRAME_SIZE);
+}
+
+static const VMStateDescription vmstate_ftgmac100 = {
+ .name = TYPE_FTGMAC100,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(irq_state, FTGMAC100State),
+ VMSTATE_UINT32(isr, FTGMAC100State),
+ VMSTATE_UINT32(ier, FTGMAC100State),
+ VMSTATE_UINT32(rx_enabled, FTGMAC100State),
+ VMSTATE_UINT32(rx_ring, FTGMAC100State),
+ VMSTATE_UINT32(rbsr, FTGMAC100State),
+ VMSTATE_UINT32(tx_ring, FTGMAC100State),
+ VMSTATE_UINT32(rx_descriptor, FTGMAC100State),
+ VMSTATE_UINT32(tx_descriptor, FTGMAC100State),
+ VMSTATE_UINT32_ARRAY(math, FTGMAC100State, 2),
+ VMSTATE_UINT32(itc, FTGMAC100State),
+ VMSTATE_UINT32(aptcr, FTGMAC100State),
+ VMSTATE_UINT32(dblac, FTGMAC100State),
+ VMSTATE_UINT32(revr, FTGMAC100State),
+ VMSTATE_UINT32(fear1, FTGMAC100State),
+ VMSTATE_UINT32(tpafcr, FTGMAC100State),
+ VMSTATE_UINT32(maccr, FTGMAC100State),
+ VMSTATE_UINT32(phycr, FTGMAC100State),
+ VMSTATE_UINT32(phydata, FTGMAC100State),
+ VMSTATE_UINT32(fcr, FTGMAC100State),
+ VMSTATE_UINT32(phy_status, FTGMAC100State),
+ VMSTATE_UINT32(phy_control, FTGMAC100State),
+ VMSTATE_UINT32(phy_advertise, FTGMAC100State),
+ VMSTATE_UINT32(phy_int, FTGMAC100State),
+ VMSTATE_UINT32(phy_int_mask, FTGMAC100State),
+ VMSTATE_UINT32(txdes0_edotr, FTGMAC100State),
+ VMSTATE_UINT32(rxdes0_edorr, FTGMAC100State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property ftgmac100_properties[] = {
+ DEFINE_PROP_BOOL("aspeed", FTGMAC100State, aspeed, false),
+ DEFINE_NIC_PROPERTIES(FTGMAC100State, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ftgmac100_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_ftgmac100;
+ dc->reset = ftgmac100_reset;
+ dc->props = ftgmac100_properties;
+ set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
+ dc->realize = ftgmac100_realize;
+ dc->desc = "Faraday FTGMAC100 Gigabit Ethernet emulation";
+}
+
+static const TypeInfo ftgmac100_info = {
+ .name = TYPE_FTGMAC100,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(FTGMAC100State),
+ .class_init = ftgmac100_class_init,
+};
+
+static void ftgmac100_register_types(void)
+{
+ type_register_static(&ftgmac100_info);
+}
+
+type_init(ftgmac100_register_types)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index c32168077a..7d091c9259 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -510,6 +510,10 @@ static int peer_attach(VirtIONet *n, int index)
return 0;
}
+ if (n->max_queues == 1) {
+ return 0;
+ }
+
return tap_enable(nc->peer);
}
diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c
index 467cbb9cb8..27fde46126 100644
--- a/hw/pci-host/versatile.c
+++ b/hw/pci-host/versatile.c
@@ -380,20 +380,8 @@ static void pci_vpb_reset(DeviceState *d)
static void pci_vpb_init(Object *obj)
{
- PCIHostState *h = PCI_HOST_BRIDGE(obj);
PCIVPBState *s = PCI_VPB(obj);
- memory_region_init(&s->pci_io_space, OBJECT(s), "pci_io", 1ULL << 32);
- memory_region_init(&s->pci_mem_space, OBJECT(s), "pci_mem", 1ULL << 32);
-
- pci_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), DEVICE(obj), "pci",
- &s->pci_mem_space, &s->pci_io_space,
- PCI_DEVFN(11, 0), TYPE_PCI_BUS);
- h->bus = &s->pci_bus;
-
- object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_VERSATILE_PCI_HOST);
- qdev_set_parent_bus(DEVICE(&s->pci_dev), BUS(&s->pci_bus));
-
/* Window sizes for VersatilePB; realview_pci's init will override */
s->mem_win_size[0] = 0x0c000000;
s->mem_win_size[1] = 0x10000000;
@@ -403,10 +391,22 @@ static void pci_vpb_init(Object *obj)
static void pci_vpb_realize(DeviceState *dev, Error **errp)
{
PCIVPBState *s = PCI_VPB(dev);
+ PCIHostState *h = PCI_HOST_BRIDGE(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
pci_map_irq_fn mapfn;
int i;
+ memory_region_init(&s->pci_io_space, OBJECT(s), "pci_io", 1ULL << 32);
+ memory_region_init(&s->pci_mem_space, OBJECT(s), "pci_mem", 1ULL << 32);
+
+ pci_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), dev, "pci",
+ &s->pci_mem_space, &s->pci_io_space,
+ PCI_DEVFN(11, 0), TYPE_PCI_BUS);
+ h->bus = &s->pci_bus;
+
+ object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_VERSATILE_PCI_HOST);
+ qdev_set_parent_bus(DEVICE(&s->pci_dev), BUS(&s->pci_bus));
+
for (i = 0; i < 4; i++) {
sysbus_init_irq(sbd, &s->irq[i]);
}
@@ -503,8 +503,6 @@ static void pci_vpb_class_init(ObjectClass *klass, void *data)
dc->reset = pci_vpb_reset;
dc->vmsd = &pci_vpb_vmstate;
dc->props = pci_vpb_properties;
- /* Reason: object_unref() hangs */
- dc->cannot_destroy_with_object_finalize_yet = true;
}
static const TypeInfo pci_vpb_info = {
@@ -526,19 +524,10 @@ static void pci_realview_init(Object *obj)
s->mem_win_size[2] = 0x08000000;
}
-static void pci_realview_class_init(ObjectClass *class, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(class);
-
- /* Reason: object_unref() hangs */
- dc->cannot_destroy_with_object_finalize_yet = true;
-}
-
static const TypeInfo pci_realview_info = {
.name = "realview_pci",
.parent = TYPE_VERSATILE_PCI,
.instance_init = pci_realview_init,
- .class_init = pci_realview_class_init,
};
static void versatile_pci_register_types(void)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index e6b08e1988..259483b1c0 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -869,6 +869,10 @@ static void do_pci_unregister_device(PCIDevice *pci_dev)
pci_dev->bus->devices[pci_dev->devfn] = NULL;
pci_config_free(pci_dev);
+ if (memory_region_is_mapped(&pci_dev->bus_master_enable_region)) {
+ memory_region_del_subregion(&pci_dev->bus_master_container_region,
+ &pci_dev->bus_master_enable_region);
+ }
address_space_destroy(&pci_dev->bus_master_as);
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 6ee566d658..35db949dbc 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1524,16 +1524,16 @@ static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr,
/* Consume invalid HPTEs */
while ((index < htabslots)
&& !HPTE_VALID(HPTE(spapr->htab, index))) {
- index++;
CLEAN_HPTE(HPTE(spapr->htab, index));
+ index++;
}
/* Consume valid HPTEs */
chunkstart = index;
while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
&& HPTE_VALID(HPTE(spapr->htab, index))) {
- index++;
CLEAN_HPTE(HPTE(spapr->htab, index));
+ index++;
}
if (index > chunkstart) {
@@ -2790,6 +2790,12 @@ static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
goto out;
}
+ if (cc->nr_threads != smp_threads) {
+ error_setg(errp, "invalid nr-threads %d, must be %d",
+ cc->nr_threads, smp_threads);
+ return;
+ }
+
core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
if (!core_slot) {
error_setg(&local_err, "core id %d out of range", cc->core_id);
@@ -3096,6 +3102,11 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
xic->ics_resend = spapr_ics_resend;
xic->icp_get = spapr_icp_get;
ispc->print_info = spapr_pic_print_info;
+ /* Force NUMA node memory size to be a multiple of
+ * SPAPR_MEMORY_BLOCK_SIZE (256M) since that's the granularity
+ * in which LMBs are represented and hot-added
+ */
+ mc->numa_mem_align_shift = 28;
}
static const TypeInfo spapr_machine_info = {
@@ -3180,6 +3191,7 @@ static void spapr_machine_2_8_class_options(MachineClass *mc)
{
spapr_machine_2_9_class_options(mc);
SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_8);
+ mc->numa_mem_align_shift = 23;
}
DEFINE_SPAPR_MACHINE(2_8, "2.8", false);
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index 150f6bf2c7..a1cdc875b1 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -135,6 +135,17 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc,
if (!drc->dev) {
return RTAS_OUT_NO_SUCH_INDICATOR;
}
+ if (drc->awaiting_release && drc->awaiting_allocation) {
+ /* kernel is acknowledging a previous hotplug event
+ * while we are already removing it.
+ * it's safe to ignore awaiting_allocation here since we know the
+ * situation is predicated on the guest either already having done
+ * so (boot-time hotplug), or never being able to acquire in the
+ * first place (hotplug followed by immediate unplug).
+ */
+ drc->awaiting_allocation_skippable = true;
+ return RTAS_OUT_NO_SUCH_INDICATOR;
+ }
}
if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI) {
@@ -436,9 +447,11 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d,
}
if (drc->awaiting_allocation) {
- drc->awaiting_release = true;
- trace_spapr_drc_awaiting_allocation(get_index(drc));
- return;
+ if (!drc->awaiting_allocation_skippable) {
+ drc->awaiting_release = true;
+ trace_spapr_drc_awaiting_allocation(get_index(drc));
+ return;
+ }
}
drc->indicator_state = SPAPR_DR_INDICATOR_STATE_INACTIVE;
@@ -448,6 +461,7 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d,
}
drc->awaiting_release = false;
+ drc->awaiting_allocation_skippable = false;
g_free(drc->fdt);
drc->fdt = NULL;
drc->fdt_start_offset = 0;
diff --git a/hw/s390x/ccw-device.c b/hw/s390x/ccw-device.c
index 28ea20440e..fb8d640a7e 100644
--- a/hw/s390x/ccw-device.c
+++ b/hw/s390x/ccw-device.c
@@ -11,11 +11,51 @@
#include "qemu/osdep.h"
#include "ccw-device.h"
+static void ccw_device_refill_ids(CcwDevice *dev)
+{
+ SubchDev *sch = dev->sch;
+
+ assert(sch);
+
+ dev->dev_id.cssid = sch->cssid;
+ dev->dev_id.ssid = sch->ssid;
+ dev->dev_id.devid = sch->devno;
+ dev->dev_id.valid = true;
+
+ dev->subch_id.cssid = sch->cssid;
+ dev->subch_id.ssid = sch->ssid;
+ dev->subch_id.devid = sch->schid;
+ dev->subch_id.valid = true;
+}
+
+static void ccw_device_realize(CcwDevice *dev, Error **errp)
+{
+ ccw_device_refill_ids(dev);
+}
+
+static Property ccw_device_properties[] = {
+ DEFINE_PROP_CSS_DEV_ID("devno", CcwDevice, devno),
+ DEFINE_PROP_CSS_DEV_ID_RO("dev_id", CcwDevice, dev_id),
+ DEFINE_PROP_CSS_DEV_ID_RO("subch_id", CcwDevice, subch_id),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ccw_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ CCWDeviceClass *k = CCW_DEVICE_CLASS(klass);
+
+ k->realize = ccw_device_realize;
+ k->refill_ids = ccw_device_refill_ids;
+ dc->props = ccw_device_properties;
+}
+
static const TypeInfo ccw_device_info = {
.name = TYPE_CCW_DEVICE,
.parent = TYPE_DEVICE,
.instance_size = sizeof(CcwDevice),
.class_size = sizeof(CCWDeviceClass),
+ .class_init = ccw_device_class_init,
.abstract = true,
};
diff --git a/hw/s390x/ccw-device.h b/hw/s390x/ccw-device.h
index 59ba01b6c5..89c8e5dff7 100644
--- a/hw/s390x/ccw-device.h
+++ b/hw/s390x/ccw-device.h
@@ -19,12 +19,19 @@ typedef struct CcwDevice {
DeviceState parent_obj;
SubchDev *sch;
/* <cssid>.<ssid>.<device number> */
- CssDevId bus_id;
+ /* The user-set busid of the virtual ccw device. */
+ CssDevId devno;
+ /* The actual busid of the virtual ccw device. */
+ CssDevId dev_id;
+ /* The actual busid of the virtual subchannel. */
+ CssDevId subch_id;
} CcwDevice;
typedef struct CCWDeviceClass {
DeviceClass parent_class;
void (*unplug)(HotplugHandler *, DeviceState *, Error **);
+ void (*realize)(CcwDevice *, Error **);
+ void (*refill_ids)(CcwDevice *);
} CCWDeviceClass;
static inline CcwDevice *to_ccw_dev_fast(DeviceState *d)
diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c
index 9a7f7ee60c..b54ac01d37 100644
--- a/hw/s390x/css-bridge.c
+++ b/hw/s390x/css-bridge.c
@@ -107,6 +107,9 @@ VirtualCssBus *virtual_css_bus_init(void)
/* Enable hotplugging */
qbus_set_hotplug_handler(bus, dev, &error_abort);
+ css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false,
+ &error_abort);
+
return cbus;
}
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 37caa98195..c03bb20bc9 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -47,7 +47,6 @@ typedef struct IoAdapter {
uint32_t id;
uint8_t type;
uint8_t isc;
- QTAILQ_ENTRY(IoAdapter) sibling;
} IoAdapter;
typedef struct ChannelSubSys {
@@ -61,7 +60,7 @@ typedef struct ChannelSubSys {
uint64_t chnmon_area;
CssImage *css[MAX_CSSID + 1];
uint8_t default_cssid;
- QTAILQ_HEAD(, IoAdapter) io_adapters;
+ IoAdapter *io_adapters[CSS_IO_ADAPTER_TYPE_NUMS][MAX_ISC + 1];
QTAILQ_HEAD(, IndAddr) indicator_addresses;
} ChannelSubSys;
@@ -72,7 +71,6 @@ static ChannelSubSys channel_subsys = {
.do_crw_mchk = true,
.crws_lost = false,
.chnmon_active = false,
- .io_adapters = QTAILQ_HEAD_INITIALIZER(channel_subsys.io_adapters),
.indicator_addresses =
QTAILQ_HEAD_INITIALIZER(channel_subsys.indicator_addresses),
};
@@ -155,44 +153,67 @@ int css_create_css_image(uint8_t cssid, bool default_image)
return 0;
}
-int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap,
- bool maskable, uint32_t *id)
+uint32_t css_get_adapter_id(CssIoAdapterType type, uint8_t isc)
{
+ if (type >= CSS_IO_ADAPTER_TYPE_NUMS || isc > MAX_ISC ||
+ !channel_subsys.io_adapters[type][isc]) {
+ return -1;
+ }
+
+ return channel_subsys.io_adapters[type][isc]->id;
+}
+
+/**
+ * css_register_io_adapters: Register I/O adapters per ISC during init
+ *
+ * @swap: an indication if byte swap is needed.
+ * @maskable: an indication if the adapter is subject to the mask operation.
+ * @errp: location to store error information.
+ */
+void css_register_io_adapters(CssIoAdapterType type, bool swap, bool maskable,
+ Error **errp)
+{
+ uint32_t id;
+ int ret, isc;
IoAdapter *adapter;
- bool found = false;
- int ret;
S390FLICState *fs = s390_get_flic();
S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
- *id = 0;
- QTAILQ_FOREACH(adapter, &channel_subsys.io_adapters, sibling) {
- if ((adapter->type == type) && (adapter->isc == isc)) {
- *id = adapter->id;
- found = true;
- ret = 0;
+ /*
+ * Disallow multiple registrations for the same device type.
+ * Report an error if registering for an already registered type.
+ */
+ if (channel_subsys.io_adapters[type][0]) {
+ error_setg(errp, "Adapters for type %d already registered", type);
+ }
+
+ for (isc = 0; isc <= MAX_ISC; isc++) {
+ id = (type << 3) | isc;
+ ret = fsc->register_io_adapter(fs, id, isc, swap, maskable);
+ if (ret == 0) {
+ adapter = g_new0(IoAdapter, 1);
+ adapter->id = id;
+ adapter->isc = isc;
+ adapter->type = type;
+ channel_subsys.io_adapters[type][isc] = adapter;
+ } else {
+ error_setg_errno(errp, -ret, "Unexpected error %d when "
+ "registering adapter %d", ret, id);
break;
}
- if (adapter->id >= *id) {
- *id = adapter->id + 1;
- }
- }
- if (found) {
- goto out;
}
- adapter = g_new0(IoAdapter, 1);
- ret = fsc->register_io_adapter(fs, *id, isc, swap, maskable);
- if (ret == 0) {
- adapter->id = *id;
- adapter->isc = isc;
- adapter->type = type;
- QTAILQ_INSERT_TAIL(&channel_subsys.io_adapters, adapter, sibling);
- } else {
- g_free(adapter);
- fprintf(stderr, "Unexpected error %d when registering adapter %d\n",
- ret, *id);
+
+ /*
+ * No need to free registered adapters in kvm: kvm will clean up
+ * when the machine goes away.
+ */
+ if (ret) {
+ for (isc--; isc >= 0; isc--) {
+ g_free(channel_subsys.io_adapters[type][isc]);
+ channel_subsys.io_adapters[type][isc] = NULL;
+ }
}
-out:
- return ret;
+
}
static void css_clear_io_interrupt(uint16_t subchannel_id,
@@ -1894,6 +1915,13 @@ PropertyInfo css_devid_propinfo = {
.set = set_css_devid,
};
+PropertyInfo css_devid_ro_propinfo = {
+ .name = "str",
+ .description = "Read-only identifier of an I/O device in the channel "
+ "subsystem, example: fe.1.23ab",
+ .get = get_css_devid,
+};
+
SubchDev *css_create_virtual_sch(CssDevId bus_id, Error **errp)
{
uint16_t schid = 0;
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 69b0291e8a..a8a1bab50a 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -23,15 +23,17 @@
#include "hw/pci/msi.h"
#include "qemu/error-report.h"
-/* #define DEBUG_S390PCI_BUS */
-#ifdef DEBUG_S390PCI_BUS
-#define DPRINTF(fmt, ...) \
- do { fprintf(stderr, "S390pci-bus: " fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
- do { } while (0)
+#ifndef DEBUG_S390PCI_BUS
+#define DEBUG_S390PCI_BUS 0
#endif
+#define DPRINTF(fmt, ...) \
+ do { \
+ if (DEBUG_S390PCI_BUS) { \
+ fprintf(stderr, "S390pci-bus: " fmt, ## __VA_ARGS__); \
+ } \
+ } while (0)
+
S390pciState *s390_get_phb(void)
{
static S390pciState *phb;
@@ -579,6 +581,9 @@ static int s390_pcihost_init(SysBusDevice *dev)
s->bus_no = 0;
QTAILQ_INIT(&s->pending_sei);
QTAILQ_INIT(&s->zpci_devs);
+
+ css_register_io_adapters(CSS_IO_ADAPTER_PCI, true, false, &error_abort);
+
return 0;
}
diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h
index dcbf4820c9..cf142a3e68 100644
--- a/hw/s390x/s390-pci-bus.h
+++ b/hw/s390x/s390-pci-bus.h
@@ -30,7 +30,6 @@
#define FH_MASK_INDEX 0x0000ffff
#define FH_SHM_VFIO 0x00010000
#define FH_SHM_EMUL 0x00020000
-#define S390_PCIPT_ADAPTER 2
#define ZPCI_MAX_FID 0xffffffff
#define ZPCI_MAX_UID 0xffff
#define UID_UNDEFINED 0
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index d2a8c0a083..314a9cbad4 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -20,15 +20,17 @@
#include "qemu/error-report.h"
#include "sysemu/hw_accel.h"
-/* #define DEBUG_S390PCI_INST */
-#ifdef DEBUG_S390PCI_INST
-#define DPRINTF(fmt, ...) \
- do { fprintf(stderr, "s390pci-inst: " fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
- do { } while (0)
+#ifndef DEBUG_S390PCI_INST
+#define DEBUG_S390PCI_INST 0
#endif
+#define DPRINTF(fmt, ...) \
+ do { \
+ if (DEBUG_S390PCI_INST) { \
+ fprintf(stderr, "s390pci-inst: " fmt, ## __VA_ARGS__); \
+ } \
+ } while (0)
+
static void s390_set_status_code(CPUS390XState *env,
uint8_t r, uint64_t status_code)
{
@@ -731,12 +733,10 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
{
int ret, len;
+ uint8_t isc = FIB_DATA_ISC(ldl_p(&fib.data));
- ret = css_register_io_adapter(S390_PCIPT_ADAPTER,
- FIB_DATA_ISC(ldl_p(&fib.data)), true, false,
- &pbdev->routes.adapter.adapter_id);
- assert(ret == 0);
-
+ pbdev->routes.adapter.adapter_id = css_get_adapter_id(
+ CSS_IO_ADAPTER_PCI, isc);
pbdev->summary_ind = get_indicator(ldq_p(&fib.aisb), sizeof(uint64_t));
len = BITS_TO_LONGS(FIB_DATA_NOI(ldl_p(&fib.data))) * sizeof(unsigned long);
pbdev->indicator = get_indicator(ldq_p(&fib.aibv), len);
@@ -755,7 +755,7 @@ static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_p(&fib.data));
pbdev->routes.adapter.ind_addr = ldq_p(&fib.aibv);
pbdev->routes.adapter.ind_offset = FIB_DATA_AIBVO(ldl_p(&fib.data));
- pbdev->isc = FIB_DATA_ISC(ldl_p(&fib.data));
+ pbdev->isc = isc;
pbdev->noi = FIB_DATA_NOI(ldl_p(&fib.data));
pbdev->sum = FIB_DATA_SUM(ldl_p(&fib.data));
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 40914fde6f..04bd0ebe40 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -113,12 +113,13 @@ static void ccw_init(MachineState *machine)
s390_sclp_init();
s390_memory_init(machine->ram_size);
+ s390_flic_init();
+
/* get a BUS */
css_bus = virtual_css_bus_init();
s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
machine->initrd_filename, "s390-ccw.img",
"s390-netboot.img", true);
- s390_flic_init();
dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE);
object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE,
@@ -336,6 +337,9 @@ static const TypeInfo ccw_machine_info = {
} \
type_init(ccw_machine_register_##suffix)
+#define CCW_COMPAT_2_9 \
+ HW_COMPAT_2_9
+
#define CCW_COMPAT_2_8 \
HW_COMPAT_2_8 \
{\
@@ -402,14 +406,26 @@ static const TypeInfo ccw_machine_info = {
.value = "0",\
},
+static void ccw_machine_2_10_instance_options(MachineState *machine)
+{
+}
+
+static void ccw_machine_2_10_class_options(MachineClass *mc)
+{
+}
+DEFINE_CCW_MACHINE(2_10, "2.10", true);
+
static void ccw_machine_2_9_instance_options(MachineState *machine)
{
+ ccw_machine_2_10_instance_options(machine);
}
static void ccw_machine_2_9_class_options(MachineClass *mc)
{
+ ccw_machine_2_10_class_options(mc);
+ SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_9);
}
-DEFINE_CCW_MACHINE(2_9, "2.9", true);
+DEFINE_CCW_MACHINE(2_9, "2.9", false);
static void ccw_machine_2_8_instance_options(MachineState *machine)
{
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 00b3bde4e9..e7167e3d05 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -616,10 +616,9 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
dev->routes.adapter.ind_offset = ind_bit;
dev->routes.adapter.summary_offset = 7;
cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len);
- ret = css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO,
- dev->thinint_isc, true, false,
- &dev->routes.adapter.adapter_id);
- assert(ret == 0);
+ dev->routes.adapter.adapter_id = css_get_adapter_id(
+ CSS_IO_ADAPTER_VIRTIO,
+ dev->thinint_isc);
sch->thinint_active = ((dev->indicators != NULL) &&
(dev->summary_indicator != NULL));
sch->curr_status.scsw.count = ccw.count - len;
@@ -680,7 +679,8 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
{
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
CcwDevice *ccw_dev = CCW_DEVICE(dev);
- SubchDev *sch = css_create_virtual_sch(ccw_dev->bus_id, errp);
+ CCWDeviceClass *ck = CCW_DEVICE_GET_CLASS(ccw_dev);
+ SubchDev *sch = css_create_virtual_sch(ccw_dev->devno, errp);
Error *err = NULL;
if (!sch) {
@@ -689,8 +689,7 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
if (!virtio_ccw_rev_max(dev) && dev->force_revision_1) {
error_setg(&err, "Invalid value of property max_rev "
"(is %d expected >= 1)", virtio_ccw_rev_max(dev));
- error_propagate(errp, err);
- return;
+ goto out_err;
}
sch->driver_data = dev;
@@ -705,7 +704,7 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
trace_virtio_ccw_new_device(
sch->cssid, sch->ssid, sch->schid, sch->devno,
- ccw_dev->bus_id.valid ? "user-configured" : "auto-configured");
+ ccw_dev->devno.valid ? "user-configured" : "auto-configured");
if (!kvm_eventfds_enabled()) {
dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD;
@@ -713,13 +712,23 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
if (k->realize) {
k->realize(dev, &err);
+ if (err) {
+ goto out_err;
+ }
}
+
+ ck->realize(ccw_dev, &err);
if (err) {
- error_propagate(errp, err);
- css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
- ccw_dev->sch = NULL;
- g_free(sch);
+ goto out_err;
}
+
+ return;
+
+out_err:
+ error_propagate(errp, err);
+ css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
+ ccw_dev->sch = NULL;
+ g_free(sch);
}
static int virtio_ccw_exit(VirtioCcwDevice *dev)
@@ -1261,12 +1270,17 @@ static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
{
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
CcwDevice *ccw_dev = CCW_DEVICE(d);
+ CCWDeviceClass *ck = CCW_DEVICE_GET_CLASS(ccw_dev);
SubchDev *s = ccw_dev->sch;
VirtIODevice *vdev = virtio_ccw_get_vdev(s);
int len;
s->driver_data = dev;
subch_device_load(s, f);
+ /* Re-fill subch_id after loading the subchannel states.*/
+ if (ck->refill_ids) {
+ ck->refill_ids(ccw_dev);
+ }
len = qemu_get_be32(f);
if (len != 0) {
dev->indicators = get_indicator(qemu_get_be64(f), len);
@@ -1293,9 +1307,9 @@ static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
dev->thinint_isc = qemu_get_byte(f);
dev->revision = qemu_get_be32(f);
if (s->thinint_active) {
- return css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO,
- dev->thinint_isc, true, false,
- &dev->routes.adapter.adapter_id);
+ dev->routes.adapter.adapter_id = css_get_adapter_id(
+ CSS_IO_ADAPTER_VIRTIO,
+ dev->thinint_isc);
}
return 0;
@@ -1354,7 +1368,6 @@ static void virtio_ccw_device_unplugged(DeviceState *d)
/**************** Virtio-ccw Bus Device Descriptions *******************/
static Property virtio_ccw_net_properties[] = {
- DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1383,7 +1396,6 @@ static const TypeInfo virtio_ccw_net = {
};
static Property virtio_ccw_blk_properties[] = {
- DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1412,7 +1424,6 @@ static const TypeInfo virtio_ccw_blk = {
};
static Property virtio_ccw_serial_properties[] = {
- DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1441,7 +1452,6 @@ static const TypeInfo virtio_ccw_serial = {
};
static Property virtio_ccw_balloon_properties[] = {
- DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1470,7 +1480,6 @@ static const TypeInfo virtio_ccw_balloon = {
};
static Property virtio_ccw_scsi_properties[] = {
- DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1500,7 +1509,6 @@ static const TypeInfo virtio_ccw_scsi = {
#ifdef CONFIG_VHOST_SCSI
static Property vhost_ccw_scsi_properties[] = {
- DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
@@ -1538,7 +1546,6 @@ static void virtio_ccw_rng_instance_init(Object *obj)
}
static Property virtio_ccw_rng_properties[] = {
- DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1567,7 +1574,6 @@ static const TypeInfo virtio_ccw_rng = {
};
static Property virtio_ccw_crypto_properties[] = {
- DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1694,7 +1700,6 @@ static const TypeInfo virtio_ccw_bus_info = {
#ifdef CONFIG_VIRTFS
static Property virtio_ccw_9p_properties[] = {
- DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1743,7 +1748,6 @@ static const TypeInfo virtio_ccw_9p_info = {
#ifdef CONFIG_VHOST_VSOCK
static Property vhost_vsock_ccw_properties[] = {
- DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
@@ -1757,9 +1761,7 @@ static void vhost_vsock_ccw_realize(VirtioCcwDevice *ccw_dev, Error **errp)
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- }
+ error_propagate(errp, err);
}
static void vhost_vsock_ccw_class_init(ObjectClass *klass, void *data)
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index e3d59b7c83..84b8caf901 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -291,7 +291,7 @@ static int megasas_map_sgl(MegasasState *s, MegasasCmd *cmd, union mfi_sgl *sgl)
if (cmd->iov_size > iov_size) {
trace_megasas_iovec_overflow(cmd->index, iov_size, cmd->iov_size);
} else if (cmd->iov_size < iov_size) {
- trace_megasas_iovec_underflow(cmd->iov_size, iov_size, cmd->iov_size);
+ trace_megasas_iovec_underflow(cmd->index, iov_size, cmd->iov_size);
}
cmd->iov_offset = 0;
return 0;
@@ -1924,8 +1924,8 @@ static int megasas_handle_abort(MegasasState *s, MegasasCmd *cmd)
abort_ctx &= (uint64_t)0xFFFFFFFF;
}
if (abort_cmd->context != abort_ctx) {
- trace_megasas_abort_invalid_context(cmd->index, abort_cmd->index,
- abort_cmd->context);
+ trace_megasas_abort_invalid_context(cmd->index, abort_cmd->context,
+ abort_cmd->index);
s->event_count++;
return MFI_STAT_ABORT_NOT_POSSIBLE;
}
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index 2933119e7d..a55ff87c22 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -237,9 +237,8 @@ static void scsi_read_complete(void * opaque, int ret)
assert(max_transfer);
stl_be_p(&r->buf[8], max_transfer);
/* Also take care of the opt xfer len. */
- if (ldl_be_p(&r->buf[12]) > max_transfer) {
- stl_be_p(&r->buf[12], max_transfer);
- }
+ stl_be_p(&r->buf[12],
+ MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
}
scsi_req_data(&r->req, len);
scsi_req_unref(&r->req);
diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index c491ece1f2..f53bc179da 100644
--- a/hw/scsi/vhost-scsi.c
+++ b/hw/scsi/vhost-scsi.c
@@ -233,9 +233,11 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
}
}
- virtio_scsi_common_realize(dev, &err, vhost_dummy_handle_output,
+ virtio_scsi_common_realize(dev,
vhost_dummy_handle_output,
- vhost_dummy_handle_output);
+ vhost_dummy_handle_output,
+ vhost_dummy_handle_output,
+ &err);
if (err != NULL) {
error_propagate(errp, err);
goto close_fd;
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index 74c95e0e60..944ea4eb53 100644
--- a/hw/scsi/virtio-scsi-dataplane.c
+++ b/hw/scsi/virtio-scsi-dataplane.c
@@ -52,28 +52,40 @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
static bool virtio_scsi_data_plane_handle_cmd(VirtIODevice *vdev,
VirtQueue *vq)
{
- VirtIOSCSI *s = (VirtIOSCSI *)vdev;
+ bool progress;
+ VirtIOSCSI *s = VIRTIO_SCSI(vdev);
+ virtio_scsi_acquire(s);
assert(s->ctx && s->dataplane_started);
- return virtio_scsi_handle_cmd_vq(s, vq);
+ progress = virtio_scsi_handle_cmd_vq(s, vq);
+ virtio_scsi_release(s);
+ return progress;
}
static bool virtio_scsi_data_plane_handle_ctrl(VirtIODevice *vdev,
VirtQueue *vq)
{
+ bool progress;
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
+ virtio_scsi_acquire(s);
assert(s->ctx && s->dataplane_started);
- return virtio_scsi_handle_ctrl_vq(s, vq);
+ progress = virtio_scsi_handle_ctrl_vq(s, vq);
+ virtio_scsi_release(s);
+ return progress;
}
static bool virtio_scsi_data_plane_handle_event(VirtIODevice *vdev,
VirtQueue *vq)
{
+ bool progress;
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
+ virtio_scsi_acquire(s);
assert(s->ctx && s->dataplane_started);
- return virtio_scsi_handle_event_vq(s, vq);
+ progress = virtio_scsi_handle_event_vq(s, vq);
+ virtio_scsi_release(s);
+ return progress;
}
static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n,
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 1dbc4bced9..46a3e3f280 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -422,31 +422,15 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req)
}
}
-static inline void virtio_scsi_acquire(VirtIOSCSI *s)
-{
- if (s->ctx) {
- aio_context_acquire(s->ctx);
- }
-}
-
-static inline void virtio_scsi_release(VirtIOSCSI *s)
-{
- if (s->ctx) {
- aio_context_release(s->ctx);
- }
-}
-
bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
{
VirtIOSCSIReq *req;
bool progress = false;
- virtio_scsi_acquire(s);
while ((req = virtio_scsi_pop_req(s, vq))) {
progress = true;
virtio_scsi_handle_ctrl_req(s, req);
}
- virtio_scsi_release(s);
return progress;
}
@@ -460,7 +444,9 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
return;
}
}
+ virtio_scsi_acquire(s);
virtio_scsi_handle_ctrl_vq(s, vq);
+ virtio_scsi_release(s);
}
static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req)
@@ -604,7 +590,6 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
- virtio_scsi_acquire(s);
do {
virtio_queue_set_notification(vq, 0);
@@ -632,7 +617,6 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
QTAILQ_FOREACH_SAFE(req, &reqs, next, next) {
virtio_scsi_handle_cmd_req_submit(s, req);
}
- virtio_scsi_release(s);
return progress;
}
@@ -647,7 +631,9 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
return;
}
}
+ virtio_scsi_acquire(s);
virtio_scsi_handle_cmd_vq(s, vq);
+ virtio_scsi_release(s);
}
static void virtio_scsi_get_config(VirtIODevice *vdev,
@@ -723,12 +709,10 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
return;
}
- virtio_scsi_acquire(s);
-
req = virtio_scsi_pop_req(s, vs->event_vq);
if (!req) {
s->events_dropped = true;
- goto out;
+ return;
}
if (s->events_dropped) {
@@ -738,7 +722,7 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
if (virtio_scsi_parse_req(req, 0, sizeof(VirtIOSCSIEvent))) {
virtio_scsi_bad_req(req);
- goto out;
+ return;
}
evt = &req->resp.event;
@@ -758,19 +742,14 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
evt->lun[3] = dev->lun & 0xFF;
}
virtio_scsi_complete_req(req);
-out:
- virtio_scsi_release(s);
}
bool virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq)
{
- virtio_scsi_acquire(s);
if (s->events_dropped) {
virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
- virtio_scsi_release(s);
return true;
}
- virtio_scsi_release(s);
return false;
}
@@ -784,7 +763,9 @@ static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq)
return;
}
}
+ virtio_scsi_acquire(s);
virtio_scsi_handle_event_vq(s, vq);
+ virtio_scsi_release(s);
}
static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
@@ -794,8 +775,10 @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_CHANGE) &&
dev->type != TYPE_ROM) {
+ virtio_scsi_acquire(s);
virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE,
sense.asc | (sense.ascq << 8));
+ virtio_scsi_release(s);
}
}
@@ -817,9 +800,11 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
}
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
+ virtio_scsi_acquire(s);
virtio_scsi_push_event(s, sd,
VIRTIO_SCSI_T_TRANSPORT_RESET,
VIRTIO_SCSI_EVT_RESET_RESCAN);
+ virtio_scsi_release(s);
}
}
@@ -831,9 +816,11 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
SCSIDevice *sd = SCSI_DEVICE(dev);
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
+ virtio_scsi_acquire(s);
virtio_scsi_push_event(s, sd,
VIRTIO_SCSI_T_TRANSPORT_RESET,
VIRTIO_SCSI_EVT_RESET_REMOVED);
+ virtio_scsi_release(s);
}
qdev_simple_device_unplug_cb(hotplug_dev, dev, errp);
@@ -854,10 +841,11 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = {
.load_request = virtio_scsi_load_request,
};
-void virtio_scsi_common_realize(DeviceState *dev, Error **errp,
+void virtio_scsi_common_realize(DeviceState *dev,
VirtIOHandleOutput ctrl,
VirtIOHandleOutput evt,
- VirtIOHandleOutput cmd)
+ VirtIOHandleOutput cmd,
+ Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev);
@@ -891,9 +879,11 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
VirtIOSCSI *s = VIRTIO_SCSI(dev);
Error *err = NULL;
- virtio_scsi_common_realize(dev, &err, virtio_scsi_handle_ctrl,
+ virtio_scsi_common_realize(dev,
+ virtio_scsi_handle_ctrl,
virtio_scsi_handle_event,
- virtio_scsi_handle_cmd);
+ virtio_scsi_handle_cmd,
+ &err);
if (err != NULL) {
error_propagate(errp, err);
return;
diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c
index 6d06968f8b..8f520cec1c 100644
--- a/hw/sh4/r2d.c
+++ b/hw/sh4/r2d.c
@@ -277,8 +277,15 @@ static void r2d_init(MachineState *machine)
sysbus_connect_irq(busdev, 2, irq[PCI_INTC]);
sysbus_connect_irq(busdev, 3, irq[PCI_INTD]);
- sm501_init(address_space_mem, 0x10000000, SM501_VRAM_SIZE,
- irq[SM501], serial_hds[2]);
+ dev = qdev_create(NULL, "sysbus-sm501");
+ busdev = SYS_BUS_DEVICE(dev);
+ qdev_prop_set_uint32(dev, "vram-size", SM501_VRAM_SIZE);
+ qdev_prop_set_uint32(dev, "base", 0x10000000);
+ qdev_prop_set_ptr(dev, "chr-state", serial_hds[2]);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(busdev, 0, 0x10000000);
+ sysbus_mmio_map(busdev, 1, 0x13e00000);
+ sysbus_connect_irq(busdev, 0, irq[SM501]);
/* onboard CF (True IDE mode, Master only). */
dinfo = drive_get(IF_IDE, 0, 0);
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 873cd7df9a..5f022cc08d 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -491,7 +491,6 @@ static void tcx_init(hwaddr addr, qemu_irq irq, int vram_size, int width,
qdev_prop_set_uint16(dev, "width", width);
qdev_prop_set_uint16(dev, "height", height);
qdev_prop_set_uint16(dev, "depth", depth);
- qdev_prop_set_uint64(dev, "prom_addr", addr);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
@@ -544,7 +543,6 @@ static void cg3_init(hwaddr addr, qemu_irq irq, int vram_size, int width,
qdev_prop_set_uint16(dev, "width", width);
qdev_prop_set_uint16(dev, "height", height);
qdev_prop_set_uint16(dev, "depth", depth);
- qdev_prop_set_uint64(dev, "prom-addr", addr);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c
index 0c189348ae..a2ec3920f8 100644
--- a/hw/timer/exynos4210_mct.c
+++ b/hw/timer/exynos4210_mct.c
@@ -53,6 +53,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "hw/sysbus.h"
#include "qemu/timer.h"
#include "qemu/main-loop.h"
@@ -1372,8 +1373,9 @@ break;
case L0_TCNTO: case L1_TCNTO:
case L0_ICNTO: case L1_ICNTO:
case L0_FRCNTO: case L1_FRCNTO:
- fprintf(stderr, "\n[exynos4210.mct: write to RO register "
- TARGET_FMT_plx "]\n\n", offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "exynos4210.mct: write to RO register " TARGET_FMT_plx,
+ offset);
break;
case L0_INT_CSTAT: case L1_INT_CSTAT:
diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c
index f5765075c7..87f63f057e 100644
--- a/hw/timer/exynos4210_pwm.c
+++ b/hw/timer/exynos4210_pwm.c
@@ -21,6 +21,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "hw/sysbus.h"
#include "qemu/timer.h"
#include "qemu-common.h"
@@ -252,9 +253,9 @@ static uint64_t exynos4210_pwm_read(void *opaque, hwaddr offset,
break;
default:
- fprintf(stderr,
- "[exynos4210.pwm: bad read offset " TARGET_FMT_plx "]\n",
- offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "exynos4210.pwm: bad read offset " TARGET_FMT_plx,
+ offset);
break;
}
return value;
@@ -343,9 +344,9 @@ static void exynos4210_pwm_write(void *opaque, hwaddr offset,
break;
default:
- fprintf(stderr,
- "[exynos4210.pwm: bad write offset " TARGET_FMT_plx "]\n",
- offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "exynos4210.pwm: bad write offset " TARGET_FMT_plx,
+ offset);
break;
}
diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c
index 1a648c5d9e..4607833e3e 100644
--- a/hw/timer/exynos4210_rtc.c
+++ b/hw/timer/exynos4210_rtc.c
@@ -26,6 +26,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "hw/sysbus.h"
#include "qemu/timer.h"
#include "qemu-common.h"
@@ -370,9 +371,9 @@ static uint64_t exynos4210_rtc_read(void *opaque, hwaddr offset,
break;
default:
- fprintf(stderr,
- "[exynos4210.rtc: bad read offset " TARGET_FMT_plx "]\n",
- offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "exynos4210.rtc: bad read offset " TARGET_FMT_plx,
+ offset);
break;
}
return value;
@@ -433,9 +434,9 @@ static void exynos4210_rtc_write(void *opaque, hwaddr offset,
if (value > TICNT_THRESHOLD) {
s->reg_ticcnt = value;
} else {
- fprintf(stderr,
- "[exynos4210.rtc: bad TICNT value %u ]\n",
- (uint32_t)value);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "exynos4210.rtc: bad TICNT value %u",
+ (uint32_t)value);
}
break;
@@ -500,9 +501,9 @@ static void exynos4210_rtc_write(void *opaque, hwaddr offset,
break;
default:
- fprintf(stderr,
- "[exynos4210.rtc: bad write offset " TARGET_FMT_plx "]\n",
- offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "exynos4210.rtc: bad write offset " TARGET_FMT_plx,
+ offset);
break;
}
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index 24f1608b4b..5939b273b9 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -762,9 +762,7 @@ static void usb_set_attached(Object *obj, bool value, Error **errp)
if (value) {
usb_device_attach(dev, &err);
- if (err) {
- error_propagate(errp, err);
- }
+ error_propagate(errp, err);
} else {
usb_device_detach(dev);
}
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index f0af852709..a2d3143bf4 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -2063,7 +2063,7 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
{
XHCIState *xhci = epctx->xhci;
- XHCIStreamContext *stctx;
+ XHCIStreamContext *stctx = NULL;
XHCITransfer *xfer;
XHCIRing *ring;
USBEndpoint *ep = NULL;
@@ -2186,6 +2186,8 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
break;
}
}
+ /* update ring dequeue ptr */
+ xhci_set_ep_state(xhci, epctx, stctx, epctx->state);
epctx->kick_active--;
ep = xhci_epid_to_usbep(epctx);
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index c9876a5b0f..f9c8eafe06 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -159,7 +159,10 @@ static void usb_host_attach_kernel(USBHostDevice *s);
#define BULK_TIMEOUT 0 /* unlimited */
#define INTR_TIMEOUT 0 /* unlimited */
-#if LIBUSBX_API_VERSION >= 0x01000103
+#ifndef LIBUSB_API_VERSION
+# define LIBUSB_API_VERSION LIBUSBX_API_VERSION
+#endif
+#if LIBUSB_API_VERSION >= 0x01000103
# define HAVE_STREAMS 1
#endif
@@ -269,7 +272,7 @@ static int usb_host_get_port(libusb_device *dev, char *port, size_t len)
size_t off;
int rc, i;
-#if LIBUSBX_API_VERSION >= 0x01000102
+#if LIBUSB_API_VERSION >= 0x01000102
rc = libusb_get_port_numbers(dev, path, 7);
#else
rc = libusb_get_port_path(ctx, dev, path, 7);
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index f3ba9b9007..6b33b9f55d 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -478,8 +478,13 @@ static void vfio_listener_region_add(MemoryListener *listener,
giommu->iommu_offset = section->offset_within_address_space -
section->offset_within_region;
giommu->container = container;
- giommu->n.notify = vfio_iommu_map_notify;
- giommu->n.notifier_flags = IOMMU_NOTIFIER_ALL;
+ llend = int128_add(int128_make64(section->offset_within_region),
+ section->size);
+ llend = int128_sub(llend, int128_one());
+ iommu_notifier_init(&giommu->n, vfio_iommu_map_notify,
+ IOMMU_NOTIFIER_ALL,
+ section->offset_within_region,
+ int128_get64(llend));
QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
memory_region_register_iommu_notifier(giommu->iommu, &giommu->n);
@@ -550,7 +555,8 @@ static void vfio_listener_region_del(MemoryListener *listener,
VFIOGuestIOMMU *giommu;
QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) {
- if (giommu->iommu == section->mr) {
+ if (giommu->iommu == section->mr &&
+ giommu->n.start == section->offset_within_region) {
memory_region_unregister_iommu_notifier(giommu->iommu,
&giommu->n);
QLIST_REMOVE(giommu, giommu_next);
diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
index e995e32dee..349085ea12 100644
--- a/hw/vfio/pci-quirks.c
+++ b/hw/vfio/pci-quirks.c
@@ -660,7 +660,7 @@ static void vfio_probe_nvidia_bar5_quirk(VFIOPCIDevice *vdev, int nr)
VFIOConfigWindowQuirk *window;
if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) ||
- !vdev->vga || nr != 5) {
+ !vdev->vga || nr != 5 || !vdev->bars[5].ioport) {
return;
}
@@ -1367,45 +1367,14 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
uint16_t cmd_orig, cmd;
Error *err = NULL;
- /* This must be an Intel VGA device. */
- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
- !vfio_is_vga(vdev) || nr != 4) {
- return;
- }
-
- /*
- * IGD is not a standard, they like to change their specs often. We
- * only attempt to support back to SandBridge and we hope that newer
- * devices maintain compatibility with generation 8.
- */
- gen = igd_gen(vdev);
- if (gen != 6 && gen != 8) {
- error_report("IGD device %s is unsupported by IGD quirks, "
- "try SandyBridge or newer", vdev->vbasedev.name);
- return;
- }
-
- /*
- * Regardless of running in UPT or legacy mode, the guest graphics
- * driver may attempt to use stolen memory, however only legacy mode
- * has BIOS support for reserving stolen memory in the guest VM.
- * Emulate the GMCH register in all cases and zero out the stolen
- * memory size here. Legacy mode may request allocation and re-write
- * this below.
- */
- gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4);
- gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8));
-
- /* GMCH is read-only, emulated */
- pci_set_long(vdev->pdev.config + IGD_GMCH, gmch);
- pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0);
- pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0);
-
/*
- * This must be at address 00:02.0 for us to even onsider enabling
- * legacy mode. The vBIOS has dependencies on the PCI bus address.
+ * This must be an Intel VGA device at address 00:02.0 for us to even
+ * consider enabling legacy mode. The vBIOS has dependencies on the
+ * PCI bus address.
*/
- if (&vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev),
+ if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
+ !vfio_is_vga(vdev) || nr != 4 ||
+ &vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev),
0, PCI_DEVFN(0x2, 0))) {
return;
}
@@ -1425,6 +1394,18 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
}
/*
+ * IGD is not a standard, they like to change their specs often. We
+ * only attempt to support back to SandBridge and we hope that newer
+ * devices maintain compatibility with generation 8.
+ */
+ gen = igd_gen(vdev);
+ if (gen != 6 && gen != 8) {
+ error_report("IGD device %s is unsupported in legacy mode, "
+ "try SandyBridge or newer", vdev->vbasedev.name);
+ return;
+ }
+
+ /*
* Most of what we're doing here is to enable the ROM to run, so if
* there's no ROM, there's no point in setting up this quirk.
* NB. We only seem to get BIOS ROMs, so a UEFI VM would need CSM support.
@@ -1479,6 +1460,8 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
goto out;
}
+ gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4);
+
/*
* If IGD VGA Disable is clear (expected) and VGA is not already enabled,
* try to enable it. Probably shouldn't be using legacy mode without VGA,
@@ -1549,11 +1532,12 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
* when IVD (IGD VGA Disable) is clear, but the claim is that it's unused,
* so let's not waste VM memory for it.
*/
+ gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8));
+
if (vdev->igd_gms) {
if (vdev->igd_gms <= 0x10) {
gms_mb = vdev->igd_gms * 32;
gmch |= vdev->igd_gms << (gen < 8 ? 3 : 8);
- pci_set_long(vdev->pdev.config + IGD_GMCH, gmch);
} else {
error_report("Unsupported IGD GMS value 0x%x", vdev->igd_gms);
vdev->igd_gms = 0;
@@ -1573,6 +1557,11 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
fw_cfg_add_file(fw_cfg_find(), "etc/igd-bdsm-size",
bdsm_size, sizeof(*bdsm_size));
+ /* GMCH is read-only, emulated */
+ pci_set_long(vdev->pdev.config + IGD_GMCH, gmch);
+ pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0);
+ pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0);
+
/* BDSM is read-write, emulated. The BIOS needs to be able to write it */
pci_set_long(vdev->pdev.config + IGD_BDSM, 0);
pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0);
diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index 6926eedd3f..1f7a7c1ae1 100644
--- a/hw/virtio/trace-events
+++ b/hw/virtio/trace-events
@@ -11,8 +11,11 @@ virtio_set_status(void *vdev, uint8_t val) "vdev %p val %u"
# hw/virtio/virtio-rng.c
virtio_rng_guest_not_ready(void *rng) "rng %p: guest not ready"
+virtio_rng_cpu_is_stopped(void *rng, int size) "rng %p: cpu is stopped, dropping %d bytes"
+virtio_rng_popped(void *rng) "rng %p: elem popped"
virtio_rng_pushed(void *rng, size_t len) "rng %p: %zd bytes pushed"
virtio_rng_request(void *rng, size_t size, unsigned quota) "rng %p: %zd bytes requested, %u bytes quota left"
+virtio_rng_vm_state_change(void *rng, int running, int state) "rng %p: state change to running %d state %d"
# hw/virtio/virtio-balloon.c
#
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index febe519bbd..0001e60b77 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -425,10 +425,8 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size)
static int vhost_dev_has_iommu(struct vhost_dev *dev)
{
VirtIODevice *vdev = dev->vdev;
- AddressSpace *dma_as = vdev->dma_as;
- return memory_region_is_iommu(dma_as->root) &&
- virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
+ return virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
}
static void *vhost_memory_map(struct vhost_dev *dev, hwaddr addr,
@@ -720,6 +718,70 @@ static void vhost_region_del(MemoryListener *listener,
}
}
+static void vhost_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
+{
+ struct vhost_iommu *iommu = container_of(n, struct vhost_iommu, n);
+ struct vhost_dev *hdev = iommu->hdev;
+ hwaddr iova = iotlb->iova + iommu->iommu_offset;
+
+ if (hdev->vhost_ops->vhost_invalidate_device_iotlb(hdev, iova,
+ iotlb->addr_mask + 1)) {
+ error_report("Fail to invalidate device iotlb");
+ }
+}
+
+static void vhost_iommu_region_add(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ struct vhost_dev *dev = container_of(listener, struct vhost_dev,
+ iommu_listener);
+ struct vhost_iommu *iommu;
+ Int128 end;
+
+ if (!memory_region_is_iommu(section->mr)) {
+ return;
+ }
+
+ iommu = g_malloc0(sizeof(*iommu));
+ end = int128_add(int128_make64(section->offset_within_region),
+ section->size);
+ end = int128_sub(end, int128_one());
+ iommu_notifier_init(&iommu->n, vhost_iommu_unmap_notify,
+ IOMMU_NOTIFIER_UNMAP,
+ section->offset_within_region,
+ int128_get64(end));
+ iommu->mr = section->mr;
+ iommu->iommu_offset = section->offset_within_address_space -
+ section->offset_within_region;
+ iommu->hdev = dev;
+ memory_region_register_iommu_notifier(section->mr, &iommu->n);
+ QLIST_INSERT_HEAD(&dev->iommu_list, iommu, iommu_next);
+ /* TODO: can replay help performance here? */
+}
+
+static void vhost_iommu_region_del(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ struct vhost_dev *dev = container_of(listener, struct vhost_dev,
+ iommu_listener);
+ struct vhost_iommu *iommu;
+
+ if (!memory_region_is_iommu(section->mr)) {
+ return;
+ }
+
+ QLIST_FOREACH(iommu, &dev->iommu_list, iommu_next) {
+ if (iommu->mr == section->mr &&
+ iommu->n.start == section->offset_within_region) {
+ memory_region_unregister_iommu_notifier(iommu->mr,
+ &iommu->n);
+ QLIST_REMOVE(iommu, iommu_next);
+ g_free(iommu);
+ break;
+ }
+ }
+}
+
static void vhost_region_nop(MemoryListener *listener,
MemoryRegionSection *section)
{
@@ -1161,17 +1223,6 @@ static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq)
event_notifier_cleanup(&vq->masked_notifier);
}
-static void vhost_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
-{
- struct vhost_dev *hdev = container_of(n, struct vhost_dev, n);
-
- if (hdev->vhost_ops->vhost_invalidate_device_iotlb(hdev,
- iotlb->iova,
- iotlb->addr_mask + 1)) {
- error_report("Fail to invalidate device iotlb");
- }
-}
-
int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
VhostBackendType backend_type, uint32_t busyloop_timeout)
{
@@ -1244,8 +1295,10 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
.priority = 10
};
- hdev->n.notify = vhost_iommu_unmap_notify;
- hdev->n.notifier_flags = IOMMU_NOTIFIER_UNMAP;
+ hdev->iommu_listener = (MemoryListener) {
+ .region_add = vhost_iommu_region_add,
+ .region_del = vhost_iommu_region_del,
+ };
if (hdev->migration_blocker == NULL) {
if (!(hdev->features & (0x1ULL << VHOST_F_LOG_ALL))) {
@@ -1455,8 +1508,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
}
if (vhost_dev_has_iommu(hdev)) {
- memory_region_register_iommu_notifier(vdev->dma_as->root,
- &hdev->n);
+ memory_listener_register(&hdev->iommu_listener, vdev->dma_as);
}
r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem);
@@ -1538,8 +1590,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
if (vhost_dev_has_iommu(hdev)) {
hdev->vhost_ops->vhost_set_iotlb_callback(hdev, false);
- memory_region_unregister_iommu_notifier(vdev->dma_as->root,
- &hdev->n);
+ memory_listener_unregister(&hdev->iommu_listener);
}
vhost_log_put(hdev, true);
hdev->started = false;
diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c
index a886011e75..3042232daf 100644
--- a/hw/virtio/virtio-bus.c
+++ b/hw/virtio/virtio-bus.c
@@ -25,6 +25,7 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "qemu/error-report.h"
+#include "qapi/error.h"
#include "hw/qdev.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio.h"
@@ -48,20 +49,33 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp)
VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
bool has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
+ Error *local_err = NULL;
DPRINTF("%s: plug device.\n", qbus->name);
if (klass->pre_plugged != NULL) {
- klass->pre_plugged(qbus->parent, errp);
+ klass->pre_plugged(qbus->parent, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
}
/* Get the features of the plugged device. */
assert(vdc->get_features != NULL);
vdev->host_features = vdc->get_features(vdev, vdev->host_features,
- errp);
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
if (klass->device_plugged != NULL) {
- klass->device_plugged(qbus->parent, errp);
+ klass->device_plugged(qbus->parent, &local_err);
+ }
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
}
if (klass->get_dma_as != NULL && has_iommu) {
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index 9639f4e89b..a6ee501051 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -53,6 +53,15 @@ static void chr_read(void *opaque, const void *buf, size_t size)
return;
}
+ /* we can't modify the virtqueue until
+ * our state is fully synced
+ */
+
+ if (!runstate_check(RUN_STATE_RUNNING)) {
+ trace_virtio_rng_cpu_is_stopped(vrng, size);
+ return;
+ }
+
vrng->quota_remaining -= size;
offset = 0;
@@ -61,6 +70,7 @@ static void chr_read(void *opaque, const void *buf, size_t size)
if (!elem) {
break;
}
+ trace_virtio_rng_popped(vrng);
len = iov_from_buf(elem->in_sg, elem->in_num,
0, buf + offset, size - offset);
offset += len;
@@ -120,17 +130,21 @@ static uint64_t get_features(VirtIODevice *vdev, uint64_t f, Error **errp)
return f;
}
-static int virtio_rng_post_load(void *opaque, int version_id)
+static void virtio_rng_vm_state_change(void *opaque, int running,
+ RunState state)
{
VirtIORNG *vrng = opaque;
+ trace_virtio_rng_vm_state_change(vrng, running, state);
+
/* We may have an element ready but couldn't process it due to a quota
- * limit. Make sure to try again after live migration when the quota may
- * have been reset.
+ * limit or because CPU was stopped. Make sure to try again when the
+ * CPU restart.
*/
- virtio_rng_process(vrng);
- return 0;
+ if (running && is_guest_ready(vrng)) {
+ virtio_rng_process(vrng);
+ }
}
static void check_rate_limit(void *opaque)
@@ -198,6 +212,9 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
vrng->rate_limit_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
check_rate_limit, vrng);
vrng->activate_timer = true;
+
+ vrng->vmstate = qemu_add_vm_change_state_handler(virtio_rng_vm_state_change,
+ vrng);
}
static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp)
@@ -205,6 +222,7 @@ static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp)
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIORNG *vrng = VIRTIO_RNG(dev);
+ qemu_del_vm_change_state_handler(vrng->vmstate);
timer_del(vrng->rate_limit_timer);
timer_free(vrng->rate_limit_timer);
virtio_cleanup(vdev);
@@ -218,7 +236,6 @@ static const VMStateDescription vmstate_virtio_rng = {
VMSTATE_VIRTIO_DEVICE,
VMSTATE_END_OF_LIST()
},
- .post_load = virtio_rng_post_load,
};
static Property virtio_rng_properties[] = {
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 82b6060b2a..03592c542a 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1528,7 +1528,18 @@ static void virtio_queue_notify_vq(VirtQueue *vq)
void virtio_queue_notify(VirtIODevice *vdev, int n)
{
- virtio_queue_notify_vq(&vdev->vq[n]);
+ VirtQueue *vq = &vdev->vq[n];
+
+ if (unlikely(!vq->vring.desc || vdev->broken)) {
+ return;
+ }
+
+ trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
+ if (vq->handle_aio_output) {
+ event_notifier_set(&vq->host_notifier);
+ } else if (vq->handle_output) {
+ vq->handle_output(vdev, vq);
+ }
}
uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)