@@ -253,8 +253,11 @@ static void pc_init1(MachineState *machine,
PCIDevice *dev;
dev = pci_new_multifunction(piix3_devfn + 1, false, "piix3-ide");
+ qdev_prop_set_bit(DEVICE(dev), "user-created", false);
pci_realize_and_unref(dev, pci_bus, &error_fatal);
pci_ide_create_devs(dev);
+ qdev_connect_gpio_out(DEVICE(dev), 0, x86ms->gsi[14]);
+ qdev_connect_gpio_out(DEVICE(dev), 1, x86ms->gsi[15]);
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);
@@ -103,6 +103,13 @@ static void bmdma_setup_bar(PCIIDEState *d)
}
}
+static void piix_ide_set_irq(void *opaque, int n, int level)
+{
+ PCIIDEState *d = opaque;
+
+ qemu_set_irq(d->isa_irqs[n], level);
+}
+
static void piix_ide_reset(DeviceState *dev)
{
PCIIDEState *d = PCI_IDE(dev);
@@ -129,14 +136,14 @@ static int pci_piix_init_ports(PCIIDEState *d)
static const struct {
int iobase;
int iobase2;
- int isairq;
} port_info[] = {
- {0x1f0, 0x3f6, 14},
- {0x170, 0x376, 15},
+ {0x1f0, 0x3f6},
+ {0x170, 0x376},
};
+ DeviceState *dev = DEVICE(d);
int i;
- {
+ if (d->user_created) {
ISABus *isa_bus;
bool ambiguous;
@@ -145,13 +152,18 @@ static int pci_piix_init_ports(PCIIDEState *d)
if (!isa_bus || ambiguous) {
return -ENODEV;
}
+
+ d->isa_irqs[0] = isa_bus->irqs[14];
+ d->isa_irqs[1] = isa_bus->irqs[15];
+ } else {
+ qdev_init_gpio_out(dev, d->isa_irqs, 2);
}
for (i = 0; i < 2; i++) {
- ide_bus_init(&d->bus[i], sizeof(d->bus[i]), DEVICE(d), i, 2);
+ ide_bus_init(&d->bus[i], sizeof(d->bus[i]), dev, i, 2);
ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase,
port_info[i].iobase2);
- ide_init2(&d->bus[i], isa_get_irq(NULL, port_info[i].isairq));
+ ide_init2(&d->bus[i], qdev_get_gpio_in(dev, i));
bmdma_init(&d->bus[i], &d->bmdma[i], d);
d->bmdma[i].bus = &d->bus[i];
@@ -181,6 +193,14 @@ static void pci_piix_ide_realize(PCIDevice *dev, Error **errp)
}
}
+static void pci_piix_ide_init(Object *obj)
+{
+ PCIIDEState *d = PCI_IDE(obj);
+ DeviceState *dev = DEVICE(d);
+
+ qdev_init_gpio_in(dev, piix_ide_set_irq, 2);
+}
+
static void pci_piix_ide_exitfn(PCIDevice *dev)
{
PCIIDEState *d = PCI_IDE(dev);
@@ -192,6 +212,11 @@ static void pci_piix_ide_exitfn(PCIDevice *dev)
}
}
+static Property piix_ide_properties[] = {
+ DEFINE_PROP_BOOL("user-created", PCIIDEState, user_created, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
static void piix3_ide_class_init(ObjectClass *klass, void *data)
{
@@ -206,11 +231,13 @@ static void piix3_ide_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_STORAGE_IDE;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->hotpluggable = false;
+ device_class_set_props(dc, piix_ide_properties);
}
static const TypeInfo piix3_ide_info = {
.name = "piix3-ide",
.parent = TYPE_PCI_IDE,
+ .instance_init = pci_piix_ide_init,
.class_init = piix3_ide_class_init,
};
@@ -228,11 +255,13 @@ static void piix4_ide_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_STORAGE_IDE;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->hotpluggable = false;
+ device_class_set_props(dc, piix_ide_properties);
}
static const TypeInfo piix4_ide_info = {
.name = "piix4-ide",
.parent = TYPE_PCI_IDE,
+ .instance_init = pci_piix_ide_init,
.class_init = piix4_ide_class_init,
};
@@ -251,10 +251,13 @@ static void piix4_realize(PCIDevice *dev, Error **errp)
/* IDE */
qdev_prop_set_int32(DEVICE(&s->ide), "addr", dev->devfn + 1);
+ qdev_prop_set_bit(DEVICE(&s->ide), "user-created", false);
if (!qdev_realize(DEVICE(&s->ide), BUS(pci_bus), errp)) {
return;
}
pci_ide_create_devs(PCI_DEVICE(&s->ide));
+ qdev_connect_gpio_out(DEVICE(&s->ide), 0, s->isa[14]);
+ qdev_connect_gpio_out(DEVICE(&s->ide), 1, s->isa[15]);
/* USB */
qdev_prop_set_int32(DEVICE(&s->uhci), "addr", dev->devfn + 2);
@@ -49,10 +49,12 @@ struct PCIIDEState {
IDEBus bus[2];
BMDMAState bmdma[2];
+ qemu_irq isa_irqs[2];
uint32_t secondary; /* used only for cmd646 */
MemoryRegion bmdma_bar;
MemoryRegion cmd_bar[2];
MemoryRegion data_bar[2];
+ bool user_created;
};
static inline IDEState *bmdma_active_if(BMDMAState *bmdma)
isa_get_irq() currently always uses the "isabus" global to get the desired qemu_irq. In order to resolve this global, we want isa_get_irq() to determine the ISABus from its *dev parameter using isa_bus_from_device(). As a preparation, all callers who pass NULL as *dev need to be resolved which seems to happen in hw/ide/piix only. This patch roughly implements the solution outlined in https:// lists.nongnu.org/archive/html/qemu-devel/2020-03/msg01707.html. In oder to address the PIIX IDE functions being user-creatable, (see https://lists.nongnu.org/archive/html/qemu-devel/2021-04/msg05655.html) a backwards compatibility quirk is introduced which can be removed after some deprecation period. The quirk consists of internal devices to opt into new behavior where the ISA interrupt wiring is performed by the caller rather than by the device itself. The opt-in can be performed by: qdev_prop_set_bit(DEVICE(dev), "user-created", false); RFC: qdev_init_gpio_in() seems to expose interrupts internal to the device. Can this be fixed? Signed-off-by: Bernhard Beschow <shentey@gmail.com> --- hw/i386/pc_piix.c | 3 +++ hw/ide/piix.c | 41 +++++++++++++++++++++++++++++++++++------ hw/isa/piix4.c | 3 +++ include/hw/ide/pci.h | 2 ++ 4 files changed, 43 insertions(+), 6 deletions(-)