diff options
Diffstat (limited to 'hw/i386/pc_piix.c')
-rw-r--r-- | hw/i386/pc_piix.c | 125 |
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) |