diff mbox series

[RFC,15/17] Convert zynq's slcr to 3-phases reset

Message ID c2bf4b5983b8f0bb42208eaf62643aaccc0163a2.1553510737.git.damien.hedde@greensocs.com
State New
Headers show
Series multi-phase reset mechanism | expand

Commit Message

Damien Hedde March 25, 2019, 11:01 a.m. UTC
Change the legacy reset function into the init phase and test the
resetting flag in register accesses.

Signed-off-by: Damien Hedde <damien.hedde@greensocs.com>
---
 hw/misc/zynq_slcr.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

Comments

Philippe Mathieu-Daudé March 25, 2019, 1:28 p.m. UTC | #1
Hi Damien,

Le lun. 25 mars 2019 12:16, Damien Hedde <damien.hedde@greensocs.com> a
écrit :

> Change the legacy reset function into the init phase and test the
> resetting flag in register accesses.
>
> Signed-off-by: Damien Hedde <damien.hedde@greensocs.com>
> ---
>  hw/misc/zynq_slcr.c | 14 +++++++++++---
>  1 file changed, 11 insertions(+), 3 deletions(-)
>
> diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c
> index baa13d1316..47f43e1d8d 100644
> --- a/hw/misc/zynq_slcr.c
> +++ b/hw/misc/zynq_slcr.c
> @@ -180,9 +180,9 @@ typedef struct ZynqSLCRState {
>      uint32_t regs[ZYNQ_SLCR_NUM_REGS];
>  } ZynqSLCRState;
>
> -static void zynq_slcr_reset(DeviceState *d)
> +static void zynq_slcr_reset_init(Object *obj, bool cold)
>  {
> -    ZynqSLCRState *s = ZYNQ_SLCR(d);
> +    ZynqSLCRState *s = ZYNQ_SLCR(obj);
>      int i;
>
>      DB_PRINT("RESET\n");
> @@ -346,6 +346,10 @@ static uint64_t zynq_slcr_read(void *opaque, hwaddr
> offset,
>      offset /= 4;
>      uint32_t ret = s->regs[offset];
>
> +    if (qdev_is_resetting((DeviceState *) opaque)) {
> +        return 0;
> +    }
> +
>      if (!zynq_slcr_check_offset(offset, true)) {
>          qemu_log_mask(LOG_GUEST_ERROR, "zynq_slcr: Invalid read access to
> "
>                        " addr %" HWADDR_PRIx "\n", offset * 4);
> @@ -361,6 +365,10 @@ static void zynq_slcr_write(void *opaque, hwaddr
> offset,
>      ZynqSLCRState *s = (ZynqSLCRState *)opaque;
>      offset /= 4;
>
> +    if (qdev_is_resetting((DeviceState *) opaque)) {
> +        return;
>

I wonder if that could be moved to generic parent, as an abstract method.
But then I'm not sure we can use a generic read() return value.

+    }
> +
>      DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx64 "\n", offset *
> 4, val);
>
>      if (!zynq_slcr_check_offset(offset, false)) {
> @@ -441,7 +449,7 @@ static void zynq_slcr_class_init(ObjectClass *klass,
> void *data)
>      DeviceClass *dc = DEVICE_CLASS(klass);
>
>      dc->vmsd = &vmstate_zynq_slcr;
> -    dc->reset = zynq_slcr_reset;
> +    dc->reset_phases.init = zynq_slcr_reset_init;
>  }
>
>  static const TypeInfo zynq_slcr_info = {
> --
> 2.21.0
>

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

>
Damien Hedde March 28, 2019, 1:54 p.m. UTC | #2
Hi Philippe,

On 3/25/19 2:28 PM, Philippe Mathieu-Daudé wrote:
> Hi Damien,
> 
> Le lun. 25 mars 2019 12:16, Damien Hedde <damien.hedde@greensocs.com
> <mailto:damien.hedde@greensocs.com>> a écrit :
> 
>     Change the legacy reset function into the init phase and test the
>     resetting flag in register accesses.
> 
>     Signed-off-by: Damien Hedde <damien.hedde@greensocs.com
>     <mailto:damien.hedde@greensocs.com>>
>     ---
>      hw/misc/zynq_slcr.c | 14 +++++++++++---
>      1 file changed, 11 insertions(+), 3 deletions(-)
> [...]
>     @@ -346,6 +346,10 @@ static uint64_t zynq_slcr_read(void *opaque,
>     hwaddr offset,
>          offset /= 4;
>          uint32_t ret = s->regs[offset];
> 
>     +    if (qdev_is_resetting((DeviceState *) opaque)) {
>     +        return 0;
>     +    }
>     +
>          if (!zynq_slcr_check_offset(offset, true)) {
>              qemu_log_mask(LOG_GUEST_ERROR, "zynq_slcr: Invalid read
>     access to "
>                            " addr %" HWADDR_PRIx "\n", offset * 4);
>     @@ -361,6 +365,10 @@ static void zynq_slcr_write(void *opaque,
>     hwaddr offset,
>          ZynqSLCRState *s = (ZynqSLCRState *)opaque;
>          offset /= 4;
> 
>     +    if (qdev_is_resetting((DeviceState *) opaque)) {
>     +        return;
> 
> 
> I wonder if that could be moved to generic parent, as an abstract method. 
> But then I'm not sure we can use a generic read() return value. 
> 

I agree it would be better not have to add this kind of test everywhere.
It is one my unresolved problem but I am not sure what is the best solution.

There is two approachs here I think:
Either we disable/enable explicitely the memory regions in the reset
handlers. But then we have to handle the migration of the memory regions
flags.
Or the memory region handlers somehow check the resetting state (like
here) and we have only to handle the resetting state migration.

Memory region are added using the following code in sysbus:
```
memory_region_init_io(&s->iomem, obj, &uart_ops, s, "uart", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_mmio_map(s, mmio_index, addr);
```
To intercept the read and write without needing a modification of every
read/write handlers, I see two options:

+ we can either find a way to "override" the read and write handlers of
the memory regions. For example, this could be done in sysbus_init_mmio,
or in a dedicated version of the function (eg sysbus_init_mmio_with_reset)

+ or we can use the MemoryRegion owner field (here _obj_ in
memory_region_init_io call) to test if the owner is Resettable and
whether it is resetting or not before calling the handlers. In that
case, this will not be limited to sysbus devices.

--
Thanks
Damien
diff mbox series

Patch

diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c
index baa13d1316..47f43e1d8d 100644
--- a/hw/misc/zynq_slcr.c
+++ b/hw/misc/zynq_slcr.c
@@ -180,9 +180,9 @@  typedef struct ZynqSLCRState {
     uint32_t regs[ZYNQ_SLCR_NUM_REGS];
 } ZynqSLCRState;
 
-static void zynq_slcr_reset(DeviceState *d)
+static void zynq_slcr_reset_init(Object *obj, bool cold)
 {
-    ZynqSLCRState *s = ZYNQ_SLCR(d);
+    ZynqSLCRState *s = ZYNQ_SLCR(obj);
     int i;
 
     DB_PRINT("RESET\n");
@@ -346,6 +346,10 @@  static uint64_t zynq_slcr_read(void *opaque, hwaddr offset,
     offset /= 4;
     uint32_t ret = s->regs[offset];
 
+    if (qdev_is_resetting((DeviceState *) opaque)) {
+        return 0;
+    }
+
     if (!zynq_slcr_check_offset(offset, true)) {
         qemu_log_mask(LOG_GUEST_ERROR, "zynq_slcr: Invalid read access to "
                       " addr %" HWADDR_PRIx "\n", offset * 4);
@@ -361,6 +365,10 @@  static void zynq_slcr_write(void *opaque, hwaddr offset,
     ZynqSLCRState *s = (ZynqSLCRState *)opaque;
     offset /= 4;
 
+    if (qdev_is_resetting((DeviceState *) opaque)) {
+        return;
+    }
+
     DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx64 "\n", offset * 4, val);
 
     if (!zynq_slcr_check_offset(offset, false)) {
@@ -441,7 +449,7 @@  static void zynq_slcr_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->vmsd = &vmstate_zynq_slcr;
-    dc->reset = zynq_slcr_reset;
+    dc->reset_phases.init = zynq_slcr_reset_init;
 }
 
 static const TypeInfo zynq_slcr_info = {