aboutsummaryrefslogtreecommitdiff
path: root/hw/i386/pc_piix.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/i386/pc_piix.c')
-rw-r--r--hw/i386/pc_piix.c125
1 files changed, 93 insertions, 32 deletions
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index e36a326..334d9a0 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -43,7 +43,6 @@
#include "net/net.h"
#include "hw/ide/isa.h"
#include "hw/ide/pci.h"
-#include "hw/ide/piix.h"
#include "hw/irq.h"
#include "sysemu/kvm.h"
#include "hw/i386/kvm/clock.h"
@@ -51,8 +50,6 @@
#include "hw/i2c/smbus_eeprom.h"
#include "exec/memory.h"
#include "hw/acpi/acpi.h"
-#include "hw/acpi/piix4.h"
-#include "hw/usb/hcd-uhci.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "sysemu/xen.h"
@@ -117,7 +114,7 @@ static void pc_init1(MachineState *machine,
MemoryRegion *system_io = get_system_io();
PCIBus *pci_bus = NULL;
ISABus *isa_bus;
- int piix3_devfn = -1;
+ Object *piix4_pm = NULL;
qemu_irq smi_irq;
GSIState *gsi_state;
BusState *idebus[MAX_IDE_BUS];
@@ -261,10 +258,29 @@ static void pc_init1(MachineState *machine,
gsi_state = pc_gsi_create(&x86ms->gsi, pcmc->pci_enabled);
if (pcmc->pci_enabled) {
- PIIX3State *piix3;
PCIDevice *pci_dev;
-
- pci_dev = pci_create_simple_multifunction(pci_bus, -1, TYPE_PIIX3_DEVICE);
+ DeviceState *dev;
+ size_t i;
+
+ pci_dev = pci_new_multifunction(-1, pcms->south_bridge);
+ object_property_set_bool(OBJECT(pci_dev), "has-usb",
+ machine_usb(machine), &error_abort);
+ object_property_set_bool(OBJECT(pci_dev), "has-acpi",
+ x86_machine_is_acpi_enabled(x86ms),
+ &error_abort);
+ object_property_set_bool(OBJECT(pci_dev), "has-pic", false,
+ &error_abort);
+ object_property_set_bool(OBJECT(pci_dev), "has-pit", false,
+ &error_abort);
+ qdev_prop_set_uint32(DEVICE(pci_dev), "smb_io_base", 0xb100);
+ object_property_set_bool(OBJECT(pci_dev), "smm-enabled",
+ x86_machine_is_smm_enabled(x86ms),
+ &error_abort);
+ dev = DEVICE(pci_dev);
+ for (i = 0; i < ISA_NUM_IRQS; i++) {
+ qdev_connect_gpio_out_named(dev, "isa-irqs", i, x86ms->gsi[i]);
+ }
+ pci_realize_and_unref(pci_dev, pci_bus, &error_fatal);
if (xen_enabled()) {
pci_device_set_intx_routing_notifier(
@@ -280,15 +296,18 @@ static void pc_init1(MachineState *machine,
XEN_IOAPIC_NUM_PIRQS);
}
- piix3 = PIIX3_PCI_DEVICE(pci_dev);
- piix3->pic = x86ms->gsi;
- piix3_devfn = piix3->dev.devfn;
- isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0"));
+ isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(pci_dev), "isa.0"));
rtc_state = ISA_DEVICE(object_resolve_path_component(OBJECT(pci_dev),
"rtc"));
+ piix4_pm = object_resolve_path_component(OBJECT(pci_dev), "pm");
+ dev = DEVICE(object_resolve_path_component(OBJECT(pci_dev), "ide"));
+ pci_ide_create_devs(PCI_DEVICE(dev));
+ idebus[0] = qdev_get_child_bus(dev, "ide.0");
+ idebus[1] = qdev_get_child_bus(dev, "ide.1");
} else {
isa_bus = isa_bus_new(NULL, system_memory, system_io,
&error_abort);
+ isa_bus_register_input_irqs(isa_bus, x86ms->gsi);
rtc_state = isa_new(TYPE_MC146818_RTC);
qdev_prop_set_int32(DEVICE(rtc_state), "base_year", 2000);
@@ -296,8 +315,9 @@ static void pc_init1(MachineState *machine,
i8257_dma_init(isa_bus, 0);
pcms->hpet_enabled = false;
+ idebus[0] = NULL;
+ idebus[1] = NULL;
}
- isa_bus_register_input_irqs(isa_bus, x86ms->gsi);
if (x86ms->pic == ON_OFF_AUTO_ON || x86ms->pic == ON_OFF_AUTO_AUTO) {
pc_i8259_create(isa_bus, gsi_state->i8259_irq);
@@ -325,12 +345,6 @@ static void pc_init1(MachineState *machine,
pc_nic_init(pcmc, isa_bus, pci_bus);
if (pcmc->pci_enabled) {
- PCIDevice *dev;
-
- dev = pci_create_simple(pci_bus, piix3_devfn + 1, TYPE_PIIX3_IDE);
- pci_ide_create_devs(dev);
- idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
- idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);
}
#ifdef CONFIG_IDE_ISA
@@ -356,21 +370,9 @@ static void pc_init1(MachineState *machine,
}
#endif
- if (pcmc->pci_enabled && machine_usb(machine)) {
- pci_create_simple(pci_bus, piix3_devfn + 2, TYPE_PIIX3_USB_UHCI);
- }
-
- if (pcmc->pci_enabled && x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) {
- PCIDevice *piix4_pm;
-
+ if (piix4_pm) {
smi_irq = qemu_allocate_irq(pc_acpi_smi_interrupt, first_cpu, 0);
- piix4_pm = pci_new(piix3_devfn + 3, TYPE_PIIX4_PM);
- qdev_prop_set_uint32(DEVICE(piix4_pm), "smb_io_base", 0xb100);
- qdev_prop_set_bit(DEVICE(piix4_pm), "smm-enabled",
- x86_machine_is_smm_enabled(x86ms));
- pci_realize_and_unref(piix4_pm, pci_bus, &error_fatal);
- qdev_connect_gpio_out(DEVICE(piix4_pm), 0, x86ms->gsi[9]);
qdev_connect_gpio_out_named(DEVICE(piix4_pm), "smi-irq", 0, smi_irq);
pcms->smbus = I2C_BUS(qdev_get_child_bus(DEVICE(piix4_pm), "i2c"));
/* TODO: Populate SPD eeprom data. */
@@ -382,7 +384,7 @@ static void pc_init1(MachineState *machine,
object_property_allow_set_link,
OBJ_PROP_LINK_STRONG);
object_property_set_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
- OBJECT(piix4_pm), &error_abort);
+ piix4_pm, &error_abort);
}
if (machine->nvdimms_state->is_enabled) {
@@ -392,6 +394,56 @@ static void pc_init1(MachineState *machine,
}
}
+typedef enum PCSouthBridgeOption {
+ PC_SOUTH_BRIDGE_OPTION_PIIX3,
+ PC_SOUTH_BRIDGE_OPTION_PIIX4,
+ PC_SOUTH_BRIDGE_OPTION_MAX,
+} PCSouthBridgeOption;
+
+static const QEnumLookup PCSouthBridgeOption_lookup = {
+ .array = (const char *const[]) {
+ [PC_SOUTH_BRIDGE_OPTION_PIIX3] = TYPE_PIIX3_DEVICE,
+ [PC_SOUTH_BRIDGE_OPTION_PIIX4] = TYPE_PIIX4_PCI_DEVICE,
+ },
+ .size = PC_SOUTH_BRIDGE_OPTION_MAX
+};
+
+#define NotifyVmexitOption_str(val) \
+ qapi_enum_lookup(&NotifyVmexitOption_lookup, (val))
+
+static int pc_get_south_bridge(Object *obj, Error **errp)
+{
+ PCMachineState *pcms = PC_MACHINE(obj);
+ int i;
+
+ for (i = 0; i < PCSouthBridgeOption_lookup.size; i++) {
+ if (g_strcmp0(PCSouthBridgeOption_lookup.array[i],
+ pcms->south_bridge) == 0) {
+ return i;
+ }
+ }
+
+ error_setg(errp, "Invalid south bridge value set");
+ return 0;
+}
+
+static void pc_set_south_bridge(Object *obj, int value, Error **errp)
+{
+ PCMachineState *pcms = PC_MACHINE(obj);
+
+ if (value < 0) {
+ error_setg(errp, "Value can't be negative");
+ return;
+ }
+
+ if (value >= PCSouthBridgeOption_lookup.size) {
+ error_setg(errp, "Value too big");
+ return;
+ }
+
+ pcms->south_bridge = PCSouthBridgeOption_lookup.array[value];
+}
+
/* Looking for a pc_compat_2_4() function? It doesn't exist.
* pc_compat_*() functions that run on machine-init time and
* change global QEMU state are deprecated. Please don't create
@@ -471,6 +523,8 @@ static void pc_xen_hvm_init(MachineState *machine)
static void pc_i440fx_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+ ObjectClass *oc = OBJECT_CLASS(m);
+ pcmc->default_south_bridge = TYPE_PIIX3_DEVICE;
pcmc->pci_root_uid = 0;
pcmc->default_cpu_version = 1;
@@ -482,6 +536,13 @@ static void pc_i440fx_machine_options(MachineClass *m)
m->no_parallel = !module_object_class_by_name(TYPE_ISA_PARALLEL);
machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE);
machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE);
+
+ object_class_property_add_enum(oc, "x-south-bridge", "PCSouthBridgeOption",
+ &PCSouthBridgeOption_lookup,
+ pc_get_south_bridge,
+ pc_set_south_bridge);
+ object_class_property_set_description(oc, "x-south-bridge",
+ "Use a different south bridge than PIIX3");
}
static void pc_i440fx_8_2_machine_options(MachineClass *m)