Re: [PATCH v4 4/7] clocksource: dw_apb_timer: Set clockevent any-possible-CPU mask

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

 



Daniel,

On Thu, May 21, 2020 at 03:53:17AM +0300, Serge Semin wrote:
> Currently the DW APB Timer driver binds all clockevent timers to
> CPU #0. This isn't good for multiple reasons. First of all seeing
> the device is placed on APB bus (which makes it accessible from any
> CPU core), accessible over MMIO and having the DYNIRQ flag set we
> can be sure that manually binding the timer to any CPU just isn't
> correct. By doing so we just set an extra limitation on device usage.
> This also doesn't reflect the device actual capability, since by
> setting the IRQ affinity we can make it virtually local to any CPU.
> Secondly imagine if you had a real CPU-local timer with the same
> rating and the same CPU-affinity. In this case if DW APB timer was
> registered first, then due to the clockevent framework tick-timer
> selection procedure we'll end up with the real CPU-local timer being
> left unselected for clock-events tracking. But on most of the platforms
> (MIPS/ARM/etc) such timers are normally embedded into the CPU core and
> are accessible with much better performance then devices placed on APB.
> For instance in MIPS architectures there is r4k-timer, which is
> CPU-local, assigned with the same rating, and normally its
> clockevent device is registered after the platform-specific one.
> 
> So in order to fix all of these issues lets set the DW APB clockevent
> timer cpumask to be 'cpu_possible_mask'. By doing so the clockevent
> framework would prefer to select the real CPU-local timer instead
> of DW APB one. Otherwise if there is no other than DW APB device for
> clockevents tracking then it will be selected.

Hm, seems to me it has been a mistake to remove the CPU affiliation for the
timers since x86 has got a specific use-case with assigning the timers to all
detected CPUs. Though for our needs we don't need this feature. I'll make the
affiliation optional then. Like this:

> dw_apb_clockevent_init(int cpu, const char *name, unsigned rating,
>                      void __iomem *base, int irq, unsigned long freq)
> {
> ...
>       dw_ced->ced.cpumask = cpu < 0 ? cpu_possible_mask : cpumask_of(cpu);
> ...
> }

DW APB Timer OF-based devices won't make the timer affiliated to the CPU #0, but
to any possible CPU by passing -1 to the dw_apb_clockevent_init():
--- drivers/clocksource/dw_apb_timer_of.c
+++ drivers/clocksource/dw_apb_timer_of.c
-       ced = dw_apb_clockevent_init(0, event_timer->name, 300, iobase, irq,
                                     rate);
+       ced = dw_apb_clockevent_init(-1, event_timer->name, 300, iobase, irq,
                                     rate);

What do you think?

-Sergey

> 
> Signed-off-by: Serge Semin <Sergey.Semin@xxxxxxxxxxxxxxxxxxxx>
> Cc: Alexey Malahov <Alexey.Malahov@xxxxxxxxxxxxxxxxxxxx>
> Cc: Thomas Bogendoerfer <tsbogend@xxxxxxxxxxxxxxxx>
> Cc: Paul Burton <paulburton@xxxxxxxxxx>
> Cc: Ralf Baechle <ralf@xxxxxxxxxxxxxx>
> Cc: Alessandro Zummo <a.zummo@xxxxxxxxxxxx>
> Cc: Alexandre Belloni <alexandre.belloni@xxxxxxxxxxx>
> Cc: Arnd Bergmann <arnd@xxxxxxxx>
> Cc: Rob Herring <robh+dt@xxxxxxxxxx>
> Cc: linux-mips@xxxxxxxxxxxxxxx
> Cc: linux-rtc@xxxxxxxxxxxxxxx
> Cc: devicetree@xxxxxxxxxxxxxxx
> ---
>  drivers/clocksource/dw_apb_timer.c    | 18 +++++++-----------
>  drivers/clocksource/dw_apb_timer_of.c |  3 +--
>  include/linux/dw_apb_timer.h          |  2 +-
>  3 files changed, 9 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c
> index b207a77b0831..8ebb43916423 100644
> --- a/drivers/clocksource/dw_apb_timer.c
> +++ b/drivers/clocksource/dw_apb_timer.c
> @@ -106,6 +106,7 @@ static irqreturn_t dw_apb_clockevent_irq(int irq, void *data)
>  		dw_ced->eoi(&dw_ced->timer);
>  
>  	evt->event_handler(evt);
> +
>  	return IRQ_HANDLED;
>  }
>  
> @@ -123,8 +124,7 @@ static int apbt_shutdown(struct clock_event_device *evt)
>  	struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
>  	u32 ctrl;
>  
> -	pr_debug("%s CPU %d state=shutdown\n", __func__,
> -		 cpumask_first(evt->cpumask));
> +	pr_debug("%s state=shutdown\n", __func__);
>  
>  	ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
>  	ctrl &= ~APBTMR_CONTROL_ENABLE;
> @@ -137,8 +137,7 @@ static int apbt_set_oneshot(struct clock_event_device *evt)
>  	struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
>  	u32 ctrl;
>  
> -	pr_debug("%s CPU %d state=oneshot\n", __func__,
> -		 cpumask_first(evt->cpumask));
> +	pr_debug("%s state=oneshot\n", __func__);
>  
>  	ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
>  	/*
> @@ -170,8 +169,7 @@ static int apbt_set_periodic(struct clock_event_device *evt)
>  	unsigned long period = DIV_ROUND_UP(dw_ced->timer.freq, HZ);
>  	u32 ctrl;
>  
> -	pr_debug("%s CPU %d state=periodic\n", __func__,
> -		 cpumask_first(evt->cpumask));
> +	pr_debug("%s state=periodic\n", __func__);
>  
>  	ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
>  	ctrl |= APBTMR_CONTROL_MODE_PERIODIC;
> @@ -194,8 +192,7 @@ static int apbt_resume(struct clock_event_device *evt)
>  {
>  	struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
>  
> -	pr_debug("%s CPU %d state=resume\n", __func__,
> -		 cpumask_first(evt->cpumask));
> +	pr_debug("%s state=resume\n", __func__);
>  
>  	apbt_enable_int(&dw_ced->timer);
>  	return 0;
> @@ -222,7 +219,6 @@ static int apbt_next_event(unsigned long delta,
>  /**
>   * dw_apb_clockevent_init() - use an APB timer as a clock_event_device
>   *
> - * @cpu:	The CPU the events will be targeted at.
>   * @name:	The name used for the timer and the IRQ for it.
>   * @rating:	The rating to give the timer.
>   * @base:	I/O base for the timer registers.
> @@ -237,7 +233,7 @@ static int apbt_next_event(unsigned long delta,
>   * releasing the IRQ.
>   */
>  struct dw_apb_clock_event_device *
> -dw_apb_clockevent_init(int cpu, const char *name, unsigned rating,
> +dw_apb_clockevent_init(const char *name, unsigned int rating,
>  		       void __iomem *base, int irq, unsigned long freq)
>  {
>  	struct dw_apb_clock_event_device *dw_ced =
> @@ -257,7 +253,7 @@ dw_apb_clockevent_init(int cpu, const char *name, unsigned rating,
>  	dw_ced->ced.max_delta_ticks = 0x7fffffff;
>  	dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced);
>  	dw_ced->ced.min_delta_ticks = 5000;
> -	dw_ced->ced.cpumask = cpumask_of(cpu);
> +	dw_ced->ced.cpumask = cpu_possible_mask;
>  	dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC |
>  				CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
>  	dw_ced->ced.set_state_shutdown = apbt_shutdown;
> diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c
> index 8c28b127759f..0a2505b323d7 100644
> --- a/drivers/clocksource/dw_apb_timer_of.c
> +++ b/drivers/clocksource/dw_apb_timer_of.c
> @@ -73,8 +73,7 @@ static void __init add_clockevent(struct device_node *event_timer)
>  
>  	timer_get_base_and_rate(event_timer, &iobase, &rate);
>  
> -	ced = dw_apb_clockevent_init(0, event_timer->name, 300, iobase, irq,
> -				     rate);
> +	ced = dw_apb_clockevent_init(event_timer->name, 300, iobase, irq, rate);
>  	if (!ced)
>  		panic("Unable to initialise clockevent device");
>  
> diff --git a/include/linux/dw_apb_timer.h b/include/linux/dw_apb_timer.h
> index 82ebf9223948..689022bc8d17 100644
> --- a/include/linux/dw_apb_timer.h
> +++ b/include/linux/dw_apb_timer.h
> @@ -39,7 +39,7 @@ void dw_apb_clockevent_resume(struct dw_apb_clock_event_device *dw_ced);
>  void dw_apb_clockevent_stop(struct dw_apb_clock_event_device *dw_ced);
>  
>  struct dw_apb_clock_event_device *
> -dw_apb_clockevent_init(int cpu, const char *name, unsigned rating,
> +dw_apb_clockevent_init(const char *name, unsigned int rating,
>  		       void __iomem *base, int irq, unsigned long freq);
>  struct dw_apb_clocksource *
>  dw_apb_clocksource_init(unsigned rating, const char *name, void __iomem *base,
> -- 
> 2.25.1
> 



[Index of Archives]     [Linux Sound]     [ALSA Users]     [ALSA Devel]     [Linux Audio Users]     [Linux Media]     [Kernel]     [Gimp]     [Yosemite News]     [Linux Media]

  Powered by Linux