aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/acpi/Kconfig7
-rw-r--r--hw/acpi/Makefile.objs1
-rw-r--r--hw/acpi/hmat.c268
-rw-r--r--hw/acpi/hmat.h42
-rw-r--r--hw/arm/omap1.c8
-rw-r--r--hw/arm/omap2.c25
-rw-r--r--hw/block/virtio-blk.c18
-rw-r--r--hw/char/omap_uart.c2
-rw-r--r--hw/char/serial-isa.c12
-rw-r--r--hw/char/serial-pci-multi.c55
-rw-r--r--hw/char/serial-pci.c18
-rw-r--r--hw/char/serial.c186
-rw-r--r--hw/char/virtio-serial-bus.c8
-rw-r--r--hw/core/machine.c68
-rw-r--r--hw/core/numa.c297
-rw-r--r--hw/core/qdev-properties.c18
-rw-r--r--hw/core/qdev.c15
-rw-r--r--hw/core/sysbus.c32
-rw-r--r--hw/cris/axis_dev88.c4
-rw-r--r--hw/display/sm501.c31
-rw-r--r--hw/dma/sparc32_dma.c2
-rw-r--r--hw/gpio/omap_gpio.c42
-rw-r--r--hw/i2c/omap_i2c.c19
-rw-r--r--hw/i2c/smbus_eeprom.c18
-rw-r--r--hw/i386/acpi-build.c5
-rw-r--r--hw/i386/intel_iommu.c100
-rw-r--r--hw/i386/intel_iommu_internal.h1
-rw-r--r--hw/i386/pc.c7
-rw-r--r--hw/i386/vmmouse.c8
-rw-r--r--hw/input/pckbd.c8
-rw-r--r--hw/input/virtio-input.c5
-rw-r--r--hw/intc/etraxfs_pic.c26
-rw-r--r--hw/intc/grlib_irqmp.c35
-rw-r--r--hw/intc/omap_intc.c17
-rw-r--r--hw/intc/pnv_xive.c18
-rw-r--r--hw/intc/spapr_xive.c14
-rw-r--r--hw/intc/spapr_xive_kvm.c9
-rw-r--r--hw/intc/xive.c28
-rw-r--r--hw/m68k/q800.c38
-rw-r--r--hw/mips/boston.c2
-rw-r--r--hw/mips/cps.c2
-rw-r--r--hw/mips/mips_jazz.c3
-rw-r--r--hw/mips/mips_malta.c2
-rw-r--r--hw/mips/mips_mipssim.c14
-rw-r--r--hw/misc/mac_via.c339
-rw-r--r--hw/misc/mos6522.c16
-rw-r--r--hw/misc/trace-events19
-rw-r--r--hw/net/dp8393x.c7
-rw-r--r--hw/net/etraxfs_eth.c44
-rw-r--r--hw/net/lance.c5
-rw-r--r--hw/net/pcnet-pci.c2
-rw-r--r--hw/net/pcnet.h2
-rw-r--r--hw/net/virtio-net.c3
-rw-r--r--hw/pci/pci_host.c25
-rw-r--r--hw/ppc/pnv.c123
-rw-r--r--hw/ppc/pnv_bmc.c8
-rw-r--r--hw/ppc/pnv_pnor.c10
-rw-r--r--hw/ppc/pnv_psi.c41
-rw-r--r--hw/ppc/ppc440_bamboo.c8
-rw-r--r--hw/ppc/spapr.c18
-rw-r--r--hw/ppc/spapr_irq.c2
-rw-r--r--hw/scsi/vhost-scsi.c2
-rw-r--r--hw/scsi/vhost-user-scsi.c24
-rw-r--r--hw/scsi/virtio-scsi.c19
-rw-r--r--hw/semihosting/console.c79
-rw-r--r--hw/sh4/r2d.c2
-rw-r--r--hw/sparc/leon3.c15
-rw-r--r--hw/vfio/pci.c4
-rw-r--r--hw/virtio/vhost-user.c8
-rw-r--r--hw/virtio/virtio-balloon.c7
-rw-r--r--hw/virtio/virtio-mmio.c17
-rw-r--r--hw/virtio/virtio-pci.c14
-rw-r--r--hw/virtio/virtio.c64
73 files changed, 1855 insertions, 610 deletions
diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig
index 12e3f1e86e..54209c6f2f 100644
--- a/hw/acpi/Kconfig
+++ b/hw/acpi/Kconfig
@@ -7,6 +7,7 @@ config ACPI_X86
select ACPI_NVDIMM
select ACPI_CPU_HOTPLUG
select ACPI_MEMORY_HOTPLUG
+ select ACPI_HMAT
config ACPI_X86_ICH
bool
@@ -23,6 +24,10 @@ config ACPI_NVDIMM
bool
depends on ACPI
+config ACPI_HMAT
+ bool
+ depends on ACPI
+
config ACPI_PCI
bool
depends on ACPI && PCI
@@ -33,5 +38,3 @@ config ACPI_VMGENID
depends on PC
config ACPI_HW_REDUCED
- bool
- depends on ACPI
diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
index 99253057e1..777da07f4d 100644
--- a/hw/acpi/Makefile.objs
+++ b/hw/acpi/Makefile.objs
@@ -7,6 +7,7 @@ common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o
common-obj-$(CONFIG_ACPI_HW_REDUCED) += generic_event_device.o
+common-obj-$(CONFIG_ACPI_HMAT) += hmat.o
common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
common-obj-$(call lnot,$(CONFIG_PC)) += acpi-x86-stub.o
diff --git a/hw/acpi/hmat.c b/hw/acpi/hmat.c
new file mode 100644
index 0000000000..7c24bb5371
--- /dev/null
+++ b/hw/acpi/hmat.c
@@ -0,0 +1,268 @@
+/*
+ * HMAT ACPI Implementation
+ *
+ * Copyright(C) 2019 Intel Corporation.
+ *
+ * Author:
+ * Liu jingqi <jingqi.liu@linux.intel.com>
+ * Tao Xu <tao3.xu@intel.com>
+ *
+ * HMAT is defined in ACPI 6.3: 5.2.27 Heterogeneous Memory Attribute Table
+ * (HMAT)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "sysemu/numa.h"
+#include "hw/acpi/hmat.h"
+
+/*
+ * ACPI 6.3:
+ * 5.2.27.3 Memory Proximity Domain Attributes Structure: Table 5-145
+ */
+static void build_hmat_mpda(GArray *table_data, uint16_t flags,
+ uint32_t initiator, uint32_t mem_node)
+{
+
+ /* Memory Proximity Domain Attributes Structure */
+ /* Type */
+ build_append_int_noprefix(table_data, 0, 2);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 2);
+ /* Length */
+ build_append_int_noprefix(table_data, 40, 4);
+ /* Flags */
+ build_append_int_noprefix(table_data, flags, 2);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 2);
+ /* Proximity Domain for the Attached Initiator */
+ build_append_int_noprefix(table_data, initiator, 4);
+ /* Proximity Domain for the Memory */
+ build_append_int_noprefix(table_data, mem_node, 4);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 4);
+ /*
+ * Reserved:
+ * Previously defined as the Start Address of the System Physical
+ * Address Range. Deprecated since ACPI Spec 6.3.
+ */
+ build_append_int_noprefix(table_data, 0, 8);
+ /*
+ * Reserved:
+ * Previously defined as the Range Length of the region in bytes.
+ * Deprecated since ACPI Spec 6.3.
+ */
+ build_append_int_noprefix(table_data, 0, 8);
+}
+
+/*
+ * ACPI 6.3: 5.2.27.4 System Locality Latency and Bandwidth Information
+ * Structure: Table 5-146
+ */
+static void build_hmat_lb(GArray *table_data, HMAT_LB_Info *hmat_lb,
+ uint32_t num_initiator, uint32_t num_target,
+ uint32_t *initiator_list)
+{
+ int i, index;
+ HMAT_LB_Data *lb_data;
+ uint16_t *entry_list;
+ uint32_t base;
+ /* Length in bytes for entire structure */
+ uint32_t lb_length
+ = 32 /* Table length upto and including Entry Base Unit */
+ + 4 * num_initiator /* Initiator Proximity Domain List */
+ + 4 * num_target /* Target Proximity Domain List */
+ + 2 * num_initiator * num_target; /* Latency or Bandwidth Entries */
+
+ /* Type */
+ build_append_int_noprefix(table_data, 1, 2);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 2);
+ /* Length */
+ build_append_int_noprefix(table_data, lb_length, 4);
+ /* Flags: Bits [3:0] Memory Hierarchy, Bits[7:4] Reserved */
+ assert(!(hmat_lb->hierarchy >> 4));
+ build_append_int_noprefix(table_data, hmat_lb->hierarchy, 1);
+ /* Data Type */
+ build_append_int_noprefix(table_data, hmat_lb->data_type, 1);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 2);
+ /* Number of Initiator Proximity Domains (s) */
+ build_append_int_noprefix(table_data, num_initiator, 4);
+ /* Number of Target Proximity Domains (t) */
+ build_append_int_noprefix(table_data, num_target, 4);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 4);
+
+ /* Entry Base Unit */
+ if (hmat_lb->data_type <= HMAT_LB_DATA_WRITE_LATENCY) {
+ /* Convert latency base from nanoseconds to picosecond */
+ base = hmat_lb->base * 1000;
+ } else {
+ /* Convert bandwidth base from Byte to Megabyte */
+ base = hmat_lb->base / MiB;
+ }
+ build_append_int_noprefix(table_data, base, 8);
+
+ /* Initiator Proximity Domain List */
+ for (i = 0; i < num_initiator; i++) {
+ build_append_int_noprefix(table_data, initiator_list[i], 4);
+ }
+
+ /* Target Proximity Domain List */
+ for (i = 0; i < num_target; i++) {
+ build_append_int_noprefix(table_data, i, 4);
+ }
+
+ /* Latency or Bandwidth Entries */
+ entry_list = g_malloc0(num_initiator * num_target * sizeof(uint16_t));
+ for (i = 0; i < hmat_lb->list->len; i++) {
+ lb_data = &g_array_index(hmat_lb->list, HMAT_LB_Data, i);
+ index = lb_data->initiator * num_target + lb_data->target;
+
+ entry_list[index] = (uint16_t)(lb_data->data / hmat_lb->base);
+ }
+
+ for (i = 0; i < num_initiator * num_target; i++) {
+ build_append_int_noprefix(table_data, entry_list[i], 2);
+ }
+
+ g_free(entry_list);
+}
+
+/* ACPI 6.3: 5.2.27.5 Memory Side Cache Information Structure: Table 5-147 */
+static void build_hmat_cache(GArray *table_data, uint8_t total_levels,
+ NumaHmatCacheOptions *hmat_cache)
+{
+ /*
+ * Cache Attributes: Bits [3:0] – Total Cache Levels
+ * for this Memory Proximity Domain
+ */
+ uint32_t cache_attr = total_levels;
+
+ /* Bits [7:4] : Cache Level described in this structure */
+ cache_attr |= (uint32_t) hmat_cache->level << 4;
+
+ /* Bits [11:8] - Cache Associativity */
+ cache_attr |= (uint32_t) hmat_cache->associativity << 8;
+
+ /* Bits [15:12] - Write Policy */
+ cache_attr |= (uint32_t) hmat_cache->policy << 12;
+
+ /* Bits [31:16] - Cache Line size in bytes */
+ cache_attr |= (uint32_t) hmat_cache->line << 16;
+
+ /* Type */
+ build_append_int_noprefix(table_data, 2, 2);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 2);
+ /* Length */
+ build_append_int_noprefix(table_data, 32, 4);
+ /* Proximity Domain for the Memory */
+ build_append_int_noprefix(table_data, hmat_cache->node_id, 4);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 4);
+ /* Memory Side Cache Size */
+ build_append_int_noprefix(table_data, hmat_cache->size, 8);
+ /* Cache Attributes */
+ build_append_int_noprefix(table_data, cache_attr, 4);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 2);
+ /*
+ * Number of SMBIOS handles (n)
+ * Linux kernel uses Memory Side Cache Information Structure
+ * without SMBIOS entries for now, so set Number of SMBIOS handles
+ * as 0.
+ */
+ build_append_int_noprefix(table_data, 0, 2);
+}
+
+/* Build HMAT sub table structures */
+static void hmat_build_table_structs(GArray *table_data, NumaState *numa_state)
+{
+ uint16_t flags;
+ uint32_t num_initiator = 0;
+ uint32_t initiator_list[MAX_NODES];
+ int i, hierarchy, type, cache_level, total_levels;
+ HMAT_LB_Info *hmat_lb;
+ NumaHmatCacheOptions *hmat_cache;
+
+ for (i = 0; i < numa_state->num_nodes; i++) {
+ flags = 0;
+
+ if (numa_state->nodes[i].initiator < MAX_NODES) {
+ flags |= HMAT_PROXIMITY_INITIATOR_VALID;
+ }
+
+ build_hmat_mpda(table_data, flags, numa_state->nodes[i].initiator, i);
+ }
+
+ for (i = 0; i < numa_state->num_nodes; i++) {
+ if (numa_state->nodes[i].has_cpu) {
+ initiator_list[num_initiator++] = i;
+ }
+ }
+
+ /*
+ * ACPI 6.3: 5.2.27.4 System Locality Latency and Bandwidth Information
+ * Structure: Table 5-146
+ */
+ for (hierarchy = HMAT_LB_MEM_MEMORY;
+ hierarchy <= HMAT_LB_MEM_CACHE_3RD_LEVEL; hierarchy++) {
+ for (type = HMAT_LB_DATA_ACCESS_LATENCY;
+ type <= HMAT_LB_DATA_WRITE_BANDWIDTH; type++) {
+ hmat_lb = numa_state->hmat_lb[hierarchy][type];
+
+ if (hmat_lb && hmat_lb->list->len) {
+ build_hmat_lb(table_data, hmat_lb, num_initiator,
+ numa_state->num_nodes, initiator_list);
+ }
+ }
+ }
+
+ /*
+ * ACPI 6.3: 5.2.27.5 Memory Side Cache Information Structure:
+ * Table 5-147
+ */
+ for (i = 0; i < numa_state->num_nodes; i++) {
+ total_levels = 0;
+ for (cache_level = 1; cache_level < HMAT_LB_LEVELS; cache_level++) {
+ if (numa_state->hmat_cache[i][cache_level]) {
+ total_levels++;
+ }
+ }
+ for (cache_level = 0; cache_level <= total_levels; cache_level++) {
+ hmat_cache = numa_state->hmat_cache[i][cache_level];
+ if (hmat_cache) {
+ build_hmat_cache(table_data, total_levels, hmat_cache);
+ }
+ }
+ }
+}
+
+void build_hmat(GArray *table_data, BIOSLinker *linker, NumaState *numa_state)
+{
+ int hmat_start = table_data->len;
+
+ /* reserve space for HMAT header */
+ acpi_data_push(table_data, 40);
+
+ hmat_build_table_structs(table_data, numa_state);
+
+ build_header(linker, table_data,
+ (void *)(table_data->data + hmat_start),
+ "HMAT", table_data->len - hmat_start, 2, NULL, NULL);
+}
diff --git a/hw/acpi/hmat.h b/hw/acpi/hmat.h
new file mode 100644
index 0000000000..437dbc6872
--- /dev/null
+++ b/hw/acpi/hmat.h
@@ -0,0 +1,42 @@
+/*
+ * HMAT ACPI Implementation Header
+ *
+ * Copyright(C) 2019 Intel Corporation.
+ *
+ * Author:
+ * Liu jingqi <jingqi.liu@linux.intel.com>
+ * Tao Xu <tao3.xu@intel.com>
+ *
+ * HMAT is defined in ACPI 6.3: 5.2.27 Heterogeneous Memory Attribute Table
+ * (HMAT)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#ifndef HMAT_H
+#define HMAT_H
+
+#include "hw/acpi/aml-build.h"
+
+/*
+ * ACPI 6.3: 5.2.27.3 Memory Proximity Domain Attributes Structure,
+ * Table 5-145, Field "flag", Bit [0]: set to 1 to indicate that data in
+ * the Proximity Domain for the Attached Initiator field is valid.
+ * Other bits reserved.
+ */
+#define HMAT_PROXIMITY_INITIATOR_VALID 0x1
+
+void build_hmat(GArray *table_data, BIOSLinker *linker, NumaState *numa_state);
+
+#endif
diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c
index 6ce038a453..761cc17ea9 100644
--- a/hw/arm/omap1.c
+++ b/hw/arm/omap1.c
@@ -3889,7 +3889,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram,
s->ih[0] = qdev_create(NULL, "omap-intc");
qdev_prop_set_uint32(s->ih[0], "size", 0x100);
- qdev_prop_set_ptr(s->ih[0], "clk", omap_findclk(s, "arminth_ck"));
+ omap_intc_set_iclk(OMAP_INTC(s->ih[0]), omap_findclk(s, "arminth_ck"));
qdev_init_nofail(s->ih[0]);
busdev = SYS_BUS_DEVICE(s->ih[0]);
sysbus_connect_irq(busdev, 0,
@@ -3899,7 +3899,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram,
sysbus_mmio_map(busdev, 0, 0xfffecb00);
s->ih[1] = qdev_create(NULL, "omap-intc");
qdev_prop_set_uint32(s->ih[1], "size", 0x800);
- qdev_prop_set_ptr(s->ih[1], "clk", omap_findclk(s, "arminth_ck"));
+ omap_intc_set_iclk(OMAP_INTC(s->ih[1]), omap_findclk(s, "arminth_ck"));
qdev_init_nofail(s->ih[1]);
busdev = SYS_BUS_DEVICE(s->ih[1]);
sysbus_connect_irq(busdev, 0,
@@ -4012,7 +4012,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram,
s->gpio = qdev_create(NULL, "omap-gpio");
qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
- qdev_prop_set_ptr(s->gpio, "clk", omap_findclk(s, "arm_gpio_ck"));
+ omap_gpio_set_clk(OMAP1_GPIO(s->gpio), omap_findclk(s, "arm_gpio_ck"));
qdev_init_nofail(s->gpio);
sysbus_connect_irq(SYS_BUS_DEVICE(s->gpio), 0,
qdev_get_gpio_in(s->ih[0], OMAP_INT_GPIO_BANK1));
@@ -4030,7 +4030,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram,
s->i2c[0] = qdev_create(NULL, "omap_i2c");
qdev_prop_set_uint8(s->i2c[0], "revision", 0x11);
- qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "mpuper_ck"));
+ omap_i2c_set_fclk(OMAP_I2C(s->i2c[0]), omap_findclk(s, "mpuper_ck"));
qdev_init_nofail(s->i2c[0]);
busdev = SYS_BUS_DEVICE(s->i2c[0]);
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C));
diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c
index 457f152bac..e1c11de5ce 100644
--- a/hw/arm/omap2.c
+++ b/hw/arm/omap2.c
@@ -2308,8 +2308,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram,
/* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */
s->ih[0] = qdev_create(NULL, "omap2-intc");
qdev_prop_set_uint8(s->ih[0], "revision", 0x21);
- qdev_prop_set_ptr(s->ih[0], "fclk", omap_findclk(s, "mpu_intc_fclk"));
- qdev_prop_set_ptr(s->ih[0], "iclk", omap_findclk(s, "mpu_intc_iclk"));
+ omap_intc_set_fclk(OMAP_INTC(s->ih[0]), omap_findclk(s, "mpu_intc_fclk"));
+ omap_intc_set_iclk(OMAP_INTC(s->ih[0]), omap_findclk(s, "mpu_intc_iclk"));
qdev_init_nofail(s->ih[0]);
busdev = SYS_BUS_DEVICE(s->ih[0]);
sysbus_connect_irq(busdev, 0,
@@ -2425,8 +2425,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram,
s->i2c[0] = qdev_create(NULL, "omap_i2c");
qdev_prop_set_uint8(s->i2c[0], "revision", 0x34);
- qdev_prop_set_ptr(s->i2c[0], "iclk", omap_findclk(s, "i2c1.iclk"));
- qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "i2c1.fclk"));
+ omap_i2c_set_iclk(OMAP_I2C(s->i2c[0]), omap_findclk(s, "i2c1.iclk"));
+ omap_i2c_set_fclk(OMAP_I2C(s->i2c[0]), omap_findclk(s, "i2c1.fclk"));
qdev_init_nofail(s->i2c[0]);
busdev = SYS_BUS_DEVICE(s->i2c[0]);
sysbus_connect_irq(busdev, 0,
@@ -2437,8 +2437,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram,
s->i2c[1] = qdev_create(NULL, "omap_i2c");
qdev_prop_set_uint8(s->i2c[1], "revision", 0x34);
- qdev_prop_set_ptr(s->i2c[1], "iclk", omap_findclk(s, "i2c2.iclk"));
- qdev_prop_set_ptr(s->i2c[1], "fclk", omap_findclk(s, "i2c2.fclk"));
+ omap_i2c_set_iclk(OMAP_I2C(s->i2c[1]), omap_findclk(s, "i2c2.iclk"));
+ omap_i2c_set_fclk(OMAP_I2C(s->i2c[1]), omap_findclk(s, "i2c2.fclk"));
qdev_init_nofail(s->i2c[1]);
busdev = SYS_BUS_DEVICE(s->i2c[1]);
sysbus_connect_irq(busdev, 0,
@@ -2449,13 +2449,14 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram,
s->gpio = qdev_create(NULL, "omap2-gpio");
qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
- qdev_prop_set_ptr(s->gpio, "iclk", omap_findclk(s, "gpio_iclk"));
- qdev_prop_set_ptr(s->gpio, "fclk0", omap_findclk(s, "gpio1_dbclk"));
- qdev_prop_set_ptr(s->gpio, "fclk1", omap_findclk(s, "gpio2_dbclk"));
- qdev_prop_set_ptr(s->gpio, "fclk2", omap_findclk(s, "gpio3_dbclk"));
- qdev_prop_set_ptr(s->gpio, "fclk3", omap_findclk(s, "gpio4_dbclk"));
+ omap2_gpio_set_iclk(OMAP2_GPIO(s->gpio), omap_findclk(s, "gpio_iclk"));
+ omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 0, omap_findclk(s, "gpio1_dbclk"));
+ omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 1, omap_findclk(s, "gpio2_dbclk"));
+ omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 2, omap_findclk(s, "gpio3_dbclk"));
+ omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 3, omap_findclk(s, "gpio4_dbclk"));
if (s->mpu_model == omap2430) {
- qdev_prop_set_ptr(s->gpio, "fclk4", omap_findclk(s, "gpio5_dbclk"));
+ omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 4,
+ omap_findclk(s, "gpio5_dbclk"));
}
qdev_init_nofail(s->gpio);
busdev = SYS_BUS_DEVICE(s->gpio);
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index d62e6377c2..9bee514c4e 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -764,13 +764,16 @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
{
VirtIOBlockReq *req;
MultiReqBuffer mrb = {};
+ bool suppress_notifications = virtio_queue_get_notification(vq);
bool progress = false;
aio_context_acquire(blk_get_aio_context(s->blk));
blk_io_plug(s->blk);
do {
- virtio_queue_set_notification(vq, 0);
+ if (suppress_notifications) {
+ virtio_queue_set_notification(vq, 0);
+ }
while ((req = virtio_blk_get_request(s, vq))) {
progress = true;
@@ -781,7 +784,9 @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
}
}
- virtio_queue_set_notification(vq, 1);
+ if (suppress_notifications) {
+ virtio_queue_set_notification(vq, 1);
+ }
} while (!virtio_queue_empty(vq));
if (mrb.num_reqs) {
@@ -908,7 +913,8 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
blk_get_geometry(s->blk, &capacity);
memset(&blkcfg, 0, sizeof(blkcfg));
virtio_stq_p(vdev, &blkcfg.capacity, capacity);
- virtio_stl_p(vdev, &blkcfg.seg_max, 128 - 2);
+ virtio_stl_p(vdev, &blkcfg.seg_max,
+ s->conf.seg_max_adjust ? s->conf.queue_size - 2 : 128 - 2);
virtio_stw_p(vdev, &blkcfg.geometry.cylinders, conf->cyls);
virtio_stl_p(vdev, &blkcfg.blk_size, blk_size);
virtio_stw_p(vdev, &blkcfg.min_io_size, conf->min_io_size / blk_size);
@@ -1133,6 +1139,11 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
error_setg(errp, "num-queues property must be larger than 0");
return;
}
+ if (conf->queue_size <= 2) {
+ error_setg(errp, "invalid queue-size property (%" PRIu16 "), "
+ "must be > 2", conf->queue_size);
+ return;
+ }
if (!is_power_of_2(conf->queue_size) ||
conf->queue_size > VIRTQUEUE_MAX_SIZE) {
error_setg(errp, "invalid queue-size property (%" PRIu16 "), "
@@ -1262,6 +1273,7 @@ static Property virtio_blk_properties[] = {
true),
DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1),
DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 128),
+ DEFINE_PROP_BOOL("seg-max-adjust", VirtIOBlock, conf.seg_max_adjust, true),
DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD,
IOThread *),
DEFINE_PROP_BIT64("discard", VirtIOBlock, host_features,
diff --git a/hw/char/omap_uart.c b/hw/char/omap_uart.c
index 13e4f43c4c..e8da933378 100644
--- a/hw/char/omap_uart.c
+++ b/hw/char/omap_uart.c
@@ -27,7 +27,7 @@
struct omap_uart_s {
MemoryRegion iomem;
hwaddr base;
- SerialState *serial; /* TODO */
+ SerialMM *serial; /* TODO */
struct omap_target_agent_s *ta;
omap_clk fclk;
qemu_irq irq;
diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c
index 9e31c51bb6..db8644551e 100644
--- a/hw/char/serial-isa.c
+++ b/hw/char/serial-isa.c
@@ -73,9 +73,8 @@ static void serial_isa_realizefn(DeviceState *dev, Error **errp)
}
index++;
- s->baudbase = 115200;
isa_init_irq(isadev, &s->irq, isa->isairq);
- serial_realize_core(s, errp);
+ object_property_set_bool(OBJECT(s), true, "realized", errp);
qdev_set_legacy_instance_id(dev, isa->iobase, 3);
memory_region_init_io(&s->io, OBJECT(isa), &serial_io_ops, s, "serial", 8);
@@ -111,10 +110,19 @@ static void serial_isa_class_initfn(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
+static void serial_isa_initfn(Object *o)
+{
+ ISASerialState *self = ISA_SERIAL(o);
+
+ object_initialize_child(o, "serial", &self->state, sizeof(self->state),
+ TYPE_SERIAL, &error_abort, NULL);
+}
+
static const TypeInfo serial_isa_info = {
.name = TYPE_ISA_SERIAL,
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(ISASerialState),
+ .instance_init = serial_isa_initfn,
.class_init = serial_isa_class_initfn,
};
diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c
index 5f13b5663b..e343a1235c 100644
--- a/hw/char/serial-pci-multi.c
+++ b/hw/char/serial-pci-multi.c
@@ -56,7 +56,7 @@ static void multi_serial_pci_exit(PCIDevice *dev)
for (i = 0; i < pci->ports; i++) {
s = pci->state + i;
- serial_exit_core(s);
+ object_property_set_bool(OBJECT(s), false, "realized", NULL);
memory_region_del_subregion(&pci->iobar, &s->io);
g_free(pci->name[i]);
}
@@ -77,43 +77,43 @@ static void multi_serial_irq_mux(void *opaque, int n, int level)
pci_set_irq(&pci->dev, pending);
}
+static size_t multi_serial_get_port_count(PCIDeviceClass *pc)
+{
+ switch (pc->device_id) {
+ case 0x0003:
+ return 2;
+ case 0x0004:
+ return 4;
+ }
+
+ g_assert_not_reached();
+}
+
+
static void multi_serial_pci_realize(PCIDevice *dev, Error **errp)
{
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
SerialState *s;
Error *err = NULL;
- int i, nr_ports = 0;
-
- switch (pc->device_id) {
- case 0x0003:
- nr_ports = 2;
- break;
- case 0x0004:
- nr_ports = 4;
- break;
- }
- assert(nr_ports > 0);
- assert(nr_ports <= PCI_SERIAL_MAX_PORTS);
+ size_t i, nports = multi_serial_get_port_count(pc);
pci->dev.config[PCI_CLASS_PROG] = pci->prog_if;
pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
- memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * nr_ports);
+ memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * nports);
pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar);
- pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci,
- nr_ports);
+ pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, nports);
- for (i = 0; i < nr_ports; i++) {
+ for (i = 0; i < nports; i++) {
s = pci->state + i;
- s->baudbase = 115200;
- serial_realize_core(s, &err);
+ object_property_set_bool(OBJECT(s), true, "realized", &err);
if (err != NULL) {
error_propagate(errp, err);
multi_serial_pci_exit(dev);
return;
}
s->irq = pci->irqs[i];
- pci->name[i] = g_strdup_printf("uart #%d", i + 1);
+ pci->name[i] = g_strdup_printf("uart #%zu", i + 1);
memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s,
pci->name[i], 8);
memory_region_add_subregion(&pci->iobar, 8 * i, &s->io);
@@ -180,10 +180,24 @@ static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
+static void multi_serial_init(Object *o)
+{
+ PCIDevice *dev = PCI_DEVICE(o);
+ PCIMultiSerialState *pms = DO_UPCAST(PCIMultiSerialState, dev, dev);
+ size_t i, nports = multi_serial_get_port_count(PCI_DEVICE_GET_CLASS(dev));
+
+ for (i = 0; i < nports; i++) {
+ object_initialize_child(o, "serial[*]", &pms->state[i],
+ sizeof(pms->state[i]),
+ TYPE_SERIAL, &error_abort, NULL);
+ }
+}
+
static const TypeInfo multi_2x_serial_pci_info = {
.name = "pci-serial-2x",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIMultiSerialState),
+ .instance_init = multi_serial_init,
.class_init = multi_2x_serial_pci_class_initfn,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
@@ -195,6 +209,7 @@ static const TypeInfo multi_4x_serial_pci_info = {
.name = "pci-serial-4x",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIMultiSerialState),
+ .instance_init = multi_serial_init,
.class_init = multi_4x_serial_pci_class_initfn,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c
index cb9b76e22b..b6a73c65a9 100644
--- a/hw/char/serial-pci.c
+++ b/hw/char/serial-pci.c
@@ -40,6 +40,8 @@ typedef struct PCISerialState {
uint8_t prog_if;
} PCISerialState;
+#define TYPE_PCI_SERIAL "pci-serial"
+#define PCI_SERIAL(s) OBJECT_CHECK(PCISerialState, (s), TYPE_PCI_SERIAL)
static void serial_pci_realize(PCIDevice *dev, Error **errp)
{
@@ -47,8 +49,7 @@ static void serial_pci_realize(PCIDevice *dev, Error **errp)
SerialState *s = &pci->state;
Error *err = NULL;
- s->baudbase = 115200;
- serial_realize_core(s, &err);
+ object_property_set_bool(OBJECT(s), true, "realized", &err);
if (err != NULL) {
error_propagate(errp, err);
return;
@@ -67,7 +68,7 @@ static void serial_pci_exit(PCIDevice *dev)
PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev);
SerialState *s = &pci->state;
- serial_exit_core(s);
+ object_property_set_bool(OBJECT(s), false, "realized", NULL);
qemu_free_irq(s->irq);
}
@@ -103,10 +104,19 @@ static void serial_pci_class_initfn(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
+static void serial_pci_init(Object *o)
+{
+ PCISerialState *ps = PCI_SERIAL(o);
+
+ object_initialize_child(o, "serial", &ps->state, sizeof(ps->state),
+ TYPE_SERIAL, &error_abort, NULL);
+}
+
static const TypeInfo serial_pci_info = {
- .name = "pci-serial",
+ .name = TYPE_PCI_SERIAL,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCISerialState),
+ .instance_init = serial_pci_init,
.class_init = serial_pci_class_initfn,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
diff --git a/hw/char/serial.c b/hw/char/serial.c
index 992b5ee944..d167c43d40 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -34,6 +34,7 @@
#include "sysemu/runstate.h"
#include "qemu/error-report.h"
#include "trace.h"
+#include "hw/qdev-properties.h"
//#define DEBUG_SERIAL
@@ -933,8 +934,10 @@ static int serial_be_change(void *opaque)
return 0;
}
-void serial_realize_core(SerialState *s, Error **errp)
+static void serial_realize(DeviceState *dev, Error **errp)
{
+ SerialState *s = SERIAL(dev);
+
s->modem_status_poll = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) serial_update_msl, s);
s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) fifo_timeout_int, s);
@@ -947,8 +950,10 @@ void serial_realize_core(SerialState *s, Error **errp)
serial_reset(s);
}
-void serial_exit_core(SerialState *s)
+static void serial_unrealize(DeviceState *dev, Error **errp)
{
+ SerialState *s = SERIAL(dev);
+
qemu_chr_fe_deinit(&s->chr, false);
timer_del(s->modem_status_poll);
@@ -980,40 +985,89 @@ const MemoryRegionOps serial_io_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-SerialState *serial_init(int base, qemu_irq irq, int baudbase,
- Chardev *chr, MemoryRegion *system_io)
+static void serial_io_realize(DeviceState *dev, Error **errp)
{
- SerialState *s;
+ SerialIO *sio = SERIAL_IO(dev);
+ SerialState *s = &sio->serial;
+ Error *local_err = NULL;
+
+ object_property_set_bool(OBJECT(s), true, "realized", &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ memory_region_init_io(&s->io, NULL, &serial_io_ops, s, "serial", 8);
+ sysbus_init_mmio(SYS_BUS_DEVICE(sio), &s->io);
+ sysbus_init_irq(SYS_BUS_DEVICE(sio), &s->irq);
+}
- s = g_malloc0(sizeof(SerialState));
+static void serial_io_class_init(ObjectClass *klass, void* data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
- s->irq = irq;
- s->baudbase = baudbase;
- qemu_chr_fe_init(&s->chr, chr, &error_abort);
- serial_realize_core(s, &error_fatal);
+ dc->realize = serial_io_realize;
+ /* No dc->vmsd: class has no migratable state */
+}
- vmstate_register(NULL, base, &vmstate_serial, s);
+static void serial_io_instance_init(Object *o)
+{
+ SerialIO *sio = SERIAL_IO(o);
- memory_region_init_io(&s->io, NULL, &serial_io_ops, s, "serial", 8);
- memory_region_add_subregion(system_io, base, &s->io);
+ object_initialize_child(o, "serial", &sio->serial, sizeof(sio->serial),
+ TYPE_SERIAL, &error_abort, NULL);
- return s;
+ qdev_alias_all_properties(DEVICE(&sio->serial), o);
}
+
+static const TypeInfo serial_io_info = {
+ .name = TYPE_SERIAL_IO,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SerialIO),
+ .instance_init = serial_io_instance_init,
+ .class_init = serial_io_class_init,
+};
+
+static Property serial_properties[] = {
+ DEFINE_PROP_CHR("chardev", SerialState, chr),
+ DEFINE_PROP_UINT32("baudbase", SerialState, baudbase, 115200),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void serial_class_init(ObjectClass *klass, void* data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ /* internal device for serialio/serialmm, not user-creatable */
+ dc->user_creatable = false;
+ dc->realize = serial_realize;
+ dc->unrealize = serial_unrealize;
+ dc->vmsd = &vmstate_serial;
+ dc->props = serial_properties;
+}
+
+static const TypeInfo serial_info = {
+ .name = TYPE_SERIAL,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SerialState),
+ .class_init = serial_class_init,
+};
+
/* Memory mapped interface */
static uint64_t serial_mm_read(void *opaque, hwaddr addr,
unsigned size)
{
- SerialState *s = opaque;
- return serial_ioport_read(s, addr >> s->it_shift, 1);
+ SerialMM *s = SERIAL_MM(opaque);
+ return serial_ioport_read(&s->serial, addr >> s->regshift, 1);
}
static void serial_mm_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
- SerialState *s = opaque;
+ SerialMM *s = SERIAL_MM(opaque);
value &= 255;
- serial_ioport_write(s, addr >> s->it_shift, value, 1);
+ serial_ioport_write(&s->serial, addr >> s->regshift, value, 1);
}
static const MemoryRegionOps serial_mm_ops[3] = {
@@ -1040,25 +1094,89 @@ static const MemoryRegionOps serial_mm_ops[3] = {
},
};
-SerialState *serial_mm_init(MemoryRegion *address_space,
- hwaddr base, int it_shift,
- qemu_irq irq, int baudbase,
- Chardev *chr, enum device_endian end)
+static void serial_mm_realize(DeviceState *dev, Error **errp)
{
- SerialState *s;
+ SerialMM *smm = SERIAL_MM(dev);
+ SerialState *s = &smm->serial;
+ Error *local_err = NULL;
- s = g_malloc0(sizeof(SerialState));
+ object_property_set_bool(OBJECT(s), true, "realized", &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ memory_region_init_io(&s->io, NULL, &serial_mm_ops[smm->endianness], smm,
+ "serial", 8 << smm->regshift);
+ sysbus_init_mmio(SYS_BUS_DEVICE(smm), &s->io);
+ sysbus_init_irq(SYS_BUS_DEVICE(smm), &smm->serial.irq);
+}
+
+SerialMM *serial_mm_init(MemoryRegion *address_space,
+ hwaddr base, int regshift,
+ qemu_irq irq, int baudbase,
+ Chardev *chr, enum device_endian end)
+{
+ SerialMM *smm = SERIAL_MM(qdev_create(NULL, TYPE_SERIAL_MM));
+ MemoryRegion *mr;
- s->it_shift = it_shift;
- s->irq = irq;
- s->baudbase = baudbase;
- qemu_chr_fe_init(&s->chr, chr, &error_abort);
+ qdev_prop_set_uint8(DEVICE(smm), "regshift", regshift);
+ qdev_prop_set_uint32(DEVICE(smm), "baudbase", baudbase);
+ qdev_prop_set_chr(DEVICE(smm), "chardev", chr);
+ qdev_set_legacy_instance_id(DEVICE(smm), base, 2);
+ qdev_prop_set_uint8(DEVICE(smm), "endianness", end);
+ qdev_init_nofail(DEVICE(smm));
- serial_realize_core(s, &error_fatal);
- vmstate_register(NULL, base, &vmstate_serial, s);
+ sysbus_connect_irq(SYS_BUS_DEVICE(smm), 0, irq);
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(smm), 0);
+ memory_region_add_subregion(address_space, base, mr);
- memory_region_init_io(&s->io, NULL, &serial_mm_ops[end], s,
- "serial", 8 << it_shift);
- memory_region_add_subregion(address_space, base, &s->io);
- return s;
+ return smm;
}
+
+static void serial_mm_instance_init(Object *o)
+{
+ SerialMM *smm = SERIAL_MM(o);
+
+ object_initialize_child(o, "serial", &smm->serial, sizeof(smm->serial),
+ TYPE_SERIAL, &error_abort, NULL);
+
+ qdev_alias_all_properties(DEVICE(&smm->serial), o);
+}
+
+static Property serial_mm_properties[] = {
+ /*
+ * Set the spacing between adjacent memory-mapped UART registers.
+ * Each register will be at (1 << regshift) bytes after the
+ * previous one.
+ */
+ DEFINE_PROP_UINT8("regshift", SerialMM, regshift, 0),
+ DEFINE_PROP_UINT8("endianness", SerialMM, endianness, DEVICE_NATIVE_ENDIAN),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void serial_mm_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->props = serial_mm_properties;
+ dc->realize = serial_mm_realize;
+}
+
+static const TypeInfo serial_mm_info = {
+ .name = TYPE_SERIAL_MM,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .class_init = serial_mm_class_init,
+ .instance_init = serial_mm_instance_init,
+ .instance_size = sizeof(SerialMM),
+ .class_init = serial_mm_class_init,
+};
+
+static void serial_register_types(void)
+{
+ type_register_static(&serial_info);
+ type_register_static(&serial_io_info);
+ type_register_static(&serial_mm_info);
+}
+
+type_init(serial_register_types)
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 33259042a9..e1cbce3ba3 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -1126,9 +1126,17 @@ static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOSerial *vser = VIRTIO_SERIAL(dev);
+ int i;
QLIST_REMOVE(vser, next);
+ virtio_delete_queue(vser->c_ivq);
+ virtio_delete_queue(vser->c_ovq);
+ for (i = 0; i < vser->bus.max_nr_ports; i++) {
+ virtio_delete_queue(vser->ivqs[i]);
+ virtio_delete_queue(vser->ovqs[i]);
+ }
+
g_free(vser->ivqs);
g_free(vser->ovqs);
g_free(vser->ports_map);
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 73bf1f8572..4f30fb5646 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -29,11 +29,15 @@
GlobalProperty hw_compat_4_2[] = {
{ "virtio-blk-device", "x-enable-wce-if-config-wce", "off" },
+ { "virtio-blk-device", "seg-max-adjust", "off"},
+ { "virtio-scsi-device", "seg_max_adjust", "off"},
+ { "vhost-blk-device", "seg_max_adjust", "off"},
};
const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2);
GlobalProperty hw_compat_4_1[] = {
{ "virtio-pci", "x-pcie-flr-init", "off" },
+ { "virtio-device", "use-disabled-flag", "false" },
};
const size_t hw_compat_4_1_len = G_N_ELEMENTS(hw_compat_4_1);
@@ -429,6 +433,20 @@ static void machine_set_nvdimm(Object *obj, bool value, Error **errp)
ms->nvdimms_state->is_enabled = value;
}
+static bool machine_get_hmat(Object *obj, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ return ms->numa_state->hmat_enabled;
+}
+
+static void machine_set_hmat(Object *obj, bool value, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ ms->numa_state->hmat_enabled = value;
+}
+
static char *machine_get_nvdimm_persistence(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
@@ -556,6 +574,7 @@ void machine_set_cpu_numa_node(MachineState *machine,
const CpuInstanceProperties *props, Error **errp)
{
MachineClass *mc = MACHINE_GET_CLASS(machine);
+ NodeInfo *numa_info = machine->numa_state->nodes;
bool match = false;
int i;
@@ -625,6 +644,17 @@ void machine_set_cpu_numa_node(MachineState *machine,
match = true;
slot->props.node_id = props->node_id;
slot->props.has_node_id = props->has_node_id;
+
+ if (machine->numa_state->hmat_enabled) {
+ if ((numa_info[props->node_id].initiator < MAX_NODES) &&
+ (props->node_id != numa_info[props->node_id].initiator)) {
+ error_setg(errp, "The initiator of CPU NUMA node %" PRId64
+ " should be itself", props->node_id);
+ return;
+ }
+ numa_info[props->node_id].has_cpu = true;
+ numa_info[props->node_id].initiator = props->node_id;
+ }
}
if (!match) {
@@ -845,6 +875,13 @@ static void machine_initfn(Object *obj)
if (mc->cpu_index_to_instance_props && mc->get_default_cpu_node_id) {
ms->numa_state = g_new0(NumaState, 1);
+ object_property_add_bool(obj, "hmat",
+ machine_get_hmat, machine_set_hmat,
+ &error_abort);
+ object_property_set_description(obj, "hmat",
+ "Set on/off to enable/disable "
+ "ACPI Heterogeneous Memory Attribute "
+ "Table (HMAT)", NULL);
}
/* Register notifier when init is done for sysbus sanity checks */
@@ -912,6 +949,32 @@ static char *cpu_slot_to_string(const CPUArchId *cpu)
return g_string_free(s, false);
}
+static void numa_validate_initiator(NumaState *numa_state)
+{
+ int i;
+ NodeInfo *numa_info = numa_state->nodes;
+
+ for (i = 0; i < numa_state->num_nodes; i++) {
+ if (numa_info[i].initiator == MAX_NODES) {
+ error_report("The initiator of NUMA node %d is missing, use "
+ "'-numa node,initiator' option to declare it", i);
+ exit(1);
+ }
+
+ if (!numa_info[numa_info[i].initiator].present) {
+ error_report("NUMA node %" PRIu16 " is missing, use "
+ "'-numa node' option to declare it first",
+ numa_info[i].initiator);
+ exit(1);
+ }
+
+ if (!numa_info[numa_info[i].initiator].has_cpu) {
+ error_report("The initiator of NUMA node %d is invalid", i);
+ exit(1);
+ }
+ }
+}
+
static void machine_numa_finish_cpu_init(MachineState *machine)
{
int i;
@@ -952,6 +1015,11 @@ static void machine_numa_finish_cpu_init(MachineState *machine)
machine_set_cpu_numa_node(machine, &props, &error_fatal);
}
}
+
+ if (machine->numa_state->hmat_enabled) {
+ numa_validate_initiator(machine->numa_state);
+ }
+
if (s->len && !qtest_enabled()) {
warn_report("CPU(s) not present in any NUMA nodes: %s",
s->str);
diff --git a/hw/core/numa.c b/hw/core/numa.c
index 19f082de12..0d1b4be76a 100644
--- a/hw/core/numa.c
+++ b/hw/core/numa.c
@@ -23,6 +23,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "sysemu/hostmem.h"
#include "sysemu/numa.h"
#include "sysemu/sysemu.h"
@@ -129,6 +130,29 @@ static void parse_numa_node(MachineState *ms, NumaNodeOptions *node,
numa_info[nodenr].node_mem = object_property_get_uint(o, "size", NULL);
numa_info[nodenr].node_memdev = MEMORY_BACKEND(o);
}
+
+ /*
+ * If not set the initiator, set it to MAX_NODES. And if
+ * HMAT is enabled and this node has no cpus, QEMU will raise error.
+ */
+ numa_info[nodenr].initiator = MAX_NODES;
+ if (node->has_initiator) {
+ if (!ms->numa_state->hmat_enabled) {
+ error_setg(errp, "ACPI Heterogeneous Memory Attribute Table "
+ "(HMAT) is disabled, enable it with -machine hmat=on "
+ "before using any of hmat specific options");
+ return;
+ }
+
+ if (node->initiator >= MAX_NODES) {
+ error_report("The initiator id %" PRIu16 " expects an integer "
+ "between 0 and %d", node->initiator,
+ MAX_NODES - 1);
+ return;
+ }
+
+ numa_info[nodenr].initiator = node->initiator;
+ }
numa_info[nodenr].present = true;
max_numa_nodeid = MAX(max_numa_nodeid, nodenr + 1);
ms->numa_state->num_nodes++;
@@ -171,6 +195,253 @@ void parse_numa_distance(MachineState *ms, NumaDistOptions *dist, Error **errp)
ms->numa_state->have_numa_distance = true;
}
+void parse_numa_hmat_lb(NumaState *numa_state, NumaHmatLBOptions *node,
+ Error **errp)
+{
+ int i, first_bit, last_bit;
+ uint64_t max_entry, temp_base, bitmap_copy;
+ NodeInfo *numa_info = numa_state->nodes;
+ HMAT_LB_Info *hmat_lb =
+ numa_state->hmat_lb[node->hierarchy][node->data_type];
+ HMAT_LB_Data lb_data = {};
+ HMAT_LB_Data *lb_temp;
+
+ /* Error checking */
+ if (node->initiator > numa_state->num_nodes) {
+ error_setg(errp, "Invalid initiator=%d, it should be less than %d",
+ node->initiator, numa_state->num_nodes);
+ return;
+ }
+ if (node->target > numa_state->num_nodes) {
+ error_setg(errp, "Invalid target=%d, it should be less than %d",
+ node->target, numa_state->num_nodes);
+ return;
+ }
+ if (!numa_info[node->initiator].has_cpu) {
+ error_setg(errp, "Invalid initiator=%d, it isn't an "
+ "initiator proximity domain", node->initiator);
+ return;
+ }
+ if (!numa_info[node->target].present) {
+ error_setg(errp, "The target=%d should point to an existing node",
+ node->target);
+ return;
+ }
+
+ if (!hmat_lb) {
+ hmat_lb = g_malloc0(sizeof(*hmat_lb));
+ numa_state->hmat_lb[node->hierarchy][node->data_type] = hmat_lb;
+ hmat_lb->list = g_array_new(false, true, sizeof(HMAT_LB_Data));
+ }
+ hmat_lb->hierarchy = node->hierarchy;
+ hmat_lb->data_type = node->data_type;
+ lb_data.initiator = node->initiator;
+ lb_data.target = node->target;
+
+ if (node->data_type <= HMATLB_DATA_TYPE_WRITE_LATENCY) {
+ /* Input latency data */
+
+ if (!node->has_latency) {
+ error_setg(errp, "Missing 'latency' option");
+ return;
+ }
+ if (node->has_bandwidth) {
+ error_setg(errp, "Invalid option 'bandwidth' since "
+ "the data type is latency");
+ return;
+ }
+
+ /* Detect duplicate configuration */
+ for (i = 0; i < hmat_lb->list->len; i++) {
+ lb_temp = &g_array_index(hmat_lb->list, HMAT_LB_Data, i);
+
+ if (node->initiator == lb_temp->initiator &&
+ node->target == lb_temp->target) {
+ error_setg(errp, "Duplicate configuration of the latency for "
+ "initiator=%d and target=%d", node->initiator,
+ node->target);
+ return;
+ }
+ }
+
+ hmat_lb->base = hmat_lb->base ? hmat_lb->base : UINT64_MAX;
+
+ if (node->latency) {
+ /* Calculate the temporary base and compressed latency */
+ max_entry = node->latency;
+ temp_base = 1;
+ while (QEMU_IS_ALIGNED(max_entry, 10)) {
+ max_entry /= 10;
+ temp_base *= 10;
+ }
+
+ /* Calculate the max compressed latency */
+ temp_base = MIN(hmat_lb->base, temp_base);
+ max_entry = node->latency / hmat_lb->base;
+ max_entry = MAX(hmat_lb->range_bitmap, max_entry);
+
+ /*
+ * For latency hmat_lb->range_bitmap record the max compressed
+ * latency which should be less than 0xFFFF (UINT16_MAX)
+ */
+ if (max_entry >= UINT16_MAX) {
+ error_setg(errp, "Latency %" PRIu64 " between initiator=%d and "
+ "target=%d should not differ from previously entered "
+ "min or max values on more than %d", node->latency,
+ node->initiator, node->target, UINT16_MAX - 1);
+ return;
+ } else {
+ hmat_lb->base = temp_base;
+ hmat_lb->range_bitmap = max_entry;
+ }
+
+ /*
+ * Set lb_info_provided bit 0 as 1,
+ * latency information is provided
+ */
+ numa_info[node->target].lb_info_provided |= BIT(0);
+ }
+ lb_data.data = node->latency;
+ } else if (node->data_type >= HMATLB_DATA_TYPE_ACCESS_BANDWIDTH) {
+ /* Input bandwidth data */
+ if (!node->has_bandwidth) {
+ error_setg(errp, "Missing 'bandwidth' option");
+ return;
+ }
+ if (node->has_latency) {
+ error_setg(errp, "Invalid option 'latency' since "
+ "the data type is bandwidth");
+ return;
+ }
+ if (!QEMU_IS_ALIGNED(node->bandwidth, MiB)) {
+ error_setg(errp, "Bandwidth %" PRIu64 " between initiator=%d and "
+ "target=%d should be 1MB aligned", node->bandwidth,
+ node->initiator, node->target);
+ return;
+ }
+
+ /* Detect duplicate configuration */
+ for (i = 0; i < hmat_lb->list->len; i++) {
+ lb_temp = &g_array_index(hmat_lb->list, HMAT_LB_Data, i);
+
+ if (node->initiator == lb_temp->initiator &&
+ node->target == lb_temp->target) {
+ error_setg(errp, "Duplicate configuration of the bandwidth for "
+ "initiator=%d and target=%d", node->initiator,
+ node->target);
+ return;
+ }
+ }
+
+ hmat_lb->base = hmat_lb->base ? hmat_lb->base : 1;
+
+ if (node->bandwidth) {
+ /* Keep bitmap unchanged when bandwidth out of range */
+ bitmap_copy = hmat_lb->range_bitmap;
+ bitmap_copy |= node->bandwidth;
+ first_bit = ctz64(bitmap_copy);
+ temp_base = UINT64_C(1) << first_bit;
+ max_entry = node->bandwidth / temp_base;
+ last_bit = 64 - clz64(bitmap_copy);
+
+ /*
+ * For bandwidth, first_bit record the base unit of bandwidth bits,
+ * last_bit record the last bit of the max bandwidth. The max
+ * compressed bandwidth should be less than 0xFFFF (UINT16_MAX)
+ */
+ if ((last_bit - first_bit) > UINT16_BITS ||
+ max_entry >= UINT16_MAX) {
+ error_setg(errp, "Bandwidth %" PRIu64 " between initiator=%d "
+ "and target=%d should not differ from previously "
+ "entered values on more than %d", node->bandwidth,
+ node->initiator, node->target, UINT16_MAX - 1);
+ return;
+ } else {
+ hmat_lb->base = temp_base;
+ hmat_lb->range_bitmap = bitmap_copy;
+ }
+
+ /*
+ * Set lb_info_provided bit 1 as 1,
+ * bandwidth information is provided
+ */
+ numa_info[node->target].lb_info_provided |= BIT(1);
+ }
+ lb_data.data = node->bandwidth;
+ } else {
+ assert(0);
+ }
+
+ g_array_append_val(hmat_lb->list, lb_data);
+}
+
+void parse_numa_hmat_cache(MachineState *ms, NumaHmatCacheOptions *node,
+ Error **errp)
+{
+ int nb_numa_nodes = ms->numa_state->num_nodes;
+ NodeInfo *numa_info = ms->numa_state->nodes;
+ NumaHmatCacheOptions *hmat_cache = NULL;
+
+ if (node->node_id >= nb_numa_nodes) {
+ error_setg(errp, "Invalid node-id=%" PRIu32 ", it should be less "
+ "than %d", node->node_id, nb_numa_nodes);
+ return;
+ }
+
+ if (numa_info[node->node_id].lb_info_provided != (BIT(0) | BIT(1))) {
+ error_setg(errp, "The latency and bandwidth information of "
+ "node-id=%" PRIu32 " should be provided before memory side "
+ "cache attributes", node->node_id);
+ return;
+ }
+
+ if (node->level < 1 || node->level >= HMAT_LB_LEVELS) {
+ error_setg(errp, "Invalid level=%" PRIu8 ", it should be larger than 0 "
+ "and less than or equal to %d", node->level,
+ HMAT_LB_LEVELS - 1);
+ return;
+ }
+
+ assert(node->associativity < HMAT_CACHE_ASSOCIATIVITY__MAX);
+ assert(node->policy < HMAT_CACHE_WRITE_POLICY__MAX);
+ if (ms->numa_state->hmat_cache[node->node_id][node->level]) {
+ error_setg(errp, "Duplicate configuration of the side cache for "
+ "node-id=%" PRIu32 " and level=%" PRIu8,
+ node->node_id, node->level);
+ return;
+ }
+
+ if ((node->level > 1) &&
+ ms->numa_state->hmat_cache[node->node_id][node->level - 1] &&
+ (node->size >=
+ ms->numa_state->hmat_cache[node->node_id][node->level - 1]->size)) {
+ error_setg(errp, "Invalid size=%" PRIu64 ", the size of level=%" PRIu8
+ " should be less than the size(%" PRIu64 ") of "
+ "level=%u", node->size, node->level,
+ ms->numa_state->hmat_cache[node->node_id]
+ [node->level - 1]->size,
+ node->level - 1);
+ return;
+ }
+
+ if ((node->level < HMAT_LB_LEVELS - 1) &&
+ ms->numa_state->hmat_cache[node->node_id][node->level + 1] &&
+ (node->size <=
+ ms->numa_state->hmat_cache[node->node_id][node->level + 1]->size)) {
+ error_setg(errp, "Invalid size=%" PRIu64 ", the size of level=%" PRIu8
+ " should be larger than the size(%" PRIu64 ") of "
+ "level=%u", node->size, node->level,
+ ms->numa_state->hmat_cache[node->node_id]
+ [node->level + 1]->size,
+ node->level + 1);
+ return;
+ }
+
+ hmat_cache = g_malloc0(sizeof(*hmat_cache));
+ memcpy(hmat_cache, node, sizeof(*hmat_cache));
+ ms->numa_state->hmat_cache[node->node_id][node->level] = hmat_cache;
+}
+
void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp)
{
Error *err = NULL;
@@ -208,6 +479,32 @@ void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp)
machine_set_cpu_numa_node(ms, qapi_NumaCpuOptions_base(&object->u.cpu),
&err);
break;
+ case NUMA_OPTIONS_TYPE_HMAT_LB:
+ if (!ms->numa_state->hmat_enabled) {
+ error_setg(errp, "ACPI Heterogeneous Memory Attribute Table "
+ "(HMAT) is disabled, enable it with -machine hmat=on "
+ "before using any of hmat specific options");
+ return;
+ }
+
+ parse_numa_hmat_lb(ms->numa_state, &object->u.hmat_lb, &err);
+ if (err) {
+ goto end;
+ }
+ break;
+ case NUMA_OPTIONS_TYPE_HMAT_CACHE:
+ if (!ms->numa_state->hmat_enabled) {
+ error_setg(errp, "ACPI Heterogeneous Memory Attribute Table "
+ "(HMAT) is disabled, enable it with -machine hmat=on "
+ "before using any of hmat specific options");
+ return;
+ }
+
+ parse_numa_hmat_cache(ms, &object->u.hmat_cache, &err);
+ if (err) {
+ goto end;
+ }
+ break;
default:
abort();
}
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index ac28890e5a..6ca7697599 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -501,13 +501,6 @@ const PropertyInfo qdev_prop_string = {
.set = set_string,
};
-/* --- pointer --- */
-
-/* Not a proper property, just for dirty hacks. TODO Remove it! */
-const PropertyInfo qdev_prop_ptr = {
- .name = "ptr",
-};
-
/* --- mac address --- */
/*
@@ -1165,17 +1158,6 @@ void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
name, &error_abort);
}
-void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
-{
- Property *prop;
- void **ptr;
-
- prop = qdev_prop_find(dev, name);
- assert(prop && prop->info == &qdev_prop_ptr);
- ptr = qdev_get_prop_ptr(dev, prop);
- *ptr = value;
-}
-
static GPtrArray *global_props(void)
{
static GPtrArray *gp;
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 501228ba08..9f1753f5cf 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -394,11 +394,8 @@ static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev,
NamedGPIOList *ngl;
QLIST_FOREACH(ngl, &dev->gpios, node) {
- /* NULL is a valid and matchable name, otherwise do a normal
- * strcmp match.
- */
- if ((!ngl->name && !name) ||
- (name && ngl->name && strcmp(name, ngl->name) == 0)) {
+ /* NULL is a valid and matchable name. */
+ if (g_strcmp0(name, ngl->name) == 0) {
return ngl;
}
}
@@ -739,14 +736,6 @@ void qdev_property_add_static(DeviceState *dev, Property *prop,
if (prop->info->create) {
prop->info->create(obj, prop, &local_err);
} else {
- /*
- * TODO qdev_prop_ptr does not have getters or setters. It must
- * go now that it can be replaced with links. The test should be
- * removed along with it: all static properties are read/write.
- */
- if (!prop->info->get && !prop->info->set) {
- return;
- }
object_property_add(obj, prop->name, prop->info->name,
prop->info->get, prop->info->set,
prop->info->release,
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index 9e69c83aed..08b0311c5f 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -250,38 +250,6 @@ DeviceState *sysbus_create_varargs(const char *name,
return dev;
}
-DeviceState *sysbus_try_create_varargs(const char *name,
- hwaddr addr, ...)
-{
- DeviceState *dev;
- SysBusDevice *s;
- va_list va;
- qemu_irq irq;
- int n;
-
- dev = qdev_try_create(NULL, name);
- if (!dev) {
- return NULL;
- }
- s = SYS_BUS_DEVICE(dev);
- qdev_init_nofail(dev);
- if (addr != (hwaddr)-1) {
- sysbus_mmio_map(s, 0, addr);
- }
- va_start(va, addr);
- n = 0;
- while (1) {
- irq = va_arg(va, qemu_irq);
- if (!irq) {
- break;
- }
- sysbus_connect_irq(s, n, irq);
- n++;
- }
- va_end(va);
- return dev;
-}
-
static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
{
SysBusDevice *s = SYS_BUS_DEVICE(dev);
diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c
index 940c7dd122..be7760476a 100644
--- a/hw/cris/axis_dev88.c
+++ b/hw/cris/axis_dev88.c
@@ -253,7 +253,6 @@ void axisdev88_init(MachineState *machine)
const char *kernel_filename = machine->kernel_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
CRISCPU *cpu;
- CPUCRISState *env;
DeviceState *dev;
SysBusDevice *s;
DriveInfo *nand;
@@ -267,7 +266,6 @@ void axisdev88_init(MachineState *machine)
/* init CPUs */
cpu = CRIS_CPU(cpu_create(machine->cpu_type));
- env = &cpu->env;
/* allocate RAM */
memory_region_allocate_system_memory(phys_ram, NULL, "axisdev88.ram",
@@ -297,8 +295,6 @@ void axisdev88_init(MachineState *machine)
dev = qdev_create(NULL, "etraxfs,pic");
- /* FIXME: Is there a proper way to signal vectors to the CPU core? */
- qdev_prop_set_ptr(dev, "interrupt_vector", &env->interrupt_vector);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(s, 0, 0x3001c000);
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 1f33c87e65..66a1bfbe60 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -1930,7 +1930,7 @@ typedef struct {
SM501State state;
uint32_t vram_size;
uint32_t base;
- void *chr_state;
+ SerialMM serial;
} SM501SysBusState;
static void sm501_realize_sysbus(DeviceState *dev, Error **errp)
@@ -1938,6 +1938,7 @@ static void sm501_realize_sysbus(DeviceState *dev, Error **errp)
SM501SysBusState *s = SYSBUS_SM501(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
DeviceState *usb_dev;
+ MemoryRegion *mr;
sm501_init(&s->state, dev, s->vram_size);
if (get_local_mem_size(&s->state) != s->vram_size) {
@@ -1958,17 +1959,15 @@ static void sm501_realize_sysbus(DeviceState *dev, Error **errp)
sysbus_pass_irq(sbd, SYS_BUS_DEVICE(usb_dev));
/* bridge to serial emulation module */
- if (s->chr_state) {
- serial_mm_init(&s->state.mmio_region, SM501_UART0, 2,
- NULL, /* TODO : chain irq to IRL */
- 115200, s->chr_state, DEVICE_LITTLE_ENDIAN);
- }
+ qdev_init_nofail(DEVICE(&s->serial));
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->serial), 0);
+ memory_region_add_subregion(&s->state.mmio_region, SM501_UART0, mr);
+ /* TODO : chain irq to IRL */
}
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(),
};
@@ -1999,9 +1998,20 @@ static void sm501_sysbus_class_init(ObjectClass *klass, void *data)
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->user_creatable = false;
- */
+}
+
+static void sm501_sysbus_init(Object *o)
+{
+ SM501SysBusState *sm501 = SYSBUS_SM501(o);
+ SerialMM *smm = &sm501->serial;
+
+ sysbus_init_child_obj(o, "serial", smm, sizeof(SerialMM), TYPE_SERIAL_MM);
+ qdev_set_legacy_instance_id(DEVICE(smm), SM501_UART0, 2);
+ qdev_prop_set_uint8(DEVICE(smm), "regshift", 2);
+ qdev_prop_set_uint8(DEVICE(smm), "endianness", DEVICE_LITTLE_ENDIAN);
+
+ object_property_add_alias(o, "chardev",
+ OBJECT(smm), "chardev", &error_abort);
}
static const TypeInfo sm501_sysbus_info = {
@@ -2009,6 +2019,7 @@ static const TypeInfo sm501_sysbus_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(SM501SysBusState),
.class_init = sm501_sysbus_class_init,
+ .instance_init = sm501_sysbus_init,
};
#define TYPE_PCI_SM501 "sm501"
diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c
index 0e5bbcdc7f..3e4da0c47f 100644
--- a/hw/dma/sparc32_dma.c
+++ b/hw/dma/sparc32_dma.c
@@ -346,7 +346,7 @@ static void sparc32_ledma_device_realize(DeviceState *dev, Error **errp)
d = qdev_create(NULL, TYPE_LANCE);
object_property_add_child(OBJECT(dev), "lance", OBJECT(d), errp);
qdev_set_nic_properties(d, nd);
- qdev_prop_set_ptr(d, "dma", dev);
+ object_property_set_link(OBJECT(d), OBJECT(dev), "dma", errp);
qdev_init_nofail(d);
}
diff --git a/hw/gpio/omap_gpio.c b/hw/gpio/omap_gpio.c
index 41e1aa798c..85c16897ae 100644
--- a/hw/gpio/omap_gpio.c
+++ b/hw/gpio/omap_gpio.c
@@ -40,10 +40,6 @@ struct omap_gpio_s {
uint16_t pins;
};
-#define TYPE_OMAP1_GPIO "omap-gpio"
-#define OMAP1_GPIO(obj) \
- OBJECT_CHECK(struct omap_gpif_s, (obj), TYPE_OMAP1_GPIO)
-
struct omap_gpif_s {
SysBusDevice parent_obj;
@@ -212,10 +208,6 @@ struct omap2_gpio_s {
uint8_t delay;
};
-#define TYPE_OMAP2_GPIO "omap2-gpio"
-#define OMAP2_GPIO(obj) \
- OBJECT_CHECK(struct omap2_gpif_s, (obj), TYPE_OMAP2_GPIO)
-
struct omap2_gpif_s {
SysBusDevice parent_obj;
@@ -747,21 +739,13 @@ static void omap2_gpio_realize(DeviceState *dev, Error **errp)
}
}
-/* Using qdev pointer properties for the clocks is not ideal.
- * qdev should support a generic means of defining a 'port' with
- * an arbitrary interface for connecting two devices. Then we
- * could reframe the omap clock API in terms of clock ports,
- * and get some type safety. For now the best qdev provides is
- * passing an arbitrary pointer.
- * (It's not possible to pass in the string which is the clock
- * name, because this device does not have the necessary information
- * (ie the struct omap_mpu_state_s*) to do the clockname to pointer
- * translation.)
- */
+void omap_gpio_set_clk(omap_gpif *gpio, omap_clk clk)
+{
+ gpio->clk = clk;
+}
static Property omap_gpio_properties[] = {
DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0),
- DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk),
DEFINE_PROP_END_OF_LIST(),
};
@@ -784,15 +768,19 @@ static const TypeInfo omap_gpio_info = {
.class_init = omap_gpio_class_init,
};
+void omap2_gpio_set_iclk(omap2_gpif *gpio, omap_clk clk)
+{
+ gpio->iclk = clk;
+}
+
+void omap2_gpio_set_fclk(omap2_gpif *gpio, uint8_t i, omap_clk clk)
+{
+ assert(i <= 5);
+ gpio->fclk[i] = clk;
+}
+
static Property omap2_gpio_properties[] = {
DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0),
- DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk),
- DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]),
- DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]),
- DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]),
- DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]),
- DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]),
- DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/i2c/omap_i2c.c b/hw/i2c/omap_i2c.c
index 3ba965a58f..3ccbd5cc2c 100644
--- a/hw/i2c/omap_i2c.c
+++ b/hw/i2c/omap_i2c.c
@@ -28,10 +28,7 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
-#define TYPE_OMAP_I2C "omap_i2c"
-#define OMAP_I2C(obj) OBJECT_CHECK(OMAPI2CState, (obj), TYPE_OMAP_I2C)
-
-typedef struct OMAPI2CState {
+struct OMAPI2CState {
SysBusDevice parent_obj;
MemoryRegion iomem;
@@ -56,7 +53,7 @@ typedef struct OMAPI2CState {
uint8_t divider;
uint8_t times[2];
uint16_t test;
-} OMAPI2CState;
+};
#define OMAP2_INTR_REV 0x34
#define OMAP2_GC_REV 0x34
@@ -504,10 +501,18 @@ static void omap_i2c_realize(DeviceState *dev, Error **errp)
}
}
+void omap_i2c_set_iclk(OMAPI2CState *i2c, omap_clk clk)
+{
+ i2c->iclk = clk;
+}
+
+void omap_i2c_set_fclk(OMAPI2CState *i2c, omap_clk clk)
+{
+ i2c->fclk = clk;
+}
+
static Property omap_i2c_properties[] = {
DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0),
- DEFINE_PROP_PTR("iclk", OMAPI2CState, iclk),
- DEFINE_PROP_PTR("fclk", OMAPI2CState, fclk),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index 54c86a0112..5adf3b15b5 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -44,7 +44,7 @@
typedef struct SMBusEEPROMDevice {
SMBusDevice smbusdev;
uint8_t data[SMBUS_EEPROM_SIZE];
- void *init_data;
+ uint8_t *init_data;
uint8_t offset;
bool accessed;
} SMBusEEPROMDevice;
@@ -129,14 +129,14 @@ static void smbus_eeprom_reset(DeviceState *dev)
static void smbus_eeprom_realize(DeviceState *dev, Error **errp)
{
+ SMBusEEPROMDevice *eeprom = SMBUS_EEPROM(dev);
+
smbus_eeprom_reset(dev);
+ if (eeprom->init_data == NULL) {
+ error_setg(errp, "init_data cannot be NULL");
+ }
}
-static Property smbus_eeprom_properties[] = {
- DEFINE_PROP_PTR("data", SMBusEEPROMDevice, init_data),
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -146,9 +146,8 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
dc->reset = smbus_eeprom_reset;
sc->receive_byte = eeprom_receive_byte;
sc->write_data = eeprom_write_data;
- dc->props = smbus_eeprom_properties;
dc->vmsd = &vmstate_smbus_eeprom;
- /* Reason: pointer property "data" */
+ /* Reason: init_data */
dc->user_creatable = false;
}
@@ -172,7 +171,8 @@ void smbus_eeprom_init_one(I2CBus *smbus, uint8_t address, uint8_t *eeprom_buf)
dev = qdev_create((BusState *) smbus, TYPE_SMBUS_EEPROM);
qdev_prop_set_uint8(dev, "address", address);
- qdev_prop_set_ptr(dev, "data", eeprom_buf);
+ /* FIXME: use an array of byte or block backend property? */
+ SMBUS_EEPROM(dev)->init_data = eeprom_buf;
qdev_init_nofail(dev);
}
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 7b8da62d41..e25df838f0 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -68,6 +68,7 @@
#include "hw/i386/intel_iommu.h"
#include "hw/acpi/ipmi.h"
+#include "hw/acpi/hmat.h"
/* These are used to size the ACPI tables for -M pc-i440fx-1.7 and
* -M pc-i440fx-2.0. Even if the actual amount of AML generated grows
@@ -2835,6 +2836,10 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
acpi_add_table(table_offsets, tables_blob);
build_slit(tables_blob, tables->linker, machine);
}
+ if (machine->numa_state->hmat_enabled) {
+ acpi_add_table(table_offsets, tables_blob);
+ build_hmat(tables_blob, tables->linker, machine->numa_state);
+ }
}
if (acpi_get_mcfg(&mcfg)) {
acpi_add_table(table_offsets, tables_blob);
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 43c94b993b..a523ef0e65 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -686,9 +686,18 @@ static inline bool vtd_pe_type_check(X86IOMMUState *x86_iommu,
return true;
}
-static int vtd_get_pasid_dire(dma_addr_t pasid_dir_base,
- uint32_t pasid,
- VTDPASIDDirEntry *pdire)
+static inline bool vtd_pdire_present(VTDPASIDDirEntry *pdire)
+{
+ return pdire->val & 1;
+}
+
+/**
+ * Caller of this function should check present bit if wants
+ * to use pdir entry for futher usage except for fpd bit check.
+ */
+static int vtd_get_pdire_from_pdir_table(dma_addr_t pasid_dir_base,
+ uint32_t pasid,
+ VTDPASIDDirEntry *pdire)
{
uint32_t index;
dma_addr_t addr, entry_size;
@@ -703,18 +712,22 @@ static int vtd_get_pasid_dire(dma_addr_t pasid_dir_base,
return 0;
}
-static int vtd_get_pasid_entry(IntelIOMMUState *s,
- uint32_t pasid,
- VTDPASIDDirEntry *pdire,
- VTDPASIDEntry *pe)
+static inline bool vtd_pe_present(VTDPASIDEntry *pe)
+{
+ return pe->val[0] & VTD_PASID_ENTRY_P;
+}
+
+static int vtd_get_pe_in_pasid_leaf_table(IntelIOMMUState *s,
+ uint32_t pasid,
+ dma_addr_t addr,
+ VTDPASIDEntry *pe)
{
uint32_t index;
- dma_addr_t addr, entry_size;
+ dma_addr_t entry_size;
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
index = VTD_PASID_TABLE_INDEX(pasid);
entry_size = VTD_PASID_ENTRY_SIZE;
- addr = pdire->val & VTD_PASID_TABLE_BASE_ADDR_MASK;
addr = addr + index * entry_size;
if (dma_memory_read(&address_space_memory, addr, pe, entry_size)) {
return -VTD_FR_PASID_TABLE_INV;
@@ -732,25 +745,54 @@ static int vtd_get_pasid_entry(IntelIOMMUState *s,
return 0;
}
-static int vtd_get_pasid_entry_from_pasid(IntelIOMMUState *s,
- dma_addr_t pasid_dir_base,
- uint32_t pasid,
- VTDPASIDEntry *pe)
+/**
+ * Caller of this function should check present bit if wants
+ * to use pasid entry for futher usage except for fpd bit check.
+ */
+static int vtd_get_pe_from_pdire(IntelIOMMUState *s,
+ uint32_t pasid,
+ VTDPASIDDirEntry *pdire,
+ VTDPASIDEntry *pe)
+{
+ dma_addr_t addr = pdire->val & VTD_PASID_TABLE_BASE_ADDR_MASK;
+
+ return vtd_get_pe_in_pasid_leaf_table(s, pasid, addr, pe);
+}
+
+/**
+ * This function gets a pasid entry from a specified pasid
+ * table (includes dir and leaf table) with a specified pasid.
+ * Sanity check should be done to ensure return a present
+ * pasid entry to caller.
+ */
+static int vtd_get_pe_from_pasid_table(IntelIOMMUState *s,
+ dma_addr_t pasid_dir_base,
+ uint32_t pasid,
+ VTDPASIDEntry *pe)
{
int ret;
VTDPASIDDirEntry pdire;
- ret = vtd_get_pasid_dire(pasid_dir_base, pasid, &pdire);
+ ret = vtd_get_pdire_from_pdir_table(pasid_dir_base,
+ pasid, &pdire);
if (ret) {
return ret;
}
- ret = vtd_get_pasid_entry(s, pasid, &pdire, pe);
+ if (!vtd_pdire_present(&pdire)) {
+ return -VTD_FR_PASID_TABLE_INV;
+ }
+
+ ret = vtd_get_pe_from_pdire(s, pasid, &pdire, pe);
if (ret) {
return ret;
}
- return ret;
+ if (!vtd_pe_present(pe)) {
+ return -VTD_FR_PASID_TABLE_INV;
+ }
+
+ return 0;
}
static int vtd_ce_get_rid2pasid_entry(IntelIOMMUState *s,
@@ -763,7 +805,7 @@ static int vtd_ce_get_rid2pasid_entry(IntelIOMMUState *s,
pasid = VTD_CE_GET_RID2PASID(ce);
pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce);
- ret = vtd_get_pasid_entry_from_pasid(s, pasid_dir_base, pasid, pe);
+ ret = vtd_get_pe_from_pasid_table(s, pasid_dir_base, pasid, pe);
return ret;
}
@@ -781,7 +823,11 @@ static int vtd_ce_get_pasid_fpd(IntelIOMMUState *s,
pasid = VTD_CE_GET_RID2PASID(ce);
pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce);
- ret = vtd_get_pasid_dire(pasid_dir_base, pasid, &pdire);
+ /*
+ * No present bit check since fpd is meaningful even
+ * if the present bit is clear.
+ */
+ ret = vtd_get_pdire_from_pdir_table(pasid_dir_base, pasid, &pdire);
if (ret) {
return ret;
}
@@ -791,7 +837,15 @@ static int vtd_ce_get_pasid_fpd(IntelIOMMUState *s,
return 0;
}
- ret = vtd_get_pasid_entry(s, pasid, &pdire, &pe);
+ if (!vtd_pdire_present(&pdire)) {
+ return -VTD_FR_PASID_TABLE_INV;
+ }
+
+ /*
+ * No present bit check since fpd is meaningful even
+ * if the present bit is clear.
+ */
+ ret = vtd_get_pe_from_pdire(s, pasid, &pdire, &pe);
if (ret) {
return ret;
}
@@ -948,6 +1002,7 @@ static VTDBus *vtd_find_as_from_bus_num(IntelIOMMUState *s, uint8_t bus_num)
return vtd_bus;
}
}
+ vtd_bus = NULL;
}
return vtd_bus;
}
@@ -2610,16 +2665,15 @@ static uint64_t vtd_mem_read(void *opaque, hwaddr addr, unsigned size)
switch (addr) {
/* Root Table Address Register, 64-bit */
case DMAR_RTADDR_REG:
+ val = vtd_get_quad_raw(s, DMAR_RTADDR_REG);
if (size == 4) {
- val = s->root & ((1ULL << 32) - 1);
- } else {
- val = s->root;
+ val = val & ((1ULL << 32) - 1);
}
break;
case DMAR_RTADDR_REG_HI:
assert(size == 4);
- val = s->root >> 32;
+ val = vtd_get_quad_raw(s, DMAR_RTADDR_REG) >> 32;
break;
/* Invalidation Queue Address Register, 64-bit */
diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h
index edcf9fc9bb..862033ebe6 100644
--- a/hw/i386/intel_iommu_internal.h
+++ b/hw/i386/intel_iommu_internal.h
@@ -479,6 +479,7 @@ typedef struct VTDRootEntry VTDRootEntry;
#define VTD_PASID_ENTRY_FPD (1ULL << 1) /* Fault Processing Disable */
/* PASID Granular Translation Type Mask */
+#define VTD_PASID_ENTRY_P 1ULL
#define VTD_SM_PASID_ENTRY_PGTT (7ULL << 6)
#define VTD_SM_PASID_ENTRY_FLT (1ULL << 6)
#define VTD_SM_PASID_ENTRY_SLT (2ULL << 6)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 42014b06de..8054bc4147 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1156,9 +1156,9 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport)
vmmouse = NULL;
}
if (vmmouse) {
- DeviceState *dev = DEVICE(vmmouse);
- qdev_prop_set_ptr(dev, "ps2_mouse", i8042);
- qdev_init_nofail(dev);
+ object_property_set_link(OBJECT(vmmouse), OBJECT(i8042),
+ "i8042", &error_abort);
+ qdev_init_nofail(DEVICE(vmmouse));
}
port92 = isa_create_simple(isa_bus, TYPE_PORT92);
@@ -1198,7 +1198,6 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
* when the HPET wants to take over. Thus we have to disable the latter.
*/
if (!no_hpet && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) {
- /* In order to set property, here not using sysbus_try_create_simple */
hpet = qdev_try_create(NULL, TYPE_HPET);
if (hpet) {
/* For pc-piix-*, hpet's intcap is always IRQ2. For pc-q35-1.7
diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c
index 41ad91ad53..c0c329f817 100644
--- a/hw/i386/vmmouse.c
+++ b/hw/i386/vmmouse.c
@@ -66,7 +66,7 @@ typedef struct VMMouseState
uint16_t status;
uint8_t absolute;
QEMUPutMouseEntry *entry;
- void *ps2_mouse;
+ ISAKBDState *i8042;
} VMMouseState;
static uint32_t vmmouse_get_status(VMMouseState *s)
@@ -105,7 +105,7 @@ static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_
/* need to still generate PS2 events to notify driver to
read from queue */
- i8042_isa_mouse_fake_event(s->ps2_mouse);
+ i8042_isa_mouse_fake_event(s->i8042);
}
static void vmmouse_remove_handler(VMMouseState *s)
@@ -275,7 +275,7 @@ static void vmmouse_realizefn(DeviceState *dev, Error **errp)
}
static Property vmmouse_properties[] = {
- DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse),
+ DEFINE_PROP_LINK("i8042", VMMouseState, i8042, TYPE_I8042, ISAKBDState *),
DEFINE_PROP_END_OF_LIST(),
};
@@ -287,8 +287,6 @@ static void vmmouse_class_initfn(ObjectClass *klass, void *data)
dc->reset = vmmouse_reset;
dc->vmsd = &vmstate_vmmouse;
dc->props = vmmouse_properties;
- /* Reason: pointer property "ps2_mouse" */
- dc->user_creatable = false;
}
static const TypeInfo vmmouse_info = {
diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c
index 2f09f780ba..60a4130320 100644
--- a/hw/input/pckbd.c
+++ b/hw/input/pckbd.c
@@ -482,17 +482,15 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
#define I8042(obj) OBJECT_CHECK(ISAKBDState, (obj), TYPE_I8042)
-typedef struct ISAKBDState {
+struct ISAKBDState {
ISADevice parent_obj;
KBDState kbd;
MemoryRegion io[2];
-} ISAKBDState;
+};
-void i8042_isa_mouse_fake_event(void *opaque)
+void i8042_isa_mouse_fake_event(ISAKBDState *isa)
{
- ISADevice *dev = opaque;
- ISAKBDState *isa = I8042(dev);
KBDState *s = &isa->kbd;
ps2_mouse_fake_event(s->mouse);
diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
index ec54e46ad6..9c013afddb 100644
--- a/hw/input/virtio-input.c
+++ b/hw/input/virtio-input.c
@@ -280,6 +280,7 @@ static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
{
VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ VirtIOInput *vinput = VIRTIO_INPUT(dev);
Error *local_err = NULL;
if (vic->unrealize) {
@@ -289,8 +290,8 @@ static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
return;
}
}
- virtio_del_queue(vdev, 0);
- virtio_del_queue(vdev, 1);
+ virtio_delete_queue(vinput->evt);
+ virtio_delete_queue(vinput->sts);
virtio_cleanup(vdev);
}
diff --git a/hw/intc/etraxfs_pic.c b/hw/intc/etraxfs_pic.c
index 77f652acec..12988c7aa9 100644
--- a/hw/intc/etraxfs_pic.c
+++ b/hw/intc/etraxfs_pic.c
@@ -27,8 +27,6 @@
#include "qemu/module.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
-//#include "pc.h"
-//#include "etraxfs.h"
#define D(x)
@@ -48,7 +46,6 @@ struct etrax_pic
SysBusDevice parent_obj;
MemoryRegion mmio;
- void *interrupt_vector;
qemu_irq parent_irq;
qemu_irq parent_nmi;
uint32_t regs[R_MAX];
@@ -79,11 +76,7 @@ static void pic_update(struct etrax_pic *fs)
}
}
- if (fs->interrupt_vector) {
- /* hack alert: ptr property */
- *(uint32_t*)(fs->interrupt_vector) = vector;
- }
- qemu_set_irq(fs->parent_irq, !!vector);
+ qemu_set_irq(fs->parent_irq, vector);
}
static uint64_t
@@ -163,28 +156,11 @@ static void etraxfs_pic_init(Object *obj)
sysbus_init_mmio(sbd, &s->mmio);
}
-static Property etraxfs_pic_properties[] = {
- DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void etraxfs_pic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->props = etraxfs_pic_properties;
- /*
- * Note: pointer property "interrupt_vector" may remain null, thus
- * no need for dc->user_creatable = false;
- */
-}
-
static const TypeInfo etraxfs_pic_info = {
.name = TYPE_ETRAX_FS_PIC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(struct etrax_pic),
.instance_init = etraxfs_pic_init,
- .class_init = etraxfs_pic_class_init,
};
static void etraxfs_pic_register_types(void)
diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c
index bc78e1a14f..794c643af2 100644
--- a/hw/intc/grlib_irqmp.c
+++ b/hw/intc/grlib_irqmp.c
@@ -25,6 +25,7 @@
*/
#include "qemu/osdep.h"
+#include "hw/irq.h"
#include "hw/sysbus.h"
#include "cpu.h"
@@ -58,10 +59,8 @@ typedef struct IRQMP {
MemoryRegion iomem;
- void *set_pil_in;
- void *set_pil_in_opaque;
-
IRQMPState *state;
+ qemu_irq irq;
} IRQMP;
struct IRQMPState {
@@ -82,7 +81,6 @@ static void grlib_irqmp_check_irqs(IRQMPState *state)
uint32_t pend = 0;
uint32_t level0 = 0;
uint32_t level1 = 0;
- set_pil_in_fn set_pil_in;
assert(state != NULL);
assert(state->parent != NULL);
@@ -97,14 +95,8 @@ static void grlib_irqmp_check_irqs(IRQMPState *state)
trace_grlib_irqmp_check_irqs(state->pending, state->force[0],
state->mask[0], level1, level0);
- set_pil_in = (set_pil_in_fn)state->parent->set_pil_in;
-
/* Trigger level1 interrupt first and level0 if there is no level1 */
- if (level1 != 0) {
- set_pil_in(state->parent->set_pil_in_opaque, level1);
- } else {
- set_pil_in(state->parent->set_pil_in_opaque, level0);
- }
+ qemu_set_irq(state->parent->irq, level1 ?: level0);
}
static void grlib_irqmp_ack_mask(IRQMPState *state, uint32_t mask)
@@ -335,6 +327,7 @@ static void grlib_irqmp_init(Object *obj)
IRQMP *irqmp = GRLIB_IRQMP(obj);
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
+ qdev_init_gpio_out_named(DEVICE(obj), &irqmp->irq, "grlib-irq", 1);
memory_region_init_io(&irqmp->iomem, obj, &grlib_irqmp_ops, irqmp,
"irqmp", IRQMP_REG_SIZE);
@@ -343,31 +336,11 @@ static void grlib_irqmp_init(Object *obj)
sysbus_init_mmio(dev, &irqmp->iomem);
}
-static void grlib_irqmp_realize(DeviceState *dev, Error **errp)
-{
- IRQMP *irqmp = GRLIB_IRQMP(dev);
-
- /* Check parameters */
- if (irqmp->set_pil_in == NULL) {
- error_setg(errp, "set_pil_in cannot be NULL.");
- }
-}
-
-static Property grlib_irqmp_properties[] = {
- DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
- DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void grlib_irqmp_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->reset = grlib_irqmp_reset;
- dc->props = grlib_irqmp_properties;
- /* Reason: pointer properties "set_pil_in", "set_pil_in_opaque" */
- dc->user_creatable = false;
- dc->realize = grlib_irqmp_realize;
}
static const TypeInfo grlib_irqmp_info = {
diff --git a/hw/intc/omap_intc.c b/hw/intc/omap_intc.c
index 854b709ca0..73bb1c2af4 100644
--- a/hw/intc/omap_intc.c
+++ b/hw/intc/omap_intc.c
@@ -38,10 +38,6 @@ struct omap_intr_handler_bank_s {
unsigned char priority[32];
};
-#define TYPE_OMAP_INTC "common-omap-intc"
-#define OMAP_INTC(obj) \
- OBJECT_CHECK(struct omap_intr_handler_s, (obj), TYPE_OMAP_INTC)
-
struct omap_intr_handler_s {
SysBusDevice parent_obj;
@@ -391,9 +387,18 @@ static void omap_intc_realize(DeviceState *dev, Error **errp)
}
}
+void omap_intc_set_iclk(omap_intr_handler *intc, omap_clk clk)
+{
+ intc->iclk = clk;
+}
+
+void omap_intc_set_fclk(omap_intr_handler *intc, omap_clk clk)
+{
+ intc->fclk = clk;
+}
+
static Property omap_intc_properties[] = {
DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
- DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
DEFINE_PROP_END_OF_LIST(),
};
@@ -647,8 +652,6 @@ static void omap2_intc_realize(DeviceState *dev, Error **errp)
static Property omap2_intc_properties[] = {
DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
revision, 0x21),
- DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
- DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c
index a0a69b98a7..715fca61ae 100644
--- a/hw/intc/pnv_xive.c
+++ b/hw/intc/pnv_xive.c
@@ -472,12 +472,8 @@ static uint8_t pnv_xive_get_block_id(XiveRouter *xrtr)
static PnvXive *pnv_xive_tm_get_xive(PowerPCCPU *cpu)
{
int pir = ppc_cpu_pir(cpu);
- PnvChip *chip;
- PnvXive *xive;
-
- chip = pnv_get_chip(PNV9_PIR2CHIP(pir));
- assert(chip);
- xive = &PNV9_CHIP(chip)->xive;
+ XivePresenter *xptr = XIVE_TCTX(pnv_cpu_state(cpu)->intc)->xptr;
+ PnvXive *xive = PNV_XIVE(xptr);
if (!pnv_xive_is_cpu_enabled(xive, cpu)) {
xive_error(xive, "IC: CPU %x is not enabled", pir);
@@ -1816,10 +1812,17 @@ static void pnv_xive_init(Object *obj)
static void pnv_xive_realize(DeviceState *dev, Error **errp)
{
PnvXive *xive = PNV_XIVE(dev);
+ PnvXiveClass *pxc = PNV_XIVE_GET_CLASS(dev);
XiveSource *xsrc = &xive->ipi_source;
XiveENDSource *end_xsrc = &xive->end_source;
Error *local_err = NULL;
+ pxc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
assert(xive->chip);
/*
@@ -1947,10 +1950,12 @@ static void pnv_xive_class_init(ObjectClass *klass, void *data)
XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass);
XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass);
XivePresenterClass *xpc = XIVE_PRESENTER_CLASS(klass);
+ PnvXiveClass *pxc = PNV_XIVE_CLASS(klass);
xdc->dt_xscom = pnv_xive_dt_xscom;
dc->desc = "PowerNV XIVE Interrupt Controller";
+ device_class_set_parent_realize(dc, pnv_xive_realize, &pxc->parent_realize);
dc->realize = pnv_xive_realize;
dc->props = pnv_xive_properties;
@@ -1971,6 +1976,7 @@ static const TypeInfo pnv_xive_info = {
.instance_init = pnv_xive_init,
.instance_size = sizeof(PnvXive),
.class_init = pnv_xive_class_init,
+ .class_size = sizeof(PnvXiveClass),
.interfaces = (InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
index 57305c56d7..7663123878 100644
--- a/hw/intc/spapr_xive.c
+++ b/hw/intc/spapr_xive.c
@@ -286,10 +286,17 @@ static void spapr_xive_instance_init(Object *obj)
static void spapr_xive_realize(DeviceState *dev, Error **errp)
{
SpaprXive *xive = SPAPR_XIVE(dev);
+ SpaprXiveClass *sxc = SPAPR_XIVE_GET_CLASS(xive);
XiveSource *xsrc = &xive->source;
XiveENDSource *end_xsrc = &xive->end_source;
Error *local_err = NULL;
+ sxc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
if (!xive->nr_irqs) {
error_setg(errp, "Number of interrupt needs to be greater 0");
return;
@@ -594,7 +601,7 @@ static int spapr_xive_cpu_intc_create(SpaprInterruptController *intc,
Object *obj;
SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
- obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(xive), errp);
+ obj = xive_tctx_create(OBJECT(cpu), XIVE_PRESENTER(xive), errp);
if (!obj) {
return -1;
}
@@ -760,10 +767,12 @@ static void spapr_xive_class_init(ObjectClass *klass, void *data)
XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass);
SpaprInterruptControllerClass *sicc = SPAPR_INTC_CLASS(klass);
XivePresenterClass *xpc = XIVE_PRESENTER_CLASS(klass);
+ SpaprXiveClass *sxc = SPAPR_XIVE_CLASS(klass);
dc->desc = "sPAPR XIVE Interrupt Controller";
dc->props = spapr_xive_properties;
- dc->realize = spapr_xive_realize;
+ device_class_set_parent_realize(dc, spapr_xive_realize,
+ &sxc->parent_realize);
dc->vmsd = &vmstate_spapr_xive;
xrc->get_eas = spapr_xive_get_eas;
@@ -794,6 +803,7 @@ static const TypeInfo spapr_xive_info = {
.instance_init = spapr_xive_instance_init,
.instance_size = sizeof(SpaprXive),
.class_init = spapr_xive_class_init,
+ .class_size = sizeof(SpaprXiveClass),
.interfaces = (InterfaceInfo[]) {
{ TYPE_SPAPR_INTC },
{ }
diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c
index 32b2809210..edb7ee0e74 100644
--- a/hw/intc/spapr_xive_kvm.c
+++ b/hw/intc/spapr_xive_kvm.c
@@ -75,7 +75,7 @@ static void kvm_cpu_disable_all(void)
void kvmppc_xive_cpu_set_state(XiveTCTX *tctx, Error **errp)
{
- SpaprXive *xive = SPAPR_MACHINE(qdev_get_machine())->xive;
+ SpaprXive *xive = SPAPR_XIVE(tctx->xptr);
uint64_t state[2];
int ret;
@@ -97,7 +97,7 @@ void kvmppc_xive_cpu_set_state(XiveTCTX *tctx, Error **errp)
void kvmppc_xive_cpu_get_state(XiveTCTX *tctx, Error **errp)
{
- SpaprXive *xive = SPAPR_MACHINE(qdev_get_machine())->xive;
+ SpaprXive *xive = SPAPR_XIVE(tctx->xptr);
uint64_t state[2] = { 0 };
int ret;
@@ -152,8 +152,7 @@ void kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp)
void kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp)
{
- MachineState *ms = MACHINE(qdev_get_machine());
- SpaprXive *xive = SPAPR_MACHINE(ms)->xive;
+ SpaprXive *xive = SPAPR_XIVE(tctx->xptr);
unsigned long vcpu_id;
int ret;
@@ -179,7 +178,7 @@ void kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp)
vcpu_id, strerror(errno));
if (errno == ENOSPC) {
error_append_hint(&local_err, "Try -smp maxcpus=N with N < %u\n",
- ms->smp.max_cpus);
+ MACHINE(qdev_get_machine())->smp.max_cpus);
}
error_propagate(errp, local_err);
return;
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index d4c6e21703..bc8019c4c9 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -654,6 +654,7 @@ static void xive_tctx_realize(DeviceState *dev, Error **errp)
Error *local_err = NULL;
assert(tctx->cs);
+ assert(tctx->xptr);
cpu = POWERPC_CPU(tctx->cs);
env = &cpu->env;
@@ -727,6 +728,8 @@ static const VMStateDescription vmstate_xive_tctx = {
static Property xive_tctx_properties[] = {
DEFINE_PROP_LINK("cpu", XiveTCTX, cs, TYPE_CPU, CPUState *),
+ DEFINE_PROP_LINK("presenter", XiveTCTX, xptr, TYPE_XIVE_PRESENTER,
+ XivePresenter *),
DEFINE_PROP_END_OF_LIST(),
};
@@ -752,7 +755,7 @@ static const TypeInfo xive_tctx_info = {
.class_init = xive_tctx_class_init,
};
-Object *xive_tctx_create(Object *cpu, XiveRouter *xrtr, Error **errp)
+Object *xive_tctx_create(Object *cpu, XivePresenter *xptr, Error **errp)
{
Error *local_err = NULL;
Object *obj;
@@ -761,6 +764,7 @@ Object *xive_tctx_create(Object *cpu, XiveRouter *xrtr, Error **errp)
object_property_add_child(cpu, TYPE_XIVE_TCTX, obj, &error_abort);
object_unref(obj);
object_property_set_link(obj, cpu, "cpu", &error_abort);
+ object_property_set_link(obj, OBJECT(xptr), "presenter", &error_abort);
object_property_set_bool(obj, true, "realized", &local_err);
if (local_err) {
goto error;
@@ -1378,6 +1382,13 @@ static int xive_router_get_block_id(XiveRouter *xrtr)
return xrc->get_block_id(xrtr);
}
+static void xive_router_realize(DeviceState *dev, Error **errp)
+{
+ XiveRouter *xrtr = XIVE_ROUTER(dev);
+
+ assert(xrtr->xfb);
+}
+
/*
* Encode the HW CAM line in the block group mode format :
*
@@ -1470,12 +1481,11 @@ int xive_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
*
* The parameters represent what is sent on the PowerBus
*/
-static bool xive_presenter_notify(uint8_t format,
+static bool xive_presenter_notify(XiveFabric *xfb, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
bool cam_ignore, uint8_t priority,
uint32_t logic_serv)
{
- XiveFabric *xfb = XIVE_FABRIC(qdev_get_machine());
XiveFabricClass *xfc = XIVE_FABRIC_GET_CLASS(xfb);
XiveTCTXMatch match = { .tctx = NULL, .ring = 0 };
int count;
@@ -1607,7 +1617,7 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
return;
}
- found = xive_presenter_notify(format, nvt_blk, nvt_idx,
+ found = xive_presenter_notify(xrtr->xfb, format, nvt_blk, nvt_idx,
xive_get_field32(END_W7_F0_IGNORE, end.w7),
priority,
xive_get_field32(END_W7_F1_LOG_SERVER_ID, end.w7));
@@ -1714,12 +1724,21 @@ void xive_router_notify(XiveNotifier *xn, uint32_t lisn)
xive_get_field64(EAS_END_DATA, eas.w));
}
+static Property xive_router_properties[] = {
+ DEFINE_PROP_LINK("xive-fabric", XiveRouter, xfb,
+ TYPE_XIVE_FABRIC, XiveFabric *),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void xive_router_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass);
dc->desc = "XIVE Router Engine";
+ dc->props = xive_router_properties;
+ /* Parent is SysBusDeviceClass. No need to call its realize hook */
+ dc->realize = xive_router_realize;
xnc->notify = xive_router_notify;
}
@@ -1727,6 +1746,7 @@ static const TypeInfo xive_router_info = {
.name = TYPE_XIVE_ROUTER,
.parent = TYPE_SYS_BUS_DEVICE,
.abstract = true,
+ .instance_size = sizeof(XiveRouter),
.class_size = sizeof(XiveRouterClass),
.class_init = xive_router_class_init,
.interfaces = (InterfaceInfo[]) {
diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index 4ca8678007..12491ecde6 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -47,7 +47,7 @@
#include "sysemu/runstate.h"
#include "sysemu/reset.h"
-#define MACROM_ADDR 0x40000000
+#define MACROM_ADDR 0x40800000
#define MACROM_SIZE 0x00100000
#define MACROM_FILENAME "MacROM.bin"
@@ -128,6 +128,27 @@ static void main_cpu_reset(void *opaque)
cpu->env.pc = ldl_phys(cs->as, 4);
}
+static uint8_t fake_mac_rom[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ /* offset: 0xa - mac_reset */
+
+ /* via2[vDirB] |= VIA2B_vPower */
+ 0x20, 0x7C, 0x50, 0xF0, 0x24, 0x00, /* moveal VIA2_BASE+vDirB,%a0 */
+ 0x10, 0x10, /* moveb %a0@,%d0 */
+ 0x00, 0x00, 0x00, 0x04, /* orib #4,%d0 */
+ 0x10, 0x80, /* moveb %d0,%a0@ */
+
+ /* via2[vBufB] &= ~VIA2B_vPower */
+ 0x20, 0x7C, 0x50, 0xF0, 0x20, 0x00, /* moveal VIA2_BASE+vBufB,%a0 */
+ 0x10, 0x10, /* moveb %a0@,%d0 */
+ 0x02, 0x00, 0xFF, 0xFB, /* andib #-5,%d0 */
+ 0x10, 0x80, /* moveb %d0,%a0@ */
+
+ /* while (true) ; */
+ 0x60, 0xFE /* bras [self] */
+};
+
static void q800_init(MachineState *machine)
{
M68kCPU *cpu = NULL;
@@ -158,6 +179,7 @@ static void q800_init(MachineState *machine)
NubusBus *nubus;
GLUEState *irq;
qemu_irq *pic;
+ DriveInfo *dinfo;
linux_boot = (kernel_filename != NULL);
@@ -200,6 +222,11 @@ static void q800_init(MachineState *machine)
/* VIA */
via_dev = qdev_create(NULL, TYPE_MAC_VIA);
+ dinfo = drive_get(IF_MTD, 0, 0);
+ if (dinfo) {
+ qdev_prop_set_drive(via_dev, "drive", blk_by_legacy_dinfo(dinfo),
+ &error_abort);
+ }
qdev_init_nofail(via_dev);
sysbus = SYS_BUS_DEVICE(via_dev);
sysbus_mmio_map(sysbus, 0, VIA_BASE);
@@ -239,7 +266,8 @@ static void q800_init(MachineState *machine)
qdev_set_nic_properties(dev, &nd_table[0]);
qdev_prop_set_uint8(dev, "it_shift", 2);
qdev_prop_set_bit(dev, "big_endian", true);
- qdev_prop_set_ptr(dev, "dma_mr", get_system_memory());
+ object_property_set_link(OBJECT(dev), OBJECT(get_system_memory()),
+ "dma_mr", &error_abort);
qdev_init_nofail(dev);
sysbus = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(sysbus, 0, SONIC_BASE);
@@ -340,6 +368,12 @@ static void q800_init(MachineState *machine)
(graphic_width * graphic_depth + 7) / 8);
BOOTINFO1(cs->as, parameters_base, BI_MAC_SCCBASE, SCC_BASE);
+ rom = g_malloc(sizeof(*rom));
+ memory_region_init_ram_ptr(rom, NULL, "m68k_fake_mac.rom",
+ sizeof(fake_mac_rom), fake_mac_rom);
+ memory_region_set_readonly(rom, true);
+ memory_region_add_subregion(get_system_memory(), MACROM_ADDR, rom);
+
if (kernel_cmdline) {
BOOTINFOSTR(cs->as, parameters_base, BI_COMMAND_LINE,
kernel_cmdline);
diff --git a/hw/mips/boston.c b/hw/mips/boston.c
index 29b476b4bd..0df3a7755a 100644
--- a/hw/mips/boston.c
+++ b/hw/mips/boston.c
@@ -50,7 +50,7 @@ typedef struct {
MachineState *mach;
MIPSCPSState cps;
- SerialState *uart;
+ SerialMM *uart;
CharBackend lcd_display;
char lcd_content[8];
diff --git a/hw/mips/cps.c b/hw/mips/cps.c
index 1660f86908..c49868d5da 100644
--- a/hw/mips/cps.c
+++ b/hw/mips/cps.c
@@ -106,7 +106,7 @@ static void mips_cps_realize(DeviceState *dev, Error **errp)
object_property_set_bool(OBJECT(&s->itu), saar_present, "saar-present",
&err);
if (saar_present) {
- qdev_prop_set_ptr(DEVICE(&s->itu), "saar", (void *)&env->CP0_SAAR);
+ s->itu.saar = &env->CP0_SAAR;
}
object_property_set_bool(OBJECT(&s->itu), true, "realized", &err);
if (err != NULL) {
diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c
index 291fd6c1b8..66fd4d867d 100644
--- a/hw/mips/mips_jazz.c
+++ b/hw/mips/mips_jazz.c
@@ -290,7 +290,8 @@ static void mips_jazz_init(MachineState *machine,
dev = qdev_create(NULL, "dp8393x");
qdev_set_nic_properties(dev, nd);
qdev_prop_set_uint8(dev, "it_shift", 2);
- qdev_prop_set_ptr(dev, "dma_mr", rc4030_dma_mr);
+ object_property_set_link(OBJECT(dev), OBJECT(rc4030_dma_mr),
+ "dma_mr", &error_abort);
qdev_init_nofail(dev);
sysbus = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(sysbus, 0, 0x80001000);
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index 72c03baa8e..5aaeaa8d53 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -83,7 +83,7 @@ typedef struct {
uint32_t i2csel;
CharBackend display;
char display_text[9];
- SerialState *uart;
+ SerialMM *uart;
bool display_inited;
} MaltaFPGAState;
diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mips_mipssim.c
index 282bbecb24..84c03dd035 100644
--- a/hw/mips/mips_mipssim.c
+++ b/hw/mips/mips_mipssim.c
@@ -40,6 +40,7 @@
#include "hw/loader.h"
#include "elf.h"
#include "hw/sysbus.h"
+#include "hw/qdev-properties.h"
#include "exec/address-spaces.h"
#include "qemu/error-report.h"
#include "sysemu/qtest.h"
@@ -219,9 +220,16 @@ mips_mipssim_init(MachineState *machine)
* A single 16450 sits at offset 0x3f8. It is attached to
* MIPS CPU INT2, which is interrupt 4.
*/
- if (serial_hd(0))
- serial_init(0x3f8, env->irq[4], 115200, serial_hd(0),
- get_system_io());
+ if (serial_hd(0)) {
+ DeviceState *dev = qdev_create(NULL, TYPE_SERIAL_IO);
+
+ qdev_prop_set_chr(dev, "chardev", serial_hd(0));
+ qdev_set_legacy_instance_id(dev, 0x3f8, 2);
+ qdev_init_nofail(dev);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, env->irq[4]);
+ sysbus_add_io(SYS_BUS_DEVICE(dev), 0x3f8,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
+ }
if (nd_table[0].used)
/* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */
diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c
index f3f130ad96..e9e6a95eab 100644
--- a/hw/misc/mac_via.c
+++ b/hw/misc/mac_via.c
@@ -27,7 +27,9 @@
#include "sysemu/runstate.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
-
+#include "hw/qdev-properties.h"
+#include "sysemu/block-backend.h"
+#include "trace.h"
/*
* VIAs: There are two in every machine,
@@ -278,6 +280,21 @@
/* VIA returns time offset from Jan 1, 1904, not 1970 */
#define RTC_OFFSET 2082844800
+enum {
+ REG_0,
+ REG_1,
+ REG_2,
+ REG_3,
+ REG_TEST,
+ REG_WPROTECT,
+ REG_PRAM_ADDR,
+ REG_PRAM_ADDR_LAST = REG_PRAM_ADDR + 19,
+ REG_PRAM_SECT,
+ REG_PRAM_SECT_LAST = REG_PRAM_SECT + 7,
+ REG_INVALID,
+ REG_EMPTY = 0xff,
+};
+
static void via1_VBL_update(MOS6522Q800VIA1State *v1s)
{
MOS6522State *s = MOS6522(v1s);
@@ -360,10 +377,71 @@ static void via2_irq_request(void *opaque, int irq, int level)
mdc->update_irq(s);
}
+
+static void pram_update(MacVIAState *m)
+{
+ if (m->blk) {
+ blk_pwrite(m->blk, 0, m->mos6522_via1.PRAM,
+ sizeof(m->mos6522_via1.PRAM), 0);
+ }
+}
+
+/*
+ * RTC Commands
+ *
+ * Command byte Register addressed by the command
+ *
+ * z0000001 Seconds register 0 (lowest-order byte)
+ * z0000101 Seconds register 1
+ * z0001001 Seconds register 2
+ * z0001101 Seconds register 3 (highest-order byte)
+ * 00110001 Test register (write-only)
+ * 00110101 Write-Protect Register (write-only)
+ * z010aa01 RAM address 100aa ($10-$13) (first 20 bytes only)
+ * z1aaaa01 RAM address 0aaaa ($00-$0F) (first 20 bytes only)
+ * z0111aaa Extended memory designator and sector number
+ *
+ * For a read request, z=1, for a write z=0
+ * The letter a indicates bits whose value depend on what parameter
+ * RAM byte you want to address
+ */
+static int via1_rtc_compact_cmd(uint8_t value)
+{
+ uint8_t read = value & 0x80;
+
+ value &= 0x7f;
+
+ /* the last 2 bits of a command byte must always be 0b01 ... */
+ if ((value & 0x78) == 0x38) {
+ /* except for the extended memory designator */
+ return read | (REG_PRAM_SECT + (value & 0x07));
+ }
+ if ((value & 0x03) == 0x01) {
+ value >>= 2;
+ if ((value & 0x1c) == 0) {
+ /* seconds registers */
+ return read | (REG_0 + (value & 0x03));
+ } else if ((value == 0x0c) && !read) {
+ return REG_TEST;
+ } else if ((value == 0x0d) && !read) {
+ return REG_WPROTECT;
+ } else if ((value & 0x1c) == 0x08) {
+ /* RAM address 0x10 to 0x13 */
+ return read | (REG_PRAM_ADDR + 0x10 + (value & 0x03));
+ } else if ((value & 0x43) == 0x41) {
+ /* RAM address 0x00 to 0x0f */
+ return read | (REG_PRAM_ADDR + (value & 0x0f));
+ }
+ }
+ return REG_INVALID;
+}
+
static void via1_rtc_update(MacVIAState *m)
{
MOS6522Q800VIA1State *v1s = &m->mos6522_via1;
MOS6522State *s = MOS6522(v1s);
+ int cmd, sector, addr;
+ uint32_t time;
if (s->b & VIA1B_vRTCEnb) {
return;
@@ -376,7 +454,9 @@ static void via1_rtc_update(MacVIAState *m)
m->data_out |= s->b & VIA1B_vRTCData;
m->data_out_cnt++;
}
+ trace_via1_rtc_update_data_out(m->data_out_cnt, m->data_out);
} else {
+ trace_via1_rtc_update_data_in(m->data_in_cnt, m->data_in);
/* receive bits from the RTC */
if ((v1s->last_b & VIA1B_vRTCClk) &&
!(s->b & VIA1B_vRTCClk) &&
@@ -386,96 +466,134 @@ static void via1_rtc_update(MacVIAState *m)
m->data_in <<= 1;
m->data_in_cnt--;
}
+ return;
}
- if (m->data_out_cnt == 8) {
- m->data_out_cnt = 0;
-
- if (m->cmd == 0) {
- if (m->data_out & 0x80) {
- /* this is a read command */
- uint32_t time = m->tick_offset +
- (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) /
- NANOSECONDS_PER_SECOND);
- if (m->data_out == 0x81) { /* seconds register 0 */
- m->data_in = time & 0xff;
- m->data_in_cnt = 8;
- } else if (m->data_out == 0x85) { /* seconds register 1 */
- m->data_in = (time >> 8) & 0xff;
- m->data_in_cnt = 8;
- } else if (m->data_out == 0x89) { /* seconds register 2 */
- m->data_in = (time >> 16) & 0xff;
- m->data_in_cnt = 8;
- } else if (m->data_out == 0x8d) { /* seconds register 3 */
- m->data_in = (time >> 24) & 0xff;
- m->data_in_cnt = 8;
- } else if ((m->data_out & 0xf3) == 0xa1) {
- /* PRAM address 0x10 -> 0x13 */
- int addr = (m->data_out >> 2) & 0x03;
- m->data_in = v1s->PRAM[addr];
- m->data_in_cnt = 8;
- } else if ((m->data_out & 0xf3) == 0xa1) {
- /* PRAM address 0x00 -> 0x0f */
- int addr = (m->data_out >> 2) & 0x0f;
- m->data_in = v1s->PRAM[addr];
- m->data_in_cnt = 8;
- } else if ((m->data_out & 0xf8) == 0xb8) {
- /* extended memory designator and sector number */
- m->cmd = m->data_out;
- }
- } else {
- /* this is a write command */
- m->cmd = m->data_out;
+ if (m->data_out_cnt != 8) {
+ return;
+ }
+
+ m->data_out_cnt = 0;
+
+ trace_via1_rtc_internal_status(m->cmd, m->alt, m->data_out);
+ /* first byte: it's a command */
+ if (m->cmd == REG_EMPTY) {
+
+ cmd = via1_rtc_compact_cmd(m->data_out);
+ trace_via1_rtc_internal_cmd(cmd);
+
+ if (cmd == REG_INVALID) {
+ trace_via1_rtc_cmd_invalid(m->data_out);
+ return;
+ }
+
+ if (cmd & 0x80) { /* this is a read command */
+ switch (cmd & 0x7f) {
+ case REG_0...REG_3: /* seconds registers */
+ /*
+ * register 0 is lowest-order byte
+ * register 3 is highest-order byte
+ */
+
+ time = m->tick_offset + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
+ / NANOSECONDS_PER_SECOND);
+ trace_via1_rtc_internal_time(time);
+ m->data_in = (time >> ((cmd & 0x03) << 3)) & 0xff;
+ m->data_in_cnt = 8;
+ trace_via1_rtc_cmd_seconds_read((cmd & 0x7f) - REG_0,
+ m->data_in);
+ break;
+ case REG_PRAM_ADDR...REG_PRAM_ADDR_LAST:
+ /* PRAM address 0x00 -> 0x13 */
+ m->data_in = v1s->PRAM[(cmd & 0x7f) - REG_PRAM_ADDR];
+ m->data_in_cnt = 8;
+ trace_via1_rtc_cmd_pram_read((cmd & 0x7f) - REG_PRAM_ADDR,
+ m->data_in);
+ break;
+ case REG_PRAM_SECT...REG_PRAM_SECT_LAST:
+ /*
+ * extended memory designator and sector number
+ * the only two-byte read command
+ */
+ trace_via1_rtc_internal_set_cmd(cmd);
+ m->cmd = cmd;
+ break;
+ default:
+ g_assert_not_reached();
+ break;
}
+ return;
+ }
+
+ /* this is a write command, needs a parameter */
+ if (cmd == REG_WPROTECT || !m->wprotect) {
+ trace_via1_rtc_internal_set_cmd(cmd);
+ m->cmd = cmd;
} else {
+ trace_via1_rtc_internal_ignore_cmd(cmd);
+ }
+ return;
+ }
+
+ /* second byte: it's a parameter */
+ if (m->alt == REG_EMPTY) {
+ switch (m->cmd & 0x7f) {
+ case REG_0...REG_3: /* seconds register */
+ /* FIXME */
+ trace_via1_rtc_cmd_seconds_write(m->cmd - REG_0, m->data_out);
+ m->cmd = REG_EMPTY;
+ break;
+ case REG_TEST:
+ /* device control: nothing to do */
+ trace_via1_rtc_cmd_test_write(m->data_out);
+ m->cmd = REG_EMPTY;
+ break;
+ case REG_WPROTECT:
+ /* Write Protect register */
+ trace_via1_rtc_cmd_wprotect_write(m->data_out);
+ m->wprotect = !!(m->data_out & 0x80);
+ m->cmd = REG_EMPTY;
+ break;
+ case REG_PRAM_ADDR...REG_PRAM_ADDR_LAST:
+ /* PRAM address 0x00 -> 0x13 */
+ trace_via1_rtc_cmd_pram_write(m->cmd - REG_PRAM_ADDR, m->data_out);
+ v1s->PRAM[m->cmd - REG_PRAM_ADDR] = m->data_out;
+ pram_update(m);
+ m->cmd = REG_EMPTY;
+ break;
+ case REG_PRAM_SECT...REG_PRAM_SECT_LAST:
+ addr = (m->data_out >> 2) & 0x1f;
+ sector = (m->cmd & 0x7f) - REG_PRAM_SECT;
if (m->cmd & 0x80) {
- if ((m->cmd & 0xf8) == 0xb8) {
- /* extended memory designator and sector number */
- int sector = m->cmd & 0x07;
- int addr = (m->data_out >> 2) & 0x1f;
-
- m->data_in = v1s->PRAM[sector * 8 + addr];
- m->data_in_cnt = 8;
- }
- } else if (!m->wprotect) {
- /* this is a write command */
- if (m->alt != 0) {
- /* extended memory designator and sector number */
- int sector = m->cmd & 0x07;
- int addr = (m->alt >> 2) & 0x1f;
-
- v1s->PRAM[sector * 8 + addr] = m->data_out;
-
- m->alt = 0;
- } else if (m->cmd == 0x01) { /* seconds register 0 */
- /* FIXME */
- } else if (m->cmd == 0x05) { /* seconds register 1 */
- /* FIXME */
- } else if (m->cmd == 0x09) { /* seconds register 2 */
- /* FIXME */
- } else if (m->cmd == 0x0d) { /* seconds register 3 */
- /* FIXME */
- } else if (m->cmd == 0x31) {
- /* Test Register */
- } else if (m->cmd == 0x35) {
- /* Write Protect register */
- m->wprotect = m->data_out & 1;
- } else if ((m->cmd & 0xf3) == 0xa1) {
- /* PRAM address 0x10 -> 0x13 */
- int addr = (m->cmd >> 2) & 0x03;
- v1s->PRAM[addr] = m->data_out;
- } else if ((m->cmd & 0xf3) == 0xa1) {
- /* PRAM address 0x00 -> 0x0f */
- int addr = (m->cmd >> 2) & 0x0f;
- v1s->PRAM[addr] = m->data_out;
- } else if ((m->cmd & 0xf8) == 0xb8) {
- /* extended memory designator and sector number */
- m->alt = m->cmd;
- }
+ /* it's a read */
+ m->data_in = v1s->PRAM[sector * 32 + addr];
+ m->data_in_cnt = 8;
+ trace_via1_rtc_cmd_pram_sect_read(sector, addr,
+ sector * 32 + addr,
+ m->data_in);
+ m->cmd = REG_EMPTY;
+ } else {
+ /* it's a write, we need one more parameter */
+ trace_via1_rtc_internal_set_alt(addr, sector, addr);
+ m->alt = addr;
}
+ break;
+ default:
+ g_assert_not_reached();
+ break;
}
- m->data_out = 0;
+ return;
}
+
+ /* third byte: it's the data of a REG_PRAM_SECT write */
+ g_assert(REG_PRAM_SECT <= m->cmd && m->cmd <= REG_PRAM_SECT_LAST);
+ sector = m->cmd - REG_PRAM_SECT;
+ v1s->PRAM[sector * 32 + m->alt] = m->data_out;
+ pram_update(m);
+ trace_via1_rtc_cmd_pram_sect_write(sector, m->alt, sector * 32 + m->alt,
+ m->data_out);
+ m->alt = REG_EMPTY;
+ m->cmd = REG_EMPTY;
}
static int adb_via_poll(MacVIAState *s, int state, uint8_t *data)
@@ -742,6 +860,9 @@ static void mac_via_reset(DeviceState *dev)
v1s->next_VBL = 0;
timer_del(v1s->one_second_timer);
v1s->next_second = 0;
+
+ m->cmd = REG_EMPTY;
+ m->alt = REG_EMPTY;
}
static void mac_via_realize(DeviceState *dev, Error **errp)
@@ -749,6 +870,7 @@ static void mac_via_realize(DeviceState *dev, Error **errp)
MacVIAState *m = MAC_VIA(dev);
MOS6522State *ms;
struct tm tm;
+ int ret;
/* Init VIAs 1 and 2 */
sysbus_init_child_obj(OBJECT(dev), "via1", &m->mos6522_via1,
@@ -782,6 +904,28 @@ static void mac_via_realize(DeviceState *dev, Error **errp)
m->adb_poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, via_adb_poll, m);
m->adb_data_ready = qdev_get_gpio_in_named(dev, "via1-irq",
VIA1_IRQ_ADB_READY_BIT);
+
+ if (m->blk) {
+ int64_t len = blk_getlength(m->blk);
+ if (len < 0) {
+ error_setg_errno(errp, -len,
+ "could not get length of backing image");
+ return;
+ }
+ ret = blk_set_perm(m->blk,
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
+ BLK_PERM_ALL, errp);
+ if (ret < 0) {
+ return;
+ }
+
+ len = blk_pread(m->blk, 0, m->mos6522_via1.PRAM,
+ sizeof(m->mos6522_via1.PRAM));
+ if (len != sizeof(m->mos6522_via1.PRAM)) {
+ error_setg(errp, "can't read PRAM contents");
+ return;
+ }
+ }
}
static void mac_via_init(Object *obj)
@@ -806,10 +950,33 @@ static void mac_via_init(Object *obj)
TYPE_ADB_BUS, DEVICE(obj), "adb.0");
}
+static void postload_update_cb(void *opaque, int running, RunState state)
+{
+ MacVIAState *m = MAC_VIA(opaque);
+
+ qemu_del_vm_change_state_handler(m->vmstate);
+ m->vmstate = NULL;
+
+ pram_update(m);
+}
+
+static int mac_via_post_load(void *opaque, int version_id)
+{
+ MacVIAState *m = MAC_VIA(opaque);
+
+ if (m->blk) {
+ m->vmstate = qemu_add_vm_change_state_handler(postload_update_cb,
+ m);
+ }
+
+ return 0;
+}
+
static const VMStateDescription vmstate_mac_via = {
.name = "mac-via",
.version_id = 1,
.minimum_version_id = 1,
+ .post_load = mac_via_post_load,
.fields = (VMStateField[]) {
/* VIAs */
VMSTATE_STRUCT(mos6522_via1.parent_obj, MacVIAState, 0, vmstate_mos6522,
@@ -842,6 +1009,11 @@ static const VMStateDescription vmstate_mac_via = {
}
};
+static Property mac_via_properties[] = {
+ DEFINE_PROP_DRIVE("drive", MacVIAState, blk),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void mac_via_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -849,6 +1021,7 @@ static void mac_via_class_init(ObjectClass *oc, void *data)
dc->realize = mac_via_realize;
dc->reset = mac_via_reset;
dc->vmsd = &vmstate_mac_via;
+ dc->props = mac_via_properties;
}
static TypeInfo mac_via_info = {
diff --git a/hw/misc/mos6522.c b/hw/misc/mos6522.c
index cecf0be59e..10b85bf751 100644
--- a/hw/misc/mos6522.c
+++ b/hw/misc/mos6522.c
@@ -244,6 +244,9 @@ uint64_t mos6522_read(void *opaque, hwaddr addr, unsigned size)
val = s->b;
break;
case VIA_REG_A:
+ qemu_log_mask(LOG_UNIMP, "Read access to register A with handshake");
+ /* fall through */
+ case VIA_REG_ANH:
val = s->a;
break;
case VIA_REG_DIRB:
@@ -297,9 +300,7 @@ uint64_t mos6522_read(void *opaque, hwaddr addr, unsigned size)
val = s->ier | 0x80;
break;
default:
- case VIA_REG_ANH:
- val = s->anh;
- break;
+ g_assert_not_reached();
}
if (addr != VIA_REG_IFR || val != 0) {
@@ -322,6 +323,9 @@ void mos6522_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
mdc->portB_write(s);
break;
case VIA_REG_A:
+ qemu_log_mask(LOG_UNIMP, "Write access to register A with handshake");
+ /* fall through */
+ case VIA_REG_ANH:
s->a = (s->a & ~s->dira) | (val & s->dira);
mdc->portA_write(s);
break;
@@ -395,9 +399,7 @@ void mos6522_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
break;
default:
- case VIA_REG_ANH:
- s->anh = val;
- break;
+ g_assert_not_reached();
}
}
@@ -439,7 +441,6 @@ const VMStateDescription vmstate_mos6522 = {
VMSTATE_UINT8(pcr, MOS6522State),
VMSTATE_UINT8(ifr, MOS6522State),
VMSTATE_UINT8(ier, MOS6522State),
- VMSTATE_UINT8(anh, MOS6522State),
VMSTATE_STRUCT_ARRAY(timers, MOS6522State, 2, 0,
vmstate_mos6522_timer, MOS6522Timer),
VMSTATE_END_OF_LIST()
@@ -460,7 +461,6 @@ static void mos6522_reset(DeviceState *dev)
s->ifr = 0;
s->ier = 0;
/* s->ier = T1_INT | SR_INT; */
- s->anh = 0;
s->timers[0].frequency = s->frequency;
s->timers[0].latch = 0xffff;
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index 1deb1d08c1..2e0c820834 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -149,3 +149,22 @@ bcm2835_mbox_write(unsigned int size, uint64_t addr, uint64_t value) "mbox write
bcm2835_mbox_read(unsigned int size, uint64_t addr, uint64_t value) "mbox read sz:%u addr:0x%"PRIx64" data:0x%"PRIx64
bcm2835_mbox_irq(unsigned level) "mbox irq:ARM level:%u"
bcm2835_mbox_property(uint32_t tag, uint32_t bufsize, size_t resplen) "mbox property tag:0x%08x in_sz:%u out_sz:%zu"
+
+# mac_via.c
+via1_rtc_update_data_out(int count, int value) "count=%d value=0x%02x"
+via1_rtc_update_data_in(int count, int value) "count=%d value=0x%02x"
+via1_rtc_internal_status(int cmd, int alt, int value) "cmd=0x%02x alt=0x%02x value=0x%02x"
+via1_rtc_internal_cmd(int cmd) "cmd=0x%02x"
+via1_rtc_cmd_invalid(int value) "value=0x%02x"
+via1_rtc_internal_time(uint32_t time) "time=0x%08x"
+via1_rtc_internal_set_cmd(int cmd) "cmd=0x%02x"
+via1_rtc_internal_ignore_cmd(int cmd) "cmd=0x%02x"
+via1_rtc_internal_set_alt(int alt, int sector, int offset) "alt=0x%02x sector=%u offset=%u"
+via1_rtc_cmd_seconds_read(int reg, int value) "reg=%d value=0x%02x"
+via1_rtc_cmd_seconds_write(int reg, int value) "reg=%d value=0x%02x"
+via1_rtc_cmd_test_write(int value) "value=0x%02x"
+via1_rtc_cmd_wprotect_write(int value) "value=0x%02x"
+via1_rtc_cmd_pram_read(int addr, int value) "addr=%u value=0x%02x"
+via1_rtc_cmd_pram_write(int addr, int value) "addr=%u value=0x%02x"
+via1_rtc_cmd_pram_sect_read(int sector, int offset, int addr, int value) "sector=%u offset=%u addr=%d value=0x%02x"
+via1_rtc_cmd_pram_sect_write(int sector, int offset, int addr, int value) "sector=%u offset=%u addr=%d value=0x%02x"
diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
index 3d991af163..cdc2631c0c 100644
--- a/hw/net/dp8393x.c
+++ b/hw/net/dp8393x.c
@@ -175,7 +175,7 @@ typedef struct dp8393xState {
int loopback_packet;
/* Memory access */
- void *dma_mr;
+ MemoryRegion *dma_mr;
AddressSpace as;
} dp8393xState;
@@ -948,7 +948,8 @@ static const VMStateDescription vmstate_dp8393x = {
static Property dp8393x_properties[] = {
DEFINE_NIC_PROPERTIES(dp8393xState, conf),
- DEFINE_PROP_PTR("dma_mr", dp8393xState, dma_mr),
+ DEFINE_PROP_LINK("dma_mr", dp8393xState, dma_mr,
+ TYPE_MEMORY_REGION, MemoryRegion *),
DEFINE_PROP_UINT8("it_shift", dp8393xState, it_shift, 0),
DEFINE_PROP_BOOL("big_endian", dp8393xState, big_endian, false),
DEFINE_PROP_END_OF_LIST(),
@@ -963,8 +964,6 @@ static void dp8393x_class_init(ObjectClass *klass, void *data)
dc->reset = dp8393x_reset;
dc->vmsd = &vmstate_dp8393x;
dc->props = dp8393x_properties;
- /* Reason: dma_mr property can't be set */
- dc->user_creatable = false;
}
static const TypeInfo dp8393x_info = {
diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c
index 4cfbf1135a..f30d963487 100644
--- a/hw/net/etraxfs_eth.c
+++ b/hw/net/etraxfs_eth.c
@@ -338,14 +338,8 @@ typedef struct ETRAXFSEthState
uint8_t macaddr[2][6];
uint32_t regs[FS_ETH_MAX_REGS];
- union {
- void *vdma_out;
- struct etraxfs_dma_client *dma_out;
- };
- union {
- void *vdma_in;
- struct etraxfs_dma_client *dma_in;
- };
+ struct etraxfs_dma_client *dma_out;
+ struct etraxfs_dma_client *dma_in;
/* MDIO bus. */
struct qemu_mdio mdio_bus;
@@ -635,8 +629,6 @@ static void etraxfs_eth_realize(DeviceState *dev, Error **errp)
static Property etraxfs_eth_properties[] = {
DEFINE_PROP_UINT32("phyaddr", ETRAXFSEthState, phyaddr, 1),
- DEFINE_PROP_PTR("dma_out", ETRAXFSEthState, vdma_out),
- DEFINE_PROP_PTR("dma_in", ETRAXFSEthState, vdma_in),
DEFINE_NIC_PROPERTIES(ETRAXFSEthState, conf),
DEFINE_PROP_END_OF_LIST(),
};
@@ -648,10 +640,40 @@ static void etraxfs_eth_class_init(ObjectClass *klass, void *data)
dc->realize = etraxfs_eth_realize;
dc->reset = etraxfs_eth_reset;
dc->props = etraxfs_eth_properties;
- /* Reason: pointer properties "dma_out", "dma_in" */
+ /* Reason: dma_out, dma_in are not user settable */
dc->user_creatable = false;
}
+
+/* Instantiate an ETRAXFS Ethernet MAC. */
+DeviceState *
+etraxfs_eth_init(NICInfo *nd, hwaddr base, int phyaddr,
+ struct etraxfs_dma_client *dma_out,
+ struct etraxfs_dma_client *dma_in)
+{
+ DeviceState *dev;
+ qemu_check_nic_model(nd, "fseth");
+
+ dev = qdev_create(NULL, "etraxfs-eth");
+ qdev_set_nic_properties(dev, nd);
+ qdev_prop_set_uint32(dev, "phyaddr", phyaddr);
+
+ /*
+ * TODO: QOM design, define a QOM interface for "I am an etraxfs
+ * DMA client" (which replaces the current 'struct
+ * etraxfs_dma_client' ad-hoc interface), implement it on the
+ * ethernet device, and then have QOM link properties on the DMA
+ * controller device so that you can pass the interface
+ * implementations to it.
+ */
+ ETRAX_FS_ETH(dev)->dma_out = dma_out;
+ ETRAX_FS_ETH(dev)->dma_in = dma_in;
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+
+ return dev;
+}
+
static const TypeInfo etraxfs_eth_info = {
.name = TYPE_ETRAX_FS_ETH,
.parent = TYPE_SYS_BUS_DEVICE,
diff --git a/hw/net/lance.c b/hw/net/lance.c
index 6631e2a4e0..4d96299041 100644
--- a/hw/net/lance.c
+++ b/hw/net/lance.c
@@ -138,7 +138,8 @@ static void lance_instance_init(Object *obj)
}
static Property lance_properties[] = {
- DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque),
+ DEFINE_PROP_LINK("dma", SysBusPCNetState, state.dma_opaque,
+ TYPE_DEVICE, DeviceState *),
DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf),
DEFINE_PROP_END_OF_LIST(),
};
@@ -153,8 +154,6 @@ static void lance_class_init(ObjectClass *klass, void *data)
dc->reset = lance_reset;
dc->vmsd = &vmstate_lance;
dc->props = lance_properties;
- /* Reason: pointer property "dma" */
- dc->user_creatable = false;
}
static const TypeInfo lance_info = {
diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c
index 4723c30c79..d067d21e2c 100644
--- a/hw/net/pcnet-pci.c
+++ b/hw/net/pcnet-pci.c
@@ -231,7 +231,7 @@ static void pci_pcnet_realize(PCIDevice *pci_dev, Error **errp)
s->irq = pci_allocate_irq(pci_dev);
s->phys_mem_read = pci_physical_memory_read;
s->phys_mem_write = pci_physical_memory_write;
- s->dma_opaque = pci_dev;
+ s->dma_opaque = DEVICE(pci_dev);
pcnet_common_init(DEVICE(pci_dev), s, &net_pci_pcnet_info);
}
diff --git a/hw/net/pcnet.h b/hw/net/pcnet.h
index 28d19a5c6f..f49b213c57 100644
--- a/hw/net/pcnet.h
+++ b/hw/net/pcnet.h
@@ -50,7 +50,7 @@ struct PCNetState_st {
uint8_t *buf, int len, int do_bswap);
void (*phys_mem_write)(void *dma_opaque, hwaddr addr,
uint8_t *buf, int len, int do_bswap);
- void *dma_opaque;
+ DeviceState *dma_opaque;
int tx_busy;
int looptest;
};
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 777d62d3c8..d7d3ad6dc7 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -3102,7 +3102,8 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp)
for (i = 0; i < max_queues; i++) {
virtio_net_del_queue(n, i);
}
-
+ /* delete also control vq */
+ virtio_del_queue(vdev, max_queues * 2);
qemu_announce_timer_del(&n->announce_timer, false);
g_free(n->vqs);
qemu_del_nic(n->nic);
diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c
index c5f9244934..ce7bcdb1d5 100644
--- a/hw/pci/pci_host.c
+++ b/hw/pci/pci_host.c
@@ -106,7 +106,7 @@ uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
return ret;
}
-void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len)
+void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, unsigned len)
{
PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
@@ -115,28 +115,21 @@ void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len)
return;
}
- PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n",
- __func__, pci_dev->name, config_addr, val, len);
pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE,
val, len);
}
-uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
+uint32_t pci_data_read(PCIBus *s, uint32_t addr, unsigned len)
{
PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
- uint32_t val;
if (!pci_dev) {
return ~0x0;
}
- val = pci_host_config_read_common(pci_dev, config_addr,
- PCI_CONFIG_SPACE_SIZE, len);
- PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n",
- __func__, pci_dev->name, config_addr, val, len);
-
- return val;
+ return pci_host_config_read_common(pci_dev, config_addr,
+ PCI_CONFIG_SPACE_SIZE, len);
}
static void pci_host_config_write(void *opaque, hwaddr addr,
@@ -167,8 +160,7 @@ static void pci_host_data_write(void *opaque, hwaddr addr,
uint64_t val, unsigned len)
{
PCIHostState *s = opaque;
- PCI_DPRINTF("write addr " TARGET_FMT_plx " len %d val %x\n",
- addr, len, (unsigned)val);
+
if (s->config_reg & (1u << 31))
pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
}
@@ -177,14 +169,11 @@ static uint64_t pci_host_data_read(void *opaque,
hwaddr addr, unsigned len)
{
PCIHostState *s = opaque;
- uint32_t val;
+
if (!(s->config_reg & (1U << 31))) {
return 0xffffffff;
}
- val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
- PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n",
- addr, len, val);
- return val;
+ return pci_data_read(s->bus, s->config_reg | (addr & 3), len);
}
const MemoryRegionOps pci_host_conf_le_ops = {
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index f77e7ca84e..e2735bb8dd 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -561,7 +561,7 @@ static void *pnv_dt_create(MachineState *machine)
static void pnv_powerdown_notify(Notifier *n, void *opaque)
{
- PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
+ PnvMachineState *pnv = container_of(n, PnvMachineState, powerdown_notifier);
if (pnv->bmc) {
pnv_bmc_powerdown(pnv->bmc);
@@ -768,6 +768,18 @@ static void pnv_init(MachineState *machine)
exit(1);
}
+ pnv->num_chips =
+ machine->smp.max_cpus / (machine->smp.cores * machine->smp.threads);
+ /*
+ * TODO: should we decide on how many chips we can create based
+ * on #cores and Venice vs. Murano vs. Naples chip type etc...,
+ */
+ if (!is_power_of_2(pnv->num_chips) || pnv->num_chips > 4) {
+ error_report("invalid number of chips: '%d'", pnv->num_chips);
+ error_printf("Try '-smp sockets=N'. Valid values are : 1, 2 or 4.\n");
+ exit(1);
+ }
+
pnv->chips = g_new0(PnvChip *, pnv->num_chips);
for (i = 0; i < pnv->num_chips; i++) {
char chip_name[32];
@@ -790,12 +802,25 @@ static void pnv_init(MachineState *machine)
&error_fatal);
object_property_set_int(chip, machine->smp.cores,
"nr-cores", &error_fatal);
+ object_property_set_int(chip, machine->smp.threads,
+ "nr-threads", &error_fatal);
+ /*
+ * The POWER8 machine use the XICS interrupt interface.
+ * Propagate the XICS fabric to the chip and its controllers.
+ */
+ if (object_dynamic_cast(OBJECT(pnv), TYPE_XICS_FABRIC)) {
+ object_property_set_link(chip, OBJECT(pnv), "xics", &error_abort);
+ }
+ if (object_dynamic_cast(OBJECT(pnv), TYPE_XIVE_FABRIC)) {
+ object_property_set_link(chip, OBJECT(pnv), "xive-fabric",
+ &error_abort);
+ }
object_property_set_bool(chip, true, "realized", &error_fatal);
}
g_free(chip_typename);
/* Create the machine BMC simulator */
- pnv->bmc = pnv_bmc_create();
+ pnv->bmc = pnv_bmc_create(pnv->pnor);
/* Instantiate ISA bus on chip 0 */
pnv->isa_bus = pnv_isa_create(pnv->chips[0], &error_fatal);
@@ -831,12 +856,12 @@ static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
Error **errp)
{
+ Pnv8Chip *chip8 = PNV8_CHIP(chip);
Error *local_err = NULL;
Object *obj;
PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
- obj = icp_create(OBJECT(cpu), TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()),
- &local_err);
+ obj = icp_create(OBJECT(cpu), TYPE_PNV_ICP, chip8->xics, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
@@ -900,7 +925,8 @@ static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
* controller object is initialized afterwards. Hopefully, it's
* only used at runtime.
*/
- obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(&chip9->xive), &local_err);
+ obj = xive_tctx_create(OBJECT(cpu), XIVE_PRESENTER(&chip9->xive),
+ &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
@@ -990,10 +1016,14 @@ static void pnv_chip_power8_instance_init(Object *obj)
{
Pnv8Chip *chip8 = PNV8_CHIP(obj);
+ object_property_add_link(obj, "xics", TYPE_XICS_FABRIC,
+ (Object **)&chip8->xics,
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_STRONG,
+ &error_abort);
+
object_initialize_child(obj, "psi", &chip8->psi, sizeof(chip8->psi),
TYPE_PNV8_PSI, &error_abort, NULL);
- object_property_add_const_link(OBJECT(&chip8->psi), "xics",
- OBJECT(qdev_get_machine()), &error_abort);
object_initialize_child(obj, "lpc", &chip8->lpc, sizeof(chip8->lpc),
TYPE_PNV8_LPC, &error_abort, NULL);
@@ -1011,7 +1041,6 @@ static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
int i, j;
char *name;
- XICSFabric *xi = XICS_FABRIC(qdev_get_machine());
name = g_strdup_printf("icp-%x", chip->chip_id);
memory_region_init(&chip8->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
@@ -1027,7 +1056,7 @@ static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
- PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));
+ PnvICPState *icp = PNV_ICP(xics_icp_get(chip8->xics, pir));
memory_region_add_subregion(&chip8->icp_mmio, pir << 12,
&icp->mmio);
@@ -1043,6 +1072,8 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
Pnv8Psi *psi8 = &chip8->psi;
Error *local_err = NULL;
+ assert(chip8->xics);
+
/* XSCOM bridge is first */
pnv_xscom_realize(chip, PNV_XSCOM_SIZE, &local_err);
if (local_err) {
@@ -1060,6 +1091,8 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
/* Processor Service Interface (PSI) Host Bridge */
object_property_set_int(OBJECT(&chip8->psi), PNV_PSIHB_BASE(chip),
"bar", &error_fatal);
+ object_property_set_link(OBJECT(&chip8->psi), OBJECT(chip8->xics),
+ ICS_PROP_XICS, &error_abort);
object_property_set_bool(OBJECT(&chip8->psi), true, "realized", &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -1201,6 +1234,8 @@ static void pnv_chip_power9_instance_init(Object *obj)
object_initialize_child(obj, "xive", &chip9->xive, sizeof(chip9->xive),
TYPE_PNV_XIVE, &error_abort, NULL);
+ object_property_add_alias(obj, "xive-fabric", OBJECT(&chip9->xive),
+ "xive-fabric", &error_abort);
object_initialize_child(obj, "psi", &chip9->psi, sizeof(chip9->psi),
TYPE_PNV9_PSI, &error_abort, NULL);
@@ -1494,7 +1529,6 @@ static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
{
- MachineState *ms = MACHINE(qdev_get_machine());
Error *error = NULL;
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
const char *typename = pnv_chip_core_typename(chip);
@@ -1530,8 +1564,8 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core),
&error_abort);
chip->cores[i] = pnv_core;
- object_property_set_int(OBJECT(pnv_core), ms->smp.threads, "nr-threads",
- &error_fatal);
+ object_property_set_int(OBJECT(pnv_core), chip->nr_threads,
+ "nr-threads", &error_fatal);
object_property_set_int(OBJECT(pnv_core), core_hwid,
CPU_CORE_PROP_CORE_ID, &error_fatal);
object_property_set_int(OBJECT(pnv_core),
@@ -1570,6 +1604,7 @@ static Property pnv_chip_properties[] = {
DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
+ DEFINE_PROP_UINT32("nr-threads", PnvChip, nr_threads, 1),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1682,67 +1717,6 @@ static int pnv_match_nvt(XiveFabric *xfb, uint8_t format,
return total_count;
}
-PnvChip *pnv_get_chip(uint32_t chip_id)
-{
- PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
- int i;
-
- for (i = 0; i < pnv->num_chips; i++) {
- PnvChip *chip = pnv->chips[i];
- if (chip->chip_id == chip_id) {
- return chip;
- }
- }
- return NULL;
-}
-
-static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- visit_type_uint32(v, name, &PNV_MACHINE(obj)->num_chips, errp);
-}
-
-static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- PnvMachineState *pnv = PNV_MACHINE(obj);
- uint32_t num_chips;
- Error *local_err = NULL;
-
- visit_type_uint32(v, name, &num_chips, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- /*
- * TODO: should we decide on how many chips we can create based
- * on #cores and Venice vs. Murano vs. Naples chip type etc...,
- */
- if (!is_power_of_2(num_chips) || num_chips > 4) {
- error_setg(errp, "invalid number of chips: '%d'", num_chips);
- return;
- }
-
- pnv->num_chips = num_chips;
-}
-
-static void pnv_machine_instance_init(Object *obj)
-{
- PnvMachineState *pnv = PNV_MACHINE(obj);
- pnv->num_chips = 1;
-}
-
-static void pnv_machine_class_props_init(ObjectClass *oc)
-{
- object_class_property_add(oc, "num-chips", "uint32",
- pnv_get_num_chips, pnv_set_num_chips,
- NULL, NULL, NULL);
- object_class_property_set_description(oc, "num-chips",
- "Specifies the number of processor chips",
- NULL);
-}
-
static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -1812,8 +1786,6 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data)
*/
mc->default_ram_size = INITRD_LOAD_ADDR + INITRD_MAX_SIZE;
ispc->print_info = pnv_pic_print_info;
-
- pnv_machine_class_props_init(oc);
}
#define DEFINE_PNV8_CHIP_TYPE(type, class_initfn) \
@@ -1866,7 +1838,6 @@ static const TypeInfo types[] = {
.parent = TYPE_MACHINE,
.abstract = true,
.instance_size = sizeof(PnvMachineState),
- .instance_init = pnv_machine_instance_init,
.class_init = pnv_machine_class_init,
.class_size = sizeof(PnvMachineClass),
.interfaces = (InterfaceInfo[]) {
diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c
index 07fa1e1c7e..8863354c1c 100644
--- a/hw/ppc/pnv_bmc.c
+++ b/hw/ppc/pnv_bmc.c
@@ -143,8 +143,8 @@ static uint16_t bytes_to_blocks(uint32_t bytes)
static void hiomap_cmd(IPMIBmcSim *ibs, uint8_t *cmd, unsigned int cmd_len,
RspBuffer *rsp)
{
- PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
- PnvPnor *pnor = pnv->pnor;
+ PnvPnor *pnor = PNV_PNOR(object_property_get_link(OBJECT(ibs), "pnor",
+ &error_abort));
uint32_t pnor_size = pnor->size;
uint32_t pnor_addr = PNOR_SPI_OFFSET;
bool readonly = false;
@@ -217,11 +217,13 @@ static const IPMINetfn hiomap_netfn = {
* Instantiate the machine BMC. PowerNV uses the QEMU internal
* simulator but it could also be external.
*/
-IPMIBmc *pnv_bmc_create(void)
+IPMIBmc *pnv_bmc_create(PnvPnor *pnor)
{
Object *obj;
obj = object_new(TYPE_IPMI_BMC_SIMULATOR);
+ object_ref(OBJECT(pnor));
+ object_property_add_const_link(obj, "pnor", OBJECT(pnor), &error_abort);
object_property_set_bool(obj, true, "realized", &error_fatal);
/* Install the HIOMAP protocol handlers to access the PNOR */
diff --git a/hw/ppc/pnv_pnor.c b/hw/ppc/pnv_pnor.c
index bfb1e92b03..b061106d1c 100644
--- a/hw/ppc/pnv_pnor.c
+++ b/hw/ppc/pnv_pnor.c
@@ -33,6 +33,7 @@ static uint64_t pnv_pnor_read(void *opaque, hwaddr addr, unsigned size)
static void pnv_pnor_update(PnvPnor *s, int offset, int size)
{
int offset_end;
+ int ret;
if (s->blk) {
return;
@@ -42,8 +43,11 @@ static void pnv_pnor_update(PnvPnor *s, int offset, int size)
offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE);
- blk_pwrite(s->blk, offset, s->storage + offset,
- offset_end - offset, 0);
+ ret = blk_pwrite(s->blk, offset, s->storage + offset,
+ offset_end - offset, 0);
+ if (ret < 0) {
+ error_report("Could not update PNOR: %s", strerror(-ret));
+ }
}
static void pnv_pnor_write(void *opaque, hwaddr addr, uint64_t data,
@@ -107,7 +111,7 @@ static void pnv_pnor_realize(DeviceState *dev, Error **errp)
}
static Property pnv_pnor_properties[] = {
- DEFINE_PROP_UINT32("size", PnvPnor, size, 128 << 20),
+ DEFINE_PROP_INT64("size", PnvPnor, size, 128 << 20),
DEFINE_PROP_DRIVE("drive", PnvPnor, blk),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
index 75e20d9da0..1d8da31738 100644
--- a/hw/ppc/pnv_psi.c
+++ b/hw/ppc/pnv_psi.c
@@ -455,7 +455,7 @@ static const MemoryRegionOps pnv_psi_xscom_ops = {
}
};
-static void pnv_psi_reset(void *dev)
+static void pnv_psi_reset(DeviceState *dev)
{
PnvPsi *psi = PNV_PSI(dev);
@@ -464,12 +464,29 @@ static void pnv_psi_reset(void *dev)
psi->regs[PSIHB_XSCOM_BAR] = psi->bar | PSIHB_BAR_EN;
}
+static void pnv_psi_reset_handler(void *dev)
+{
+ device_reset(DEVICE(dev));
+}
+
+static void pnv_psi_realize(DeviceState *dev, Error **errp)
+{
+ PnvPsi *psi = PNV_PSI(dev);
+
+ /* Default BAR for MMIO region */
+ pnv_psi_set_bar(psi, psi->bar | PSIHB_BAR_EN);
+
+ qemu_register_reset(pnv_psi_reset_handler, dev);
+}
+
static void pnv_psi_power8_instance_init(Object *obj)
{
Pnv8Psi *psi8 = PNV8_PSI(obj);
object_initialize_child(obj, "ics-psi", &psi8->ics, sizeof(psi8->ics),
TYPE_ICS, &error_abort, NULL);
+ object_property_add_alias(obj, ICS_PROP_XICS, OBJECT(&psi8->ics),
+ ICS_PROP_XICS, &error_abort);
}
static const uint8_t irq_to_xivr[] = {
@@ -485,19 +502,10 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
{
PnvPsi *psi = PNV_PSI(dev);
ICSState *ics = &PNV8_PSI(psi)->ics;
- Object *obj;
Error *err = NULL;
unsigned int i;
- obj = object_property_get_link(OBJECT(dev), "xics", &err);
- if (!obj) {
- error_setg(errp, "%s: required link 'xics' not found: %s",
- __func__, error_get_pretty(err));
- return;
- }
-
/* Create PSI interrupt control source */
- object_property_set_link(OBJECT(ics), obj, ICS_PROP_XICS, &error_abort);
object_property_set_int(OBJECT(ics), PSI_NUM_INTERRUPTS, "nr-irqs", &err);
if (err) {
error_propagate(errp, err);
@@ -523,9 +531,6 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&psi->regs_mr, OBJECT(dev), &psi_mmio_ops, psi,
"psihb", PNV_PSIHB_SIZE);
- /* Default BAR for MMIO region */
- pnv_psi_set_bar(psi, psi->bar | PSIHB_BAR_EN);
-
/* Default sources in XIVR */
for (i = 0; i < PSI_NUM_INTERRUPTS; i++) {
uint8_t xivr = irq_to_xivr[i];
@@ -533,7 +538,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
((uint64_t) i << PSIHB_XIVR_SRC_SH);
}
- qemu_register_reset(pnv_psi_reset, dev);
+ pnv_psi_realize(dev, errp);
}
static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
@@ -816,7 +821,7 @@ static void pnv_psi_power9_irq_set(PnvPsi *psi, int irq, bool state)
qemu_set_irq(psi->qirqs[irq], state);
}
-static void pnv_psi_power9_reset(void *dev)
+static void pnv_psi_power9_reset(DeviceState *dev)
{
Pnv9Psi *psi = PNV9_PSI(dev);
@@ -868,9 +873,7 @@ static void pnv_psi_power9_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&psi->regs_mr, OBJECT(dev), &pnv_psi_p9_mmio_ops, psi,
"psihb", PNV9_PSIHB_SIZE);
- pnv_psi_set_bar(psi, psi->bar | PSIHB_BAR_EN);
-
- qemu_register_reset(pnv_psi_power9_reset, dev);
+ pnv_psi_realize(dev, errp);
}
static void pnv_psi_power9_class_init(ObjectClass *klass, void *data)
@@ -882,6 +885,7 @@ static void pnv_psi_power9_class_init(ObjectClass *klass, void *data)
dc->desc = "PowerNV PSI Controller POWER9";
dc->realize = pnv_psi_power9_realize;
+ dc->reset = pnv_psi_power9_reset;
ppc->xscom_pcba = PNV9_XSCOM_PSIHB_BASE;
ppc->xscom_size = PNV9_XSCOM_PSIHB_SIZE;
@@ -934,6 +938,7 @@ static void pnv_psi_class_init(ObjectClass *klass, void *data)
dc->desc = "PowerNV PSI Controller";
dc->props = pnv_psi_properties;
+ dc->reset = pnv_psi_reset;
}
static const TypeInfo pnv_psi_info = {
diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
index 4d95c0f8a8..b782641b23 100644
--- a/hw/ppc/ppc440_bamboo.c
+++ b/hw/ppc/ppc440_bamboo.c
@@ -71,12 +71,12 @@ static int bamboo_load_device_tree(hwaddr addr,
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
if (!filename) {
- goto out;
+ return -1;
}
fdt = load_device_tree(filename, &fdt_size);
g_free(filename);
if (fdt == NULL) {
- goto out;
+ return -1;
}
/* Manipulate device tree in memory. */
@@ -117,10 +117,6 @@ static int bamboo_load_device_tree(hwaddr addr,
rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
g_free(fdt);
return 0;
-
-out:
-
- return ret;
}
/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index f11422fc41..30a5fbd3be 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -878,7 +878,7 @@ static int spapr_dt_cas_updates(SpaprMachineState *spapr, void *fdt,
g_assert(smc->dr_lmb_enabled);
ret = spapr_populate_drconf_memory(spapr, fdt);
if (ret) {
- goto out;
+ return ret;
}
}
@@ -889,11 +889,8 @@ static int spapr_dt_cas_updates(SpaprMachineState *spapr, void *fdt,
return offset;
}
}
- ret = spapr_ovec_populate_dt(fdt, offset, spapr->ov5_cas,
- "ibm,architecture-vec-5");
-
-out:
- return ret;
+ return spapr_ovec_populate_dt(fdt, offset, spapr->ov5_cas,
+ "ibm,architecture-vec-5");
}
static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
@@ -1597,6 +1594,7 @@ static void spapr_machine_reset(MachineState *machine)
void *fdt;
int rc;
+ kvmppc_svm_off(&error_fatal);
spapr_caps_apply(spapr);
first_ppc_cpu = POWERPC_CPU(first_cpu);
@@ -4197,19 +4195,19 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj,
kvm_irqchip_in_kernel() ? "in-kernel" : "emulated");
}
+/*
+ * This is a XIVE only operation
+ */
static int spapr_match_nvt(XiveFabric *xfb, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
bool cam_ignore, uint8_t priority,
uint32_t logic_serv, XiveTCTXMatch *match)
{
SpaprMachineState *spapr = SPAPR_MACHINE(xfb);
- XivePresenter *xptr = XIVE_PRESENTER(spapr->xive);
+ XivePresenter *xptr = XIVE_PRESENTER(spapr->active_intc);
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
int count;
- /* This is a XIVE only operation */
- assert(spapr->active_intc == SPAPR_INTC(spapr->xive));
-
count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
priority, logic_serv, match);
if (count < 0) {
diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c
index 373505d28b..1f630f296b 100644
--- a/hw/ppc/spapr_irq.c
+++ b/hw/ppc/spapr_irq.c
@@ -332,6 +332,8 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
* priority
*/
qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3);
+ object_property_set_link(OBJECT(dev), OBJECT(spapr), "xive-fabric",
+ &error_abort);
qdev_init_nofail(dev);
spapr->xive = SPAPR_XIVE(dev);
diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index c693fc748a..26f710d3ec 100644
--- a/hw/scsi/vhost-scsi.c
+++ b/hw/scsi/vhost-scsi.c
@@ -275,6 +275,8 @@ static Property vhost_scsi_properties[] = {
DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues, 1),
DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSICommon, conf.virtqueue_size,
128),
+ DEFINE_PROP_BOOL("seg_max_adjust", VirtIOSCSICommon, conf.seg_max_adjust,
+ true),
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors,
0xFFFF),
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128),
diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c
index 6a6c15dd32..23f972df59 100644
--- a/hw/scsi/vhost-user-scsi.c
+++ b/hw/scsi/vhost-user-scsi.c
@@ -39,6 +39,10 @@ static const int user_feature_bits[] = {
VHOST_INVALID_FEATURE_BIT
};
+enum VhostUserProtocolFeature {
+ VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13,
+};
+
static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserSCSI *s = (VHostUserSCSI *)vdev;
@@ -62,6 +66,25 @@ static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status)
}
}
+static void vhost_user_scsi_reset(VirtIODevice *vdev)
+{
+ VHostSCSICommon *vsc = VHOST_SCSI_COMMON(vdev);
+ struct vhost_dev *dev = &vsc->dev;
+
+ /*
+ * Historically, reset was not implemented so only reset devices
+ * that are expecting it.
+ */
+ if (!virtio_has_feature(dev->protocol_features,
+ VHOST_USER_PROTOCOL_F_RESET_DEVICE)) {
+ return;
+ }
+
+ if (dev->vhost_ops->vhost_reset_device) {
+ dev->vhost_ops->vhost_reset_device(dev);
+ }
+}
+
static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
}
@@ -182,6 +205,7 @@ static void vhost_user_scsi_class_init(ObjectClass *klass, void *data)
vdc->get_features = vhost_scsi_common_get_features;
vdc->set_config = vhost_scsi_common_set_config;
vdc->set_status = vhost_user_scsi_set_status;
+ vdc->reset = vhost_user_scsi_reset;
fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path;
}
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index e8b2b64d09..4bc73a370e 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -597,12 +597,15 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
{
VirtIOSCSIReq *req, *next;
int ret = 0;
+ bool suppress_notifications = virtio_queue_get_notification(vq);
bool progress = false;
QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
do {
- virtio_queue_set_notification(vq, 0);
+ if (suppress_notifications) {
+ virtio_queue_set_notification(vq, 0);
+ }
while ((req = virtio_scsi_pop_req(s, vq))) {
progress = true;
@@ -622,7 +625,9 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
}
}
- virtio_queue_set_notification(vq, 1);
+ if (suppress_notifications) {
+ virtio_queue_set_notification(vq, 1);
+ }
} while (ret != -EINVAL && !virtio_queue_empty(vq));
QTAILQ_FOREACH_SAFE(req, &reqs, next, next) {
@@ -654,7 +659,8 @@ static void virtio_scsi_get_config(VirtIODevice *vdev,
VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(vdev);
virtio_stl_p(vdev, &scsiconf->num_queues, s->conf.num_queues);
- virtio_stl_p(vdev, &scsiconf->seg_max, 128 - 2);
+ virtio_stl_p(vdev, &scsiconf->seg_max,
+ s->conf.seg_max_adjust ? s->conf.virtqueue_size - 2 : 128 - 2);
virtio_stl_p(vdev, &scsiconf->max_sectors, s->conf.max_sectors);
virtio_stl_p(vdev, &scsiconf->cmd_per_lun, s->conf.cmd_per_lun);
virtio_stl_p(vdev, &scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
@@ -893,6 +899,11 @@ void virtio_scsi_common_realize(DeviceState *dev,
virtio_cleanup(vdev);
return;
}
+ if (s->conf.virtqueue_size <= 2) {
+ error_setg(errp, "invalid virtqueue_size property (= %" PRIu32 "), "
+ "must be > 2", s->conf.virtqueue_size);
+ return;
+ }
s->cmd_vqs = g_new0(VirtQueue *, s->conf.num_queues);
s->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
s->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE;
@@ -949,6 +960,8 @@ static Property virtio_scsi_properties[] = {
DEFINE_PROP_UINT32("num_queues", VirtIOSCSI, parent_obj.conf.num_queues, 1),
DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSI,
parent_obj.conf.virtqueue_size, 128),
+ DEFINE_PROP_BOOL("seg_max_adjust", VirtIOSCSI,
+ parent_obj.conf.seg_max_adjust, true),
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSI, parent_obj.conf.max_sectors,
0xFFFF),
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSI, parent_obj.conf.cmd_per_lun,
diff --git a/hw/semihosting/console.c b/hw/semihosting/console.c
index b4b17c8afb..6346bd7f50 100644
--- a/hw/semihosting/console.c
+++ b/hw/semihosting/console.c
@@ -20,8 +20,15 @@
#include "hw/semihosting/semihost.h"
#include "hw/semihosting/console.h"
#include "exec/gdbstub.h"
+#include "exec/exec-all.h"
#include "qemu/log.h"
#include "chardev/char.h"
+#include <pthread.h>
+#include "chardev/char-fe.h"
+#include "sysemu/sysemu.h"
+#include "qemu/main-loop.h"
+#include "qapi/error.h"
+#include "qemu/fifo8.h"
int qemu_semihosting_log_out(const char *s, int len)
{
@@ -98,3 +105,75 @@ void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr)
__func__, addr);
}
}
+
+#define FIFO_SIZE 1024
+
+/* Access to this structure is protected by the BQL */
+typedef struct SemihostingConsole {
+ CharBackend backend;
+ GSList *sleeping_cpus;
+ bool got;
+ Fifo8 fifo;
+} SemihostingConsole;
+
+static SemihostingConsole console;
+
+static int console_can_read(void *opaque)
+{
+ SemihostingConsole *c = opaque;
+ int ret;
+ g_assert(qemu_mutex_iothread_locked());
+ ret = (int) fifo8_num_free(&c->fifo);
+ return ret;
+}
+
+static void console_wake_up(gpointer data, gpointer user_data)
+{
+ CPUState *cs = (CPUState *) data;
+ /* cpu_handle_halt won't know we have work so just unbung here */
+ cs->halted = 0;
+ qemu_cpu_kick(cs);
+}
+
+static void console_read(void *opaque, const uint8_t *buf, int size)
+{
+ SemihostingConsole *c = opaque;
+ g_assert(qemu_mutex_iothread_locked());
+ while (size-- && !fifo8_is_full(&c->fifo)) {
+ fifo8_push(&c->fifo, *buf++);
+ }
+ g_slist_foreach(c->sleeping_cpus, console_wake_up, NULL);
+ c->sleeping_cpus = NULL;
+}
+
+target_ulong qemu_semihosting_console_inc(CPUArchState *env)
+{
+ uint8_t ch;
+ SemihostingConsole *c = &console;
+ g_assert(qemu_mutex_iothread_locked());
+ g_assert(current_cpu);
+ if (fifo8_is_empty(&c->fifo)) {
+ c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, current_cpu);
+ current_cpu->halted = 1;
+ current_cpu->exception_index = EXCP_HALTED;
+ cpu_loop_exit(current_cpu);
+ /* never returns */
+ }
+ ch = fifo8_pop(&c->fifo);
+ return (target_ulong) ch;
+}
+
+void qemu_semihosting_console_init(void)
+{
+ Chardev *chr = semihosting_get_chardev();
+
+ if (chr) {
+ fifo8_create(&console.fifo, FIFO_SIZE);
+ qemu_chr_fe_init(&console.backend, chr, &error_abort);
+ qemu_chr_fe_set_handlers(&console.backend,
+ console_can_read,
+ console_read,
+ NULL, NULL, &console,
+ NULL, true);
+ }
+}
diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c
index ee0840f380..72bb5285cc 100644
--- a/hw/sh4/r2d.c
+++ b/hw/sh4/r2d.c
@@ -272,7 +272,7 @@ static void r2d_init(MachineState *machine)
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_hd(2));
+ qdev_prop_set_chr(dev, "chardev", serial_hd(2));
qdev_init_nofail(dev);
sysbus_mmio_map(busdev, 0, 0x10000000);
sysbus_mmio_map(busdev, 1, 0x13e00000);
diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c
index c5f1b1ee72..8038887ff7 100644
--- a/hw/sparc/leon3.c
+++ b/hw/sparc/leon3.c
@@ -143,9 +143,14 @@ void leon3_irq_ack(void *irq_manager, int intno)
grlib_irqmp_ack((DeviceState *)irq_manager, intno);
}
-static void leon3_set_pil_in(void *opaque, uint32_t pil_in)
+/*
+ * This device assumes that the incoming 'level' value on the
+ * qemu_irq is the interrupt number, not just a simple 0/1 level.
+ */
+static void leon3_set_pil_in(void *opaque, int n, int level)
{
- CPUSPARCState *env = (CPUSPARCState *)opaque;
+ CPUSPARCState *env = opaque;
+ uint32_t pil_in = level;
CPUState *cs;
assert(env != NULL);
@@ -225,8 +230,10 @@ static void leon3_generic_hw_init(MachineState *machine)
/* Allocate IRQ manager */
dev = qdev_create(NULL, TYPE_GRLIB_IRQMP);
- qdev_prop_set_ptr(dev, "set_pil_in", leon3_set_pil_in);
- qdev_prop_set_ptr(dev, "set_pil_in_opaque", env);
+ qdev_init_gpio_in_named_with_opaque(DEVICE(cpu), leon3_set_pil_in,
+ env, "pil", 1);
+ qdev_connect_gpio_out_named(dev, "grlib-irq", 0,
+ qdev_get_gpio_in_named(DEVICE(cpu), "pil", 0));
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, LEON3_IRQMP_OFFSET);
env->irq_manager = dev;
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 2d40b396f2..337a173ce7 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -3076,7 +3076,9 @@ static void vfio_exitfn(PCIDevice *pdev)
vfio_unregister_req_notifier(vdev);
vfio_unregister_err_notifier(vdev);
pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
- kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier);
+ if (vdev->irqchip_change_notifier.notify) {
+ kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier);
+ }
vfio_disable_interrupts(vdev);
if (vdev->intx.mmap_timer) {
timer_free(vdev->intx.mmap_timer);
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 02a9b25199..d27a10fcc6 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -58,6 +58,7 @@ enum VhostUserProtocolFeature {
VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD = 10,
VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11,
VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12,
+ VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13,
VHOST_USER_PROTOCOL_F_MAX
};
@@ -98,6 +99,7 @@ typedef enum VhostUserRequest {
VHOST_USER_GET_INFLIGHT_FD = 31,
VHOST_USER_SET_INFLIGHT_FD = 32,
VHOST_USER_GPU_SET_SOCKET = 33,
+ VHOST_USER_RESET_DEVICE = 34,
VHOST_USER_MAX
} VhostUserRequest;
@@ -890,10 +892,14 @@ static int vhost_user_set_owner(struct vhost_dev *dev)
static int vhost_user_reset_device(struct vhost_dev *dev)
{
VhostUserMsg msg = {
- .hdr.request = VHOST_USER_RESET_OWNER,
.hdr.flags = VHOST_USER_VERSION,
};
+ msg.hdr.request = virtio_has_feature(dev->protocol_features,
+ VHOST_USER_PROTOCOL_F_RESET_DEVICE)
+ ? VHOST_USER_RESET_DEVICE
+ : VHOST_USER_RESET_OWNER;
+
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
return -1;
}
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 40b04f5180..57f3b9f22d 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -831,6 +831,13 @@ static void virtio_balloon_device_unrealize(DeviceState *dev, Error **errp)
}
balloon_stats_destroy_timer(s);
qemu_remove_balloon_handler(s);
+
+ virtio_delete_queue(s->ivq);
+ virtio_delete_queue(s->dvq);
+ virtio_delete_queue(s->svq);
+ if (s->free_page_vq) {
+ virtio_delete_queue(s->free_page_vq);
+ }
virtio_cleanup(vdev);
}
diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
index 94d934c44b..872f2cd237 100644
--- a/hw/virtio/virtio-mmio.c
+++ b/hw/virtio/virtio-mmio.c
@@ -65,6 +65,19 @@ static void virtio_mmio_stop_ioeventfd(VirtIOMMIOProxy *proxy)
virtio_bus_stop_ioeventfd(&proxy->bus);
}
+static void virtio_mmio_soft_reset(VirtIOMMIOProxy *proxy)
+{
+ int i;
+
+ if (proxy->legacy) {
+ return;
+ }
+
+ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
+ proxy->vqs[i].enabled = 0;
+ }
+}
+
static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
{
VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
@@ -295,8 +308,9 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
break;
case VIRTIO_MMIO_QUEUE_NUM:
trace_virtio_mmio_queue_write(value, VIRTQUEUE_MAX_SIZE);
+ virtio_queue_set_num(vdev, vdev->queue_sel, value);
+
if (proxy->legacy) {
- virtio_queue_set_num(vdev, vdev->queue_sel, value);
virtio_queue_update_rings(vdev, vdev->queue_sel);
} else {
proxy->vqs[vdev->queue_sel].num = value;
@@ -378,6 +392,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
if (vdev->status == 0) {
virtio_reset(vdev);
+ virtio_mmio_soft_reset(proxy);
}
break;
case VIRTIO_MMIO_QUEUE_DESC_LOW:
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index c6b47a9c73..f723b9f631 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -608,10 +608,14 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
pcie_cap_flr_write_config(pci_dev, address, val, len);
}
- if (range_covers_byte(address, len, PCI_COMMAND) &&
- !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
- virtio_pci_stop_ioeventfd(proxy);
- virtio_set_status(vdev, vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
+ if (range_covers_byte(address, len, PCI_COMMAND)) {
+ if (!(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
+ virtio_set_disabled(vdev, true);
+ virtio_pci_stop_ioeventfd(proxy);
+ virtio_set_status(vdev, vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
+ } else {
+ virtio_set_disabled(vdev, false);
+ }
}
if (proxy->config_cap &&
@@ -1256,6 +1260,8 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr,
break;
case VIRTIO_PCI_COMMON_Q_SIZE:
proxy->vqs[vdev->queue_sel].num = val;
+ virtio_queue_set_num(vdev, vdev->queue_sel,
+ proxy->vqs[vdev->queue_sel].num);
break;
case VIRTIO_PCI_COMMON_Q_MSIX:
msix_vector_unuse(&proxy->pci_dev,
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 04716b5f6c..7b861e0ca0 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -432,6 +432,11 @@ static void virtio_queue_packed_set_notification(VirtQueue *vq, int enable)
}
}
+bool virtio_queue_get_notification(VirtQueue *vq)
+{
+ return vq->notification;
+}
+
void virtio_queue_set_notification(VirtQueue *vq, int enable)
{
vq->notification = enable;
@@ -546,7 +551,7 @@ static inline bool is_desc_avail(uint16_t flags, bool wrap_counter)
* Called within rcu_read_lock(). */
static int virtio_queue_empty_rcu(VirtQueue *vq)
{
- if (unlikely(vq->vdev->broken)) {
+ if (virtio_device_disabled(vq->vdev)) {
return 1;
}
@@ -565,7 +570,7 @@ static int virtio_queue_split_empty(VirtQueue *vq)
{
bool empty;
- if (unlikely(vq->vdev->broken)) {
+ if (virtio_device_disabled(vq->vdev)) {
return 1;
}
@@ -783,7 +788,7 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
virtqueue_unmap_sg(vq, elem, len);
- if (unlikely(vq->vdev->broken)) {
+ if (virtio_device_disabled(vq->vdev)) {
return;
}
@@ -839,7 +844,7 @@ static void virtqueue_packed_flush(VirtQueue *vq, unsigned int count)
void virtqueue_flush(VirtQueue *vq, unsigned int count)
{
- if (unlikely(vq->vdev->broken)) {
+ if (virtio_device_disabled(vq->vdev)) {
vq->inuse -= count;
return;
}
@@ -1602,7 +1607,7 @@ err_undo_map:
void *virtqueue_pop(VirtQueue *vq, size_t sz)
{
- if (unlikely(vq->vdev->broken)) {
+ if (virtio_device_disabled(vq->vdev)) {
return NULL;
}
@@ -1698,7 +1703,7 @@ unsigned int virtqueue_drop_all(VirtQueue *vq)
{
struct VirtIODevice *vdev = vq->vdev;
- if (unlikely(vdev->broken)) {
+ if (virtio_device_disabled(vq->vdev)) {
return 0;
}
@@ -1816,7 +1821,7 @@ static void virtio_notify_vector(VirtIODevice *vdev, uint16_t vector)
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- if (unlikely(vdev->broken)) {
+ if (virtio_device_disabled(vdev)) {
return;
}
@@ -1920,6 +1925,7 @@ void virtio_reset(void *opaque)
vdev->guest_features = 0;
vdev->queue_sel = 0;
vdev->status = 0;
+ vdev->disabled = false;
atomic_set(&vdev->isr, 0);
vdev->config_vector = VIRTIO_NO_VECTOR;
virtio_notify_vector(vdev, vdev->config_vector);
@@ -2330,17 +2336,24 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
return &vdev->vq[i];
}
+void virtio_delete_queue(VirtQueue *vq)
+{
+ vq->vring.num = 0;
+ vq->vring.num_default = 0;
+ vq->handle_output = NULL;
+ vq->handle_aio_output = NULL;
+ g_free(vq->used_elems);
+ vq->used_elems = NULL;
+ virtio_virtqueue_reset_region_cache(vq);
+}
+
void virtio_del_queue(VirtIODevice *vdev, int n)
{
if (n < 0 || n >= VIRTIO_QUEUE_MAX) {
abort();
}
- vdev->vq[n].vring.num = 0;
- vdev->vq[n].vring.num_default = 0;
- vdev->vq[n].handle_output = NULL;
- vdev->vq[n].handle_aio_output = NULL;
- g_free(vdev->vq[n].used_elems);
+ virtio_delete_queue(&vdev->vq[n]);
}
static void virtio_set_isr(VirtIODevice *vdev, int value)
@@ -2553,6 +2566,13 @@ static bool virtio_started_needed(void *opaque)
return vdev->started;
}
+static bool virtio_disabled_needed(void *opaque)
+{
+ VirtIODevice *vdev = opaque;
+
+ return vdev->disabled;
+}
+
static const VMStateDescription vmstate_virtqueue = {
.name = "virtqueue_state",
.version_id = 1,
@@ -2718,6 +2738,17 @@ static const VMStateDescription vmstate_virtio_started = {
}
};
+static const VMStateDescription vmstate_virtio_disabled = {
+ .name = "virtio/disabled",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = &virtio_disabled_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(disabled, VirtIODevice),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_virtio = {
.name = "virtio",
.version_id = 1,
@@ -2735,6 +2766,7 @@ static const VMStateDescription vmstate_virtio = {
&vmstate_virtio_extra_state,
&vmstate_virtio_started,
&vmstate_virtio_packed_virtqueues,
+ &vmstate_virtio_disabled,
NULL
}
};
@@ -3384,17 +3416,12 @@ static bool virtio_queue_host_notifier_aio_poll(void *opaque)
{
EventNotifier *n = opaque;
VirtQueue *vq = container_of(n, VirtQueue, host_notifier);
- bool progress;
if (!vq->vring.desc || virtio_queue_empty(vq)) {
return false;
}
- progress = virtio_queue_notify_aio_vq(vq);
-
- /* In case the handler function re-enabled notifications */
- virtio_queue_set_notification(vq, 0);
- return progress;
+ return virtio_queue_notify_aio_vq(vq);
}
static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n)
@@ -3569,6 +3596,7 @@ static void virtio_device_instance_finalize(Object *obj)
static Property virtio_properties[] = {
DEFINE_VIRTIO_COMMON_FEATURES(VirtIODevice, host_features),
DEFINE_PROP_BOOL("use-started", VirtIODevice, use_started, true),
+ DEFINE_PROP_BOOL("use-disabled-flag", VirtIODevice, use_disabled_flag, true),
DEFINE_PROP_END_OF_LIST(),
};