Skip to contentSkip to conversation

Support cpu timer for SMP case

RFC New Jun Sun 1 participant 1 message Apr 20, 2004 MIPS

lore
Share & tools
lore

Jun Sun

author
#0 lore raw

RFC 1/1 Support cpu timer for SMP case

This patch illustrates that the cpu timer can be used as system timer on a SMP system:

1) count/compare on CPU 0 registers are used to generate jiffy interrupts

2) at the end of processing jiffy interrupt, cpu 0 sends a special inter-processor interrupt (IPI) to all other cpus and make them do process accounting stuff (local_timer_interrupt()).

3) count registers on all CPU 0 are sync'ed up at the beginning. As a result we will have a consistent time reading on all CPUs (do_gettimeofday()).

This patch assumes that the count registers on different CPUs don't drift from each other after they sync up. If they do drift, we can change the code to allow periodic sync up. We can probably even support different count frequencies.

This patch is actually tested to be working on sibyte boards.

As a by-product of the patch we also fix a "gettimeofday() going backward" problem on those smp boards.

Jun

P.S., the patch really looks more complicated than it should be, because
I am leaving the old time code for the board there but "ifdef"ed out. If we make a complete transition to cpu timer, all the ifdef's and old time code for the board should go away.

arch/mips/Kconfig +2 -0
diff -u linux/arch/mips/Kconfig linux/arch/mips/Kconfig
@@ -522,10 +522,12 @@
 config SIBYTE_SENTOSA
 	bool "BCM91250E-Sentosa"
 	select SIBYTE_SB1250
+	select CPU_TIMER
 
 config SIBYTE_RHONE
 	bool "BCM91125E-Rhone"
 	select SIBYTE_BCM1125H
+	select CPU_TIMER
 
 config SIBYTE_CARMEL
 	bool "BCM91120x-Carmel"
arch/mips/kernel/cpu-timer.c +150 -0

162 lines not on this page · raw message

only in patch2:
unchanged:

include/asm-mips/smp.h renamed from include/asm-mips/smp.h.orig +1 -0
@@ -46,6 +46,7 @@
 
 #define SMP_RESCHEDULE_YOURSELF	0x1	/* XXX braindead */
 #define SMP_CALL_FUNCTION	0x2
+#define SMP_EMULATE_LOCAL_TIMER	0x4
 
 extern cpumask_t phys_cpu_present_map;
 extern cpumask_t cpu_online_map;

only in patch2:
unchanged:

arch/mips/sibyte/swarm/setup.c renamed from arch/mips/sibyte/swarm/setup.c.orig +5 -0
@@ -57,6 +57,7 @@
 
 void __init swarm_timer_setup(struct irqaction *irq)
 {
+#if !defined(CONFIG_CPU_TIMER)
         /*
          * we don't set up irqaction, because we will deliver timer
          * interrupts through low-level (direct) meachanism.
@@ -64,6 +65,7 @@
 
         /* We only need to setup the generic timer */
         sb1250_time_init();
+#endif
 }
 
 int swarm_be_handler(struct pt_regs *regs, int is_fixup)
@@ -104,6 +106,9 @@
 		rtc_set_time = m41t81_set_time;
 	}
 
+	/* hack for now */
+	mips_hpt_frequency = 600000000;
+
 	printk("This kernel optimized for "
 #ifdef CONFIG_SIMULATION
 	       "simulation"

only in patch2:
unchanged:

arch/mips/sibyte/sb1250/Makefile renamed from arch/mips/sibyte/sb1250/Makefile.orig +5 -1
@@ -1,8 +1,12 @@
-obj-y := setup.o irq.o irq_handler.o time.o
+obj-y := setup.o irq.o irq_handler.o 
 
 obj-$(CONFIG_SMP)			+= smp.o
 obj-$(CONFIG_SIBYTE_TBPROF)		+= bcm1250_tbprof.o
 obj-$(CONFIG_SIBYTE_STANDALONE)		+= prom.o
 obj-$(CONFIG_SIBYTE_BUS_WATCHER)	+= bus_watcher.o
 
+ifndef CONFIG_CPU_TIMER
+obj-y					+= time.o
+endif
+
 EXTRA_AFLAGS := $(CFLAGS)

only in patch2:
unchanged:

arch/mips/sibyte/sb1250/irq_handler.S renamed from arch/mips/sibyte/sb1250/irq_handler.S.orig +14 -0
@@ -65,6 +65,8 @@
 #endif
 	/* Read cause */
 	mfc0	s0, CP0_CAUSE
+	mfc0    t0, CP0_STATUS
+	and     s0, s0, t0              /* mask away disabled irqs */
 
 #ifdef CONFIG_SIBYTE_SB1250_PROF
 	/* Cpu performance counter interrupt is routed to IP[7] */
@@ -80,6 +82,17 @@
 0:
 #endif
 
+#if defined(CONFIG_CPU_TIMER)
+	andi    t1, s0, CAUSEF_IP7
+	beqz    t1, 1f
+	nop
+	li      a0, 64
+	move    a1, sp
+	jal     ll_timer_interrupt
+	nop
+	j       ret_from_irq
+	nop
+#else
 	/* Timer interrupt is routed to IP[4] */
 	andi	t1, s0, CAUSEF_IP4
 	beqz	t1, 1f
@@ -88,6 +101,7 @@
 	 move	a0, sp			/* Pass the registers along */
 	j	ret_from_irq
 	 nop				# delay slot
+#endif
 1:
 
 #ifdef CONFIG_SMP

only in patch2:
unchanged:

arch/mips/sibyte/sb1250/irq.c renamed from arch/mips/sibyte/sb1250/irq.c.orig +3 -0
@@ -386,6 +386,9 @@
 #ifdef CONFIG_KGDB
 	imask |= STATUSF_IP6;
 #endif
+#if defined(CONFIG_CPU_TIMER)
+	imask |= STATUSF_IP7;
+#endif
 	/* Enable necessary IPs, disable the rest */
 	change_c0_status(ST0_IM, imask);
 	set_except_vector(0, sb1250_irq_handler);

only in patch2:
unchanged:

arch/mips/sibyte/sb1250/smp.c renamed from arch/mips/sibyte/sb1250/smp.c.orig +9 -0
@@ -22,6 +22,7 @@
 #include <linux/smp.h>
 #include <linux/kernel_stat.h>
 
+#include <asm/time.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
 #include <asm/sibyte/sb1250.h>
@@ -57,8 +58,10 @@
 
 void sb1250_smp_finish(void)
 {
+#if !defined(CONFIG_CPU_TIMER)
 	extern void sb1250_time_init(void);
 	sb1250_time_init();
+#endif
 	local_irq_enable();
 }
 
@@ -95,4 +98,10 @@
 
 	if (action & SMP_CALL_FUNCTION)
 		smp_call_function_interrupt();
+
+	if (action & SMP_EMULATE_LOCAL_TIMER) {
+		irq_enter();
+		local_timer_interrupt(0, NULL, regs);
+		irq_exit();
+	}
 }

only in patch2:
unchanged:

arch/mips/kernel/smp.c renamed from arch/mips/kernel/smp.c.orig +7 -0
@@ -224,6 +224,13 @@
 void __init smp_cpus_done(unsigned int max_cpus)
 {
 	prom_cpus_done();
+
+#if defined(CONFIG_CPU_TIMER)
+	{
+		extern void sync_c0_count(void);
+		sync_c0_count();
+	}
+#endif
 }
 
 /* called from main before smp_init() */