root/arch/openrisc/kernel/sync-timer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. synchronise_count_master
  2. synchronise_count_slave

   1 /*
   2  * OR1K timer synchronisation
   3  *
   4  * Based on work from MIPS implementation.
   5  *
   6  * All CPUs will have their count registers synchronised to the CPU0 next time
   7  * value. This can cause a small timewarp for CPU0. All other CPU's should
   8  * not have done anything significant (but they may have had interrupts
   9  * enabled briefly - prom_smp_finish() should not be responsible for enabling
  10  * interrupts...)
  11  */
  12 
  13 #include <linux/kernel.h>
  14 #include <linux/irqflags.h>
  15 #include <linux/cpumask.h>
  16 
  17 #include <asm/time.h>
  18 #include <asm/timex.h>
  19 #include <linux/atomic.h>
  20 #include <asm/barrier.h>
  21 
  22 #include <asm/spr.h>
  23 
  24 static unsigned int initcount;
  25 static atomic_t count_count_start = ATOMIC_INIT(0);
  26 static atomic_t count_count_stop = ATOMIC_INIT(0);
  27 
  28 #define COUNTON 100
  29 #define NR_LOOPS 3
  30 
  31 void synchronise_count_master(int cpu)
  32 {
  33         int i;
  34         unsigned long flags;
  35 
  36         pr_info("Synchronize counters for CPU %u: ", cpu);
  37 
  38         local_irq_save(flags);
  39 
  40         /*
  41          * We loop a few times to get a primed instruction cache,
  42          * then the last pass is more or less synchronised and
  43          * the master and slaves each set their cycle counters to a known
  44          * value all at once. This reduces the chance of having random offsets
  45          * between the processors, and guarantees that the maximum
  46          * delay between the cycle counters is never bigger than
  47          * the latency of information-passing (cachelines) between
  48          * two CPUs.
  49          */
  50 
  51         for (i = 0; i < NR_LOOPS; i++) {
  52                 /* slaves loop on '!= 2' */
  53                 while (atomic_read(&count_count_start) != 1)
  54                         mb();
  55                 atomic_set(&count_count_stop, 0);
  56                 smp_wmb();
  57 
  58                 /* Let the slave writes its count register */
  59                 atomic_inc(&count_count_start);
  60 
  61                 /* Count will be initialised to current timer */
  62                 if (i == 1)
  63                         initcount = get_cycles();
  64 
  65                 /*
  66                  * Everyone initialises count in the last loop:
  67                  */
  68                 if (i == NR_LOOPS-1)
  69                         openrisc_timer_set(initcount);
  70 
  71                 /*
  72                  * Wait for slave to leave the synchronization point:
  73                  */
  74                 while (atomic_read(&count_count_stop) != 1)
  75                         mb();
  76                 atomic_set(&count_count_start, 0);
  77                 smp_wmb();
  78                 atomic_inc(&count_count_stop);
  79         }
  80         /* Arrange for an interrupt in a short while */
  81         openrisc_timer_set_next(COUNTON);
  82 
  83         local_irq_restore(flags);
  84 
  85         /*
  86          * i386 code reported the skew here, but the
  87          * count registers were almost certainly out of sync
  88          * so no point in alarming people
  89          */
  90         pr_cont("done.\n");
  91 }
  92 
  93 void synchronise_count_slave(int cpu)
  94 {
  95         int i;
  96 
  97         /*
  98          * Not every cpu is online at the time this gets called,
  99          * so we first wait for the master to say everyone is ready
 100          */
 101 
 102         for (i = 0; i < NR_LOOPS; i++) {
 103                 atomic_inc(&count_count_start);
 104                 while (atomic_read(&count_count_start) != 2)
 105                         mb();
 106 
 107                 /*
 108                  * Everyone initialises count in the last loop:
 109                  */
 110                 if (i == NR_LOOPS-1)
 111                         openrisc_timer_set(initcount);
 112 
 113                 atomic_inc(&count_count_stop);
 114                 while (atomic_read(&count_count_stop) != 2)
 115                         mb();
 116         }
 117         /* Arrange for an interrupt in a short while */
 118         openrisc_timer_set_next(COUNTON);
 119 }
 120 #undef NR_LOOPS

/* [<][>][^][v][top][bottom][index][help] */