Il 19/02/2013 15:40, David Woodhouse ha scritto: > On Tue, 2013-02-19 at 13:31 +0100, Paolo Bonzini wrote: >> So you can make the hard reset line a qemu_irq (output in PIIX, input in >> i440FX) using qdev_init_gpio_in/out. The input side in the i440FX then >> can reset the PAM registers while the output side can pulse it before >> calling qemu_system_reset_request() if RCR bit 1 is set. Then you can >> connect it using qdev_connect_gpio_out/qdev_get_gpio_in in >> i440fx_common_init. > > Like this?
Exactly. > I've still left i440fx_reset() hooked up as dc->reset, and > conditionally do the full reset based on a flag in the state. If I > actually *do* the reset directly from i440fx_handle_reset() rather than > just setting the flag there, it might happen too early? I think it'd be okay, but without actually tracing what happens I agree that it's safer this way. Paolo > diff --git a/hw/piix_pci.c b/hw/piix_pci.c > index 6c77e49..0c8f613 100644 > --- a/hw/piix_pci.c > +++ b/hw/piix_pci.c > @@ -71,6 +71,7 @@ typedef struct PIIX3State { > uint64_t pic_levels; > > qemu_irq *pic; > + qemu_irq reset_out; > > /* This member isn't used. Just for save/load compatibility */ > int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS]; > @@ -92,6 +93,7 @@ struct PCII440FXState { > PAMMemoryRegion pam_regions[13]; > MemoryRegion smram_region; > uint8_t smm_enabled; > + uint8_t hard_reset; > }; > > > @@ -171,6 +173,42 @@ static int i440fx_load_old(QEMUFile* f, void *opaque, > int version_id) > return 0; > } > > +static void i440fx_reset(DeviceState *ds) > +{ > + PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, ds); > + PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev); > + uint8_t *pci_conf = d->dev.config; > + > + /* We only reset the PAM configuration if it was a *hard* reset, > + * triggered from the RCR on the PIIX3 (or from the TRCR on the > + * i440FX itself, but we don't implement that yet and software > + * is advised not to use it when there's a PIIX). */ > + if (!d->hard_reset) > + return; > + > + d->hard_reset = 0; > + > + pci_conf[0x59] = 0x00; // Reset PAM setup > + pci_conf[0x5a] = 0x00; > + pci_conf[0x5b] = 0x00; > + pci_conf[0x5c] = 0x00; > + pci_conf[0x5d] = 0x00; > + pci_conf[0x5e] = 0x00; > + pci_conf[0x5f] = 0x00; > + pci_conf[0x72] = 0x02; // And SMM > + > + i440fx_update_memory_mappings(d); > +} > + > +static void i440fx_handle_reset(void *opaque, int n, int level) > +{ > + PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, opaque); > + PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev); > + > + if (level) > + d->hard_reset = 1; > +} > + > static int i440fx_post_load(void *opaque, int version_id) > { > PCII440FXState *d = opaque; > @@ -216,6 +254,8 @@ static int i440fx_initfn(PCIDevice *dev) > > d->dev.config[I440FX_SMRAM] = 0x02; > > + qdev_init_gpio_in(&d->dev.qdev, i440fx_handle_reset, 1); > + > cpu_smm_register(&i440fx_set_smm, d); > return 0; > } > @@ -297,6 +337,8 @@ static PCIBus *i440fx_common_init(const char *device_name, > pci_bus_set_route_irq_fn(b, piix3_route_intx_pin_to_irq); > } > piix3->pic = pic; > + qdev_connect_gpio_out(&piix3->dev.qdev, 0, > + qdev_get_gpio_in(&f->dev.qdev, 0)); > *isa_bus = DO_UPCAST(ISABus, qbus, > qdev_get_child_bus(&piix3->dev.qdev, "isa.0")); > > @@ -521,6 +563,8 @@ static void rcr_write(void *opaque, hwaddr addr, uint64_t > val, unsigned len) > PIIX3State *d = opaque; > > if (val & 4) { > + if (val & 2) > + qemu_irq_pulse(d->reset_out); > qemu_system_reset_request(); > return; > } > @@ -550,6 +594,7 @@ static int piix3_initfn(PCIDevice *dev) > memory_region_add_subregion_overlap(pci_address_space_io(dev), > RCR_IOPORT, > &d->rcr_mem, 1); > > + qdev_init_gpio_out(&dev->qdev, &d->reset_out, 1); > qemu_register_reset(piix3_reset, d); > return 0; > } > @@ -615,6 +660,7 @@ static void i440fx_class_init(ObjectClass *klass, void > *data) > dc->desc = "Host bridge"; > dc->no_user = 1; > dc->vmsd = &vmstate_i440fx; > + dc->reset = i440fx_reset; > } > > static const TypeInfo i440fx_info = { > > > >