* [PATCH 0/2] wdt_aspeed: Fix behaviour of control register @ 2021-07-09 5:31 Andrew Jeffery 2021-07-09 5:31 ` [PATCH 1/2] watchdog: aspeed: Sanitize control register values Andrew Jeffery 2021-07-09 5:31 ` [PATCH 2/2] watchdog: aspeed: Fix sequential control writes Andrew Jeffery 0 siblings, 2 replies; 7+ messages in thread From: Andrew Jeffery @ 2021-07-09 5:31 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, qemu-arm, clg, joel Hello, I discovered a couple of bugs in the watchdog while testing a tool to poke Aspeed BMCs over their various AHB bridges. The immediate observation was that the model for the 2500 wasn't signalling use of the fixed 1MHz clock, which is resolved in the first patch. The other observation was that sequential writes to control weren't sticking if the enable bit wasn't toggled, which is fixed in the second patch. Please review. Andrew Andrew Jeffery (2): watchdog: aspeed: Sanitize control register values watchdog: aspeed: Fix sequential control writes hw/watchdog/wdt_aspeed.c | 26 ++++++++++++++++++++++++-- include/hw/watchdog/wdt_aspeed.h | 1 + 2 files changed, 25 insertions(+), 2 deletions(-) -- 2.30.2 ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/2] watchdog: aspeed: Sanitize control register values 2021-07-09 5:31 [PATCH 0/2] wdt_aspeed: Fix behaviour of control register Andrew Jeffery @ 2021-07-09 5:31 ` Andrew Jeffery 2021-07-19 15:53 ` Cédric Le Goater 2021-07-09 5:31 ` [PATCH 2/2] watchdog: aspeed: Fix sequential control writes Andrew Jeffery 1 sibling, 1 reply; 7+ messages in thread From: Andrew Jeffery @ 2021-07-09 5:31 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, qemu-arm, clg, joel While some of the critical fields remain the same, there is variation in the definition of the control register across the SoC generations. Reserved regions are adjusted, while in other cases the mutability or behaviour of fields change. Introduce a callback to sanitize the value on writes to ensure model behaviour reflects the hardware. Fixes: 854123bf8d4b ("wdt: Add Aspeed watchdog device model") Signed-off-by: Andrew Jeffery <andrew@aj.id.au> --- hw/watchdog/wdt_aspeed.c | 24 ++++++++++++++++++++++-- include/hw/watchdog/wdt_aspeed.h | 1 + 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index 6352ba1b0e5b..faa3d35fdf21 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -118,13 +118,27 @@ static void aspeed_wdt_reload_1mhz(AspeedWDTState *s) } } +static uint64_t aspeed_2400_sanitize_ctrl(uint64_t data) +{ + return data & 0xffff; +} + +static uint64_t aspeed_2500_sanitize_ctrl(uint64_t data) +{ + return (data & ~(0xfUL << 8)) | WDT_CTRL_1MHZ_CLK; +} + +static uint64_t aspeed_2600_sanitize_ctrl(uint64_t data) +{ + return data & ~(0x7UL << 7); +} static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, unsigned size) { AspeedWDTState *s = ASPEED_WDT(opaque); AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(s); - bool enable = data & WDT_CTRL_ENABLE; + bool enable; offset >>= 2; @@ -144,6 +158,8 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, } break; case WDT_CTRL: + data = awc->sanitize_ctrl(data); + enable = data & WDT_CTRL_ENABLE; if (enable && !aspeed_wdt_is_enabled(s)) { s->regs[WDT_CTRL] = data; awc->wdt_reload(s); @@ -207,11 +223,12 @@ static const MemoryRegionOps aspeed_wdt_ops = { static void aspeed_wdt_reset(DeviceState *dev) { AspeedWDTState *s = ASPEED_WDT(dev); + AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(s); s->regs[WDT_STATUS] = 0x3EF1480; s->regs[WDT_RELOAD_VALUE] = 0x03EF1480; s->regs[WDT_RESTART] = 0; - s->regs[WDT_CTRL] = 0; + s->regs[WDT_CTRL] = awc->sanitize_ctrl(0); s->regs[WDT_RESET_WIDTH] = 0xFF; timer_del(s->timer); @@ -293,6 +310,7 @@ static void aspeed_2400_wdt_class_init(ObjectClass *klass, void *data) awc->ext_pulse_width_mask = 0xff; awc->reset_ctrl_reg = SCU_RESET_CONTROL1; awc->wdt_reload = aspeed_wdt_reload; + awc->sanitize_ctrl = aspeed_2400_sanitize_ctrl; } static const TypeInfo aspeed_2400_wdt_info = { @@ -328,6 +346,7 @@ static void aspeed_2500_wdt_class_init(ObjectClass *klass, void *data) awc->reset_ctrl_reg = SCU_RESET_CONTROL1; awc->reset_pulse = aspeed_2500_wdt_reset_pulse; awc->wdt_reload = aspeed_wdt_reload_1mhz; + awc->sanitize_ctrl = aspeed_2500_sanitize_ctrl; } static const TypeInfo aspeed_2500_wdt_info = { @@ -348,6 +367,7 @@ static void aspeed_2600_wdt_class_init(ObjectClass *klass, void *data) awc->reset_ctrl_reg = AST2600_SCU_RESET_CONTROL1; awc->reset_pulse = aspeed_2500_wdt_reset_pulse; awc->wdt_reload = aspeed_wdt_reload_1mhz; + awc->sanitize_ctrl = aspeed_2600_sanitize_ctrl; } static const TypeInfo aspeed_2600_wdt_info = { diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h index 80b03661e303..f945cd6c5833 100644 --- a/include/hw/watchdog/wdt_aspeed.h +++ b/include/hw/watchdog/wdt_aspeed.h @@ -44,6 +44,7 @@ struct AspeedWDTClass { uint32_t reset_ctrl_reg; void (*reset_pulse)(AspeedWDTState *s, uint32_t property); void (*wdt_reload)(AspeedWDTState *s); + uint64_t (*sanitize_ctrl)(uint64_t data); }; #endif /* WDT_ASPEED_H */ -- 2.30.2 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] watchdog: aspeed: Sanitize control register values 2021-07-09 5:31 ` [PATCH 1/2] watchdog: aspeed: Sanitize control register values Andrew Jeffery @ 2021-07-19 15:53 ` Cédric Le Goater 0 siblings, 0 replies; 7+ messages in thread From: Cédric Le Goater @ 2021-07-19 15:53 UTC (permalink / raw) To: Andrew Jeffery, qemu-devel; +Cc: peter.maydell, qemu-arm, joel On 7/9/21 7:31 AM, Andrew Jeffery wrote: > While some of the critical fields remain the same, there is variation in > the definition of the control register across the SoC generations. > Reserved regions are adjusted, while in other cases the mutability or > behaviour of fields change. > > Introduce a callback to sanitize the value on writes to ensure model > behaviour reflects the hardware. > > Fixes: 854123bf8d4b ("wdt: Add Aspeed watchdog device model") > Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Reviewed-by: Cédric Le Goater <clg@kaod.org> > --- > hw/watchdog/wdt_aspeed.c | 24 ++++++++++++++++++++++-- > include/hw/watchdog/wdt_aspeed.h | 1 + > 2 files changed, 23 insertions(+), 2 deletions(-) > > diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c > index 6352ba1b0e5b..faa3d35fdf21 100644 > --- a/hw/watchdog/wdt_aspeed.c > +++ b/hw/watchdog/wdt_aspeed.c > @@ -118,13 +118,27 @@ static void aspeed_wdt_reload_1mhz(AspeedWDTState *s) > } > } > > +static uint64_t aspeed_2400_sanitize_ctrl(uint64_t data) > +{ > + return data & 0xffff; > +} > + > +static uint64_t aspeed_2500_sanitize_ctrl(uint64_t data) > +{ > + return (data & ~(0xfUL << 8)) | WDT_CTRL_1MHZ_CLK; > +} > + > +static uint64_t aspeed_2600_sanitize_ctrl(uint64_t data) > +{ > + return data & ~(0x7UL << 7); > +} > > static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, > unsigned size) > { > AspeedWDTState *s = ASPEED_WDT(opaque); > AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(s); > - bool enable = data & WDT_CTRL_ENABLE; > + bool enable; > > offset >>= 2; > > @@ -144,6 +158,8 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, > } > break; > case WDT_CTRL: > + data = awc->sanitize_ctrl(data); > + enable = data & WDT_CTRL_ENABLE; > if (enable && !aspeed_wdt_is_enabled(s)) { > s->regs[WDT_CTRL] = data; > awc->wdt_reload(s); > @@ -207,11 +223,12 @@ static const MemoryRegionOps aspeed_wdt_ops = { > static void aspeed_wdt_reset(DeviceState *dev) > { > AspeedWDTState *s = ASPEED_WDT(dev); > + AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(s); > > s->regs[WDT_STATUS] = 0x3EF1480; > s->regs[WDT_RELOAD_VALUE] = 0x03EF1480; > s->regs[WDT_RESTART] = 0; > - s->regs[WDT_CTRL] = 0; > + s->regs[WDT_CTRL] = awc->sanitize_ctrl(0); > s->regs[WDT_RESET_WIDTH] = 0xFF; > > timer_del(s->timer); > @@ -293,6 +310,7 @@ static void aspeed_2400_wdt_class_init(ObjectClass *klass, void *data) > awc->ext_pulse_width_mask = 0xff; > awc->reset_ctrl_reg = SCU_RESET_CONTROL1; > awc->wdt_reload = aspeed_wdt_reload; > + awc->sanitize_ctrl = aspeed_2400_sanitize_ctrl; > } > > static const TypeInfo aspeed_2400_wdt_info = { > @@ -328,6 +346,7 @@ static void aspeed_2500_wdt_class_init(ObjectClass *klass, void *data) > awc->reset_ctrl_reg = SCU_RESET_CONTROL1; > awc->reset_pulse = aspeed_2500_wdt_reset_pulse; > awc->wdt_reload = aspeed_wdt_reload_1mhz; > + awc->sanitize_ctrl = aspeed_2500_sanitize_ctrl; > } > > static const TypeInfo aspeed_2500_wdt_info = { > @@ -348,6 +367,7 @@ static void aspeed_2600_wdt_class_init(ObjectClass *klass, void *data) > awc->reset_ctrl_reg = AST2600_SCU_RESET_CONTROL1; > awc->reset_pulse = aspeed_2500_wdt_reset_pulse; > awc->wdt_reload = aspeed_wdt_reload_1mhz; > + awc->sanitize_ctrl = aspeed_2600_sanitize_ctrl; > } > > static const TypeInfo aspeed_2600_wdt_info = { > diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h > index 80b03661e303..f945cd6c5833 100644 > --- a/include/hw/watchdog/wdt_aspeed.h > +++ b/include/hw/watchdog/wdt_aspeed.h > @@ -44,6 +44,7 @@ struct AspeedWDTClass { > uint32_t reset_ctrl_reg; > void (*reset_pulse)(AspeedWDTState *s, uint32_t property); > void (*wdt_reload)(AspeedWDTState *s); > + uint64_t (*sanitize_ctrl)(uint64_t data); > }; > > #endif /* WDT_ASPEED_H */ > ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2/2] watchdog: aspeed: Fix sequential control writes 2021-07-09 5:31 [PATCH 0/2] wdt_aspeed: Fix behaviour of control register Andrew Jeffery 2021-07-09 5:31 ` [PATCH 1/2] watchdog: aspeed: Sanitize control register values Andrew Jeffery @ 2021-07-09 5:31 ` Andrew Jeffery 2021-07-09 7:29 ` Philippe Mathieu-Daudé 2021-07-19 15:54 ` Cédric Le Goater 1 sibling, 2 replies; 7+ messages in thread From: Andrew Jeffery @ 2021-07-09 5:31 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, qemu-arm, clg, joel The logic in the handling for the control register required toggling the enable state for writes to stick. Rework the condition chain to allow sequential writes that do not update the enable state. Fixes: 854123bf8d4b ("wdt: Add Aspeed watchdog device model") Signed-off-by: Andrew Jeffery <andrew@aj.id.au> --- hw/watchdog/wdt_aspeed.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index faa3d35fdf21..69c37af9a6e9 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -166,6 +166,8 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, } else if (!enable && aspeed_wdt_is_enabled(s)) { s->regs[WDT_CTRL] = data; timer_del(s->timer); + } else { + s->regs[WDT_CTRL] = data; } break; case WDT_RESET_WIDTH: -- 2.30.2 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] watchdog: aspeed: Fix sequential control writes 2021-07-09 5:31 ` [PATCH 2/2] watchdog: aspeed: Fix sequential control writes Andrew Jeffery @ 2021-07-09 7:29 ` Philippe Mathieu-Daudé 2021-07-13 2:41 ` Andrew Jeffery 2021-07-19 15:54 ` Cédric Le Goater 1 sibling, 1 reply; 7+ messages in thread From: Philippe Mathieu-Daudé @ 2021-07-09 7:29 UTC (permalink / raw) To: Andrew Jeffery, qemu-devel; +Cc: peter.maydell, qemu-arm, clg, joel On 7/9/21 7:31 AM, Andrew Jeffery wrote: > The logic in the handling for the control register required toggling the > enable state for writes to stick. Rework the condition chain to allow > sequential writes that do not update the enable state. > > Fixes: 854123bf8d4b ("wdt: Add Aspeed watchdog device model") > Signed-off-by: Andrew Jeffery <andrew@aj.id.au> > --- > hw/watchdog/wdt_aspeed.c | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c > index faa3d35fdf21..69c37af9a6e9 100644 > --- a/hw/watchdog/wdt_aspeed.c > +++ b/hw/watchdog/wdt_aspeed.c > @@ -166,6 +166,8 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, > } else if (!enable && aspeed_wdt_is_enabled(s)) { > s->regs[WDT_CTRL] = data; > timer_del(s->timer); > + } else { > + s->regs[WDT_CTRL] = data; What about simplifying by moving here: if (!enable && aspeed_wdt_is_enabled(s)) { timer_del(s->timer); } > } > break; > case WDT_RESET_WIDTH: > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] watchdog: aspeed: Fix sequential control writes 2021-07-09 7:29 ` Philippe Mathieu-Daudé @ 2021-07-13 2:41 ` Andrew Jeffery 0 siblings, 0 replies; 7+ messages in thread From: Andrew Jeffery @ 2021-07-13 2:41 UTC (permalink / raw) To: Philippe Mathieu-Daudé, Cameron Esfahani via Cc: Peter Maydell, qemu-arm, Cédric Le Goater, Joel Stanley On Fri, 9 Jul 2021, at 16:59, Philippe Mathieu-Daudé wrote: > On 7/9/21 7:31 AM, Andrew Jeffery wrote: > > The logic in the handling for the control register required toggling the > > enable state for writes to stick. Rework the condition chain to allow > > sequential writes that do not update the enable state. > > > > Fixes: 854123bf8d4b ("wdt: Add Aspeed watchdog device model") > > Signed-off-by: Andrew Jeffery <andrew@aj.id.au> > > --- > > hw/watchdog/wdt_aspeed.c | 2 ++ > > 1 file changed, 2 insertions(+) > > > > diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c > > index faa3d35fdf21..69c37af9a6e9 100644 > > --- a/hw/watchdog/wdt_aspeed.c > > +++ b/hw/watchdog/wdt_aspeed.c > > @@ -166,6 +166,8 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, > > } else if (!enable && aspeed_wdt_is_enabled(s)) { > > s->regs[WDT_CTRL] = data; > > timer_del(s->timer); > > + } else { > > + s->regs[WDT_CTRL] = data; > > What about simplifying by moving here: > > if (!enable && aspeed_wdt_is_enabled(s)) { > timer_del(s->timer); > } > I don't think that works, as aspeed_wdt_is_enabled() tests the value of s->regs[WDT_CTRL]. If you set it before you test then you end up in the wrong state. Andrew ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] watchdog: aspeed: Fix sequential control writes 2021-07-09 5:31 ` [PATCH 2/2] watchdog: aspeed: Fix sequential control writes Andrew Jeffery 2021-07-09 7:29 ` Philippe Mathieu-Daudé @ 2021-07-19 15:54 ` Cédric Le Goater 1 sibling, 0 replies; 7+ messages in thread From: Cédric Le Goater @ 2021-07-19 15:54 UTC (permalink / raw) To: Andrew Jeffery, qemu-devel; +Cc: peter.maydell, qemu-arm, joel On 7/9/21 7:31 AM, Andrew Jeffery wrote: > The logic in the handling for the control register required toggling the > enable state for writes to stick. Rework the condition chain to allow > sequential writes that do not update the enable state. > > Fixes: 854123bf8d4b ("wdt: Add Aspeed watchdog device model") > Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Reviewed-by: Cédric Le Goater <clg@kaod.org> > --- > hw/watchdog/wdt_aspeed.c | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c > index faa3d35fdf21..69c37af9a6e9 100644 > --- a/hw/watchdog/wdt_aspeed.c > +++ b/hw/watchdog/wdt_aspeed.c > @@ -166,6 +166,8 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, > } else if (!enable && aspeed_wdt_is_enabled(s)) { > s->regs[WDT_CTRL] = data; > timer_del(s->timer); > + } else { > + s->regs[WDT_CTRL] = data; > } > break; > case WDT_RESET_WIDTH: > ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2021-07-19 15:55 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2021-07-09 5:31 [PATCH 0/2] wdt_aspeed: Fix behaviour of control register Andrew Jeffery 2021-07-09 5:31 ` [PATCH 1/2] watchdog: aspeed: Sanitize control register values Andrew Jeffery 2021-07-19 15:53 ` Cédric Le Goater 2021-07-09 5:31 ` [PATCH 2/2] watchdog: aspeed: Fix sequential control writes Andrew Jeffery 2021-07-09 7:29 ` Philippe Mathieu-Daudé 2021-07-13 2:41 ` Andrew Jeffery 2021-07-19 15:54 ` Cédric Le Goater
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).