[PATCH 0/3] watchdog: honour hw_margin_ms property

Stefan Roese sr at denx.de
Thu Jun 4 10:41:50 CEST 2020


On 04.06.20 10:28, Rasmus Villemoes wrote:
> On 02/06/2020 17.38, Rasmus Villemoes wrote:
>> On 02/06/2020 16.53, Stefan Roese wrote:
>>> On 02.06.20 15:29, Rasmus Villemoes wrote:
>>>> On 16/03/2020 16.52, Rasmus Villemoes wrote:
>>>>> On 14/03/2020 13.04, Stefan Roese wrote:
>>>>>> On 13.03.20 17:04, Rasmus Villemoes wrote:
>>>>>
> 
>>>> But, as I suspected, I do have a problem when loading a compressed
>>>> kernel image - what I write above "so even in U-Boot proper, time as
>>>> measured by get_timer() ceases to pass after that point, so all the
>>>> WATCHDOG_RESET() calls from the inflate code effectively get ignored."
>>>> is indeed the case.
>>>>
>>>> So, what's the best way to proceed? Should there be a hook disabling the
>>>>    rate-limiting logic that bootm_disable_interrupts() can call? Or must
>>>> get_timer() always return a sensible result even with interrupts
>>>> disabled?
>>>
>>> Wouldn't it make sense to move the bootm_disable_interrupts() call to
>>> after loading and uncompressing the OS image? To right before jumping
>>> to the OS?
>>
>> No, because the point of disabling interrupts is that we may start
>> writing to physical address 0 (e.g. if that's the load= address in the
>> FIT image), which is also where the interrupt vectors reside - i.e.,
>> we're about to overwrite 0x900 (the decrementer interrupt vector), so if
>> we don't disable interrupts, we'll crash on the very next decrementer
>> interrupt (i.e., within one millisecond).

Ah, thanks for refreshing me on this.

> FWIW, the below very hacky patch makes get_timer() return sensible
> results on ppc even when interrupts are disabled, and hence ensures that
> the watchdog does get petted. It's obviously not meant for inclusion as
> is (it's prepared for being a proper config option, but for toying
> around it's easier to have it all in one file - also, I don't really
> like the name of the config knob). But it's also kind of expensive to do
> that do_div(), so I'm not sure I think this is even the right approach.

I agree. This does not look as its going into the right direction. But
thanks for working on this anyways.

> You previously rejected allowing the board to provide an override for
> the rate-limiting,

 From my memory, I "just" suggested working on a different, more generic
approach. But if this fails, I'm open to re-visit the options.

> and at least the "hw_margin_ms" parsing now solves
> part of what I wanted to use that for. What about implementing the
> rate-limiting instead in terms of get_ticks() (the hw_margin_ms can
> trivially be translated to a number of ticks at init time - there's
> already a usec_to_tick helper)? Are there any boards where get_ticks()
> doesn't return something sensible?

Could you please send a new version of a patch(set) to address these
issues by using the "override for the rate-limiting" or some other
idea you have right now for this? I'll review it soon'ish.

Thanks,
Stefan

> Rasmus
> 
> _Not_ for inclusion:
> 
> diff --git a/arch/powerpc/lib/interrupts.c b/arch/powerpc/lib/interrupts.c
> index 23ac5bca1e..e6b6a967ae 100644
> --- a/arch/powerpc/lib/interrupts.c
> +++ b/arch/powerpc/lib/interrupts.c
> @@ -10,11 +10,14 @@
>   #include <common.h>
>   #include <irq_func.h>
>   #include <asm/processor.h>
> +#include <div64.h>
>   #include <watchdog.h>
>   #ifdef CONFIG_LED_STATUS
>   #include <status_led.h>
>   #endif
> 
> +#define CONFIG_GET_TIMER_IRQ 1
> +
>   #ifndef CONFIG_MPC83XX_TIMER
>   #ifndef CONFIG_SYS_WATCHDOG_FREQ
>   #define CONFIG_SYS_WATCHDOG_FREQ (CONFIG_SYS_HZ / 2)
> @@ -39,8 +42,33 @@ static __inline__ void set_dec (unsigned long val)
>   }
>   #endif /* !CONFIG_MPC83XX_TIMER */
> 
> +static u64 irq_off_ticks = 0;
> +static int interrupts_enabled = 0;
> +static volatile ulong timestamp = 0;
> +
> +static u32 irq_off_msecs(void)
> +{
> +	u64 t;
> +	u32 d = get_tbclk();
> +
> +	if (!d)
> +		return 0;
> +	t = get_ticks() - irq_off_ticks;
> +	t *= 1000;
> +	do_div(t, d);
> +	return t;
> +}
> +
>   void enable_interrupts(void)
>   {
> +	ulong msr = get_msr ();
> +
> +	if (IS_ENABLED(CONFIG_GET_TIMER_IRQ) && !(msr & MSR_EE)) {
> +		/* Account for the time interrupts were off. */
> +		timestamp += irq_off_msecs();
> +		interrupts_enabled = 1;
> +	}
> +
>   	set_msr (get_msr () | MSR_EE);
>   }
> 
> @@ -50,6 +78,13 @@ int disable_interrupts(void)
>   	ulong msr = get_msr ();
> 
>   	set_msr (msr & ~MSR_EE);
> +
> +	if (IS_ENABLED(CONFIG_GET_TIMER_IRQ) && (msr & MSR_EE)) {
> +		/* Record when interrupts were disabled. */
> +		irq_off_ticks = get_ticks();
> +		interrupts_enabled = 0;
> +	}
> +
>   	return ((msr & MSR_EE) != 0);
>   }
> 
> @@ -61,13 +96,11 @@ int interrupt_init(void)
> 
>   	set_dec (decrementer_count);
> 
> -	set_msr (get_msr () | MSR_EE);
> +	enable_interrupts();
> 
>   	return (0);
>   }
> 
> -static volatile ulong timestamp = 0;
> -
>   void timer_interrupt(struct pt_regs *regs)
>   {
>   	/* call cpu specific function from $(CPU)/interrupts.c */
> @@ -90,6 +123,12 @@ void timer_interrupt(struct pt_regs *regs)
> 
>   ulong get_timer (ulong base)
>   {
> -	return (timestamp - base);
> +	ulong ts = timestamp;
> +
> +	/* If called within an irq-off section, account for the time since
> irqs were turned off. */
> +	if (IS_ENABLED(CONFIG_GET_TIMER_IRQ) && !interrupts_enabled)
> +		ts += irq_off_msecs();
> +
> +	return (ts - base);
>   }
>   #endif /* !CONFIG_MPC83XX_TIMER */
> 
> 
> 


Viele Grüße,
Stefan

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr at denx.de


More information about the U-Boot mailing list