qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [RFC PATCH] Distinguish between reset types


From: Anthony Liguori
Subject: Re: [Qemu-devel] [RFC PATCH] Distinguish between reset types
Date: Tue, 19 Feb 2013 14:29:54 -0600
User-agent: Notmuch/0.13.2+93~ged93d79 (http://notmuchmail.org) Emacs/23.3.1 (x86_64-pc-linux-gnu)

David Woodhouse <address@hidden> writes:

> 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? 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?
>
> 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();


This is a bit strange to me.  From the spec:

"Bits 1 and 2 in this register are used by PIIX4 to generate a hard reset
 or a soft reset. During a hard reset, PIIX4 asserts CPURST, PCIRST#, and
 RSTDRV, as well as reset its core and suspend well logic. During a soft
 reset, PIIX4 asserts INIT."

Bit
2   Reset CPU (RCPU). This bit is used to initiate (transitions from 0
    to 1) a hard reset (bit 1 in this register is set to 1) or a soft
    reset to the CPU. PIIX4 will also initiate a hard reset when PWROK
    is asserted. This bit cannot be read as a 1.

1   System Reset (SRST). This bit is used to select the type of reset
    generated when bit 2 in this register is set to 1. When SRST=1,
    PIIX4 initiates a hard reset to the CPU when bit 2 in this register
    transitions from 0 to 1. When SRST=0, PIIX4 initiates a soft reset
    when bit 2 in this register transitions from 0 to 1.

Now this maps to two signals: INIT# and CPURST#.  PCIRST# is strictly
about resetting the PCI bus.  PCIRST# is only asserted during hard
reset.

So should we even be resetting anything other than the CPU during soft
reset?

In the very least, shouldn't we expose qemu_irqs from the PIIX and let
the i440fx decide what to do with them?  In this case, it would be an
INIT# and CPURST# qemu_irq corresponding to soft and hard reset
respectively.

Regards,

Anthony Liguori


>          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 = {
>
>
>
>
> -- 
> dwmw2



reply via email to

[Prev in Thread] Current Thread [Next in Thread]