diff -u linux/arch/mips/Kconfig linux/arch/mips/Kconfig --- linux/arch/mips/Kconfig 2004-04-19 16:42:18.000000000 -0700 +++ linux/arch/mips/Kconfig 2004-04-20 14:38:18.000000000 -0700 @@ -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" diff -u linux/arch/mips/kernel/cpu-timer.c linux/arch/mips/kernel/cpu-timer.c --- linux/arch/mips/kernel/cpu-timer.c 2004-04-19 17:01:13.000000000 -0700 +++ linux/arch/mips/kernel/cpu-timer.c 2004-04-20 14:23:11.000000000 -0700 @@ -244,6 +244,11 @@ atomic_inc((atomic_t *)&prof_buffer[pc]); } } + +#ifdef CONFIG_SMP + /* in UP mode, update_process_times() is invoked by do_timer() */ + update_process_times(user_mode(regs)); +#endif } /* @@ -296,6 +301,16 @@ */ local_timer_interrupt(irq, dev_id, regs); +#if defined(CONFIG_SMP) + /* In SMP mode, we also ask other CPUs to do the same */ + { + int i; + for (i = 1; i < NR_CPUS; i++) + if (cpu_online(i)) + core_send_ipi(i, SMP_EMULATE_LOCAL_TIMER); + } +#endif + return IRQ_HANDLED; } @@ -446,0 +461,135 @@ + +#if defined(CONFIG_SMP) +static atomic_t rend_start; +static atomic_t rend_ready; +static atomic_t rend_cpus; + +static void rendezvous_init(int v) +{ + atomic_set(&rend_cpus, 0); mb(); + atomic_set(&rend_start, v); mb(); + atomic_set(&rend_ready, v); mb(); +} + +static void rendezvous_master(int v) +{ + db_assert(atomic_read(&rend_start) != v); + + atomic_set(&rend_cpus, 0); mb(); + atomic_set(&rend_start, v); mb(); + while (atomic_read(&rend_cpus) != num_online_cpus() -1) + mb(); + atomic_set(&rend_ready, v); mb(); +} + +#define rendezvous_master_extra(v, cmd) { \ + int val=(v); \ + db_assert(atomic_read(&rend_start) != val); \ + atomic_set(&rend_cpus, 0); mb(); \ + atomic_set(&rend_start, val); mb(); \ + while (atomic_read(&rend_cpus) != num_online_cpus() -1) mb(); \ + { cmd; } \ + atomic_set(&rend_ready, val); mb(); \ +} + +static void rendezvous_slave(int v) +{ + while (atomic_read(&rend_start) != v) + mb(); + atomic_inc(&rend_cpus); mb(); + while (atomic_read(&rend_ready) != v) + mb(); +} + +static void rendezvous_slave_exit(int v) +{ + while (atomic_read(&rend_start) != v) + mb(); + atomic_inc(&rend_cpus); mb(); +} + +#define LOOPS 8 +static u32 c0_count[NR_CPUS]; +static u32 c[NR_CPUS][LOOPS+1]; +static void sync_c0_count_slave(void *info) +{ + unsigned long flags; + int i, loop; + int cpu = smp_processor_id(); + u32 diff; + int prev_diff; + + db_assert(cpu != 0); + + i=1; + prev_diff = 0; + + local_irq_save(flags); + for (loop=0; loop<= LOOPS; loop++) { + + rendezvous_slave(i++); + c[cpu][loop] = c0_count[cpu] = read_c0_count(); mb(); + + if (loop == LOOPS) + break; + + rendezvous_slave(i++); + diff = c0_count[0] - c0_count[cpu]; + diff += (u32)prev_diff; + diff += read_c0_count(); + write_c0_count(diff); + + /* discard the first diff which is probably very big */ + if (loop > 0) + prev_diff = (prev_diff >> 1) + + ((int)(c0_count[0] - c0_count[cpu]) >> 1); + } + + rendezvous_slave_exit(i++); + local_irq_restore(flags); +} + +void sync_c0_count(void) +{ + int cpu=smp_processor_id(); + unsigned long flags; + int i, loop; + + db_assert(cpu == 0); + + printk("SMP: start to sync c0 count...\n"); + + i=0; rendezvous_init(i++); + + smp_call_function(sync_c0_count_slave, NULL, 0, 0); + + local_irq_save(flags); + for (loop=0; loop<= LOOPS; loop++) { + /* wait for all cpus to gether here */ + rendezvous_master(i++); + c[cpu][loop] = c0_count[cpu] = read_c0_count(); mb(); + + if (loop == LOOPS) + break; + + rendezvous_master(i++); + /* master does nothing here */ + } + + rendezvous_master(i++); + local_irq_restore(flags); + + /* print results */ + printk("SMP: end of c0 count sync'ing ... \n"); + for (i=0; i<= LOOPS; i++) { + int j; + printk("\t%08x", c[0][i]); + for (j=1; j #include +#include #include #include #include @@ -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: --- linux/arch/mips/kernel/smp.c.orig 2004-03-09 16:40:21.000000000 -0800 +++ linux/arch/mips/kernel/smp.c 2004-04-20 14:18:55.000000000 -0700 @@ -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() */