[PATCH qemu] wdt: aspeed: Fix failed reboot due to timer miscalculation
Joel Stanley
joel at jms.id.au
Thu Nov 3 16:39:16 AEDT 2016
On Thu, Nov 3, 2016 at 3:57 PM, Andrew Jeffery <andrew at aj.id.au> wrote:
> The implementation was incorrectly scaling the reload value by
> nanoseconds per second. In reality the span represented by the reload
> value is determined by the selected clock, either APB or 1MHz.
>
> Test the selected clock and apply the appropriate scaling, then convert to
> nanoseconds for the timer infrastructure. Note that the APB rate is hard-coded
> and reflects the value used by the timer controller, and isn't necessarily an
> accurate representation of the clock configuration programmed in the SCU.
>
> Signed-off-by: Andrew Jeffery <andrew at aj.id.au>
> ---
>
> I'm hesitant to send this upstream as I don't like the idea of hardcoding the
> clock rates in the way that we have (i.e. the timer as well). I think we should
> rework the timer and the watchdog to derive their clocks from the SCU, but
> that's more work than I'm willing to put in to get reboots working.
The watchdog driver as upstreamed always runs from a 1MHz clock.
It looks like the model needs to be updated with this knowledge. Then
we don't need to worry about hardcoding. We print a warning if the bit
in the register that says "use 1MHz" is cleared.
Cheers,
Joel
>
> hw/watchdog/wdt_aspeed.c | 28 +++++++++++++++++++++++-----
> 1 file changed, 23 insertions(+), 5 deletions(-)
>
> diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c
> index 2ec01769b745..c81608d6ac74 100644
> --- a/hw/watchdog/wdt_aspeed.c
> +++ b/hw/watchdog/wdt_aspeed.c
> @@ -61,11 +61,14 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size)
>
> }
>
> +#define PCLK_HZ 24000000
> +
> static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
> unsigned size)
> {
> AspeedWDTState *s = ASPEED_WDT(opaque);
> bool en = data & BIT(0);
> + bool pclk = !(data & BIT(4));
>
> switch (offset) {
> case WDT_STATUS:
> @@ -78,21 +81,36 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
> break;
> case WDT_RESTART:
> if ((data & 0xFFFF) == 0x4755) {
> + uint32_t reload;
> +
> s->reg_status = s->reg_reload_value;
>
> + if (pclk) {
> + reload = muldiv64(s->reg_reload_value, NANOSECONDS_PER_SECOND,
> + PCLK_HZ) ;
> + } else {
> + reload = s->reg_reload_value * 1000;
> + }
> +
> if (s->enabled) {
> timer_mod(s->timer,
> - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> - s->reg_reload_value * NANOSECONDS_PER_SECOND);
> + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + reload);
> }
> }
> break;
> case WDT_CTRL:
> if (en && !s->enabled) {
> + uint32_t reload;
> +
> + if (pclk) {
> + reload = muldiv64(s->reg_reload_value, NANOSECONDS_PER_SECOND,
> + PCLK_HZ) ;
> + } else {
> + reload = s->reg_reload_value * 1000;
> + }
> +
> s->enabled = true;
> - timer_mod(s->timer,
> - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> - s->reg_reload_value * NANOSECONDS_PER_SECOND);
> + timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + reload);
> }
> else if (!en && s->enabled) {
> s->enabled = false;
> --
> 2.7.4
>
More information about the openbmc
mailing list