Support cpu timer for SMP case
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
@@ -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 0x4extern 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() */