Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 56942fec authored by Jonathan Austin's avatar Jonathan Austin Committed by Russell King
Browse files

ARM: 7538/1: delay: add registration mechanism for delay timer sources



The current timer-based delay loop relies on the architected timer to
initiate the switch away from the polling-based implementation. This is
unfortunate for platforms without the architected timers but with a
suitable delay source (that is, constant frequency, always powered-up
and ticking as long as the CPUs are online).

This patch introduces a registration mechanism for the delay timer
(which provides an unconditional read_current_timer implementation) and
updates the architected timer code to use the new interface.

Reviewed-by: default avatarStephen Boyd <sboyd@codeaurora.org>
Signed-off-by: default avatarJonathan Austin <jonathan.austin@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent a1b2dde7
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -5,7 +5,6 @@
#include <linux/clocksource.h>
#include <linux/clocksource.h>


#ifdef CONFIG_ARM_ARCH_TIMER
#ifdef CONFIG_ARM_ARCH_TIMER
#define ARCH_HAS_READ_CURRENT_TIMER
int arch_timer_of_register(void);
int arch_timer_of_register(void);
int arch_timer_sched_clock_init(void);
int arch_timer_sched_clock_init(void);
struct timecounter *arch_timer_get_timecounter(void);
struct timecounter *arch_timer_get_timecounter(void);
+9 −0
Original line number Original line Diff line number Diff line
@@ -15,6 +15,11 @@


#ifndef __ASSEMBLY__
#ifndef __ASSEMBLY__


struct delay_timer {
	unsigned long (*read_current_timer)(void);
	unsigned long freq;
};

extern struct arm_delay_ops {
extern struct arm_delay_ops {
	void (*delay)(unsigned long);
	void (*delay)(unsigned long);
	void (*const_udelay)(unsigned long);
	void (*const_udelay)(unsigned long);
@@ -56,6 +61,10 @@ extern void __loop_delay(unsigned long loops);
extern void __loop_udelay(unsigned long usecs);
extern void __loop_udelay(unsigned long usecs);
extern void __loop_const_udelay(unsigned long);
extern void __loop_const_udelay(unsigned long);


/* Delay-loop timer registration. */
#define ARCH_HAS_READ_CURRENT_TIMER
extern void register_current_timer_delay(const struct delay_timer *timer);

#endif /* __ASSEMBLY__ */
#endif /* __ASSEMBLY__ */


#endif /* defined(_ARM_DELAY_H) */
#endif /* defined(_ARM_DELAY_H) */
+0 −6
Original line number Original line Diff line number Diff line
@@ -12,15 +12,9 @@
#ifndef _ASMARM_TIMEX_H
#ifndef _ASMARM_TIMEX_H
#define _ASMARM_TIMEX_H
#define _ASMARM_TIMEX_H


#include <asm/arch_timer.h>
#include <mach/timex.h>
#include <mach/timex.h>


typedef unsigned long cycles_t;
typedef unsigned long cycles_t;

#ifdef ARCH_HAS_READ_CURRENT_TIMER
#define get_cycles()	({ cycles_t c; read_current_timer(&c) ? 0 : c; })
#define get_cycles()	({ cycles_t c; read_current_timer(&c) ? 0 : c; })
#else
#define get_cycles()	(0)
#endif


#endif
#endif
+8 −9
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <linux/io.h>


#include <asm/cputype.h>
#include <asm/cputype.h>
#include <asm/delay.h>
#include <asm/localtimer.h>
#include <asm/localtimer.h>
#include <asm/arch_timer.h>
#include <asm/arch_timer.h>
#include <asm/system_info.h>
#include <asm/system_info.h>
@@ -39,8 +40,7 @@ enum ppi_nr {
static int arch_timer_ppi[MAX_TIMER_PPI];
static int arch_timer_ppi[MAX_TIMER_PPI];


static struct clock_event_device __percpu **arch_timer_evt;
static struct clock_event_device __percpu **arch_timer_evt;

static struct delay_timer arch_delay_timer;
extern void init_current_timer_delay(unsigned long freq);


static bool arch_timer_use_virtual = true;
static bool arch_timer_use_virtual = true;


@@ -325,12 +325,9 @@ static cycle_t arch_counter_read(struct clocksource *cs)
	return arch_counter_get_cntpct();
	return arch_counter_get_cntpct();
}
}


int read_current_timer(unsigned long *timer_val)
static unsigned long arch_timer_read_current_timer(void)
{
{
	if (!arch_timer_rate)
	return arch_counter_get_cntpct();
		return -ENXIO;
	*timer_val = arch_counter_get_cntpct();
	return 0;
}
}


static cycle_t arch_counter_read_cc(const struct cyclecounter *cc)
static cycle_t arch_counter_read_cc(const struct cyclecounter *cc)
@@ -441,11 +438,13 @@ static int __init arch_timer_register(void)
		arch_timer_global_evt.cpumask = cpumask_of(0);
		arch_timer_global_evt.cpumask = cpumask_of(0);
		err = arch_timer_setup(&arch_timer_global_evt);
		err = arch_timer_setup(&arch_timer_global_evt);
	}
	}

	if (err)
	if (err)
		goto out_free_irq;
		goto out_free_irq;


	init_current_timer_delay(arch_timer_rate);
	/* Use the architected timer for the delay loop. */
	arch_delay_timer.read_current_timer = &arch_timer_read_current_timer;
	arch_delay_timer.freq = arch_timer_rate;
	register_current_timer_delay(&arch_delay_timer);
	return 0;
	return 0;


out_free_irq:
out_free_irq:
+26 −8
Original line number Original line Diff line number Diff line
@@ -34,7 +34,18 @@ struct arm_delay_ops arm_delay_ops = {
	.udelay		= __loop_udelay,
	.udelay		= __loop_udelay,
};
};


#ifdef ARCH_HAS_READ_CURRENT_TIMER
static const struct delay_timer *delay_timer;
static bool delay_calibrated;

int read_current_timer(unsigned long *timer_val)
{
	if (!delay_timer)
		return -ENXIO;

	*timer_val = delay_timer->read_current_timer();
	return 0;
}

static void __timer_delay(unsigned long cycles)
static void __timer_delay(unsigned long cycles)
{
{
	cycles_t start = get_cycles();
	cycles_t start = get_cycles();
@@ -55,17 +66,24 @@ static void __timer_udelay(unsigned long usecs)
	__timer_const_udelay(usecs * UDELAY_MULT);
	__timer_const_udelay(usecs * UDELAY_MULT);
}
}


void __init init_current_timer_delay(unsigned long freq)
void __init register_current_timer_delay(const struct delay_timer *timer)
{
{
	if (!delay_calibrated) {
		pr_info("Switching to timer-based delay loop\n");
		pr_info("Switching to timer-based delay loop\n");
	lpj_fine			= freq / HZ;
		delay_timer			= timer;
		lpj_fine			= timer->freq / HZ;
		loops_per_jiffy			= lpj_fine;
		arm_delay_ops.delay		= __timer_delay;
		arm_delay_ops.delay		= __timer_delay;
		arm_delay_ops.const_udelay	= __timer_const_udelay;
		arm_delay_ops.const_udelay	= __timer_const_udelay;
		arm_delay_ops.udelay		= __timer_udelay;
		arm_delay_ops.udelay		= __timer_udelay;
		delay_calibrated		= true;
	} else {
		pr_info("Ignoring duplicate/late registration of read_current_timer delay\n");
	}
}
}


unsigned long __cpuinit calibrate_delay_is_known(void)
unsigned long __cpuinit calibrate_delay_is_known(void)
{
{
	delay_calibrated = true;
	return lpj_fine;
	return lpj_fine;
}
}
#endif