summaryrefslogtreecommitdiffstats
path: root/hw/isa/piix3.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/isa/piix3.c')
-rw-r--r--hw/isa/piix3.c115
1 files changed, 69 insertions, 46 deletions
diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c
index dab901c9ad..6388558f92 100644
--- a/hw/isa/piix3.c
+++ b/hw/isa/piix3.c
@@ -24,6 +24,7 @@
#include "qemu/osdep.h"
#include "qemu/range.h"
+#include "qapi/error.h"
#include "hw/southbridge/piix.h"
#include "hw/irq.h"
#include "hw/isa/isa.h"
@@ -32,12 +33,10 @@
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
#include "migration/vmstate.h"
+#include "hw/acpi/acpi_aml_interface.h"
#define XEN_PIIX_NUM_PIRQS 128ULL
-#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],
@@ -81,6 +80,17 @@ static void piix3_set_irq(void *opaque, int pirq, int level)
piix3_set_irq_level(piix3, pirq, level);
}
+/*
+ * 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_SLOT(pci_dev->devfn) - 1;
+ return (pci_intx + slot_addend) & 3;
+}
+
static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin)
{
PIIX3State *piix3 = opaque;
@@ -269,7 +279,7 @@ static const MemoryRegionOps rcr_ops = {
.endianness = DEVICE_LITTLE_ENDIAN
};
-static void piix3_realize(PCIDevice *dev, Error **errp)
+static void pci_piix3_realize(PCIDevice *dev, Error **errp)
{
PIIX3State *d = PIIX3_PCI_DEVICE(dev);
@@ -286,15 +296,28 @@ static void piix3_realize(PCIDevice *dev, Error **errp)
qemu_register_reset(piix3_reset, d);
}
+static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
+{
+ BusChild *kid;
+ BusState *bus = qdev_get_child_bus(DEVICE(adev), "isa.0");
+
+ /* PIIX PCI to ISA irq remapping */
+ aml_append(scope, aml_operation_region("P40C", AML_PCI_CONFIG,
+ aml_int(0x60), 0x04));
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ call_dev_aml_func(DEVICE(kid->child), scope);
+ }
+}
+
static void pci_piix3_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_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;
@@ -304,6 +327,7 @@ static void pci_piix3_class_init(ObjectClass *klass, void *data)
* pc_piix.c's pc_init1()
*/
dc->user_creatable = false;
+ adevc->build_dev_aml = build_pci_isa_aml;
}
static const TypeInfo piix3_pci_type_info = {
@@ -314,15 +338,33 @@ static const TypeInfo piix3_pci_type_info = {
.class_init = pci_piix3_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { TYPE_ACPI_DEV_AML_IF },
{ },
},
};
+static void piix3_realize(PCIDevice *dev, Error **errp)
+{
+ ERRP_GUARD();
+ PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev);
+ PCIBus *pci_bus = pci_get_bus(dev);
+
+ pci_piix3_realize(dev, errp);
+ if (*errp) {
+ return;
+ }
+
+ 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);
+};
+
static void piix3_class_init(ObjectClass *klass, void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->config_write = piix3_write_config;
+ k->realize = piix3_realize;
}
static const TypeInfo piix3_info = {
@@ -331,11 +373,33 @@ static const TypeInfo piix3_info = {
.class_init = piix3_class_init,
};
+static void piix3_xen_realize(PCIDevice *dev, Error **errp)
+{
+ ERRP_GUARD();
+ PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev);
+ PCIBus *pci_bus = pci_get_bus(dev);
+
+ pci_piix3_realize(dev, errp);
+ if (*errp) {
+ return;
+ }
+
+ /*
+ * 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.
+ */
+ pci_bus_irqs(pci_bus, xen_piix3_set_irq, xen_pci_slot_get_pirq,
+ piix3, XEN_PIIX_NUM_PIRQS);
+};
+
static void piix3_xen_class_init(ObjectClass *klass, void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->config_write = piix3_write_config_xen;
+ k->realize = piix3_xen_realize;
};
static const TypeInfo piix3_xen_info = {
@@ -352,44 +416,3 @@ static void piix3_register_types(void)
}
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_SLOT(pci_dev->devfn) - 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;
-}