All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tony Breeds <tony@bakeyournoodle.com>
To: <linuxppc-dev@ozlabs.org>, Paul Mackerras <paulus@samba.org>
Cc: Thomas Gleixner <tglx@linutronix.de>,
	Realtime Kernel <linux-rt-users@vger.kernel.org>
Subject: [PATCH 3/5] Implement clockevents driver for powerpc
Date: Wed, 19 Sep 2007 16:49:47 +1000	[thread overview]
Message-ID: <20070919064947.5EA57399911@thor> (raw)
In-Reply-To: <1190184586.867449.381310088392.qpush@thor>

Signed-off-by: Tony Breeds <tony@bakeyournoodle.com>

---

 arch/powerpc/Kconfig       |    3 
 arch/powerpc/kernel/smp.c  |    3 
 arch/powerpc/kernel/time.c |  134 +++++++++++++++++++++++++------------
 include/asm-powerpc/time.h |    1 
 4 files changed, 98 insertions(+), 43 deletions(-)

Index: working/arch/powerpc/Kconfig
===================================================================
--- working.orig/arch/powerpc/Kconfig
+++ working/arch/powerpc/Kconfig
@@ -30,6 +30,9 @@ config GENERIC_TIME
 config GENERIC_TIME_VSYSCALL
 	def_bool y
 
+config GENERIC_CLOCKEVENTS
+	def_bool y
+
 config GENERIC_HARDIRQS
 	bool
 	default y
Index: working/arch/powerpc/kernel/smp.c
===================================================================
--- working.orig/arch/powerpc/kernel/smp.c
+++ working/arch/powerpc/kernel/smp.c
@@ -560,6 +560,9 @@ int __devinit start_secondary(void *unus
 	if (system_state > SYSTEM_BOOTING)
 		snapshot_timebase();
 
+	/* FIXME: should be in if() above */
+	secondary_cpu_time_init();
+
 	spin_lock(&call_lock);
 	cpu_set(cpu, cpu_online_map);
 	spin_unlock(&call_lock);
Index: working/arch/powerpc/kernel/time.c
===================================================================
--- working.orig/arch/powerpc/kernel/time.c
+++ working/arch/powerpc/kernel/time.c
@@ -76,6 +76,7 @@
 
 /* powerpc clocksource/clockevent code */
 
+#include <linux/clockchips.h>
 #include <linux/clocksource.h>
 
 static cycle_t timebase_read(void);
@@ -90,6 +91,27 @@ static struct clocksource clocksource_ti
 	.read         = timebase_read,
 };
 
+#define DECREMENTER_MAX	0x7fffffff
+
+static int decrementer_set_next_event(unsigned long evt,
+				      struct clock_event_device *dev);
+static void decrementer_set_mode(enum clock_event_mode mode,
+				 struct clock_event_device *dev);
+
+static struct clock_event_device decrementer_clockevent = {
+       .name           = "decrementer",
+       .rating         = 200,
+       .shift          = 32,
+       .mult           = 0,	/* To be filled in */
+       .irq            = -1,
+       .set_next_event = decrementer_set_next_event,
+       .set_mode       = decrementer_set_mode,
+       .features       = CLOCK_EVT_FEAT_ONESHOT,
+};
+
+static DEFINE_PER_CPU(struct clock_event_device, decrementers);
+void init_decrementer_clockevent(void);
+
 #ifdef CONFIG_PPC_ISERIES
 static unsigned long __initdata iSeries_recal_titan;
 static signed long __initdata iSeries_recal_tb;
@@ -510,10 +532,12 @@ void __init iSeries_time_init_early(void
 void timer_interrupt(struct pt_regs * regs)
 {
 	struct pt_regs *old_regs;
-	int next_dec;
 	int cpu = smp_processor_id();
-	unsigned long ticks;
-	u64 tb_next_jiffy;
+	struct clock_event_device *evt = &per_cpu(decrementers, cpu);
+
+	/* Ensure a positive value is written to the decrementer, or else
+	 * some CPUs will continuue to take decrementer exceptions */
+	set_dec(DECREMENTER_MAX);
 
 #ifdef CONFIG_PPC32
 	if (atomic_read(&ppc_n_lost_interrupts) != 0)
@@ -523,7 +547,6 @@ void timer_interrupt(struct pt_regs * re
 	old_regs = set_irq_regs(regs);
 	irq_enter();
 
-	profile_tick(CPU_PROFILING);
 	calculate_steal_time();
 
 #ifdef CONFIG_PPC_ISERIES
@@ -531,44 +554,20 @@ void timer_interrupt(struct pt_regs * re
 		get_lppaca()->int_dword.fields.decr_int = 0;
 #endif
 
-	while ((ticks = tb_ticks_since(per_cpu(last_jiffy, cpu)))
-	       >= tb_ticks_per_jiffy) {
-		/* Update last_jiffy */
-		per_cpu(last_jiffy, cpu) += tb_ticks_per_jiffy;
-		/* Handle RTCL overflow on 601 */
-		if (__USE_RTC() && per_cpu(last_jiffy, cpu) >= 1000000000)
-			per_cpu(last_jiffy, cpu) -= 1000000000;
-
-		/*
-		 * We cannot disable the decrementer, so in the period
-		 * between this cpu's being marked offline in cpu_online_map
-		 * and calling stop-self, it is taking timer interrupts.
-		 * Avoid calling into the scheduler rebalancing code if this
-		 * is the case.
-		 */
-		if (!cpu_is_offline(cpu))
-			account_process_time(regs);
-
-		/*
-		 * No need to check whether cpu is offline here; boot_cpuid
-		 * should have been fixed up by now.
-		 */
-		if (cpu != boot_cpuid)
-			continue;
+	/*
+	 * We cannot disable the decrementer, so in the period
+	 * between this cpu's being marked offline in cpu_online_map
+	 * and calling stop-self, it is taking timer interrupts.
+	 * Avoid calling into the scheduler rebalancing code if this
+	 * is the case.
+	 */
+	if (!cpu_is_offline(cpu))
+		account_process_time(regs);
 
-		write_seqlock(&xtime_lock);
-		tb_next_jiffy = tb_last_jiffy + tb_ticks_per_jiffy;
-		if (__USE_RTC() && tb_next_jiffy >= 1000000000)
-			tb_next_jiffy -= 1000000000;
-		if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) {
-			tb_last_jiffy = tb_next_jiffy;
-			do_timer(1);
-		}
-		write_sequnlock(&xtime_lock);
-	}
-	
-	next_dec = tb_ticks_per_jiffy - ticks;
-	set_dec(next_dec);
+	if (evt->event_handler)
+		evt->event_handler(evt);
+	else
+		evt->set_next_event(DECREMENTER_MAX, evt);
 
 #ifdef CONFIG_PPC_ISERIES
 	if (firmware_has_feature(FW_FEATURE_ISERIES) && hvlpevent_is_pending())
@@ -781,8 +780,58 @@ void __init clocksource_init(void)
 	printk(KERN_INFO "clocksource: %s mult[%x] shift[%d] registered\n",
 	       clocksource_timebase.name,
 	       clocksource_timebase.mult, clocksource_timebase.shift);
+
+	return;
+}
+
+static int decrementer_set_next_event(unsigned long evt,
+				      struct clock_event_device *dev)
+{
+	set_dec(evt);
+	return 0;
+}
+
+static void decrementer_set_mode(enum clock_event_mode mode,
+				 struct clock_event_device *dev)
+{
+	if (mode != CLOCK_EVT_MODE_ONESHOT)
+		decrementer_set_next_event(DECREMENTER_MAX, dev);
+}
+
+static void register_decrementer_clockevent(int cpu)
+{
+	struct clock_event_device *dec = &per_cpu(decrementers, cpu);
+
+	*dec = decrementer_clockevent;
+	dec->cpumask = cpumask_of_cpu(cpu);
+
+	printk(KERN_ERR "clockevent: %s mult[%lx] shift[%d] cpu[%d]\n",
+	       dec->name, dec->mult, dec->shift, cpu);
+
+	clockevents_register_device(dec);
+}
+
+void init_decrementer_clockevent(void)
+{
+	int cpu = smp_processor_id();
+
+	decrementer_clockevent.mult = div_sc(ppc_tb_freq, NSEC_PER_SEC,
+					     decrementer_clockevent.shift);
+	decrementer_clockevent.max_delta_ns =
+		clockevent_delta2ns(DECREMENTER_MAX, &decrementer_clockevent);
+	decrementer_clockevent.min_delta_ns = 1000;
+
+	register_decrementer_clockevent(cpu);
 }
 
+void secondary_cpu_time_init(void)
+{
+	/* FIME: Should make unrelatred change to move snapshot_timebase
+	 * call here ! */
+	register_decrementer_clockevent(smp_processor_id());
+}
+
+
 /* This function is only called on the boot processor */
 void __init time_init(void)
 {
@@ -898,8 +947,7 @@ void __init time_init(void)
 #endif
 		clocksource_init();
 
-	/* Not exact, but the timer interrupt takes care of this */
-	set_dec(tb_ticks_per_jiffy);
+	init_decrementer_clockevent();
 }
 
 
Index: working/include/asm-powerpc/time.h
===================================================================
--- working.orig/include/asm-powerpc/time.h
+++ working/include/asm-powerpc/time.h
@@ -245,6 +245,7 @@ extern void snapshot_timebases(void);
 #define snapshot_timebases()			do { } while (0)
 #endif
 
+extern void secondary_cpu_time_init(void);
 extern void iSeries_time_init_early(void);
 
 #endif /* __KERNEL__ */

  reply	other threads:[~2007-09-19  6:51 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-09-19  6:49 [PATCH 1/5] Implement {read,update}_persistent_clock Tony Breeds
2007-09-19  6:49 ` Tony Breeds [this message]
2007-09-19  6:49 ` [PATCH 4/5] Include hrtimer.h in tick.h Tony Breeds
2007-09-19  6:49 ` [PATCH 2/5] Implement generic time of day clocksource for powerpc machines Tony Breeds
2007-09-19 15:43   ` Daniel Walker
2007-09-19 15:43     ` Daniel Walker
2007-09-20  0:52     ` Paul Mackerras
2007-09-20  0:52       ` Paul Mackerras
2007-09-20  1:35       ` Daniel Walker
2007-09-20  1:35         ` Daniel Walker
2007-09-20  1:46         ` Paul Mackerras
2007-09-20  1:46           ` Paul Mackerras
2007-09-20  1:54           ` Daniel Walker
2007-09-20  1:54             ` Daniel Walker
2007-09-20  3:29             ` David Gibson
2007-09-20  3:29               ` David Gibson
2007-09-20  3:38               ` Daniel Walker
2007-09-20  3:38                 ` Daniel Walker
2007-09-20 16:35       ` john stultz
2007-09-20 16:35         ` john stultz
2007-09-20 23:46         ` Tony Breeds
2007-09-20 23:46           ` Tony Breeds
2007-09-19  6:49 ` [PATCH 5/5] Enable tickless idle and high res timers for powerpc Tony Breeds
2007-09-19  6:53 ` [PATCH 1/5] Implement {read,update}_persistent_clock Tony Breeds

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=20070919064947.5EA57399911@thor \
    --to=tony@bakeyournoodle.com \
    --cc=linux-rt-users@vger.kernel.org \
    --cc=linuxppc-dev@ozlabs.org \
    --cc=paulus@samba.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.