All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sergei Shtylyov <sshtylyov@ru.mvista.com>
To: tglx@linutronix.de
Cc: linuxppc-dev@ozlabs.org, greg.weeks@timesys.com
Subject: [PATCH] PowerPC: clockevents and HRT support
Date: Wed, 8 Nov 2006 01:05:08 +0400	[thread overview]
Message-ID: <200611080005.08633.sshtylyov@ru.mvista.com> (raw)

Add PowerPC decrementer clock event driver and enable HRT.
Every effort has been made to support the different implementations of the
decrementer: the classic one (with 970 series variation), 40x and Book E
specific ones.

I had to make CONFIG_GENERIC_CLOCKEVENTS option selectable for the
compatibility reasons -- this option is not compatible with the PPC64
deterministic time accounting.

Thanks to Daniel Walker and Thomas Gleixner for suggestions they made...

Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>

---
This patch has been reworked against 2.6.18-hrt-dyntick2 patchset and
tested on the classic and Book E 32-bit CPUs.

CONFIG_PPC_MULTIPLATFORM was the best option I was able to come up with
to cover machines built on 970 series CPU...

 arch/powerpc/Kconfig       |   13 ++++
 arch/powerpc/kernel/time.c |  121 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 133 insertions(+), 1 deletion(-)

Index: linux-2.6/arch/powerpc/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/Kconfig
+++ linux-2.6/arch/powerpc/Kconfig
@@ -281,7 +281,7 @@ config PPC_STD_MMU_32
 
 config VIRT_CPU_ACCOUNTING
 	bool "Deterministic task and CPU time accounting"
-	depends on PPC64
+	depends on PPC64 && !GENERIC_CLOCKEVENTS
 	default y
 	help
 	  Select this option to enable more accurate task and CPU time
@@ -599,6 +599,17 @@ config HIGHMEM
 	depends on PPC32
 
 source kernel/Kconfig.hz
+
+config GENERIC_CLOCKEVENTS
+	bool "Clock event devices support"
+	default n
+	help
+	  Enable support for the clock event devices necessary for the
+	  high-resolution timers and the tickless system support.
+	  NOTE: This is not compatible with the deterministic time accounting
+	  option on PPC64.
+
+source kernel/time/Kconfig
 source kernel/Kconfig.preempt
 source "fs/Kconfig.binfmt"
 
Index: linux-2.6/arch/powerpc/kernel/time.c
===================================================================
--- linux-2.6.orig/arch/powerpc/kernel/time.c
+++ linux-2.6/arch/powerpc/kernel/time.c
@@ -51,6 +51,7 @@
 #include <linux/rtc.h>
 #include <linux/jiffies.h>
 #include <linux/posix-timers.h>
+#include <linux/clockchips.h>
 
 #include <asm/io.h>
 #include <asm/processor.h>
@@ -124,6 +125,80 @@ unsigned long ppc_tb_freq;
 static u64 tb_last_jiffy __cacheline_aligned_in_smp;
 static DEFINE_PER_CPU(u64, last_jiffy);
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#define DECREMENTER_MAX 0xffffffff
+#else
+#define DECREMENTER_MAX 0x7fffffff /* setting MSB triggers an interrupt */
+#endif
+
+struct decrementer_device {
+       struct clock_event_device device;
+       int mode;
+};
+
+static void decrementer_set_next_event(unsigned long evt,
+				       struct clock_event_device *dev)
+{
+#if defined(CONFIG_40x)
+	mtspr(SPRN_PIT, evt);	/* 40x has a hidden PIT auto-reload register */
+#elif defined(CONFIG_BOOKE)
+	mtspr(SPRN_DECAR, evt); /* Book E  has separate auto-reload register */
+	set_dec(evt);
+#else
+	set_dec(evt - 1);	/* Classic decrementer interrupts at -1 */
+#endif
+}
+
+static void decrementer_set_mode(enum	clock_event_mode mode,
+				 struct clock_event_device *dev)
+{
+	struct decrementer_device *decrementer;
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+	u32 tcr = mfspr(SPRN_TCR);
+
+	if (mode == CLOCK_EVT_PERIODIC)
+		tcr |=  TCR_ARE;
+	else
+		tcr &= ~TCR_ARE;
+
+	mtspr(SPRN_TCR, tcr);
+#endif
+	decrementer = container_of(dev, struct decrementer_device, device);
+	decrementer->mode = mode;
+
+	if (mode == CLOCK_EVT_PERIODIC)
+		decrementer_set_next_event(tb_ticks_per_jiffy, dev);
+}
+
+static struct clock_event_device decrementer_template = {
+	.name		= "decrementer",
+	.capabilities	= CLOCK_CAP_PROFILE | CLOCK_CAP_UPDATE |
+			  CLOCK_CAP_NEXTEVT,
+	.shift		= 32,
+	.set_mode	= decrementer_set_mode,
+	.set_next_event	= decrementer_set_next_event,
+};
+
+static DEFINE_PER_CPU(struct decrementer_device, decrementers);
+
+static void register_decrementer(void)
+{
+	int cpu = smp_processor_id();
+	struct decrementer_device *decrementer = &per_cpu(decrementers, cpu);
+
+	decrementer->device = decrementer_template;
+
+	/* We only want do_timer() to be called on a boot CPU. */
+	if (cpu == boot_cpuid) 
+		decrementer->device.capabilities |= CLOCK_CAP_TICK;
+
+	register_local_clockevent(&decrementer->device);
+}
+
+#endif /* CONFIG_GENERIC_CLOCKEVENTS */
+
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 /*
  * Factors for converting from cputime_t (timebase ticks) to
@@ -340,6 +415,9 @@ void snapshot_timebase(void)
 {
 	__get_cpu_var(last_jiffy) = get_tb();
 	snapshot_purr();
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+	register_decrementer();
+#endif
 }
 
 void __delay(unsigned long loops)
@@ -495,7 +573,28 @@ void timer_interrupt(struct pt_regs * re
 
 	irq_enter();
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+#ifdef CONFIG_PPC_MULTIPLATFORM
+	/*
+	 * We must write a positive value to the decrementer to clear
+	 * the interrupt on the IBM 970 CPU series.  In periodic mode,
+	 * this happens when the decrementer gets reloaded later, but
+	 * in one-shot mode, we have to do it here since an event handler
+	 * may skip loading the new value...
+	 */
+	if (per_cpu(decrementers, cpu).mode != CLOCK_EVT_PERIODIC)
+		set_dec(DECREMENTER_MAX);
+#endif
+	/*
+	 * We can't disable the decrementer, so in the period between
+	 * CPU being marked offline and calling stop-self, it's taking
+	 * timer interrupts...
+	 */
+	if (!cpu_is_offline(cpu))
+		per_cpu(decrementers, cpu).device.event_handler(regs);
+#else
 	profile_tick(CPU_PROFILING, regs);
+#endif
 	calculate_steal_time();
 
 #ifdef CONFIG_PPC_ISERIES
@@ -510,6 +609,7 @@ void timer_interrupt(struct pt_regs * re
 		if (__USE_RTC() && per_cpu(last_jiffy, cpu) >= 1000000000)
 			per_cpu(last_jiffy, cpu) -= 1000000000;
 
+#ifndef CONFIG_GENERIC_CLOCKEVENTS
 		/*
 		 * We cannot disable the decrementer, so in the period
 		 * between this cpu's being marked offline in cpu_online_map
@@ -519,6 +619,7 @@ void timer_interrupt(struct pt_regs * re
 		 */
 		if (!cpu_is_offline(cpu))
 			account_process_time(regs);
+#endif
 
 		/*
 		 * No need to check whether cpu is offline here; boot_cpuid
@@ -531,14 +632,23 @@ void timer_interrupt(struct pt_regs * re
 		tb_next_jiffy = tb_last_jiffy + tb_ticks_per_jiffy;
 		if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) {
 			tb_last_jiffy = tb_next_jiffy;
+#ifndef CONFIG_GENERIC_CLOCKEVENTS
 			do_timer(1);
+#endif
 			timer_check_rtc();
 		}
 		write_sequnlock(&xtime_lock);
 	}
 	
 	next_dec = tb_ticks_per_jiffy - ticks;
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+#if !defined(CONFIG_40x) && !defined(CONFIG_BOOKE)
+	if (per_cpu(decrementers, cpu).mode == CLOCK_EVT_PERIODIC)
+		set_dec(next_dec - 1);
+#endif
+#else
 	set_dec(next_dec);
+#endif
 
 #ifdef CONFIG_PPC_ISERIES
 	if (hvlpevent_is_pending())
@@ -787,8 +897,19 @@ void __init time_init(void)
 	tb_to_ns_scale = scale;
 	tb_to_ns_shift = shift;
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+	decrementer_template.mult = div_sc(ppc_tb_freq, NSEC_PER_SEC,
+					   decrementer_template.shift);
+	decrementer_template.max_delta_ns =
+		clockevent_delta2ns(DECREMENTER_MAX, &decrementer_template);
+	decrementer_template.min_delta_ns =
+		clockevent_delta2ns(0xf, &decrementer_template);
+
+	register_decrementer();
+#else
 	/* Not exact, but the timer interrupt takes care of this */
 	set_dec(tb_ticks_per_jiffy);
+#endif
 }
 
 #define FEBRUARY	2

             reply	other threads:[~2006-11-07 21:05 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-11-07 21:05 Sergei Shtylyov [this message]
2006-11-07 22:36 ` [PATCH] PowerPC: clockevents and HRT support Benjamin Herrenschmidt
2006-11-07 22:44   ` Sergei Shtylyov
2006-11-07 23:04     ` Benjamin Herrenschmidt
2006-11-07 23:21       ` Sergei Shtylyov
2006-11-08  0:18         ` Benjamin Herrenschmidt
2006-11-08  1:19           ` Mark A. Greer
2006-11-08  2:06             ` Benjamin Herrenschmidt
2006-11-08 14:14               ` Sergei Shtylyov
2006-11-08  2:00     ` Paul Mackerras
2006-11-08 14:21       ` Sergei Shtylyov
2006-11-10  8:32         ` Paul Mackerras
2006-11-10 14:08           ` Sergei Shtylyov
2006-11-10 23:52             ` Paul Mackerras
2006-11-12 18:30               ` Sergei Shtylyov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200611080005.08633.sshtylyov@ru.mvista.com \
    --to=sshtylyov@ru.mvista.com \
    --cc=greg.weeks@timesys.com \
    --cc=linuxppc-dev@ozlabs.org \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.