aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/acpi/pcihp.c2
-rw-r--r--hw/acpi/piix4.c42
-rw-r--r--hw/arm/boot.c3
-rw-r--r--hw/core/irq.c14
-rw-r--r--hw/core/numa.c2
-rw-r--r--hw/core/ptimer.c91
-rw-r--r--hw/i386/Kconfig3
-rw-r--r--hw/i386/acpi-build.c132
-rw-r--r--hw/i386/pc_piix.c10
-rw-r--r--hw/i386/xen/xen-hvm.c5
-rw-r--r--hw/intc/apic_common.c49
-rw-r--r--hw/isa/Kconfig4
-rw-r--r--hw/isa/Makefile.objs1
-rw-r--r--hw/isa/piix3.c399
-rw-r--r--hw/isa/piix4.c143
-rw-r--r--hw/m68k/q800.c40
-rw-r--r--hw/mips/gt64xxx_pci.c5
-rw-r--r--hw/mips/mips_malta.c46
-rw-r--r--hw/misc/grlib_ahb_apb_pnp.c12
-rw-r--r--hw/net/dp8393x.c113
-rw-r--r--hw/nvram/fw_cfg.c7
-rw-r--r--hw/pci-host/Kconfig3
-rw-r--r--hw/pci-host/Makefile.objs2
-rw-r--r--hw/pci-host/i440fx.c (renamed from hw/pci-host/piix.c)424
-rw-r--r--hw/pci/pci.c43
-rw-r--r--hw/rdma/rdma_backend.c13
-rw-r--r--hw/rdma/rdma_backend.h5
-rw-r--r--hw/rdma/rdma_rm.c5
-rw-r--r--hw/rdma/vmw/pvrdma_main.c6
-rw-r--r--hw/riscv/virt.c2
-rw-r--r--hw/timer/i8254_common.c40
-rw-r--r--hw/usb/host-libusb.c13
-rw-r--r--hw/virtio/virtio-bus.c4
-rw-r--r--hw/virtio/virtio.c9
34 files changed, 905 insertions, 787 deletions
diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
index 82d295b6e8..8413348a33 100644
--- a/hw/acpi/pcihp.c
+++ b/hw/acpi/pcihp.c
@@ -27,7 +27,7 @@
#include "qemu/osdep.h"
#include "hw/acpi/pcihp.h"
-#include "hw/i386/pc.h"
+#include "hw/pci-host/i440fx.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bridge.h"
#include "hw/acpi/acpi.h"
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 4e079b39bd..93aec2dd2c 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -21,6 +21,7 @@
#include "qemu/osdep.h"
#include "hw/i386/pc.h"
+#include "hw/southbridge/piix.h"
#include "hw/irq.h"
#include "hw/isa/apm.h"
#include "hw/i2c/pm_smbus.h"
@@ -32,7 +33,6 @@
#include "qapi/error.h"
#include "qemu/range.h"
#include "exec/address-spaces.h"
-#include "hw/acpi/piix4.h"
#include "hw/acpi/pcihp.h"
#include "hw/acpi/cpu_hotplug.h"
#include "hw/acpi/cpu.h"
@@ -41,7 +41,6 @@
#include "hw/acpi/memory_hotplug.h"
#include "hw/acpi/acpi_dev_interface.h"
#include "hw/xen/xen.h"
-#include "migration/qemu-file-types.h"
#include "migration/vmstate.h"
#include "hw/core/cpu.h"
#include "trace.h"
@@ -204,43 +203,6 @@ static const VMStateDescription vmstate_pci_status = {
}
};
-static int acpi_load_old(QEMUFile *f, void *opaque, int version_id)
-{
- PIIX4PMState *s = opaque;
- int ret, i;
- uint16_t temp;
-
- ret = pci_device_load(PCI_DEVICE(s), f);
- if (ret < 0) {
- return ret;
- }
- qemu_get_be16s(f, &s->ar.pm1.evt.sts);
- qemu_get_be16s(f, &s->ar.pm1.evt.en);
- qemu_get_be16s(f, &s->ar.pm1.cnt.cnt);
-
- ret = vmstate_load_state(f, &vmstate_apm, &s->apm, 1);
- if (ret) {
- return ret;
- }
-
- timer_get(f, s->ar.tmr.timer);
- qemu_get_sbe64s(f, &s->ar.tmr.overflow_time);
-
- qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts);
- for (i = 0; i < 3; i++) {
- qemu_get_be16s(f, &temp);
- }
-
- qemu_get_be16s(f, (uint16_t *)s->ar.gpe.en);
- for (i = 0; i < 3; i++) {
- qemu_get_be16s(f, &temp);
- }
-
- ret = vmstate_load_state(f, &vmstate_pci_status,
- &s->acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT], 1);
- return ret;
-}
-
static bool vmstate_test_use_acpi_pci_hotplug(void *opaque, int version_id)
{
PIIX4PMState *s = opaque;
@@ -312,8 +274,6 @@ static const VMStateDescription vmstate_acpi = {
.name = "piix4_pm",
.version_id = 3,
.minimum_version_id = 3,
- .minimum_version_id_old = 1,
- .load_state_old = acpi_load_old,
.post_load = vmstate_acpi_post_load,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(parent_obj, PIIX4PMState),
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index ef6724960c..8fb4a63606 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -240,6 +240,9 @@ void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu,
};
uint32_t board_setup_blob[] = {
/* board setup addr */
+ 0xee110f51, /* mrc p15, 0, r0, c1, c1, 2 ;read NSACR */
+ 0xe3800b03, /* orr r0, #0xc00 ;set CP11, CP10 */
+ 0xee010f51, /* mcr p15, 0, r0, c1, c1, 2 ;write NSACR */
0xe3a00e00 + (mvbar_addr >> 4), /* mov r0, #mvbar_addr */
0xee0c0f30, /* mcr p15, 0, r0, c12, c0, 1 ;set MVBAR */
0xee110f11, /* mrc p15, 0, r0, c1 , c1, 0 ;read SCR */
diff --git a/hw/core/irq.c b/hw/core/irq.c
index 7cc0295d0e..fb3045b912 100644
--- a/hw/core/irq.c
+++ b/hw/core/irq.c
@@ -120,20 +120,6 @@ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2)
return qemu_allocate_irq(qemu_splitirq, s, 0);
}
-static void proxy_irq_handler(void *opaque, int n, int level)
-{
- qemu_irq **target = opaque;
-
- if (*target) {
- qemu_set_irq((*target)[n], level);
- }
-}
-
-qemu_irq *qemu_irq_proxy(qemu_irq **target, int n)
-{
- return qemu_allocate_irqs(proxy_irq_handler, target, n);
-}
-
void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n)
{
int i;
diff --git a/hw/core/numa.c b/hw/core/numa.c
index 038c96d4ab..e3332a984f 100644
--- a/hw/core/numa.c
+++ b/hw/core/numa.c
@@ -503,7 +503,7 @@ static void allocate_system_memory_nonnuma(MemoryRegion *mr, Object *owner,
warn_report("falling back to regular RAM allocation");
error_printf("This is deprecated. Make sure that -mem-path "
" specified path has sufficient resources to allocate"
- " -m specified RAM amount");
+ " -m specified RAM amount\n");
/* Legacy behavior: if allocation failed, fall back to
* regular RAM allocation.
*/
diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
index 7239b8227c..b5a54e2536 100644
--- a/hw/core/ptimer.c
+++ b/hw/core/ptimer.c
@@ -29,7 +29,6 @@ struct ptimer_state
int64_t last_event;
int64_t next_event;
uint8_t policy_mask;
- QEMUBH *bh;
QEMUTimer *timer;
ptimer_cb callback;
void *callback_opaque;
@@ -46,12 +45,7 @@ struct ptimer_state
/* Use a bottom-half routine to avoid reentrancy issues. */
static void ptimer_trigger(ptimer_state *s)
{
- if (s->bh) {
- replay_bh_schedule_event(s->bh);
- }
- if (s->callback) {
- s->callback(s->callback_opaque);
- }
+ s->callback(s->callback_opaque);
}
static void ptimer_reload(ptimer_state *s, int delta_adjust)
@@ -296,15 +290,10 @@ uint64_t ptimer_get_count(ptimer_state *s)
void ptimer_set_count(ptimer_state *s, uint64_t count)
{
- assert(s->in_transaction || !s->callback);
+ assert(s->in_transaction);
s->delta = count;
if (s->enabled) {
- if (!s->callback) {
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s, 0);
- } else {
- s->need_reload = true;
- }
+ s->need_reload = true;
}
}
@@ -312,7 +301,7 @@ void ptimer_run(ptimer_state *s, int oneshot)
{
bool was_disabled = !s->enabled;
- assert(s->in_transaction || !s->callback);
+ assert(s->in_transaction);
if (was_disabled && s->period == 0) {
if (!qtest_enabled()) {
@@ -322,12 +311,7 @@ void ptimer_run(ptimer_state *s, int oneshot)
}
s->enabled = oneshot ? 2 : 1;
if (was_disabled) {
- if (!s->callback) {
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s, 0);
- } else {
- s->need_reload = true;
- }
+ s->need_reload = true;
}
}
@@ -335,7 +319,7 @@ void ptimer_run(ptimer_state *s, int oneshot)
is immediately restarted. */
void ptimer_stop(ptimer_state *s)
{
- assert(s->in_transaction || !s->callback);
+ assert(s->in_transaction);
if (!s->enabled)
return;
@@ -343,42 +327,30 @@ void ptimer_stop(ptimer_state *s)
s->delta = ptimer_get_count(s);
timer_del(s->timer);
s->enabled = 0;
- if (s->callback) {
- s->need_reload = false;
- }
+ s->need_reload = false;
}
/* Set counter increment interval in nanoseconds. */
void ptimer_set_period(ptimer_state *s, int64_t period)
{
- assert(s->in_transaction || !s->callback);
+ assert(s->in_transaction);
s->delta = ptimer_get_count(s);
s->period = period;
s->period_frac = 0;
if (s->enabled) {
- if (!s->callback) {
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s, 0);
- } else {
- s->need_reload = true;
- }
+ s->need_reload = true;
}
}
/* Set counter frequency in Hz. */
void ptimer_set_freq(ptimer_state *s, uint32_t freq)
{
- assert(s->in_transaction || !s->callback);
+ assert(s->in_transaction);
s->delta = ptimer_get_count(s);
s->period = 1000000000ll / freq;
s->period_frac = (1000000000ll << 32) / freq;
if (s->enabled) {
- if (!s->callback) {
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s, 0);
- } else {
- s->need_reload = true;
- }
+ s->need_reload = true;
}
}
@@ -386,17 +358,12 @@ void ptimer_set_freq(ptimer_state *s, uint32_t freq)
count = limit. */
void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
{
- assert(s->in_transaction || !s->callback);
+ assert(s->in_transaction);
s->limit = limit;
if (reload)
s->delta = limit;
if (s->enabled && reload) {
- if (!s->callback) {
- s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s, 0);
- } else {
- s->need_reload = true;
- }
+ s->need_reload = true;
}
}
@@ -407,7 +374,7 @@ uint64_t ptimer_get_limit(ptimer_state *s)
void ptimer_transaction_begin(ptimer_state *s)
{
- assert(!s->in_transaction || !s->callback);
+ assert(!s->in_transaction);
s->in_transaction = true;
s->need_reload = false;
}
@@ -448,37 +415,12 @@ const VMStateDescription vmstate_ptimer = {
}
};
-ptimer_state *ptimer_init_with_bh(QEMUBH *bh, uint8_t policy_mask)
-{
- ptimer_state *s;
-
- s = (ptimer_state *)g_malloc0(sizeof(ptimer_state));
- s->bh = bh;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ptimer_tick, s);
- s->policy_mask = policy_mask;
-
- /*
- * These two policies are incompatible -- trigger-on-decrement implies
- * a timer trigger when the count becomes 0, but no-immediate-trigger
- * implies a trigger when the count stops being 0.
- */
- assert(!((policy_mask & PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT) &&
- (policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)));
- return s;
-}
-
ptimer_state *ptimer_init(ptimer_cb callback, void *callback_opaque,
uint8_t policy_mask)
{
ptimer_state *s;
- /*
- * The callback function is mandatory; so we use it to distinguish
- * old-style QEMUBH ptimers from new transaction API ptimers.
- * (ptimer_init_with_bh() allows a NULL bh pointer and at least
- * one device (digic-timer) passes NULL, so it's not the case
- * that either s->bh != NULL or s->callback != NULL.)
- */
+ /* The callback function is mandatory. */
assert(callback);
s = g_new0(ptimer_state, 1);
@@ -499,9 +441,6 @@ ptimer_state *ptimer_init(ptimer_cb callback, void *callback_opaque,
void ptimer_free(ptimer_state *s)
{
- if (s->bh) {
- qemu_bh_delete(s->bh);
- }
timer_free(s->timer);
g_free(s);
}
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
index b25bb6d78a..5a494342ea 100644
--- a/hw/i386/Kconfig
+++ b/hw/i386/Kconfig
@@ -60,7 +60,8 @@ config I440FX
select PC_PCI
select PC_ACPI
select ACPI_SMBUS
- select PCI_PIIX
+ select PCI_I440FX
+ select PIIX3
select IDE_PIIX
select DIMM
select SMBIOS
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 9dd3dbb16c..12ff55fcfb 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -34,7 +34,6 @@
#include "hw/acpi/acpi-defs.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/cpu.h"
-#include "hw/acpi/piix4.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/acpi/bios-linker-loader.h"
#include "hw/isa/isa.h"
@@ -52,7 +51,7 @@
#include "sysemu/reset.h"
/* Supported chipsets: */
-#include "hw/acpi/piix4.h"
+#include "hw/southbridge/piix.h"
#include "hw/acpi/pcihp.h"
#include "hw/i386/ich9.h"
#include "hw/pci/pci_bus.h"
@@ -210,7 +209,7 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm)
/* The above need not be conditional on machine type because the reset port
* happens to be the same on PIIX (pc) and ICH9 (q35). */
- QEMU_BUILD_BUG_ON(ICH9_RST_CNT_IOPORT != RCR_IOPORT);
+ QEMU_BUILD_BUG_ON(ICH9_RST_CNT_IOPORT != PIIX_RCR_IOPORT);
/* Fill in optional s3/s4 related properties */
o = object_property_get_qobject(obj, ACPI_PM_PROP_S3_DISABLED, NULL);
@@ -2518,12 +2517,105 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker)
*/
#define IOAPIC_SB_DEVID (uint64_t)PCI_BUILD_BDF(0, PCI_DEVFN(0x14, 0))
+/*
+ * Insert IVHD entry for device and recurse, insert alias, or insert range as
+ * necessary for the PCI topology.
+ */
+static void
+insert_ivhd(PCIBus *bus, PCIDevice *dev, void *opaque)
+{
+ GArray *table_data = opaque;
+ uint32_t entry;
+
+ /* "Select" IVHD entry, type 0x2 */
+ entry = PCI_BUILD_BDF(pci_bus_num(bus), dev->devfn) << 8 | 0x2;
+ build_append_int_noprefix(table_data, entry, 4);
+
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
+ PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
+ uint8_t sec = pci_bus_num(sec_bus);
+ uint8_t sub = dev->config[PCI_SUBORDINATE_BUS];
+
+ if (pci_bus_is_express(sec_bus)) {
+ /*
+ * Walk the bus if there are subordinates, otherwise use a range
+ * to cover an entire leaf bus. We could potentially also use a
+ * range for traversed buses, but we'd need to take care not to
+ * create both Select and Range entries covering the same device.
+ * This is easier and potentially more compact.
+ *
+ * An example bare metal system seems to use Select entries for
+ * root ports without a slot (ie. built-ins) and Range entries
+ * when there is a slot. The same system also only hard-codes
+ * the alias range for an onboard PCIe-to-PCI bridge, apparently
+ * making no effort to support nested bridges. We attempt to
+ * be more thorough here.
+ */
+ if (sec == sub) { /* leaf bus */
+ /* "Start of Range" IVHD entry, type 0x3 */
+ entry = PCI_BUILD_BDF(sec, PCI_DEVFN(0, 0)) << 8 | 0x3;
+ build_append_int_noprefix(table_data, entry, 4);
+ /* "End of Range" IVHD entry, type 0x4 */
+ entry = PCI_BUILD_BDF(sub, PCI_DEVFN(31, 7)) << 8 | 0x4;
+ build_append_int_noprefix(table_data, entry, 4);
+ } else {
+ pci_for_each_device(sec_bus, sec, insert_ivhd, table_data);
+ }
+ } else {
+ /*
+ * If the secondary bus is conventional, then we need to create an
+ * Alias range for everything downstream. The range covers the
+ * first devfn on the secondary bus to the last devfn on the
+ * subordinate bus. The alias target depends on legacy versus
+ * express bridges, just as in pci_device_iommu_address_space().
+ * DeviceIDa vs DeviceIDb as per the AMD IOMMU spec.
+ */
+ uint16_t dev_id_a, dev_id_b;
+
+ dev_id_a = PCI_BUILD_BDF(sec, PCI_DEVFN(0, 0));
+
+ if (pci_is_express(dev) &&
+ pcie_cap_get_type(dev) == PCI_EXP_TYPE_PCI_BRIDGE) {
+ dev_id_b = dev_id_a;
+ } else {
+ dev_id_b = PCI_BUILD_BDF(pci_bus_num(bus), dev->devfn);
+ }
+
+ /* "Alias Start of Range" IVHD entry, type 0x43, 8 bytes */
+ build_append_int_noprefix(table_data, dev_id_a << 8 | 0x43, 4);
+ build_append_int_noprefix(table_data, dev_id_b << 8 | 0x0, 4);
+
+ /* "End of Range" IVHD entry, type 0x4 */
+ entry = PCI_BUILD_BDF(sub, PCI_DEVFN(31, 7)) << 8 | 0x4;
+ build_append_int_noprefix(table_data, entry, 4);
+ }
+ }
+}
+
+/* For all PCI host bridges, walk and insert IVHD entries */
+static int
+ivrs_host_bridges(Object *obj, void *opaque)
+{
+ GArray *ivhd_blob = opaque;
+
+ if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
+ PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus;
+
+ if (bus) {
+ pci_for_each_device(bus, pci_bus_num(bus), insert_ivhd, ivhd_blob);
+ }
+ }
+
+ return 0;
+}
+
static void
build_amd_iommu(GArray *table_data, BIOSLinker *linker)
{
- int ivhd_table_len = 28;
+ int ivhd_table_len = 24;
int iommu_start = table_data->len;
AMDVIState *s = AMD_IOMMU_DEVICE(x86_iommu_get_default());
+ GArray *ivhd_blob = g_array_new(false, true, 1);
/* IVRS header */
acpi_data_push(table_data, sizeof(AcpiTableHeader));
@@ -2545,12 +2637,34 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker)
1);
/*
+ * A PCI bus walk, for each PCI host bridge, is necessary to create a
+ * complete set of IVHD entries. Do this into a separate blob so that we
+ * can calculate the total IVRS table length here and then append the new
+ * blob further below. Fall back to an entry covering all devices, which
+ * is sufficient when no aliases are present.
+ */
+ object_child_foreach_recursive(object_get_root(),
+ ivrs_host_bridges, ivhd_blob);
+
+ if (!ivhd_blob->len) {
+ /*
+ * Type 1 device entry reporting all devices
+ * These are 4-byte device entries currently reporting the range of
+ * Refer to Spec - Table 95:IVHD Device Entry Type Codes(4-byte)
+ */
+ build_append_int_noprefix(ivhd_blob, 0x0000001, 4);
+ }
+
+ ivhd_table_len += ivhd_blob->len;
+
+ /*
* When interrupt remapping is supported, we add a special IVHD device
* for type IO-APIC.
*/
if (x86_iommu_ir_supported(x86_iommu_get_default())) {
ivhd_table_len += 8;
}
+
/* IVHD length */
build_append_int_noprefix(table_data, ivhd_table_len, 2);
/* DeviceID */
@@ -2570,12 +2684,10 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker)
(1UL << 2) | /* GTSup */
(1UL << 6), /* GASup */
4);
- /*
- * Type 1 device entry reporting all devices
- * These are 4-byte device entries currently reporting the range of
- * Refer to Spec - Table 95:IVHD Device Entry Type Codes(4-byte)
- */
- build_append_int_noprefix(table_data, 0x0000001, 4);
+
+ /* IVHD entries as found above */
+ g_array_append_vals(table_data, ivhd_blob->data, ivhd_blob->len);
+ g_array_free(ivhd_blob, TRUE);
/*
* Add a special IVHD device type.
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index c15929a1f5..2aefa3b8df 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -30,6 +30,8 @@
#include "hw/i386/x86.h"
#include "hw/i386/pc.h"
#include "hw/i386/apic.h"
+#include "hw/pci-host/i440fx.h"
+#include "hw/southbridge/piix.h"
#include "hw/display/ramfb.h"
#include "hw/firmware/smbios.h"
#include "hw/pci/pci.h"
@@ -190,14 +192,20 @@ static void pc_init1(MachineState *machine,
gsi_state = pc_gsi_create(&x86ms->gsi, pcmc->pci_enabled);
if (pcmc->pci_enabled) {
+ PIIX3State *piix3;
+
pci_bus = i440fx_init(host_type,
pci_type,
- &i440fx_state, &piix3_devfn, &isa_bus, x86ms->gsi,
+ &i440fx_state,
system_memory, system_io, machine->ram_size,
x86ms->below_4g_mem_size,
x86ms->above_4g_mem_size,
pci_memory, ram_memory);
pcms->bus = pci_bus;
+
+ piix3 = piix3_create(pci_bus, &isa_bus);
+ piix3->pic = x86ms->gsi;
+ piix3_devfn = piix3->dev.devfn;
} else {
pci_bus = NULL;
i440fx_state = NULL;
diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c
index 95f23a263c..82ece6b9e7 100644
--- a/hw/i386/xen/xen-hvm.c
+++ b/hw/i386/xen/xen-hvm.c
@@ -14,6 +14,7 @@
#include "hw/pci/pci.h"
#include "hw/pci/pci_host.h"
#include "hw/i386/pc.h"
+#include "hw/southbridge/piix.h"
#include "hw/irq.h"
#include "hw/hw.h"
#include "hw/i386/apic-msidef.h"
@@ -156,8 +157,8 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
v = 0;
}
v &= 0xf;
- if (((address + i) >= 0x60) && ((address + i) <= 0x63)) {
- xen_set_pci_link_route(xen_domid, address + i - 0x60, v);
+ if (((address + i) >= PIIX_PIRQCA) && ((address + i) <= PIIX_PIRQCD)) {
+ xen_set_pci_link_route(xen_domid, address + i - PIIX_PIRQCA, v);
}
}
}
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
index aafd8e0e33..375cb6abe9 100644
--- a/hw/intc/apic_common.c
+++ b/hw/intc/apic_common.c
@@ -31,7 +31,6 @@
#include "sysemu/kvm.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
-#include "migration/qemu-file-types.h"
#include "migration/vmstate.h"
static int apic_irq_delivered;
@@ -262,52 +261,6 @@ static void apic_reset_common(DeviceState *dev)
apic_init_reset(dev);
}
-/* This function is only used for old state version 1 and 2 */
-static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
-{
- APICCommonState *s = opaque;
- APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
- int i;
-
- if (version_id > 2) {
- return -EINVAL;
- }
-
- /* XXX: what if the base changes? (registered memory regions) */
- qemu_get_be32s(f, &s->apicbase);
- qemu_get_8s(f, &s->id);
- qemu_get_8s(f, &s->arb_id);
- qemu_get_8s(f, &s->tpr);
- qemu_get_be32s(f, &s->spurious_vec);
- qemu_get_8s(f, &s->log_dest);
- qemu_get_8s(f, &s->dest_mode);
- for (i = 0; i < 8; i++) {
- qemu_get_be32s(f, &s->isr[i]);
- qemu_get_be32s(f, &s->tmr[i]);
- qemu_get_be32s(f, &s->irr[i]);
- }
- for (i = 0; i < APIC_LVT_NB; i++) {
- qemu_get_be32s(f, &s->lvt[i]);
- }
- qemu_get_be32s(f, &s->esr);
- qemu_get_be32s(f, &s->icr[0]);
- qemu_get_be32s(f, &s->icr[1]);
- qemu_get_be32s(f, &s->divide_conf);
- s->count_shift = qemu_get_be32(f);
- qemu_get_be32s(f, &s->initial_count);
- s->initial_count_load_time = qemu_get_be64(f);
- s->next_time = qemu_get_be64(f);
-
- if (version_id >= 2) {
- s->timer_expiry = qemu_get_be64(f);
- }
-
- if (info->post_load) {
- info->post_load(s);
- }
- return 0;
-}
-
static const VMStateDescription vmstate_apic_common;
static void apic_common_realize(DeviceState *dev, Error **errp)
@@ -408,8 +361,6 @@ static const VMStateDescription vmstate_apic_common = {
.name = "apic",
.version_id = 3,
.minimum_version_id = 3,
- .minimum_version_id_old = 1,
- .load_state_old = apic_load_old,
.pre_load = apic_pre_load,
.pre_save = apic_dispatch_pre_save,
.post_load = apic_dispatch_post_load,
diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig
index 98a289957e..8a38813cc1 100644
--- a/hw/isa/Kconfig
+++ b/hw/isa/Kconfig
@@ -29,6 +29,10 @@ config PC87312
select FDC
select IDE_ISA
+config PIIX3
+ bool
+ select ISA_BUS
+
config PIIX4
bool
# For historical reasons, SuperIO devices are created in the board
diff --git a/hw/isa/Makefile.objs b/hw/isa/Makefile.objs
index ff97485504..8e73960a75 100644
--- a/hw/isa/Makefile.objs
+++ b/hw/isa/Makefile.objs
@@ -3,6 +3,7 @@ common-obj-$(CONFIG_ISA_SUPERIO) += isa-superio.o
common-obj-$(CONFIG_APM) += apm.o
common-obj-$(CONFIG_I82378) += i82378.o
common-obj-$(CONFIG_PC87312) += pc87312.o
+common-obj-$(CONFIG_PIIX3) += piix3.o
common-obj-$(CONFIG_PIIX4) += piix4.o
common-obj-$(CONFIG_VT82C686) += vt82c686.o
common-obj-$(CONFIG_SMC37C669) += smc37c669-superio.o
diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c
new file mode 100644
index 0000000000..fd1c78879f
--- /dev/null
+++ b/hw/isa/piix3.c
@@ -0,0 +1,399 @@
+/*
+ * QEMU PIIX PCI ISA Bridge Emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/range.h"
+#include "hw/southbridge/piix.h"
+#include "hw/irq.h"
+#include "hw/isa/isa.h"
+#include "hw/xen/xen.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/reset.h"
+#include "sysemu/runstate.h"
+#include "migration/vmstate.h"
+
+#define XEN_PIIX_NUM_PIRQS 128ULL
+
+#define TYPE_PIIX3_PCI_DEVICE "pci-piix3"
+#define PIIX3_PCI_DEVICE(obj) \
+ OBJECT_CHECK(PIIX3State, (obj), TYPE_PIIX3_PCI_DEVICE)
+
+#define TYPE_PIIX3_DEVICE "PIIX3"
+#define TYPE_PIIX3_XEN_DEVICE "PIIX3-xen"
+
+static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
+{
+ qemu_set_irq(piix3->pic[pic_irq],
+ !!(piix3->pic_levels &
+ (((1ULL << PIIX_NUM_PIRQS) - 1) <<
+ (pic_irq * PIIX_NUM_PIRQS))));
+}
+
+static void piix3_set_irq_level_internal(PIIX3State *piix3, int pirq, int level)
+{
+ int pic_irq;
+ uint64_t mask;
+
+ pic_irq = piix3->dev.config[PIIX_PIRQCA + pirq];
+ if (pic_irq >= PIIX_NUM_PIC_IRQS) {
+ return;
+ }
+
+ mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
+ piix3->pic_levels &= ~mask;
+ piix3->pic_levels |= mask * !!level;
+}
+
+static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
+{
+ int pic_irq;
+
+ pic_irq = piix3->dev.config[PIIX_PIRQCA + pirq];
+ if (pic_irq >= PIIX_NUM_PIC_IRQS) {
+ return;
+ }
+
+ piix3_set_irq_level_internal(piix3, pirq, level);
+
+ piix3_set_irq_pic(piix3, pic_irq);
+}
+
+static void piix3_set_irq(void *opaque, int pirq, int level)
+{
+ PIIX3State *piix3 = opaque;
+ piix3_set_irq_level(piix3, pirq, level);
+}
+
+static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin)
+{
+ PIIX3State *piix3 = opaque;
+ int irq = piix3->dev.config[PIIX_PIRQCA + pin];
+ PCIINTxRoute route;
+
+ if (irq < PIIX_NUM_PIC_IRQS) {
+ route.mode = PCI_INTX_ENABLED;
+ route.irq = irq;
+ } else {
+ route.mode = PCI_INTX_DISABLED;
+ route.irq = -1;
+ }
+ return route;
+}
+
+/* irq routing is changed. so rebuild bitmap */
+static void piix3_update_irq_levels(PIIX3State *piix3)
+{
+ PCIBus *bus = pci_get_bus(&piix3->dev);
+ int pirq;
+
+ piix3->pic_levels = 0;
+ for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
+ piix3_set_irq_level(piix3, pirq, pci_bus_get_irq_level(bus, pirq));
+ }
+}
+
+static void piix3_write_config(PCIDevice *dev,
+ uint32_t address, uint32_t val, int len)
+{
+ pci_default_write_config(dev, address, val, len);
+ if (ranges_overlap(address, len, PIIX_PIRQCA, 4)) {
+ PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev);
+ int pic_irq;
+
+ pci_bus_fire_intx_routing_notifier(pci_get_bus(&piix3->dev));
+ piix3_update_irq_levels(piix3);
+ for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) {
+ piix3_set_irq_pic(piix3, pic_irq);
+ }
+ }
+}
+
+static void piix3_write_config_xen(PCIDevice *dev,
+ uint32_t address, uint32_t val, int len)
+{
+ xen_piix_pci_write_config_client(address, val, len);
+ piix3_write_config(dev, address, val, len);
+}
+
+static void piix3_reset(void *opaque)
+{
+ PIIX3State *d = opaque;
+ uint8_t *pci_conf = d->dev.config;
+
+ pci_conf[0x04] = 0x07; /* master, memory and I/O */
+ pci_conf[0x05] = 0x00;
+ pci_conf[0x06] = 0x00;
+ pci_conf[0x07] = 0x02; /* PCI_status_devsel_medium */
+ pci_conf[0x4c] = 0x4d;
+ pci_conf[0x4e] = 0x03;
+ pci_conf[0x4f] = 0x00;
+ pci_conf[0x60] = 0x80;
+ pci_conf[0x61] = 0x80;
+ pci_conf[0x62] = 0x80;
+ pci_conf[0x63] = 0x80;
+ pci_conf[0x69] = 0x02;
+ pci_conf[0x70] = 0x80;
+ pci_conf[0x76] = 0x0c;
+ pci_conf[0x77] = 0x0c;
+ pci_conf[0x78] = 0x02;
+ pci_conf[0x79] = 0x00;
+ pci_conf[0x80] = 0x00;
+ pci_conf[0x82] = 0x00;
+ pci_conf[0xa0] = 0x08;
+ pci_conf[0xa2] = 0x00;
+ pci_conf[0xa3] = 0x00;
+ pci_conf[0xa4] = 0x00;
+ pci_conf[0xa5] = 0x00;
+ pci_conf[0xa6] = 0x00;
+ pci_conf[0xa7] = 0x00;
+ pci_conf[0xa8] = 0x0f;
+ pci_conf[0xaa] = 0x00;
+ pci_conf[0xab] = 0x00;
+ pci_conf[0xac] = 0x00;
+ pci_conf[0xae] = 0x00;
+
+ d->pic_levels = 0;
+ d->rcr = 0;
+}
+
+static int piix3_post_load(void *opaque, int version_id)
+{
+ PIIX3State *piix3 = opaque;
+ int pirq;
+
+ /*
+ * Because the i8259 has not been deserialized yet, qemu_irq_raise
+ * might bring the system to a different state than the saved one;
+ * for example, the interrupt could be masked but the i8259 would
+ * not know that yet and would trigger an interrupt in the CPU.
+ *
+ * Here, we update irq levels without raising the interrupt.
+ * Interrupt state will be deserialized separately through the i8259.
+ */
+ piix3->pic_levels = 0;
+ for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
+ piix3_set_irq_level_internal(piix3, pirq,
+ pci_bus_get_irq_level(pci_get_bus(&piix3->dev), pirq));
+ }
+ return 0;
+}
+
+static int piix3_pre_save(void *opaque)
+{
+ int i;
+ PIIX3State *piix3 = opaque;
+
+ for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) {
+ piix3->pci_irq_levels_vmstate[i] =
+ pci_bus_get_irq_level(pci_get_bus(&piix3->dev), i);
+ }
+
+ return 0;
+}
+
+static bool piix3_rcr_needed(void *opaque)
+{
+ PIIX3State *piix3 = opaque;
+
+ return (piix3->rcr != 0);
+}
+
+static const VMStateDescription vmstate_piix3_rcr = {
+ .name = "PIIX3/rcr",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = piix3_rcr_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(rcr, PIIX3State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_piix3 = {
+ .name = "PIIX3",
+ .version_id = 3,
+ .minimum_version_id = 2,
+ .post_load = piix3_post_load,
+ .pre_save = piix3_pre_save,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(dev, PIIX3State),
+ VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State,
+ PIIX_NUM_PIRQS, 3),
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription*[]) {
+ &vmstate_piix3_rcr,
+ NULL
+ }
+};
+
+
+static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len)
+{
+ PIIX3State *d = opaque;
+
+ if (val & 4) {
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ return;
+ }
+ d->rcr = val & 2; /* keep System Reset type only */
+}
+
+static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len)
+{
+ PIIX3State *d = opaque;
+
+ return d->rcr;
+}
+
+static const MemoryRegionOps rcr_ops = {
+ .read = rcr_read,
+ .write = rcr_write,
+ .endianness = DEVICE_LITTLE_ENDIAN
+};
+
+static void piix3_realize(PCIDevice *dev, Error **errp)
+{
+ PIIX3State *d = PIIX3_PCI_DEVICE(dev);
+
+ if (!isa_bus_new(DEVICE(d), get_system_memory(),
+ pci_address_space_io(dev), errp)) {
+ return;
+ }
+
+ memory_region_init_io(&d->rcr_mem, OBJECT(dev), &rcr_ops, d,
+ "piix3-reset-control", 1);
+ memory_region_add_subregion_overlap(pci_address_space_io(dev),
+ PIIX_RCR_IOPORT, &d->rcr_mem, 1);
+
+ qemu_register_reset(piix3_reset, d);
+}
+
+static void pci_piix3_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ dc->desc = "ISA bridge";
+ dc->vmsd = &vmstate_piix3;
+ dc->hotpluggable = false;
+ k->realize = piix3_realize;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
+ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0;
+ k->class_id = PCI_CLASS_BRIDGE_ISA;
+ /*
+ * Reason: part of PIIX3 southbridge, needs to be wired up by
+ * pc_piix.c's pc_init1()
+ */
+ dc->user_creatable = false;
+}
+
+static const TypeInfo piix3_pci_type_info = {
+ .name = TYPE_PIIX3_PCI_DEVICE,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PIIX3State),
+ .abstract = true,
+ .class_init = pci_piix3_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
+};
+
+static void piix3_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->config_write = piix3_write_config;
+}
+
+static const TypeInfo piix3_info = {
+ .name = TYPE_PIIX3_DEVICE,
+ .parent = TYPE_PIIX3_PCI_DEVICE,
+ .class_init = piix3_class_init,
+};
+
+static void piix3_xen_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->config_write = piix3_write_config_xen;
+};
+
+static const TypeInfo piix3_xen_info = {
+ .name = TYPE_PIIX3_XEN_DEVICE,
+ .parent = TYPE_PIIX3_PCI_DEVICE,
+ .class_init = piix3_xen_class_init,
+};
+
+static void piix3_register_types(void)
+{
+ type_register_static(&piix3_pci_type_info);
+ type_register_static(&piix3_info);
+ type_register_static(&piix3_xen_info);
+}
+
+type_init(piix3_register_types)
+
+/*
+ * Return the global irq number corresponding to a given device irq
+ * pin. We could also use the bus number to have a more precise mapping.
+ */
+static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
+{
+ int slot_addend;
+ slot_addend = (pci_dev->devfn >> 3) - 1;
+ return (pci_intx + slot_addend) & 3;
+}
+
+PIIX3State *piix3_create(PCIBus *pci_bus, ISABus **isa_bus)
+{
+ PIIX3State *piix3;
+ PCIDevice *pci_dev;
+
+ /*
+ * Xen supports additional interrupt routes from the PCI devices to
+ * the IOAPIC: the four pins of each PCI device on the bus are also
+ * connected to the IOAPIC directly.
+ * These additional routes can be discovered through ACPI.
+ */
+ if (xen_enabled()) {
+ pci_dev = pci_create_simple_multifunction(pci_bus, -1, true,
+ TYPE_PIIX3_XEN_DEVICE);
+ piix3 = PIIX3_PCI_DEVICE(pci_dev);
+ pci_bus_irqs(pci_bus, xen_piix3_set_irq, xen_pci_slot_get_pirq,
+ piix3, XEN_PIIX_NUM_PIRQS);
+ } else {
+ pci_dev = pci_create_simple_multifunction(pci_bus, -1, true,
+ TYPE_PIIX3_DEVICE);
+ piix3 = PIIX3_PCI_DEVICE(pci_dev);
+ pci_bus_irqs(pci_bus, piix3_set_irq, pci_slot_get_pirq,
+ piix3, PIIX_NUM_PIRQS);
+ pci_bus_set_route_irq_fn(pci_bus, piix3_route_intx_pin_to_irq);
+ }
+ *isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0"));
+
+ return piix3;
+}
diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c
index 890d999abf..86678e6829 100644
--- a/hw/isa/piix4.c
+++ b/hw/isa/piix4.c
@@ -2,6 +2,7 @@
* QEMU PIIX4 PCI Bridge Emulation
*
* Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2018 Hervé Poussineau
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,19 +24,34 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/irq.h"
#include "hw/i386/pc.h"
+#include "hw/southbridge/piix.h"
#include "hw/pci/pci.h"
#include "hw/isa/isa.h"
#include "hw/sysbus.h"
+#include "hw/dma/i8257.h"
+#include "hw/timer/i8254.h"
+#include "hw/rtc/mc146818rtc.h"
+#include "hw/ide.h"
#include "migration/vmstate.h"
+#include "sysemu/reset.h"
+#include "sysemu/runstate.h"
PCIDevice *piix4_dev;
typedef struct PIIX4State {
PCIDevice dev;
+ qemu_irq cpu_intr;
+ qemu_irq *isa;
+
+ RTCState rtc;
+ /* Reset Control Register */
+ MemoryRegion rcr_mem;
+ uint8_t rcr;
} PIIX4State;
-#define TYPE_PIIX4_PCI_DEVICE "PIIX4"
#define PIIX4_PCI_DEVICE(obj) \
OBJECT_CHECK(PIIX4State, (obj), TYPE_PIIX4_PCI_DEVICE)
@@ -87,24 +103,102 @@ static const VMStateDescription vmstate_piix4 = {
}
};
+static void piix4_request_i8259_irq(void *opaque, int irq, int level)
+{
+ PIIX4State *s = opaque;
+ qemu_set_irq(s->cpu_intr, level);
+}
+
+static void piix4_set_i8259_irq(void *opaque, int irq, int level)
+{
+ PIIX4State *s = opaque;
+ qemu_set_irq(s->isa[irq], level);
+}
+
+static void piix4_rcr_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned int len)
+{
+ PIIX4State *s = opaque;
+
+ if (val & 4) {
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ return;
+ }
+
+ s->rcr = val & 2; /* keep System Reset type only */
+}
+
+static uint64_t piix4_rcr_read(void *opaque, hwaddr addr, unsigned int len)
+{
+ PIIX4State *s = opaque;
+
+ return s->rcr;
+}
+
+static const MemoryRegionOps piix4_rcr_ops = {
+ .read = piix4_rcr_read,
+ .write = piix4_rcr_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
+};
+
static void piix4_realize(PCIDevice *dev, Error **errp)
{
- PIIX4State *d = PIIX4_PCI_DEVICE(dev);
+ PIIX4State *s = PIIX4_PCI_DEVICE(dev);
+ ISABus *isa_bus;
+ qemu_irq *i8259_out_irq;
+ Error *err = NULL;
- if (!isa_bus_new(DEVICE(d), pci_address_space(dev),
- pci_address_space_io(dev), errp)) {
+ isa_bus = isa_bus_new(DEVICE(dev), pci_address_space(dev),
+ pci_address_space_io(dev), errp);
+ if (!isa_bus) {
return;
}
- piix4_dev = &d->dev;
+
+ qdev_init_gpio_in_named(DEVICE(dev), piix4_set_i8259_irq,
+ "isa", ISA_NUM_IRQS);
+ qdev_init_gpio_out_named(DEVICE(dev), &s->cpu_intr,
+ "intr", 1);
+
+ memory_region_init_io(&s->rcr_mem, OBJECT(dev), &piix4_rcr_ops, s,
+ "reset-control", 1);
+ memory_region_add_subregion_overlap(pci_address_space_io(dev),
+ PIIX_RCR_IOPORT, &s->rcr_mem, 1);
+
+ /* initialize i8259 pic */
+ i8259_out_irq = qemu_allocate_irqs(piix4_request_i8259_irq, s, 1);
+ s->isa = i8259_init(isa_bus, *i8259_out_irq);
+
+ /* initialize ISA irqs */
+ isa_bus_irqs(isa_bus, s->isa);
+
+ /* initialize pit */
+ i8254_pit_init(isa_bus, 0x40, 0, NULL);
+
+ /* DMA */
+ i8257_dma_init(isa_bus, 0);
+
+ /* RTC */
+ qdev_set_parent_bus(DEVICE(&s->rtc), BUS(isa_bus));
+ qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000);
+ object_property_set_bool(OBJECT(&s->rtc), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ isa_init_irq(ISA_DEVICE(&s->rtc), &s->rtc.irq, RTC_ISA_IRQ);
+
+ piix4_dev = dev;
}
-int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn)
+static void piix4_init(Object *obj)
{
- PCIDevice *d;
+ PIIX4State *s = PIIX4_PCI_DEVICE(obj);
- d = pci_create_simple_multifunction(bus, devfn, true, "PIIX4");
- *isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(d), "isa.0"));
- return d->devfn;
+ object_initialize(&s->rtc, sizeof(s->rtc), TYPE_MC146818_RTC);
}
static void piix4_class_init(ObjectClass *klass, void *data)
@@ -131,6 +225,7 @@ static const TypeInfo piix4_info = {
.name = TYPE_PIIX4_PCI_DEVICE,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PIIX4State),
+ .instance_init = piix4_init,
.class_init = piix4_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
@@ -144,3 +239,31 @@ static void piix4_register_types(void)
}
type_init(piix4_register_types)
+
+DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus,
+ I2CBus **smbus, size_t ide_buses)
+{
+ size_t ide_drives = ide_buses * MAX_IDE_DEVS;
+ DriveInfo **hd;
+ PCIDevice *pci;
+ DeviceState *dev;
+
+ pci = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(10, 0),
+ true, TYPE_PIIX4_PCI_DEVICE);
+ dev = DEVICE(pci);
+ if (isa_bus) {
+ *isa_bus = ISA_BUS(qdev_get_child_bus(dev, "isa.0"));
+ }
+
+ hd = g_new(DriveInfo *, ide_drives);
+ ide_drive_get(hd, ide_drives);
+ pci_piix4_ide_init(pci_bus, hd, pci->devfn + 1);
+ g_free(hd);
+ pci_create_simple(pci_bus, pci->devfn + 2, "piix4-usb-uhci");
+ if (smbus) {
+ *smbus = piix4_pm_init(pci_bus, pci->devfn + 3, 0x1100,
+ isa_get_irq(NULL, 9), NULL, 0, NULL);
+ }
+
+ return dev;
+}
diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index 2b4842f8c6..4ca8678007 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -60,14 +60,19 @@
#define MACH_MAC 3
#define Q800_MAC_CPU_ID 2
-#define VIA_BASE 0x50f00000
-#define SONIC_PROM_BASE 0x50f08000
-#define SONIC_BASE 0x50f0a000
-#define SCC_BASE 0x50f0c020
-#define ESP_BASE 0x50f10000
-#define ESP_PDMA 0x50f10100
-#define ASC_BASE 0x50F14000
-#define SWIM_BASE 0x50F1E000
+#define IO_BASE 0x50000000
+#define IO_SLICE 0x00040000
+#define IO_SIZE 0x04000000
+
+#define VIA_BASE (IO_BASE + 0x00000)
+#define SONIC_PROM_BASE (IO_BASE + 0x08000)
+#define SONIC_BASE (IO_BASE + 0x0a000)
+#define SCC_BASE (IO_BASE + 0x0c020)
+#define ESP_BASE (IO_BASE + 0x10000)
+#define ESP_PDMA (IO_BASE + 0x10100)
+#define ASC_BASE (IO_BASE + 0x14000)
+#define SWIM_BASE (IO_BASE + 0x1E000)
+
#define NUBUS_SUPER_SLOT_BASE 0x60000000
#define NUBUS_SLOT_BASE 0xf0000000
@@ -135,6 +140,9 @@ static void q800_init(MachineState *machine)
int32_t initrd_size;
MemoryRegion *rom;
MemoryRegion *ram;
+ MemoryRegion *io;
+ const int io_slice_nb = (IO_SIZE / IO_SLICE) - 1;
+ int i;
ram_addr_t ram_size = machine->ram_size;
const char *kernel_filename = machine->kernel_filename;
const char *initrd_filename = machine->initrd_filename;
@@ -163,10 +171,26 @@ static void q800_init(MachineState *machine)
cpu = M68K_CPU(cpu_create(machine->cpu_type));
qemu_register_reset(main_cpu_reset, cpu);
+ /* RAM */
ram = g_malloc(sizeof(*ram));
memory_region_init_ram(ram, NULL, "m68k_mac.ram", ram_size, &error_abort);
memory_region_add_subregion(get_system_memory(), 0, ram);
+ /*
+ * Memory from IO_BASE to IO_BASE + IO_SLICE is repeated
+ * from IO_BASE + IO_SLICE to IO_BASE + IO_SIZE
+ */
+ io = g_new(MemoryRegion, io_slice_nb);
+ for (i = 0; i < io_slice_nb; i++) {
+ char *name = g_strdup_printf("mac_m68k.io[%d]", i + 1);
+
+ memory_region_init_alias(&io[i], NULL, name, get_system_memory(),
+ IO_BASE, IO_SLICE);
+ memory_region_add_subregion(get_system_memory(),
+ IO_BASE + (i + 1) * IO_SLICE, &io[i]);
+ g_free(name);
+ }
+
/* IRQ Glue */
irq = g_new0(GLUEState, 1);
diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c
index f325bd6c1c..5cab9c1ee1 100644
--- a/hw/mips/gt64xxx_pci.c
+++ b/hw/mips/gt64xxx_pci.c
@@ -28,6 +28,7 @@
#include "hw/mips/mips.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_host.h"
+#include "hw/southbridge/piix.h"
#include "migration/vmstate.h"
#include "hw/i386/pc.h"
#include "hw/irq.h"
@@ -1012,12 +1013,12 @@ static void gt64120_pci_set_irq(void *opaque, int irq_num, int level)
/* now we change the pic irq level according to the piix irq mappings */
/* XXX: optimize */
- pic_irq = piix4_dev->config[0x60 + irq_num];
+ pic_irq = piix4_dev->config[PIIX_PIRQCA + irq_num];
if (pic_irq < 16) {
/* The pic level is the logical OR of all the PCI irqs mapped to it. */
pic_level = 0;
for (i = 0; i < 4; i++) {
- if (pic_irq == piix4_dev->config[0x60 + i]) {
+ if (pic_irq == piix4_dev->config[PIIX_PIRQCA + i]) {
pic_level |= pci_irq_levels[i];
}
}
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index c1c8810e71..92e9ca5bfa 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -26,9 +26,8 @@
#include "qemu/units.h"
#include "qemu-common.h"
#include "cpu.h"
-#include "hw/i386/pc.h"
+#include "hw/southbridge/piix.h"
#include "hw/isa/superio.h"
-#include "hw/dma/i8257.h"
#include "hw/char/serial.h"
#include "net/net.h"
#include "hw/boards.h"
@@ -45,8 +44,6 @@
#include "hw/irq.h"
#include "hw/loader.h"
#include "elf.h"
-#include "hw/rtc/mc146818rtc.h"
-#include "hw/timer/i8254.h"
#include "exec/address-spaces.h"
#include "hw/sysbus.h" /* SysBusDevice */
#include "qemu/host-utils.h"
@@ -97,11 +94,9 @@ typedef struct {
SysBusDevice parent_obj;
MIPSCPSState cps;
- qemu_irq *i8259;
+ qemu_irq i8259[ISA_NUM_IRQS];
} MaltaState;
-static ISADevice *pit;
-
static struct _loaderparams {
int ram_size, ram_low_size;
const char *kernel_filename;
@@ -1235,12 +1230,9 @@ void mips_malta_init(MachineState *machine)
int64_t kernel_entry, bootloader_run_addr;
PCIBus *pci_bus;
ISABus *isa_bus;
- qemu_irq *isa_irq;
qemu_irq cbus_irq, i8259_irq;
- int piix4_devfn;
I2CBus *smbus;
DriveInfo *dinfo;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
int fl_idx = 0;
int be;
@@ -1407,37 +1399,17 @@ void mips_malta_init(MachineState *machine)
/* Board ID = 0x420 (Malta Board with CoreLV) */
stl_p(memory_region_get_ram_ptr(bios_copy) + 0x10, 0x00000420);
- /*
- * We have a circular dependency problem: pci_bus depends on isa_irq,
- * isa_irq is provided by i8259, i8259 depends on ISA, ISA depends
- * on piix4, and piix4 depends on pci_bus. To stop the cycle we have
- * qemu_irq_proxy() adds an extra bit of indirection, allowing us
- * to resolve the isa_irq -> i8259 dependency after i8259 is initialized.
- */
- isa_irq = qemu_irq_proxy(&s->i8259, 16);
-
/* Northbridge */
- pci_bus = gt64120_register(isa_irq);
+ pci_bus = gt64120_register(s->i8259);
/* Southbridge */
- ide_drive_get(hd, ARRAY_SIZE(hd));
+ dev = piix4_create(pci_bus, &isa_bus, &smbus, MAX_IDE_BUS);
- piix4_devfn = piix4_init(pci_bus, &isa_bus, 80);
-
- /*
- * Interrupt controller
- * The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2
- */
- s->i8259 = i8259_init(isa_bus, i8259_irq);
-
- isa_bus_irqs(isa_bus, s->i8259);
- pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
- pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci");
- smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
- isa_get_irq(NULL, 9), NULL, 0, NULL);
- pit = i8254_pit_init(isa_bus, 0x40, 0, NULL);
- i8257_dma_init(isa_bus, 0);
- mc146818_rtc_init(isa_bus, 2000, NULL);
+ /* Interrupt controller */
+ qdev_connect_gpio_out_named(dev, "intr", 0, i8259_irq);
+ for (int i = 0; i < ISA_NUM_IRQS; i++) {
+ s->i8259[i] = qdev_get_gpio_in_named(dev, "isa", i);
+ }
/* generate SPD EEPROM data */
generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size);
diff --git a/hw/misc/grlib_ahb_apb_pnp.c b/hw/misc/grlib_ahb_apb_pnp.c
index 7338461694..e230e25363 100644
--- a/hw/misc/grlib_ahb_apb_pnp.c
+++ b/hw/misc/grlib_ahb_apb_pnp.c
@@ -22,6 +22,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "hw/sysbus.h"
#include "hw/misc/grlib_ahb_apb_pnp.h"
@@ -231,9 +232,20 @@ static uint64_t grlib_apb_pnp_read(void *opaque, hwaddr offset, unsigned size)
return apb_pnp->regs[offset >> 2];
}
+static void grlib_apb_pnp_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__);
+}
+
static const MemoryRegionOps grlib_apb_pnp_ops = {
.read = grlib_apb_pnp_read,
+ .write = grlib_apb_pnp_write,
.endianness = DEVICE_BIG_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
};
static void grlib_apb_pnp_realize(DeviceState *dev, Error **errp)
diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
index 693e244ce6..3d991af163 100644
--- a/hw/net/dp8393x.c
+++ b/hw/net/dp8393x.c
@@ -171,6 +171,7 @@ typedef struct dp8393xState {
/* Temporaries */
uint8_t tx_buffer[0x10000];
+ uint16_t data[12];
int loopback_packet;
/* Memory access */
@@ -224,26 +225,25 @@ static uint32_t dp8393x_wt(dp8393xState *s)
return s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
}
-static uint16_t dp8393x_get(dp8393xState *s, int width, uint16_t *base,
- int offset)
+static uint16_t dp8393x_get(dp8393xState *s, int width, int offset)
{
uint16_t val;
if (s->big_endian) {
- val = be16_to_cpu(base[offset * width + width - 1]);
+ val = be16_to_cpu(s->data[offset * width + width - 1]);
} else {
- val = le16_to_cpu(base[offset * width]);
+ val = le16_to_cpu(s->data[offset * width]);
}
return val;
}
-static void dp8393x_put(dp8393xState *s, int width, uint16_t *base, int offset,
+static void dp8393x_put(dp8393xState *s, int width, int offset,
uint16_t val)
{
if (s->big_endian) {
- base[offset * width + width - 1] = cpu_to_be16(val);
+ s->data[offset * width + width - 1] = cpu_to_be16(val);
} else {
- base[offset * width] = cpu_to_le16(val);
+ s->data[offset * width] = cpu_to_le16(val);
}
}
@@ -267,7 +267,6 @@ static void dp8393x_update_irq(dp8393xState *s)
static void dp8393x_do_load_cam(dp8393xState *s)
{
- uint16_t data[8];
int width, size;
uint16_t index = 0;
@@ -277,13 +276,13 @@ static void dp8393x_do_load_cam(dp8393xState *s)
while (s->regs[SONIC_CDC] & 0x1f) {
/* Fill current entry */
address_space_rw(&s->as, dp8393x_cdp(s),
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
- s->cam[index][0] = dp8393x_get(s, width, data, 1) & 0xff;
- s->cam[index][1] = dp8393x_get(s, width, data, 1) >> 8;
- s->cam[index][2] = dp8393x_get(s, width, data, 2) & 0xff;
- s->cam[index][3] = dp8393x_get(s, width, data, 2) >> 8;
- s->cam[index][4] = dp8393x_get(s, width, data, 3) & 0xff;
- s->cam[index][5] = dp8393x_get(s, width, data, 3) >> 8;
+ MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0);
+ s->cam[index][0] = dp8393x_get(s, width, 1) & 0xff;
+ s->cam[index][1] = dp8393x_get(s, width, 1) >> 8;
+ s->cam[index][2] = dp8393x_get(s, width, 2) & 0xff;
+ s->cam[index][3] = dp8393x_get(s, width, 2) >> 8;
+ s->cam[index][4] = dp8393x_get(s, width, 3) & 0xff;
+ s->cam[index][5] = dp8393x_get(s, width, 3) >> 8;
DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index,
s->cam[index][0], s->cam[index][1], s->cam[index][2],
s->cam[index][3], s->cam[index][4], s->cam[index][5]);
@@ -295,8 +294,8 @@ static void dp8393x_do_load_cam(dp8393xState *s)
/* Read CAM enable */
address_space_rw(&s->as, dp8393x_cdp(s),
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
- s->regs[SONIC_CE] = dp8393x_get(s, width, data, 0);
+ MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0);
+ s->regs[SONIC_CE] = dp8393x_get(s, width, 0);
DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
/* Done */
@@ -307,20 +306,19 @@ static void dp8393x_do_load_cam(dp8393xState *s)
static void dp8393x_do_read_rra(dp8393xState *s)
{
- uint16_t data[8];
int width, size;
/* Read memory */
width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
size = sizeof(uint16_t) * 4 * width;
address_space_rw(&s->as, dp8393x_rrp(s),
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
+ MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0);
/* Update SONIC registers */
- s->regs[SONIC_CRBA0] = dp8393x_get(s, width, data, 0);
- s->regs[SONIC_CRBA1] = dp8393x_get(s, width, data, 1);
- s->regs[SONIC_RBWC0] = dp8393x_get(s, width, data, 2);
- s->regs[SONIC_RBWC1] = dp8393x_get(s, width, data, 3);
+ s->regs[SONIC_CRBA0] = dp8393x_get(s, width, 0);
+ s->regs[SONIC_CRBA1] = dp8393x_get(s, width, 1);
+ s->regs[SONIC_RBWC0] = dp8393x_get(s, width, 2);
+ s->regs[SONIC_RBWC1] = dp8393x_get(s, width, 3);
DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n",
s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1],
s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]);
@@ -417,7 +415,6 @@ static void dp8393x_do_receiver_disable(dp8393xState *s)
static void dp8393x_do_transmit_packets(dp8393xState *s)
{
NetClientState *nc = qemu_get_queue(s->nic);
- uint16_t data[12];
int width, size;
int tx_len, len;
uint16_t i;
@@ -429,18 +426,17 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
size = sizeof(uint16_t) * 6 * width;
s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
DPRINTF("Transmit packet at %08x\n", dp8393x_ttda(s));
- address_space_rw(&s->as,
- dp8393x_ttda(s) + sizeof(uint16_t) * width,
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
+ address_space_rw(&s->as, dp8393x_ttda(s) + sizeof(uint16_t) * width,
+ MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0);
tx_len = 0;
/* Update registers */
- s->regs[SONIC_TCR] = dp8393x_get(s, width, data, 0) & 0xf000;
- s->regs[SONIC_TPS] = dp8393x_get(s, width, data, 1);
- s->regs[SONIC_TFC] = dp8393x_get(s, width, data, 2);
- s->regs[SONIC_TSA0] = dp8393x_get(s, width, data, 3);
- s->regs[SONIC_TSA1] = dp8393x_get(s, width, data, 4);
- s->regs[SONIC_TFS] = dp8393x_get(s, width, data, 5);
+ s->regs[SONIC_TCR] = dp8393x_get(s, width, 0) & 0xf000;
+ s->regs[SONIC_TPS] = dp8393x_get(s, width, 1);
+ s->regs[SONIC_TFC] = dp8393x_get(s, width, 2);
+ s->regs[SONIC_TSA0] = dp8393x_get(s, width, 3);
+ s->regs[SONIC_TSA1] = dp8393x_get(s, width, 4);
+ s->regs[SONIC_TFS] = dp8393x_get(s, width, 5);
/* Handle programmable interrupt */
if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) {
@@ -465,10 +461,10 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
size = sizeof(uint16_t) * 3 * width;
address_space_rw(&s->as,
dp8393x_ttda(s) + sizeof(uint16_t) * (4 + 3 * i) * width,
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
- s->regs[SONIC_TSA0] = dp8393x_get(s, width, data, 0);
- s->regs[SONIC_TSA1] = dp8393x_get(s, width, data, 1);
- s->regs[SONIC_TFS] = dp8393x_get(s, width, data, 2);
+ MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0);
+ s->regs[SONIC_TSA0] = dp8393x_get(s, width, 0);
+ s->regs[SONIC_TSA1] = dp8393x_get(s, width, 1);
+ s->regs[SONIC_TFS] = dp8393x_get(s, width, 2);
}
}
@@ -495,12 +491,12 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
s->regs[SONIC_TCR] |= SONIC_TCR_PTX;
/* Write status */
- dp8393x_put(s, width, data, 0,
+ dp8393x_put(s, width, 0,
s->regs[SONIC_TCR] & 0x0fff); /* status */
size = sizeof(uint16_t) * width;
address_space_rw(&s->as,
dp8393x_ttda(s),
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
+ MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 1);
if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
/* Read footer of packet */
@@ -509,9 +505,9 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
dp8393x_ttda(s) +
sizeof(uint16_t) *
(4 + 3 * s->regs[SONIC_TFC]) * width,
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
- s->regs[SONIC_CTDA] = dp8393x_get(s, width, data, 0) & ~0x1;
- if (dp8393x_get(s, width, data, 0) & 0x1) {
+ MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0);
+ s->regs[SONIC_CTDA] = dp8393x_get(s, width, 0) & ~0x1;
+ if (dp8393x_get(s, width, 0) & 0x1) {
/* EOL detected */
break;
}
@@ -748,7 +744,6 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
size_t size)
{
dp8393xState *s = qemu_get_nic_opaque(nc);
- uint16_t data[10];
int packet_type;
uint32_t available, address;
int width, rx_len = size;
@@ -773,8 +768,8 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
size = sizeof(uint16_t) * 1 * width;
address = dp8393x_crda(s) + sizeof(uint16_t) * 5 * width;
address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED,
- (uint8_t *)data, size, 0);
- if (dp8393x_get(s, width, data, 0) & 0x1) {
+ (uint8_t *)s->data, size, 0);
+ if (dp8393x_get(s, width, 0) & 0x1) {
/* Still EOL ; stop reception */
return -1;
} else {
@@ -818,27 +813,33 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
/* Write status to memory */
DPRINTF("Write status at %08x\n", dp8393x_crda(s));
- dp8393x_put(s, width, data, 0, s->regs[SONIC_RCR]); /* status */
- dp8393x_put(s, width, data, 1, rx_len); /* byte count */
- dp8393x_put(s, width, data, 2, s->regs[SONIC_TRBA0]); /* pkt_ptr0 */
- dp8393x_put(s, width, data, 3, s->regs[SONIC_TRBA1]); /* pkt_ptr1 */
- dp8393x_put(s, width, data, 4, s->regs[SONIC_RSC]); /* seq_no */
+ dp8393x_put(s, width, 0, s->regs[SONIC_RCR]); /* status */
+ dp8393x_put(s, width, 1, rx_len); /* byte count */
+ dp8393x_put(s, width, 2, s->regs[SONIC_TRBA0]); /* pkt_ptr0 */
+ dp8393x_put(s, width, 3, s->regs[SONIC_TRBA1]); /* pkt_ptr1 */
+ dp8393x_put(s, width, 4, s->regs[SONIC_RSC]); /* seq_no */
size = sizeof(uint16_t) * 5 * width;
address_space_rw(&s->as, dp8393x_crda(s),
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
+ MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 1);
/* Move to next descriptor */
size = sizeof(uint16_t) * width;
address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 5 * width,
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
- s->regs[SONIC_LLFA] = dp8393x_get(s, width, data, 0);
+ MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0);
+ s->regs[SONIC_LLFA] = dp8393x_get(s, width, 0);
if (s->regs[SONIC_LLFA] & 0x1) {
/* EOL detected */
s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
} else {
- dp8393x_put(s, width, data, 0, 0); /* in_use */
- address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 6 * width,
- MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1);
+ /* Clear in_use, but it is always 16bit wide */
+ int offset = dp8393x_crda(s) + sizeof(uint16_t) * 6 * width;
+ if (s->big_endian && width == 2) {
+ /* we need to adjust the offset of the 16bit field */
+ offset += sizeof(uint16_t);
+ }
+ s->data[0] = 0;
+ address_space_rw(&s->as, offset, MEMTXATTRS_UNSPECIFIED,
+ (uint8_t *)s->data, sizeof(uint16_t), 1);
s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 44a3c19326..5d879c471e 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -237,7 +237,7 @@ static void fw_cfg_bootsplash(FWCfgState *s)
static void fw_cfg_reboot(FWCfgState *s)
{
const char *reboot_timeout = NULL;
- int64_t rt_val = -1;
+ uint64_t rt_val = -1;
uint32_t rt_le32;
/* get user configuration */
@@ -247,10 +247,11 @@ static void fw_cfg_reboot(FWCfgState *s)
if (reboot_timeout) {
rt_val = qemu_opt_get_number(opts, "reboot-timeout", -1);
+
/* validate the input */
- if (rt_val < 0 || rt_val > 0xffff) {
+ if (rt_val > 0xffff && rt_val != (uint64_t)-1) {
error_report("reboot timeout is invalid,"
- "it should be a value between 0 and 65535");
+ "it should be a value between -1 and 65535");
exit(1);
}
}
diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
index 1edc1a31d4..b0aa8351c4 100644
--- a/hw/pci-host/Kconfig
+++ b/hw/pci-host/Kconfig
@@ -28,11 +28,10 @@ config PCI_SABRE
select PCI
bool
-config PCI_PIIX
+config PCI_I440FX
bool
select PCI
select PAM
- select ISA_BUS
config PCI_EXPRESS_Q35
bool
diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs
index a9cd3e022d..efd752b766 100644
--- a/hw/pci-host/Makefile.objs
+++ b/hw/pci-host/Makefile.objs
@@ -13,7 +13,7 @@ common-obj-$(CONFIG_VERSATILE_PCI) += versatile.o
common-obj-$(CONFIG_PCI_SABRE) += sabre.o
common-obj-$(CONFIG_FULONG) += bonito.o
-common-obj-$(CONFIG_PCI_PIIX) += piix.o
+common-obj-$(CONFIG_PCI_I440FX) += i440fx.o
common-obj-$(CONFIG_PCI_EXPRESS_Q35) += q35.o
common-obj-$(CONFIG_PCI_EXPRESS_GENERIC_BRIDGE) += gpex.o
common-obj-$(CONFIG_PCI_EXPRESS_XILINX) += xilinx-pcie.o
diff --git a/hw/pci-host/piix.c b/hw/pci-host/i440fx.c
index 135c645535..f27131102d 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/i440fx.c
@@ -24,21 +24,14 @@
#include "qemu/osdep.h"
#include "hw/i386/pc.h"
-#include "hw/irq.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_host.h"
+#include "hw/pci-host/i440fx.h"
#include "hw/qdev-properties.h"
-#include "hw/isa/isa.h"
#include "hw/sysbus.h"
#include "qapi/error.h"
-#include "qemu/range.h"
-#include "hw/xen/xen.h"
-#include "migration/qemu-file-types.h"
#include "migration/vmstate.h"
#include "hw/pci-host/pam.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "hw/i386/ioapic.h"
#include "qapi/visitor.h"
#include "qemu/error-report.h"
@@ -58,50 +51,9 @@ typedef struct I440FXState {
uint32_t short_root_bus;
} I440FXState;
-#define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */
-#define PIIX_NUM_PIRQS 4ULL /* PIRQ[A-D] */
-#define XEN_PIIX_NUM_PIRQS 128ULL
-#define PIIX_PIRQC 0x60
-
-typedef struct PIIX3State {
- PCIDevice dev;
-
- /*
- * bitmap to track pic levels.
- * The pic level is the logical OR of all the PCI irqs mapped to it
- * So one PIC level is tracked by PIIX_NUM_PIRQS bits.
- *
- * PIRQ is mapped to PIC pins, we track it by
- * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with
- * pic_irq * PIIX_NUM_PIRQS + pirq
- */
-#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64
-#error "unable to encode pic state in 64bit in pic_levels."
-#endif
- uint64_t pic_levels;
-
- qemu_irq *pic;
-
- /* This member isn't used. Just for save/load compatibility */
- int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
-
- /* Reset Control Register contents */
- uint8_t rcr;
-
- /* IO memory region for Reset Control Register (RCR_IOPORT) */
- MemoryRegion rcr_mem;
-} PIIX3State;
-
-#define TYPE_PIIX3_PCI_DEVICE "pci-piix3"
-#define PIIX3_PCI_DEVICE(obj) \
- OBJECT_CHECK(PIIX3State, (obj), TYPE_PIIX3_PCI_DEVICE)
-
#define I440FX_PCI_DEVICE(obj) \
OBJECT_CHECK(PCII440FXState, (obj), TYPE_I440FX_PCI_DEVICE)
-#define TYPE_PIIX3_DEVICE "PIIX3"
-#define TYPE_PIIX3_XEN_DEVICE "PIIX3-xen"
-
struct PCII440FXState {
/*< private >*/
PCIDevice parent_obj;
@@ -128,21 +80,6 @@ struct PCII440FXState {
*/
#define I440FX_COREBOOT_RAM_SIZE 0x57
-static void piix3_set_irq(void *opaque, int pirq, int level);
-static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pci_intx);
-static void piix3_write_config_xen(PCIDevice *dev,
- uint32_t address, uint32_t val, int len);
-
-/* return the global irq number corresponding to a given device irq
- pin. We could also use the bus number to have a more precise
- mapping. */
-static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
-{
- int slot_addend;
- slot_addend = (pci_dev->devfn >> 3) - 1;
- return (pci_intx + slot_addend) & 3;
-}
-
static void i440fx_update_memory_mappings(PCII440FXState *d)
{
int i;
@@ -174,28 +111,6 @@ static void i440fx_write_config(PCIDevice *dev,
}
}
-static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id)
-{
- PCII440FXState *d = opaque;
- PCIDevice *pd = PCI_DEVICE(d);
- int ret, i;
- uint8_t smm_enabled;
-
- ret = pci_device_load(pd, f);
- if (ret < 0)
- return ret;
- i440fx_update_memory_mappings(d);
- qemu_get_8s(f, &smm_enabled);
-
- if (version_id == 2) {
- for (i = 0; i < PIIX_NUM_PIRQS; i++) {
- qemu_get_be32(f); /* dummy load for compatibility */
- }
- }
-
- return 0;
-}
-
static int i440fx_post_load(void *opaque, int version_id)
{
PCII440FXState *d = opaque;
@@ -208,8 +123,6 @@ static const VMStateDescription vmstate_i440fx = {
.name = "I440FX",
.version_id = 3,
.minimum_version_id = 3,
- .minimum_version_id_old = 1,
- .load_state_old = i440fx_load_old,
.post_load = i440fx_post_load,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(parent_obj, PCII440FXState),
@@ -358,8 +271,6 @@ static void i440fx_realize(PCIDevice *dev, Error **errp)
PCIBus *i440fx_init(const char *host_type, const char *pci_type,
PCII440FXState **pi440fx_state,
- int *piix3_devfn,
- ISABus **isa_bus, qemu_irq *pic,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
ram_addr_t ram_size,
@@ -372,7 +283,6 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type,
PCIBus *b;
PCIDevice *d;
PCIHostState *s;
- PIIX3State *piix3;
PCII440FXState *f;
unsigned i;
I440FXState *i440fx;
@@ -425,29 +335,6 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type,
PAM_EXPAN_SIZE);
}
- /* Xen supports additional interrupt routes from the PCI devices to
- * the IOAPIC: the four pins of each PCI device on the bus are also
- * connected to the IOAPIC directly.
- * These additional routes can be discovered through ACPI. */
- if (xen_enabled()) {
- PCIDevice *pci_dev = pci_create_simple_multifunction(b,
- -1, true, TYPE_PIIX3_XEN_DEVICE);
- piix3 = PIIX3_PCI_DEVICE(pci_dev);
- pci_bus_irqs(b, xen_piix3_set_irq, xen_pci_slot_get_pirq,
- piix3, XEN_PIIX_NUM_PIRQS);
- } else {
- PCIDevice *pci_dev = pci_create_simple_multifunction(b,
- -1, true, TYPE_PIIX3_DEVICE);
- piix3 = PIIX3_PCI_DEVICE(pci_dev);
- pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
- PIIX_NUM_PIRQS);
- pci_bus_set_route_irq_fn(b, piix3_route_intx_pin_to_irq);
- }
- piix3->pic = pic;
- *isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0"));
-
- *piix3_devfn = piix3->dev.devfn;
-
ram_size = ram_size / 8 / 1024 / 1024;
if (ram_size > 255) {
ram_size = 255;
@@ -467,312 +354,6 @@ PCIBus *find_i440fx(void)
return s ? s->bus : NULL;
}
-/* PIIX3 PCI to ISA bridge */
-static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
-{
- qemu_set_irq(piix3->pic[pic_irq],
- !!(piix3->pic_levels &
- (((1ULL << PIIX_NUM_PIRQS) - 1) <<
- (pic_irq * PIIX_NUM_PIRQS))));
-}
-
-static void piix3_set_irq_level_internal(PIIX3State *piix3, int pirq, int level)
-{
- int pic_irq;
- uint64_t mask;
-
- pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
- if (pic_irq >= PIIX_NUM_PIC_IRQS) {
- return;
- }
-
- mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
- piix3->pic_levels &= ~mask;
- piix3->pic_levels |= mask * !!level;
-}
-
-static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
-{
- int pic_irq;
-
- pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
- if (pic_irq >= PIIX_NUM_PIC_IRQS) {
- return;
- }
-
- piix3_set_irq_level_internal(piix3, pirq, level);
-
- piix3_set_irq_pic(piix3, pic_irq);
-}
-
-static void piix3_set_irq(void *opaque, int pirq, int level)
-{
- PIIX3State *piix3 = opaque;
- piix3_set_irq_level(piix3, pirq, level);
-}
-
-static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin)
-{
- PIIX3State *piix3 = opaque;
- int irq = piix3->dev.config[PIIX_PIRQC + pin];
- PCIINTxRoute route;
-
- if (irq < PIIX_NUM_PIC_IRQS) {
- route.mode = PCI_INTX_ENABLED;
- route.irq = irq;
- } else {
- route.mode = PCI_INTX_DISABLED;
- route.irq = -1;
- }
- return route;
-}
-
-/* irq routing is changed. so rebuild bitmap */
-static void piix3_update_irq_levels(PIIX3State *piix3)
-{
- PCIBus *bus = pci_get_bus(&piix3->dev);
- int pirq;
-
- piix3->pic_levels = 0;
- for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
- piix3_set_irq_level(piix3, pirq, pci_bus_get_irq_level(bus, pirq));
- }
-}
-
-static void piix3_write_config(PCIDevice *dev,
- uint32_t address, uint32_t val, int len)
-{
- pci_default_write_config(dev, address, val, len);
- if (ranges_overlap(address, len, PIIX_PIRQC, 4)) {
- PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev);
- int pic_irq;
-
- pci_bus_fire_intx_routing_notifier(pci_get_bus(&piix3->dev));
- piix3_update_irq_levels(piix3);
- for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) {
- piix3_set_irq_pic(piix3, pic_irq);
- }
- }
-}
-
-static void piix3_write_config_xen(PCIDevice *dev,
- uint32_t address, uint32_t val, int len)
-{
- xen_piix_pci_write_config_client(address, val, len);
- piix3_write_config(dev, address, val, len);
-}
-
-static void piix3_reset(void *opaque)
-{
- PIIX3State *d = opaque;
- uint8_t *pci_conf = d->dev.config;
-
- pci_conf[0x04] = 0x07; /* master, memory and I/O */
- pci_conf[0x05] = 0x00;
- pci_conf[0x06] = 0x00;
- pci_conf[0x07] = 0x02; /* PCI_status_devsel_medium */
- pci_conf[0x4c] = 0x4d;
- pci_conf[0x4e] = 0x03;
- pci_conf[0x4f] = 0x00;
- pci_conf[0x60] = 0x80;
- pci_conf[0x61] = 0x80;
- pci_conf[0x62] = 0x80;
- pci_conf[0x63] = 0x80;
- pci_conf[0x69] = 0x02;
- pci_conf[0x70] = 0x80;
- pci_conf[0x76] = 0x0c;
- pci_conf[0x77] = 0x0c;
- pci_conf[0x78] = 0x02;
- pci_conf[0x79] = 0x00;
- pci_conf[0x80] = 0x00;
- pci_conf[0x82] = 0x00;
- pci_conf[0xa0] = 0x08;
- pci_conf[0xa2] = 0x00;
- pci_conf[0xa3] = 0x00;
- pci_conf[0xa4] = 0x00;
- pci_conf[0xa5] = 0x00;
- pci_conf[0xa6] = 0x00;
- pci_conf[0xa7] = 0x00;
- pci_conf[0xa8] = 0x0f;
- pci_conf[0xaa] = 0x00;
- pci_conf[0xab] = 0x00;
- pci_conf[0xac] = 0x00;
- pci_conf[0xae] = 0x00;
-
- d->pic_levels = 0;
- d->rcr = 0;
-}
-
-static int piix3_post_load(void *opaque, int version_id)
-{
- PIIX3State *piix3 = opaque;
- int pirq;
-
- /* Because the i8259 has not been deserialized yet, qemu_irq_raise
- * might bring the system to a different state than the saved one;
- * for example, the interrupt could be masked but the i8259 would
- * not know that yet and would trigger an interrupt in the CPU.
- *
- * Here, we update irq levels without raising the interrupt.
- * Interrupt state will be deserialized separately through the i8259.
- */
- piix3->pic_levels = 0;
- for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
- piix3_set_irq_level_internal(piix3, pirq,
- pci_bus_get_irq_level(pci_get_bus(&piix3->dev), pirq));
- }
- return 0;
-}
-
-static int piix3_pre_save(void *opaque)
-{
- int i;
- PIIX3State *piix3 = opaque;
-
- for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) {
- piix3->pci_irq_levels_vmstate[i] =
- pci_bus_get_irq_level(pci_get_bus(&piix3->dev), i);
- }
-
- return 0;
-}
-
-static bool piix3_rcr_needed(void *opaque)
-{
- PIIX3State *piix3 = opaque;
-
- return (piix3->rcr != 0);
-}
-
-static const VMStateDescription vmstate_piix3_rcr = {
- .name = "PIIX3/rcr",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = piix3_rcr_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(rcr, PIIX3State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_piix3 = {
- .name = "PIIX3",
- .version_id = 3,
- .minimum_version_id = 2,
- .post_load = piix3_post_load,
- .pre_save = piix3_pre_save,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, PIIX3State),
- VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State,
- PIIX_NUM_PIRQS, 3),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_piix3_rcr,
- NULL
- }
-};
-
-
-static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len)
-{
- PIIX3State *d = opaque;
-
- if (val & 4) {
- qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
- return;
- }
- d->rcr = val & 2; /* keep System Reset type only */
-}
-
-static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len)
-{
- PIIX3State *d = opaque;
-
- return d->rcr;
-}
-
-static const MemoryRegionOps rcr_ops = {
- .read = rcr_read,
- .write = rcr_write,
- .endianness = DEVICE_LITTLE_ENDIAN
-};
-
-static void piix3_realize(PCIDevice *dev, Error **errp)
-{
- PIIX3State *d = PIIX3_PCI_DEVICE(dev);
-
- if (!isa_bus_new(DEVICE(d), get_system_memory(),
- pci_address_space_io(dev), errp)) {
- return;
- }
-
- memory_region_init_io(&d->rcr_mem, OBJECT(dev), &rcr_ops, d,
- "piix3-reset-control", 1);
- memory_region_add_subregion_overlap(pci_address_space_io(dev), RCR_IOPORT,
- &d->rcr_mem, 1);
-
- qemu_register_reset(piix3_reset, d);
-}
-
-static void pci_piix3_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- dc->desc = "ISA bridge";
- dc->vmsd = &vmstate_piix3;
- dc->hotpluggable = false;
- k->realize = piix3_realize;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
- k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0;
- k->class_id = PCI_CLASS_BRIDGE_ISA;
- /*
- * Reason: part of PIIX3 southbridge, needs to be wired up by
- * pc_piix.c's pc_init1()
- */
- dc->user_creatable = false;
-}
-
-static const TypeInfo piix3_pci_type_info = {
- .name = TYPE_PIIX3_PCI_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PIIX3State),
- .abstract = true,
- .class_init = pci_piix3_class_init,
- .interfaces = (InterfaceInfo[]) {
- { INTERFACE_CONVENTIONAL_PCI_DEVICE },
- { },
- },
-};
-
-static void piix3_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->config_write = piix3_write_config;
-}
-
-static const TypeInfo piix3_info = {
- .name = TYPE_PIIX3_DEVICE,
- .parent = TYPE_PIIX3_PCI_DEVICE,
- .class_init = piix3_class_init,
-};
-
-static void piix3_xen_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->config_write = piix3_write_config_xen;
-};
-
-static const TypeInfo piix3_xen_info = {
- .name = TYPE_PIIX3_XEN_DEVICE,
- .parent = TYPE_PIIX3_PCI_DEVICE,
- .class_init = piix3_xen_class_init,
-};
-
static void i440fx_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -934,9 +515,6 @@ static void i440fx_register_types(void)
{
type_register_static(&i440fx_info);
type_register_static(&igd_passthrough_i440fx_info);
- type_register_static(&piix3_pci_type_info);
- type_register_static(&piix3_info);
- type_register_static(&piix3_xen_info);
type_register_static(&i440fx_pcihost_info);
}
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index c68498c0de..cbc7a32568 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -2646,12 +2646,49 @@ AddressSpace *pci_device_iommu_address_space(PCIDevice *dev)
{
PCIBus *bus = pci_get_bus(dev);
PCIBus *iommu_bus = bus;
+ uint8_t devfn = dev->devfn;
- while(iommu_bus && !iommu_bus->iommu_fn && iommu_bus->parent_dev) {
- iommu_bus = pci_get_bus(iommu_bus->parent_dev);
+ while (iommu_bus && !iommu_bus->iommu_fn && iommu_bus->parent_dev) {
+ PCIBus *parent_bus = pci_get_bus(iommu_bus->parent_dev);
+
+ /*
+ * The requester ID of the provided device may be aliased, as seen from
+ * the IOMMU, due to topology limitations. The IOMMU relies on a
+ * requester ID to provide a unique AddressSpace for devices, but
+ * conventional PCI buses pre-date such concepts. Instead, the PCIe-
+ * to-PCI bridge creates and accepts transactions on behalf of down-
+ * stream devices. When doing so, all downstream devices are masked
+ * (aliased) behind a single requester ID. The requester ID used
+ * depends on the format of the bridge devices. Proper PCIe-to-PCI
+ * bridges, with a PCIe capability indicating such, follow the
+ * guidelines of chapter 2.3 of the PCIe-to-PCI/X bridge specification,
+ * where the bridge uses the seconary bus as the bridge portion of the
+ * requester ID and devfn of 00.0. For other bridges, typically those
+ * found on the root complex such as the dmi-to-pci-bridge, we follow
+ * the convention of typical bare-metal hardware, which uses the
+ * requester ID of the bridge itself. There are device specific
+ * exceptions to these rules, but these are the defaults that the
+ * Linux kernel uses when determining DMA aliases itself and believed
+ * to be true for the bare metal equivalents of the devices emulated
+ * in QEMU.
+ */
+ if (!pci_bus_is_express(iommu_bus)) {
+ PCIDevice *parent = iommu_bus->parent_dev;
+
+ if (pci_is_express(parent) &&
+ pcie_cap_get_type(parent) == PCI_EXP_TYPE_PCI_BRIDGE) {
+ devfn = PCI_DEVFN(0, 0);
+ bus = iommu_bus;
+ } else {
+ devfn = parent->devfn;
+ bus = parent_bus;
+ }
+ }
+
+ iommu_bus = parent_bus;
}
if (iommu_bus && iommu_bus->iommu_fn) {
- return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, dev->devfn);
+ return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, devfn);
}
return &address_space_memory;
}
diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c
index c39051068d..c346407cd3 100644
--- a/hw/rdma/rdma_backend.c
+++ b/hw/rdma/rdma_backend.c
@@ -391,7 +391,11 @@ static int build_host_sge_array(RdmaDeviceResources *rdma_dev_res,
return VENDOR_ERR_INVLKEY | ssge[ssge_idx].lkey;
}
+#ifdef LEGACY_RDMA_REG_MR
dsge->addr = (uintptr_t)mr->virt + ssge[ssge_idx].addr - mr->start;
+#else
+ dsge->addr = ssge[ssge_idx].addr;
+#endif
dsge->length = ssge[ssge_idx].length;
dsge->lkey = rdma_backend_mr_lkey(&mr->backend_mr);
@@ -735,10 +739,19 @@ void rdma_backend_destroy_pd(RdmaBackendPD *pd)
}
}
+#ifdef LEGACY_RDMA_REG_MR
int rdma_backend_create_mr(RdmaBackendMR *mr, RdmaBackendPD *pd, void *addr,
size_t length, int access)
+#else
+int rdma_backend_create_mr(RdmaBackendMR *mr, RdmaBackendPD *pd, void *addr,
+ size_t length, uint64_t guest_start, int access)
+#endif
{
+#ifdef LEGACY_RDMA_REG_MR
mr->ibmr = ibv_reg_mr(pd->ibpd, addr, length, access);
+#else
+ mr->ibmr = ibv_reg_mr_iova(pd->ibpd, addr, length, guest_start, access);
+#endif
if (!mr->ibmr) {
rdma_error_report("ibv_reg_mr fail, errno=%d", errno);
return -EIO;
diff --git a/hw/rdma/rdma_backend.h b/hw/rdma/rdma_backend.h
index 7c1a19a2b5..127f96e2d5 100644
--- a/hw/rdma/rdma_backend.h
+++ b/hw/rdma/rdma_backend.h
@@ -78,8 +78,13 @@ int rdma_backend_query_port(RdmaBackendDev *backend_dev,
int rdma_backend_create_pd(RdmaBackendDev *backend_dev, RdmaBackendPD *pd);
void rdma_backend_destroy_pd(RdmaBackendPD *pd);
+#ifdef LEGACY_RDMA_REG_MR
int rdma_backend_create_mr(RdmaBackendMR *mr, RdmaBackendPD *pd, void *addr,
size_t length, int access);
+#else
+int rdma_backend_create_mr(RdmaBackendMR *mr, RdmaBackendPD *pd, void *addr,
+ size_t length, uint64_t guest_start, int access);
+#endif
void rdma_backend_destroy_mr(RdmaBackendMR *mr);
int rdma_backend_create_cq(RdmaBackendDev *backend_dev, RdmaBackendCQ *cq,
diff --git a/hw/rdma/rdma_rm.c b/hw/rdma/rdma_rm.c
index 1927f85472..1524dfaeaa 100644
--- a/hw/rdma/rdma_rm.c
+++ b/hw/rdma/rdma_rm.c
@@ -227,8 +227,13 @@ int rdma_rm_alloc_mr(RdmaDeviceResources *dev_res, uint32_t pd_handle,
mr->length = guest_length;
mr->virt += (mr->start & (TARGET_PAGE_SIZE - 1));
+#ifdef LEGACY_RDMA_REG_MR
ret = rdma_backend_create_mr(&mr->backend_mr, &pd->backend_pd, mr->virt,
mr->length, access_flags);
+#else
+ ret = rdma_backend_create_mr(&mr->backend_mr, &pd->backend_pd, mr->virt,
+ mr->length, guest_start, access_flags);
+#endif
if (ret) {
ret = -EIO;
goto out_dealloc_mr;
diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c
index 3722d9e772..6f0fc405c7 100644
--- a/hw/rdma/vmw/pvrdma_main.c
+++ b/hw/rdma/vmw/pvrdma_main.c
@@ -664,6 +664,12 @@ static void pvrdma_realize(PCIDevice *pdev, Error **errp)
dev->shutdown_notifier.notify = pvrdma_shutdown_notifier;
qemu_register_shutdown_notifier(&dev->shutdown_notifier);
+#ifdef LEGACY_RDMA_REG_MR
+ rdma_info_report("Using legacy reg_mr");
+#else
+ rdma_info_report("Using iova reg_mr");
+#endif
+
out:
if (rc) {
pvrdma_fini(pdev);
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index cc8f311e6b..23f340df19 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -62,7 +62,7 @@ static const struct MemmapEntry {
[VIRT_PLIC] = { 0xc000000, 0x4000000 },
[VIRT_UART0] = { 0x10000000, 0x100 },
[VIRT_VIRTIO] = { 0x10001000, 0x1000 },
- [VIRT_FLASH] = { 0x20000000, 0x2000000 },
+ [VIRT_FLASH] = { 0x20000000, 0x4000000 },
[VIRT_DRAM] = { 0x80000000, 0x0 },
[VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 },
[VIRT_PCIE_PIO] = { 0x03000000, 0x00010000 },
diff --git a/hw/timer/i8254_common.c b/hw/timer/i8254_common.c
index 57bf10cc94..050875b497 100644
--- a/hw/timer/i8254_common.c
+++ b/hw/timer/i8254_common.c
@@ -29,7 +29,6 @@
#include "qemu/timer.h"
#include "hw/timer/i8254.h"
#include "hw/timer/i8254_internal.h"
-#include "migration/qemu-file-types.h"
#include "migration/vmstate.h"
/* val must be 0 or 1 */
@@ -202,43 +201,6 @@ static const VMStateDescription vmstate_pit_channel = {
}
};
-static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
-{
- PITCommonState *pit = opaque;
- PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
- PITChannelState *s;
- int i;
-
- if (version_id != 1) {
- return -EINVAL;
- }
-
- for (i = 0; i < 3; i++) {
- s = &pit->channels[i];
- s->count = qemu_get_be32(f);
- qemu_get_be16s(f, &s->latched_count);
- qemu_get_8s(f, &s->count_latched);
- qemu_get_8s(f, &s->status_latched);
- qemu_get_8s(f, &s->status);
- qemu_get_8s(f, &s->read_state);
- qemu_get_8s(f, &s->write_state);
- qemu_get_8s(f, &s->write_latch);
- qemu_get_8s(f, &s->rw_mode);
- qemu_get_8s(f, &s->mode);
- qemu_get_8s(f, &s->bcd);
- qemu_get_8s(f, &s->gate);
- s->count_load_time = qemu_get_be64(f);
- s->irq_disabled = 0;
- if (i == 0) {
- s->next_transition_time = qemu_get_be64(f);
- }
- }
- if (c->post_load) {
- c->post_load(pit);
- }
- return 0;
-}
-
static int pit_dispatch_pre_save(void *opaque)
{
PITCommonState *s = opaque;
@@ -266,8 +228,6 @@ static const VMStateDescription vmstate_pit_common = {
.name = "i8254",
.version_id = 3,
.minimum_version_id = 2,
- .minimum_version_id_old = 1,
- .load_state_old = pit_load_old,
.pre_save = pit_dispatch_pre_save,
.post_load = pit_dispatch_post_load,
.fields = (VMStateField[]) {
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index 472cc26fc4..fcf48c0193 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -86,7 +86,9 @@ struct USBHostDevice {
uint32_t options;
uint32_t loglevel;
bool needs_autoscan;
- bool allow_guest_reset;
+ bool allow_one_guest_reset;
+ bool allow_all_guest_resets;
+
/* state */
QTAILQ_ENTRY(USBHostDevice) next;
int seen, errcount;
@@ -1462,10 +1464,10 @@ static void usb_host_handle_reset(USBDevice *udev)
USBHostDevice *s = USB_HOST_DEVICE(udev);
int rc;
- if (!s->allow_guest_reset) {
+ if (!s->allow_one_guest_reset && !s->allow_all_guest_resets) {
return;
}
- if (udev->addr == 0) {
+ if (!s->allow_all_guest_resets && udev->addr == 0) {
return;
}
@@ -1586,7 +1588,10 @@ static Property usb_host_dev_properties[] = {
DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0),
DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames, 32),
- DEFINE_PROP_BOOL("guest-reset", USBHostDevice, allow_guest_reset, true),
+ DEFINE_PROP_BOOL("guest-reset", USBHostDevice,
+ allow_one_guest_reset, true),
+ DEFINE_PROP_BOOL("guest-resets-all", USBHostDevice,
+ allow_all_guest_resets, false),
DEFINE_PROP_UINT32("loglevel", USBHostDevice, loglevel,
LIBUSB_LOG_LEVEL_WARNING),
DEFINE_PROP_BIT("pipeline", USBHostDevice, options,
diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c
index b2c804292e..d6332d45c3 100644
--- a/hw/virtio/virtio-bus.c
+++ b/hw/virtio/virtio-bus.c
@@ -288,6 +288,10 @@ int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign)
k->ioeventfd_assign(proxy, notifier, n, false);
}
+ if (r == 0) {
+ virtio_queue_set_host_notifier_enabled(vq, assign);
+ }
+
return r;
}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 762df12f4c..04716b5f6c 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -128,6 +128,7 @@ struct VirtQueue
VirtIODevice *vdev;
EventNotifier guest_notifier;
EventNotifier host_notifier;
+ bool host_notifier_enabled;
QLIST_ENTRY(VirtQueue) node;
};
@@ -2271,7 +2272,7 @@ void virtio_queue_notify(VirtIODevice *vdev, int n)
}
trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
- if (vq->handle_aio_output) {
+ if (vq->host_notifier_enabled) {
event_notifier_set(&vq->host_notifier);
} else if (vq->handle_output) {
vq->handle_output(vdev, vq);
@@ -3145,6 +3146,7 @@ void virtio_init(VirtIODevice *vdev, const char *name,
vdev->vq[i].vector = VIRTIO_NO_VECTOR;
vdev->vq[i].vdev = vdev;
vdev->vq[i].queue_index = i;
+ vdev->vq[i].host_notifier_enabled = false;
}
vdev->name = name;
@@ -3436,6 +3438,11 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq)
return &vq->host_notifier;
}
+void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled)
+{
+ vq->host_notifier_enabled = enabled;
+}
+
int virtio_queue_set_host_notifier_mr(VirtIODevice *vdev, int n,
MemoryRegion *mr, bool assign)
{